{"id":2444,"date":"2016-12-28T23:15:35","date_gmt":"2016-12-29T07:15:35","guid":{"rendered":"http:\/\/pididu.com\/wordpress\/?p=2444"},"modified":"2016-12-28T23:15:35","modified_gmt":"2016-12-29T07:15:35","slug":"save-client-area-of-a-window-to-png-file","status":"publish","type":"post","link":"http:\/\/pididu.com\/wordpress\/blog\/save-client-area-of-a-window-to-png-file\/","title":{"rendered":"Save Client Area of a Window to PNG File"},"content":{"rendered":"<p>This is offered to anyone who might be able to use it. \u00a0It&#8217;s plain c code to write the contents of a Microsoft window (from a win32 app) to a png file. \u00a0pnglib provides all the primitives necessary, but I&#8217;ve put it all together into one simple function.<\/p>\n<p style=\"padding-left: 30px;\"><a href=\"http:\/\/pididu.com\/wordpress\/wp-content\/uploads\/2016\/12\/ClientToPng-Source.zip\">ClientToPng Source (2.7k)<\/a><\/p>\n<p style=\"padding-left: 30px;\"><a href=\"http:\/\/pididu.com\/wordpress\/wp-content\/uploads\/2016\/12\/ClientToPng-Precompiled.zip\">ClientToPng Precompiled (665k)<\/a><\/p>\n<p>The first file above contains the source (shown at the end of this article) if you want to compile it yourself. This is the most reliable way of making it work, but requires that you have a static libpng.lib available to link to. Instructions on how to do that are <a title=\"how to compile libpng\" href=\"http:\/\/pididu.com\/wordpress\/blog\/compile-libpng-as-a-static-library-for-windows-with-visual-studio-2010-express\/\" target=\"_blank\">here<\/a>.<\/p>\n<p>The second file includes a precompiled static library. It has the kitchen sink in it, so is almost 2 MB when unzipped. However, the only function you will need to call is ClientToPng(), which will add perhaps 100k to the size of your program. You will need to include ClientToPng.h at the top of your program, then make a call something like this:<\/p>\n<pre>#define OUTSTR_LEN 255\r\nlong status;\r\nTCHAR OutString[OUTSTR_LEN];\r\n\r\n\/\/ handle of window to save, filename to save to\r\n<span style=\"color: #00ff00;\">status = SaveClientAreaToPng(hWnd, L\"filename.png\")<\/span>;\r\n\r\n\/\/ the status returned is a standard Windows error\r\nif (status != NO_ERROR) {\r\n    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, status, 0,\r\n        OutString1, OUTSTR_LEN, NULL);\r\n    MessageBox(hWndMain, OutString1, TEXT(\"Error\"),\r\n        MB_ICONINFORMATION);\r\n}<\/pre>\n<p>You would then link ClientToPng.lib to your program. Although this is theoretically simple, there could be complications if settings that ClientToPng.lib were complied with do not match those of your program. In particular, this library was compiled for x86 (not x64) code, non-debug, non-runtime-dll, under Microsoft Visual Studio 2010 Express. If you need other settings, you&#8217;ll have to recompile the source yourself, linking to libpng.lib .<\/p>\n<p>Here is the source. \u00a0There were a few parts that were tricky.<\/p>\n<ul>\n<li>The buffer size for retrieving pixels from a Microsoft bitmap must be a whole number of strides.<\/li>\n<li>The rows in Microsoft bitmaps go from the bottom up, in PNG, they go from the top down.<\/li>\n<li>Colors are represented as BGR from Microsoft, and stored as RGB for PNG files.<\/li>\n<\/ul>\n<pre>#include \"StdAfx.h\"\r\n#include \"png.h\"\r\n#include \"ClientToPng.h\"\r\n\r\n\/\/ Save client area of supplied hWnd to filename.png\r\n\/\/ Warning!  filename is probably a WCHAR string, depending on compiler settings\r\n\/\/ Assumptions:\r\n\/\/ 1) Compatible bitmap has bottom-up orientation\r\n\/\/ 2) Compatible bitmap will return colors in BGR instead of RGB format\r\n\/\/ 3) Client Rect has lower bound of 0 in both x and y dimension\r\n\/\/ 4) Bitmap it not palletized\r\n\/\/ Return value: 0 = success, others return standard WinError number\r\n\/\/ writing PNG leverged from http:\/\/www.labbookpages.co.uk\/software\/imgProc\/files\/libPNG\/makePNG.c\r\nlong SaveClientAreaToPng(HWND hWnd, TCHAR *filename) {\r\n\tlong code;  \/\/ return code\r\n\tFILE *fp = NULL;\r\n\tpng_structp png_ptr = NULL;\r\n\tpng_infop info_ptr = NULL;\r\n\tpng_bytep row = NULL;\r\n\tRECT Rect;\r\n\tHDC hdc = NULL;\r\n\tHDC hDest = NULL;\r\n\tHBITMAP hBitmap = NULL;\r\n\tHBITMAP hPrevBitmap = NULL;\r\n\tBITMAPINFO bi = {sizeof(BITMAPINFOHEADER)};\r\n\r\n\t\/\/ get dimensions of client area to save\r\n\t\/\/ note that this is generally smaller than the whole window\r\n\tGetClientRect(hWnd, &amp;Rect);\r\n\r\n\t\/\/ Open file for writing (binary mode)\r\n\tcode = _tfopen_s(&amp;fp, filename, TEXT(\"wb\"));\r\n\tif (code != NO_ERROR) {\r\n\t\tgoto finalise;\r\n\t}\r\n\r\n\t\/\/ Initialize write structure\r\n\tpng_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);\r\n\tif (png_ptr == NULL) {\r\n\t\tcode = ERROR_NOT_ENOUGH_MEMORY;\r\n\t\tgoto finalise;\r\n\t}\r\n\r\n\t\/\/ Initialize info structure\r\n\tinfo_ptr = png_create_info_struct(png_ptr);\r\n\tif (info_ptr == NULL) {\r\n\t\tcode = ERROR_NOT_ENOUGH_MEMORY;\r\n\t\tgoto finalise;\r\n\t}\r\n\r\n\t\/\/ Setup Exception handling\r\n\t\/\/ Any subsequent errors in png_xxxx calls will cause this\r\n\t\/\/ to execute\r\n\tif (setjmp(png_jmpbuf(png_ptr))) {\r\n\t\tcode = ERROR_INVALID_DATA;  \/\/ best match standard error message\r\n\t\tgoto finalise;\r\n\t}\r\n\r\n\tpng_init_io(png_ptr, fp);\r\n\r\n\t\/\/ Write header (8 bit colour depth)\r\n\tpng_set_IHDR(png_ptr, info_ptr, Rect.right, Rect.bottom,\r\n\t\t\t8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,\r\n\t\t\tPNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);\r\n\r\n\t\/\/ Set title\r\n\t\/\/if (title != NULL) {\r\n\t\/\/\tpng_text title_text;\r\n\t\/\/\ttitle_text.compression = PNG_TEXT_COMPRESSION_NONE;\r\n\t\/\/\ttitle_text.key = \"Title\";\r\n\t\/\/\ttitle_text.text = title;\r\n\t\/\/\tpng_set_text(png_ptr, info_ptr, &amp;title_text, 1);\r\n\t\/\/}\r\n\r\n\tpng_write_info(png_ptr, info_ptr);\r\n\r\n\t\/\/ Now fetch the actual contents of the Window\r\n\thdc = GetDC(hWnd);\r\n\thDest = CreateCompatibleDC(hdc);\r\n\r\n\t\/\/ create a compatible bitmap to store the pixels\r\n\thBitmap = CreateCompatibleBitmap(hdc, Rect.right, Rect.bottom);\r\n\r\n\t\/\/ bits copied to the context will go to the bitmap\r\n\thPrevBitmap = (HBITMAP) SelectObject(hDest, hBitmap);\r\n\r\n\t\/\/copy from the window's dc to the dc with the bitmap\r\n\tBitBlt(hDest, 0, 0, Rect.right, Rect.bottom, hdc, 0, 0, SRCCOPY);\r\n\t\/\/ MUST unselect hBitmap in order to use GetDIBits() later\r\n\t\/\/ bssides, restoring previous object is good practice\r\n\tSelectObject(hDest, hPrevBitmap);\r\n\r\n\t\/\/ First call with buffer pointer null just retrieves\r\n\t\/\/ bitmap information into bi structure\r\n    bi.bmiHeader.biBitCount = 0;  \/\/ must set to 0 to retrieve infoheader\r\n\tGetDIBits(hDest, hBitmap, 0, 0, NULL, &amp;bi, DIB_RGB_COLORS);\r\n\t\/\/ Modify to the format we want to retrieve:\r\n\t\/\/ uncompressed, 3-byte RGB format\r\n    bi.bmiHeader.biBitCount = 24;    \r\n    bi.bmiHeader.biCompression = BI_RGB;    \r\n\r\n\t\/\/ Allocate memory for one row of the picture.\r\n\t\/\/ Format is 3 bytes (24 bits) per pixel.\r\n\t\/\/ The buffer is filled by GetDIBits().\r\n\t\/\/ The buffer is output to a file by libpng calls.\r\n\t\/\/ For sake of GetDIBits(), must round up to whole number of DWORDs (the \"stride\")\r\n\trow = (png_bytep) malloc((Rect.right * bi.bmiHeader.biBitCount \/ 8 * sizeof(png_byte) + 3) &amp; ~3);\r\n\tif (row == NULL) {\r\n\t\tcode = ERROR_NOT_ENOUGH_MEMORY;\r\n\t\tgoto finalise;\r\n\t}\r\n\r\n\t\/\/ Write image data one row at a time\r\n\t\/\/ Microsoft image is bottom-up, png is top-down, so must go\r\n\t\/\/ in reverse order for y.\r\n\t\/\/ Each Microsoft pixel is BGR, must swap bytes for RGB orderof png\r\n\tint x, y;\r\n\tUCHAR temp;\r\n\tfor (y=Rect.bottom-1 ; y&gt;=0; y--) {\r\n\t\tGetDIBits(hDest, hBitmap, y, 1, row, &amp;bi, DIB_RGB_COLORS);\r\n\t\tfor (x=0 ; x&lt;Rect.right; x++) {\r\n\t\t\ttemp = row[x*3];\r\n\t\t\trow[x*3] = row[x*3+2];\r\n\t\t\t\/\/row[x*3+1] = row[x*3+1];  \/\/ middle byte unchanged\r\n\t\t\trow[x*3+2] = temp;\r\n\t\t}\r\n\t\tpng_write_row(png_ptr, row);\r\n\t}\r\n\r\n\t\/\/ End write\r\n\tpng_write_end(png_ptr, NULL);\r\n\r\nfinalise:\r\n\tif (fp != NULL) fclose(fp);\r\n\tif (info_ptr != NULL) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);\r\n\tif (png_ptr != NULL) png_destroy_write_struct(&amp;png_ptr, (png_infopp)NULL);\r\n\tif (row != NULL) free(row);\r\n\tif (hdc != NULL) ReleaseDC(NULL, hdc);\r\n\tif (hDest != NULL) DeleteDC(hDest);\r\n\tif (hBitmap != NULL) DeleteObject(hBitmap);\r\n\r\n\treturn code;\r\n}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>This is offered to anyone who might be able to use it. \u00a0It&#8217;s plain c code to write the contents of a Microsoft window (from a win32 app) to a png file. \u00a0pnglib provides all the primitives necessary, but I&#8217;ve put it all together into one simple function. ClientToPng Source (2.7k) ClientToPng Precompiled (665k) The &hellip; <a href=\"http:\/\/pididu.com\/wordpress\/blog\/save-client-area-of-a-window-to-png-file\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Save Client Area of a Window to PNG File<\/span> <span class=\"meta-nav\">&rarr;<\/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":[166],"tags":[220,217,214,219,218,208,207,205],"_links":{"self":[{"href":"http:\/\/pididu.com\/wordpress\/wp-json\/wp\/v2\/posts\/2444"}],"collection":[{"href":"http:\/\/pididu.com\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/pididu.com\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/pididu.com\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/pididu.com\/wordpress\/wp-json\/wp\/v2\/comments?post=2444"}],"version-history":[{"count":0,"href":"http:\/\/pididu.com\/wordpress\/wp-json\/wp\/v2\/posts\/2444\/revisions"}],"wp:attachment":[{"href":"http:\/\/pididu.com\/wordpress\/wp-json\/wp\/v2\/media?parent=2444"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/pididu.com\/wordpress\/wp-json\/wp\/v2\/categories?post=2444"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/pididu.com\/wordpress\/wp-json\/wp\/v2\/tags?post=2444"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}