Proper way to display PNG using libpng onto a graphics buffer - c

I am trying to load png image using LibPNG c library onto a graphics buffer like so
//m_pBuffer is the graphics buffer
//row_pointers is the data from png
//width is width of image
//height height of image
//y = 100
//x = 100
//ScreenWidth = 1024
//channel_num = 4
int pDst = (y + height - 1) * ScreenWidth + x;
for (y = height - 1; y >= 0 ; y--)
{
png_bytep row = row_pointers[y];
u32 *pBuffer = m_pBuffer + pDst;
for(x = 0; x < width; x++) {
png_bytep px = &(row[x * channel_num]);
*pBuffer++ = RGBA(px[3], px[2], px[1], px[0]);
}
pDst -= ScreenWidth;
}
but what I get is a slightly distorted image.
Yet this is the original pic
How do I get rid of the slightly yellow background and white borders?
This is how row_pointers is populated
png_bytep row_pointers[height];
int row = 0;
for (row = 0; row < height; row++)
row_pointers[row] = NULL;
for (row = 0; row < height; row++)
row_pointers[row] = (png_byte*)png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));
int pass = 0;
int number_passes = 1;
for (pass = 0; pass < number_passes; pass++)
{
for (int j = 0; j < height; j++)
{
png_read_rows(png_ptr, NULL, &row_pointers[j], 1);
}
}
png_read_end(png_ptr, info_ptr);

Related

C issue, blur filter not working properly

Got a problem with code in C, the purpose is to blur given image working as a filter. The code reads height and width from RGBTRIPLE bmp.h file, makes a copy of each pixel in advance to compute the average in the middle pixel (when its 3x3 pixels chunk) or the boundary pixel's average (when its 2x3 chunk). I nested for-loops, 2 outer ones to copy each pixel from 'image', defined there 4 integers (3 doubles, 1 int.) to count each pixel's red, green and blue. The last int. is named counter to be my denominator in division.
The problem occurs not in syntax, but on the image. 4 down rows of pixels are like rainbow, each is different, not blurred. And the image is darkened.
When I don't use the pixels' copy it seems to work fine.
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE copy[height][width];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
// make a copy of rgbtriple image
copy[i][j].rgbtRed = image[i][j].rgbtRed;
copy[i][j].rgbtGreen = image[i][j].rgbtGreen;
copy[i][j].rgbtBlue = image[i][j].rgbtBlue;
// i need to ensure that image's pixels wont be out of bounds of rows/columns
// it's inappropriate to have static division by 9 because sometimes there will be less pixels to divide by
double sumRed = 0;
double sumGreen = 0;
double sumBlue = 0;
int count = 0;
for (int ii = i - 1; ii <= i + 1; ii++)
{
for (int jj = j - 1; jj <= j + 1; jj++)
{
if (ii >= 0 && ii < height && jj >= 0 && jj < width)
{
sumRed += copy[ii][jj].rgbtRed;
sumGreen += copy[ii][jj].rgbtGreen;
sumBlue += copy[ii][jj].rgbtBlue;
count++;
}
}
}
if (count != 0 && count <= 9)
{
image[i][j].rgbtRed = round(sumRed / count);
image[i][j].rgbtGreen = round(sumGreen / count);
image[i][j].rgbtBlue = round(sumBlue / count);
}
}
}
return;
}
Thanks in advance!
You compute the new value of the image pixels from the data in the copy matrix, but you did not copy the whole image before hand, only pixel values up to the current pixel. Hence the results are incorrect.
You should copy the whole image in a separate loop or using memcpy.
Here is a modified version:
#include <string.h>
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width]) {
RGBTRIPLE copy[height][width];
// make a copy of rgbtriple image
#if 1 // using memcpy
memcpy(copy, image, sizeof(copy));
#else
// if you cannot use memcpy
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
copy[i][j] = image[i][j];
}
}
#endif
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
// Mix the color values with the adjacent pixels
// making sure the pixels are inside the image.
// It is inappropriate to always divide by 9
// because depending on the pixel position and image size
// count can be 1, 2, 3, 4, 6 or 9
double sumRed = 0;
double sumGreen = 0;
double sumBlue = 0;
int count = 0;
for (int ii = i - 1; ii <= i + 1; ii++) {
for (int jj = j - 1; jj <= j + 1; jj++) {
if (ii >= 0 && ii < height && jj >= 0 && jj < width) {
sumRed += copy[ii][jj].rgbtRed;
sumGreen += copy[ii][jj].rgbtGreen;
sumBlue += copy[ii][jj].rgbtBlue;
count++;
}
}
}
// no need to test count: there is at least one pixel
image[i][j].rgbtRed = round(sumRed / count);
image[i][j].rgbtGreen = round(sumGreen / count);
image[i][j].rgbtBlue = round(sumBlue / count);
}
}
}

