|
3 | 3 | #include <stdlib.h> |
4 | 4 |
|
5 | 5 | #include "helpers.h" |
| 6 | +#include "image_io.h" |
6 | 7 |
|
7 | 8 | int main(int argc, char *argv[]) |
8 | 9 | { |
9 | 10 | // Define allowable filters |
10 | 11 | char *filters = "bgrsivtdGoB:"; |
11 | 12 |
|
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 | + } |
14 | 19 | int filterCount = 0; |
| 20 | + int brightness_value = 0; |
15 | 21 |
|
16 | 22 | // gets all filter flags and checks validity |
17 | 23 | int opt; |
18 | 24 | while ((opt = getopt(argc, argv, filters)) != -1) { |
19 | 25 | if (opt == '?') { |
20 | 26 | printf("Invalid filter option\n"); |
| 27 | + free(filterArr); |
21 | 28 | return 1; |
22 | 29 | } |
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 | + } |
24 | 42 | } |
25 | 43 |
|
26 | 44 |
|
27 | 45 | // Ensure proper usage |
28 | 46 | if (argc < optind + 2) |
29 | 47 | { |
30 | 48 | 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); |
31 | 51 | return 3; |
32 | 52 | } |
33 | 53 |
|
34 | 54 | // Remember filenames |
35 | 55 | char *infile = argv[optind]; |
36 | 56 | char *outfile = argv[optind + 1]; |
37 | 57 |
|
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"); |
43 | 68 | return 4; |
44 | 69 | } |
45 | 70 |
|
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; |
85 | 76 | } |
86 | 77 |
|
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 |
95 | 82 |
|
96 | | - // Skip over padding |
97 | | - fseek(inptr, padding, SEEK_CUR); |
98 | | - } |
| 83 | + RGBTRIPLE(*image)[width] = (RGBTRIPLE(*)[width])img.pixels[0]; |
99 | 84 |
|
100 | 85 | // Filter image |
101 | 86 | for(int i=0; i<filterCount; i++){ |
@@ -152,37 +137,29 @@ int main(int argc, char *argv[]) |
152 | 137 |
|
153 | 138 | default: |
154 | 139 | printf("Unknown filter: %c\n", filterArr[i]); |
155 | | - free(image); |
156 | | - fclose(inptr); |
157 | | - fclose(outptr); |
| 140 | + free_image(&img); |
| 141 | + free(filterArr); |
158 | 142 | return 7; |
159 | 143 |
|
160 | 144 | } |
161 | 145 | } |
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; |
179 | 160 | } |
180 | 161 |
|
181 | 162 | // Free memory for image |
182 | | - free(image); |
183 | | - |
184 | | - // Close files |
185 | | - fclose(inptr); |
186 | | - fclose(outptr); |
| 163 | + free_image(&img); |
187 | 164 | return 0; |
188 | 165 | } |
0 commit comments