diff options
Diffstat (limited to 'wk4/pset')
-rw-r--r-- | wk4/pset/filter-less/Makefile | 2 | ||||
-rw-r--r-- | wk4/pset/filter-less/bmp.h | 57 | ||||
-rw-r--r-- | wk4/pset/filter-less/filter.c | 150 | ||||
-rw-r--r-- | wk4/pset/filter-less/helpers.c | 114 | ||||
-rw-r--r-- | wk4/pset/filter-less/helpers.h | 13 | ||||
-rw-r--r-- | wk4/pset/volume/volume.c | 53 |
6 files changed, 389 insertions, 0 deletions
diff --git a/wk4/pset/filter-less/Makefile b/wk4/pset/filter-less/Makefile new file mode 100644 index 0000000..5f6c8e4 --- /dev/null +++ b/wk4/pset/filter-less/Makefile @@ -0,0 +1,2 @@ +filter: + clang -ggdb3 -gdwarf-4 -O0 -Qunused-arguments -std=c11 -Wall -Werror -Wextra -Wno-gnu-folding-constant -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wshadow -lm -o filter filter.c helpers.c diff --git a/wk4/pset/filter-less/bmp.h b/wk4/pset/filter-less/bmp.h new file mode 100644 index 0000000..c213029 --- /dev/null +++ b/wk4/pset/filter-less/bmp.h @@ -0,0 +1,57 @@ +// BMP-related data types based on Microsoft's own + +#include <stdint.h> + +// These data types are essentially aliases for C/C++ primitive data types. +// Adapted from http://msdn.microsoft.com/en-us/library/cc230309.aspx. +// See https://en.wikipedia.org/wiki/C_data_types#stdint.h for more on stdint.h. + +typedef uint8_t BYTE; +typedef uint32_t DWORD; +typedef int32_t LONG; +typedef uint16_t WORD; + +// 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; + +// 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; + +// The RGBTRIPLE 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;
\ No newline at end of file diff --git a/wk4/pset/filter-less/filter.c b/wk4/pset/filter-less/filter.c new file mode 100644 index 0000000..3b04023 --- /dev/null +++ b/wk4/pset/filter-less/filter.c @@ -0,0 +1,150 @@ +#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; +} diff --git a/wk4/pset/filter-less/helpers.c b/wk4/pset/filter-less/helpers.c new file mode 100644 index 0000000..7db229f --- /dev/null +++ b/wk4/pset/filter-less/helpers.c @@ -0,0 +1,114 @@ +#include "helpers.h" +#include <math.h> + +// Convert image to grayscale +void grayscale(int height, int width, RGBTRIPLE image[height][width]) +{ + for (int i = 0; i < height; i++) + { + for (int j = 0; j < width; j++) + { + int gray = + round((image[i][j].rgbtRed + image[i][j].rgbtBlue + image[i][j].rgbtGreen) / 3.0); + image[i][j].rgbtRed = gray; + image[i][j].rgbtBlue = gray; + image[i][j].rgbtGreen = gray; + } + } + return; +} + +// Convert image to sepia +void sepia(int height, int width, RGBTRIPLE image[height][width]) +{ + for (int i = 0; i < height; i++) + { + for (int j = 0; j < width; j++) + { + int sepiaRed = round(.393 * image[i][j].rgbtRed + .769 * image[i][j].rgbtGreen + + .189 * image[i][j].rgbtBlue); + if (sepiaRed > 255) + { + sepiaRed = 255; + } + int sepiaBlue = round(.272 * image[i][j].rgbtRed + .534 * image[i][j].rgbtGreen + + .131 * image[i][j].rgbtBlue); + if (sepiaBlue > 255) + { + sepiaBlue = 255; + } + int sepiaGreen = round(.349 * image[i][j].rgbtRed + .686 * image[i][j].rgbtGreen + + .168 * image[i][j].rgbtBlue); + if (sepiaGreen > 255) + { + sepiaGreen = 255; + } + image[i][j].rgbtRed = sepiaRed; + image[i][j].rgbtBlue = sepiaBlue; + image[i][j].rgbtGreen = sepiaGreen; + } + } + return; +} + +// Reflect image horizontally +void reflect(int height, int width, RGBTRIPLE image[height][width]) +{ + for (int i = 0; i < height; i++) + { + for (int j = 0; j < floor(width / 2); j++) + { + RGBTRIPLE temp = image[i][j]; + image[i][j] = image[i][width - j - 1]; + image[i][width - j - 1] = temp; + } + } + return; +} + +// Blur image +void blur(int height, int width, RGBTRIPLE image[height][width]) +{ + RGBTRIPLE copy[height][width]; + for (int i = 0; i < height; i++) + { + for (int j = 0; j < width; j++) + { + copy[i][j] = image[i][j]; + } + } + + for (int i = 0; i < height; i++) + { + for (int j = 0; j < width; j++) + { + int red = 0; + int blue = 0; + int green = 0; + float count = 0.0; + for (int k = i - 1; k <= i + 1; k++) + { + if (k >= 0 && k < height) + { + for (int l = j - 1; l <= j + 1; l++) + { + if (l >= 0 && l < width) + { + red += copy[k][l].rgbtRed; + blue += copy[k][l].rgbtBlue; + green += copy[k][l].rgbtGreen; + count++; + } + } + } + } + if (count > 0) + { + image[i][j].rgbtRed = round(red / count); + image[i][j].rgbtBlue = round(blue / count); + image[i][j].rgbtGreen = round(green / count); + } + } + } + return; +} diff --git a/wk4/pset/filter-less/helpers.h b/wk4/pset/filter-less/helpers.h new file mode 100644 index 0000000..412da8c --- /dev/null +++ b/wk4/pset/filter-less/helpers.h @@ -0,0 +1,13 @@ +#include "bmp.h" + +// Convert image to grayscale +void grayscale(int height, int width, RGBTRIPLE image[height][width]); + +// Convert image to sepia +void sepia(int height, int width, RGBTRIPLE image[height][width]); + +// Reflect image horizontally +void reflect(int height, int width, RGBTRIPLE image[height][width]); + +// Blur image +void blur(int height, int width, RGBTRIPLE image[height][width]); diff --git a/wk4/pset/volume/volume.c b/wk4/pset/volume/volume.c new file mode 100644 index 0000000..0cde962 --- /dev/null +++ b/wk4/pset/volume/volume.c @@ -0,0 +1,53 @@ +// Modifies the volume of an audio file + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +// Number of bytes in .wav header +const int HEADER_SIZE = 44; + +int main(int argc, char *argv[]) +{ + // Check command-line arguments + if (argc != 4) + { + printf("Usage: ./volume input.wav output.wav factor\n"); + return 1; + } + + // Open files and determine scaling factor + FILE *input = fopen(argv[1], "r"); + if (input == NULL) + { + printf("Could not open file.\n"); + return 1; + } + + FILE *output = fopen(argv[2], "w"); + if (output == NULL) + { + printf("Could not open file.\n"); + return 1; + } + + float factor = atof(argv[3]); + + // TODO: Copy header from input file to output file + uint8_t header[HEADER_SIZE]; + fread(header, HEADER_SIZE, 1, input); + fwrite(header, HEADER_SIZE, 1, output); + + // TODO: Read samples from input file and write updated data to output file + int16_t buffer; + + while (fread(&buffer, sizeof(int16_t), 1, input)) + { + buffer *= factor; + fwrite(&buffer, sizeof(uint16_t), 1, output); + } + + // Close files + fclose(input); + fclose(output); +} |