WPF DrawingContext DrawGlyphRun blur text - wpf

I'm using the DrawingContext DrawGlyphRun(GlyphRun) function to draw text in the Canvas using the solution from https://smellegantcode.wordpress.com/2008/07/03/glyphrun-and-so-forth/.
I'm using this over the FormattedText because it's faster and it's also used for calculating text width.
This works well except for 2 problems:
Text is blurred (see below the image). Text at the top is displayed using GlyphRun. The bottom text is displayed using FormattedText which has better quality.
Cannot display Japanese or Chinese characters.
Problem with characters seems to be that GlyphTypeface.CharacterToGlyphMap cannot find the jp or cn character, so I'm not sure how exactly to deal with these characters.

I just found your question after some research that I made.
GlyphRun created using public constructors creates object with TextFormattingMode = Ideal
All WPF contols for their rendring use methods/constructors that accepts TextFormattingMode as parameter.
You can call GlyphRun.TryCreate() static method via reflection:
internal static GlyphRun TryCreate(
GlyphTypeface glyphTypeface,
int bidiLevel,
bool isSideways,
double renderingEmSize,
IList<ushort> glyphIndices,
Point baselineOrigin,
IList<double> advanceWidths,
IList<Point> glyphOffsets,
IList<char> characters,
string deviceFontName,
IList<ushort> clusterMap,
IList<bool> caretStops,
XmlLanguage language,
TextFormattingMode textLayout
)
but the problem that you need to get advanceWidths with TextFormattingMode = Ideal. For this you need access via reflection to internal methods provided by GlyphTypeface class.
GlyphTypeface.AdvanceWidths property that returns dictionary with these widths internally calls to
internal double GetAdvanceWidth(ushort glyph, TextFormattingMode textFormattingMode, bool isSideways)
when you access dictionary by index with textFormattingMode = TextFormattingMode.Ideal
You can download .Net source code and check it yourself.
As for your second question I think that you use chars instead of unicode code points to get glyph index.

Related

GDI+ Graphics.DrawString with TextTrimming set to EllipsisCharacter doesn't work if output rectangle contains one character

We use the classic GDI+ DrawString method to output text and set the Trimming property of its format parameter to EllipsisCharacter (see also the StringTrimming enumeration). If the output rectangle is enough small so it can display just one character, the ellipsis is not present on the screen - which misleads the user:
Is there a way to solve this problem?

Highlight line(s)/characters in WPF

Scenario
I am currently developing an application. Within this application, I have a TextBox/RichTextBox. I have not decided on the control yet. Within this control, there will be a few paragraphs of text.
Problem
I want to be able to highlight a range of lines, or particular characters within that line, using two given numbers. What would the easiest way to do this be?
Use RichTextBox. You can't use TextBox, that is because TextBox has only one style applied to all text.
Use the TextRange.ApplyPropertyValue method. A TextRange is specified by its starting and ending position, which are two TextPointer.
Something like this
var startingPos = RichTextBox1.ContentStart.GetPositionAtOffset(n1, LogicalDirection.Forward);
var endingPos = startingPos.GetPositionAtOffset(n2 - n1, LogicalDirection.Forward);
var textrange = new TextRange(startingPos, endingPos);
textrange.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.DarkRed);
You have to carefully calculate the offsets of the starting and ending positions, taking linebreaks into account.

Fastest way to convert RTF to FlowDocument

