2010-11-01 3 views
0

Je veux charger un fichier bmp en mémoire dans C. J'ai trouvé beaucoup de différents types de structures BmpFileHeader et BmpInfoHeader. Le dernier que je l'ai pris de msdn.microsoft.com mais il ne lit toujours pas correctement du fichier binaire. Avec le fichier de test lena Taille de l'image: -1076791624 La mémoire n'a pas pu être allouéeProblèmes avec les structures BMP {FileHeader, InfoHeader}

Quel est le point qui me manque? Merci.

#include <stdio.h> 
#include <stdlib.h> 

typedef struct tagBITMAPFILEHEADER { 
    unsigned short bfType; 
    unsigned int bfSize; 
    short bfReserved1; 
    short bfReserved2; 
    unsigned int bfOffBits; 
} BITMAPFILEHEADER; 

typedef struct tagBITMAPINFOHEADER { 
    unsigned int biSize; 
    int biWidth; 
    int biHeight; 
    short biPlanes; 
    short biBitCount; 
    unsigned int biCompression; 
    unsigned int biSizeImage; 
    int biXPelsPerMeter; 
    int biYPelsPerMeter; 
    unsigned int biClrUsed; 
    unsigned int biClrImportant; 
} BITMAPINFOHEADER; 

int main(int argc, char *argv[]) 
{ 
    if(argc != 2) 
    { 
    printf("Usage: %s input.bmp\n", argv[0]); 
    exit(-1); 
    } 

    FILE *filePtr; 
    BITMAPFILEHEADER bitmapFileHeader; 
    BITMAPINFOHEADER bitmapInfoHeader; 
    unsigned char *bitmapImage; 
    int imageIdx=0; 
    unsigned char tempRGB; 

    filePtr = fopen(argv[1],"rb"); 
    if (filePtr == NULL) 
    { 
    printf("File could not opened\n"); 
    exit(-1); 
    } 

    //read the bitmap file header 
    fread(&bitmapFileHeader, sizeof(bitmapFileHeader), 1, filePtr); 

    if (bitmapFileHeader.bfType !=0x4D42) 
    { 
    fclose(filePtr); 
    printf("Not a bmp file\n"); 
    exit(-1); 
    } 

    fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET); 
    bitmapImage = (unsigned char*)malloc(sizeof(unsigned char)*bitmapInfoHeader.biSizeImage); 
    printf("Image Size: %d\n", bitmapInfoHeader.biSizeImage); 

    if (!bitmapImage) 
    { 
    free(bitmapImage); 
    fclose(filePtr); 
    printf("Memory could not be allocated\n"); 
    exit(-1); 
    } 

    //swap the r and b values to get RGB (bitmap is BGR) 
    for (imageIdx = 0; imageIdx < bitmapInfoHeader.biSizeImage; imageIdx+=3) 
    { 
    tempRGB = bitmapImage[imageIdx]; 
    bitmapImage[imageIdx] = bitmapImage[imageIdx + 2]; 
    bitmapImage[imageIdx + 2] = tempRGB; 
    } 

    int i; 

    for(i = 0; i < bitmapInfoHeader.biSizeImage; i+=3){ 
    printf("R: %c G: %c B: %c\n", bitmapImage[i], bitmapImage[i + 1], bitmapImage[i + 2]); 
    } 

    fclose(filePtr); 

    return 0; 

} 
+0

Le format printf pour la taille de l'image doit être% u au lieu de% d parce que bitmapInfoHeader.biSizeImage est un int non signé. Ceci empêchera l'indication de taille d'image négative trompeuse. Utilisez un débogueur pour regarder le contenu des structures après les avoir lues sur le disque pour voir si elles sont correctement remplies. Il est possible que le compilateur insère des octets de remplissage supplémentaires pour que l'alignement des mots soit agréable (voir bfReserved1/bfReserved2 et biPlanes/biBitCount). – jholl

Répondre

0

La première chose que je ferais est de trouver une déclaration faisant autorité sur le byte layout de ces en-têtes, puis, en supposant que vous souhaitiez continuer à utiliser les structures que vous avez définies, ajoutez des assertions sur les offsets, pour exemple:

assert(offsetof(BITMAPFILEHEADER, bfType) == 0);  // or whatever 
assert(offsetof(BITMAPFILEHEADER, bfSize) == 2);  // or whatever 
assert(offsetof(BITMAPFILEHEADER, bfOffBits) == 10); // or whatever 
etc. 

Il y a des chances que votre utilisation de unsigned int, court, etc ainsi que vos options de compilateur (en particulier l'emballage de la structure) pourrait signifier que vos champs de struct ne correspondent pas aux données de fichier BMP réelles (en offset, et peut-être en longueur).

0

Votre bitmapInfoHeader est uninitialized!

En d'autres termes, vous lisez le bitmapFileHeader, puis définissez le pointeur de fichier sur l'emplacement réel des données bitmap. Mais vous n'avez pas lu le bitmapInfoHeader, qui contient toutes les informations sur le bitmap (dimensions, bpp et etc.)

P.S. La prochaine fois s'il vous plaît essayez de déboguer votre code avant de poster la question.

+0

Oui, vous avez raison. J'ai ajouté la ligne; fread (& bitmapInfoHeader, sizeof (bitmapInfoHeader), 1, fichierPtr); Cependant, la sortie est; Taille de l'image: 4 R: 0 G: 0 B: 0 R: 0 G: 0 B: 0 Le fichier image est de 257,1 ko..Quelque chose ne va pas – anarhikos

0

Il existe plusieurs versions du format de fichier BMP et la plupart d'entre elles diffèrent par la taille des en-têtes. Si vous voulez pouvoir lire tous les fichiers BMP valides, vous devez tous les prendre en charge. L'image lena semble être une version de Windows V3.

Il existe une bonne description des différentes versions dans Wikipedia.

En outre, je ne vois pas de gestion endianness dans votre code. Si vous êtes une machine n'est pas petit boutiste, ça ne marchera pas.

Enfin, l'alignement des membres struct est un problème. Votre compilateur alignera vraisemblablement le membre bfSize au décalage 4, mais il devrait être au décalage 2. (Voir l'article de Wikipedia pour une solution.)