Remove/Overwrite padding - BMP

I don't know how to overwrite the padding from a BMP image.I need to replace the pixels that are not white with a given color from output. I'd like solutions who do not contain sophisticated libraries / functions (only simple stuff) . "bmp_header.h" contains the BMP structure described in wikipedia.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
 #include "bmp_header.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(void)
{
    FILE *f;
    f = fopen("captcha9.bmp","rb");
    fread(&BMP_header,sizeof(BMP_header),1,f);
    fread(&BMP_info_header,sizeof(BMP_info_header),1,f);
    fseek(f,BMP_header.imageDataOffset,SEEK_SET);
    int rowSize = (BMP_info_header.bitPix * BMP_info_header.width + 31 ) /32 * 4 ;
    unsigned char *PixelArray = (unsigned char *)malloc(rowSize * abs(BMP_info_header.height));
    fread(PixelArray,sizeof(char),BMP_info_header.biSizeImage,f);
    int i,j,k,addPadding;
    int padding = 4-((BMP_info_header.width*3)%4);

    for( i = 0; i<abs(BMP_info_header.height); i++)

    {
                   for(j = 0 ; j<rowSize-padding; j+= 3)
                  {
                        int offset = i * (rowSize-padding) + j;
                        if((PixelArray[offset] != 255 ) && (PixelArray[offset+1] != 255) && (PixelArray[offset+2] != 255))
                       {
                            PixelArray[offset] = 69;
                            PixelArray[offset+1] = 106;
                            PixelArray[offset+2] = 671;
                       }
                  }

                  for (addPadding = 0 ; addPadding < padding ; addPadding ++)

                        PixelArray[ i * (rowSize+padding) + j  ] = 255;

    }



    f = fopen("result.bmp","wb");
    fwrite(&BMP_header,sizeof(BMP_header),1,f);
    fwrite(&BMP_info_header,sizeof(BMP_info_header),1,f);
    fwrite(PixelArray,rowSize * abs(BMP_info_header.height),1,f);
    fclose(f);
    free(PixelArray);


    return 0;
}
Last edited on
I don't know how to overwrite the padding from a BMP image.

What is "padding?" I would've guessed it referred to the padding appended to lines to ensure they consisted of a number of bytes that was evenly divisible by 4 in the context of a BMP image, however....


I need to replace the pixels that are not white with a given color from output.

Are you defining "padding" as any pixel which is not white? And, output is something you generate. Its use here isn't very illuminating.


"bmp_header.h" contains the BMP structure described in wikipedia.

So, rather than make it easy for someone to run your code and possibly find your problem, you expect them to re-implement something (that could very well contain the source of your problem?)
Last edited on
sorry , here is "bmp_header.h"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#pragma pack(1)

struct bmp_fileheader
{
    unsigned char  fileMarker1; /* 'B' */
    unsigned char  fileMarker2; /* 'M' */
    unsigned int   bfSize; /* File's size */
    unsigned short unused1;
    unsigned short unused2;
    unsigned int   imageDataOffset; /* Offset to the start of image data */
}BMP_header,BMP_header_out;

struct bmp_infoheader
{
    unsigned int   biSize; /* Size of the info header - 40 bytes */
    signed int     width; /* Width of the image */
    signed int     height; /* Height of the image */
    unsigned short planes;
    unsigned short bitPix;
    unsigned int   biCompression;
    unsigned int   biSizeImage; /* Size of the image data */
    int            biXPelsPerMeter;
    int            biYPelsPerMeter;
    unsigned int   biClrUsed;
    unsigned int   biClrImportant;
}BMP_info_header,BMP_info_header_out;

#pragma pack() 

Padding bytes (not necessarily 0) must be appended to the end of the rows in order to bring up the length of the rows to a multiple of four bytes.
After running this code , at the right upper corner of my image a thick black line that ocupies one third of the width , and i don't know how to remove it . I've thought it happens because of the padding .
Last edited on
Padding shouldn't be displayed, so that shouldn't be an issue.

Try this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    for (i = 0; i<abs(BMP_info_header.height); i++)

    {
        for (j = 0; j < rowSize-padding; j += 3)
        {
            int offset = i * rowSize  + j;
            if ((PixelArray[offset] != 255) && (PixelArray[offset + 1] != 255) && (PixelArray[offset + 2] != 255))
            {
                PixelArray[offset] = 69;
                PixelArray[offset + 1] = 106;
                PixelArray[offset + 2] = 671;
            }
        }

        //for (addPadding = 0; addPadding < padding; addPadding++)

        //    PixelArray[i * (rowSize + padding) + j] = 255;

    }


You were accounting for the padding incorrectly.

You are calculating the padding bytes incorrectly too. You set padding to 4 when no padding is required.
Last edited on
Ok . i changed the padding accordingly and commented that part of code but the output is the same..
1
2
3
 int padding = 0;
    if((BMP_info_header.width*3)%4!=0)
        padding = 4 - (BMP_info_header.width*3)%4;
Last edited on
Ok . i changed the padding accordingly and commented that part of code but the output is the same..