CS50 Problem Set 4 Filter (less). I keep getting Seg Fault errors

Everything else works fine, but whenever I run it gives me a segmentation fault error. I have spent hours reading over my own code, but I can't find it. I also can't use debug50 for some reason. Please help!
I tried to create a box blur effect on a bitmap image. This is done by taking the average RGB of surrounding boxes (if they are within the bounds of the image) and then updating the pixel colour.
void blur(int height, int width, RGBTRIPLE image[height][width])
{
// make a copy?
RGBTRIPLE copy[height][width];
// set primary cursor
for (int j = 0; j < height; j++)
{
for (int i = 0; i < width; i++)
{
// primary cursor moving means refresh count
int denom = 0;
double totalR = 0;
double totalG = 0;
double totalB = 0;
int avgR = 0;
int avgG = 0;
int avgB = 0;
// set index positions
int yCoord[] = {j - 1, j, j + 1};
int xCoord[] = {i - 1, i, i + 1};
// set secondary cursor (creating mini 3x3 search grid area)
for (int row = 0; row < 3; row++)
{
for (int col = 0; col < 3; col++)
{
int secRow = yCoord[row];
int secCol = xCoord[col];
// check inbounds
if (yCoord[row] >= 0 && yCoord[row] < 5 && xCoord[col] >= 0 && xCoord[col] < 5)
{
RGBTRIPLE pixel = image[secRow][secCol];
// inbounds
denom++;
// update total count around primary cursor
totalR += pixel.rgbtRed;
totalG += pixel.rgbtGreen;
totalB += pixel.rgbtBlue;
}
}
}
// update primary cursor avg
copy[j][i].rgbtRed = round(totalR / denom);
copy[j][i].rgbtGreen = round(totalG / denom);
copy[i][j].rgbtBlue = round(totalB / denom);
}
}
// transfer copy to original image at the end
for (int j = 0; j < height; j++)
{
for (int i = 0; i < width; i++)
{
image[j][i] = copy[j][i];
}
}
return;
}

Trying to blurr an image in C but whole row is blured same way

