Created
December 31, 2020 23:16
-
-
Save Edmundworks/a5b37d38654bb18a6306c861db900410 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
// Resizes a BMP file | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <ctype.h> | |
#include "bmp.h" | |
// Use debug50 if confused | |
// check with check50 | |
// look at style with style50 | |
int main(int argc, char *argv[]) | |
{ | |
// ensure proper usage | |
if (argc != 4) | |
{ | |
fprintf(stderr, "Usage: size-factor infile outfile\n"); | |
return 1; | |
} | |
// Create size factor from input | |
// Note - have changed the below from int n and atoi to double n and atof | |
double n_double = atof(argv[1]); | |
// Check n is greater than 1 and less than 100 | |
if (n_double < 0 || n_double > 100) | |
{ | |
fprintf(stderr, "Usage: n needs to be positive number less than 100\n"); | |
return 1; | |
} | |
// Save n | |
double n_save = n_double; | |
// Separate the integer part of n | |
int int_n = n_double; | |
// Separate the remainder part of n | |
double n_remain = n_double - int_n; | |
// Declare n and the special nx for use for floats less than 1 | |
int n = 0; | |
double nx = 0; | |
// new triage | |
// floats between 0.5 and 0.999... are rounded up to one | |
// Idea - could increase this limit to 0.75, so 0.5 is still considered 0.5! | |
// floats between 0 and 0.5 are rounded to 0.5 | |
// numbers 2.01 to 2.49 are rounded down to 2 | |
// numbers like 2.5 to 2.99 are rounded up to 3 | |
// for numbers between 0 and 1 | |
if (int_n == 0) | |
{ | |
// if over 0.5, round to 1 | |
if (n_remain > 0.5) | |
{ | |
n = 1; | |
} | |
// if 0.5 or less, round to 0.5 | |
else if (n_remain <= 0.5) | |
{ | |
nx = 0.5; | |
} | |
} | |
// if remainder is between 0 and 0.5, round down to whole number | |
else if (n_remain > 0 && n_remain < 0.5) | |
{ | |
n = int_n; | |
} | |
// if remainder is equal to or over 0.5 round up to whole number | |
else if (n_remain >= 0.5) | |
{ | |
n = int_n + 1; | |
} | |
// if no remainder, set n as whole number | |
else if (n_remain == 0) | |
{ | |
n = int_n; | |
} | |
// remember filenames | |
char *infile = argv[2]; | |
char *outfile = argv[3]; | |
// open input file | |
FILE *inptr = fopen(infile, "r"); | |
if (inptr == NULL) | |
{ | |
fprintf(stderr, "Could not open %s.\n", infile); | |
return 2; | |
} | |
// open output file | |
FILE *outptr = fopen(outfile, "w"); | |
if (outptr == NULL) | |
{ | |
fclose(inptr); | |
fprintf(stderr, "Could not create %s.\n", outfile); | |
return 3; | |
} | |
// 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 4; | |
} | |
// Save width and height (height saved as positive number) | |
int width_save = bi.biWidth; | |
int height_save = abs(bi.biHeight); | |
int sizeimage_save = bi.biSizeImage; | |
int size_save = bf.bfSize; | |
// Padding save | |
int padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4; | |
int padding_save = padding; | |
// Triage point | |
if (nx == 0) | |
{ | |
// Change width and height based on n | |
bi.biWidth = bi.biWidth * n; | |
bi.biHeight = bi.biHeight * n; | |
// Adjust new padding using new bi.biWidth | |
padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4; | |
// Create new Size Image and size | |
bi.biSizeImage = ((sizeof(RGBTRIPLE) * bi.biWidth) + padding) * abs(bi.biHeight); | |
bf.bfSize = bi.biSizeImage + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); | |
// write outfile's BITMAPFILEHEADER | |
fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr); | |
// write outfile's BITMAPINFOHEADER | |
fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr); | |
// iterate over infile's scanlines | |
// Change the limit in this condition from new height to height save | |
for (int i = 0; i < height_save; i++) | |
{ | |
// iterate over pixels in scanline | |
// Use width_save as the limit rather than bi.biWidth | |
int loop_limit = n - 1; | |
for (int x = 0; x < loop_limit; x++) | |
{ | |
for (int j = 0; j < width_save; j++) | |
{ | |
// temporary storage | |
RGBTRIPLE triple; | |
// read RGB triple from infile | |
fread(&triple, sizeof(RGBTRIPLE), 1, inptr); | |
// write RGB triple to outfile | |
for (int l = 0; l < n; l++) | |
{ | |
fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr); | |
} | |
} | |
// Insert end of line padding | |
for (int k = 0; k < padding; k++) | |
{ | |
fputc(0x00, outptr); | |
} | |
// Create offset, old width in pixels converted to bytes | |
int offset = -3 * width_save; | |
// Move cursor | |
fseek(inptr, offset, SEEK_CUR); | |
} | |
for (int j = 0; j < width_save; j++) | |
{ | |
// temporary storage | |
RGBTRIPLE triple; | |
// read RGB triple from infile | |
fread(&triple, sizeof(RGBTRIPLE), 1, inptr); | |
// write RGB triple to outfile | |
for (int l = 0; l < n; l++) | |
{ | |
fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr); | |
} | |
} | |
// Insert end of line padding | |
for (int k = 0; k < padding; k++) | |
{ | |
fputc(0x00, outptr); | |
} | |
// final row write | |
// skip over padding, if any | |
// Replace padding in fseek with padding_save | |
fseek(inptr, padding_save, SEEK_CUR); | |
} | |
} | |
// Branch for 0.5's etc | |
else if (n == 0) | |
{ | |
// the pre-process triage for even or odd widths and heights | |
// even width | |
if (width_save % 2 == 0) | |
{ | |
bi.biWidth = bi.biWidth * 0.5; | |
} | |
// odd width | |
else if (width_save % 2 != 0) | |
{ | |
bi.biWidth = (bi.biWidth - 1) * 0.5; | |
} | |
// even height | |
if (height_save % 2 == 0) | |
{ | |
bi.biHeight = bi.biHeight * 0.5; | |
} | |
// odd height | |
else if (height_save % 2 != 0) | |
{ | |
// + rather than - because biheight is negative | |
bi.biHeight = (bi.biHeight + 1) * 0.5; | |
} | |
{ | |
// The Process | |
// make height positive | |
int absolute_height_new = abs(bi.biHeight); | |
// Adjust new padding using new bi.biWidth | |
padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4; | |
// Create new Size Image and size | |
bi.biSizeImage = ((sizeof(RGBTRIPLE) * bi.biWidth) + padding) * abs(bi.biHeight); | |
bf.bfSize = bi.biSizeImage + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); | |
// write outfile's BITMAPFILEHEADER | |
fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr); | |
// write outfile's BITMAPINFOHEADER | |
fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr); | |
// make offset, the distance (in bytes) the cursor has to move forward after store 2 and before store 3 | |
int offset = (3 * (width_save - 2)) + padding_save; | |
// make reset, the distance (in bytes) the cursor has to move backwards after store 4 to be in position for the next loop | |
int reset = (3 * width_save) + padding_save; | |
// make deset, the distance in bytes the cursor has to move forward on the final turn of each row | |
int deset = reset + padding_save; | |
for (int x = 0; x < absolute_height_new; x++) | |
{ | |
for (int i = 0; i < bi.biWidth; i++) | |
{ | |
// temp storage for 1 | |
RGBTRIPLE store1; | |
// read RGB triple from infile | |
fread(&store1, sizeof(RGBTRIPLE), 1, inptr); | |
RGBTRIPLE store2; | |
fread(&store2, sizeof(RGBTRIPLE), 1, inptr); | |
fseek(inptr, offset, SEEK_CUR); | |
RGBTRIPLE store3; | |
fread(&store3, sizeof(RGBTRIPLE), 1, inptr); | |
RGBTRIPLE store4; | |
fread(&store4, sizeof(RGBTRIPLE), 1, inptr); | |
// take average of store 1-4 | |
RGBTRIPLE store_average; | |
store_average.rgbtBlue = (store1.rgbtBlue + store2.rgbtBlue + store3.rgbtBlue + store4.rgbtBlue) / 4; | |
store_average.rgbtGreen = (store1.rgbtGreen + store2.rgbtGreen + store3.rgbtGreen + store4.rgbtGreen) / 4; | |
store_average.rgbtRed = (store1.rgbtRed + store2.rgbtRed + store3.rgbtRed + store4.rgbtRed) / 4; | |
// write the pixel | |
fwrite(&store_average, sizeof(RGBTRIPLE), 1, outptr); | |
// put cursor to start of new position | |
fseek(inptr, - reset, SEEK_CUR); | |
} | |
// Insert end of line padding | |
for (int k = 0; k < padding; k++) | |
{ | |
fputc(0x00, outptr); | |
} | |
// re-reset cursor | |
fseek(inptr, deset, SEEK_CUR); | |
} | |
} | |
} | |
// close infile | |
fclose(inptr); | |
// close outfile | |
fclose(outptr); | |
// success | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment