Création D'un fichier BMP (bitmap) en C

j'essaie de faire un bitmap en C, juste à partir du code. Je suis en train d'essayer de faire un très facile .image bmp, avec une hauteur de 1px et d'une largeur de 4 pixels, avec tous les pixels blancs. J'ai lu la description du format et a essayé de l'appliquer. Il en est résulté le code suivant:

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);
}

quand j'essaie d'ouvrir cette image, elle dit que l'image est endommagée. Suis-je manqué quelque chose?

j'ai aussi remarqué que l'encodage du .BMP entiers est petit endian. J'ai pensé que cela signifie que je dois inverser l'ordre des octets. Par exemple, 256 en quatre octets est: 00000000 00000000 00000001 00000000, et je pense en little endian ce serait: 00000000 00000001 00000000 00000000

quelqu'un Peut-il me donner un coup de main ici? Est-ce que j'utilise une bonne approche? Toute aide serait appréciée!

Merci d'avance!

14
demandé sur Prof. Falken 2012-06-13 01:05:15

3 réponses

votre pixel offset (octets 10..13) est zéro, mais les données pixel ne commencent pas réellement au début du fichier, ils commencent à l'octet 54.

Aussi:

  • votre commentaire sur le byte 34 dit "bits" mais signifie "bytes", mais bien sûr que cela n'a pas d'importance.

  • vos résolutions horizontales et verticales ont le mauvais ordre de byte, mais je doute beaucoup que cela importe.

si je le faisais, je définirais les structures pour les données d'en-tête (en effet, si vous êtes sous Windows, Microsoft l'a déjà fait) et utilisez une macro ou quelque chose pour mettre des octets dans le bon ordre de façon portable.

Si vous "devez inverser l'ordre des octets" dépend de la endianity du processeur que vous utilisez. Écrire des octets séparés séparément, comme vous le faites, est un moyen efficace pour éviter d'avoir à s'inquiéter à ce sujet.

8
répondu Gareth McCaughan 2012-06-12 21:16:09

Voici le code testé sur 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);
}
4
répondu Balamurugan A 2014-04-25 22:06:50

Ouvrez votre fichier avec un éditeur hexadécimal pour voir ce qui est réellement là. Cela vous aidera à déterminer si votre code fait quelque chose d'inattendu.

3
répondu jdigital 2012-06-12 21:17:29