Advertisement
Guest User

win32 bitmap output C++

a guest
May 16th, 2011
785
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.74 KB | None | 0 0
  1. /* NOTE: This function is based on some code I found on usenet, in a post by
  2.     Allan Bruce on July 26th 2005 in comp.os.ms-windows.programmer.win32.
  3.     Although it was poorly commented and written, it was mostly correct,
  4.     so that's the basis of what I'm using here. The rest was filled in by
  5.     knowledge base article Q80080, which was valuable even though it was
  6.     apparently written in 1985.
  7. */
  8. T_Status    C_Bitmap::Write_To_File(char * filename, HDC source)
  9. {
  10.     T_Status            status = SUCCESS;
  11.     unsigned long       count, width, height, data_size, actual, color_size, bitdepth;
  12.     int                 result;
  13.     HDC                 dc;
  14.     BITMAPINFOHEADER *  header;
  15.     BITMAPFILEHEADER    fileheader;
  16.     BYTE *              data_ptr = NULL;
  17.     HANDLE              handle = NULL;
  18.     BOOL                is_ok;
  19.     BITMAPINFO          info;
  20.     BITMAPINFO *        info_ptr = NULL;
  21.     RGBQUAD *           colors;
  22.  
  23.     /* Get a DC either from the canvas we were given, or allocate a new one.
  24.     */
  25.     if (source != NULL)
  26.         dc = source;
  27.     else {
  28.         dc = CreateCompatibleDC(NULL);
  29.         if (x_Trap_Opt(dc == NULL)) {
  30.             status = ERR_PUBVISUAL_UNEXPECTED_ERROR;
  31.             goto cleanup_exit;
  32.             }
  33.         }
  34.  
  35.     /* Get the bitmap dimensions for later use
  36.     */
  37.     Get_Dimensions(&width, &height);
  38.  
  39.     /* Calculate the bit depth to use
  40.     */
  41.     bitdepth = Get_Bit_Depth();
  42.     if (bitdepth <= 1)
  43.         bitdepth = 1;
  44.     else if (bitdepth <= 4)
  45.         bitdepth = 4;
  46.     else if (bitdepth <= 8)
  47.         bitdepth = 8;
  48.     else
  49.         bitdepth = 24;
  50.  
  51.     /* Set up our BITMAPINFO structure with the required fields. I've put
  52.         comments on all the ones I don't really understand.
  53.     */
  54.     memset(&info, 0, sizeof(info));
  55.     header = &info.bmiHeader;
  56.     header->biSize = sizeof(info.bmiHeader);
  57.     header->biWidth = width;
  58.     header->biHeight = height;
  59.     header->biPlanes = 1; // Must be set to 1 according to docs
  60.     header->biBitCount = (WORD) bitdepth;
  61.     header->biCompression = BI_RGB;
  62.     header->biSizeImage = 0; // 0 is ok for BI_RGB bitmaps, apparently
  63.     header->biXPelsPerMeter = 0; // I'm not sure how this is relevant
  64.     header->biYPelsPerMeter = 0; // I'm not sure how this is relevant
  65.     header->biClrUsed = 0; // 0 = use default number of colors, should be ok
  66.     header->biClrImportant = 0; // 0 = requires all colors, should be ok
  67.     info_ptr = &info;
  68.  
  69.     /* Work out how much space our color table will take up. This is going to
  70.         be (number of colors) * sizeof(RGBQUAD), except for 24-bit color, when
  71.         it is 0 (24-bit images don't have a color table).
  72.     */
  73.     if (bitdepth == 24)
  74.         color_size = 0;
  75.     else
  76.         color_size = sizeof(RGBQUAD) * (1 << header->biBitCount);
  77.  
  78.     /* Allocate space for our color table, and copy our BITMAPINFO structure
  79.         into it for later filling up of said color table.
  80.     */
  81.     if (color_size == 0)
  82.         info_ptr = &info;
  83.     else {
  84.         count = sizeof(BITMAPINFOHEADER) + color_size;
  85.         info_ptr = (BITMAPINFO *) malloc(count);
  86.         if (x_Trap_Opt(info_ptr == NULL))
  87.             goto cleanup_exit;
  88.         memset(info_ptr, 0, count);
  89.         memcpy(info_ptr, &info, sizeof(info));
  90.         header = &info_ptr->bmiHeader;
  91.         }
  92.     colors = info_ptr->bmiColors;
  93.  
  94.     /* Call GetDIBits once, to calculate the size of the image.
  95.     */
  96.     result = GetDIBits(dc, m_bitmap, 0, 1, NULL, info_ptr, DIB_RGB_COLORS);
  97.     if (x_Trap_Opt(result == 0)) {
  98.         status = ERR_PUBVISUAL_UNEXPECTED_ERROR;
  99.         goto cleanup_exit;
  100.         }
  101.  
  102.     /* Except GetDIBits apparently doesn't always calculate the size of the
  103.         image! So we sometimes have to do it manually.
  104.     */
  105.     if (header->biSizeImage == 0)
  106.         header->biSizeImage = ((((width * header->biBitCount) + 31) & ~31) >> 3) * height;
  107.     data_size = header->biSizeImage;
  108.  
  109.     /* Allocate enough space for the bitmap data.
  110.     */
  111.     data_ptr = new BYTE[data_size];
  112.     if (x_Trap_Opt(data_ptr == NULL)) {
  113.         status = ERR_PUBVISUAL_OUT_OF_MEMORY;
  114.         goto cleanup_exit;
  115.         }
  116.  
  117.     /* Call GetDIBits a final time to get the bits from the bitmap and put them
  118.         into the space we just allocated.
  119.     */
  120.     result = GetDIBits(dc, m_bitmap, 0, height, data_ptr, info_ptr, DIB_RGB_COLORS);
  121.     if (x_Trap_Opt(result == 0)) {
  122.         status = ERR_PUBVISUAL_UNEXPECTED_ERROR;
  123.         goto cleanup_exit;
  124.         }
  125.  
  126.     /* Set up a BITMAPFILEHEADER structure with the relevant info
  127.     */
  128.     memset(&fileheader, 0, sizeof(fileheader));
  129.     fileheader.bfType = ((WORD) ('M' << 8) | 'B'); // "BM"
  130.     fileheader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFO) + (data_size);
  131.     fileheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + color_size;
  132.  
  133.     /* If the file we're going to output already exists, delete it.
  134.     */
  135.     if (Does_File_Exist(filename)) {
  136.         status = PubVisual_Delete_File(filename);
  137.         x_Trap_Opt(!x_Is_Success(status));
  138.         }
  139.  
  140.     /* Create a new, empty file.
  141.     */
  142.     handle = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_NEW,
  143.                         FILE_ATTRIBUTE_NORMAL, NULL);
  144.     if (x_Trap_Opt(handle == NULL))
  145.         goto cleanup_exit;
  146.  
  147.     /* Write the file - we write out the BITMAPFILEHEADER, then the
  148.         BITMAPINFO, then the data.
  149.     */
  150.     count = sizeof(fileheader);
  151.     is_ok = WriteFile(handle, &fileheader, count, &actual, NULL);
  152.     if (x_Trap_Opt(!is_ok))
  153.         goto cleanup_exit;
  154.     if (x_Trap_Opt(actual != count)) {
  155.         status = ERR_PUBVISUAL_FILE_WRITE_ERROR;
  156.         goto cleanup_exit;
  157.         }
  158.  
  159.     /* When writing out the bitmapinfo, output enough bytes for the header plus
  160.         the color table.
  161.     */
  162.     count = sizeof(BITMAPINFOHEADER) + color_size;
  163.     is_ok = WriteFile(handle, header, count, &actual, NULL);
  164.     if (x_Trap_Opt(!is_ok))
  165.         goto cleanup_exit;
  166.     if (x_Trap_Opt(actual != count)) {
  167.         status = ERR_PUBVISUAL_FILE_WRITE_ERROR;
  168.         goto cleanup_exit;
  169.         }
  170.  
  171.     /* Finally, write out the data.
  172.     */
  173.     count = data_size;
  174.     is_ok = WriteFile(handle, data_ptr, count, &actual, NULL);
  175.     if (x_Trap_Opt(!is_ok))
  176.         goto cleanup_exit;
  177.     if (x_Trap_Opt(actual != count)) {
  178.         status = ERR_PUBVISUAL_FILE_WRITE_ERROR;
  179.         goto cleanup_exit;
  180.         }
  181.  
  182.     /* Close the file
  183.     */
  184. cleanup_exit:
  185.     if (handle != NULL)
  186.         CloseHandle(handle);
  187.  
  188.     /* Clean up everything we allocated
  189.     */
  190.     if (data_ptr != NULL)
  191.         delete [] data_ptr;
  192.     if (source != NULL)
  193.         DeleteDC(dc);
  194.     if (info_ptr != &info)
  195.         free(info_ptr);
  196.  
  197.     x_Status_Return(status);
  198. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement