You know how System.Drawing.Rectangle was replaced by System.Windows.Int32Rect? (As far as non-floating-point shapes are concerned ...)
Is there a similar new object for an integer point or size? If not, I'll just use System.Drawing - but that kinda seems like a minor mix of two platforms that ought not to me mixed.
Anyway, what do you think about this?
The drawing primitives in WPF store all measurements/locations values in doubles - apparently all except Int32Rect, as you pointed out. The reasoning behind this design is due to how WPF is not bound directly from pixel-to-display - it uses "device independent pixels" (DIPs) which can be scaled for whatever device on which it is being rendered. This gives WPF the ability to scale and translate everything that it is displaying very easily.
As for System.Windows.Int32Rect, the only place I see it being used inside the API is for capturing and cropping pixels. This makes sense - when doing a screen capture, you're wanting to get exactly the pixels that are currently displayed on the device.
Related
I am trying to write a PCL document, which has several drawing objects (lines, rectangles, texts...)
I found that if I draw the rectangles before anything else, they appear in the right position and size. However, if I draw them among the rest of objects, they are drawn smaller and in the wrong place.
The PCL seems to be OK (although this is yet to be proven), but it has made me think that perhaps graphic objects must be drawn in a particular order (I am using HPGL/2, by the way).
Does someone know if this is so? I have not been able to find anything in the PCL Manual nor in the internet (which leads me to believe that there is not such drawing order).
Perhaps you have written position or scale commands that unintentionally affect your rectangles.
I'm drawing certain images in WPF which will be displayed by a game (developed by a third party). I currently produce the images using a RenderTargetBitmap. Unfortunately it seems that this only supports the Ideal text formatting mode, resulting in blurry small fonts. The application is a third-party game and thus there's no way around using images.
Can I tell the RenderTargetBitmap to assume that it's drawing an image destined for one of the current montiors? Is there another way to get WPF to use the Display rendering mode for off-screen drawing?
I understand why this might seem wrong in the theoretical sense, but in practice there are reasons why I think this is not an unreasonable thing to do:
One of the things the Display mode allows is aliased text, which looks better at small sizes than the Ideal rendering, and is completely independent of monitor properties such as gamma.
A screenshot of small Display-mode text rendered in ClearType looks far better on any screen, even those with different gamma, than Ideal-mode text.
Can the WPF rendering engine do this, or do I have to fall back onto GDI? (which has no difficulties with using Aliased or ClearType rendering off-screen)
There is certainly no obvious way of doing this. I guess drawing to images was never a goal of WPF; the fact that it can actually do this fairly well most of the time must be accidental.
It seems that this works now. Could someone else verify? Here's the relevant code:
var textBlock = new TextBlock();
textBlock.Text = "Hello World";
textBlock.FontFamily = new System.Windows.Media.FontFamily("Arial");
textBlock.Background = System.Windows.Media.Brushes.Transparent;
textBlock.Foreground = System.Windows.Media.Brushes.Black;
textBlock.FontSize = 50;
// . Set Formatting Mode Works! Setting the rendering mode doesn't.
System.Windows.Media.TextOptions.SetTextFormattingMode(textBlock, System.Windows.Media.TextFormattingMode.Display);
Edit: Forgot to mention I'm using the .NET 4.5 framework
Edit2: The difference between Display and Ideal is especially noticeable at smaller font sizes.
I have a WPF application with many tabs..
in one tab.. i make a verycomplex vector drawing consisting of thousands of drawing visuals.. (this represents a machine and all elements need to be interactable..)
It takes 3/4 seconds for drawing this for the first time..After the first draw it should be done..
The problem is if i switch to another tab and comeback, it takes atlease 2,3 seconds to show the tabpage with drawing again.. Since there is no redraw, why should it take so much time..?
If the component is not going to change, you could call Freeze() on it to mark it as done. Without trying it out I don't know if that would help, but you could give it a shot.
Not all objects are Freezable. Check out the MSDN documentation for more info:
http://msdn.microsoft.com/en-us/library/ms750509.aspx
Another thing you could try would be rendering the vector art to a bitmap, and displaying that. Maybe it makes you feel icky to lose the vector precision, but if you know it's not going to change and it will look the same, what's the harm? (If you support printing or something that will require a hi-res version, you could always switch back for that operation.) For info on how to convert a UIElement to a bitmap, check out:
http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.rendertargetbitmap.aspx
Another possible solution: You don't really explain what kind of interaction you are doing with the elements, but if all you want to do is zoom and pan, a RenderTransform may be good enough (which is more efficient than a LayoutTransform and/or moving all the elements individually). I haven't played around with combining Freeze() and a RenderTransform, but you may be able to get the desired zooming while reducing the amount of layout WPF has to do.
This is a question regarding a very simple construction - I have the following XAML:
<Viewbox Height="100" Stretch="Uniform">
<TextBlock FontFamily="Georgia">My Cool Text</TextBlock>
</Viewbox>
This is quite simple to understand. Yet when I start the program I get strange blurry text (there are no bitmap effects anywhere in my project).
(left side - the designer view in VS2010, right side - the running application)
Does anyone have ANY suggestions about why this is happening??
While Jefim has correctly answered his own question, I wanted to explain why you get this behaviour when using this particular set of features. Jefim suggests that this is a bug in WPF, but it's not. The problem arises as a result of asking for WPF to do something impossible. It has to pick a compromise when you've asked for this impossible thing, and the result is what you see above.
The explanation is a bit long for a comment, which is why I'm putting it in a separate answer.
This example uses two mutually contradictory features of WPF. Those features are:
The ability to render visuals consistently at any scale
The ability to render text in the same way GDI32 renders text
You can't use both features at once. GDI32 renders text in a way that cannot be scaled consistently: if a particular piece of text at a certain font size happens to be 200 pixels wide, if you multiply the font size by 3, and render the same text in the same font family at that new font size, in GDI32 it probably won't be 600 pixels - it'll be close, but it will typically not be quite right.
GDI32 messes with the shapes and widths of characters in order to enhance the clarity and sharpness of the text. Specifically, it bends letters out of shape so that their features align better with the pixels on your screen. And where necessary, it will adjust the width of individual characters to be an exact number of pixels wide. Since this letter bending is all based around actual pixels, it bends text in different ways at different font sizes.
While that gives you nice sharp looking text, it looks absolutely horrible if you try to change the scale gradually. If you try to animate the font size of some text rendered in this fashion, the thing will seem to shimmer and shudder, because the adjustments made in the name of clarity end up being slightly different at each font size. Even if you're not animating, it can still produce poor results - if you have a single typeface shown at a number of sizes, it can look quite different at each size; if your application has a zoom feature, the character of the text can seem to change significantly as you zoom in and out. (And so can the layout. If you use Microsoft Word, you may have noticed that you sometimes get odd-looking extra wide spaces between certain words. This is the result of Word fighting with GDI32 - Word attempts to keep the on-screen layout as close as possible to how things will look when printing, which means it sometimes clashes with GDI32's grid fitting.)
So WPF offers a different approach to text rendering: it can render text in a way that is as faithful as possible to the original design of the font. This distorts the text less, and it means that you don't get discontinuities as you scale.
The downside is that the text looks blurry, compared to how text rendered by GDI32 looks. (The distortions made by GDI32 are all aimed at improving clarity.)
So in WPF 4.0, Microsoft added the ability to render text in the way GDI32 would. That's what TextOptions.TextFormattingMode="Display" does.
By turning on that option, you are saying "I don't need consistent scaling, and I'd prefer clarity, so generate the same pixels you would have done in GDI32." If you then go on to apply scaling, having told WPF you didn't need scalability, you get crappy results. WPF carefully generated a bitmap representation of the text exactly to your specifications, and you then told it to render that text at a different scale. And so it looks like what it is: a scaled bitmap of some text that was generated for a different resolution.
You could argue that WPF could do something different here: if you apply a scale transform in GDI32 you'd see different behaviour - you'd see the inconsistency at different scales described earlier. If you really want that effect in WPF you can get it by modifying the font size directly. But WPF doesn't prioritise getting that same effect - its goals are to make it possible to get GDI32-style crisp text when you really need it, and to provide consistent scaling by default.
And what you're running into here is the "consistent scaling". Turning on GDI32-style text rendering doesn't break consistent scaling: applying a scale factor (either directly, via a ScaleTransform or indirectly via a Viewbox) will change the dimensions of the visual by exactly the specified scale factor. If it were to re-generate the text visuals by grid fitting to the newly scaled size, the text would come out at a different width. That would actually cause the Viewbox problems: it applies a scale factor based on the content's natural size, designed to make it fit the available space. But if it re-did the grid fit after scaling, that would actually change the width. Because of the inconsistencies inherent in how GDI32 text rendering works, it might not even be possible for the ViewBox to find a suitable scale - it's possible to come up with a piece of text which, when rendered in a particular font, will never come out at 200 pixels wide. For some font sizes, the rounding inherent in grid fitting might bump the size down to, say, 198, and it might stick at that as you make tiny increments in the font size, until you go past some threshold at which point it might jump to 202 pixels.
For a Viewbox attempting to force the text to fit into exactly 200 pixels, that would be a problem. But Viewbox doesn't work that way - it uses WPF's consistent scaling, downstream of the point at which you chose the font size to which GDI32-style text rendering is working. So Viewbox will always be able to do what it is designed to do, but that is task that's fundamentally incompatible with GDI32-style text rendering.
So in short, WPF renders the text for the font size you requested, and then scales the result.
So you have to pick just one feature - you can't have both because that's simply impossible. Either don't attempt to render text in a context in which an arbitrary scale factor may be applied (e.g. Viewbox) or don't turn on GDI32-style text rendering. Otherwise, you get that weird pixelated text that you've encountered.
Ok, bug found. My Window style has the following setter:
<Setter Property="TextOptions.TextFormattingMode" Value="Display"/>
If I set it back to "Ideal" (which is the default value) then it renders the text inside the viewbox correctly. I would say that this is a bug inside WPF. Basically, if you try this:
<Viewbox Height="100" Stretch="Uniform" TextOptions.TextFormattingMode="Display">
<TextBlock FontFamily="Georgia">My Cool Text</TextBlock>
</Viewbox>
You will get the same result as in my initial picture.
What is the best approach to render charts and then save them on a hard drive for further distribution using WPF?
I found a number of ways to accomplish this by using the following types:
DrawingVisual - creating a object of this type and then rendering graphics on its context;
Shape - deriving from the Shape class and then overriding its DefiningGeometry property where the actual rendering is happening;
PathFigure - adding LineSegment-s to an instance of this class and then adding this instance to a Canvas;
Adorner - deriving from it and then overriding its OnRender method;
WritableBitmap - rendering on it and then adding the bitmap to a Canvas.
Of course I'm going to write an app to test how fast each of these will be. But can anybody tell me:
whether am I on the right track?
are there any other means to do such rendering?
which one of them is the best in
terms of performance?
It all depends on your actual usage, in your case you mention saving on the hard drive for "further distribution" - I'm going to assume you are saving them as an image (jpg or png) and not as wpf objects (xaml).
You should consider if WPF is the right tool for the job, WPF is a UI framework and not a generic image processing library, it may be best to use something else entirely for generating images.
For a reasonable number of points your performance bottleneck will be encoding the image and saving it to disk - not actually rendering it - so you should choose the method that is easier for you to code.
All the articles about high performance WPF charts are a: about charts with 10,000 points and more (because that is where the performance problems are), b: about charts you display in your GUI (because otherwise you can use an image processing library to create the bitmap) and c: charts that change all the time (so they work nicely with data binding) - there's a reason why they don't talk about saving charts to disk.
For a very large number of points:
The fastest way to draw in WPF is to inherit from FrameworkElement (not Adorner) and override OnRender.
When the data changes often it is recommended to use multiple DrawingVisual objects because then you don't have to re-render everything when one value change - but this is not relevant for you since the image won't change after you save it anyway.
WritableBitmap is used for raw bitmap access, you use it when you decide to give up on all the nice layout and drawing WPF gives you because you can't take the overhead, if this is the case you should re-read my first point above.
So, to summarize, you are asking the wrong question :-) if you need to save images to disk than either the WPF rendering speed is not your bottleneck or you shouldn't be using WPF to begin with. If you do use WPF just pick whatever is easiest for you to code.
BTW: Adorners are used to display "floating" elements above the normal UI, you can use them for tooltip-like features but not for the main chart rendering (and you probably don't want them at all since your main usage is saving the image to disk), FrameworkElement is the base class you are looking for.