2012-06-12 20 views
14

Próbuję zrobić bitmapę w C, właśnie z kodu. Obecnie próbuję utworzyć bardzo prosty obraz .bmp o wysokości 1 piksela i szerokości 4 pikseli ze wszystkimi białymi pikselami. Przeczytałem opis formatu i próbowałem go zastosować. W rezultacie powstał następujący kod:Tworzenie pliku BMP (mapa bitowa) w 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); 
} 

Kiedy próbuję otworzyć ten obraz, mówi on, że obraz jest uszkodzony. Czy coś mi umyka?

Zauważyłem również, że kodowanie liczb całkowitych .bmp jest małe endian. Myślałem, że to oznacza, że ​​muszę odwrócić kolejność bajtów. Na przykład 256 w czterech bajtach to: 00000000 00000000 00000001 00000000, i myślę, że w małym endianie to będzie: 00000000 00000001 00000000 00000000

Czy ktoś może mi tu podać pomocną dłoń? Czy używam właściwego podejścia? Każda pomoc będzie doceniona!

Z góry dziękuję!

+3

Narysuj obraz, który chciałbyś wygenerować za pomocą ulubionego edytora graficznego, a następnie spróbuj skopiować jego bajt po bajcie. – dasblinkenlight

+0

Masz błąd endianizmu w polach rozdzielczości. Twoja praca będzie znacznie łatwiejsza, jeśli napiszesz funkcje pomocnicze, aby pobrać 2-bajtowe i 4-bajtowe liczby całkowite i spakować je do swojej tablicy bajtów. –

+0

dasblinkenlight, próbowałem to zrobić w Pixelmator (na Macu), ale dostałem plik bmp o wielkości 84 bajtów, podczas gdy oczekuję, że będzie to 66 bajtów, może spróbuję otworzyć go programem, który pokazuje mi bajt na bajt;) – Devos50

Odpowiedz

8

Twój przesunięcie pikseli (bajty 10..13) wynosi zero, ale dane pikselowe nie zacząć na początku pliku, zaczynają w bajcie 54.

również:

  • Twój komentarz na temat bajtu 34 mówi "bity", ale oznacza "bajty", ale oczywiście to nie ma znaczenia.

  • Twoje rozdzielczości w poziomie i pionie mają nieprawidłową kolejność bajtów, ale bardzo wątpię, że to ma znaczenie.

Gdybym robił to bym określić konstrukcjom dla danych nagłówka (w rzeczywistości, jeśli jesteś na Windows, Microsoft już zrobione) i użyć makra lub coś na oddanie bajtów w odpowiedniej kolejności przenośnie.

To, czy "musisz odwrócić kolejność bajtów", zależy od endianiczności procesora, z którego korzystasz. Samodzielne pisanie oddzielnych bajtów jest skutecznym sposobem, aby nie martwić się o to.

+0

Ah, więc mówisz, że przesunięcie to liczba bajtów między początkiem pliku a początek danych pikseli? Więc w tym przypadku będzie to 54 bajty (14 bajtów dla nagłówka pliku i 40 dla nagłówka bitmapy)? – Devos50

+0

Mam już działa! Problem polegał na przesunięciu piksela, zmieniłem go na 54, a teraz mogę otworzyć mapę bitową! Dziękuję wszystkim za pomoc :) – Devos50

+0

Poprawnie.[Zignoruj ​​tę notatkę - to tylko dodatkowy tekst, ponieważ Stack Overflow nie pozwala na bardzo krótkie komentarze.] –

3

Otwórz plik za pomocą edytora szesnastkowego, aby zobaczyć, co faktycznie tam jest. Pomoże to ustalić, czy twój kod robi coś nieoczekiwanego.

+0

Zdecydowanie zamierzam spróbować tego jutro! Dzieki za sugestie! – Devos50

+1

BTW, możesz chcieć otworzyć plik w trybie "wb +" (binarnym). – jdigital

4

Oto kod testowany na Linuksie.

#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

To zakłada, że ​​twoja natywna endianness jest taka sama jak Windows '(twórca formatu pliku BMP). "Testowane na Linuksie" nie mówi nic o możliwych problemach z endianizmem. – usr2564301