Help me snap to device pixels...

Why can't I get SnapsToDevicePixels to work

<Window x:Class="WindowsApplication1.Window1"
xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowsApplication1" Height="300" Width="300" SnapsToDevicePixels="True">
<Grid SnapsToDevicePixels="True">
<ScrollViewer Background="Black" HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto" SnapsToDevicePixels="True">
<Image Source="checkerboard.bmp" HorizontalAlignment="Center"
VerticalAlignment="Center" SnapsToDevicePixels="True"/>
</ScrollViewer>
</Grid>
</Window>

Here's a sample project if you want to see what I mean:

http://www.upload2.net/page/download/xzMiYdJqCsk3Efe/SimpleExample.zip.html



Answer this question

Help me snap to device pixels...

  • Michael W.

    I don't think there is a good way to do this. WPF does snap the image geometry to the device pixels, producing a rectangle which is snapped. However, the location of the image itself does not get snapped. This is a little confusing, so I'll say it another way. This snapped rectangle is drawn internally with an unsnapped image brush, producing a blurry image.

    One of the ways you can make more use of pixel snapping is to use geometry to describe your content instead of bitmaps. In your example, that might mean replacing your checkerboard bitmap with a DrawingImage that describes the checkerboard.

    This issue does come up now and again. I'm sorry not to have a better workaround. We will be looking at improving this in the future.

    -Miles


  • xx-Cougar-xx

    In WPF, images have both an ImageWidth/Height and a PixelWidth/Height. [I'll drop the word "Height" from the future of this post.] PixelWidth is what people are used to, coming from platforms other than WPF. It is measured in pixels. ImageWidth on the other hand is measured in inches (technically 1/96th of an inch). So when you ask that an image be placed in a certain location without stretching, the thing that WPF doesn't stretch is the number of inches that the image takes up. The pixels in the underlying bitmap can still be stretched to make this work.

    For a screen capture tool, I think you'd want to ensure that the BitmapImage DPI is the same as the DPI of the monitor. I've never done this from managed code, but I trust that it is possible. If your BitmapImage DPI is the same as the display, then this should mean that your image is not stretched.

    Now... if you know the DPI of the display you are targeting* as it looks like you will, you can work around some of the Image centering issues. The reason the images look blurry is not because they are centered, but because they are not positioned exactly on a pixel boundary. So, if you can change the size of the element that the image is centered within, this can allow the image to be centered and not-blurry. If you have an even number of pixels in the bitmap, you should make sure the element it is cenered within also has an even number of pixels. And if there are an odd number of pixels in the bitmap, the element it is within must be odd. If you can dynamically change the size of your elements based on DPI, you might be able to achieve this... though this will mean responding to mode changes if you really want to get it right.

    But image centering is not the only thing that can cause an image to be unaligned. If you position an image at the top left of another element, but that element is positioned, say 5/96ths of an inch from the left side of the window, this will mean that your image will be aligned to device pixels on a 96 DPI monitor, but on a 120 DPI monitor it will not be aligned. Turning on pixel snapping here again won't help. You'd need to change the location of the element based on DPI and this is something WPF does not do. Pixel snapping instead just moves the geometry that the element internally draws itself with.

    * A thing to watch for: Part of the problem with knowing the DPI and making decisions based on it is that a system can have multiple displays, each with a different DPI. This is a nasty situation to account for, and WPF doesn't handle it perfectly itself today. Nevertheless, know that it can happen, and be aware that you may need to add extra fudge if you want to try and support this scenario.


  • Johnson Road

    Thanks, I'll keep that in mind. With my current set of images, the blur is very noticeable -- distracting even. I suppose in the long run, the best solution will be to convert these over to vector graphics.
  • Rebecca23

    Nope. I want each bitmap pixel to align with a hardware pixel. My images are bigger. This was just a trivial sample. However, if I set the alignment to top, left it works fine. But when it's centered SnapToDevicePixels doesn't force the pixels to align with hardware pixels.
  • danielo1

    I'm sorry to say that there is no way to prevent your bitmap images from getting blurry when using relative positioning. I'd suggest authoring your bitmap images such that they don't have really high frequencies in them (such as thin lines or checker patterns). This will cut down on the amount of noticeable blur on 96dpi displays, and it will allow your app to scale better at other DPIs.

  • NorbertHH

    I've run into a similar problem. Like most applications of today, I have various bitmap images used in my application for toolbar and button icons. Even with SnapToDevicePixels enabled the whole way up the visual tree, I still get a blurry image unless I use absolute positioning. Using a StackPanel, Grid, etc. apparently shifts the image just enough that it's off the pixel boundary. How can I take advantage of the relative positioning of StackPanel, etc. and still render pixel perfect images
  • Ajeeth Kumar

    To completely answer the questions posed in this thread, Miles and Anthony put together a great post explaining the details of how to best place an image in WPF:

    http://blogs.msdn.com/seema/archive/2006/11/07/why-do-my-bitmaps-look-blurry-by-anthony-hodsdon-miles-cohen.aspx

    Best, SeemaR



  • Jayson Speer

    Wow, I've got to admit I'm surprised there's no approach for this. I created the checkerboard bitmap simply because it illustrates the point. In reality, my app is doing screen captures (like the Vista snipping tool). If the pixels don't align with hardware pixels, then it really looks bad. I guess for now, I'll just have to align it with the top left corner. Unfortunately, that screws up the visual balace of the containing Window.

    Perhaps you could help me address another related issue... When I change my dpi setting to anything other than 96, I get stretching problems. I understand why that's happening, and it makes sense. However, I can't figure out how to programmatically get Window's dpi setting in order to apply the appropriate transformation.

    I realize the rationale for device independent pixels and I absolutely love the way the vector compositing works. However, putting bitmaps in applications, either as the content of an image viewer control or as part of the UI, isn't going away anytime soon. The Vista shell, including apps like WMP 11, are still bitmap based. It's surprising that it's somewhat difficult to work with bitmaps in WPF. I guess I was anticipating better interoperability between vector and raster functionality in the framework. Just giving an Image control a ForceBitmapPixelsToHardwarePixels property would be a huge help.


  • Sandhya

    Its likely that you want to use the "Stretch" property on the alignment.
  • Help me snap to device pixels...