Skip to content

Commit 200432a

Browse files
Merge pull request #43 from indrasuthar07/png-support
feat: add PNG & JPEG file support for filters
2 parents 4b01097 + bbd6104 commit 200432a

File tree

12 files changed

+721
-124
lines changed

12 files changed

+721
-124
lines changed

Makefile

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,24 @@
11
# Compiler and compiler flags
22
CC = gcc
3-
CFLAGS = -g -std=c11 -Wall -Wextra -Werror -Wshadow
4-
LDFLAGS = -lm
3+
CFLAGS = -g -std=c11 -Wall -Wextra -Wshadow
4+
LDFLAGS = -lm -lpng -ljpeg
5+
6+
# Include paths (adjust for your system)
7+
INCLUDES = -I/ucrt64/include
8+
# For Linux/macOS with standard paths, comment out INCLUDES or set to empty:
9+
# INCLUDES =
510

611
# Source files and executable name
7-
SRCS = filter.c helpers.c
8-
TARGET = filter
12+
SRCS = filter.c helpers.c image_io.c bmp_io.c png_io.c jpeg_io.c
13+
TARGET = filter.exe
914

1015
# Default target
1116
all: $(TARGET)
1217

1318
# Rule to link the object files into the final executable
1419
$(TARGET): $(SRCS)
15-
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
20+
$(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ $(LDFLAGS)
1621

1722
# Rule to clean up generated files
1823
clean:
19-
rm -f $(TARGET)
24+
rm -f $(TARGET) *.o

README.md

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -261,9 +261,81 @@ To apply a filter via command-line:
261261
- `B <value>`: brightness
262262
- `o`: oilpaint
263263

264-
265-
Example for glow:
266-
filter -G input.bmp output.bmp
264+
#### Examples:
265+
266+
```bash
267+
# Grayscale a PNG image
268+
./filter.exe -g input.png output.png
269+
# Sepia on JPEG image
270+
./filter.exe -s input.jpg output.jpg
271+
# Blur a BMP image
272+
./filter.exe -b input.bmp output.bmp
273+
# Chain multiple filters
274+
./filter.exe -g -b input.png output.png
275+
# Convert format (PNG to JPEG)
276+
./filter.exe -g input.png output.jpg
277+
# Brightness adjustment
278+
./filter.exe -B 40 input.jpg output.jpg
279+
```
280+
281+
You can also chain multiple filters by supplying multiple tags (e.g., `./filter.exe -v -g input.bmp output.bmp` for vignette then grayscale).
282+
283+
## Supported Image Formats
284+
285+
The Image-Filtering tool supports multiple image formats:
286+
287+
- **BMP**: 24-bit uncompressed BMP files
288+
- **PNG**: PNG images with RGB color space (supports various PNG formats including RGBA, grayscale, palette - automatically converted to RGB)
289+
- **JPEG**: JPEG images with RGB color space (supports grayscale and RGB JPEGs)
290+
291+
### Format Auto-Detection
292+
293+
The tool automatically detects the input image format based on file signatures (magic bytes). The output format is determined by the file extension of the output filename. You can convert between formats by simply changing the output file extension.
294+
295+
### Examples with Different Formats
296+
297+
```bash
298+
# Process PNG image
299+
./filter.exe -g photo.png photo_gray.png
300+
# Process JPEG image
301+
./filter.exe -s photo.jpg photo_sepia.jpg
302+
# Convert PNG to JPEG
303+
./filter.exe -g input.png output.jpg
304+
# Convert JPEG to BMP
305+
./filter.exe -b input.jpg output.bmp
306+
# Chain filters on PNG
307+
./filter.exe -g -b input.png output.png
308+
```
309+
310+
## Building and Installation
311+
312+
#### Windows (MSYS2)
313+
```bash
314+
# Install dependencies in MSYS2 UCRT64 terminal
315+
pacman -Syu
316+
pacman -S mingw-w64-ucrt-x86_64-gcc
317+
pacman -S mingw-w64-ucrt-x86_64-libpng
318+
pacman -S mingw-w64-ucrt-x86_64-libjpeg-turbo
319+
pacman -S make
320+
```
321+
322+
#### Linux (Ubuntu/Debian)
323+
```bash
324+
sudo apt-get update
325+
sudo apt-get install libpng-dev libjpeg-dev build-essential
326+
```
327+
328+
#### macOS
329+
```bash
330+
brew install libpng libjpeg
331+
```
332+
333+
### Building
334+
335+
```bash
336+
make clean
337+
make
338+
```
267339

268340
You can also chain multiple filters by supplying multiple tags (e.g., `./filter vg input.bmp output.bmp` for vignette then grayscale).
269341

bmp.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
#endif
1515

1616
// --- Bitmap File Header (14 bytes) ---
17-
typedef struct
17+
typedef struct bmp_file_header_struct
1818
{
1919
uint16_t bfType; // File type ("BM")
2020
uint32_t bfSize; // Size of the file in bytes
@@ -24,7 +24,7 @@ typedef struct
2424
} BITMAPFILEHEADER;
2525

2626
// --- Bitmap Info Header (40 bytes for BITMAPINFOHEADER) ---
27-
typedef struct
27+
typedef struct bmp_info_header_struct
2828
{
2929
uint32_t biSize; // Header size (40 bytes)
3030
int32_t biWidth; // Image width in pixels
@@ -40,7 +40,7 @@ typedef struct
4040
} BITMAPINFOHEADER;
4141

4242
// --- RGB Triple (3 bytes per pixel) ---
43-
typedef struct
43+
typedef struct bmp_rgb_triple_struct
4444
{
4545
uint8_t rgbtBlue;
4646
uint8_t rgbtGreen;

bmp_io.c

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#include "image_io.h"
2+
#include "bmp.h"
3+
#include <stdlib.h>
4+
#include <string.h>
5+
6+
// Read BMP file
7+
int read_bmp(const char *filename, ImageData *img) {
8+
FILE *inptr = fopen(filename, "rb");
9+
if (inptr == NULL) {
10+
return 1;
11+
}
12+
BITMAPFILEHEADER bf;
13+
if (fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr) != 1) {
14+
fclose(inptr);
15+
return 1;
16+
}
17+
BITMAPINFOHEADER bi;
18+
if (fread(&bi, sizeof(BITMAPINFOHEADER), 1, inptr) != 1) {
19+
fclose(inptr);
20+
return 1;
21+
}
22+
if (bf.bfType != 0x4d42 || bf.bfOffBits != 54 || bi.biSize != 40 || bi.biBitCount != 24 || bi.biCompression != 0) {
23+
fclose(inptr);
24+
return 1;
25+
}
26+
img->height = abs(bi.biHeight);
27+
img->width = bi.biWidth;
28+
img->format = IMAGE_FORMAT_BMP;
29+
30+
img->pixels = (RGBTRIPLE **)malloc(img->height * sizeof(RGBTRIPLE *));
31+
if (img->pixels == NULL) {
32+
fclose(inptr);
33+
return 1;
34+
}
35+
RGBTRIPLE *pixel_data = (RGBTRIPLE *)calloc(img->height * img->width, sizeof(RGBTRIPLE));
36+
if (pixel_data == NULL) {
37+
free(img->pixels);
38+
fclose(inptr);
39+
return 1;
40+
}
41+
for (int i = 0; i < img->height; i++) {
42+
img->pixels[i] = pixel_data + i * img->width;
43+
}
44+
int padding = (4 - (img->width * sizeof(RGBTRIPLE)) % 4) % 4;
45+
46+
// Read pixels
47+
for (int i = 0; i < img->height; i++) {
48+
if (fread(img->pixels[i], sizeof(RGBTRIPLE), img->width, inptr) != (size_t)img->width) {
49+
free_image(img);
50+
fclose(inptr);
51+
return 1;
52+
}
53+
fseek(inptr, padding, SEEK_CUR);
54+
}
55+
56+
fclose(inptr);
57+
return 0;
58+
}
59+
60+
// Write BMP file
61+
int write_bmp(const char *filename, ImageData *img) {
62+
FILE *outptr = fopen(filename, "wb");
63+
if (outptr == NULL) {
64+
return 1;
65+
}
66+
int padding = (4 - (img->width * sizeof(RGBTRIPLE)) % 4) % 4;
67+
int row_size = img->width * sizeof(RGBTRIPLE) + padding;
68+
int image_size = row_size * img->height;
69+
70+
BITMAPFILEHEADER bf;
71+
bf.bfType = 0x4d42;
72+
bf.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + image_size;
73+
bf.bfReserved1 = 0;
74+
bf.bfReserved2 = 0;
75+
bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
76+
77+
BITMAPINFOHEADER bi;
78+
bi.biSize = sizeof(BITMAPINFOHEADER);
79+
bi.biWidth = img->width;
80+
bi.biHeight = img->height;
81+
bi.biPlanes = 1;
82+
bi.biBitCount = 24;
83+
bi.biCompression = 0;
84+
bi.biSizeImage = image_size;
85+
bi.biXPelsPerMeter = 0;
86+
bi.biYPelsPerMeter = 0;
87+
bi.biClrUsed = 0;
88+
bi.biClrImportant = 0;
89+
90+
if (fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr) != 1 || fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr) != 1) {
91+
fclose(outptr);
92+
return 1;
93+
}
94+
95+
for (int i = 0; i < img->height; i++) {
96+
if (fwrite(img->pixels[i], sizeof(RGBTRIPLE), img->width, outptr) != (size_t)img->width) {
97+
fclose(outptr);
98+
return 1;
99+
}
100+
for (int k = 0; k < padding; k++) {
101+
fputc(0x00, outptr);
102+
}
103+
}
104+
fclose(outptr);
105+
return 0;
106+
}
107+

ex2.png

205 KB
Loading

0 commit comments

Comments
 (0)