How to create HBITMAP from WICBitmapSource

来源:互联网 发布:常见的木马编程技术 16 编辑:程序博客网 时间:2024/05/16 14:17

// Creates a 32-bit DIB from the specified WIC bitmap.

HBITMAP CreateHBITMAP(IWICBitmapSource * ipBitmap)

{
    // initialize return value
    HBITMAP hbmp = NULL;

    // get image attributes and check for valid image

    UINT width = 0;

    UINT height = 0;

    if (FAILED(ipBitmap->GetSize(&width, &height)) || width == 0 || height == 0)

        goto Return;

    // prepare structure giving bitmap information (negative height indicates a top-down DIB)

    BITMAPINFO bminfo;

    ZeroMemory(&bminfo, sizeof(bminfo));

    bminfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);

    bminfo.bmiHeader.biWidth = width;

    bminfo.bmiHeader.biHeight = -((LONG) height);

    bminfo.bmiHeader.biPlanes = 1;

    bminfo.bmiHeader.biBitCount = 32;

    bminfo.bmiHeader.biCompression = BI_RGB;

    // create a DIB section that can hold the image

    void * pvImageBits = NULL;

    HDC hdcScreen = GetDC(NULL);

    hbmp = CreateDIBSection(hdcScreen, &bminfo, DIB_RGB_COLORS, &pvImageBits, NULL, 0);

    ReleaseDC(NULL, hdcScreen);

    if (hbmp == NULL)

        goto Return;

    // extract the image into the HBITMAP

    const UINT cbStride = width * 4;

    const UINT cbImage = cbStride * height;

    if (FAILED(ipBitmap->CopyPixels(NULL, cbStride, cbImage, static_cast<BYTE *>(pvImageBits))))

    {

        // couldn't extract image; delete HBITMAP

        DeleteObject(hbmp);

        hbmp = NULL;

    }
 
Return:

    return hbmp;

}

Use CreateDIBSection to allocate a DIB that can be written to directly. By setting up a BITMAPINFO structure with the right values, the DIB will be of the same format as the 32bpp BGRA image loaded by WIC, and the pixels can be copied directly from the WIC bitmap to the DIB.

 

Or use SetDIBits to set DIB to a HBITMAP like the following:

HBITMAP GetImageFromBitmapSource(IWICBitmapSource* image)
{
    // Maps a WIC image source to an aready cached HBITMAP.
    // If not already cached, it creates the HBITMAP from WIC.

    if (image == NULL)
        return NULL;

    // Convert the WIC image to a ready-to-use device-dependent GDI bitmap.
    // so that we don't recreate a new bitmap every draw call.
    //
    // * Note this expects BGRA pixel format.

    UINT width, height;
    if (FAILED(image->GetSize(&width, &height)))
        return NULL;

    UINT stride = width * 4;
    UINT pixelBufferSize = stride * height;
    std::vector<UINT8> pixelBuffer(pixelBufferSize);

    if (FAILED(image->CopyPixels(NULL, stride, pixelBufferSize, &pixelBuffer[0])))
        return NULL;

    // Initialize bitmap information.
    BITMAPINFO bmi = {
        sizeof(BITMAPINFOHEADER),   // biSize
        width,                      // biWidth
        -int(height),               // biHeight
        1,                          // biPlanes
        32,                         // biBitCount
        BI_RGB,                     // biCompression
        pixelBufferSize,            // biSizeImage
        1,                          // biXPelsPerMeter
        1,                          // biYPelsPerMeter
        0,                          // biClrUsed
        0,                          // biClrImportant
        0                           // RGB QUAD
    };

    HDC hdc = GetDC(NULL);

    HDC hMemoryDC = CreateCompatibleDC(hdc);

    HBITMAP bitmap = CreateCompatibleBitmap(hdc, width, height);

    if (bitmap == NULL)
        return NULL;

    SetDIBits(
        hMemoryDC,
        bitmap,
        0,              // starting line
        height,         // total scanlines
        &pixelBuffer[0],
        &bmi,
        DIB_RGB_COLORS
        );

    return bitmap;
}

 

Then create BITMAPINFO struct for bitmap, and save the HBITMAP to bitmap file:

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

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

    // 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 the 24-bit-per-pixel format.

     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.
    // For Windows NT, the width must be DWORD aligned unless
    // the bitmap is RLE compressed. This example shows this.
    // For Windows 95/98/Me, the width must be WORD 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(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)
        return;

    // 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))
    {
        return;
    }

    // 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)
        return;
    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) )
    {
       return;
    }

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

    // 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))
           return;

    // Close the .BMP file.
     if (!CloseHandle(hf))
           return;

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

原创粉丝点击