仅使用 Win32 将 HBITMAP 保存到 *.bmp 文件 [英] Save HBITMAP to *.bmp file using only Win32

查看:54
本文介绍了仅使用 Win32 将 HBITMAP 保存到 *.bmp 文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的纯 Win32 项目中有一个 HBITMAP(没有使用外部库).是否可以仅使用 Winapi 和/或 CRT 函数将其导出到 *.bmp 文件,这样我就不必向项目添加依赖项?

解决方案

没有 API 可以直接保存到文件中,因为通常,拥有位图句柄并不意味着您可以直接访问位图数据.您的解决方案是使用数据访问 (DIB) 将位图复制到另一个位图中,然后使用它的数据写入文件.

您通常要么使用 CreateDIBSection 创建另一个位图,要么使用 GetDIBits 获取位图数据.

CreateFile, WriteFile 将数据写入文件.

您编写:BITMAPFILEHEADER,然后是 BITMAPINFOHEADER,然后是调色板(当位/像素超过 8 时通常没有调色板),然后是数据本身.

另见:

代码

这是MSDN文章中的代码(注意需要定义errhandler()函数):

PBITMAPINFO CreateBitmapInfoStruct(HWND hwnd, HBITMAP hBmp){位图 bmp;PBITMAPINFO pbmi;字 cClrBits;//检索位图颜色格式、宽度和高度.if (!GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp))错误处理程序(GetObject",hwnd);//将颜色格式转换为位数.cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);如果(cClrBits == 1)cClrBits = 1;否则如果(cClrBits <= 4)cClrBits = 4;否则如果(cClrBits <= 8)cClrBits = 8;否则如果(cClrBits <= 16)cClrBits = 16;否则如果(cClrBits <= 24)cClrBits = 24;否则 cClrBits = 32;//为 BITMAPIINFO 结构分配内存.(这种结构//包含一个 BITMAPINFOHEADER 结构和一个 RGBQUAD 数组//数据结构.)如果 (cClrBits <24)pbmi = (PBITMAPINFO) LocalAlloc(LPTR,大小(BITMAPINFOHEADER)+sizeof(RGBQUAD) * (1<bmiHeader.biSize = sizeof(BITMAPINFOHEADER);pbmi->bmiHeader.biWidth = bmp.bmWidth;pbmi->bmiHeader.biHeight = bmp.bmHeight;pbmi->bmiHeader.biPlanes = bmp.bmPlanes;pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;如果 (cClrBits <24)pbmi->bmiHeader.biClrUsed = (1<bmiHeader.biCompression = BI_RGB;//计算颜色数组中的字节数//索引并将结果存储在 biSizeImage 中.//宽度必须是 DWORD 对齐的,除非位图是 RLE//压缩.pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31)/8* pbmi->bmiHeader.biHeight;//设置 biClrImportant 为 0,表示所有的//设备颜色很重要.pbmi->bmiHeader.biClrImportant = 0;返回 pbmi;}无效CreateBMPFile(HWND hwnd,LPTSTR pszFile,PBITMAPINFO pbi,HBITMAP hBMP, HDC hDC){处理高频;//文件句柄位图文件头 hdr;//位图文件头PBITMAPINFOHEADER pbih;//位图信息头LPBYTE lpBits;//内存指针DWORD dwTotal;//总字节数双字 cb;//增量字节数字节 *hp;//字节指针DWORD dwTmp;pbih = (PBITMAPINFOHEADER) pbi;lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);如果(!lpBits)错误处理程序(GlobalAlloc",hwnd);//检索颜色表(RGBQUAD 数组)和位//(调色板索引数组)来自 DIB.if (!GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight, lpBits, pbi,DIB_RGB_COLORS)){错误处理程序(GetDIBits",hwnd);}//创建 .BMP 文件.hf = CreateFile(pszFile,GENERIC_READ |GENERIC_WRITE,(双字) 0,空值,创建_始终,FILE_ATTRIBUTE_NORMAL,(句柄) NULL);if (hf == INVALID_HANDLE_VALUE)错误处理程序(创建文件",hwnd);hdr.bfType = 0x4d42;//0x42 = "B" 0x4d = "M"//计算整个文件的大小.hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) +pbih->biSize + pbih->biClrUsed* sizeof(RGBQUAD) + pbih->biSizeImage);hdr.bfReserved1 = 0;hdr.bfReserved2 = 0;//计算颜色索引数组的偏移量.hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) +pbih->biSize + pbih->biClrUsed* 大小(RGBQUAD);//将 BITMAPFILEHEADER 复制到 .BMP 文件中.如果 (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER),(LPDWORD) &dwTmp, NULL)){错误处理程序(WriteFile",hwnd);}//将 BITMAPINFOHEADER 和 RGBQUAD 数组复制到文件中.if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER)+ pbih->biClrUsed * sizeof (RGBQUAD),(LPDWORD) &dwTmp, (NULL)))错误处理程序(WriteFile",hwnd);//将颜色索引数组复制到 .BMP 文件中.dwTotal = cb = pbih->biSizeImage;hp = lpBits;if (!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp,NULL))错误处理程序(WriteFile",hwnd);//关闭 .BMP 文件.如果 (!CloseHandle(hf))错误处理程序(CloseHandle",hwnd);//空闲内存.GlobalFree((HGLOBAL)lpBits);}

I have a HBITMAP in my pure Win32 project (no external libraries are used). Can I export it to a *.bmp file using only Winapi and/or CRT functions so I don't have to add dependencies to the project?

解决方案

There is no API to save into file directly because, generally, having a bitmap handle does not mean you have direct access to bitmap data. Your solution is to copy bitmap into another bitmap with data access (DIB) and then using it data to write into file.

You typically either create another bitmap using CreateDIBSection, or you get bitmap data with GetDIBits.

CreateFile, WriteFile writes data into file.

You write: BITMAPFILEHEADER, then BITMAPINFOHEADER, then palette (which you typically don't have when bits/pixel is over 8), then data itself.

See also:

The Code

This is the code from the MSDN article (Note that you need to define the errhandler() function):

PBITMAPINFO CreateBitmapInfoStruct(HWND hwnd, HBITMAP hBmp)
{ 
    BITMAP bmp; 
    PBITMAPINFO pbmi; 
    WORD    cClrBits; 

    // Retrieve the bitmap color format, width, and height.  
    if (!GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp)) 
        errhandler("GetObject", hwnd); 

    // Convert the color format to a count of bits.  
    cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel); 
    if (cClrBits == 1) 
        cClrBits = 1; 
    else if (cClrBits <= 4) 
        cClrBits = 4; 
    else if (cClrBits <= 8) 
        cClrBits = 8; 
    else if (cClrBits <= 16) 
        cClrBits = 16; 
    else if (cClrBits <= 24) 
        cClrBits = 24; 
    else cClrBits = 32; 

    // Allocate memory for the BITMAPINFO structure. (This structure  
    // contains a BITMAPINFOHEADER structure and an array of RGBQUAD  
    // data structures.)  

    if (cClrBits < 24) 
        pbmi = (PBITMAPINFO) LocalAlloc(LPTR, 
        sizeof(BITMAPINFOHEADER) + 
        sizeof(RGBQUAD) * (1<< cClrBits)); 

    // There is no RGBQUAD array for these formats: 24-bit-per-pixel or 32-bit-per-pixel 

    else 
        pbmi = (PBITMAPINFO) LocalAlloc(LPTR, 
        sizeof(BITMAPINFOHEADER)); 

    // Initialize the fields in the BITMAPINFO structure.  

    pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 
    pbmi->bmiHeader.biWidth = bmp.bmWidth; 
    pbmi->bmiHeader.biHeight = bmp.bmHeight; 
    pbmi->bmiHeader.biPlanes = bmp.bmPlanes; 
    pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel; 
    if (cClrBits < 24) 
        pbmi->bmiHeader.biClrUsed = (1<<cClrBits); 

    // If the bitmap is not compressed, set the BI_RGB flag.  
    pbmi->bmiHeader.biCompression = BI_RGB; 

    // Compute the number of bytes in the array of color  
    // indices and store the result in biSizeImage.  
    // The width must be DWORD aligned unless the bitmap is RLE 
    // compressed. 
    pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8
        * pbmi->bmiHeader.biHeight; 
    // Set biClrImportant to 0, indicating that all of the  
    // device colors are important.  
    pbmi->bmiHeader.biClrImportant = 0; 
    return pbmi; 
} 

