How to use a different coordinate system in WPF? (scaling only) - c#

(Let me give you some context)
I am currently designing an application that is supposed to generate a printable A4 page based on some data.
Naturally, the device independent pixels of WPF (96 pixels/inch) are not a very natural unit of measurement in the paper world. Something like millimetres would be more appropriate. So I got my calculator out and arrived at a scaling factor of something around 3.779.
It turns out that simply slapping everything that's supposed to go on the page in a ScaleTransform has one nasty side effect: Font sizes are scaled too (naturally). This, however, is not what I intended. I would like 12pt Arial to render like 12pt Arial would render normally.
Is there any other way to change the coordinate system without having to call into extensions or whatever to convert each and every coordinate, length, thickness and so on?
- or -
Is there any way to map font sizes on-the-fly, being DependencyProperties? Via a custom control that wraps all the paper content, maybe?

For the outlined requirements you do not need to do anything special at all, just go ahead and use centimeters as unit of measurement for the WPF elements themselves (i.e. without any transform) - the very nature of WPF device independence allows you to to the following:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="29.7cm" Width="21cm" FontSize="16pt">
<Grid>
<TextBlock Text="Sample" Height="1in" Width="1in" FontSize="12pt"
HorizontalAlignment="Center" VerticalAlignment="Center"
TextAlignment="Center"/>
</Grid>
</Window>
That is: you'll get a A4 window specified in 'cm' with a centered square TextBox specified in 'in' and a font specified in 'pt'. All these will scale properly by whatever transform you might apply additionally, if need be (e.g. via a zoom slider for the users view port), respecting their relative sizes regardless of being specified with different units each (i.e. mixed usage at will).
Available units are px (default), in, cm and pt, see for example FrameworkElement.Height for details on their specification.

You can also set sizes in points (FontSize="10pt"), in inches (FontSize="10in") or in centimeters (FontSize="10cm"). Of course the real size depends on the DPI setting of Windows and the DPI of your monitor or printer in this case.

Just set the font size to 12 / 3.779 = 3.175, no? Assign it to the containing object and it should trickle down to all children.

Related

Resizing System.Controls.Image with Nearest Neighbour resizing mode

I'm trying to make a game which uses a pixel art style. I've created my assets and used them as resources, which are added into the window as System.Controls.Image objects.
In the designer, they always turn out too small. As a result, when I resize them, they become somewhat blurred due to some sort of bicubic interpolation being applied onto them.
I have managed to avoid this by avoiding resizing; I resize in the designer to find out what size is appropriate, and then use nearest neighbour resizing on the original image (using an external program) to get the source file to that size. I then update the image in the project and remove any resizing, therefore leaving it at original size, i.e. interpolation-free.
As you can imagine, this is a rather tedious process. I looked into interpolation choices during resizing, but most answers I can find relate to System.Drawing.Image, not System.Controls.Image. I feel like any such solution (if adapted) would be horribly messy and involve multiple (and perhaps unecessary) conversions/casts.
Is there any way to get nearest neighbour resizing on System.Controls.Image?
To set the resize mode, you need to set the RenderOptions.BitmapScalingMode="NearestNeighbor" option for the visual tree. You can set this at the window level.
To address the larger issue, it seems that something is causing your images to be scaled in the first place:
Ensure you are setting the Stretch="None" option on the Image control,
Ensure that you are using SnapsToDeveicePixels or Layout rounding
Lastly if all else fails, explicitly set the width and height of the image.
I have also run into instances where the image file's DPI not being set to (I believe) 90, causes the renderer to apply scaling.

Unable to fix Screen Resolution for different devices like projector,monitor of asp.net projet

I am working on project in ASP.NET WEB APPLICATION in which I am having problem with screen Resolution. Whenever I connect my project execution to different devices like from laptop to monitor or to Projector, the fields, labels, drop down lists and other are randomly displaced on the screen. I want to have same display look irrespective of the device on which the out put is being seen. I have seen so many ways but I couldn't find the one which suits my scenario.I want to adjust the out put to be displayed in same way when the resolution is changed that is like from 1024*768 to 1280*1024, etc. I want the out put to be spread across the entire screen in same manner irrespective of the resolution.In the project the resolution for all the controls is declared in measure of pixels not on percentage based.I don't want to change pixels into percentage that makes me to change every where in the project but by keeping them as pixels I want to adjust the resolution whenever it is changed so that the controls will be evenly displaced. Please help me with this.
Set up a displacefactor, that displaces "objects" on x, and y axis by a value calculated from the resolution. I'd check if the "object" is on the left or the right side of the screen (by getting the width of the screen and if its bigger than the half then displacefactor is poisitive, if not then its negative, and you displace the object on the x axis), you can do that with the height so you can displace them on the y axis. I can't be more specific because i can't program C# nor javascript, but i hope you understand what i'm trying to explain.

