Search code examples
clinuxgccraspbianfread

I can't read .bmp file in C on Linux, but I can do it in raspbian (same code)


Sorry for my bad English.

Im trying to read a .bmp file in a C code using gcc on Linux (Fedora 27) but it doesn't work, the specific problem is when I use "fread()". I run the same code on raspbian (4.9.2-10) and magically works, read and write a .bmp file correctly. I really don't know what happening, I need help, please :'(

I use this image: https://mega.nz/#!c5hVEYTb!u4Mc3JxvrHxxpaMLpH8A-KS3_bb72_Nj9bHv1x-2keU

This is the code:

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



#pragma pack(push, 1)
typedef struct Pix
{
  unsigned char R;
  unsigned char G;
  unsigned char B;
  unsigned char L;
  int BW;
}Pix;
#pragma pack(pop)


#pragma pack(push, 1)
typedef struct BitMap
{
    short Signature;                        
    long Reserved1;             
    long Reserved2;             
    long DataOffSet;            

    long Size;                  
    long Width;             
    long Height;                
    short Planes;               
    short BitsPerPixel;         
    long Compression;           
    long SizeImage;                 
    long XPixelsPreMeter;       
    long YPixelsPreMeter;       
    long ColorsUsed;            
    long ColorsImportant;       
    struct Pix *pixels;         
}BitMap;
#pragma pack(pop)


int main(int argc, char **argv)
{
    unsigned long int i=0;
    unsigned long int S=0;

    struct BitMap source_info;
    struct Pix source_pix;

    FILE *fp;
    FILE *Dfp;

    fp=fopen("in.bmp","rb");
    if (fp==NULL)
    {
        fputs("File error:", stderr);
        exit(1);
    }


    Dfp=fopen("out.bmp","wb");


    //I think maybe in this line is the problem:
    fread(&source_info, sizeof(source_info),1,fp); 

    S=source_info.Width*source_info.Height;
    source_info.pixels =  (struct Pix *) malloc(sizeof(struct Pix)*S);

    for(i=1;i<=S;i++)
    {
        //read pixel from the source file
        fread(&source_pix,sizeof(struct Pix),1,fp);
        source_info.pixels[i-1] = source_pix;
    }

    fwrite(&source_info, sizeof(BitMap),1,Dfp);

    // write pixels to destination file
    for(i=1;i<=S;i++)
    {
        fwrite(&source_info.pixels[i-1],sizeof(struct Pix),1,Dfp);
    }

    fclose(fp);
    fclose(Dfp);

    return 0;
}

Solution

  • You are not using fixed size types between architectures. For example on a 32-bit platform long is 32 bit, but on 64-bit long is 64 bit, which is why on a 64-bit platform it can not read the headers correctly. The solution is to use the defines in stdint.

    #include <stdint.h>
    
    #pragma pack(push, 1)
    typedef struct Pix
    {
        uint8_t R, G, B;
        int32_t BW;
    }
    Pix;
    
    typedef struct BitMap
    {
        int16_t Signature;                        
        int32_t Reserved1;             
        int32_t Reserved2;             
        int32_t DataOffSet;            
    
        int32_t Size;                  
        int32_t Width;             
        int32_t Height;                
        int16_t Planes;               
        int16_t BitsPerPixel;         
        int32_t Compression;           
        int32_t SizeImage;                 
        int32_t XPixelsPreMeter;       
        int32_t YPixelsPreMeter;       
        int32_t ColorsUsed;            
        int32_t ColorsImportant;       
        struct Pix *pixels;         
    }
    BitMap;
    #pragma pack(pop)