{"id":398,"date":"2013-01-03T21:03:26","date_gmt":"2013-01-03T10:03:26","guid":{"rendered":"http:\/\/blog.quppa.net\/?p=398"},"modified":"2013-01-03T21:03:26","modified_gmt":"2013-01-03T10:03:26","slug":"pixel-perfect-multi-dpi-images-in-wpf-part-1","status":"publish","type":"post","link":"https:\/\/www.quppa.net\/blog\/2013\/01\/03\/pixel-perfect-multi-dpi-images-in-wpf-part-1\/","title":{"rendered":"Pixel-perfect Multi-DPI Images in WPF (Part 1)"},"content":{"rendered":"<blockquote><p><a href=\"https:\/\/github.com\/Quppa\/PNGToMultiDPITIFF\" title=\"GitHub: PNGToMultiDPITIFF\">View source on GitHub.<\/a><\/p><\/blockquote>\n<p><i>See also: <a href=\"https:\/\/www.quppa.net\/blog\/2013\/01\/03\/pixel-perfect-multi-dpi-images-in-wpf-part-2\/\" title=\"Quppa's Blog: Pixel-perfect Multi-DPI Images in WPF (Part 2)\">Part 2<\/a> and <a href=\"https:\/\/www.quppa.net\/blog\/2013\/01\/04\/pixel-perfect-multi-dpi-images-in-wpf-part-3\/\" title=\"Quppa's Blog: Pixel-perfect Multi-DPI Images in WPF (Part 3)\">Part 3<\/a>.<\/i><\/p>\n<p>I\u2019ve <a title=\"Quppa&#39;s Blog: Pixel Measurements in WPF\" href=\"https:\/\/www.quppa.net\/blog\/2011\/01\/07\/pixel-measurements-in-wpf\/\">written previously<\/a> about DPI-awareness in the Windows Presentation Foundation and how to specify measurements in pixels rather than Device Independent Units (DIUs). Something else to consider is image scaling \u2013 unlike the <a title=\"MSDN: Specifying Ribbon Image Resources\" href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/dd316921(v=vs.85).aspx\">Windows Ribbon control<\/a> or <a title=\"Building 8: Scaling to different screens\" href=\"http:\/\/blogs.msdn.com\/b\/b8\/archive\/2012\/03\/21\/scaling-to-different-screens.aspx\">WinRT<\/a>, WPF has no in-built mechanism for displaying different images according to the system\u2019s DPI setting. This is a nuisance.<\/p>\n<p>To illustrate the problem, I created 5 images. Left-to-right, the image DPIs (vertical and horizontal) are: 72, 96, 120, 144 and 192. The image dimensions are: 32x32px, 32x32px, 40x40px, 48x48px and 64x64px. I purposely used single-pixel-wide lines to make any stretching obvious.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" title=\"Original Images\" style=\"margin: 5px auto; border: 0px currentcolor; float: none; display: block; background-image: none;\" border=\"0\" alt=\"Original Images\" src=\"https:\/\/www.quppa.net\/blog\/wp-content\/uploads\/original.png\" width=\"375\" height=\"69\" \/><\/p>\n<p>Read on to see what WPF does with these images.<\/p>\n<p><!--more--><\/p>\n<p>I created a simple application to display these images while varying certain properties. I present here screenshots of the application running at 96 DPI, 120 DPI, 144 DPI and 192 DPI.<\/p>\n<p>The code for the first row of images is:<\/p>\n<pre class=\"lang:c# decode:true \">&lt;Image Stretch=&quot;None&quot; \u2026 \/&gt;<\/pre>\n<p>The code for the second row of images is:<\/p>\n<pre class=\"lang:xaml decode:true \">&lt;Image Stretch=&quot;None&quot; RenderOptions.BitmapScalingMode=&quot;NearestNeighbour&quot; \u2026 \/&gt;<\/pre>\n<p>The code for the third row of images is:<\/p>\n<pre class=\"lang:xaml decode:true \">&lt;Image Stretch=&quot;None&quot; RenderOptions.BitmapScalingMode=&quot;NearestNeighbour&quot; SnapsToDevicePixels=&quot;True&quot; \u2026 \/&gt;<\/pre>\n<p>The code for the fourth row of images is:<\/p>\n<pre class=\"lang:xaml decode:true \">&lt;Image Stretch=&quot;None&quot; RenderOptions.BitmapScalingMode=&quot;NearestNeighbour&quot; SnapsToDevicePixels=&quot;True&quot; UseLayoutRounding=&quot;True&quot; \u2026 \/&gt;<\/pre>\n<p>The code for the fifth row of images is:<\/p>\n<pre class=\"lang:xaml decode:true \">&lt;Image Stretch=&quot;Uniform&quot; SnapsToDevicePixels=&quot;True&quot; UseLayoutRounding=&quot;True&quot; Width=&quot;32&quot; Height=&quot;32&quot; \u2026 \/&gt;<\/pre>\n<p>The code for the sixth row of images is:<\/p>\n<pre class=\"lang:xaml decode:true \">&lt;Image Stretch=&quot;Uniform&quot; RenderOptions.BitmapScalingMode=&quot;NearestNeighbour&quot; SnapsToDevicePixels=&quot;True&quot; UseLayoutRounding=&quot;True&quot; Width=&quot;32&quot; Height=&quot;32&quot; \u2026 \/&gt;<\/pre>\n<h1>96 DPI<\/h1>\n<p><a href=\"https:\/\/www.quppa.net\/blog\/wp-content\/uploads\/96-grid.png\"><img loading=\"lazy\" decoding=\"async\" title=\"96 DPI\" style=\"margin: 5px auto; border: 0px currentcolor; float: none; display: block; background-image: none;\" border=\"0\" alt=\"96 DPI\" src=\"https:\/\/www.quppa.net\/blog\/wp-content\/uploads\/96-grid_thumb.png\" width=\"375\" height=\"345\" \/><\/a><\/p>\n<h1>120 DPI<\/h1>\n<p><a href=\"https:\/\/www.quppa.net\/blog\/wp-content\/uploads\/120-grid.png\"><img loading=\"lazy\" decoding=\"async\" title=\"120 DPI\" style=\"margin: 5px auto; border: 0px currentcolor; float: none; display: block; background-image: none;\" border=\"0\" alt=\"120 DPI\" src=\"https:\/\/www.quppa.net\/blog\/wp-content\/uploads\/120-grid_thumb.png\" width=\"462\" height=\"435\" \/><\/a><\/p>\n<h1>144 DPI<\/h1>\n<p><a href=\"https:\/\/www.quppa.net\/blog\/wp-content\/uploads\/144-grid.png\"><img loading=\"lazy\" decoding=\"async\" title=\"144 DPI\" style=\"margin: 5px auto; border: 0px currentcolor; float: none; display: block; background-image: none;\" border=\"0\" alt=\"144 DPI\" src=\"https:\/\/www.quppa.net\/blog\/wp-content\/uploads\/144-grid_thumb.png\" width=\"554\" height=\"521\" \/><\/a><\/p>\n<h1>192 DPI<\/h1>\n<p><a href=\"https:\/\/www.quppa.net\/blog\/wp-content\/uploads\/192-grid.png\"><img loading=\"lazy\" decoding=\"async\" title=\"192 DPI\" style=\"margin: 5px auto; border: 0px currentcolor; float: none; display: block; background-image: none;\" border=\"0\" alt=\"192 DPI\" src=\"https:\/\/www.quppa.net\/blog\/wp-content\/uploads\/192-grid_thumb.png\" width=\"742\" height=\"699\" \/><\/a><\/p>\n<h1>Discussion<\/h1>\n<p>If you want pixel-perfect bitmap images in your WPF application, the two important properties are \u2018UseLayoutRounding\u2019 and \u2018SnapsToDevicePixels\u2019. I recommend setting both of these to \u2018true\u2019 on your Window; you can disable them for specific child elements if necessary. RenderOptions.BitmapScalingMode can be set to \u2018NearestNeighbour\u2019 when you have an image designed for the current DPI. If no such image is available, you should set it to one of <a title=\"MSDN: BitmapScalingMode Enumeration\" href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.windows.media.bitmapscalingmode.aspx\">LowQuality, Linear (the default), HighQuality or Fant<\/a> for a better result when scaling is necessary.<\/p>\n<p>Notice that when the width and height is not set explicitly, the 72 DPI 32x32px image is scaled to about 43x43px when running at 96 DPI. Be careful with tools like <a title=\"PNGOUT\" href=\"http:\/\/advsys.net\/ken\/utils.htm\">PNGOUT<\/a> (and the great Windows GUI <a title=\"PNGGauntlet\" href=\"http:\/\/pnggauntlet.com\/\">PNGGauntlet<\/a>), as they will strip out DPI\/PPI information, <a title=\"Scott Hanselman: Be Aware of DPI with Image PNGs in WPF - Images Scale Weird or are Blurry\" href=\"http:\/\/www.hanselman.com\/blog\/BeAwareOfDPIWithImagePNGsInWPFImagesScaleWeirdOrAreBlurry.aspx\">causing WPF to scale your images when you\u2019d not expect it to<\/a>.<\/p>\n<p>In the next part, I\u2019ll describe my solution to displaying different images at different DPIs.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>View source on GitHub. See also: Part 2 and Part 3. I\u2019ve written previously about DPI-awareness in the Windows Presentation Foundation and how to specify measurements in pixels rather than Device Independent Units (DIUs). Something else to consider is image scaling \u2013 unlike the Windows Ribbon control or WinRT, WPF has no in-built mechanism for &hellip; <a href=\"https:\/\/www.quppa.net\/blog\/2013\/01\/03\/pixel-perfect-multi-dpi-images-in-wpf-part-1\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Pixel-perfect Multi-DPI Images in WPF (Part 1)&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,9],"tags":[48,68,102,123,171,185],"class_list":["post-398","post","type-post","status-publish","format-standard","hentry","category-programming","category-windows","tag-dpi","tag-images","tag-ppi","tag-scaling","tag-windows-2","tag-wpf"],"_links":{"self":[{"href":"https:\/\/www.quppa.net\/blog\/wp-json\/wp\/v2\/posts\/398","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.quppa.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.quppa.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.quppa.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.quppa.net\/blog\/wp-json\/wp\/v2\/comments?post=398"}],"version-history":[{"count":0,"href":"https:\/\/www.quppa.net\/blog\/wp-json\/wp\/v2\/posts\/398\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.quppa.net\/blog\/wp-json\/wp\/v2\/media?parent=398"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.quppa.net\/blog\/wp-json\/wp\/v2\/categories?post=398"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.quppa.net\/blog\/wp-json\/wp\/v2\/tags?post=398"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}