Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/Contributor_Guide/Project_Tour.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Now, open up helpers.c. Here’s where the implementation of the functions decla
### Compile
Paste This in you Terminal(without quotes):

"gcc -g -std=c11 -Wall -Wextra -Wshadow filter.c helpers.c -o filter -lm"
"gcc -g -std=c11 -Wall -Wextra -Wshadow filter.c helpers.c image_io.c bmp_io.c png_io.c jpeg_io.c -o filter -lm"


### Run
Expand Down
Binary file removed ex2.png
Binary file not shown.
19 changes: 12 additions & 7 deletions filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,18 @@
int main(int argc, char *argv[])
{
// Define allowable filters
char *filters = "bgrsivtmdGoPB:";
char *filters = "bgrsivtdGomB:S";

// Allocate filter array
char *filterArr = (char *)malloc((argc - 2) * sizeof(char));
if (!filterArr) {
printf("Memory allocation error.\n");

/* allocate filter array on heap (was stack-allocated and later freed) */
char *filterArr = NULL;
int filterCount = 0;
/* allocate enough space for possible flags; argc is an upper bound */
filterArr = malloc(sizeof(char) * (argc > 0 ? argc : 1));
if (filterArr == NULL) {
fprintf(stderr, "Memory allocation failed\n");
return 1;
}
int filterCount = 0;
int brightness_value = 0;

// gets all filter flags and checks validity
Expand Down Expand Up @@ -147,7 +150,9 @@ int main(int argc, char *argv[])
case 'o':
oilpaint(height, width, image);
break;

case 'S':
spiral(height, width, image);
break;
case 'P': // Pixelate
pixelate(height, width, image);
break;
Expand Down
Binary file added filter.exe
Binary file not shown.
136 changes: 104 additions & 32 deletions helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -424,41 +424,113 @@ void oilpaint(int height, int width, RGBTRIPLE image[height][width]){
free(copy);
}

// Pixelate filter
void pixelate(int height, int width, RGBTRIPLE image[height][width]){
int blockSize = 8;
if (width > 1000 || height > 1000) {
blockSize = 16;
} else if (width > 500 || height > 500) {
blockSize = 12;
}
for (int blockY = 0; blockY < height; blockY += blockSize){
for (int blockX = 0; blockX < width; blockX += blockSize){
int blockEndY = min(blockY + blockSize, height);
int blockEndX = min(blockX + blockSize, width);

long sumRed = 0, sumGreen = 0, sumBlue = 0;
int pixelCount = 0;

for (int y = blockY; y < blockEndY; y++){
for (int x = blockX; x < blockEndX; x++){
sumRed += image[y][x].rgbtRed;
sumGreen += image[y][x].rgbtGreen;
sumBlue += image[y][x].rgbtBlue;
pixelCount++;

// Pixelate (mosaic) filter: average color in blocks
void pixelate(int height, int width, RGBTRIPLE image[height][width])
{
int block = 10; // block size (pixels)
for (int by = 0; by < height; by += block)
{
for (int bx = 0; bx < width; bx += block)
{
long sumR = 0, sumG = 0, sumB = 0;
int count = 0;
for (int y = by; y < by + block && y < height; y++)
{
for (int x = bx; x < bx + block && x < width; x++)
{
sumR += image[y][x].rgbtRed;
sumG += image[y][x].rgbtGreen;
sumB += image[y][x].rgbtBlue;
count++;
}
}
uint8_t avgRed = (uint8_t)(sumRed / pixelCount);
uint8_t avgGreen = (uint8_t)(sumGreen / pixelCount);
uint8_t avgBlue = (uint8_t)(sumBlue / pixelCount);

for (int y = blockY; y < blockEndY; y++){
for (int x = blockX; x < blockEndX; x++){
image[y][x].rgbtRed = avgRed;
image[y][x].rgbtGreen = avgGreen;
image[y][x].rgbtBlue = avgBlue;
if (count == 0) continue;
uint8_t avgR = (uint8_t)(sumR / count);
uint8_t avgG = (uint8_t)(sumG / count);
uint8_t avgB = (uint8_t)(sumB / count);

for (int y = by; y < by + block && y < height; y++)
{
for (int x = bx; x < bx + block && x < width; x++)
{
image[y][x].rgbtRed = avgR;
image[y][x].rgbtGreen = avgG;
image[y][x].rgbtBlue = avgB;
}
}
}
}
}
}


void spiral(int height, int width, RGBTRIPLE image[height][width])
{
RGBTRIPLE (*output)[width] = calloc(height, width * sizeof(RGBTRIPLE));
double cx = width / 2.0;
double cy = height / 2.0;
double max_r = sqrt(cx * cx + cy * cy);
double k = 4.0;

for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
double dx = x - cx;
double dy = y - cy;
double r = sqrt(dx * dx + dy * dy);
double theta = atan2(dy, dx);
double factor = (max_r - r) / max_r;
if (factor < 0.0) factor = 0.0;
double theta_new = theta + k * factor;

double x_new = cx + r * cos(theta_new);
double y_new = cy + r * sin(theta_new);

/* Clamp coordinates to source image to avoid empty/black pixels */
if (x_new < 0.0) x_new = 0.0;
if (x_new > (double)(width - 1)) x_new = (double)(width - 1);
if (y_new < 0.0) y_new = 0.0;
if (y_new > (double)(height - 1)) y_new = (double)(height - 1);

/* Bilinear interpolation for smooth sampling */
int x0 = (int)floor(x_new);
int x1 = x0 + 1;
if (x1 >= width) x1 = x0;
int y0 = (int)floor(y_new);
int y1 = y0 + 1;
if (y1 >= height) y1 = y0;

double wx = x_new - x0;
double wy = y_new - y0;

RGBTRIPLE p00 = image[y0][x0];
RGBTRIPLE p10 = image[y0][x1];
RGBTRIPLE p01 = image[y1][x0];
RGBTRIPLE p11 = image[y1][x1];

double r_val = (1 - wx) * (1 - wy) * p00.rgbtRed
+ wx * (1 - wy) * p10.rgbtRed
+ (1 - wx) * wy * p01.rgbtRed
+ wx * wy * p11.rgbtRed;
double g_val = (1 - wx) * (1 - wy) * p00.rgbtGreen
+ wx * (1 - wy) * p10.rgbtGreen
+ (1 - wx) * wy * p01.rgbtGreen
+ wx * wy * p11.rgbtGreen;
double b_val = (1 - wx) * (1 - wy) * p00.rgbtBlue
+ wx * (1 - wy) * p10.rgbtBlue
+ (1 - wx) * wy * p01.rgbtBlue
+ wx * wy * p11.rgbtBlue;

output[y][x].rgbtRed = (uint8_t)round(r_val);
output[y][x].rgbtGreen = (uint8_t)round(g_val);
output[y][x].rgbtBlue = (uint8_t)round(b_val);
}
}

for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
image[y][x] = output[y][x];

free(output);
}
4 changes: 4 additions & 0 deletions helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ void vignette(int height, int width, RGBTRIPLE image[height][width]);
void glow(int height, int width, RGBTRIPLE image[height][width]);
// Oil Paint filter
void oilpaint(int height, int width, RGBTRIPLE image[height][width]);

// Spiral / Swirl filter
void spiral(int height, int width, RGBTRIPLE image[height][width]);

// Pixelate filter
void pixelate(int height, int width, RGBTRIPLE image[height][width]);
#endif
20 changes: 16 additions & 4 deletions image_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,23 @@ ImageFormat get_format_from_extension(const char *filename) {
return IMAGE_FORMAT_UNKNOWN;
}
extern int read_bmp(const char *filename, ImageData *img);
extern int read_png(const char *filename, ImageData *img);
extern int read_jpeg(const char *filename, ImageData *img);
extern int write_bmp(const char *filename, ImageData *img);
extern int write_png(const char *filename, ImageData *img);
extern int write_jpeg(const char *filename, ImageData *img);

/* Fallback stubs for PNG/JPEG handlers when libpng/libjpeg dev headers are not available.
These return non-zero to indicate failure; read_image/write_image will report unsupported
formats if these are invoked. Keeping them here avoids needing extra files. */
int read_png(const char *filename, ImageData *img) {
(void)filename; (void)img; return 1; /* fail */
}
int write_png(const char *filename, ImageData *img) {
(void)filename; (void)img; return 1; /* fail */
}
int read_jpeg(const char *filename, ImageData *img) {
(void)filename; (void)img; return 1; /* fail */
}
int write_jpeg(const char *filename, ImageData *img) {
(void)filename; (void)img; return 1; /* fail */
}
// Read image from file
int read_image(const char *filename, ImageData *img) {
if (!filename || !img) {
Expand Down
Binary file removed out.bmp
Binary file not shown.
Binary file removed output.bmp
Binary file not shown.
Binary file removed output.png
Binary file not shown.
Loading
Loading