Created
August 23, 2022 07:29
-
-
Save florestankorp/171cf3152b466bc423af090a2342a503 to your computer and use it in GitHub Desktop.
Part of Harvard's CS50X Course: pset4 Filter - Apply operations to a BMP file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <getopt.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include "helpers.h" | |
int main(int argc, char *argv[]) | |
{ | |
// Define allowable filters | |
char *filters = "bgrs"; | |
// Get filter flag and check validity | |
char filter = getopt(argc, argv, filters); | |
if (filter == '?') | |
{ | |
printf("Invalid filter.\n"); | |
return 1; | |
} | |
// Ensure only one filter | |
if (getopt(argc, argv, filters) != -1) | |
{ | |
printf("Only one filter allowed.\n"); | |
return 2; | |
} | |
// Ensure proper usage | |
if (argc != optind + 2) | |
{ | |
printf("Usage: ./filter [flag] infile outfile\n"); | |
return 3; | |
} | |
// Remember filenames | |
char *infile = argv[optind]; | |
char *outfile = argv[optind + 1]; | |
// Open input file | |
FILE *inptr = fopen(infile, "r"); | |
if (inptr == NULL) | |
{ | |
printf("Could not open %s.\n", infile); | |
return 4; | |
} | |
// Open output file | |
FILE *outptr = fopen(outfile, "w"); | |
if (outptr == NULL) | |
{ | |
fclose(inptr); | |
printf("Could not create %s.\n", outfile); | |
return 5; | |
} | |
// Read infile's BITMAPFILEHEADER | |
BITMAPFILEHEADER bf; | |
fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr); | |
// Read infile's BITMAPINFOHEADER | |
BITMAPINFOHEADER bi; | |
fread(&bi, sizeof(BITMAPINFOHEADER), 1, inptr); | |
// Ensure infile is (likely) a 24-bit uncompressed BMP 4.0 | |
if (bf.bfType != 0x4d42 || bf.bfOffBits != 54 || bi.biSize != 40 || | |
bi.biBitCount != 24 || bi.biCompression != 0) | |
{ | |
fclose(outptr); | |
fclose(inptr); | |
printf("Unsupported file format.\n"); | |
return 6; | |
} | |
// Get image's dimensions | |
int height = abs(bi.biHeight); | |
int width = bi.biWidth; | |
// Allocate memory for image | |
RGBTRIPLE(*image) | |
[width] = calloc(height, width * sizeof(RGBTRIPLE)); | |
if (image == NULL) | |
{ | |
printf("Not enough memory to store image.\n"); | |
fclose(outptr); | |
fclose(inptr); | |
return 7; | |
} | |
// Determine padding for scanlines | |
int padding = (4 - (width * sizeof(RGBTRIPLE)) % 4) % 4; | |
// Iterate over infile's scanlines | |
for (int i = 0; i < height; i++) | |
{ | |
// Read row into pixel array | |
fread(image[i], sizeof(RGBTRIPLE), width, inptr); | |
// Skip over padding | |
fseek(inptr, padding, SEEK_CUR); | |
} | |
// Filter image | |
switch (filter) | |
{ | |
// Blur | |
case 'b': | |
blur(height, width, image); | |
break; | |
// Grayscale | |
case 'g': | |
grayscale(height, width, image); | |
break; | |
// Reflection | |
case 'r': | |
reflect(height, width, image); | |
break; | |
// Sepia | |
case 's': | |
sepia(height, width, image); | |
break; | |
} | |
// Write outfile's BITMAPFILEHEADER | |
fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr); | |
// Write outfile's BITMAPINFOHEADER | |
fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr); | |
// Write new pixels to outfile | |
for (int i = 0; i < height; i++) | |
{ | |
// Write row to outfile | |
fwrite(image[i], sizeof(RGBTRIPLE), width, outptr); | |
// Write padding at end of row | |
for (int k = 0; k < padding; k++) | |
{ | |
fputc(0x00, outptr); | |
} | |
} | |
// Free memory for image | |
free(image); | |
// Close files | |
fclose(inptr); | |
fclose(outptr); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment