I am adding Image instances to a Canvas in Windows Runtime environment and my image keeps getting scaled up when in 140 and 180 scale resolution displays, it looks perfect in scale resolution 100. I tried creating 3 PNG images, one for each scale size: 100, 140, 180 but it still scales them up and they look blurry. I created a test image with 4 black pixels on a cyan background and I took a screenshot from the simulator, see how the image is blurry, my original image has just 4 perfect black pixels:
I tried changing the stretch mode of my Image objects, but it does nothing. I'm using this code to add the images at runtime:
var bitmapImage = new BitmapImage();
StorageFile bitmapFile = await StorageFile.GetFileFromApplicationUriAsync(imageUri);
await bitmapImage.SetSourceAsync(await bitmapFile.OpenReadAsync());
Image image = new Image{ Source = bitmapImage};
image.SetValue(Canvas.LeftProperty, x);
image.SetValue(Canvas.TopProperty, y);
canvas.Children.Add(image);
How do I get the images to draw pixel perfectly in the canvas without scaling and at the exact x/y coordinates I want?
I think I have a workaround, but it requires two steps:
First I have to load the image using a more a standard way that doesn't involve getting the file path like so.
var bitmapImage = new BitmapImage(imageUri);
Somehow this must retain more information internally that this image came from a file with the corresponding ResolutionScale for the current display. Thus when it is drawn by the canvas it is not scaled at all. However this only solves half the problem.
The next problem is that the x, y coordinates used to specify where the image is drawn are being scaled so the image is drawn in the wrong place, further than where I wanted. The only thing I can figure to do is unscale them first like so:
var resScale = DisplayInformation.GetForCurrentView().ResolutionScale;
Image image = new Image{ Source = bitmapImage};
image.SetValue(Canvas.LeftProperty, (x * 100.0) / (int)resScale);
image.SetValue(Canvas.TopProperty, (y * 100.0) / (int)resScale);
canvas.Children.Add(image);
The whole thing seems a bit crazy but it seems to work so far... Anyone have a better solution or an explanation why all this is necessary? Seems like the Canvas class needs an unscaled mode that doesn't mess with the images or coordinates across different resolution displays.
UPDATE: This doesn't work perfectly, using a double to store the value results in precision loss and sometimes there are anti-aliasing artifacts. This is not acceptable if you want pixel perfect graphics. I am still looking for a perfect solution.
There are a few more things that might help with your solution.
UseLayoutRounding="False"
on your image.Canvas
in a full-screen Viewbox
, then set the Canvas
Width
and Height
to the screen resolution. You'd use unscaled Canvas.Left
/Top
values in this case.Good luck.
You can change the Stretch
property to "None"
, If you image is still meshed-up:
You should look at what DPI it is saved on. WPF tries to be DPI-independend, so it tries to draw an image of 5"x5" on every monitor the same size. Even when the resolution is higher, it still should be 5"x5" only a high resolution would render(rasterize) the image in higher quality.
Here's some info: http://www.wpflearningexperience.com/?p=41
How do I convert a WPF size to physical pixels?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With