4

My project use some font like Arabic character, I also need use stroke on the font. I already try some way to display the Stroke, like :

https://stackoverflow.com/a/9887123/1900498 (OuterTextBlock)

https://stackoverflow.com/a/97728/1900498 (OutlineText)

The Stroke can display now, but the problem is the Arabic character connection position still display some stroke, So I need to remove it.

the result like this: enter image description here

So Is there any way I can remove the stroke from the connection position? I mean If the character is connection, just stroke on the full connection outsize, not all character stroke 1 time.

I need the result like this(I'm using PHOTOSHOP to edit the second picture and remove the stroke from character connection position, not WPF, that is just for you understand the correct result must handle by WPF) enter image description here

UPDATE: please download the 2 class from the 2 link , then use This code :

<Window x:Class="test.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:test"
    Title="MainWindow" Height="200" Width="400">
<Grid Background="Black">
    <local:OutlinedTextBlock  HorizontalAlignment="Left" Height="200" VerticalAlignment="Bottom"  FontSize="150" StrokeThickness="1" Fill="White" Stroke="Red" TextDecorations="">ئالما</local:OutlinedTextBlock>
    <local:OutlinedText  HorizontalAlignment="Right" Height="200" VerticalAlignment="Top"  FontSize="150" StrokeThickness="1" Fill="White" Stroke="Red" Text="ئالما"></local:OutlinedText>
</Grid>

Community
  • 1
  • 1
qakmak
  • 1,287
  • 9
  • 31
  • 62
  • Please add some code for better understanding – Mayur Dhingra Aug 19 '14 at 12:45
  • 1
    Not an answer because I haven't tried and it seems to me more like a workaround, but you could try [combining](http://msdn.microsoft.com/en-us/library/ms607449%28v=vs.110%29.aspx) the geometries of adjacent characters with [`GeometryCombineMode.Union`](http://msdn.microsoft.com/en-us/library/system.windows.media.geometrycombinemode%28v=vs.110%29.aspx) for all character groups until you hit a whitespace. – O. R. Mapper Aug 19 '14 at 13:00
  • @Mayur Dhingra, you can download the two class from the 2 link. then you can use this code to display it which I just update it. – qakmak Aug 19 '14 at 15:13
  • @O.R.Mapper, thank you for the suggest, but I see the 2 source code, looks like it will create the Text with stroke when generate the Geometry, So I think I can't use GeometryCombineMode.Union – qakmak Aug 19 '14 at 15:19
  • @qakmak: At least the first answer creates *one* `Geometry` instance that defines the complete outline of all characters. That geometry is passed to [`DrawGeometry`](http://msdn.microsoft.com/en-us/library/system.windows.media.drawingcontext.drawgeometry%28v=vs.110%29.aspx), which colors both the outline and the inner area of the geometry. Presumeably, you can access the single elements in that geometry and try to combine them as a union. – O. R. Mapper Aug 19 '14 at 15:28
  • @qakmak: I have successfully tried my idea and documented what I did in my answer. – O. R. Mapper Aug 19 '14 at 16:19

1 Answers1

4

Initial observations: The artifacts you are seeing seem to be the actual edges of the single characters. The characters touch and overlap slightly, while you would like to perceive several characters as one consecutive shape.

I have tried my suggestion from the comments by extending the OutlinedTextBlock class from the first linked answer by Kent Boogaart.

The Geometry instance obtained by OutlinedTextBlock from the BuildGeometry method consists of nested GeometryGroup instances (at least, separate such groups are created when incorporating text with several reading directions). After diving through those groups, you will find one PathGeometry instance per character.

N.B.: This is what I figured out when looking at the data. It is probably undocumented (?), and if it ever changes, this solution may not work any more.

By using the Geometry.Combine method, all of these PathGeometry instances can be combined with GeometryCombineMode.Union, which means that overlapping areas will be merged.

First, I have defined a method for finding all the PathGeometry objects. It recursively dives into the hierarchy of GeometryGroup objects and is rather not very efficient, but it serves to demonstrate the point - feel free to optimize this performance-wise:

private IEnumerable<PathGeometry> FindAllPathGeometries(Geometry geometry)
{
    var pathGeometry = geometry as PathGeometry;
    if (pathGeometry != null) {
        yield return pathGeometry;
    } else {
        var geoGroup = geometry as GeometryGroup;
        if (geoGroup != null) {
            foreach (var geo in geoGroup.Children) {
                foreach (var pg in FindAllPathGeometries(geo)) {
                    yield return pg;
                }
            }
        }
    }
}

Then, I have modified the OutlinedTextBox.EnsureGeometry method. Originally, the geometry retrieved from BuildGeometry was directly displayed:

private void EnsureGeometry()
{
    if (this.textGeometry != null) {
        return;
    }

    this.EnsureFormattedText();
    this.textGeometry = this.formattedText.BuildGeometry(new Point(0, 0));
}

Instead, I now process that geometry by iterating over all of the contained PathGeometry instances and incrementally combining them with the Union mode. For the sake of convenience (and so you can actually observe the difference), I have made that behaviour optional by adding a MergeShapes property:

private void EnsureGeometry()
{
    if (this.textGeometry != null) {
        return;
    }

    this.EnsureFormattedText();
    var originalGeometry = this.formattedText.BuildGeometry(new Point(0, 0));

    if (MergeShapes) {
      PathGeometry newGeo = new PathGeometry();
      foreach (var pg in FindAllPathGeometries(originalGeometry)) {
        newGeo = Geometry.Combine(newGeo, pg, GeometryCombineMode.Union, null);
      }

      this.textGeometry = newGeo;
    } else {
        this.textGeometry = originalGeometry;
    }
}

public static readonly DependencyProperty MergeShapesProperty = DependencyProperty.Register("MergeShapes",
                                                                                            typeof(bool),
                                                                                            typeof(OutlinedTextBlock),
                                                                                            new FrameworkPropertyMetadata(OnFormattedTextUpdated));

public bool MergeShapes {
    get {
        return (bool)GetValue(MergeShapesProperty);
    }
    set {
        SetValue(MergeShapesProperty, value);
    }
}
Community
  • 1
  • 1
O. R. Mapper
  • 20,083
  • 9
  • 69
  • 114