void CreateBMPFile(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi, 
                   HBITMAP hBMP, HDC hDC) 
{ 
    HANDLE hf;                 // file handle  
    BITMAPFILEHEADER hdr;       // bitmap file-header  
    PBITMAPINFOHEADER pbih;     // bitmap info-header  
    LPBYTE lpBits;              // memory pointer  
    DWORD dwTotal;              // total count of bytes  
    DWORD cb;                   // incremental count of bytes  
    BYTE *hp;                   // byte pointer  
    DWORD dwTmp; 

    pbih = (PBITMAPINFOHEADER) pbi; 
    lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);

    if (!lpBits) 
        errhandler("GlobalAlloc", hwnd); 

    // Retrieve the color table (RGBQUAD array) and the bits  
    // (array of palette indices) from the DIB.  
    if (!GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight, lpBits, pbi, 
        DIB_RGB_COLORS)) 
    {
        errhandler("GetDIBits", hwnd); 
    }

    // Create the .BMP file.  
    hf = CreateFile(pszFile, 
        GENERIC_READ | GENERIC_WRITE, 
        (DWORD) 0, 
        NULL, 
        CREATE_ALWAYS, 
        FILE_ATTRIBUTE_NORMAL, 
        (HANDLE) NULL); 
    if (hf == INVALID_HANDLE_VALUE) 
        errhandler("CreateFile", hwnd); 
    hdr.bfType = 0x4d42;        // 0x42 = "B" 0x4d = "M"  
    // Compute the size of the entire file.  
    hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + 
        pbih->biSize + pbih->biClrUsed 
        * sizeof(RGBQUAD) + pbih->biSizeImage); 
    hdr.bfReserved1 = 0; 
    hdr.bfReserved2 = 0; 

    // Compute the offset to the array of color indices.  
    hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + 
        pbih->biSize + pbih->biClrUsed 
        * sizeof (RGBQUAD); 

    // Copy the BITMAPFILEHEADER into the .BMP file.  
    if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER), 
        (LPDWORD) &dwTmp,  NULL)) 
    {
        errhandler("WriteFile", hwnd); 
    }

    // Copy the BITMAPINFOHEADER and RGBQUAD array into the file.  
    if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER) 
        + pbih->biClrUsed * sizeof (RGBQUAD), 
        (LPDWORD) &dwTmp, ( NULL)))
        errhandler("WriteFile", hwnd); 

    // Copy the array of color indices into the .BMP file.  
    dwTotal = cb = pbih->biSizeImage; 
    hp = lpBits; 
    if (!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp,NULL)) 
        errhandler("WriteFile", hwnd); 

    // Close the .BMP file.  
    if (!CloseHandle(hf)) 
        errhandler("CloseHandle", hwnd); 

    // Free memory.  
    GlobalFree((HGLOBAL)lpBits);
}

这篇关于仅使用 Win32 将 HBITMAP 保存到 *.bmp 文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