{"id":28993,"date":"2006-11-15T10:00:01","date_gmt":"2006-11-15T10:00:01","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2006\/11\/15\/manipulating-the-dib-color-table-for-fun-and-profit\/"},"modified":"2006-11-15T10:00:01","modified_gmt":"2006-11-15T10:00:01","slug":"manipulating-the-dib-color-table-for-fun-and-profit","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20061115-01\/?p=28993","title":{"rendered":"Manipulating the DIB color table for fun and profit"},"content":{"rendered":"<p>\nIf you create a DIB section at 8bpp or lower,\nthen it will come with a color table.\nPixels in the bitmap are represented not by their red\/blue\/green\ncomponent values, but are instead indices into the color table.\nFor example, a 4bpp DIB section can have up to sixteen colors in\nits color table.\n<\/p>\n<p>\nAlthough displays that use 8bpp or lower are considered\nwoefully outdated nowadays,\nbitmaps in that format are actually quite useful\nprecisely due to the fact that you can manipulate colors\nin the bitmap, not by manipulating the bits themselves, but instead\nby manipulating the color table.\n<\/p>\n<p>\nLet&#8217;s demonstrate this by taking the &#8220;Gone Fishing&#8221; bitmap\nand converting it to grayscale.\nStart with our\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2003\/07\/23\/54576.aspx\">\nscratch program<\/a> and make these changes:\n<\/p>\n<pre>\n<font COLOR=\"blue\">HBITMAP g_hbm;<\/font>\nBOOL\nOnCreate(HWND hwnd, LPCREATESTRUCT lpcs)\n{\n <font COLOR=\"blue\">\/\/ change path as appropriate\n g_hbm = (HBITMAP)LoadImage(g_hinst,\n                      TEXT(\"C:\\\\Windows\\\\Gone Fishing.bmp\"),\n                      IMAGE_BITMAP, 0, 0,\n                      LR_CREATEDIBSECTION | LR_LOADFROMFILE);\n if (g_hbm) {\n  HDC hdc = CreateCompatibleDC(NULL);\n  if (hdc) {\n   HBITMAP hbmPrev = SelectBitmap(hdc, g_hbm);\n   RGBQUAD rgbColors[256];\n   UINT cColors = GetDIBColorTable(hdc, 0, 256, rgbColors);\n   for (UINT iColor = 0; iColor &lt; cColors; iColor++) {\n    BYTE b = (BYTE)((30 * rgbColors[iColor].rgbRed +\n                     59 * rgbColors[iColor].rgbGreen +\n                     11 * rgbColors[iColor].rgbBlue) \/ 100);\n    rgbColors[iColor].rgbRed = b;\n    rgbColors[iColor].rgbGreen = b;\n    rgbColors[iColor].rgbBlue = b;\n   }\n   SetDIBColorTable(hdc, 0, cColors, rgbColors);\n   SelectBitmap(hdc, hbmPrev);\n   DeleteDC(hdc);\n  }\n }<\/font>\n return TRUE;\n}\nvoid\nOnDestroy(HWND hwnd)\n{\n <font COLOR=\"blue\">if (g_hbm) DeleteObject(g_hbm);<\/font>\n PostQuitMessage(0);\n}\nvoid\nPaintContent(HWND hwnd, PAINTSTRUCT *pps)\n{\n <font COLOR=\"blue\">if (g_hbm) {\n  HDC hdc = CreateCompatibleDC(NULL);\n  if (hdc) {\n   HBITMAP hbmPrev = SelectBitmap(hdc, g_hbm);\n   BITMAP bm;\n   if (GetObject(g_hbm, sizeof(bm), &amp;bm) == sizeof(bm)) {\n    BitBlt(pps-&gt;hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdc, 0, 0, SRCCOPY);\n   }\n   SelectBitmap(hdc, hbmPrev);\n   DeleteDC(hdc);\n  }\n }<\/font>\n}\n<\/pre>\n<p>\nThe <code>OnDestroy<\/code> function merely cleans up, and the\n<code>PaintContent<\/code> function simply draws the bitmap to\nthe window&#8217;s client area.\nAll the work really happens in the <code>OnCreate<\/code> function.\n<\/p>\n<p>\nFirst, we load the bitmap as a DIB section by passing the\n<code>LR_CREATEDIBSECTION<\/code> flag.\nThis opens up the exciting world of DIB sections,\nbut all we care about is the color table.\nThat happens when we call <code>GetDIBColorTable<\/code>.\nSince color tables are supported only up to 8bpp,\na color table of size 256 is big enough to handle the worst case.\nOnce we get the color table, we go through each color in it\nand convert it to grayscale,\nthen set the new color table into the DIB section.\nThat&#8217;s all.\n<\/p>\n<p>\nNotice that we were able to change the color of every single\npixel in the bitmap by modifying just 1KB of data.\n(Four bytes per <code>RGBQUAD<\/code> times a worst-case of\n256 colors.)\nEven if the bitmap were 1024&nbsp;&times;&nbsp;768,\nmodifying just the color table is enough to change all the colors\nin the bitmap.\n<\/p>\n<p>\nManipulating the DIB color table is how flags like\n<code>LR_LOADMAP3DCOLORS<\/code> and <code>LR_LOADTRANSPARENT<\/code>\ndo their work.\nThey don&#8217;t walk the bitmap updating every single pixel;\ninstead, they just load the color table,\nlook for the colors they are interested in, and change\nthat entry in the color table.\nThis technique of editing the color table is\n<!-- backref: raster ops -->\nwhat I was referring to<\/a>\nwhen I suggested you could use DIB sections to\navoid the pesky DSna raster operation.\nAnd it&#8217;s faster, too.\nBut it only works on bitmaps that are 8bpp or lower.\n<\/p>\n<p>\nYou may also have noticed that <code>LR_LOADTRANSPARENT<\/code>\ndoesn&#8217;t actually load a transparent bitmap.\nRather, it loads a bitmap that <strong>appears to be<\/strong>\ntransparent provided that you draw it against a window whose color\nis <code>COLOR_WINDOW<\/code>.\nWhy this misleading name?\nBecause at the time this flag was invented,\nGDI didn&#8217;t support transparent bitmaps.\n(And even today, it still doesn&#8217;t really support then,\nwith the notable exception of functions like <code>AlphaBlend<\/code>.)\nThe best you could do was fake it.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you create a DIB section at 8bpp or lower, then it will come with a color table. Pixels in the bitmap are represented not by their red\/blue\/green component values, but are instead indices into the color table. For example, a 4bpp DIB section can have up to sixteen colors in its color table. Although [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-28993","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>If you create a DIB section at 8bpp or lower, then it will come with a color table. Pixels in the bitmap are represented not by their red\/blue\/green component values, but are instead indices into the color table. For example, a 4bpp DIB section can have up to sixteen colors in its color table. Although [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/28993","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=28993"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/28993\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=28993"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=28993"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=28993"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}