What is the fastest way to convert a RTF to FlowDocument? I store RTF as plain string and then reload it back, I am using following method,
FlowDocument document = new FlowDocument();
document.SetValue(FlowDocument.TextAlignmentProperty, TextAlignment.Left);
TextRange content = new TextRange(document.ContentStart, document.ContentEnd);
if (content.CanLoad(DataFormats.Rtf) && string.IsNullOrEmpty(rtf) == false)
{
// If so then load it with RTF
byte[] valueArray = Encoding.ASCII.GetBytes(rtf);
using (MemoryStream stream = new MemoryStream(valueArray))
{
content.Load(stream, DataFormats.Rtf);
}
}
But this method is very slow. I need to load many RTFs (around 1000). What can be the trick to make the process fast? Is there any other way around to load a Flowdocument?
You really need to define what you actually need. TextBlock is not weak at all.
It has things to offer ;).
Colours(Background/Foreground + you can color specific part of TextBlock even)
Alignments(you can align TextBlocks as you want, and perhaps even part of them?! Not sure about the last one.
It has TextDecorations, which means it supports bold/italic/underline/strikethrough etc.
Fonts(yeah it supports custom fonts and whatever font you want)
But fair enough. I think you should store FlowDocument XAML instead of actual RTF. This way there will be no conversion and it should be multiple times faster. (See DataFormats.xaml)
Hello Vibhore the TextBlock element should be used when limited text support is required, Label can be used when minimal text support is required.
The FlowDocument element is a container for re-flowable documents that support rich presentation of content, and therefore, has a greater performance impact than using the TextBlock or Label controls.

Vector graphics in silverlight

I am new to Silverlight. Just created my first application that shows deepzoom images.
Looking for some pointers how to display vector graphics in Silverligth. The graphics are all in 2D and is a series of lines (x1y1, x2y2), points (xy), basic shapes. The data is available in ASCII text files.
What is the way(s) to read the data from files and draw in SL? Do I need to convert / translate the vector objects into images (XAML) first? Where to start?
The ideal case is that all vector obects should be selectable either programmatically or by user actions.
Thanks,
Val
There is no direct drawing API to my knoweldge, but you can add the values seperately by adding various shapes to the visual tree.
The code you are looking for will likely involve the Path class and, in turn, PathFigure and PolyLineSegment (or possibly LineSegment).
Below is some code that draws a square:
PolyLineSegment segment = new PolyLineSegment();
segment.Points.Add(new Point(0, 50));
segment.Points.Add(new Point(50, 50));
segment.Points.Add(new Point(50, 0));
segment.Points.Add(new Point(0, 0));
PathFigure figure = new PathFigure()
{
StartPoint = new Point(0, 0)
};
figure.Segments.Add(segment);
PathGeometry geometry = new PathGeometry()
{
Figures.Add(pathFigure)
};
Path path = new Path()
{
Stroke = new SolidColorBrush(Colors.Black),
StrokeThickness = 2,
Data = pathGeometry
};
// To render, the Path needs to be added to the visual tree
LayoutRoot.Children.Add(path);
Edit If the data in the ASCII text files cannot change at runtime, it might be worth investigating writing a script that transforms the files into XAML so it can be compiled.
First of you have the issue of actually getting access to the files.
Getting the file content
If you have these files held somewhere serverside then you would use WebClient to fetch the file using DownloadStringAsync.
On the other hand if the user is to open a file locally then you need use the OpenFileDialog class to ask them to open the file and then use OpenText on the FileInfo object that OpenFileDialog provides to read the string data.
Parsing
Well its your format so you'll have to code that yourself.
__Generating UI elements_
You will not have to convert it to Xaml. Since you want these vector items to be individually selectable elements then you probably want to use the set of Shape types found in the System.Windows.Shapes namely, Elipse, Line, Path, Polygon, Polyline and Rectangle.
No doubt the format in question has someway to define the position of these elements relative to a fixed 0,0 point. Hence the best panel to use to display these is a Canvas.
You would read through each Vectored item, select create an instance of one of the appropriate shapes set its properties based on the data in the item. You would need to determine its correct location within a Canvas and use the Canvas.Left and Canvas.Top attached properties. The add the shape to the Children collection of the Canvas.

WPF Line, path ..etc custom drawing style

In WPF is there a way that you can modify the way any path is drawn APART from Dash-Dot sequences? Say I want draw a triple line for any path I am drawing or small triangles,waves..etc on the drawing path itself. I have tried Brushes but it will not follow the Path. Please help
thx
WPF's Geometry classes have all the primitives you need to accomplish this easily, but you will need to do it in code. When I need to do custom lines I usually construct a Drawing based on the Geometry, but in your case you can simply build a Geometry that has three lines in parallel and stroke that.
Start with PathGeometry.CreateFromGeometry() to get a PathGeometry for the input path
Use GetWidenedPathGeometry(), passing in the desired spacing, to get a new geometry whose edges correspond to the side lines
(optional) Remove segments at the end of the widened geometry, if desired
Combine the side line geomerty with original geometry using a CombinedGeometry
Stroke the combined geometry to get a triple line
More explanation on step 3: The widened geometry has line segments at the end of the original line. This causes a line to be drawn across the end of your line, which actually looks aesthetically pleasing in many situations. If your situation would look better without it, remove it by iterating the side line geometry and removing all line segments that pass through the endpoints of the original path.
The above takes about 8 lines of code if you don't strike off the ends, or 15 if you do.
A trick to make this convenient is to create an attached property which effectively coerces the Data property of the Path control it is attached to. With such an attached property, all you need to write is:
<Path TripleStroke.Enable="true" Data="..." />
If you know how to implement attached properties and register handlers in them, this is a piece of cake. If not, plan on spending several hours learning how to code attached properties to simulate value coercion before implementing the attached property approach.
Update
The basic technique I describe above can also be extended to allow an arbitrary pattern to be applied along a path. For an example, see custom brushes in the Expression Design tool. There is nothing built into WPF to do this for you, however, so you'll need to create it yourself, and I can tell you from experience that it is a lot of work. Here are the basic steps:
First create a method that takes a Geometry an existing Drawing, and some parameters for end caps, etc and creates a new Drawing that repeats the given Drawing along the path given by the Geometry. Then it is easy to draw a stroked path: Create a Drawing to describe the custom stroke, then display the stroke using a DrawingVisual that contains a Binding with a converter that calls your conversion method.
To actually implement the conversion method:
Convert the source drawing into a set of GeometryDrawing objects (I also supported ImageDrawing but that is more complicated since you need to use the 3D system to stretch the images). This is done by recursing through DrawingGroup objects, keeping track of transforms as you go, and constructing GeometryDrawings with appropriate transform.
Remove portions of geometry in the "end cap" areas of the original drawing and set them aside.
Iterate along the path, duplicating the GeometryDrawing objects repeatedly with appropriate coordinate transformations applied to all coordinates in the geometry.
Process the "end cap" sections of the geometry using the same procedure.
Also note in step 1 that any GlyphRunDrawings are handled using FormattedText.BuildGeometry to create an equivalent GeometryDrawing.
There is no supported method for doing this in WPF. The solution is going to involve either composite Path objects or fancy code-behind gymnastics. Are you specificly looking for a triple-line path implementation?

Resources