2012-06-12 23 views
14

Ich versuche, eine Bitmap in C nur aus Code zu erstellen. Ich versuche gerade, ein sehr einfaches .bmp-Bild mit einer Höhe von 1 Pixel und einer Breite von 4 Pixel mit allen weißen Pixeln zu erstellen. Ich habe die Formatbeschreibung gelesen und versucht, sie anzuwenden. Dies führte zu dem folgenden Code:Erstellen einer BMP-Datei (Bitmap) in C

char bitmap[1000]; 

void BMPmake() 
{ 
    // -- FILE HEADER -- // 

    // bitmap signature 
    bitmap[0] = 'B'; 
    bitmap[1] = 'M'; 

    // file size 
    bitmap[2] = 66; // 40 + 14 + 12 
    bitmap[3] = 0; 
    bitmap[4] = 0; 
    bitmap[5] = 0; 

    // reserved field (in hex. 00 00 00 00) 
    for(int i = 6; i < 10; i++) bitmap[i] = 0; 

    // offset of pixel data inside the image 
    for(int i = 10; i < 14; i++) bitmap[i] = 0; 

    // -- BITMAP HEADER -- // 

    // header size 
    bitmap[14] = 40; 
    for(int i = 15; i < 18; i++) bitmap[i] = 0; 

    // width of the image 
    bitmap[18] = 4; 
    for(int i = 19; i < 22; i++) bitmap[i] = 0; 

    // height of the image 
    bitmap[22] = 1; 
    for(int i = 23; i < 26; i++) bitmap[i] = 0; 

    // reserved field 
    bitmap[26] = 1; 
    bitmap[27] = 0; 

    // number of bits per pixel 
    bitmap[28] = 24; // 3 byte 
    bitmap[29] = 0; 

    // compression method (no compression here) 
    for(int i = 30; i < 34; i++) bitmap[i] = 0; 

    // size of pixel data 
    bitmap[34] = 12; // 12 bits => 4 pixels 
    bitmap[35] = 0; 
    bitmap[36] = 0; 
    bitmap[37] = 0; 

    // horizontal resolution of the image - pixels per meter (2835) 
    bitmap[38] = 0; 
    bitmap[39] = 0; 
    bitmap[40] = 0b00110000; 
    bitmap[41] = 0b10110001; 

    // vertical resolution of the image - pixels per meter (2835) 
    bitmap[42] = 0; 
    bitmap[43] = 0; 
    bitmap[44] = 0b00110000; 
    bitmap[45] = 0b10110001; 

    // color pallette information 
    for(int i = 46; i < 50; i++) bitmap[i] = 0; 

    // number of important colors 
    for(int i = 50; i < 54; i++) bitmap[i] = 0; 

    // -- PIXEL DATA -- // 
    for(int i = 54; i < 66; i++) bitmap[i] = 0; 
} 

void BMPwrite() 
{ 
    FILE *file; 
    file = fopen("bitmap.bmp", "w+"); 
    for(int i = 0; i < 66; i++) 
    { 
     fputc(bitmap[i], file); 
    } 
    fclose(file); 
} 

Wenn ich versuche, dieses Bild zu öffnen, heißt es, dass das Bild beschädigt ist. Fehle ich hier etwas?

Ich habe auch festgestellt, dass die Kodierung der .bmp Integer ist Little Endian. Ich dachte, dass dies bedeutet, dass ich die Reihenfolge der Bytes umkehren muss. Zum Beispiel ist 256 in vier Bytes: 00000000 00000000 00000001 00000000, und ich denke, in Little Endian wäre das: 00000000 00000001 00000000 00000000

Kann mir jemand hier helfen? Benütze ich einen richtigen Ansatz? Jede Hilfe wäre willkommen!

Vielen Dank im Voraus!

+3

Zeichnen Sie ein Bild, das Sie mit Ihrem bevorzugten Grafikeditor erstellen möchten, und versuchen Sie dann, es Byte für Byte zu replizieren. – dasblinkenlight

+0

Sie haben die Endianness falsch in den Auflösungsfeldern. Sie werden Ihre Arbeit viel einfacher finden, wenn Sie Hilfsfunktionen schreiben, die 2-Byte- und 4-Byte-Ganzzahlen aufnehmen und sie für Sie in Ihr Byte-Array packen. –

+0

dasblinkenlight, ich habe versucht, das in Pixelmator (auf dem Mac), aber ich habe eine bmp-Datei von 84 Bytes, während ich erwarte es 66 Bytes, vielleicht kann ich versuchen, es mit einem Programm, das zeigt mir Byte pro zeigt byte;) – Devos50

Antwort

8

Ihr Pixel-Offset (Bytes 10..13) ist Null, aber die Pixeldaten tatsächlich nicht am Anfang der Datei starten, sie beginnen bei Byte 54.

auch:

  • Ihr Kommentar zu Byte 34 sagt "Bits", bedeutet aber "Bytes", aber das spielt natürlich keine Rolle.

  • Ihre horizontalen und vertikalen Auflösungen haben die falsche Byte-Reihenfolge, aber ich bezweifle sehr, dass dies von Bedeutung ist.

