Dealing with padding in a BMP file in C - c

I am trying to edit a BMP file in C. My code works for BMP files with no padding but I am having trouble dealing with padding.
There are a few other questions on BMP files that I have read but most of them use other languages like C# and Java so I didn't find them very useful.
Here is what the pixel array looks like, but much larger:
char bmpArray[MAX] = {B,G,R,B,G,R,B,G,R,0,0,0,
B,G,R,B,G,R,B,G,R,0,0,0,
B,G,R,B,G,R,B,G,R,0,0,0}
The zeros are for padding bytes to make each row divisible by 4, it depends on the pixel width of the image. What I am trying to do is leave these padding bytes the way they are in the same position and only deal with the B,G,R bytes. If I apply edits to the padding values, the resulting image will be distorted.
I made a function that generates the amount of padding bytes based on the width.
It uses this formula 4 - ((width * 3) % 4) and it works as I tested it with images with different width.
I successfully extracted the B, G, R data of the BMP file and put it into an array so I will only post the part of the code I am having trouble with.
int c = 0;
for (int a = 0; a < height; a++) {
for (int b = 0; b < width*3; b++) {
if (bmpArray[a*(width*3)+b] < 127) {
bmpArray[a*(width*3)+b] = 0;
} else {
bmpArray[a*(width*3)+b] = 255;
}
c++;
}
for (int pad = 0; pad < padding; pad++) {
bmpArray[c++] = 0x00;
}
}
What I am trying to do is "draw" each row of the output BMP file and then stop as soon as I reach the end of the row, that is width*3, then after that draw the padding bytes before going to the next row of pixels.
Alternatively, is there a way I can identify the padding pixels using a single for loop and then use an if statement to not modify the padding pixels? For example:
for (int a = 0; a < bmpArraySize; a++) {
paddingBytes = ??? //for example for the first row
// paddingBytes are i + width*3 + 1
// and i + width*3 + 2 and i + width*3 + 3 if padding = 3
if (a = paddingBytes) {
bmpArray[a] = 0x00;
}
else if (bmpArray[a] < 127) {
bmpArray[a] = 0;
}
else {
bmpArray[a] = 255;
}
}

The problem is in this part:
int c = 0;
for (int a = 0; a < height; a++) {
for (int b = 0; b < width*3; b++) {
if (bmpArray[a*(width*3)+b] < 127) {
bmpArray[a*(width*3)+b] = 0;
} else {
bmpArray[a*(width*3)+b] = 255;
}
}
for (int pad = 0; pad < padding; pad++) {
bmpArray[c++] = 0x00; /* ONLY HERE is 'c' updated! */
}
}
At the end of each line, you fill out the padding starting at c, which starts out at 0 and so overwrites the first few bytes of the first line. Then, each next line gets copied but you continue overwriting from the start (where c initially pointed to).
The padding should be added on each line. In the loops, you adjust a and b but you forget to adjust for the padding.
I suggest the more straightforward code (untested!):
for (int a = 0; a < height; a++) {
for (int b = 0; b < width*3; b++) {
if (bmpArray[a*(width*3 + padding)+b] < 127) {
bmpArray[a*(width*3 + padding)+b] = 0;
} else {
bmpArray[a*(width*3 + padding)+b] = 255;
}
}
for (int pad = 0; pad < padding; pad++) {
bmpArray[a*(width*3 + padding) + 3*width + pad] = 0x00;
}
}
is there a way I can identify the padding pixels ..
Yes – in my loop above with adjustments for padding, it automatically skips the padding itself. You can safely remove the explicit 'set padding to 0' loop at the end.

Something like:
...
int originalLineSize = width * 3;
int workLineSize = originalLineSize + 4 - originalLineSize % 4;
for (int a = 0; a < bmpArraySize; ++a) {
if ((a % workLineSize) >= originalLineSize)
bmpArray[a] = 0x00;
}
else if (bmpArray[a] < 127) {
bmpArray[a] = 0;
...
}

The "padding bytes" are the bytes following the pixels of a scanline. You are not so interested in the padding as in the scanline size and pixel size:
iScanlineSize = ((width * bitsperpixel) + 31) / 32 * 4;
iBytesperPixel = bitsperpixel / 8;
Now you can loop over scanlines and adress pixels and pixel parts (colors) as follows:
for (int a = 0; a < height; a++) {
for (int b = 0; b < width; b++) {
for (int c = 0; c < iBytesperPixel; c++) {
pixelPart= bmpArray[a*iScanlineSize + b*iBytesperPixel + c];
}
]
}

Related

Blur image function causing segfault in C