Drawing a fading grid in WPF

I'm trying to draw a graph-paper like grid as the background of a Canvas. This grid is different from most explanations of how to do this that I've found because the canvas can be scaled to implement zooming. What I want to do is have a series of scales of grid lines, i.e. at every 10^n units. Then, the grid lines should fade out as they become close together due to zooming. In other words if n is large, the lines associated with that grid should be darker/heavier weight than those for a smaller n.
This was easy to do in WinForms, I implemented it by overriding OnPaint and defining the color of the line to be a function of the distance to the next grid line. Lines far apart were given a heavier weight than lines close together.
I have not figured out how to do this in WPF. I can sort of get this behavior by creating a line that has a StrokeThickness according to the spacing of the grid lines, but this only works for a small range of StrokeThickness and scaling values. It would work if it were possible to define a line as having a very heavy weight, but still a small StrokeThickness.
Even doing this via implementing a custom control with OnRender is difficult because I have not found a reliable way to get the scale of the control while rendering it (the ScaleTransform is part of one of the parent controls, not the immediate parent).
Any thoughts on how to accomplish this goal would be much appreciated!
I solved this by NOT adding the grid to the canvas but by stacking the canvas on top of another control that contains the grid:
<Grid>
<Canvas x:Name="GridLayer"/>
<Canvas x:Name="DrawingLayer" />
</Grid>
When zooming events occur I simply redraw the GridLayer.
This allowed me to only draw the lines that are needed, to draw them exactly how I want them and, in my case very important because I had potentially a gazillion grid lines, I did not need to draw the lines any longer/taller than needed. This way I conserved a lot of CPU time.
Another thing to note is that I implemented my own zoom code. I did not use a RenderTransform or a ViewBox because I wanted the line to stay at the same width. All I did was keep track of the coordinates of the top left corner to support panning and the zoomlevel. As soon as one of these changes I redraw the canvases. I wrote two functions: one transforms a coordinate on the Canvas to a graph coordinate and the other one does the reverse. The first method allows me to translate cursor coordinates to graph coordinates and the second one will turn the coordinates of the graph into points that can be used to draw on the canvas.
Untested code and making a lot of assumptions about the orientation of axis:
Point Graph2Canvas(Point graphPoint)
{
var canvasPoint = new Point(graphPoint);
canvasPoint.X *= zoomLevel;
canvasPoint.Y *= zoomLevel;
canvasPoint.X -= topLeft.X;
canvasPoint.Y -= topLeft.Y;
return canvasPoint;
}
This can be optimized and the truth is I created more functions that do the same thing for collections of points.
Extra:
I ended up with a far more complex setup that looked a bit like this:
<Grid>
<Canvas x:Name="BackgroundLayer"/>
<Canvas x:Name="GridLayer"/>
<Canvas x:Name="AxisLayer"/>
<Canvas x:Name="DrawingLayer" />
<Canvas x:Name="SelectionBoxLayer"/>
<Canvas x:Name="CursorLayer"/>
</Grid>

High CPU load when changing background image of Canvas containing overlay elements

I am working on an Application that loads live video images from a camera and displays an overlay on top of said image. The Overlay does not change often so it can be considered as still. However it usually contains about 1,000 to 10,000 Lines.
When the video image is updated there is a notable impact to the CPU load depending on whether the overlay is visible or not. The overlay does neither get invalidated nor changed, just the image behind it is changing.
My setup is this:
<Canvas>
<Image/>
<Canvas>
<OverlayElement 1/>
<OverlayElement 2/>
<OverlayElement 3/>
<.../>
</Canvas>
</Canvas>
The Image's Source is a WriteableBitmap. Every time a new camera image (type byte[]) is available, the main Canvas' Dispatcher is invoked to write the image data by using WriteableBitmap.WritePixels().
The inner Canvas contains all Overlay Elements, being
- a contour (PolyLine)
- a circle (Path with EllipseGeometry) and
- a set of Rays (Path with one Figure containing LineSgements).
The number n of Points in the contour equals the number of line Segments in the last mentioned Path. n is usually around 1,000 - 3,000.
Depending on the count and length of Lines shown in the overlay the CPU load for showing a live image varies (increases if length or count go up) even if the overlay does not change. At some point this affects the frame rate and makes the program unusable. Line length is mostly correlated with line intersection, so maybe the Path is struggling to calculate it's fill area despite it is not painted?
So how could I improve the performance here?
What bugs me most is that even if the overlay does not change, the render time increases with it's primitive count. I would expect to have constant render time once the overlay has been drawn in it's last set state. What could I do to achieve that aside from rendering the whole overlay to a bitmap?
I am also open minded for suggestions on how to get the byte[] onto the screen more efficiently. Just keep in mind this problem is part of a bigger Application and i cannot change all paradigms concentrating on how to get the image drawn.
What I have tried so far:
Override the OnRender() method of the inner Canvas, drawing the overlay myself. This works fine but has the performance issue that brings me here ;)
Use Shapes (PolyLine, Ellipse, Path) as the inner Canvas' children to hold the overlay elements. This works, too. It is faster to redraw the overlay when it changes but on the other hand worsens the performance issue when updating the background image.
Like 2., but use Freeze() on Geometries wherever possible. Has no or little performance impact.
Thanks for your help in advance.

