2010-04-16 4 views
33

In meinem Algorithmus muss ich Informationsausgabe erstellen. Ich muss Boolesche Matrix in BMP-Datei schreiben. Es muss monochrome Bild sein, wobei Pixel weiß ist, wenn die Matrix auf einem solchen Element wahr ist. Hauptproblem ist bmp-Header und wie man dies schreibt.Schreiben von BMP-Bild in reinem c/C++ ohne andere Bibliotheken

+1

können Sie http://qdbmp.sourceforge.net/ Details Implementierung überprüfen :). – Marco

+0

Vielleicht von Nutzen für Besucher Googling ähnliche Konzepte ist meine fast verwandte Frage und Antwort hier: http://stackoverflow.com/questions/17918978/plot-an-array-into-bitmap-in-c-for-thermal-printer –

Antwort

20

Ohne die Verwendung einer anderen Bibliothek können Sie die BMP file format betrachten. Ich habe es in der Vergangenheit implementiert und es kann ohne zu viel Arbeit getan werden.

Bitmap-Datei-Strukturen

Jede Bitmap-Datei enthält einen Bitmap-Datei-Header, ein Bitmap-Informationskopf, eine Farbtabelle und ein Array von Bytes, die die Bits Bitmap definiert. Die Datei hat das folgende Formular:

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

... sehen Sie das Dateiformat für mehr Details

+0

Vielen Dank. Es scheint zu gute Beschreibung. –

+1

Denken Sie daran, alles aus Little-Endian zu schreiben, wenn Ihr Prozessor nicht x86 ist. –

+0

Ich habe x86 danke. –

6

Beachten Sie, dass die Linien von unten nach oben und nicht umgekehrt gespeichert werden.

Zusätzlich müssen die Scanlines eine Byte-Länge von Vielfachen von vier haben, Sie sollten am Ende der Zeilen Füllbytes einfügen, um dies zu gewährleisten.

+2

Ich begreife nichts, was du geschrieben hast. –

+15

Mach dir keine Sorgen, du wirst es einmal versuchen, dies zu implementieren. –

+1

@Ben, es ist leicht, die Vielfachen von vier Anforderungen beim Testen zu verpassen, da die meisten realen Bilder bereits ein Vielfaches von 4 sind. –

41

