Thread: Problem reading 8 bit greyscale images !

  1. #1
    Registered User
    Join Date
    Apr 2007
    Posts
    7

    Problem reading 8 bit greyscale images !

    Hi everyone

    I am trying to read and print the negative of a 8 bit gray scale .bmp image with the following code, unfortunately it reads only 2 of the .bmp images i have, but doesn't read the other .bmp images including the one i have attached lena256.bmp, even though its an 8 bit greyscale .bmp image.
    All of them happen to have the same properties but with this code am unable to read all the .bmp files, only 2 wud give proper output :

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    
    /*-------STRUCTURES---------*/
    typedef struct {int rows; int cols; int bits; unsigned char* data;} sImage;
    
    /*-------PROTOTYPES---------*/
    long getImageInfo(FILE*, long, int);
    void copyImageInfo(FILE*, FILE*);
    void copyColorTable(FILE*, FILE*, int);
    
    int main()
    {
      FILE         *bmpInput, *bmpOutput;
      sImage      originalImage;
      unsigned char      someChar;
      unsigned char*   pChar;
      int         nColors;  /* BMP number of colors */
      long         fileSize; /* BMP file size */
      int         vectorSize; /* BMP vector size */
      int         r, c;       /* r = rows, c = cols */
      int           pixels[600][600];
      char imagein[30];
      char imageout[30];
      /* initialize pointer */
      someChar = '0';
      pChar = &someChar;
      printf("Enter input image : ");
      gets(imagein);
     
      printf("Enter output image : ");
      gets(imageout);
     
      /*--------READ INPUT FILE------------*/
      bmpInput = fopen(imagein, "rb");
      fseek(bmpInput, 0L, SEEK_END);
     
      /*--------DECLARE OUTPUT FILE--------*/
      bmpOutput = fopen(imageout, "wb");
    
      /*--------GET BMP DATA---------------*/
      originalImage.cols = (int)getImageInfo(bmpInput, 18, 4);
      originalImage.rows = (int)getImageInfo(bmpInput, 22, 4);
      originalImage.bits = (int)getImageInfo(bmpInput, 28, 4);
      fileSize = getImageInfo(bmpInput, 2, 4);
      nColors = getImageInfo(bmpInput, 46, 4);
      vectorSize = fileSize - (14 + 40 + 4*nColors);
    
      /*-------PRINT DATA TO SCREEN-------------*/
      printf("Width: %d\n", originalImage.cols);
      printf("Height: %d\n", originalImage.rows);
      printf("Bits per Pixel: %d\n", originalImage.bits);
      printf("File size: %ld\n", fileSize);
      printf("# Colors: %d\n", nColors);
      printf("Vector size: %d\n", vectorSize);
     
      copyImageInfo(bmpInput, bmpOutput);
      copyColorTable(bmpInput, bmpOutput, nColors);
    
      /*----START AT BEGINNING OF RASTER DATA-----*/
      fseek(bmpInput, (54 + 4*nColors), SEEK_SET);
    
      /*----------READ RASTER DATA----------*/
      for(r=0; r<=originalImage.rows - 1; r++)
      {
        for(c=0; c<=originalImage.cols - 1; c++)
        {
          /*-----read data, reflect and write to output file----*/
          fread(pChar, sizeof(char), 1, bmpInput);
          pixels[r][c] = *pChar;
          *pChar = 255 - *pChar;
          fwrite(pChar, sizeof(char), 1, bmpOutput);
        }
      }
     
      fclose(bmpInput);
      fclose(bmpOutput);
      getch();
    }
    
    /*----------GET IMAGE INFO SUBPROGRAM--------------*/
    long getImageInfo(FILE* inputFile, long offset, int numberOfChars)
    {
      unsigned char      *ptrC;
      long         value = 0L;
      unsigned char      dummy;
      int         i;
    
      dummy = '0';
      ptrC = &dummy;
    
      fseek(inputFile, offset, SEEK_SET);
    
      for(i=1; i<=numberOfChars; i++)
      {
        fread(ptrC, sizeof(char), 1, inputFile);
        /* calculate value based on adding bytes */
        value = (long)(value + (*ptrC)*(pow(256, (i-1))));
      }
      return(value);
    
    } /* end of getImageInfo */
    
    /*-------------COPIES HEADER AND INFO HEADER----------------*/
    void copyImageInfo(FILE* inputFile, FILE* outputFile)
    {
      unsigned char      *ptrC;
      unsigned char      dummy;
      int i;
      dummy = '0';
      ptrC = &dummy;
    
      fseek(inputFile, 0L, SEEK_SET);
      fseek(outputFile, 0L, SEEK_SET);
    
      for(i=0; i<=50; i++)
      {
        fread(ptrC, sizeof(char), 1, inputFile);
        fwrite(ptrC, sizeof(char), 1, outputFile);
      }
    }
    
    /*----------------COPIES COLOR TABLE-----------------------------*/
    void copyColorTable(FILE* inputFile, FILE* outputFile, int nColors)
    {
      unsigned char      *ptrC;
      unsigned char      dummy;
      int i;
    
      dummy = '0';
      ptrC = &dummy;
    
      fseek(inputFile, 54L, SEEK_SET);
      fseek(outputFile, 54L, SEEK_SET);
    
      for(i=0; i<=(4*nColors); i++)  /* there are (4*nColors) bytesin color table */
      {
        fread(ptrC, sizeof(char), 1, inputFile);
        fwrite(ptrC, sizeof(char), 1, outputFile);
      }
    
    }
    I would be really grateful if someone could go through this code and find out where am going wrong.

    Thank you in advance.
    Anna

  2. #2
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Why write your own bitmap loader when you can just use LoadImage, or OLELoadPicture?

    Reading BMPs is a lot harder to get right than most people think. Use functions that have alrady been written to load them.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  3. #3
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    > int pixels[600][600];
    You're probably clobbering the program stack with this array. I would either move the array above main() or create the array dynamically using malloc. I tried your code, and once I moved the array above main(), it ran fine.

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    > pixels[r][c] = *pChar;
    Why do you even need to store it at all?
    I mean, you never use the array contents after assigning it.
    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.

  5. #5
    Registered User
    Join Date
    Apr 2007
    Posts
    7

    problem reading 8 bit gray scale .bmp image

    Hey, thanks for ur suggestion , but i tried moving the int pixels[600][600] array above main and still am not able to run my code for lena256.bmp .... By moving the array above main , i hope you mean that i should just declare it above main , right ?



    Quote Originally Posted by swoopy View Post
    > int pixels[600][600];
    You're probably clobbering the program stack with this array. I would either move the array above main() or create the array dynamically using malloc. I tried your code, and once I moved the array above main(), it ran fine.

  6. #6
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    Quote Originally Posted by Clueless@work View Post
    Hey, thanks for ur suggestion , but i tried moving the int pixels[600][600] array above main and still am not able to run my code for lena256.bmp .... By moving the array above main , i hope you mean that i should just declare it above main , right ?
    Right. What errors are you getting or what exactly isn't working? I was able to run your code with the posted image. I did make some minor changes, like moving the array, and I believe I commented out this line:
    Code:
      fseek(bmpInput, 0L, SEEK_END);
    Not sure if that made any difference. And as Salem said you don't use the array, so you could comment it out as well. A better description of your error would help. And you should also check the return values of your fopen()'s to make sure it actually found the file.

  7. #7
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    By the way the image came out sort of bluish gray after the inversion, if I remember correctly.

  8. #8
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Remember that all bmp files are zero padded to the nearest 4 byte boundary. So if your width is evenly divisible by 4 a normal algorithm that does not take padding into account will work. For images with widths that are not evenly divisible by 4 the algorithm will completely fall apart.

  9. #9
    Registered User
    Join Date
    Apr 2007
    Posts
    7
    Well , the problem is that there is no image being printed out .... It prints out the Image width height no. of bits and everything , the program ends fine ... But when i try to view the output image , am unable to view the image... It says Drawing failed for Windows Image viewer , I cant even open and view the image in Paintbrush .... but if i check for the image properties by right clicking on it , it gives the correct properties ... But there's no view available....

  10. #10
    Registered User
    Join Date
    Mar 2004
    Posts
    536
    Quote Originally Posted by Clueless@work View Post
    Well , the problem is that there is no image being printed out .... It prints out the Image width height no. of bits and everything , the program ends fine ... But when i try to view the output image , am unable to view the image... It says Drawing failed for Windows Image viewer , I cant even open and view the image
    For the picture you are using: ncolors = 0 for b&w, but your calculation doesn't allow for a color palette (A gray ramp in this case). There is a 1024-bit palette between the end of the headers and the beginning of the data.

    The integer located 10 bytes from the start of the file tells where the data starts, relative the start of the file. In this file it is 0x00000436 (1078 decimal).

    So, no matter how you do it the action for this file is:

    You should copy everything from byte zero up to and including byte 1077 to the output file, then do the value change for the next 65536 bytes.

    Result is attached.


    D

  11. #11
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    You're writing one too many bytes for the color table:
    Code:
    >void copyColorTable(FILE* inputFile, FILE* outputFile, int nColors)
    >.
    >.
    >  for(i=0; i<=(4*nColors); i++)  /* there are (4*nColors) bytesin color table */
    Should be:
    Code:
      for(i=0; i<(4*nColors); i++)  /* there are (4*nColors) bytesin color table */

  12. #12
    Registered User
    Join Date
    Mar 2004
    Posts
    536
    Quote Originally Posted by swoopy View Post
    You're writing one too many bytes for the color table:
    Code:
    >void copyColorTable(FILE* inputFile, FILE* outputFile, int nColors)
    >.
    >.
    >  for(i=0; i<=(4*nColors); i++)  /* there are (4*nColors) bytesin color table */
    Should be:
    Code:
      for(i=0; i<(4*nColors); i++)  /* there are (4*nColors) bytesin color table */
    For this file nColors = 0

    The original program is only writing one byte where it should be writing 1024. That's why the original program gave an output file that was 1023 bytes shorter than the original file. In fact, with this file, there is a 1024 byte color table (gray ramp) between the end of the header(s) and the beginning of the pixel bytes.

    I'm not talking about how it is supposed to be (nColors = 256, I'm thinking), I am talking about the specific file that was attached. It is apparently defective.

    This is the answer to the original question about why some files weren't converted properly: it's a bad file. But with a little detective work it can be salvaged. Some viewers work one way, some work another. For example, Firefox could open and display the original file OK, but not Microsoft's whatever.


    With swoopy's fix and a proper file, I'm thinking that the program should be OK (after the superfluous pixel array is deleted, of course).

    Edit
    (As a matter of fact, I just replaced the nColors value with the proper value in the original file and now all is just swell--- with the loop fix swoopy posted.)


    Bottom line: the output file size should be exactly the same size as the input file. All file contents other than pixel data should match exactly.


    D
    Last edited by Dave Evans; 06-29-2007 at 04:28 PM.

  13. #13
    Registered User
    Join Date
    Apr 2007
    Posts
    7
    Hey guys thanks a lot !!!
    After fixing the ncolors = 256 and the loop change , i can run all my 8 bit images....
    Thanks a lot !!
    Wish i cud buy you guys dinner

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 22
    Last Post: 12-23-2008, 01:53 PM
  2. 32 bit color depth bitmap problem with XP
    By kalabala in forum C++ Programming
    Replies: 0
    Last Post: 12-22-2008, 06:56 AM
  3. Accessing bit fields using a union problem.
    By samdomville in forum C Programming
    Replies: 6
    Last Post: 12-10-2008, 04:39 PM
  4. Slight problem with socket reading!!!
    By bobthebullet990 in forum C Programming
    Replies: 5
    Last Post: 02-15-2006, 09:55 AM
  5. problem reading files in C
    By angelfly in forum C Programming
    Replies: 9
    Last Post: 10-10-2001, 11:58 AM