Thread: Read a 24 bit image using a 2d array

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Registered User
    Join Date
    Oct 2013
    Posts
    6

    Read a 24 bit image using a 2d array

    Hello all, I'm new and in need of some direction with a problem.

    I am trying to read a 24 bit image but I'm getting errors when I'm tryting to read the pixels.

    -The reading part looks bad because I'm reading both headers field by field. But I'm sure that it is reading both headers correctly.

    -Right now my biggest concern is to get it to read successfully an entire bmp image

    I'm using this calculation to get my padding bytes:

    padding bytes = [4-(3*width)mod 4]mod 4

    When I use a 2x2.bmp file to test it, I get an error that the [1][1] pixel was not read. When I use a bigger image it gives me the same error after about 100 rows and then every pixel is an error from that point on.

    This is what I got so far:

    Code:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    const size_t cSizeofPixel = 3; //size of struct tPixel
    typedef struct{
       unsigned char blue;
       unsigned char green;
       unsigned char red;
    } tPixel;
    
    
    int main()
    {
    int padding=0;
    char temp[4];
    int row = 0;
    int col = 0;
    
       FILE *bmpIn = fopen("2x2.bmp", "rb");
       if (bmpIn == NULL)
        puts("The file could not be opened.");
       char signature[3] = { '\0' };
    
       if (fread(signature, sizeof(char), 2, bmpIn) != 2)
        puts("Error, signature bits could not be read");
    
       if (strcmp(signature, "BM"))
        puts("This is not a BMP file.");
       else
        puts("This is a BMP file.");
    
       int32_t fileSize;
       if (fread(&fileSize, sizeof(fileSize), 1, bmpIn) != 1)
        puts("Error reading file size");
       
       int16_t resv1;
       if (fread(&resv1, sizeof(resv1), 1, bmpIn) != 1)
        puts("Error reading resv1");  
    
       int16_t resv2;
       if (fread(&resv2, sizeof(resv2), 1, bmpIn) != 1)
        puts("Error reading resv2");
    
       int32_t pixelOffset;
       if (fread(&pixelOffset, sizeof(pixelOffset), 1, bmpIn) != 1)
        puts("Error reading pixelOffset");  
    
       int32_t size;
       if (fread(&size, sizeof(size), 1, bmpIn) != 1)
        puts("Error reading size");
    
       int32_t width;
       if (fread(&width, sizeof(width), 1, bmpIn) != 1)
        puts("Error reading width");
    
       int32_t height;
       if (fread(&height, sizeof(height), 1, bmpIn) != 1)
        puts("Error reading height");
    
       int16_t colorPlanes;
       if (fread(&colorPlanes, sizeof(colorPlanes), 1, bmpIn) != 1)
        puts("Error reading color Planes");
       
       int16_t bitsPerPixel;
       if (fread(&bitsPerPixel, sizeof(bitsPerPixel), 1, bmpIn) != 1)
        puts("Error reading bits per pixel");
    
       unsigned int Compression;
       if (fread(&Compression, sizeof(Compression), 1, bmpIn) != 1)
        puts("Error reading Compression");
    
       unsigned int ImageSize;
       if (fread(&ImageSize, sizeof(ImageSize), 1, bmpIn) != 1)
        puts("Error reading ImageSize");
    
       int xResolution;
       if (fread(&xResolution, sizeof(xResolution), 1, bmpIn) != 1)
        puts("Error reading xResolution");
    
       int yResolution;
       if (fread(&yResolution, sizeof(yResolution), 1, bmpIn) != 1)
        puts("Error reading yResolution"); 
      
       unsigned int Colors;
       if (fread(&Colors, sizeof(Colors), 1, bmpIn) != 1)
        puts("Error reading Colors");
    
       unsigned int ImportantColors;
       if (fread(&ImportantColors, sizeof(ImportantColors), 1, bmpIn) != 1)
        puts("Error reading ImportantColors");
       
       padding = width % 4;
       if (padding != 0) {
        padding = (4-(3*width)%4)%4;
       }
    
    
       tPixel **pixels = (tPixel **)malloc(height * sizeof(tPixel *));
       for (row = 0; row < height; ++row) {
        pixels[row] = (tPixel *)malloc(width * sizeof(tPixel));
       }
    
       printf("\nReading Pixels Info!!!\n");
    
       for (row = 0; row < height; ++row) {
        for (col = 0; col < width; ++col) {
            if (fread(&pixels[row][col], cSizeofPixel, 1, bmpIn) != 1) {
                printf("\nError reading pixel [%d] ", row);
                printf("[%d]\n", col);
            }
          if (padding != 0) {
            fread(&temp, padding, 1, bmpIn);
          }
        }
       }
    
       for (row = 0; row < height; ++row) 
        free(pixels[row]);
       free(pixels);    
       
       fclose(bmpIn);
       
    
       return(0);
    }

    Any help will be greatly appreciated.

    I read this post

    Reading 24 bit BMP file into a 2d array.

    which helped me a lot but I still don't know if my error is when I allocate memory to my 2d array, or if I'm doing the padding bytes wrong or if it is something else.

  2. #2
    Registered User
    Join Date
    Jan 2009
    Location
    Australia
    Posts
    375
    I don't know if this is THE error that's messing you up but you should account for structure padding. There is no guarantee that your structure is stored contiguously like an array so there may be bytes between blue, green and red. You should reach each field of structure seperately. I'm guessing that maybe you originally used sizeof the pixel structure but it wasn't 3 as you expected so you hardcoded it.

    Your memory allocation looks fine to me.

    Some debugging tips to try might be to output all of the fields that you are reading in at the beginning to ensure that they are as expected and that you're not accidentally reading past it. Also outputting all the bytes read and looking at your bmp through a hex editor would probably be really helpful.

    Sorry I couldn't be more help ;(

  3. #3
    Registered User
    Join Date
    Oct 2013
    Posts
    6
    Quote Originally Posted by DeadPlanet View Post
    I don't know if this is THE error that's messing you up but you should account for structure padding. There is no guarantee that your structure is stored contiguously like an array so there may be bytes between blue, green and red. You should reach each field of structure seperately. I'm guessing that maybe you originally used sizeof the pixel structure but it wasn't 3 as you expected so you hardcoded it.

    Your memory allocation looks fine to me.

    Some debugging tips to try might be to output all of the fields that you are reading in at the beginning to ensure that they are as expected and that you're not accidentally reading past it. Also outputting all the bytes read and looking at your bmp through a hex editor would probably be really helpful.

    Sorry I couldn't be more help ;(
    Thanks for responding.

    Well I am accounting for the padding bytes but it was to my understanding that there are only padding bytes at the end of each row of the pixel array so you only have to read them at the end of each row you read, but please correct me if I'm mistaken.

    I changed my code to display all of the fields from both headers and they seem fine to me but I'm no expert in bmp files.

    Here's what I have now:

    Code:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    const size_t cSizeofPixel = 3;
    typedef struct tPixel{
       unsigned char blue;
       unsigned char green;
       unsigned char red;
    } tPixel;
    
    
    int main()
    {
    int padding=0;
    char temp[4];
    int row = 0;
    int col = 0;
    
       FILE *bmpIn = fopen("2x2.bmp", "rb");
       if (bmpIn == NULL)
        puts("The file could not be opened.");
       
       char signature[3] = { '\0' };
       if (fread(signature, sizeof(char), 2, bmpIn) != 2)
        puts("Error, signature bits could not be read");
       if (strcmp(signature, "BM"))    //check to see if the file is an bmp file
        puts("This is not a BMP file.");
       else
        puts("This is a BMP file.");
    
       unsigned int fileSize;
       if (fread(&fileSize, sizeof(fileSize), 1, bmpIn) != 1)
        puts("Error reading file size");
       
       unsigned short int resv1;
       if (fread(&resv1, sizeof(resv1), 1, bmpIn) != 1)
        puts("Error reading resv1");  
    
       unsigned short int resv2;
       if (fread(&resv2, sizeof(resv2), 1, bmpIn) != 1)
        puts("Error reading resv2");
    
       unsigned int pixelOffset;
       if (fread(&pixelOffset, sizeof(pixelOffset), 1, bmpIn) != 1)
        puts("Error reading pixelOffset");  
    
       unsigned int size;
       if (fread(&size, sizeof(size), 1, bmpIn) != 1)
        puts("Error reading size");
    
       int width;
       if (fread(&width, sizeof(width), 1, bmpIn) != 1)
        puts("Error reading width");
    
       int height;
       if (fread(&height, sizeof(height), 1, bmpIn) != 1)
        puts("Error reading height");
    
       unsigned short int colorPlanes;
       if (fread(&colorPlanes, sizeof(colorPlanes), 1, bmpIn) != 1)
        puts("Error reading color Planes");
       
       unsigned short int bitsPerPixel;
       if (fread(&bitsPerPixel, sizeof(bitsPerPixel), 1, bmpIn) != 1)
        puts("Error reading bits per pixel");
    
       unsigned int Compression;
       if (fread(&Compression, sizeof(Compression), 1, bmpIn) != 1)
        puts("Error reading Compression");
    
       unsigned int ImageSize;
       if (fread(&ImageSize, sizeof(ImageSize), 1, bmpIn) != 1)
        puts("Error reading ImageSize");
    
       int xResolution;
       if (fread(&xResolution, sizeof(xResolution), 1, bmpIn) != 1)
        puts("Error reading xResolution");
    
       int yResolution;
       if (fread(&yResolution, sizeof(yResolution), 1, bmpIn) != 1)
        puts("Error reading yResolution"); 
      
       unsigned int Colors;
       if (fread(&Colors, sizeof(Colors), 1, bmpIn) != 1)
        puts("Error reading Colors");
    
       unsigned int ImportantColors;
       if (fread(&ImportantColors, sizeof(ImportantColors), 1, bmpIn) != 1)
        puts("Error reading ImportantColors");
    //Finish reading both headers #############################################################
    
       printf("\nType: %s", signature );
       printf("\nFile Size: %d", fileSize);
       printf("\nReserved 1: %hd", resv1);
       printf("\nReserved 2: %hd", resv2);
       printf("\nOffset: %d", pixelOffset);
       printf("\n\nInfo Header Size: %d", size);
       printf("\nWidth: %d", width);
       printf("\nHeight: %d", height);
       printf("\nPlanes: %hd", colorPlanes);
       printf("\nBits per pixel: %d", bitsPerPixel);
       printf("\nCompression: %d", Compression);
       printf("\nImageSize: %d", ImageSize);
       printf("\nxResolution: %d", xResolution);
       printf("\nyResolution: %d", yResolution);
       printf("\nColors: %d", Colors);
       printf("\nImportantColors: %d", ImportantColors);
       printf("\n");
    
    //Finish printing the information from both headers #######################################
    
       padding = width % 4;
       if(padding != 0 ) {
           padding = (4-(3*width)%4)%4;;
       } 
    
    //Memory Allocation below
       tPixel **pixels = (tPixel **)malloc(height * sizeof(tPixel *));
       for (row = 0; row < height; ++row) {
        pixels[row] = (tPixel *)malloc(width * sizeof(tPixel));
       }   
    
       printf("\nReading Pixels Info!!!\n");
    
       for (row = 0; row < height; ++row) {
        for (col = 0; col < width; ++col) {
            if (fread(&pixels[row][col], cSizeofPixel, 1, bmpIn) != 1) {
                printf("\nError reading pixel [%d] ", row);
                printf("[%d]\n", col);
            }
          if (padding != 0) {
            if (fread(&temp, padding, 1, bmpIn) != 1)
            printf("\nError reading padding in row %d \n", row+1);
          }
        }
       }
    
       for (row = 0; row < height; row) 
        free(pixels[row]);
       free(pixels); 
    
    
       fclose(bmpIn);
    
       return(0);
    }

    When I ran my code on a 2x2 pixel image, I can't read properly the last pixel and therefore the padding also is not read correctly.

    On a larger image 400 something by 5000 something, I can read succesfully until the 116 row, then I can't read the padding correctly and every other pixel and padding is read incorrectly.

    This really doesn't make any sense to me because I can read 116 rows of pixels just fine and then it stops working

    Any suggestions?
    Last edited by leo191919; 10-29-2013 at 09:54 AM.

  4. #4
    Registered User
    Join Date
    Jan 2009
    Location
    Australia
    Posts
    375
    I'm super drunk right now so I can't give an amazing response but the padding bytes that you're thinking or are different to the struct packing bytes that I'm talking about.

    When a structure is created there is no guarantee that the fields are allocated contiguously. You need to read in each field of the structure individually. You can probably look up "C structure packing" to get a better idea of what I'm talking about.

    Again I don't actually think this is the cause of the exact error that you're talking about but it's something you should fix regardless!

  5. #5
    Registered User
    Join Date
    Oct 2013
    Posts
    6
    Thanks for the response.

    Is this in regards about the pixel struct?? Could this be affecting the way I'm reading it?

    I just created a couple of images without padding on Paint: 4x4, 8x8, and 32x32 pixel images and it reads them just fine.

    I'll try reading each field of the pixel struct separately and see if that solves my problem with the bigger images that have padding bytes.

    Thanks

  6. #6
    Registered User
    Join Date
    Jan 2009
    Location
    Australia
    Posts
    375
    >Is this in regards about the pixel struct?? Could this be affecting the way I'm reading it?

    Yes. Yes.

    >I'll try reading each field of the pixel struct separately and see if that solves my problem with the bigger images that have padding bytes.

    Do that. It won't solve the padding problem but do it anyway as it's still a significant bug.

    Alrighty man so I'm going to have to ask you to chill out for a second. I've done a little reading because I'm interested in your problem and I think you have a small problem with your understanding of the padding. The padding on a row is simply to bring the number of bytes in a row to a multiple of four. So padding is added to the end of the row, not to the end of each pixel data. At least that's what my understanding of the wikipedia article tells me.

  7. #7
    Registered User
    Join Date
    Oct 2013
    Posts
    6
    I figured it out, my error was that I was reading a padding byte after each pixel instead of reading the padding byte at the end of each row.

    So I can read the images now, but now my problems is that I can't seem to write the pixels into a new image. I added the code to write both headers to a new file and it does but when I get to writing the pixels I get a "segmentation fault" which I'm not 100% sure what it means but I'm using gcc on a linux box to compile and run my code and I think that error has to do with me not passing the values right.

    Anyone could help me out with writing the pixels to a new file?

    This is what I got so far

    Code:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    const size_t cSizeofPixel = 3; //size of struct tPixel
    typedef struct{
       unsigned char blue;
       unsigned char green;
       unsigned char red;
    } tPixel;
    
    
    int main()
    {
    int padding=0;
    char temp[4];
    int row = 0;
    int col = 0;
    
       FILE *bmpIn = fopen("testimg1.bmp", "rb");
       if (bmpIn == NULL)
        puts("The file could not be opened.");
       char signature[3] = { '\0' };
    
       if (fread(signature, sizeof(char), 2, bmpIn) != 2)
        puts("Error, signature bits could not be read");
    
       if (strcmp(signature, "BM"))
        puts("This is not a BMP file.");
       else
        puts("This is a BMP file.");
    
       int32_t fileSize;
       if (fread(&fileSize, sizeof(fileSize), 1, bmpIn) != 1)
        puts("Error reading file size");
       
       int16_t resv1;
       if (fread(&resv1, sizeof(resv1), 1, bmpIn) != 1)
        puts("Error reading resv1");  
    
       int16_t resv2;
       if (fread(&resv2, sizeof(resv2), 1, bmpIn) != 1)
        puts("Error reading resv2");
    
       int32_t pixelOffset;
       if (fread(&pixelOffset, sizeof(pixelOffset), 1, bmpIn) != 1)
        puts("Error reading pixelOffset");  
    
       int32_t size;
       if (fread(&size, sizeof(size), 1, bmpIn) != 1)
        puts("Error reading size");
    
       int32_t width;
       if (fread(&width, sizeof(width), 1, bmpIn) != 1)
        puts("Error reading width");
    
       int32_t height;
       if (fread(&height, sizeof(height), 1, bmpIn) != 1)
        puts("Error reading height");
    
       int16_t colorPlanes;
       if (fread(&colorPlanes, sizeof(colorPlanes), 1, bmpIn) != 1)
        puts("Error reading color Planes");
       
       int16_t bitsPerPixel;
       if (fread(&bitsPerPixel, sizeof(bitsPerPixel), 1, bmpIn) != 1)
        puts("Error reading bits per pixel");
    
       unsigned int Compression;
       if (fread(&Compression, sizeof(Compression), 1, bmpIn) != 1)
        puts("Error reading Compression");
    
       unsigned int ImageSize;
       if (fread(&ImageSize, sizeof(ImageSize), 1, bmpIn) != 1)
        puts("Error reading ImageSize");
    
       int xResolution;
       if (fread(&xResolution, sizeof(xResolution), 1, bmpIn) != 1)
        puts("Error reading xResolution");
    
       int yResolution;
       if (fread(&yResolution, sizeof(yResolution), 1, bmpIn) != 1)
        puts("Error reading yResolution"); 
      
       unsigned int Colors;
       if (fread(&Colors, sizeof(Colors), 1, bmpIn) != 1)
        puts("Error reading Colors");
    
       unsigned int ImportantColors;
       if (fread(&ImportantColors, sizeof(ImportantColors), 1, bmpIn) != 1)
        puts("Error reading ImportantColors");
    
    //Finish reading both headers #############################################################
    
       printf("\nType: %s", signature );
       printf("\nFile Size: %d", fileSize);
       printf("\nReserved 1: %hd", resv1);
       printf("\nReserved 2: %hd", resv2);
       printf("\nOffset: %d", pixelOffset);
       printf("\n\nInfo Header Size: %d", size);
       printf("\nWidth: %d", width);
       printf("\nHeight: %d", height);
       printf("\nPlanes: %hd", colorPlanes);
       printf("\nBits per pixel: %d", bitsPerPixel);
       printf("\nCompression: %d", Compression);
       printf("\nImageSize: %d", ImageSize);
       printf("\nxResolution: %d", xResolution);
       printf("\nyResolution: %d", yResolution);
       printf("\nColors: %d", Colors);
       printf("\nImportantColors: %d", ImportantColors);
       printf("\n");
    
    //Finish printing the information from both headers #######################################
    
    
       
       padding = width % 4;
       if (padding != 0) {
        padding = (4-(3*width)%4)%4;
       }
    
    
    
       tPixel **pixels = (tPixel **)malloc(height * sizeof(tPixel *));
       for (row = 0; row < height; ++row) {
        pixels[row] = (tPixel *)malloc(width * sizeof(tPixel));
       }
    
       printf("\nReading Pixels Info!!!\n");
    
       for (row = 0; row < height; ++row) {
        for (col = 0; col < width; ++col) {
            if (fread(&pixels[row][col], cSizeofPixel, 1, bmpIn) != 1) {
                printf("\nError reading pixel [%d] ", row);
                printf("[%d]\n", col);
            }
            }
          if (padding != 0) {
            if (fread(&temp, padding, 1, bmpIn) != 1)
            printf("\nError reading padding in row %d \n", row);
          
        }
       }
    
       for (row = 0; row < height; ++row) 
        free(pixels[row]);
       free(pixels);    
       
       fclose(bmpIn);
    
    
    
    FILE *bmpOut = fopen("new.bmp", "wb");
       if (bmpOut == NULL) {
          printf("\nCannot open file\n");
       }
        
       printf("\nWriting Header...\n");
       //save to new bmp file
    
       if (fwrite(signature, sizeof(char), 2, bmpOut) != 2)
        puts("Error writing signature bits");
    
       if (fwrite(&fileSize, sizeof(fileSize), 1, bmpOut) != 1)
        puts("Error writing file size");
    
       if (fwrite(&resv1, sizeof(resv1), 1, bmpOut) != 1)
        puts("Error writing resv1");  
    
       if (fwrite(&resv2, sizeof(resv2), 1, bmpOut) != 1)
        puts("Error writing resv2");
    
       if (fwrite(&pixelOffset, sizeof(pixelOffset), 1, bmpOut) != 1)
        puts("Error writing pixelOffset");  
    
       if (fwrite(&size, sizeof(size), 1, bmpOut) != 1)
        puts("Error writing size");
    
       if (fwrite(&width, sizeof(width), 1, bmpOut) != 1)
        puts("Error writing width");
    
       if (fwrite(&height, sizeof(height), 1, bmpOut) != 1)
        puts("Error writing height");
    
       if (fwrite(&colorPlanes, sizeof(colorPlanes), 1, bmpOut) != 1)
        puts("Error writing color Planes");
       
       if (fwrite(&bitsPerPixel, sizeof(bitsPerPixel), 1, bmpOut) != 1)
        puts("Error writing bits per pixel");
    
       if (fwrite(&Compression, sizeof(Compression), 1, bmpOut) != 1)
        puts("Error writing Compression");
    
       if (fwrite(&ImageSize, sizeof(ImageSize), 1, bmpOut) != 1)
        puts("Error writing ImageSize");
    
       if (fwrite(&xResolution, sizeof(xResolution), 1, bmpOut) != 1)
        puts("Error writing xResolution");
    
       if (fwrite(&yResolution, sizeof(yResolution), 1, bmpOut) != 1)
        puts("Error writing yResolution"); 
      
       if (fwrite(&Colors, sizeof(Colors), 1, bmpOut) != 1)
        puts("Error writing Colors");
    
       if (fwrite(&ImportantColors, sizeof(ImportantColors), 1, bmpOut) != 1)
        puts("Error writing ImportantColors");
    
        
    printf("\nWriting Pixels...\n");
       for(row=0; row < height ; row++) {
          for(col=0; col < width; col++) {  
            if (fwrite(&pixels[row][col], cSizeofPixel, 1, bmpOut) != 1) {
                printf("\nError writing pixel [%d] ", row);
                printf("[%d]\n", col);
            }
          }
          if(padding != 0) {
             fwrite(&temp, padding, 1, bmpOut);
          }
       }
       printf("\nDone writing...\n");
    
    fclose(bmpOut);   
    
       return(0);
    }
    Last edited by leo191919; 10-29-2013 at 12:12 PM.

  8. #8
    Registered User
    Join Date
    Jan 2009
    Location
    Australia
    Posts
    375
    You're free-ing the array you used for the pixel data before you're writing it out to the file which is causing a segmentation fault.

  9. #9
    Registered User
    Join Date
    Oct 2013
    Posts
    6
    You're right. I'm getting tired with this thing so I just completely forgot about that.

    Thank you so much, your suggestions really helped me out.

    I'll probably post again if I have more questions since there's more parts to the problem.

    Thanks again

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Please, help me.. How the way to read image in C++
    By Arif Lazuardi in forum C++ Programming
    Replies: 2
    Last Post: 05-01-2013, 02:30 PM
  2. How to read an 8 bit Raw Image
    By geewhan in forum C++ Programming
    Replies: 7
    Last Post: 07-13-2012, 10:32 PM
  3. Replies: 13
    Last Post: 11-20-2009, 04:43 PM
  4. How to read out the RGB values of an image?
    By pjeremy in forum C Programming
    Replies: 5
    Last Post: 05-28-2006, 08:49 AM
  5. How to read a image in C++?
    By DramaKing in forum C++ Programming
    Replies: 2
    Last Post: 10-26-2001, 12:34 AM