Я мог бы нуждаться в некоторой помощи, чтобы выяснить, как прокормить процесс ниже. Мне нужно написать монохромный файл BMP. Код ниже (его из: Как сохранить монохромное изображение как BMP в Windows C ++?Похоже, что это можно сделать. Я сейчас застрял на том, как конвертировать std::bitset
или предпочтительно boost::dynamic_bitset
в это byte*
формат. Все мои попытки пока не увенчались успехом, я не смог написать что-то вроде шаблона проверки 8×8 в 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 colorfileHeader.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);
}
У меня есть что-то очень похожее …
Этот подход НЕ обрабатывает заполнение формата 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 растет снизу вверх.
Если у вас есть ширина растрового изображения пиксель на бит (реальное монохроматическое растровое изображение), вы можете проверить биты и заполнить imageData. Чтобы проверить немного в байте сделать как myByte >> position & 1
где position
это бит, который вы хотите проверить от 0 до 7.
Просто для архива, ниже рабочей версии. В качестве входного пиксельного хранилища требуется усиленный битовый набор.
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 colorfileHeader.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();
}
Интересно, есть ли более простой / быстрый способ поместить биты в файл? Вместо этого весь набор битов может быть преобразован в массив строк, чтобы пропустить извлечение подмножества.