2012-06-12 31 views
14

Tôi đang cố gắng tạo một bitmap trong C, chỉ từ mã. Tôi hiện đang cố gắng tạo một hình ảnh .bmp rất dễ, với chiều cao là 1px và chiều rộng là 4 pixel, với tất cả các pixel màu trắng. Tôi đã đọc mô tả định dạng và cố gắng áp dụng nó. Điều này dẫn đến đoạn mã sau:Tạo một tập tin BMP (bitmap) trong 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); 
} 

Khi tôi cố gắng để mở hình ảnh này, nó nói rằng hình ảnh bị hư hỏng. Am i thiếu cái gì ở đây?

Tôi cũng nhận thấy rằng việc mã hóa các số nguyên .bmp là ít kết thúc. Tôi nghĩ rằng điều này có nghĩa là tôi phải đảo ngược thứ tự các byte. Ví dụ, 256 trong bốn byte là: 00000000 00000000 00000001 00000000, và tôi nghĩ rằng trong ít endian này sẽ là: 00000000 00000001 00000000 00000000

Bất cứ ai có thể cho tôi một bàn tay ở đây? Tôi đang sử dụng một cách tiếp cận đúng? Bất kỳ trợ giúp sẽ được đánh giá cao!

Cảm ơn trước!

+3

Vẽ hình ảnh mà bạn muốn tạo bằng trình chỉnh sửa đồ họa yêu thích của mình, sau đó thử sao chép byte theo byte. – dasblinkenlight

+0

Bạn đã có sai số cuối cùng trên các trường có độ phân giải. Bạn sẽ tìm thấy công việc của mình dễ dàng hơn nhiều nếu bạn viết các hàm trợ giúp để lấy các số nguyên 2 byte và 4 byte và gộp chúng vào mảng byte của bạn cho bạn. –

+0

dasblinkenlight, tôi đã thử làm điều đó trong Pixelmator (trên Mac), nhưng tôi có một tập tin bmp 84 byte trong khi tôi hy vọng nó là 66 byte, có lẽ tôi có thể thử mở nó với một chương trình cho thấy tôi byte mỗi byte;) – Devos50

Trả lời

8

điểm ảnh của bạn bù đắp (byte 10..13) là số không, nhưng dữ liệu pixel không thực sự bắt đầu vào đầu của tập tin, họ bắt đầu từ byte 54.

Ngoài ra:

  • Nhận xét của bạn về byte 34 nói "bit" nhưng có nghĩa là "byte", nhưng tất nhiên điều đó không quan trọng.

  • Độ phân giải ngang và dọc của bạn có thứ tự byte sai, nhưng tôi rất nghi ngờ rằng điều đó quan trọng.

Nếu tôi làm điều này, tôi xác định cấu trúc cho dữ liệu tiêu đề (thực sự, nếu bạn đang sử dụng Windows, Microsoft đã thực hiện việc này) và sử dụng macro hoặc thứ gì đó để đặt byte vào đúng thứ tự một cách hợp lý.

Cho dù bạn "phải đảo ngược thứ tự các byte" phụ thuộc vào độ cuối của bộ xử lý bạn đang sử dụng. Viết riêng các byte riêng biệt, như bạn đang làm, là một cách hiệu quả để tránh phải lo lắng về điều này.

+0

Ah, vì vậy bạn đang nói rằng bù đắp là số byte giữa đầu tệp và sự bắt đầu của dữ liệu pixel? Vì vậy, trong trường hợp này nó sẽ là 54 byte (14 byte cho tiêu đề tập tin và 40 cho tiêu đề bitmap)? – Devos50

+0

Tôi đã có nó hoạt động ngay bây giờ! Vấn đề thực sự là với bù đắp pixel, tôi đã thay đổi nó thành 54 và bây giờ tôi có thể mở bitmap! Cảm ơn tất cả mọi người đã giúp đỡ của họ :) – Devos50

+0

Đúng.[Bỏ qua lưu ý này - nó chỉ là một số văn bản bổ sung bởi vì Stack Overflow không cho phép các nhận xét rất ngắn.] –

3

Mở tệp của bạn bằng trình chỉnh sửa hex để xem những gì thực sự ở đó. Điều này sẽ giúp bạn xác định xem mã của bạn có đang làm điều gì đó không mong muốn hay không.

+0

Chắc chắn sẽ cố gắng mà ngày mai! Cám ơn vì sự gợi ý! – Devos50

+1

BTW, bạn có thể muốn mở tệp ở chế độ "wb +" (nhị phân). – jdigital

4

Đây là mã được thử nghiệm trên 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

Điều này giả định rằng tính cuối cùng của bạn giống với Windows '(trình khởi tạo của định dạng tệp BMP). "Thử nghiệm trên Linux" không nói gì về các vấn đề có thể có của endianness. – usr2564301

Các vấn đề liên quan