So I am trying to make a function that blurs an image, basically checks all pixels around it by 1 if there is adds to counter and divides total RGB and for some reason my picture comes out like this: and idk what is happening
blurred result , I think the image is blurring whole row using same value? why is that?
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE temp[height][width];
for(int i = 0; i < height; i++)
{
for(int j = 0; j < width; j++)
{
float totalRed,totalGreen,totalBlue;
totalRed = totalGreen = totalBlue = 0;
float counter = 0.00;
//close pixels
for(int x = -1; x < 2; x++)
{
for(int y = -1; y < 2; y++)
{
int nbrX = i + x;
int nbrY = i + y;
if (nbrX < 0 || nbrX > (height - 1) || nbrY < 0 || nbrY > (width - 1))
{
continue;
}
totalRed += image[nbrX][nbrY].rgbtRed;
totalGreen += image[nbrX][nbrY].rgbtGreen;
totalBlue += image[nbrX][nbrY].rgbtBlue;
counter++;
}
temp[i][j].rgbtRed = round(totalRed/ counter);
temp[i][j].rgbtGreen = round(totalGreen/ counter);
temp[i][j].rgbtBlue = round(totalBlue/ counter);
}
}
}
for(int i = 0; i < height; i++)
{
for(int j = 0; j < width; j++)
{
image[i][j].rgbtRed = temp[i][j].rgbtRed;
image[i][j].rgbtGreen = temp[i][j].rgbtGreen;
image[i][j].rgbtBlue = temp[i][j].rgbtBlue;
}
}
}
Because your variables for x/y-coordinates of the "nearby"-pixel both use "i" as reference..
int nbrX = j + x;
int nbrY = i + y;
(I'd rather have made a comment - but without reputation..)

CS50 Pset4 filter-more blur() function not working

Link to the problem (blur part only) here.
In this code I am trying to blur a bmp image by taking the weighted sum across 3x3 matrix for each pixel and replacing the original value with the average obtained.
I have tried various different things, the code compiles correctly (there is no error), and also I couldn't find any problem while debugging the code , but the output image obtained is not what was desired, it is a black and colored pattern repeated 3 times vertically instead of the edges of the input photo.
Thanks for helping out.
Here is the main code of the function:
// Blur image
void blur(int height, int width, RGBTRIPLE image[height][width])
{
// Array for storing corresponding blur values of the pixels.
RGBTRIPLE(*blur)[width] = calloc(height, width * sizeof(RGBTRIPLE));
if (image == NULL)
{
printf("Not enough memory to store blur pixels.\n");
return;
}
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
sum3x3(row, col, height, width, image, blur);
}
}
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
image[row][col] = blur[row][col];
}
}
free(blur);
return;
}
Here is the code for sum3x3 function:
void sum3x3(int row, int col, int height, int width, RGBTRIPLE matrix[row][col], RGBTRIPLE new_matrix[row][col] )
{
float counter = 0;
float blue = 0;
float green = 0;
float red = 0;
for (int i = -1; i < 2; i++)
{
for (int j = -1; j < 2; j++)
{
// skip rows out of range.
if ( (i + row) < 0 || (i + row >= height)) continue;
// skip columns out of range.
if ( (j + col) < 0 || (j + col >= width)) continue;
// add to sum.
counter ++;
blue += matrix[i + row][j + col].rgbtBlue;
green += matrix[i + row][j + col].rgbtGreen;
red += matrix[i + row][j + col].rgbtRed;
}
}
new_matrix[row][col].rgbtBlue += round(blue/counter);
new_matrix[row][col].rgbtGreen += round(green/counter);
new_matrix[row][col].rgbtRed += round(red/counter);
}
The RGBTRIPLE data structure:
typedef struct
{
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;
Update: I made some changes to the code according to the suggestions in comments but still not getting the desired output.

Scaling up an image using nearest-neighbor

I have been trying to make my program scale up an image. I had some problem to allocate new space for my scaled image, but I think it is fixed. The problem I am having is that the program crashes when I am trying to send back my image from my temporary memory holder.
The loaded image is placed in my struct Image. The pixels are placed in
img->pixels, the height in img->height and the width in img->width. But I have no idea why the program crashes when I transfer the pixels from my tmp2 struct to my img struct while it does not crash when I do the opposite. Here is the code:
void makeBigger(Image *img, int scale) {
Image *tmp2;
tmp2 = (Image*)malloc(sizeof(Image));
tmp2->height = img->height*scale;
tmp2->width = img->width*scale;
tmp2->pixels = (Pixel**)malloc(sizeof(Pixel*)*tmp2->height);
for (unsigned int i = 0; i < img->height; i++)
{
tmp2->pixels[i] = (Pixel*)malloc(sizeof(Pixel)*tmp2->width);
for (unsigned int j = 0; j < img->width; j++)
{
tmp2->pixels[i][j] = img->pixels[i][j];
}
}
free(img->pixels);
//scaling up the struct's height and width
img->height *= scale;
img->width *= scale;
img->pixels = (Pixel**)malloc(sizeof(Pixel*)*img->height);
for (unsigned int i = 0; i < tmp2->height; i++)
{
img->pixels[i] = (Pixel*)malloc(sizeof(Pixel)*img->width);
for (unsigned int j = 0; j < tmp2->width; j++)
{
img->pixels[i][j] = tmp2->pixels[i+i/2][j+j/2];
}
}
}
I would be glad if you have any idea of how to make the nearest-neighbor method to work.
EDIT: I am trying to crop the inner rectangle so I can scale it up (zoom).
Image *tmp = (Image*)malloc(sizeof(Image));
tmp->height = img->height / 2;
tmp->width = img->width / 2;
tmp->pixels = (Pixel**)malloc(sizeof(Pixel*) * tmp->height);
for (unsigned i = img->height / 4 - 1; i < img->height - img->height / 4; i++) {
tmp->pixels[i] = (Pixel*)malloc(sizeof(Pixel) * tmp->width);
for (unsigned j = img->width / 4; j < img->width - img->width / 4; j++) {
tmp->pixels[i][j] = img->pixels[i][j];
}
}
for (unsigned i = 0; i < img->height; i++) {
free(img->pixels[i]);
}
free(img->pixels);
img->height = tmp->height;
img->width = tmp->width;
img->pixels = tmp->pixels;
free(tmp);
I see that you're overcomplicating things (walking over the image twice for example).Here's the code (I am posting the whole program - I made assumptions about Pixel and Image that might not match what you have), but if you copy / paste makeBigger it should work in your code OOTB:
code00.c:
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
typedef uint32_t Pixel;
typedef struct {
uint32_t width, height;
Pixel **pixels;
} Image;
void makeBigger(Image *img, int scale)
{
uint32_t i = 0, j = 0;
Image *tmp = (Image*)malloc(sizeof(Image));
tmp->height = img->height * scale;
tmp->width = img->width * scale;
tmp->pixels = (Pixel**)malloc(sizeof(Pixel*) * tmp->height);
for (i = 0; i < tmp->height; i++) {
tmp->pixels[i] = (Pixel*)malloc(sizeof(Pixel) * tmp->width);
for (j = 0; j < tmp->width; j++) {
tmp->pixels[i][j] = img->pixels[i / scale][j / scale];
}
}
for (i = 0; i < img->height; i++)
free(img->pixels[i]);
free(img->pixels);
img->width = tmp->width;
img->height = tmp->height;
img->pixels = tmp->pixels;
free(tmp);
}
void printImage(Image *img)
{
printf("Width: %d, Height: %d\n", img->width, img->height);
for (uint32_t i = 0; i < img->height; i++) {
for (uint32_t j = 0; j < img->width; j++)
printf("%3d", img->pixels[i][j]);
printf("\n");
}
printf("\n");
}
int main()
{
uint32_t i = 0, j = 0, k = 1;
Image img;
// Initialize the image
img.height = 2;
img.width = 3;
img.pixels = (Pixel**)malloc(sizeof(Pixel*) * img.height);
for (i = 0; i < img.height; i++) {
img.pixels[i] = (Pixel*)malloc(sizeof(Pixel) * img.width);
for (j = 0; j < img.width; j++)
img.pixels[i][j] = k++;
}
printImage(&img);
makeBigger(&img, 2);
printImage(&img);
// Destroy the image
for (i = 0; i < img.height; i++)
free(img.pixels[i]);
free(img.pixels);
printf("\nDone.\n");
return 0;
}
Notes (makeBigger related - designed to replace the content of the image given as argument):
Construct a temporary image that will be the enlarged one
Only traverse the temporary image once (populate its pixels as we allocate them); to maintain scaling to the original image and make sure that the appropriate pixel is "copied" into the new one, simply divide the indexes by the scaling factor: tmp->pixels[i][j] = img->pixels[i / scale][j / scale]
Deallocate the original image content: since each pixel row is malloced, it should also be freed (free(img->pixels); alone will yield memory leaks)
Store the temporary image content (into the original one) and then deallocate it
Output:
[cfati#cfati-5510-0:/cygdrive/e/Work/Dev/StackOverflow/q041861274]> ~/sopr.sh
### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###
[064bit prompt]> ls
code00.c
[064bit prompt]> gcc -o code00.exe code00.c
[064bit prompt]> ./code00.exe
Width: 3, Height: 2
1 2 3
4 5 6
Width: 6, Height: 4
1 1 2 2 3 3
1 1 2 2 3 3
4 4 5 5 6 6
4 4 5 5 6 6
Done.

Resources