I am receiving a Segmentation fault (core dumped) error when trying to blur an image, but I cannot find out why. To achieve a blur, I loop through each element in the 2x2 image array. I then check each of the 9x9 squares around & including it - if they exist, their RGB values are added to a sum (sumRed, sumGreen, sumBlue) for each color. I also increment a counter called numPixel each time this is successful so I can average the RGB values at the end.
There are other parts of the code, but I am certain that this blur() function is causing the segfault. This is because when I comment out the body of the function, the segfault goes away.
However, within the function I do not see what is triggering the segfault. I don't think I'm going out of bound in an array, which has been the cause of most of my segfaults in the past. From commenting out certain portions of the code, I also gathered that memcpy() is not the cause of the error (or at least not the only cause).
There's also a custom header file, which includes definitions for BYTE and RGBTRIPLE:
typedef uint8_t BYTE;
...
typedef struct
{
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;
The actual code is:
// TODO: Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE new_image[height][width];
BYTE sumRed, sumGreen, sumBlue;
BYTE numPixels;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; w++)
{
sumRed = sumGreen = sumBlue = 0;
numPixels = 0;
// Check from 1 higher to 1 lower
for (int h = i - 1; h <= i + 1; h++)
{
// Check from 1 left to 1 right
for (int w = j - 1; w <= j + 1; j++)
{
// If neither index is out of bound, add neighboring RGB values
if (0 <= h < height && 0 <= w < width)
{
sumRed += image[h][w].rgbtRed;
sumGreen += image[h][w].rgbtGreen;
sumBlue += image[h][w].rgbtBlue;
numPixels++;
}
}
}
new_image[i][j].rgbtRed = (BYTE) sumRed / numPixels;
new_image[i][j].rgbtGreen = (BYTE) sumGreen / numPixels;
new_image[i][j].rgbtBlue = (BYTE) sumBlue / numPixels;
}
}
memcpy(&image[0][0], &new_image[0][0], sizeof(image[0][0]) * height * width);
return;
}
Be sure of your logic, not relying on braces to save the day. Use simple short names in "local context". "Ease of reading" trumps being "Overly explicit."
for (int h = 0; h < height; h++)
for (int w = 0; w < width; w++) {
// bigger accumulators, short names, declared & init'd locally
uint16_t sumR = 0;
uint16_t sumG = 0;
uint16_t sumB = 0;
int nPix = 0;
for (int hO = -1; hO <= 1; hO++) // height offset range
for (int wO = -1; wO <= 1; wO++) { // width offset range
int indH = h + hO; // Simple!
int indW = w + wO;
if (0 <= indH && indH < height && 0 <= indW && indW < width) {
RGBTRIPLE *p = &image[ indH ][ indW ]; // short alias
sumR += p->rgbtRed;
sumG += p->rgbtGreen;
sumB += p->rgbtBlue;
nPix++;
}
}
new_image[i][j].rgbtRed = (BYTE)( sumR / nPix );
new_image[i][j].rgbtGreen = (BYTE)( sumG / nPix );
new_image[i][j].rgbtBlue = (BYTE)( sumB / nPix );
}
/* memcpy....*/
I'm still uneasy with possible confusion between "Height/width" and "vertical/Horizontal".
Here's an alternative for the two inner loops. Don't bother to set-up the width if the height is out-of-frame...
// From -1 offset, examine >>3<< pixels: -1, 0, 1...
for( int ih = h-1, limH = ih+3; ih < limH; ih++ ) { // height range
if( ih < 0 || height <= ih ) continue;
for( int iw = w-1, limW = iw+3; iw < limW; iw++) { // width range
if( iw < 0 || width <= iw ) continue;
RGBTRIPLE *p = &image[ ih ][ iw ]; // short alias
sumR += p->rgbtRed;
sumG += p->rgbtGreen;
sumB += p->rgbtBlue;
nPix++;
}
}

bmp file into 2D binary array

I need to read a bmp file and display it as a 2d array of 1 and 0
if the pixel is blue the value in the array is 1 and 0 for white.
unsigned int temp;
int i, j, width, hight;
int** bmp;
FILE* pic;
fopen_s(&pic, "fishpool2.bmp", "rb");
pic_size(pic, &width, &hight);
printf_s("width = %d\thight = %d\n", width, hight);
fseek(pic, 54, SEEK_SET);
for (i = 0; i < hight; i++) {
for (j = 0; j < width; j++) {
temp = fgetc(pic);
fgetc(pic);
fgetc(pic);
if (temp >= 155 && temp <= 245) bmp[i][j] = 1;
}
}
for (i = 0; i < hight; i++) {
for (j = 0; j < width; j++) {
printf_s("%d", bmp[i][j]);
}
puts("");
}
this is what I have so far. I didn't include the code part with i allocate memory and getting the height and width of the pic.
I don't know why but when I run the code the blue spots aren't in the correct position.
(I need to read the picture from the bottom left to top right)
Read this.
BMP file format - Wikipedia
The BMP file format is complex with many variations. Which documents did you look at and code? And you seem to be limiting yourself to specific formats and parameters to read, does that match the actual file you are trying to read?
The stride between two consecutive rows is rounded to 4 bytes. From https://en.wikipedia.org/wiki/BMP_file_format#Pixel_array_(bitmap_data)
For file storage purposes, only the size of each row must be a multiple of 4 bytes while the file offset can be arbitrary.
Therefore in your case (width = 110), each line is 330 bytes long. The stride is rounded to the next multiplicity of 4 which is 332. Therefore the program should fetch 332-330 = 2 extra bytes after processing each row:
for (i = 0; i < hight; i++) {
for (j = 0; j < width; j++) {
temp = fgetc(pic);
fgetc(pic);
fgetc(pic);
if (temp >= 155 && temp <= 245) bmp[i][j] = 1;
}
// fetch 2 extra bytes
fgetc(pic);
fgetc(pic);
}
The more robust solution could be:
size_t row_size = width * 3;
size_t row_size_rounded = (row_size + 3) / 4 * 4;
size_t padding = rows_size_rounded - rows_size;
...
for (i = 0; i < hight; i++) {
for (j = 0; j < width; j++) {
...
}
for (size_t p = 0; p < padding; ++p)
fgetc(pic);
}
When approaching a well-known file format, it is usually a good idea not to "reinvent the wheel". Rather, you look for a library which reads/parses this format into something your program can use more easily. If you search on GitHub, for example, you'll find several BMP reading/writing libraries you could use.
Or you could go for the "swiss army knife" which is ImageMagic; see here.

