Copying a bmp in c

后端 未结 1 692
春和景丽
春和景丽 2021-01-25 09:45

Background:
I want to copy a bmp (uncompressed 24 RGB) image from one file name to another. I am using the mingw compiler from TDM-GCC (version 4.9.2, 32 bit, SJLJ) that

1条回答
  •  北恋
    北恋 (楼主)
    2021-01-25 10:28

    I fiddled a little bit with the data provided, and I'm quite sure what happened:

    FILE *inptr = fopen(infile, "r");
    

    and

    FILE *outptr = fopen(outfile, "w");
    

    open the files in text mode.

    This is a special behavior I know from Microsoft's C API and it seems that this applies to mingw TDM-GCC as well (which I struggled to believe until the dumped data convinced me that my suspicion was right).

    The file I/O in Microsoft's C API distinguishs between text mode and binary mode:

    • fopen(infile, "rt") and fopen(outfile, "wt") open the files in text mode.
    • fopen(infile, "rb") and fopen(outfile, "wb") open the files in binary mode.
    • fopen(infile, "r") and fopen(outfile, "w") default to text mode.

    In text mode the file reading replaces all Microsoft line-endings ("\r\n") by Unix line-endings ("\n") as well as the writing does the opposite ("\n" becomes "\r\n").

    This is reasonable if the contents is plain text but it probably corrupts output of binary contents where a byte 0x0d is inserted whenever a byte 0x0a (with any meaning) occurs in the data stream.

    To prove this,

    1. I downloaded your sample files (unfortunately uploaded in PNG format)
    2. converted the files (back) to 24 bit BMP (using GIMP)
    3. made a hex-dump for each:

      $ hexdump -C IkW6FbN.bmp >IkW6FbN.bmp.txt
      
      $ hexdump -C jnxpTwE.bmp >jnxpTwE.bmp.txt
      
    4. and finally loaded IkW6FbN.bmp.txt and jnxpTwE.bmp.txt into WinMerge for comparison.

    As the snapshot illustrates, the input and output file have identical contents for the first 14037 (0x36d5) bytes. Then, the input file contains "accidentally" three bytes 0a 0a 0a where the output file has instead 0d 0a 0d 0a 0d 0a. Thus, the respective original pixels (and all following) are corrupted.

    (As you might already guess, 0a is the hexadecimal value of the line-feed character '\n', 0d the one of the carriage-return '\r'.)

    Btw. the output file is probably a little bit longer than the input file (due to the inserted CR bytes). This might be ignored by a BMP viewer as the BMP header states exactly how many bytes are needed for the raw image (and the extra bytes are simply ignored).

    As you already might've recognized you should change the fopen() calls to

    FILE *inptr = fopen(infile, "rb");
    

    and

    FILE *outptr = fopen(outfile, "wb");
    

    to fix your issue.

    Btw. the C APIs on *x OSes (e.g. Linux) doesn't have such a distinction of text and binary mode. Instead, the b is simply ignored (which is helpful to write portable code).

    Further reading: fopen, fopen_s on cppreference.com

    0 讨论(0)
提交回复
热议问题