Skip to content

Commit ac08fb0

Browse files
committed
feat: png,jpeg file support
1 parent 83ea8ea commit ac08fb0

File tree

11 files changed

+624
-92
lines changed

11 files changed

+624
-92
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

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

filter.c

Lines changed: 60 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -3,99 +3,84 @@
33
#include <stdlib.h>
44

55
#include "helpers.h"
6+
#include "image_io.h"
67

78
int main(int argc, char *argv[])
89
{
910
// Define allowable filters
1011
char *filters = "bgrsivtdGoB:";
1112

12-
13-
char filterArr[argc-3];
13+
// Allocate filter array
14+
char *filterArr = (char *)malloc((argc - 2) * sizeof(char));
15+
if (!filterArr) {
16+
printf("Memory allocation error.\n");
17+
return 1;
18+
}
1419
int filterCount = 0;
20+
int brightness_value = 0;
1521

1622
// gets all filter flags and checks validity
1723
int opt;
1824
while ((opt = getopt(argc, argv, filters)) != -1) {
1925
if (opt == '?') {
2026
printf("Invalid filter option\n");
27+
free(filterArr);
2128
return 1;
2229
}
23-
filterArr[filterCount++] = opt;
30+
if (opt == 'B') {
31+
if (optarg) {
32+
brightness_value = atoi(optarg);
33+
} else {
34+
printf("Brightness filter requires a value. Usage: -B <value>\n");
35+
free(filterArr);
36+
return 1;
37+
}
38+
filterArr[filterCount++] = opt;
39+
} else {
40+
filterArr[filterCount++] = opt;
41+
}
2442
}
2543

2644

2745
// Ensure proper usage
2846
if (argc < optind + 2)
2947
{
3048
printf("Usage: ./filter [flag] infile outfile\n");
49+
printf("Filters: -g (grayscale), -s (sepia), -r (reflect), -b (blur), -i (invert), -v (vignette), -G (glow), -t (threshold), -d (edge detection), -o (oil paint), -B <value> (brightness)\n");
50+
free(filterArr);
3151
return 3;
3252
}
3353

3454
// Remember filenames
3555
char *infile = argv[optind];
3656
char *outfile = argv[optind + 1];
3757

38-
// Open input file
39-
FILE *inptr = fopen(infile, "rb");
40-
if (inptr == NULL)
41-
{
42-
printf("Could not open %s.\n", infile);
58+
// Read image using new I/O system
59+
ImageData img;
60+
img.pixels = NULL;
61+
img.width = 0;
62+
img.height = 0;
63+
img.format = IMAGE_FORMAT_UNKNOWN;
64+
65+
if (read_image(infile, &img) != 0) {
66+
printf("Could not read %s. Unsupported file format or file not found.\n", infile);
67+
printf("Supported formats: BMP, PNG, JPEG\n");
4368
return 4;
4469
}
4570

46-
// Open output file
47-
FILE *outptr = fopen(outfile, "wb");
48-
if (outptr == NULL)
49-
{
50-
fclose(inptr);
51-
printf("Could not create %s.\n", outfile);
52-
return 5;
53-
}
54-
55-
// Read infile's BITMAPFILEHEADER
56-
BITMAPFILEHEADER bf;
57-
fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr);
58-
59-
// Read infile's BITMAPINFOHEADER
60-
BITMAPINFOHEADER bi;
61-
fread(&bi, sizeof(BITMAPINFOHEADER), 1, inptr);
62-
63-
// Ensure infile is (likely) a 24-bit uncompressed BMP 4.0
64-
if (bf.bfType != 0x4d42 || bf.bfOffBits != 54 || bi.biSize != 40 ||
65-
bi.biBitCount != 24 || bi.biCompression != 0)
66-
{
67-
fclose(outptr);
68-
fclose(inptr);
69-
printf("Unsupported file format.\n");
70-
return 6;
71-
}
72-
73-
// Get image's dimensions
74-
int height = abs(bi.biHeight);
75-
int width = bi.biWidth;
76-
77-
// Allocate memory for image
78-
RGBTRIPLE(*image)[width] = calloc(height, width * sizeof(RGBTRIPLE));
79-
if (image == NULL)
80-
{
81-
printf("Not enough memory to store image.\n");
82-
fclose(outptr);
83-
fclose(inptr);
84-
return 7;
71+
// Validate image was read correctly
72+
if (img.pixels == NULL || img.width <= 0 || img.height <= 0 || img.pixels[0] == NULL) {
73+
printf("Error: Invalid image data after reading.\n");
74+
free_image(&img);
75+
return 4;
8576
}
8677

87-
// Determine padding for scanlines
88-
int padding = (4 - (width * sizeof(RGBTRIPLE)) % 4) % 4;
89-
90-
// Iterate over infile's scanlines
91-
for (int i = 0; i < height; i++)
92-
{
93-
// Read row into pixel array
94-
fread(image[i], sizeof(RGBTRIPLE), width, inptr);
78+
int height = img.height;
79+
int width = img.width;
80+
81+
// Cast pixels to match filter function
9582

96-
// Skip over padding
97-
fseek(inptr, padding, SEEK_CUR);
98-
}
83+
RGBTRIPLE(*image)[width] = (RGBTRIPLE(*)[width])img.pixels[0];
9984

10085
// Filter image
10186
for(int i=0; i<filterCount; i++){
@@ -152,37 +137,29 @@ int main(int argc, char *argv[])
152137

153138
default:
154139
printf("Unknown filter: %c\n", filterArr[i]);
155-
free(image);
156-
fclose(inptr);
157-
fclose(outptr);
140+
free_image(&img);
141+
free(filterArr);
158142
return 7;
159143

160144
}
161145
}
162-
// Write outfile's BITMAPFILEHEADER
163-
fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr);
164-
165-
// Write outfile's BITMAPINFOHEADER
166-
fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr);
167-
168-
// Write new pixels to outfile
169-
for (int i = 0; i < height; i++)
170-
{
171-
// Write row to outfile
172-
fwrite(image[i], sizeof(RGBTRIPLE), width, outptr);
173-
174-
// Write padding at end of row
175-
for (int k = 0; k < padding; k++)
176-
{
177-
fputc(0x00, outptr);
178-
}
146+
147+
// Free filter array
148+
free(filterArr);
149+
150+
// Write image using I/O system
151+
ImageFormat output_format = get_format_from_extension(outfile);
152+
if (output_format == IMAGE_FORMAT_UNKNOWN) {
153+
output_format = img.format;
154+
}
155+
156+
if (write_image(outfile, &img, output_format) != 0) {
157+
printf("Could not write %s.\n", outfile);
158+
free_image(&img);
159+
return 5;
179160
}
180161

181162
// Free memory for image
182-
free(image);
183-
184-
// Close files
185-
fclose(inptr);
186-
fclose(outptr);
163+
free_image(&img);
187164
return 0;
188165
}

filter.exe

112 KB
Binary file not shown.

0 commit comments

Comments
 (0)