Escrevendo a imagem BMP em c / c ++ puro sem outras bibliotecas

No meu algoritmo eu preciso criar saída de informação. Devo escrever matriz booleana no arquivo bmp. Deve ser uma imagem monocromática, em que o pixel é branco se a matriz desse elemento for verdadeira. O principal problema é o header bmp e como escrever isso.

Sem o uso de qualquer outra biblioteca, você pode ver o formato de arquivo BMP . Eu implementei isso no passado e isso pode ser feito sem muito trabalho.

Estruturas de arquivos de bitmap

Cada arquivo de bitmap contém um header de arquivo de bitmap, um header de informações de bitmap, uma tabela de colors e uma matriz de bytes que define os bits de bitmap. O arquivo tem o seguinte formato:

BITMAPFILEHEADER bmfh;
BITMAPINFOHEADER bmih;
RGBCARAD aColors [];
BYTE aBitmapBits [];

… veja o formato do arquivo para mais detalhes

Veja se isso funciona para você … Neste código, eu tinha 3 matrizes bidimensionais, chamadas vermelho, verde e azul. Cada um era de tamanho [largura] [altura] e cada elemento correspondia a um pixel – espero que isso faça sentido!

FILE *f; unsigned char *img = NULL; int filesize = 54 + 3*w*h; //w is your image width, h is image height, both int img = (unsigned char *)malloc(3*w*h); memset(img,0,3*w*h); for(int i=0; i 255) r=255; if (g > 255) g=255; if (b > 255) b=255; img[(x+y*w)*3+2] = (unsigned char)(r); img[(x+y*w)*3+1] = (unsigned char)(g); img[(x+y*w)*3+0] = (unsigned char)(b); } } unsigned char bmpfileheader[14] = {'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0}; unsigned char bmpinfoheader[40] = {40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0}; unsigned char bmppad[3] = {0,0,0}; bmpfileheader[ 2] = (unsigned char)(filesize ); bmpfileheader[ 3] = (unsigned char)(filesize>> 8); bmpfileheader[ 4] = (unsigned char)(filesize>>16); bmpfileheader[ 5] = (unsigned char)(filesize>>24); bmpinfoheader[ 4] = (unsigned char)( w ); bmpinfoheader[ 5] = (unsigned char)( w>> 8); bmpinfoheader[ 6] = (unsigned char)( w>>16); bmpinfoheader[ 7] = (unsigned char)( w>>24); bmpinfoheader[ 8] = (unsigned char)( h ); bmpinfoheader[ 9] = (unsigned char)( h>> 8); bmpinfoheader[10] = (unsigned char)( h>>16); bmpinfoheader[11] = (unsigned char)( h>>24); f = fopen("img.bmp","wb"); fwrite(bmpfileheader,1,14,f); fwrite(bmpinfoheader,1,40,f); for(int i=0; i 

