Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* NOTE: This function is based on some code I found on usenet, in a post by
- Allan Bruce on July 26th 2005 in comp.os.ms-windows.programmer.win32.
- Although it was poorly commented and written, it was mostly correct,
- so that's the basis of what I'm using here. The rest was filled in by
- knowledge base article Q80080, which was valuable even though it was
- apparently written in 1985.
- */
- T_Status C_Bitmap::Write_To_File(char * filename, HDC source)
- {
- T_Status status = SUCCESS;
- unsigned long count, width, height, data_size, actual, color_size, bitdepth;
- int result;
- HDC dc;
- BITMAPINFOHEADER * header;
- BITMAPFILEHEADER fileheader;
- BYTE * data_ptr = NULL;
- HANDLE handle = NULL;
- BOOL is_ok;
- BITMAPINFO info;
- BITMAPINFO * info_ptr = NULL;
- RGBQUAD * colors;
- /* Get a DC either from the canvas we were given, or allocate a new one.
- */
- if (source != NULL)
- dc = source;
- else {
- dc = CreateCompatibleDC(NULL);
- if (x_Trap_Opt(dc == NULL)) {
- status = ERR_PUBVISUAL_UNEXPECTED_ERROR;
- goto cleanup_exit;
- }
- }
- /* Get the bitmap dimensions for later use
- */
- Get_Dimensions(&width, &height);
- /* Calculate the bit depth to use
- */
- bitdepth = Get_Bit_Depth();
- if (bitdepth <= 1)
- bitdepth = 1;
- else if (bitdepth <= 4)
- bitdepth = 4;
- else if (bitdepth <= 8)
- bitdepth = 8;
- else
- bitdepth = 24;
- /* Set up our BITMAPINFO structure with the required fields. I've put
- comments on all the ones I don't really understand.
- */
- memset(&info, 0, sizeof(info));
- header = &info.bmiHeader;
- header->biSize = sizeof(info.bmiHeader);
- header->biWidth = width;
- header->biHeight = height;
- header->biPlanes = 1; // Must be set to 1 according to docs
- header->biBitCount = (WORD) bitdepth;
- header->biCompression = BI_RGB;
- header->biSizeImage = 0; // 0 is ok for BI_RGB bitmaps, apparently
- header->biXPelsPerMeter = 0; // I'm not sure how this is relevant
- header->biYPelsPerMeter = 0; // I'm not sure how this is relevant
- header->biClrUsed = 0; // 0 = use default number of colors, should be ok
- header->biClrImportant = 0; // 0 = requires all colors, should be ok
- info_ptr = &info;
- /* Work out how much space our color table will take up. This is going to
- be (number of colors) * sizeof(RGBQUAD), except for 24-bit color, when
- it is 0 (24-bit images don't have a color table).
- */
- if (bitdepth == 24)
- color_size = 0;
- else
- color_size = sizeof(RGBQUAD) * (1 << header->biBitCount);
- /* Allocate space for our color table, and copy our BITMAPINFO structure
- into it for later filling up of said color table.
- */
- if (color_size == 0)
- info_ptr = &info;
- else {
- count = sizeof(BITMAPINFOHEADER) + color_size;
- info_ptr = (BITMAPINFO *) malloc(count);
- if (x_Trap_Opt(info_ptr == NULL))
- goto cleanup_exit;
- memset(info_ptr, 0, count);
- memcpy(info_ptr, &info, sizeof(info));
- header = &info_ptr->bmiHeader;
- }
- colors = info_ptr->bmiColors;
- /* Call GetDIBits once, to calculate the size of the image.
- */
- result = GetDIBits(dc, m_bitmap, 0, 1, NULL, info_ptr, DIB_RGB_COLORS);
- if (x_Trap_Opt(result == 0)) {
- status = ERR_PUBVISUAL_UNEXPECTED_ERROR;
- goto cleanup_exit;
- }
- /* Except GetDIBits apparently doesn't always calculate the size of the
- image! So we sometimes have to do it manually.
- */
- if (header->biSizeImage == 0)
- header->biSizeImage = ((((width * header->biBitCount) + 31) & ~31) >> 3) * height;
- data_size = header->biSizeImage;
- /* Allocate enough space for the bitmap data.
- */
- data_ptr = new BYTE[data_size];
- if (x_Trap_Opt(data_ptr == NULL)) {
- status = ERR_PUBVISUAL_OUT_OF_MEMORY;
- goto cleanup_exit;
- }
- /* Call GetDIBits a final time to get the bits from the bitmap and put them
- into the space we just allocated.
- */
- result = GetDIBits(dc, m_bitmap, 0, height, data_ptr, info_ptr, DIB_RGB_COLORS);
- if (x_Trap_Opt(result == 0)) {
- status = ERR_PUBVISUAL_UNEXPECTED_ERROR;
- goto cleanup_exit;
- }
- /* Set up a BITMAPFILEHEADER structure with the relevant info
- */
- memset(&fileheader, 0, sizeof(fileheader));
- fileheader.bfType = ((WORD) ('M' << 8) | 'B'); // "BM"
- fileheader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFO) + (data_size);
- fileheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + color_size;
- /* If the file we're going to output already exists, delete it.
- */
- if (Does_File_Exist(filename)) {
- status = PubVisual_Delete_File(filename);
- x_Trap_Opt(!x_Is_Success(status));
- }
- /* Create a new, empty file.
- */
- handle = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_NEW,
- FILE_ATTRIBUTE_NORMAL, NULL);
- if (x_Trap_Opt(handle == NULL))
- goto cleanup_exit;
- /* Write the file - we write out the BITMAPFILEHEADER, then the
- BITMAPINFO, then the data.
- */
- count = sizeof(fileheader);
- is_ok = WriteFile(handle, &fileheader, count, &actual, NULL);
- if (x_Trap_Opt(!is_ok))
- goto cleanup_exit;
- if (x_Trap_Opt(actual != count)) {
- status = ERR_PUBVISUAL_FILE_WRITE_ERROR;
- goto cleanup_exit;
- }
- /* When writing out the bitmapinfo, output enough bytes for the header plus
- the color table.
- */
- count = sizeof(BITMAPINFOHEADER) + color_size;
- is_ok = WriteFile(handle, header, count, &actual, NULL);
- if (x_Trap_Opt(!is_ok))
- goto cleanup_exit;
- if (x_Trap_Opt(actual != count)) {
- status = ERR_PUBVISUAL_FILE_WRITE_ERROR;
- goto cleanup_exit;
- }
- /* Finally, write out the data.
- */
- count = data_size;
- is_ok = WriteFile(handle, data_ptr, count, &actual, NULL);
- if (x_Trap_Opt(!is_ok))
- goto cleanup_exit;
- if (x_Trap_Opt(actual != count)) {
- status = ERR_PUBVISUAL_FILE_WRITE_ERROR;
- goto cleanup_exit;
- }
- /* Close the file
- */
- cleanup_exit:
- if (handle != NULL)
- CloseHandle(handle);
- /* Clean up everything we allocated
- */
- if (data_ptr != NULL)
- delete [] data_ptr;
- if (source != NULL)
- DeleteDC(dc);
- if (info_ptr != &info)
- free(info_ptr);
- x_Status_Return(status);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement