Escribir una imagen BMP en c / c ++ puro sin otras bibliotecas

En mi algoritmo necesito crear salida de información. Debo escribir una matriz booleana en un archivo bmp. Debe ser una imagen monocromica, donde el píxel es blanco si la matriz en dicho elemento es verdadera. El principal problema es el encabezado bmp y cómo escribir esto.

Sin el uso de ninguna otra biblioteca puede mirar el formato de archivo BMP . Lo he implementado en el pasado y se puede hacer sin demasiado trabajo.

Estructuras de archivo de bitmap

Cada archivo de bitmap contiene un encabezado de archivo de bitmap, un encabezado de información de bitmap, una tabla de colores y una matriz de bytes que define los bits de bitmap. El archivo tiene la siguiente forma:

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

… ver el formato de archivo para más detalles

Vea si esto funciona para usted … En este código, tenía 3 arrays bidimensionales, llamados rojo, verde y azul. Cada uno era de tamaño [ancho] [alto], y cada elemento correspondía a un píxel. ¡Espero que tenga 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 es el mejor ejemplo de bajo nivel que conozco, 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); 

Tenga en cuenta que las líneas se guardan de abajo hacia arriba y no al revés.

Además, las líneas de exploración deben tener un byte de longitud de múltiplos de cuatro, debe insertar bytes de relleno al final de las líneas para garantizar esto.

Aquí hay una variante C ++ del código que funciona para mí. Tenga en cuenta que tuve que cambiar el cálculo de tamaño para dar cuenta del relleno de línea.

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

Código de limpieza C para la generación de imágenes de bitmap (BMP)

Imagen generada:

imagen de mapa de bits


El código no usa ninguna biblioteca que no sea stdio.h . Por lo tanto, el código se puede incorporar fácilmente en otros lenguajes de C-Family, 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; } 

Edité el código htp de ralf para que comstackra (en gcc, ejecutando ubuntu 16.04 lts). Fue solo una cuestión de inicialización de las 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 

Si obtienes interruptores de colores extraños en el medio de tu imagen usando la función C ++ anterior. Asegúrese de abrir el outstream en modo binario: imgFile.open(filename, std::ios_base::out | std::ios_base::binary);
¡De lo contrario, Windows inserta caracteres no deseados en el medio de tu archivo! (me he estado dando vueltas con este tema durante horas)

Consulte la pregunta relacionada aquí: ¿Por qué ofstream inserta un byte 0x0D antes de 0x0A?

    Intereting Posts