Создать монохромный BMP из битсета

Я мог бы нуждаться в некоторой помощи, чтобы выяснить, как прокормить процесс ниже. Мне нужно написать монохромный файл 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);

4

Решение

Код у вас очень близок. Вот несколько мыслей о том, где это может быть.

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);
}
2

Другие решения

У меня есть что-то очень похожее …

  • Этот подход НЕ обрабатывает заполнение формата 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.

0

Просто для архива, ниже рабочей версии. В качестве входного пиксельного хранилища требуется усиленный битовый набор.

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();

}

Интересно, есть ли более простой / быстрый способ поместить биты в файл? Вместо этого весь набор битов может быть преобразован в массив строк, чтобы пропустить извлечение подмножества.

0
По вопросам рекламы [email protected]