Did you also change the calculation of offset?
I don't know how to calculate offset in another way.
I played around with this program but I'm not sure whether I got it right. Testing image processing programs is not easy, just because it may appear to work, it doesn't necessarily mean its correct. An image from another source may bring to light issues which previously passed unnoticed. There may be problems in this code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include "bmp_header.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main(void)
{
    const char * fnamein  = "test.bmp";
    const char * fnameout = "output.bmp";

    FILE *f;
    f = fopen(fnamein,"rb");
    if (f == NULL)
    {
        printf("File not open:\n %s\n\nExiting....\n", fnamein);
        return 1;       
    }
    
    fread(&BMP_header,sizeof(BMP_header),1,f);
    fread(&BMP_info_header,sizeof(BMP_info_header),1,f);

    if (BMP_info_header.bitPix != 24)
    {
        printf("Expected 24 bit colour. Found %d bits\nExiting....\n", BMP_info_header.bitPix);
        return 1;
    }
        
    fseek(f,BMP_header.imageDataOffset,SEEK_SET);
    
    unsigned int imageHeight = abs(BMP_info_header.height);
    unsigned int imageWidth  = ((BMP_info_header.width * BMP_info_header.bitPix) + 7) / 8;
    imageWidth = (imageWidth + 3) / 4;
    imageWidth *= 4;
    unsigned int imageSize = imageHeight * imageWidth;
    
    if (imageSize != BMP_info_header.biSizeImage)
    {
        printf ("Size discrepancy: expected = %d   calculated = %d\n", BMP_info_header.biSizeImage, imageSize);
        return 1;
    }
    else
    {
        printf ("Size is GOOD! expected = %d   calculated = %d\n", BMP_info_header.biSizeImage, imageSize);     
    }
    
    unsigned char *PixelArray = (unsigned char *)malloc(imageSize);
    fread(PixelArray, imageSize, 1 , f);
    
    unsigned int i;
    unsigned int j;

    for (i = 0; i<imageHeight; i++)
    {
        for (j = 0 ; j<imageWidth-2; j+= 3)
        {
            int offset = (i * imageWidth) + j;

            if ((PixelArray[offset] != 255 ) || (PixelArray[offset+1] != 255) || (PixelArray[offset+2] != 255))
            {
                PixelArray[offset+0] = 127;
                PixelArray[offset+1] = 50;
                PixelArray[offset+2] = 0;
            }
        }
    }


    f = fopen(fnameout,"wb");
    fwrite(&BMP_header,sizeof(BMP_header),1,f);
    fwrite(&BMP_info_header,sizeof(BMP_info_header),1,f);
    fwrite(PixelArray, imageSize, 1 , f);      
    fclose(f);
    free(PixelArray);

    return 0;
} 
I don't think it's working ..all i get is a full black background image..
Why don't you supply a link to an image that's giving you issues?
I don't think it's working ..all i get is a full black background image..

Depends on the image. Not many photographs have full white pixels (all of red, green and blue are at maximum brightness). I had to manually edit some existing images to paint in some white areas for testing.
Ok sure . http://postimg.org/image/ltpq0471x/5268a3d6/
I know for sure that all the images have perfect white background.
I've realised this happens with images that have size discrepancy..
Last edited on
I couldn't find a BMP image at that link?
There is a 256-colour PNG?
Thanks. Got that one now.
My own version of the code doesn't work with that image, I need to check further to see why.

edit: well, my code does seem to work if I remove the return 1; at line 39.
But it reports a discrepancy, which indicates my previous understanding or expectation may have been wrong.
Size discrepancy: expected = 5643   calculated = 5700

I've not checked the implications yet...
Last edited on
Anyway...can you please explain me what i was doing wrong and how you corrected that?
Ok, I think I understand it now.

The image is 99 x 19 (width x height) pixels.

99 x 3 (for RGB data) gives 297. Pad to multiple of 4. gives 300.

So the actual image data is 19 * 297 bytes = 5643
but it is stored in the file as 19 * 300 bytes = 5700

I believe it is safe to ignore the discrepancy (which was only something I added to confirm whether or not it made sense). It just means the header holds the unpadded image data size, rather than the padded size.

When I tried re-saving a copy of the bitmap in a photo editor, it changed the header value to 5700. (except for photoshop, which weirdly added another 2 bytes and came up with 5702).


Anyway...can you please explain me what i was doing wrong and how you corrected that?

I wasn't sure exactly what your code was doing, so I just re-wrote some of the code without reference to your version.

My approach was to base everything off the height and width.
1
2
BMP_info_header.height
BMP_info_header.width

From those two values I figured out the data size and used that for both reading from and writing to the file.

There were a couple of other changes I made in the for-loop as well, check the code and see.

It does raise the question though of what purpose the header value BMP_info_header.biSizeImage serves if it is unreliable.
May I ask what was the source of the file "captcha98.bmp" which generated the file with those header values?
Last edited on
Oh ok , i see now . It was given to me by the professor. (this was one of the tasks i had to solve) . Thanks for your help , it is deeply appreciated.
You're welcome. But I noticed a small issue with my code. It modifies the colour of the non-image data in the padding region. Hardly a major disaster, but it the results are tested simply by doing a byte-for-byte comparison of the output file, it could be flagged as incorrect.

To fix it, I created another variable to store the unpadded data width and used that in the loop instead of the padded value on this line:
 
    for (j = 0 ; j<imageWidth-2; j+= 3)



Topic archived. No new replies allowed.