Create HBITMAP from jpeg memory buffer?

2019-08-10 22:13发布

问题:

I want to create HBITMAP from byte array with JPEG format.

I have searched but I only can create it from bitmap file as

HBITMAP hbm = (HBITMAP)LoadImage(NULL,"fileName",IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION);

Can someone show me how to do it?

回答1:

Just use GDIplus. It supports loading JPEGs, and some other stuff feels much more logically

http://msdn.microsoft.com/en-us/library/ms533830%28v=vs.85%29.aspx

Use "Bitmap" class. When you have the jpeg in a buffer, you need to read it by a stream.



回答2:

MFC provides a CImage class that wraps a bitmap object. It provides convenience methods to load and save images in a host of formats, including JPEG, GIF, BMP, and PNG.

So the first order of business is obtaining a CImage object representing your HBITMAP. You can do this by calling the Attach method and passing the handle.

But in this case, it looks like you can skip that entirely and just have the CImage object load your image from the file directly. Use the Load method for that.

Once you've got a CImage object representing your image, just call the Save method and specify the desired file name with the appropriate extension. According to the documentation:

If the guidFileType parameter is not included, the file name's file extension will be used to determine the image format. If no extension is provided, the image will be saved in BMP format.

Sample code:

CImage img;
img.Load(TEXT("fileName.bmp"));  // load a bitmap (BMP)
img.Save(TEXT("fileName.jpg"));  // and save as a JPEG (JPG)

You can also reverse this pattern, using the Load method to load JPEG files and the Save method to save BMP files.



回答3:

I found the following code //http://katahiromz.web.fc2.com/win32/loadjpeg.html

The red and blue were swapped, so here is a corrected version with the colours corrected. It uses jpeglib, so you must first compile that. If you need only to convert a buffer, then you can skip the line that loads the file - the details of converting should be the same.

extern "C" {         
#include <jpeglib.h> 
#include <jerror.h>
}
#pragma comment(lib, "jpeg.lib")
HBITMAP LoadJpegAsBitmap(const std::string & filename)
{ 

    struct jpeg_decompress_struct decomp{};
    struct jpeg_error_mgr jerror{};
    BITMAPINFO bi = {};
    LPBYTE lpBuf, pb = NULL;
    HBITMAP hbm{};
    JSAMPARRAY buffer{};
    INT row = 0;

    decomp.err = jpeg_std_error(&jerror);
    jpeg_create_decompress(&decomp);
    FILE* file = fopen(filename.c_str(), "rb");
    if (file == nullptr)
    {   
        return NULL;
    }

    jpeg_stdio_src(&decomp, file);

    jpeg_read_header(&decomp, TRUE); // read jpeg file header
    jpeg_start_decompress(&decomp);  // decompress the file

    row = ((decomp.output_width * 3 + 3) & ~3);
    buffer = (*decomp.mem->alloc_sarray)((j_common_ptr)&decomp, JPOOL_IMAGE,
        row, 1);

    ZeroMemory(&bi.bmiHeader, sizeof(BITMAPINFOHEADER));
    bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bi.bmiHeader.biWidth = decomp.output_width;
    bi.bmiHeader.biHeight = decomp.output_height;
    bi.bmiHeader.biPlanes = 1;
    bi.bmiHeader.biBitCount = 24;
    bi.bmiHeader.biCompression = BI_RGB;
    bi.bmiHeader.biSizeImage = row * decomp.output_height;

    hbm = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, (void**)&lpBuf, NULL, 0);
    if (hbm == NULL)
    {
        jpeg_destroy_decompress(&decomp);
        fclose(file);
        return NULL;
    }

    pb = lpBuf + row * decomp.output_height;
    while (decomp.output_scanline < decomp.output_height)
    {
        pb -= row;
        jpeg_read_scanlines(&decomp, buffer, 1);

        if (decomp.out_color_components == 1)
        {
            UINT i;
            LPBYTE p = (LPBYTE)buffer[0];
            for (i = 0; i < decomp.output_width; i++)
            {    
                pb[3 * i + 0] = p[i];
                pb[3 * i + 1] = p[i];
                pb[3 * i + 2] = p[i];  
            }
        }
        else if (decomp.out_color_components == 3)
        {
            // There was talk on Internet about one being RGB and another BGR. 
            // If colors appear swapped, then swap the bytes, and update this comment.
            //CopyMemory(pb, buffer[0], row);

            // Updated color correction
            UINT i;
            LPBYTE p = (LPBYTE)buffer[0];
            for (i = 0; i < row; i += 3)
            {
                pb[i + 0] = p[i + 2]; // Blue   
                pb[i + 1] = p[i + 1]; // Green  
                pb[i +2] = p[i + 0];  // Red    
            }
        }
        else
        {
            jpeg_destroy_decompress(&decomp);
            fclose(file);
            DeleteObject(hbm);
            return NULL;
        }
    }

    SetDIBits(NULL, hbm, 0, decomp.output_height, lpBuf, &bi, DIB_RGB_COLORS);

    jpeg_finish_decompress(&decomp);
    jpeg_destroy_decompress(&decomp);

    fclose(file);

    return hbm;
}