Skip to content

Commit 963504b

Browse files
feat: add filter.c for reading and writing bmp images
1 parent 0d07681 commit 963504b

File tree

1 file changed

+150
-0
lines changed

1 file changed

+150
-0
lines changed

filter.c

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
#include <getopt.h>
2+
#include <stdio.h>
3+
#include <stdlib.h>
4+
5+
#include "helpers.h"
6+
7+
int main(int argc, char *argv[])
8+
{
9+
// Define allowable filters
10+
char *filters = "bgrs";
11+
12+
// Get filter flag and check validity
13+
char filter = getopt(argc, argv, filters);
14+
if (filter == '?')
15+
{
16+
printf("Invalid filter.\n");
17+
return 1;
18+
}
19+
20+
// Ensure only one filter
21+
if (getopt(argc, argv, filters) != -1)
22+
{
23+
printf("Only one filter allowed.\n");
24+
return 2;
25+
}
26+
27+
// Ensure proper usage
28+
if (argc != optind + 2)
29+
{
30+
printf("Usage: ./filter [flag] infile outfile\n");
31+
return 3;
32+
}
33+
34+
// Remember filenames
35+
char *infile = argv[optind];
36+
char *outfile = argv[optind + 1];
37+
38+
// Open input file
39+
FILE *inptr = fopen(infile, "rb");
40+
if (inptr == NULL)
41+
{
42+
printf("Could not open %s.\n", infile);
43+
return 4;
44+
}
45+
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;
85+
}
86+
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);
95+
96+
// Skip over padding
97+
fseek(inptr, padding, SEEK_CUR);
98+
}
99+
100+
// Filter image
101+
switch (filter)
102+
{
103+
// Blur
104+
case 'b':
105+
blur(height, width, image);
106+
break;
107+
108+
// Grayscale
109+
case 'g':
110+
grayscale(height, width, image);
111+
break;
112+
113+
// Reflection
114+
case 'r':
115+
reflect(height, width, image);
116+
break;
117+
118+
// Sepia
119+
case 's':
120+
sepia(height, width, image);
121+
break;
122+
}
123+
124+
// Write outfile's BITMAPFILEHEADER
125+
fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr);
126+
127+
// Write outfile's BITMAPINFOHEADER
128+
fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr);
129+
130+
// Write new pixels to outfile
131+
for (int i = 0; i < height; i++)
132+
{
133+
// Write row to outfile
134+
fwrite(image[i], sizeof(RGBTRIPLE), width, outptr);
135+
136+
// Write padding at end of row
137+
for (int k = 0; k < padding; k++)
138+
{
139+
fputc(0x00, outptr);
140+
}
141+
}
142+
143+
// Free memory for image
144+
free(image);
145+
146+
// Close files
147+
fclose(inptr);
148+
fclose(outptr);
149+
return 0;
150+
}

0 commit comments

Comments
 (0)