0

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;
}
  • 2
    "It doesn't work" is not sufficiently clear when you describe the program behavior. What's the error messages? – user202729 Feb 25 '18 at 06:45
  • If you think the problem is in the `fread` line, capture the return value and make sure that you get `1`. `size_t n = fread(...); if ( n != 1 ) { /* Deal with problem */ }` – R Sahu Feb 25 '18 at 06:45
  • [How to debug using GDB?](https://stackoverflow.com/questions/2069367/how-to-debug-using-gdb) Have you tried debugging your program? The error is on which line? – user202729 Feb 25 '18 at 06:46
  • 4
    I see you use "long" wich is of different sizes between 32bit and 64bit arch. Are you using 32bit arm raspbian and x86_64 fedora? – ulix Feb 25 '18 at 06:48
  • 3
    use standard fixed size integer like `int32_t` and beware of padding bytes if you want to make it portable. And [don't cast the result of malloc in C](https://stackoverflow.com/q/605845/995714) – phuclv Feb 25 '18 at 06:56
  • Thanks guys, I solved the problem by changing data types, short to int16_t and long to int32_t – XxX_Code.Destroyer_XxX Feb 25 '18 at 07:49
  • check the returned value from `fread()` to assure the operation was successful. – user3629249 Feb 26 '18 at 10:54
  • in C, when calling any of the heap allocation functions (malloc, calloc, realloc) 1) the returned type is `void*` which can be assigned to any pointer. Casting just clutters the code, making it more difficult to understand, debug, etc. 2) always check (!=NULL) the returned value to assure the operation was successful. – user3629249 Feb 26 '18 at 10:56
  • with a .bmp file, the number of horizontal pixels has to be a multiple of 4, the Width and Height fields are in pixels, not bytes, so need to be multiplied by the number of bytes in a pixel. The number of bytes in a pixel can be 1 or 2 or 3 or 4 you need to look at the field `short BitsPerPixel;` (and divide by 8) to get the number of bytes in a pixel. A `long` might not be 4 bytes Suggest using `uint32_t` and convert to numeric as needed/ Similarly, a `short` might not be 2 bytes, suggest using`uint16_t` and convert to numeric as needed. Suggest removing the `#pragma pack` statements – user3629249 Feb 26 '18 at 11:05
  • regarding: `int main(int argc, char **argv)` those parameters are not being used. Suggest: `int main( void )` – user3629249 Feb 26 '18 at 11:06
  • regarding: `fputs("File error:", stderr);` this fails to tell the user why the call to `fopen()` failed. Strongly suggest using: `perror( "fopen to read 'in.bmp' failed" );` – user3629249 Feb 26 '18 at 11:08
  • regarding: `Dfp=fopen("out.bmp","wb");` Always check for errors. – user3629249 Feb 26 '18 at 11:09
  • when calling `fwrite()`, always check the returned value to assure the operation was successful. – user3629249 Feb 26 '18 at 11:10
  • regarding: `for(i=1;i<=S;i++) { fwrite(&source_info.pixels[i-1],sizeof(struct Pix),1,Dfp);` this is sloppy coding. suggest: `for( i=0; i – user3629249 Feb 26 '18 at 11:12
  • usually, the pixel map is not the end of the image data. Suggest reading/understanding [.bmp format](https://en.wikipedia.org/wiki/BMP_file_format) – user3629249 Feb 26 '18 at 11:16

1 Answers1

3

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)
Geoffrey
  • 10,843
  • 3
  • 33
  • 46