Thread: I need help with resizing a bitmap file

  1. #1
    Registered User
    Join Date
    Dec 2012
    Posts
    28

    I need help with resizing a bitmap file

    I am currently writing a program that will resize a bitmap file by a factor of n(n being a value the user enters). The program takes in three values: the resize value, the input file and the output file. The program compiles and everything, however, when I run the program, I keep getting "bogus header data"within the output file.Here is the code I have:
    Code:
       char* number=argv[1];
        char* infile = argv[2];
        char* outfile = argv[3];
        factor = (int) number;
    if (factor>100 && factor<0)
    {
     
     printf("Please enter in a number greater than 0 and less than 100 ");
            return 2;
          
    }
        // open input file 
        FILE* inptr = fopen(infile, "r");
        if (inptr == NULL)
        {
            printf("Could not open %s.\n", infile);
            return 3;
        }
        // open output file
        FILE* outptr = fopen(outfile, "w");
        if (outptr == NULL)
        {
            fclose(inptr);
            fprintf(stderr, "Could not create %s.\n", outfile);
            return 4;
        }
        // read infile's BITMAPFILEHEADER
        BITMAPFILEHEADER bf;
        fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr);
        // read infile's BITMAPINFOHEADER
        BITMAPINFOHEADER bi;
        fread(&bi, sizeof(BITMAPINFOHEADER), 1, inptr);
         Oldwidth=bi.biWidth;
         OldHeight=bi.biHeight;
         oldSizeImage=bi.biSizeImage; 
         bi.biWidth=bi.biWidth*factor;
         bi.biHeight=bi.biHeight*factor;
                     
         oldpadding= (4-(Oldwidth*sizeof(RGBTRIPLE)) % 4) % 4; 
         bi.biSizeImage=(bi.biWidth * bi.biHeight) * 3 ;
         
         
         
        // ensure infile is (likely) a 24-bit uncompressed BMP 4.0
        if (bf.bfType != 0x4d42 || bf.bfOffBits != 54 || bi.biSize != 40 || 
            bi.biBitCount != 24 || bi.biCompression != 0)
        {
            fclose(outptr);
            fclose(inptr);
            fprintf(stderr, "Unsupported file format.\n");
            return 4;
        }
         
         RGBTRIPLE *buffer = malloc(sizeof(RGBTRIPLE) * bi.biWidth); 
        // write outfile's BITMAPFILEHEADER
        fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr);
        // write outfile's BITMAPINFOHEADER
        fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr);
        // determine padding for scanlines
        int padding =  (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
        int element=0;
        // iterate over infile's scanlines
        for (int i = 0; i<abs(OldHeight);  i++)
        {
             
            // iterate over pixels in scanline
            for (int j = 0; j < Oldwidth; j++)
            {
                // temporary storage
                RGBTRIPLE triple;
                // read RGB triple from infile
                fread(&triple, sizeof(RGBTRIPLE), 1, inptr);
              
                  
               
              
                
                
                 //iterate over each pixel factor times 
                for (int k = 0; k <factor; k++) 
                { 
                    buffer[element] = triple; 
                    element++; 
                } 
             
                // skip over padding, if any
               fseek(inptr, padding, SEEK_CUR); 
              } 
              
               for (int r = 0; r < factor; r++) 
               { 
                // write RGB triple to outfile 
                fwrite(buffer, sizeof(RGBTRIPLE), bi.biWidth, outptr); 
               
                // write padding to outfile 
                for (int p = 0; p < padding; p++) 
                fputc(0x00, outptr); 
               }
      
             
           
        
          
        }
        // close infile
        fclose(inptr);
        // close outfile
        fclose(outptr);
        
        return 0;
    any help would be greatly appreciated. Not sure if I should have included my bmp.h.But if anyone needs to see it to make a determination on what maybe the problem, let me know. Thanks

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    https://en.wikipedia.org/wiki/Data_structure_alignment

    Code:
    #include <stdio.h>
    #include <stddef.h>
    
    struct bmp {
      unsigned char signature[2]; // 2 bytes
      unsigned long filesize;     // 4 bytes
      unsigned short res1;        // 2 bytes
      unsigned short res2;        // 2 bytes
      unsigned long offset;       // 4 bytes
    };
    
    // Print the position and size of a struct member,
    // and also print the gap between it and the previous member
    #define DUMP_FIELD(x)   do { printf("%s: Offset=%zd, size=%zd, gap=%zd\n", \
            #x, \
            offsetof(struct bmp,x), \
            sizeof(h.x), \
            offsetof(struct bmp,x) - gap ); \
            gap = offsetof(struct bmp,x) + sizeof(h.x); \
            } while ( 0 )
    
      
    int main ( ) {
      struct bmp  h;
      size_t  gap = 0;
      DUMP_FIELD(signature);
      DUMP_FIELD(filesize);
      DUMP_FIELD(res1);
      DUMP_FIELD(res2);
      DUMP_FIELD(offset);
      return 0;
    }
    
    
    $ gcc foo.c
    $ ./a.out 
    signature: Offset=0, size=2, gap=0
    filesize: Offset=8, size=8, gap=6
    res1: Offset=16, size=2, gap=0
    res2: Offset=18, size=2, gap=0
    offset: Offset=24, size=8, gap=4
    Now look at the BMP file format.
    https://en.wikipedia.org/wiki/BMP_file_format
    The first thing you should note is that all the gaps should be ZERO (they're not in my test code).

    Use it to explore your structs
    BITMAPFILEHEADER bf;
    BITMAPINFOHEADER bi;

    If any of the individual sizes are wrong, and if any gaps are non-zero, then you need another plan.
    Simply reading x bytes from a file will no longer work.


    Of course, if your machine has a different endian (https://en.wikipedia.org/wiki/Endianness), you're going to need a completely different plan.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Dec 2012
    Posts
    28
    thank you for responding back. Quick question, what does that ./a command do?

  4. #4
    Registered User
    Join Date
    Dec 2012
    Posts
    28
    is that the name of the file, ./a.out?

  5. #5
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    The name of the file is a.out yes. On the command line, entering in a file will usually open it, so he is literally navigating to the file and opening it.

  6. #6
    Registered User
    Join Date
    Dec 2012
    Posts
    28
    Ok, so how would I test that with a .bmp file? Would I use, say "gcc resize.c" along with the .bmp file after it? Or would the .bmp need to be renamed to a .out file or something like that?

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    No, you need to understand the problem that if you have
    Code:
    struct foo {
        unsigned char sig[2];
        unsigned long filesize];
    };
    struct foo bar;
    fread(&bar,sizeof(bar),1,fp);
    then bar will seemingly contain garbage.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #8
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    Code:
    char* number=argv[1];
    char* infile = argv[2];
    char* outfile = argv[3];
    factor = (int) number;
    if (factor>100 && factor<0)
    {
        printf("Please enter in a number greater than 0 and less than 100 ");
        return 2;  
    }
    1) Casting is not converting! The value of number is a memory address and you tell the compiler to treat that value as an integer and assign it to factor. Just print the value of factor and be surprised :-)

    If you want to convert a string to an integer use strtol() or atoi(). Only use a cast if you are absolutely sure about it!

    2) If you finally got your factor you should also think about your validation check (tell us which numbers are greater than 100 AND smaller than 0).

    Bye, Andreas

  9. #9
    Registered User
    Join Date
    Nov 2012
    Posts
    1,393
    Quote Originally Posted by saldar05 View Post
    Ok, so how would I test that with a .bmp file? Would I use, say "gcc resize.c" along with the .bmp file after it? Or would the .bmp need to be renamed to a .out file or something like that?
    Look in your first lines of code
    Code:
    char* number=argv[1];
        char* infile = argv[2];
        char* outfile = argv[3];
    If you type at the command line:
    ./a.out 75 picture_old.bmp picture_new.bmp

    Then argv[1] is "75", argv[2] is "picture_old.bmp" and argv[3] is "picture_new.bmp"

  10. #10
    Registered User
    Join Date
    Dec 2012
    Posts
    28
    Quote Originally Posted by AndiPersti View Post
    Code:
    char* number=argv[1];
    char* infile = argv[2];
    char* outfile = argv[3];
    factor = (int) number;
    if (factor>100 && factor<0)
    {
        printf("Please enter in a number greater than 0 and less than 100 ");
        return 2;  
    }
    1) Casting is not converting! The value of number is a memory address and you tell the compiler to treat that value as an integer and assign it to factor. Just print the value of factor and be surprised :-)

    If you want to convert a string to an integer use strtol() or atoi(). Only use a cast if you are absolutely sure about it!

    2) If you finally got your factor you should also think about your validation check (tell us which numbers are greater than 100 AND smaller than 0).

    Bye, Andreas

    thanks for that.Helped alot!

  11. #11
    Registered User
    Join Date
    Dec 2012
    Posts
    28
    Quote Originally Posted by c99tutorial View Post
    Look in your first lines of code
    Code:
    char* number=argv[1];
        char* infile = argv[2];
        char* outfile = argv[3];
    If you type at the command line:
    ./a.out 75 picture_old.bmp picture_new.bmp

    Then argv[1] is "75", argv[2] is "picture_old.bmp" and argv[3] is "picture_new.bmp"
    Thanks! I appreciate the advice.

  12. #12
    Registered User
    Join Date
    Dec 2012
    Posts
    28
    Quote Originally Posted by Salem View Post
    No, you need to understand the problem that if you have
    Code:
    struct foo {
        unsigned char sig[2];
        unsigned long filesize];
    };
    struct foo bar;
    fread(&bar,sizeof(bar),1,fp);
    then bar will seemingly contain garbage.
    Thanks. Appreciate the advice!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. bitmap file ..
    By mad_muppet in forum C Programming
    Replies: 2
    Last Post: 05-22-2011, 01:35 AM
  2. reading bitmap file
    By R.Stiltskin in forum C++ Programming
    Replies: 7
    Last Post: 01-03-2007, 01:41 PM
  3. Writing Raw Bitmap File
    By Tonto in forum Windows Programming
    Replies: 1
    Last Post: 06-05-2005, 12:06 AM
  4. Hello all (re:bitmap image file)
    By Plastyksouljah in forum C++ Programming
    Replies: 7
    Last Post: 11-21-2003, 10:07 PM
  5. large bitmap file
    By sunis in forum Windows Programming
    Replies: 3
    Last Post: 01-16-2003, 04:06 AM