Wenn ich dies tat, ich structs für die Kopfdaten definieren würde (in der Tat, wenn Sie unter Windows sind, Microsoft hat dies bereits getan) und einen Makro oder etwas für Bytes in die richtige Reihenfolge verwenden setzen portabel.

Ob Sie die Reihenfolge der Bytes umkehren müssen, hängt von der Endianität des Prozessors ab, den Sie verwenden. Das separate Schreiben von Bytes, wie Sie es gerade tun, ist ein effektiver Weg, sich darüber keine Sorgen zu machen.

+0

Ah ist. Sie sagen also, dass der Offset die Anzahl der Bytes zwischen dem Anfang der Datei und der Anfang der Pixeldaten? Also in diesem Fall wären es 54 Bytes (14 Bytes für den Dateiheader und 40 für den Bitmap-Header)? – Devos50

+0

Ich habe es jetzt funktioniert! Das Problem war in der Tat mit dem Pixel Offset, ich habe es auf 54 geändert und jetzt kann ich die Bitmap öffnen! Danke allen für ihre Hilfe :) – Devos50

+0

Richtig.[Ignoriere diesen Hinweis - es ist nur ein zusätzlicher Text, da Stack Overflow keine sehr kurzen Kommentare zulässt.] –

3

Öffnen Sie Ihre Datei mit einem Hex-Editor, um zu sehen, was tatsächlich da ist. Dadurch können Sie feststellen, ob Ihr Code etwas Unerwartetes tut.

+0

Definitiv werde ich das morgen versuchen! Danke für den Vorschlag! – Devos50

+1

BTW, möchten Sie vielleicht die Datei im "wb +" (binären) Modus öffnen. – jdigital

4

Hier ist der Code auf Linux getestet.

#include <stdio.h> 
#include <stdint.h> 
#include <string.h> 
#include <malloc.h> 
#define _height 600 
#define _width 800 
#define _bitsperpixel 24 
#define _planes 1 
#define _compression 0 
#define _pixelbytesize _height*_width*_bitsperpixel/8 
#define _filesize _pixelbytesize+sizeof(bitmap) 
#define _xpixelpermeter 0x130B //2835 , 72 DPI 
#define _ypixelpermeter 0x130B //2835 , 72 DPI 
#define pixel 0xFF 
#pragma pack(push,1) 
typedef struct{ 
    uint8_t signature[2]; 
    uint32_t filesize; 
    uint32_t reserved; 
    uint32_t fileoffset_to_pixelarray; 
} fileheader; 
typedef struct{ 
    uint32_t dibheadersize; 
    uint32_t width; 
    uint32_t height; 
    uint16_t planes; 
    uint16_t bitsperpixel; 
    uint32_t compression; 
    uint32_t imagesize; 
    uint32_t ypixelpermeter; 
    uint32_t xpixelpermeter; 
    uint32_t numcolorspallette; 
    uint32_t mostimpcolor; 
} bitmapinfoheader; 
typedef struct { 
    fileheader fileheader; 
    bitmapinfoheader bitmapinfoheader; 
} bitmap; 
#pragma pack(pop) 

int main (int argc , char *argv[]) { 
    FILE *fp = fopen("test.bmp","wb"); 
    bitmap *pbitmap = (bitmap*)calloc(1,sizeof(bitmap)); 
    uint8_t *pixelbuffer = (uint8_t*)malloc(_pixelbytesize); 
    strcpy(pbitmap->fileheader.signature,"BM"); 
    pbitmap->fileheader.filesize = _filesize; 
    pbitmap->fileheader.fileoffset_to_pixelarray = sizeof(bitmap); 
    pbitmap->bitmapinfoheader.dibheadersize =sizeof(bitmapinfoheader); 
    pbitmap->bitmapinfoheader.width = _width; 
    pbitmap->bitmapinfoheader.height = _height; 
    pbitmap->bitmapinfoheader.planes = _planes; 
    pbitmap->bitmapinfoheader.bitsperpixel = _bitsperpixel; 
    pbitmap->bitmapinfoheader.compression = _compression; 
    pbitmap->bitmapinfoheader.imagesize = _pixelbytesize; 
    pbitmap->bitmapinfoheader.ypixelpermeter = _ypixelpermeter ; 
    pbitmap->bitmapinfoheader.xpixelpermeter = _xpixelpermeter ; 
    pbitmap->bitmapinfoheader.numcolorspallette = 0; 
    fwrite (pbitmap, 1, sizeof(bitmap),fp); 
    memset(pixelbuffer,pixel,_pixelbytesize); 
    fwrite(pixelbuffer,1,_pixelbytesize,fp); 
    fclose(fp); 
    free(pbitmap); 
    free(pixelbuffer); 
} 
+0

Dies setzt voraus, dass Ihre native Endianz mit Windows 'identisch ist (der Ursprung des BMP-Dateiformats). "Getestet unter Linux" sagt nichts über mögliche Probleme mit der Endianz aus. – usr2564301