commit 7315d5005d5677b7ddae6c149022166abf3514fa Author: Andrew Haynes Date: Wed Mar 4 21:59:41 2026 -0500 update diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..369e701 --- /dev/null +++ b/.clang-format @@ -0,0 +1,19 @@ +--- +BasedOnStyle: Google +Standard: Latest +UseTab: Always +TabWidth: 8 +IndentWidth: 8 +BreakBeforeBraces: Allman +SpaceBeforeCpp11BracedList: true +SeparateDefinitionBlocks: Always +Cpp11BracedListStyle: false +BreakAfterReturnType: TopLevel +AlignTrailingComments: + Kind: Always +ReflowComments: Always +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: AllIfsAndElse +AllowShortLoopsOnASingleLine: true +IndentAccessModifiers: false # Indent access specifiers by one level +AccessModifierOffset: -4 # Optional: adjust offset relative to the class indentation level diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5b79a54 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/ +.cache/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..225404f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.16) +set(CMAKE_C_STANDARD 23) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +include_directories(include) +project(ppm_image_processor LANGUAGES C) + +add_executable(ppm_image_processor src/main.c) diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..1355ecb --- /dev/null +++ b/src/main.c @@ -0,0 +1,267 @@ +#include +#include +#include + +unsigned int +encoder(unsigned char r, unsigned char g, unsigned char b) +{ + unsigned int color = 0; + color |= b << 0; + color |= g << 8; + color |= r << 16; + return color; +} + +unsigned char +decoder(unsigned int clr, int byte) +{ + if (byte == 1) return (clr & 0x000000FF) >> 0; + else if (byte == 2) return (clr & 0x0000FF00) >> 8; + else if (byte == 3) return (clr & 0x00FF0000) >> 16; + else if (byte == 4) return (clr & 0xFF000000) >> 24; + return 0; +} + +// unsigned int +// decoder_int(unsigned int clr, int byte) +// { +// if (byte == 1) return (clr & 0x000000FF) >> 0; +// else if (byte == 2) return (clr & 0x0000FF00) >> 8; +// else if (byte == 3) return (clr & 0x00FF0000) >> 16; +// else if (byte == 4) return (clr & 0xFF000000) >> 24; +// return 0; +// } + +unsigned int +set_alpha(unsigned int clr, unsigned char alpha_value) +{ + return (clr & 0x00FFFFFF) | alpha_value << 24; +} + +unsigned int +invert_rgb(unsigned int clr) +{ + unsigned char alpha = (clr & 0xFF000000) >> 24; + + return ((~clr) & 0x00FFFFFF) | alpha << 24; +} + +unsigned int +swap_rb(unsigned int clr) +{ + return (((clr & 0xFF00FF00) | ((decoder(clr, 3)) << 0) | + ((decoder(clr, 1) >> 0) << 16))); +} + +unsigned int +to_grayscale(unsigned int clr) +{ + unsigned char alpha = decoder(clr, 4); + unsigned char red = decoder(clr, 3); + unsigned char green = decoder(clr, 2); + unsigned char blue = decoder(clr, 1); + + int average = (red + green + blue) / 3; + unsigned int mask = encoder(average, average, average); + mask = set_alpha(mask, alpha); + + return mask; +} + +unsigned int +apply_threshold(unsigned int clr, unsigned char limit) +{ + unsigned int mask = 0; + unsigned char average = decoder(to_grayscale(clr), 1); + if (average < limit) mask = encoder(0, 0, 0); + else mask = encoder(255, 255, 255); + mask = set_alpha(mask, decoder(clr, 4)); + return mask; +} + +unsigned int +adjust_brightness(unsigned int clr, float factor) +{ + unsigned int red = decoder(clr, 3) * factor; + unsigned int green = decoder(clr, 2) * factor; + unsigned int blue = decoder(clr, 1) * factor; + if (red > 255) red = 255; + if (green > 255) green = 255; + if (blue > 255) blue = 255; + unsigned int mask = encoder(red, green, blue); + mask = set_alpha(mask, decoder(clr, 4)); + return mask; +} + +unsigned int +apply_tint(unsigned int clr_a, unsigned int clr_b) +{ + unsigned char blue = (decoder(clr_a, 1) + decoder(clr_b, 1)) / 2; + unsigned char green = (decoder(clr_a, 2) + decoder(clr_b, 2)) / 2; + unsigned char red = (decoder(clr_a, 3) + decoder(clr_b, 3)) / 2; + + return set_alpha(encoder(red, green, blue), decoder(clr_a, 4)); +} + +unsigned int +apply_opacity(unsigned clr_a, unsigned int clr_b, float ratio) +{ + unsigned char blue = + (decoder(clr_a, 1) * (1 - ratio) + (decoder(clr_b, 1) * ratio)); + unsigned char green = + (decoder(clr_a, 2) * (1 - ratio) + (decoder(clr_b, 2) * ratio)); + unsigned char red = + (decoder(clr_a, 3) * (1 - ratio) + (decoder(clr_b, 3) * ratio)); + return set_alpha(encoder(red, green, blue), decoder(clr_a, 4)); +} + +unsigned int* +ppm_encode(char* file, int* w, int* h, int* max_val, char* magic_number) +{ + unsigned char r, g, b; + FILE* fptr; + fptr = fopen(file, "r"); + if (!fptr) return NULL; + fscanf(fptr, "%s", magic_number); + fscanf(fptr, "%d %d", w, h); + fscanf(fptr, "%d", max_val); + unsigned int* buf = malloc((*w) * (*h) * sizeof(unsigned int)); + if (!buf) return NULL; + + for (int i = 0; i < (*w * *h); i++) + { + fscanf(fptr, "%hhu %hhu %hhu", &r, &g, &b); + unsigned int packed = encoder(r, g, b); + buf[i] = set_alpha(packed, 255); + } + fclose(fptr); + return buf; +} + +void +ppm_apply_brightness(unsigned int* buf, int buf_size, float factor) +{ + for (int i = 0; i < buf_size; i++) + { + buf[i] = adjust_brightness(buf[i], factor); + } +} + +void +ppm_decode(unsigned int* buf, int buf_size, char* name, int* w, int* h) +{ + unsigned char red, green, blue; + FILE* fptr = fopen(name, "w"); + if (!fptr) return; + fprintf(fptr, "P3\n%d %d\n255\n", *w, *h); + for (int i = 0; i < buf_size; i++) + { + red = decoder(buf[i], 3); + green = decoder(buf[i], 2); + blue = decoder(buf[i], 1); + fprintf(fptr, "%d %d %d ", red, green, blue); + if ((i + 1) % *w == 0) + { + fprintf(fptr, "\n"); + } + } + fclose(fptr); +} + +unsigned int +channel_mask(unsigned int clr, char keep) +{ + unsigned int mask = 0; + switch (keep) + { + case 'r': + mask = encoder(decoder(clr, 3), 0, 0); + break; + case 'g': + mask = encoder(0, decoder(clr, 2), 0); + break; + case 'b': + mask = encoder(0, 0, decoder(clr, 1)); + break; + } + mask = set_alpha(mask, decoder(clr, 4)); + return mask; +} + +unsigned int +chromatic_circular_shift(unsigned int clr, int n) +{ + unsigned int mask = 0; + unsigned char r, g, b; + r = decoder(clr, 3); + g = decoder(clr, 2); + b = decoder(clr, 1); + + r = (r << n) | (r >> (8 - n)); + g = (g << n) | (g >> (8 - n)); + b = (b << n) | (b >> (8 - n)); + mask = encoder(r, g, b); + mask = set_alpha(mask, decoder(clr, 4)); + return mask; +} + +unsigned int* +horizontal_flip(unsigned int* buf, int size, int w) { + +} + +unsigned int* +vertical_flip(unsigned int* buf, int size, int w, int h) { + +} + + +void +print_bits_int(unsigned int n) +{ + for (int i = 31; i >= 0; i--) + { + if (i == 7 || i == 15 || i == 23) write(1, " ", 1); + char bit = (n & (1 << i)) ? '1' : '0'; + write(1, &bit, 1); + } + write(1, "\n", 1); +} + +void +print_bits_char(unsigned char n) +{ + for (int i = 7; i >= 0; i--) + { + char bit = (n & (1 << i)) ? '1' : '0'; + write(1, &bit, 1); + } + write(1, "\n", 1); +} + +int +main() +{ + // unsigned int test = 40; + // print_bits_int(test); + // test = (test << 3) | (test >> (8 - 3)); + // print_bits_int(test); + + unsigned int color = encoder(200, 10, 50); + color = set_alpha(color, 100); + print_bits_int(color); + // unsigned int channelled_color = channel_mask(color, 'g'); + color = chromatic_circular_shift(color, 3); + print_bits_int(color); + // int width, height; + // char magic_number[3]; + // int max_val; + // + // unsigned int* buf = + // ppm_encode("../test.ppm", &width, &height, &max_val, + // magic_number); + // ppm_apply_brightness(buf, (width * height), .5); + // ppm_decode(buf, (width * height), "../new.ppm", &width, &height); + // free(buf); + return 0; +}