{"id":1524,"date":"2013-06-28T03:25:24","date_gmt":"2013-06-28T03:25:24","guid":{"rendered":"http:\/\/www.gssezisoft.com\/main\/?p=1524"},"modified":"2015-02-02T04:47:56","modified_gmt":"2015-02-02T04:47:56","slug":"setting-the-dpi-resolution-of-a-bitmap-file","status":"publish","type":"post","link":"http:\/\/www.gssezisoft.com\/main\/2013\/06\/setting-the-dpi-resolution-of-a-bitmap-file\/","title":{"rendered":"Setting the DPI Resolution of a Bitmap file"},"content":{"rendered":"<p>Setting the DPI resolution of a bitmap file isn&#8217;t hard. Many programs already do it. It is frustrating that some don&#8217;t.<\/p>\n<p>Here&#8217;s a way to fix that.<\/p>\n<p><!--more--><\/p>\n<h2>Background<\/h2>\n<p>The early versions of <a title=\"CmdTwain\" href=\"http:\/\/www.gssezisoft.com\/main\/product\/cmdtwain\/\">CmdTwain<\/a> used a library to save scans as bitmap files (*.bmp) or as JPEG files (*.jpg). The program worked really well but one user drew my attention to the &#8220;dots per inch&#8221; (DPI) value in the saved files. It didn&#8217;t matter whether he scanned at 200 DPI or 300 DPI, the scans were always being reported as 96 DPI. The 300 DPI resolution scan was bigger (more pixels) than the 200 DPI resolution one for the same page but instead of the page size being reported as the same, the page size was supposedly bigger. Windows scales images to fit on a printed page so mostly it didn&#8217;t matter. But it was wrong.<\/p>\n<p>Sometimes you scan a document and it prints back out at a fraction of the size. It looks crazy. It used to frustrate me and, in my day job, I was using other people&#8217;s expensive scanning software and having these problems. I could certainly understand a user&#8217;s frustration with CmdTwain getting this wrong.<\/p>\n<p>The fix to CmdTwain is incidental to this article. It was the catalyst but this article is broader than CmdTwain. (If you are only using CmdTwain 1.02 or later, you don&#8217;t need to read this article.)<\/p>\n<h2>Solution<\/h2>\n<p>If the DPI resolution of a bmp file from another program is wrong and you want to fix it, you can use <a href=\"http:\/\/www.gssezisoft.com\/download\/CmdTwain\/get_dpi.zip\">get_dpi<\/a> to check the file and <a href=\"http:\/\/www.gssezisoft.com\/download\/CmdTwain\/set_dpi.zip\">set_dpi<\/a> to change it.<\/p>\n<p>Both of these links are to ZIP files containing a program and a Borland C runtime DLL. Their use is straight forward:<\/p>\n<ul>\n<li>Download them.<\/li>\n<li>Extract the files to a suitable location (eg somewhere in your PATH, C:\\TEST, or even &#8211; after checking you&#8217;re not overwriting anything &#8211; C:\\WINDOWS).<\/li>\n<li>Copy the file you want to check \/ fix into the same directory.<\/li>\n<li>Run up a DOS prompt (Start, Run, cmd).<\/li>\n<li>get_dpi file.bmp<\/li>\n<li>set_dpi file.bmp 300<\/li>\n<\/ul>\n<p>&#8220;get_dpi&#8221; will tell you the current DPI resolution.<br \/>\n&#8220;set_dpi&#8221; will change it.<\/p>\n<h2>What it Looks Like<\/h2>\n<p>When run, they look like this:<\/p>\n<pre>\r\nC:\\Test2&gt;get_dpi\r\nGet_dpi Ver 1.00\r\nCopyright (c) 2013 GssEzisoft\r\n\r\nUsage: get_dpi filename.{jpg|jpeg|bmp}\r\n\r\nC:\\Test2&gt;get_dpi 67.bmp\r\nx= 400 DPI, y= 400 DPI\r\n\r\nC:\\Test2&gt;set_dpi\r\nSet_dpi Ver 1.00\r\nCopyright (c) 2013 GssEzisoft\r\n\r\nUsage: set_dpi filename.{jpg|jpeg|bmp} xDPI [yDPI]\r\neg1  : set_dpi fred.jpg 300\r\neg2  : set_dpi demo.bmp 300 400\r\n\r\nC:\\Test2&gt;set_dpi 67.bmp 300\r\n\r\nC:\\Test2&gt;get_dpi 67.bmp\r\nx= 300 DPI, y= 300 DPI\r\n\r\nC:\\Test2&gt;\r\n<\/pre>\n<h2>Unspecified DPI<\/h2>\n<p>When you run get_dpi on a bitmap file which doesn&#8217;t have DPI set at all, you&#8217;ll see 0 for the values. Shockingly, the fastest way to get an incorrect bitmap like this &#8211; is to use MS Paint.<\/p>\n<p>The result looks like:<\/p>\n<pre>\r\nC:\\Test2&gt;get_dpi 20x20-red.bmp\r\nx= 0 DPI, y= 0 DPI\r\n\r\nC:\\Test2&gt;\r\n<\/pre>\n<p>Windows (right-click the file, properties) will say 96 DPI:<br \/>\n<a href=\"http:\/\/www.gssezisoft.com\/main\/wp-content\/uploads\/2013\/06\/bitmap-file-properties-with-zero-dpi.png\"><img loading=\"lazy\" src=\"http:\/\/www.gssezisoft.com\/main\/wp-content\/uploads\/2013\/06\/bitmap-file-properties-with-zero-dpi.png\" alt=\"bitmap-file-properties-with-zero-dpi\" width=\"367\" height=\"509\" class=\"alignnone size-full wp-image-1532\" srcset=\"http:\/\/www.gssezisoft.com\/main\/wp-content\/uploads\/2013\/06\/bitmap-file-properties-with-zero-dpi.png 367w, http:\/\/www.gssezisoft.com\/main\/wp-content\/uploads\/2013\/06\/bitmap-file-properties-with-zero-dpi-108x150.png 108w, http:\/\/www.gssezisoft.com\/main\/wp-content\/uploads\/2013\/06\/bitmap-file-properties-with-zero-dpi-216x300.png 216w\" sizes=\"(max-width: 367px) 100vw, 367px\" \/><\/a><br \/>\nThe &#8220;96&#8221; is a made-up value based on typical DPI sizes for typical devices and on Windows not wanting to say zero. Let&#8217;s be polite and call it a default number.<\/p>\n<h2>Under the Hood<\/h2>\n<p>Bail out now if you&#8217;re not technical.<\/p>\n<p>Internally, a bitmap file looks like this:<\/p>\n<pre>\r\n000000: 42 4D A6 0D 13 00 00 00  00 00 36 00 00 00 28 00 BM........6...(.\r\n000010: 00 00 F6 01 00 00 3C 03  00 00 01 00 18 00 00 00 ......<.........\r\n000020: 00 00 70 0D 13 00 23 2E  00 00 23 2E 00 00 00 00 ..p...#...#.....\r\n000030: 00 00 00 00 00 00 FF FF  FF FF FF FF FF FF FF FF ................\r\n000040: FF FF FF FF FF FF FF FF  FF FF FF FF FF FF FF FF ................\r\n000050: FF FF FF FF FF FF FF FF  FF FF FF FF FF FF FF FF ................\r\n<\/pre>\n<p>The structure is:<\/p>\n<pre>\r\ntypedef struct tagBITMAPFILEHEADER {\r\n00:  WORD  bfType;\r\n02:  DWORD bfSize;\r\n06:  WORD  bfReserved1;\r\n08:  WORD  bfReserved2;\r\n0a:  DWORD bfOffBits;\r\n} BITMAPFILEHEADER, *PBITMAPFILEHEADER;\r\n<\/pre>\n<p>A BITMAPINFO or ... structure immediately follows the BITMAPFILEHEADER structure in the DIB file. <\/p>\n<pre>typedef struct tagBITMAPINFO {\r\n0e:  BITMAPINFOHEADER bmiHeader;\r\n     RGBQUAD          bmiColors[1];\r\n} BITMAPINFO, *PBITMAPINFO;\r\n\r\ntypedef struct tagBITMAPINFOHEADER {\r\n0e:  DWORD biSize;\r\n12:  LONG  biWidth;\r\n16:  LONG  biHeight;\r\n1a:  WORD  biPlanes;\r\n1c:  WORD  biBitCount;\r\n1e:  DWORD biCompression;\r\n22:  DWORD biSizeImage;\r\n26:  LONG  biXPelsPerMeter; <<<<<<<<<<<<<<<<<\r\n2a:  LONG  biYPelsPerMeter; <<<<<<<<<<<<<<<<<\r\n     DWORD biClrUsed;\r\n     DWORD biClrImportant;\r\n} BITMAPINFOHEADER, *PBITMAPINFOHEADER;\r\n<\/pre>\n<p>So:<\/p>\n<pre>\r\nfile[00..01] = \"BM\" (bfType)\r\nfile[02..05] = 0013 0DA6 = 1248678\r\n             = 502 w x 828 h x 3 bytes per pixel (24bit RGB)\r\nfile[0e..11] = 0000 0028 = 40 = biSize\r\nfile[12..15] = 0000 01F6 = 502 = biWidth\r\nfile[16..19] = 0000 033C = 828 = biHeight\r\nfile[26..29] = 0000 2E23 = 11811 = biXPelsPerMeter\r\n             = 118.11 pixels per cm\r\n             = 299.9994 pixels per inch (1 inch = exactly 2.54 cm)\r\n               Windows displays this as 299.\r\nfile[2a..2d] = same\r\n<\/pre>\n<p>See <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/dd183374(v=vs.85).aspx\">MSDN<\/a> or wingdi.h for the structure details. <\/p>\n<p>Reading or writing the DPI resolution for a bitmap file is simply a matter of reading or writing 4 bytes at offsets 0x26 and 0x2a of the file.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Setting the DPI resolution of a bitmap file isn&#8217;t hard. Many programs already do it. It is frustrating that some don&#8217;t. Here&#8217;s a way to fix that.<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[40],"tags":[],"_links":{"self":[{"href":"http:\/\/www.gssezisoft.com\/main\/wp-json\/wp\/v2\/posts\/1524"}],"collection":[{"href":"http:\/\/www.gssezisoft.com\/main\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.gssezisoft.com\/main\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.gssezisoft.com\/main\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"http:\/\/www.gssezisoft.com\/main\/wp-json\/wp\/v2\/comments?post=1524"}],"version-history":[{"count":0,"href":"http:\/\/www.gssezisoft.com\/main\/wp-json\/wp\/v2\/posts\/1524\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.gssezisoft.com\/main\/wp-json\/wp\/v2\/media?parent=1524"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.gssezisoft.com\/main\/wp-json\/wp\/v2\/categories?post=1524"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.gssezisoft.com\/main\/wp-json\/wp\/v2\/tags?post=1524"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}