pset 4
filter
Implement a program that applies filters to BMPs, per the below.
$ ./filter -r image.bmp reflected.bmpFiltering options:
-g= grayscale-r= reflect-b= blur-e= edges
Directoryimages
- courtyard.bmp
- stadium.bmp
- tower.bmp
- yard.bmp
- bmp.h
- filter
- filter.c
- helpers.c
- helpers.h
- Makefile
- out.bmp
// BMP-related data types based on Microsoft's own
#include <stdint.h>
/** * Common Data Types * * The data types in this section are essentially aliases for C/C++ * primitive data types. * * Adapted from http://msdn.microsoft.com/en-us/library/cc230309.aspx. * See http://en.wikipedia.org/wiki/Stdint.h for more on stdint.h. */typedef uint8_t BYTE;typedef uint32_t DWORD;typedef int32_t LONG;typedef uint16_t WORD;
/** * BITMAPFILEHEADER * * The BITMAPFILEHEADER structure contains information about the type, size, * and layout of a file that contains a DIB [device-independent bitmap]. * * Adapted from http://msdn.microsoft.com/en-us/library/dd183374(VS.85).aspx. */typedef struct{ WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits;} __attribute__((__packed__))BITMAPFILEHEADER;
/** * BITMAPINFOHEADER * * The BITMAPINFOHEADER structure contains information about the * dimensions and color format of a DIB [device-independent bitmap]. * * Adapted from http://msdn.microsoft.com/en-us/library/dd183376(VS.85).aspx. */typedef struct{ DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant;} __attribute__((__packed__))BITMAPINFOHEADER;
/** * RGBTRIPLE * * This structure describes a color consisting of relative intensities of * red, green, and blue. * * Adapted from http://msdn.microsoft.com/en-us/library/aa922590.aspx. */typedef struct{ BYTE rgbtBlue; BYTE rgbtGreen; BYTE rgbtRed;} __attribute__((__packed__))RGBTRIPLE;#include <getopt.h>#include <stdio.h>#include <stdlib.h>
#include "helpers.h"
int main(int argc, char *argv[]){
// Define allowable filters char *filters = "begr";
// Get filter flag and check validity char filter = getopt(argc, argv, filters); if (filter == '?') { fprintf(stderr, "Invalid filter.\n"); return 1; }
// Ensure only one filter if (getopt(argc, argv, filters) != -1) { fprintf(stderr, "Only one filter allowed.\n"); return 2; }
// Ensure proper usage if (argc != optind + 2) { fprintf(stderr, "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) { fprintf(stderr, "Could not open %s.\n", infile); return 4; }
// Open output file FILE *outptr = fopen(outfile, "w"); if (outptr == NULL) { fclose(inptr); fprintf(stderr, "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); fprintf(stderr, "Unsupported file format.\n"); return 6; }
int height = abs(bi.biHeight); int width = bi.biWidth;
// Allocate memory for image RGBTRIPLE(*image)[width] = calloc(height, width * sizeof(RGBTRIPLE)); if (image == NULL) { fprintf(stderr, "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;
// Edges case 'e': edges(height, width, image); break;
// Grayscale case 'g': grayscale(height, width, image); break;
// Reflect case 'r': reflect(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 infile fclose(inptr);
// Close outfile fclose(outptr);
return 0;}#include "helpers.h"#include <math.h>#include <stdio.h>#include <stdlib.h>
// Convert image to grayscalevoid grayscale(int height, int width, RGBTRIPLE image[height][width]){ float avg; int val; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { avg = (float)(image[i][j].rgbtBlue + image[i][j].rgbtGreen + image[i][j].rgbtRed) / 3.0; val = round(avg); image[i][j].rgbtBlue = image[i][j].rgbtGreen = image[i][j].rgbtRed = val; } }
return;}
// Reflect image horizontallyvoid reflect(int height, int width, RGBTRIPLE image[height][width]){ RGBTRIPLE temp; for (int i = 0; i < height; i++) { for (int j = 0, k = width - 1; j < width / 2; j++, k--) { temp = image[i][j]; image[i][j] = image[i][k]; image[i][k] = temp; } }
return;}
// Blur imagevoid blur(int height, int width, RGBTRIPLE image[height][width]){ RGBTRIPLE blurred[height][width]; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { int cnt = 0; int sumRed = 0; int sumBlue = 0; int sumGreen = 0; for (int k = i - 1; k <= i + 1; k++) { for (int l = j - 1; l <= j + 1; l++) { if ((k >= 0) && (k < height) && (l >= 0) && (l < width)) { sumBlue += image[k][l].rgbtBlue; sumGreen += image[k][l].rgbtGreen; sumRed += image[k][l].rgbtRed; cnt++; } } }
float avgBlue = sumBlue / (float) cnt; float avgGreen = sumGreen / (float) cnt; float avgRed = sumRed / (float) cnt;
blurred[i][j].rgbtBlue = round(avgBlue); blurred[i][j].rgbtGreen = round(avgGreen); blurred[i][j].rgbtRed = round(avgRed); } }
//copy blurred image to the original for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { image[i][j] = blurred[i][j]; } }
return;}
// Detect edgesvoid edges(int height, int width, RGBTRIPLE image[height][width]){ int Gxk[3][3] = {{-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1}}; int Gyk[3][3] = {{-1, -2, -1}, {0, 0, 0}, {1, 2, 1}}; RGBTRIPLE(*edged)[width] = calloc(height, width * sizeof(RGBTRIPLE));
for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { int GxRed = 0, GyRed = 0, GxGreen = 0, GyGreen = 0, GxBlue = 0, GyBlue = 0;
for (int k = i - 1; k <= i + 1; k++) { for (int l = j - 1; l <= j + 1; l++) { if ((k >= 0) && (k < height) && (l >= 0) && (l < width)) { GxRed += (image[k][l].rgbtRed * Gxk[k - i + 1][l - j + 1]); GyRed += (image[k][l].rgbtRed * Gyk[k - i + 1][l - j + 1]); GxGreen += (image[k][l].rgbtGreen * Gxk[k - i + 1][l - j + 1]); GyGreen += (image[k][l].rgbtGreen * Gyk[k - i + 1][l - j + 1]); GxBlue += (image[k][l].rgbtBlue * Gxk[k - i + 1][l - j + 1]); GyBlue += (image[k][l].rgbtBlue * Gyk[k - i + 1][l - j + 1]); } } }
// combine the directional values double Red = sqrt((double)(GxRed * GxRed + GyRed * GyRed)); double Blue = sqrt((double)(GxBlue * GxBlue + GyBlue * GyBlue)); double Green = sqrt((double)(GxGreen * GxGreen + GyGreen * GyGreen));
// cap the values at 255 Red = (Red > 255) ? 255 : Red; Green = (Green > 255) ? 255 : Green; Blue = (Blue > 255) ? 255 : Blue;
// round the values and save it edged[i][j].rgbtRed = round(Red); edged[i][j].rgbtGreen = round(Green); edged[i][j].rgbtBlue = round(Blue); } }
// copy edged image to the original for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { image[i][j] = edged[i][j]; } }
free(edged);
return;}#include "bmp.h"
// Convert image to grayscalevoid grayscale(int height, int width, RGBTRIPLE image[height][width]);
// Reflect image horizontallyvoid reflect(int height, int width, RGBTRIPLE image[height][width]);
// Detect edgesvoid edges(int height, int width, RGBTRIPLE image[height][width]);
// Blur imagevoid blur(int height, int width, RGBTRIPLE image[height][width]);// Makefilefilter: clang -fsanitize=signed-integer-overflow -fsanitize=undefined -ggdb3 -O0 -Qunused-arguments -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow -o filter filter.c helpers.crecover
Implement a program that recovers JPEGs from a forensic image, per the below.
$ ./recover card.raw- card.raw
- recovered-images
- recover.c
#include <stdio.h>#include <stdlib.h>#include <stdint.h>#include <stdbool.h>
typedef uint8_t BYTE;
int main(int argc, char *argv[]){ // Ensure proper use if (argc != 2) { printf("Usage: ./recover image\n"); return 1; }
// Save the filename char *infile = argv[1];
// Open input file FILE *inptr = fopen(infile, "r"); if (inptr == NULL) { fclose(inptr); fprintf(stderr, "Could not open %s\n", infile); return 1; }
// Recovery BYTE *buffer = malloc(512 * sizeof(BYTE)); char *imgname = malloc(10 * sizeof(char)); bool firstFound = false, running = false;
int imgnameCnt = 0; sprintf(imgname, "%03i.jpg", imgnameCnt); FILE *img = fopen(imgname, "w");
while (fread(buffer, 512 * sizeof(BYTE), 1, inptr) == 1) { if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff && (buffer[3] & 0xf0) == 0xe0) { if (firstFound == false) { firstFound = true; fwrite(buffer, 512 * sizeof(BYTE), 1, img); running = true; } else { fclose(img); running = false; sprintf(imgname, "%03i.jpg", ++imgnameCnt); img = fopen(imgname, "w"); fwrite(buffer, 512 * sizeof(BYTE), 1, img); running = true; } } else { if (running == true) { fwrite(buffer, 512 * sizeof(BYTE), 1, img); } } }
fclose(img); fclose(inptr); free(buffer); free(imgname);
}