Este é o melhor exemplo de baixo nível que conheço, escrito por Evercat. copiado de https://en.wikipedia.org/wiki/User:Evercat/Buddhabrot.c

 void drawbmp (char * filename) { unsigned int headers[13]; FILE * outfile; int extrabytes; int paddedsize; int x; int y; int n; int red, green, blue; extrabytes = 4 - ((WIDTH * 3) % 4); // How many bytes of padding to add to each // horizontal line - the size of which must // be a multiple of 4 bytes. if (extrabytes == 4) extrabytes = 0; paddedsize = ((WIDTH * 3) + extrabytes) * HEIGHT; // Headers... // Note that the "BM" identifier in bytes 0 and 1 is NOT included in these "headers". headers[0] = paddedsize + 54; // bfSize (whole file size) headers[1] = 0; // bfReserved (both) headers[2] = 54; // bfOffbits headers[3] = 40; // biSize headers[4] = WIDTH; // biWidth headers[5] = HEIGHT; // biHeight // Would have biPlanes and biBitCount in position 6, but they're shorts. // It's easier to write them out separately (see below) than pretend // they're a single int, especially with endian issues... headers[7] = 0; // biCompression headers[8] = paddedsize; // biSizeImage headers[9] = 0; // biXPelsPerMeter headers[10] = 0; // biYPelsPerMeter headers[11] = 0; // biClrUsed headers[12] = 0; // biClrImportant outfile = fopen(filename, "wb"); // // Headers begin... // When printing ints and shorts, we write out 1 character at a time to avoid endian issues. // fprintf(outfile, "BM"); for (n = 0; n < = 5; n++) { fprintf(outfile, "%c", headers[n] & 0x000000FF); fprintf(outfile, "%c", (headers[n] & 0x0000FF00) >> 8); fprintf(outfile, "%c", (headers[n] & 0x00FF0000) >> 16); fprintf(outfile, "%c", (headers[n] & (unsigned int) 0xFF000000) >> 24); } // These next 4 characters are for the biPlanes and biBitCount fields. fprintf(outfile, "%c", 1); fprintf(outfile, "%c", 0); fprintf(outfile, "%c", 24); fprintf(outfile, "%c", 0); for (n = 7; n < = 12; n++) { fprintf(outfile, "%c", headers[n] & 0x000000FF); fprintf(outfile, "%c", (headers[n] & 0x0000FF00) >> 8); fprintf(outfile, "%c", (headers[n] & 0x00FF0000) >> 16); fprintf(outfile, "%c", (headers[n] & (unsigned int) 0xFF000000) >> 24); } // // Headers done, now write the data... // for (y = HEIGHT - 1; y >= 0; y--) // BMP image format is written from bottom to top... { for (x = 0; x < = WIDTH - 1; x++) { red = reduce(redcount[x][y] + COLOUR_OFFSET) * red_multiplier; green = reduce(greencount[x][y] + COLOUR_OFFSET) * green_multiplier; blue = reduce(bluecount[x][y] + COLOUR_OFFSET) * blue_multiplier; if (red > 255) red = 255; if (red < 0) red = 0; if (green > 255) green = 255; if (green < 0) green = 0; if (blue > 255) blue = 255; if (blue < 0) blue = 0; // Also, it's written in (b,g,r) format... fprintf(outfile, "%c", blue); fprintf(outfile, "%c", green); fprintf(outfile, "%c", red); } if (extrabytes) // See above - BMP lines must be of lengths divisible by 4. { for (n = 1; n <= extrabytes; n++) { fprintf(outfile, "%c", 0); } } } fclose(outfile); return; } drawbmp(filename); 

Note que as linhas são salvas de baixo para cima e não o contrário.

Além disso, as linhas de varredura devem ter um comprimento de byte de múltiplos de quatro, você deve inserir bytes de preenchimento no final das linhas para garantir isso.

Aqui está uma variante C ++ do código que funciona para mim. Observe que eu tive que alterar o cálculo de tamanho para considerar o preenchimento de linha.

 // mimeType = "image/bmp"; unsigned char file[14] = { 'B','M', // magic 0,0,0,0, // size in bytes 0,0, // app data 0,0, // app data 40+14,0,0,0 // start of data offset }; unsigned char info[40] = { 40,0,0,0, // info hd size 0,0,0,0, // width 0,0,0,0, // heigth 1,0, // number color planes 24,0, // bits per pixel 0,0,0,0, // compression is none 0,0,0,0, // image bits size 0x13,0x0B,0,0, // horz resoluition in pixel / m 0x13,0x0B,0,0, // vert resolutions (0x03C3 = 96 dpi, 0x0B13 = 72 dpi) 0,0,0,0, // #colors in pallete 0,0,0,0, // #important colors }; int w=waterfallWidth; int h=waterfallHeight; int padSize = (4-(w*3)%4)%4; int sizeData = w*h*3 + h*padSize; int sizeAll = sizeData + sizeof(file) + sizeof(info); file[ 2] = (unsigned char)( sizeAll ); file[ 3] = (unsigned char)( sizeAll>> 8); file[ 4] = (unsigned char)( sizeAll>>16); file[ 5] = (unsigned char)( sizeAll>>24); info[ 4] = (unsigned char)( w ); info[ 5] = (unsigned char)( w>> 8); info[ 6] = (unsigned char)( w>>16); info[ 7] = (unsigned char)( w>>24); info[ 8] = (unsigned char)( h ); info[ 9] = (unsigned char)( h>> 8); info[10] = (unsigned char)( h>>16); info[11] = (unsigned char)( h>>24); info[20] = (unsigned char)( sizeData ); info[21] = (unsigned char)( sizeData>> 8); info[22] = (unsigned char)( sizeData>>16); info[23] = (unsigned char)( sizeData>>24); stream.write( (char*)file, sizeof(file) ); stream.write( (char*)info, sizeof(info) ); unsigned char pad[3] = {0,0,0}; for ( int y=0; y 255 ) red=255; long green = red; long blue = red; unsigned char pixel[3]; pixel[0] = blue; pixel[1] = green; pixel[2] = red; stream.write( (char*)pixel, 3 ); } stream.write( (char*)pad, padSize ); } 

Limpe o código C para geração de imagem de bitmap (BMP)

Imagem gerada:

Imagem em formato bitmap


O código não usa nenhuma biblioteca diferente de stdio.h . Assim, o código pode ser facilmente incorporado em outras linguagens da família C, como C ++, C #, Java.


 #include  const int bytesPerPixel = 3; /// red, green, blue const int fileHeaderSize = 14; const int infoHeaderSize = 40; void generateBitmapImage(unsigned char *image, int height, int width, char* imageFileName); unsigned char* createBitmapFileHeader(int height, int width); unsigned char* createBitmapInfoHeader(int height, int width); int main(){ int height = 541; int width = 800; unsigned char image[height][width][bytesPerPixel]; char* imageFileName = "bitmapImage.bmp"; int i, j; for(i=0; i> 8); fileHeader[ 4] = (unsigned char)(fileSize>>16); fileHeader[ 5] = (unsigned char)(fileSize>>24); fileHeader[10] = (unsigned char)(fileHeaderSize + infoHeaderSize); return fileHeader; } unsigned char* createBitmapInfoHeader(int height, int width){ static unsigned char infoHeader[] = { 0,0,0,0, /// header size 0,0,0,0, /// image width 0,0,0,0, /// image height 0,0, /// number of color planes 0,0, /// bits per pixel 0,0,0,0, /// compression 0,0,0,0, /// image size 0,0,0,0, /// horizontal resolution 0,0,0,0, /// vertical resolution 0,0,0,0, /// colors in color table 0,0,0,0, /// important color count }; infoHeader[ 0] = (unsigned char)(infoHeaderSize); infoHeader[ 4] = (unsigned char)(width ); infoHeader[ 5] = (unsigned char)(width>> 8); infoHeader[ 6] = (unsigned char)(width>>16); infoHeader[ 7] = (unsigned char)(width>>24); infoHeader[ 8] = (unsigned char)(height ); infoHeader[ 9] = (unsigned char)(height>> 8); infoHeader[10] = (unsigned char)(height>>16); infoHeader[11] = (unsigned char)(height>>24); infoHeader[12] = (unsigned char)(1); infoHeader[14] = (unsigned char)(bytesPerPixel*8); return infoHeader; } 

Eu editei o código htp do ralf para que ele compilasse (no gcc, executando o Ubuntu 16.04 lts). Foi apenas uma questão de inicializar as variables.

  int w = 100; /* Put here what ever width you want */ int h = 100; /* Put here what ever height you want */ int red[w][h]; int green[w][h]; int blue[w][h]; FILE *f; unsigned char *img = NULL; int filesize = 54 + 3*w*h; //w is your image width, h is image height, both int if( img ) free( img ); img = (unsigned char *)malloc(3*w*h); memset(img,0,sizeof(img)); int x; int y; int r; int g; int b; for(int i=0; i 255) r=255; if (g > 255) g=255; if (b > 255) b=255; img[(x+y*w)*3+2] = (unsigned char)(r); img[(x+y*w)*3+1] = (unsigned char)(g); img[(x+y*w)*3+0] = (unsigned char)(b); } } unsigned char bmpfileheader[14] = {'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0}; unsigned char bmpinfoheader[40] = {40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0}; unsigned char bmppad[3] = {0,0,0}; bmpfileheader[ 2] = (unsigned char)(filesize ); bmpfileheader[ 3] = (unsigned char)(filesize>> 8); bmpfileheader[ 4] = (unsigned char)(filesize>>16); bmpfileheader[ 5] = (unsigned char)(filesize>>24); bmpinfoheader[ 4] = (unsigned char)( w ); bmpinfoheader[ 5] = (unsigned char)( w>> 8); bmpinfoheader[ 6] = (unsigned char)( w>>16); bmpinfoheader[ 7] = (unsigned char)( w>>24); bmpinfoheader[ 8] = (unsigned char)( h ); bmpinfoheader[ 9] = (unsigned char)( h>> 8); bmpinfoheader[10] = (unsigned char)( h>>16); bmpinfoheader[11] = (unsigned char)( h>>24); f = fopen("img.bmp","wb"); fwrite(bmpfileheader,1,14,f); fwrite(bmpinfoheader,1,40,f); for(int i=0; i 

Se você obtiver colors estranhas, alternará no meio da imagem usando a function C ++ acima. Certifique-se de abrir o outstream no modo binário: imgFile.open(filename, std::ios_base::out | std::ios_base::binary);
Caso contrário, o Windows insere caracteres indesejados no meio do seu arquivo! (batendo minha cabeça nesta questão por horas)

Veja a questão relacionada aqui: Por que o ofstream insere um byte 0x0D antes de 0x0A?