我需要从一个字节数组创建一个CImage(实际上,它是一个unsigned char
数组,但我可以转换为必要的任何形式)。字节数组的格式为“RGBRGBRGB ...”。新图像需要包含图像字节的副本,而不是使用字节数组本身的内存。
我已经尝试了很多不同的方法来实现这一目标 - 包括通过各种HBITMAP创建函数,尝试使用BitBlt - 到目前为止还没有任何工作。
要测试该功能是否有效,它应通过此测试:
BYTE* imgBits;
int width;
int height;
int Bpp; // BYTES per pixel (e.g. 3)
getImage(&imgBits, &width, &height, &Bpp); // get the image bits
// This is the magic function I need!!!
CImage img = createCImage(imgBits, width, height, Bpp);
// Test the image
BYTE* data = img.GetBits(); // data should now have the same data as imgBits
到目前为止,createCImage()
的所有实现都以[{1}}指向空(零填充)数组结束。
答案 0 :(得分:1)
CImage
非常巧妙地支持DIB,并且有一个SetPixel()
方法,所以你可能会做这样的事情(未编译的,未经测试的代码!):
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));
}
}
也许不是最有效的方法,但我认为这是最简单的方法。
答案 1 :(得分:1)
使用memcpy复制数据,然后使用SetDIBits或SetDIBitsToDevice,具体取决于您需要执行的操作。但请注意,原始图像数据的扫描线在4字节边界上对齐(IIRC,这是我做了几年后的几年)所以从GetDIBits返回的数据永远不会与原始数据完全相同(它可能,取决于图像大小)。
因此,您很可能需要通过扫描线记忆扫描线。
答案 2 :(得分:1)
谢谢大家,我设法在你的帮助下最终解决了这个问题。它主要涉及@tinman和@ Roel的使用SetDIBitsToDevice()
的建议,但它涉及一些额外的比特和内存管理,所以我想我在这里分享我的终点。
在下面的代码中,我假设设置了width
,height
和Bpp
(每个像素的字节),data
是指向RGB像素值数组的指针。
// 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;
答案 3 :(得分:1)
这是一个更简单的解决方案。您可以使用GetPixelAddress(...)代替所有这些BITMAPHEADERINFO和SedDIBitsToDevice。我解决的另一个问题是8位图像,需要定义颜色表。
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);
}