C ++从8位位图构build像素数据并访问bmiColor表信息

我是一个在过去几天一直在看这个问题的人,我只是普通的卡住了。 我正在OpenSuse Linux中工作,尝试使用Cairographics库解释Windows位图图像进行显示。 简而言之,我只需要将每个像素的颜色信息提取到一个数组中,并将其提供给开罗,例如pixeldata [i] = someColor,即可获取图像中的所有像素。 到目前为止,我已经想出了如何通过位图头parsing,并得到它显示24位位图的伟大工作。

但是,现在我正在努力获得8位位图,而这只是一个笨拙的,不直观的野兽争吵。 我能够显示图像,但显示的颜色是错误的…不仅如此,它们每次运行程序时都会改变! :PI认为我正在访问和错误地解释bmiColors调色板数组。 下面是我从我的冗长的互联网研究中拼凑出来的相关代码,这些代码构build了像素数组(请注意,在代码中这一点上,头信息已经被parsing,并在对象m_bmpInfoHeader和m_bmpHeader中可用):

#define RGB(r, g, b) ((long)(((char)(r) | ((char)((short)(g)) << 8)) | (((char)(b)) << 16 ))) #pragma pack (2) typedef struct tagRGBQUAD { long rgbBlue; long rgbGreen; long rgbRed; int rgbReserved; } RGBQUAD; typedef struct { char verifier[2]; unsigned int size; unsigned short int reserved1, reserved2; unsigned int offset; } BITMAPHEADER; typedef struct { unsigned int size; /* Header size in bytes */ signed int width, height; /* Width and height of image */ unsigned short int planes; /* Number of colour planes */ unsigned short int bits; /* Bits per pixel */ unsigned int compression; /* Compression type */ unsigned int imagesize; /* Image size in bytes */ int xresolution,yresolution; /* Pixels per meter */ unsigned int ncolors; /* Number of colors */ unsigned int importantcolors; /* Important colors */ RGBQUAD bmiColors [1]; } BITMAPINFOHEADER; #pragma pack() // Function sets up and returns color index for bitmap. long BitmapDef::GetColorInx (int numbits, char* data, long offset) { long inx; switch (numbits) { case 1: inx = data[offset >> 3]; offset &= 7; inx >>= offset; inx &= 0x01; break; case 2: inx = data[offset >> 2]; offset &= 3; offset <<= 1; inx >>= offset; inx &= 0x03; break; case 4: inx = data[offset >> 1]; if (!(offset & 1)) { inx >>= 4; } inx &= 0x0f; break; case 24: { offset *= 3; inx = *((long*) &data[offset]); char r = GetBValue(inx); char g = GetGValue(inx); char b = GetRValue(inx); inx = ((r << 16) + (g << 8) + b); break; } case 8: default: inx = data[offset] & 0xff; break; } return inx; } void BitmapDef::Build8BitPixelData() { m_PixelData = new unsigned int[m_bmpInfoHeader.width * m_bmpInfoHeader.height]; FILE * pFile; long lSize; char * buffer; size_t result; pFile = fopen ((const char *)m_Filename, "rb" ); if (pFile==NULL) { fputs ("File error", stderr); exit (1); } // obtain file size: fseek (pFile , 0 , SEEK_END); lSize = ftell (pFile); rewind (pFile); // allocate memory to contain the whole file: buffer = (char*) malloc (sizeof(char) * lSize); if (buffer == NULL) {fputs ("Memory error", stderr); exit (2);} // copy the file into the buffer: result = fread (buffer, 1, lSize, pFile); if (result != lSize) {fputs ("Reading error",stderr); exit (3);} BITMAPHEADER* bmfh = (BITMAPHEADER*) (&(buffer[0])); char* bmp = (char*) &buffer[m_bmpHeader.offset]; BITMAPINFOHEADER * bmi = (BITMAPINFOHEADER*) &buffer[sizeof(*bmfh)]; std::cout<<"\nsize: "<<bmi->size<<std::endl; std::cout<<"width: "<<bmi->width<<std::endl; std::cout<<"height: "<<bmi->height<<std::endl; std::cout<<"planes: "<<bmi->planes<<std::endl; std::cout<<"bits: "<<bmi->bits<<std::endl; std::cout<<"annnd compression: "<<bmi->planes<<std::endl; int ix, iy; int position = 0; for (iy = 0; iy < bmi->height; ++iy) { for (ix = 0; ix < bmi->width; ++ix) { int offset = (m_bmpInfoHeader.height - 1 - iy) * m_bmpInfoHeader.width; offset += ix; //std::cout<<"offset: "<<offset<<" bmp[offset]: "<<bmp[offset] << " " ; long inx = GetColorInx (m_bmpInfoHeader.bits, dataBuf, offset); //std::cout<<inx<<" "; m_PixelData[position] = RGB(bmi->bmiColors[inx].rgbRed, bmi->bmiColors[inx].rgbGreen, bmi->bmiColors[inx].rgbBlue); position++; } } fclose (pFile); free (buffer); } 

有任何想法吗? 请注意,我在非Windows环境下工作,所以我必须翻译许多以Windows为中心的函数才能在C ++中工作。 任何帮助表示赞赏,谢谢!

更新:

感谢cbranch的build议,我修改了RGBQUAD,使其具有char属性而不是long / int,以便它保持一个4字节的结构。 这解决了颜色不断变化的问题。 然而,奇怪的是颜色仍然是closures的。 目前,我正试图在黑色背景上显示绿色钻石的简单图像,但由于某种原因钻石显示为黄色。 有任何想法吗?

另外,我刚刚注意到,我不小心将“#pragma pack()”指令从我的原始文章的结构中移出,并且刚刚将它们添加到了文章中。

RGBQuad应该是四个字节。

这个宏:

 #define RGB(r, g, b) ((long)(((char)(r) | ((char)((short)(g)) << 8)) | (((char)(b)) << 16 ))) 

是有问题的。 你可能会得到符号扩展。 一个完整的绿色像素将有g == 0xFF。 你把它转换成(带符号),所以你可能会得到符号扩展(0xFFFF),然后转换。 现在你已经有了红色和绿色设置为完整的值,因此它看起来黄色。

按位操作时,几乎总是要使用无符号值。