summaryrefslogtreecommitdiff
path: root/wk4/pset
diff options
context:
space:
mode:
authorFudgerboy <91767657+Fudgerboy@users.noreply.github.com>2024-04-04 06:44:49 +0000
committerFudgerboy <91767657+Fudgerboy@users.noreply.github.com>2024-04-04 06:44:49 +0000
commitab3fca1ae25c2ea2a95a8d93a1fc3e8bef0d0e69 (patch)
tree1e4beeb0d8163871786b0c5d2879f3f5f6e65cb9 /wk4/pset
parent1295585ad4f11c58deeba8888678ccabc40bc695 (diff)
Wed, Apr 3, 2024, 11:44 PM -07:00
Diffstat (limited to 'wk4/pset')
-rw-r--r--wk4/pset/filter-less/Makefile2
-rw-r--r--wk4/pset/filter-less/bmp.h57
-rw-r--r--wk4/pset/filter-less/filter.c150
-rw-r--r--wk4/pset/filter-less/helpers.c114
-rw-r--r--wk4/pset/filter-less/helpers.h13
-rw-r--r--wk4/pset/volume/volume.c53
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);
+}