2012-06-12 16 views
14

Sto provando a creare una bitmap in C, solo dal codice. Attualmente sto cercando di creare un'immagine .bmp molto semplice, con un'altezza di 1 pixel e una larghezza di 4 pixel, con tutti i pixel bianchi. Ho letto la descrizione del formato e ho provato ad applicarlo. Ciò ha provocato il seguente codice:Creazione di un file BMP (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); 
} 

Quando provo ad aprire questa immagine, si dice che l'immagine è danneggiata. Mi sto perdendo qualcosa qui?

Ho anche notato che la codifica degli interi .bmp è little endian. Ho pensato che questo significa che devo invertire l'ordine dei byte. Ad esempio, 256 in quattro byte è: 00000000 00000000 00000001 00000000, e penso che in little endian questo sarebbe: 00000000 00000001 00000000 00000000

Qualcuno può darmi una mano qui? Sto usando un approccio corretto? Qualsiasi aiuto sarebbe apprezzato!

Grazie in anticipo!

+3

Disegna un'immagine che desideri generare utilizzando il tuo editor grafico preferito, quindi prova a replicarla byte per byte. – dasblinkenlight

+0

Hai sbagliato l'endianità nei campi della risoluzione. Troverai il tuo lavoro molto più semplice se scrivi funzioni di supporto per prendere interi a 2 e 4 byte e li impacchetta nel tuo array di byte. –

+0

dasblinkenlight, ho provato a farlo in Pixelmator (su Mac), ma ho ottenuto un file bmp di 84 byte mentre mi aspetto che sia 66 byte, forse posso provare ad aprirlo con un programma che mi mostra byte per byte;) – Devos50

risposta

8

compensare il pixel (byte 10..13) è pari a zero, ma i dati dei pixel in realtà non iniziare all'inizio del file, cominciano al byte 54.

anche:

  • Il tuo commento sul byte 34 dice "bit" ma significa "byte", ma ovviamente non importa.

  • Le risoluzioni orizzontali e verticali hanno l'ordine dei byte errato, ma dubito fortemente che ciò contenga.

se fossi facendo questo mi piacerebbe definire le strutture per i dati di intestazione (anzi, se siete su Windows, Microsoft ha già fatto) e utilizzare una macro o qualcosa per mettere byte in giusto ordine portabile.

Se "si deve invertire l'ordine dei byte" dipende dalla endianità del processore che si sta utilizzando. Scrivere separatamente byte separati, come si sta facendo, è un modo efficace per evitare di doversi preoccupare di questo.

+0

Ah, quindi stai dicendo che l'offset è il numero di byte tra l'inizio del file e l'inizio dei dati dei pixel? Quindi in questo caso sarebbero 54 byte (14 byte per l'intestazione del file e 40 per l'intestazione della bitmap)? – Devos50

+0

Ho funzionato ora! Il problema era in effetti con l'offset del pixel, l'ho modificato in 54 e ora posso aprire la bitmap! Grazie a tutti per il loro aiuto :) – Devos50

+0

Corretto.[Ignora questa nota: è solo un testo in più perché Stack Overflow non consente commenti molto brevi.] –

3

Apri il file con un editor esadecimale per vedere cosa c'è effettivamente. Questo ti aiuterà a determinare se il tuo codice sta facendo qualcosa di inaspettato.

+0

Sicuramente andrò a provarlo domani! Grazie per il suggerimento! – Devos50

+1

BTW, potresti voler aprire il file in modalità "wb +" (binaria). – jdigital

4

Ecco il codice testato su linux.

#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

Questo presuppone che il tuo endianness nativo sia lo stesso di Windows '(il creatore del formato di file BMP). "Testato su Linux" non dice nulla sui possibili problemi di endianness. – usr2564301