Resolution Free Application

What is meant by the Resolution free application, As I have discussed it with many of my friend and they says that resolution free mean what ever resolution user want to see an application it should adjust it position, the resolultion is monitor resolution or any say 100 by 100 what is resolution?
Ideally, applications would use higher pixel densities to show more detail. For example, a high-resolution monitor could display similarly sized toolbar icons but use the extra pixels to render sharper graphics. That way you could keep the same basic layout but offer increased clarity and detail. For a variety of reasons, this solution hasn’t been possible in the past. Although you can resize graphical content that’s drawn with GDI/GDI+, User32 (which generates the visuals for common controls) doesn’t support true scaling.
WPF doesn’t suffer from this problem because it renders all user interface elements itself, from simple shapes to common controls such as buttons. As a result, if you create a button that’s 1 inch wide on your computer monitor, it can remain 1 inch wide on a high-resolution monitor—WPF will simply render it in greater detail and with more pixels.
WPF bases its scaling on the system DPI setting, not the DPI of your physical display device. It uses the system DPI setting when it calculates sizes.
WPF Units
A WPF window and all the elements inside it are measured using device-independent units. A single device-independent unit is defined as 1/96 of an inch. To understand what this means in practice, you’ll need to consider an example.
Imagine that you create a small button in WPF that’s 96 by 96 units in size. If you’re using the standard Windows DPI setting (96 dpi), each device-independent unit corresponds to one real, physical pixel. That’s because WPF uses this calculation:
[Physical Unit Size] = [Device-Independent Unit Size] × [System DPI]
= 1/96 inch × 96 dpi
= 1 pixel
Essentially, WPF assumes it takes 96 pixels to make an inch because Windows tells it that through the system DPI setting. However, the reality depends on your display device.
For example, consider a 20-inch LCD monitor with a maximum resolution of 1600 by 1200 pixels. Using a dash of Pythagoras, you can calculate the pixel density for this monitor, as shown here:
[Screen DPI] = ((Sqroot of)(1600*1600)+(1200*1200))pixels/19 inches = 100dpi
In this case, the pixel density works out to 100 dpi, which is slightly higher than what Windows assumes. As a result, on this monitor a 96-by-96-pixel button will be slightly smaller than 1 inch.
On the other hand, consider a 15-inch LCD monitor with a resolution of 1024 by 768. Here, the pixel density drops to about 85 dpi, so the 96-by-96 pixel button appears slightly larger than 1 inch.
In both these cases, if you reduce the screen size (say, by switching to 800 by 600 resolution), the button (and every other screen element) will appear proportionately larger. That’s because the system DPI setting remains at 96 dpi. In other words, Windows continues to assume it takes 96 pixels to make an inch, even though at a lower resolution it takes far fewer pixels.
Reference:
Pro WPF in C# 2008: Windows Presentation Foundation with .NET 3.5, Second Edition
WPF uses device-independent coordinates which means applications scale correctly and uniformly at different DPI settings.
Another very useful feature of WPF is the ViewBox which can be used to create a scalable application. Try the following.
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="300" Height="300">
<Viewbox Stretch="Uniform">
<Grid Width="300" Height="300">
<Button Content="Button" Margin="16,8,0,0"
Width="104" Height="32"
HorizontalAlignment="Left"
VerticalAlignment="Top" />
<CheckBox Content="CheckBox" Margin="136,8,0,0"
Width="112" Height="24"
HorizontalAlignment="Left" VerticalAlignment="Top" />
</Grid>
</Viewbox>
</Window>
This simple example is a little off cause of the window title bar and border but you get the idea. When this window is resized, the content scales uniformly so it looks the same at any resolution.
You can use WPF for your application. Every control that you create on a form will be the in different screen resolutions.
One of the main claimed benefits of WPF is “resolution independence”. Often this benefit is described in relatively vague terms leading people to believe that it means that the same WPF window will display on any monitor at the same size regardless of the resolution at which that monitor is set.
I think it means that the proportions should be the same, on different resolutions. It doesn't mean the application will resize its windows internally to adjust to the new resolution. But this is not universal.
Another very important thing to mention, is the context this is brought on. For example there are different expectations for a web application, which may change the layout or page size depending on the resolution. Video games, which may render things very differently depending on the screen resolution and aspect. And regular windows applications (GUI), which I already mentioned.

Categories