我可能需要一些帮助来弄清楚如何喂养下面的过程。我需要编写一个单色 BMP 文件。下面的代码(来自:如何在窗口中将单色图像另存为 bmp C++?)看起来能够做到这一点。我现在坚持如何将std::bitset
或最好boost::dynamic_bitset
转换为这种byte*
格式。到目前为止,我的所有尝试都失败了,我无法将 8x8 检查器模式之类的东西写入 BMP。该过程创建BMP,并且可以由Photoshop读取,但内容一团糟。因此,任何如何解决此问题的建议将不胜感激!
Save1BppImage(byte* ImageData, const char* filename, long w, long h){
int bitmap_dx = w; // Width of image
int bitmap_dy = h; // Height of Image
// create file
std::ofstream file(filename, std::ios::binary | std::ios::trunc);
if(!file) return;
// save bitmap file headers
BITMAPFILEHEADER fileHeader;
BITMAPINFOHEADER * infoHeader;
infoHeader = (BITMAPINFOHEADER*) malloc(sizeof(BITMAPINFOHEADER) );
RGBQUAD bl = {0,0,0,0}; //black color
RGBQUAD wh = {0xff,0xff,0xff,0xff}; // white color
fileHeader.bfType = 0x4d42;
fileHeader.bfSize = 0;
fileHeader.bfReserved1 = 0;
fileHeader.bfReserved2 = 0;
fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + (sizeof(BITMAPINFOHEADER));
infoHeader->biSize = (sizeof(BITMAPINFOHEADER) );
infoHeader->biWidth = bitmap_dx;
infoHeader->biHeight = bitmap_dy;
infoHeader->biPlanes = 1;
infoHeader->biBitCount = 1;
infoHeader->biCompression = BI_RGB; //no compression needed
infoHeader->biSizeImage = 0;
infoHeader->biXPelsPerMeter = 0;
infoHeader->biYPelsPerMeter = 0;
infoHeader->biClrUsed = 2;
infoHeader->biClrImportant = 2;
file.write((char*)&fileHeader, sizeof(fileHeader)); //write bitmapfileheader
file.write((char*)infoHeader, (sizeof(BITMAPINFOHEADER) )); //write bitmapinfoheader
file.write((char*)&bl,sizeof(bl)); //write RGBQUAD for black
file.write((char*)&wh,sizeof(wh)); //write RGBQUAD for white
int bytes = (w/8) * h ; //for example for 32X64 image = (32/8)bytes X 64 = 256;
file.write((const char*)ImageData, bytes);
file.close();
}
-编辑-
我的一个天真的方法是这样的
byte test[64];
for(unsigned int i=0; i<64; ++i)
if(i % 2)
test[i] = 0;
else
test[i] = 1;
Save1BppImage(test, "C:/bitmap.bmp", 8, 8);
您拥有的代码非常接近。以下是关于它可能关闭位置的一些想法。
bfOffBits
值必须包括调色板的大小。
fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + (sizeof(BITMAPINFOHEADER)) + 2*sizeof(RGBQUAD);
某些软件可能会将0
解释为白色,1
解释为黑色,而不管调色板说什么。尽管文件格式允许您采用任何一种方式,但您最好按该顺序指定调色板,并在必要时反转您的位。
位图的每一行都将从 4 字节边界开始。如果您的位图宽度不是 32 的倍数,则需要在每行之间添加一些填充。
BMP 文件从底行到顶行排序,这与大多数人组织数组的方式相反。
最后两个建议组合在一起,如下所示:
int bytes_in = (w + 7) / 8;
int bytes_out = ((w + 31) / 32) * 4;
const char * zeros[4] = {0, 0, 0, 0};
for (int y = h - 1; y >= 0; --y)
{
file.write(((const char *)ImageData) + (y * bytes_in), bytes_in);
if (bytes_out != bytes_in)
file.write(zeros, bytes_out - bytes_in);
}
仅用于存档,在工作版本下方。它采用升压位集作为输入像素存储。
void bitsetToBmp(boost::dynamic_bitset<unsigned char> bitset, const char* filename, int width, int height){
//write the bitset to file as 1-bit deep bmp
//bit order 0...n equals image pixels top left...bottom right, row by row
//the bitset must be at least the size of width*height, this is not checked
std::ofstream file(filename, std::ios::binary | std::ios::trunc);
if(!file) return;
// save bitmap file headers
BITMAPFILEHEADER fileHeader;
BITMAPINFOHEADER * infoHeader;
infoHeader = (BITMAPINFOHEADER*) malloc(sizeof(BITMAPINFOHEADER) );
RGBQUAD bl = {0,0,0,0}; //black color
RGBQUAD wh = {0xff,0xff,0xff,0xff}; // white color
fileHeader.bfType = 0x4d42;
fileHeader.bfSize = 0;
fileHeader.bfReserved1 = 0;
fileHeader.bfReserved2 = 0;
fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + (sizeof(BITMAPINFOHEADER)) + 2*sizeof(RGBQUAD);
infoHeader->biSize = (sizeof(BITMAPINFOHEADER) );
infoHeader->biWidth = width;
infoHeader->biHeight = height;
infoHeader->biPlanes = 1;
infoHeader->biBitCount = 1;
infoHeader->biCompression = BI_RGB; //no compression needed
infoHeader->biSizeImage = 0;
infoHeader->biXPelsPerMeter = 0;
infoHeader->biYPelsPerMeter = 0;
infoHeader->biClrUsed = 2;
infoHeader->biClrImportant = 2;
file.write((char*)&fileHeader, sizeof(fileHeader)); //write bitmapfileheader
file.write((char*)infoHeader, (sizeof(BITMAPINFOHEADER) )); //write bitmapinfoheader
file.write((char*)&bl,sizeof(bl)); //write RGBQUAD for black
file.write((char*)&wh,sizeof(wh)); //write RGBQUAD for white
// convert the bits into bytes and write the file
int offset, numBytes = ((width + 31) / 32) * 4;
byte* bytes = (byte*) malloc(numBytes * sizeof(byte));
for(int y=height - 1; y>=0; --y){
offset = y * width;
memset(bytes, 0, (numBytes * sizeof(byte)));
for(int x=0; x<width; ++x)
if(bitset[offset++]){
bytes[x / 8] |= 1 << (7 - x % 8);
};
file.write((const char *)bytes, numBytes);
};
free(bytes);
file.close();
}
我想知道是否有更简单/更快的方法将位放入文件中?相反,可以将整个位集作为行数组进行覆盖,以跳过子集提取。
我有一些非常相似的东西...
-
此方法不处理 BMP 格式的填充。因此,您只能制作宽度倍数为 4 的位图。
-
这不是单色位图。这是一种 RGB 格式,但您可以轻松调整它。
-
这不是一个确切的答案,但肯定可能对你有用。
享受它。
void createBitmap( byte * imageData, const char * filename, int width, int height )
{
BITMAPFILEHEADER bitmapFileHeader;
memset( &bitmapFileHeader, 0, sizeof( bitmapFileHeader ) );
bitmapFileHeader.bfType = ( 'B' | 'M' << 8 );
bitmapFileHeader.bfOffBits = sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER );
bitmapFileHeader.bfSize = bitmapFileHeader.bfOffBits + width * height * 3;
BITMAPINFOHEADER bitmapInfoHeader;
memset( &bitmapInfoHeader, 0, sizeof( bitmapInfoHeader ) );
bitmapInfoHeader.biSize = sizeof( BITMAPINFOHEADER );
bitmapInfoHeader.biWidth = width;
bitmapInfoHeader.biHeight = height;
bitmapInfoHeader.biPlanes = 1;
bitmapInfoHeader.biBitCount = 24;
std::ofstream file( filename, std::fstream::binary );
file.write( reinterpret_cast< char * >( &bitmapFileHeader ), sizeof( bitmapFileHeader ) );
file.write( reinterpret_cast< char * >( &bitmapInfoHeader ), sizeof( bitmapInfoHeader ) );
// the pixels!
file.write( imageData, width * height * 3 );
file.close();
}
int main( int argc, const char * argv[] )
{
int width = 12; // multiple of 4
int height = 12;
byte imageData[ width * height * 3 ];
// fill imageData the way you want, this is just a sample
// on how to set the pixel at any specific (X,Y) position
for ( int y = 0; y < height; ++y )
{
for ( int x = 0; x < width; ++x )
{
int pos = 3 * ( y * width + x );
byte pixelColor = ( x == 2 && y == 2 ) ? 0x00 : 0xff;
imageData[ pos ] = pixelColor;
imageData[ pos + 1 ] = pixelColor;
imageData[ pos + 2 ] = pixelColor;
}
}
createBitmap( imageData, "bitmap.bmp", width, height );
return 0;
}
在此示例中,我们想要一个白色位图,其中位置 X = 2,Y = 2 处有一个黑色像素。
BMP格式表示Y从下到上长大。
如果你有一个位图宽度,每个位一个像素(真正的单色位图),你可以测试位并填充图像数据。要测试字节中的位,请喜欢myByte >> position & 1
其中position
是您要从 0 到 7 测试的位。