What can i do to make this program return values that it's supposed to?

Program is supposed to take every pixel around the pixel and average color values.
It seems to be working fine visually, but obviously it is not as it doesn't pass the test. The only test it passes is 'pixel in the corner'.
I would really appreciate some hints on where the bug might be.
Here is the code:
//iterate through each row and column
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
/*create variables to define 3x3 box for each pixel
also create variables to store sum of each colour values for all elements of each box*/
int highi = i + 1;
int highj = j + 1;
int counter = 0;
int blue = 0;
int red = 0;
int green = 0;
//iterate through each element of newly created box and add sums of colour values
for(int lowi = i-1 ; lowi <= highi; lowi++)
{
if(lowi < 0)
{
lowi = i;
}
for (int lowj = j-1 ; lowj <= highj; lowj++)
{
if(lowj < 0)
{
lowj = j;
}
blue += image[lowi][lowj].rgbtBlue;
red += image[lowi][lowj].rgbtRed;
green += image[lowi][lowj].rgbtGreen;
counter++;
}
//calculate average of colour values for each pixel
image[i][j].rgbtBlue = blue/counter;
image[i][j].rgbtRed = red/counter;
image[i][j].rgbtGreen = green/counter;
}
The issue was that OP was writing to his image[][] array while reading from it, this causing it to be in error after the first read/write pass.

How I can resize a bitmap properly?

I want to downsample the bitmap of a BMP file by a factor M. I want to obatain the image without aliasing. So in order to achieve it I compute the mean of the MxM pixels in this way:
The problem apears when I try to resize non-squared images because it only compute the mean proprely in a square. For example, if the final image is 300x150, the mean is right until 150x150 pixel. If I had the previous_mean -> new_mean = (previous_mean+value)/2
This is how I actually compute it:
for (i = 0; i < new_height; i++) {
for (j = 0; j < new_width; j++) {
mean.r = bitmap[i*factor][j*factor].r;
mean.g = bitmap[i*factor][j*factor].g;
mean.b = bitmap[i*factor][j*factor].b;
for(k = i*factor; (k < i*factor+factor)&&(k<old_height); k++){
for(l = j*factor; (l < j*factor+factor)&&(l<old_width); l++){
mean.r = (mean.r + bitmap[k][l].r)/2;
mean.g = (mean.g + bitmap[k][l].g)/2;
mean.b = (mean.b + bitmap[k][l].b)/2;
}
}
new_bitmap[i][j] = mean;
mean.r = 0;
mean.g = 0;
mean.b = 0;
}
}
new_bitmap and bitmap are 2-D array of PIXELS, being PIXELS:
typedef struct __attribute__((__packed__)){
unsigned char b;
unsigned char g;
unsigned char r;
} PIXELS;
This is absolutely correct, I were permutating the old_width with the old_heigth.

How to reduce or increase the size of a image in pixel level in c

The color data is just the color data, headers are not included. After I ran my code, the picture with new size shows only black pixel and at the bottom are some random dark colors. The size, width and height are all good but the colors.
//code to change to bigger image
int r, c, i, j;
for (r = 0; r < height; r++)
{
for (c = 0; c < width*3; c++)
{
for (i = 0; i < 2; i++)
{
for (j = 0; j < 2; j++)
{
if (j == 0)
{
bigColorData[2*r+i][c] = oldColorData[r][c];
}
else
{
bigColorData[2*r+i][2*c+2] = oldColorData[r][c];
}
}
}
}
}
From the c < width*3 I deduce you are working with 3 bytes-per-pixel pixels (24 bit color).
But this will not work as the scanlines (width) are rounded up to the nearest word, so the loop must be:
int bits= 3*8;
int scanlinesize= ((bits + 31) / 32 * 4);
unsigned char *pix, *scanline= begin_of_image_data;
for (r = 0; r < height; r++, scanline += scanlinesize)
{
pix= scanline;
for (c = 0; c < width; c++, pix += 3)
{
// now pix points to the first byte of the pixel

Resources