Create CImage from Byte array

后端 未结 4 761
面向向阳花
面向向阳花 2020-12-21 12:02

I need to create a CImage from a byte array (actually, its an array of unsigned char, but I can cast to whatever form is necessary). The byte array is in the fo

相关标签:
4条回答
  • 2020-12-21 12:27

    Here is a simpler solution. You can use GetPixelAddress(...) instead of all this BITMAPHEADERINFO and SedDIBitsToDevice. Another problem I have solved was with 8-bit images, which need to have the color table defined.

    CImage outImage;
    outImage.Create(width, height, channelCount * 8);
    
    int lineSize = width * channelCount;
    if (channelCount == 1)
    {
        // Define the color table
        RGBQUAD* tab = new RGBQUAD[256];
        for (int i = 0; i < 256; ++i)
        {
            tab[i].rgbRed = i;
            tab[i].rgbGreen = i;
            tab[i].rgbBlue = i;
            tab[i].rgbReserved = 0;
        }
        outImage.SetColorTable(0, 256, tab);
        delete[] tab;
    }
    
    // Copy pixel values
    // Warining: does not convert from RGB to BGR
    for ( int i = 0; i < height; i++ )
    {
        void*       dst = outImage.GetPixelAddress(0, i);
        const void* src = /* put the pointer to the i'th source row here */;
        memcpy(dst, src, lineSize);
    }
    
    0 讨论(0)
  • 2020-12-21 12:30

    CImage supports DIBs quite neatly and has a SetPixel() method so you could presumably do something like this (uncompiled, untested code ahead!):

    CImage img;
    img.Create(width, height, 24 /* bpp */, 0 /* No alpha channel */);
    
    int nPixel = 0;
    for(int row = 0; row < height; row++)
    {
        for(int col = 0; col < width; col++)
        {
            BYTE r = imgBits[nPixel++];
            BYTE g = imgBits[nPixel++];
            BYTE b = imgBits[nPixel++];
            img.SetPixel(row, col, RGB(r, g, b));
        }
    }
    

    Maybe not the most efficient method but I should think it is the simplest approach.

    0 讨论(0)
  • 2020-12-21 12:32

    Use memcpy to copy the data, then SetDIBits or SetDIBitsToDevice depending on what you need to do. Take care though, the scanlines of the raw image data are aligned on 4-byte boundaries (IIRC, it's been a few years since I did this) so the data you get back from GetDIBits will never be exactly the same as the original data (well it might, depending on the image size).

    So most likely you will need to memcpy scanline by scanline.

    0 讨论(0)
  • 2020-12-21 12:34

    Thanks everyone, I managed to solve it in the end with your help. It mainly involved @tinman and @Roel's suggestion to use SetDIBitsToDevice(), but it involved a bit of extra bit-twiddling and memory management, so I thought I'd share my end-point here.

    In the code below, I assume that width, height and Bpp (Bytes per pixel) are set, and that data is a pointer to the array of RGB pixel values.

    // Create the header info
    bmInfohdr.biSize = sizeof(BITMAPINFOHEADER);
    bmInfohdr.biWidth = width;
    bmInfohdr.biHeight = -height;
    bmInfohdr.biPlanes = 1;
    bmInfohdr.biBitCount = Bpp*8;
    bmInfohdr.biCompression = BI_RGB;
    bmInfohdr.biSizeImage = width*height*Bpp;
    bmInfohdr.biXPelsPerMeter = 0;
    bmInfohdr.biYPelsPerMeter = 0;
    bmInfohdr.biClrUsed = 0;
    bmInfohdr.biClrImportant = 0;
    
    BITMAPINFO bmInfo;
    bmInfo.bmiHeader = bmInfohdr;
    bmInfo.bmiColors[0].rgbBlue=255;
    
    // Allocate some memory and some pointers
    unsigned char * p24Img = new unsigned char[width*height*3];
    BYTE *pTemp,*ptr;
    pTemp=(BYTE*)data;
    ptr=p24Img;
    
    // Convert image from RGB to BGR
    for (DWORD index = 0; index < width*height ; index++)
    {
        unsigned char r = *(pTemp++);
        unsigned char g = *(pTemp++);
        unsigned char b = *(pTemp++);   
    
        *(ptr++) = b;
        *(ptr++) = g;
        *(ptr++) = r;
    }
    
    // Create the CImage
    CImage im;
    im.Create(width, height, 24, NULL);
    
    HDC dc = im.GetDC();
    SetDIBitsToDevice(dc, 0,0,width,height,0,0, 0, height, p24Img, &bmInfo, DIB_RGB_COLORS);
    im.ReleaseDC();
    
    delete[] p24Img;
    
    0 讨论(0)
提交回复
热议问题