Sehen Sie, ob dies für Sie funktioniert ... In diesem Code hatte ich 3 2-dimensionale Arrays, genannt rot, grün und blau. Jeder hatte die Größe [Breite] [Höhe], und jedes Element entsprach einem Pixel - ich hoffe, das macht Sinn!

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<w; i++) 
{ 
    for(int j=0; j<h; j++) 
    { 
     x=i; y=(h-1)-j; 
     r = red[i][j]*255; 
     g = green[i][j]*255; 
     b = blue[i][j]*255; 
     if (r > 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<h; i++) 
{ 
    fwrite(img+(w*(h-i-1)*3),3,w,f); 
    fwrite(bmppad,1,(4-(w*3)%4)%4,f); 
} 

free(img); 
fclose(f); 
+10

Hmm, Kommentare würden nicht weh tun. –

+1

Wahr, aber der ganze Code ist selbsterklärend. Und es funktioniert. Setzen Sie es einfach in die 'main()' Funktion und initialisieren Sie alle Variablen. Und fertig! ;) – sinner

+7

Kann mir jemand sagen, was im Code 'yres' steht ?? –

5

Hier ist eine C++ - Variante des Codes, die für mich funktioniert. Hinweis: Ich musste die Größenberechnung ändern, um den Zeilenabstand zu berücksichtigen.

// 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<h; y++) 
{ 
    for (int x=0; x<w; x++) 
    { 
     long red = lround(255.0 * waterfall[x][y]); 
     if (red < 0) red=0; 
     if (red > 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); 
} 
+1

Die Padsize scheint nicht richtig zu sein; Ich glaube, es sollte sein: 'int padSize = (4 - 3 * w% 4)% 4;' – etienne

+3

Was ist Wasserfall [] [] hier? – manujmv

1

Wenn Sie seltsame Farben Schalter in der Mitte Ihres Bildes mithilfe der obigen C++ - Funktion erhalten. Achten Sie darauf, den Outstream im Binärmodus zu öffnen: imgFile.open(filename, std::ios_base::out | std::ios_base::binary);
Andernfalls fügt Windows unerwünschte Zeichen in der Mitte der Datei ein! (Worden schlägt meinen Kopf zu diesem Thema für Stunden)

damit verbundene Frage Siehe hier: Why does ofstream insert a 0x0D byte before 0x0A?

6

dies ist das beste Low-Pegel Beispiel weiß ich, von Evercat geschrieben. kopiert von 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); 
+0

Antwort mit nur Link ist nicht gut, sollten Sie einige Informationen über die Antwort zur Verfügung stellen. –

+0

@kevstev nicht bearbeiten, ist eine funktionierende Lösung. Wenn Sie dieses Programm anpassen möchten, veröffentlichen Sie in diesem Thread eine neue Version in einer neuen Antwort –

1

I edited htp-Code des ralf, so dass sie (auf gcc, ubuntu 16.04 LTS läuft) kompilieren würde. Es war nur eine Frage der Initialisierung der Variablen.

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<w; i++) 
    { 
      for(int j=0; j<h; j++) 
      { 
        x=i; y=(h-1)-j; 
        r = red[i][j]*255; 
        g = green[i][j]*255; 
        b = blue[i][j]*255; 
        if (r > 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<h; i++) 
    { 
      fwrite(img+(w*(h-i-1)*3),3,w,f); 
      fwrite(bmppad,1,(4-(w*3)%4)%4,f); 
    } 
    fclose(f); 
2

reinigen C-Code für Bitmap (BMP) Bilderzeugung

generiert:

bitmap image


Der Code jede Bibliothek nicht anders als stdio.h verwenden. So kann der Code leicht in andere Sprachen der C-Familie integriert werden, wie C++, C#, Java.


#include <stdio.h> 

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<height; i++){ 
     for(j=0; j<width; j++){ 
      image[i][j][2] = (unsigned char)((double)i/height*255); ///red 
      image[i][j][1] = (unsigned char)((double)j/width*255); ///green 
      image[i][j][0] = (unsigned char)(((double)i+j)/(height+width)*255); ///blue 
     } 
    } 

    generateBitmapImage((unsigned char *)image, height, width, imageFileName); 
} 


void generateBitmapImage(unsigned char *image, int height, int width, char* imageFileName){ 

    unsigned char* fileHeader = createBitmapFileHeader(height, width); 
    unsigned char* infoHeader = createBitmapInfoHeader(height, width); 
    unsigned char padding[3] = {0, 0, 0}; 
    int paddingSize = (4-(width*bytesPerPixel)%4)%4; 

    FILE* imageFile = fopen(imageFileName, "wb"); 

    fwrite(fileHeader, 1, fileHeaderSize, imageFile); 
    fwrite(infoHeader, 1, infoHeaderSize, imageFile); 

    int i; 
    for(i=0; i<height; i++){ 
     fwrite(image+(i*width*bytesPerPixel), bytesPerPixel, width, imageFile); 
     fwrite(padding, 1, paddingSize, imageFile); 
    } 

    fclose(imageFile); 
} 

unsigned char* createBitmapFileHeader(int height, int width){ 
    int fileSize = fileHeaderSize + infoHeaderSize + bytesPerPixel*height*width; 

    static unsigned char fileHeader[] = { 
     0,0, /// signature 
     0,0,0,0, /// image file size in bytes 
     0,0,0,0, /// reserved 
     0,0,0,0, /// start of pixel array 
    }; 

    fileHeader[ 0] = (unsigned char)('B'); 
    fileHeader[ 1] = (unsigned char)('M'); 
    fileHeader[ 2] = (unsigned char)(fileSize ); 
    fileHeader[ 3] = (unsigned char)(fileSize>> 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; 
} 
Verwandte Themen