From 4782c3e8763bb7bafd4637c3a759b403b929dfd7 Mon Sep 17 00:00:00 2001 From: Andrew Haynes Date: Tue, 10 Mar 2026 16:17:14 -0400 Subject: [PATCH] added working jpeg --- CMakeLists.txt | 22 ++++-- program | Bin 0 -> 33960 bytes src/main.c | 207 +++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 202 insertions(+), 27 deletions(-) create mode 100755 program diff --git a/CMakeLists.txt b/CMakeLists.txt index 074f498..e8de43f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,11 +3,23 @@ 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) -find_package(JPEG REQUIRED) +project(image_processor LANGUAGES C) +# find_package(JPEG REQUIRED) +# +# add_executable(image_processor src/main.c) +# +# target_include_directories(image_processor PRIVATE ${JPEG_INCLUDE_DIRS}) +# +# target_link_libraries(image_processor PRIVATE ${JPEG_LIBRARIES}) -add_executable(ppm_image_processor src/main.c) +find_library(TURBOJPEG_LIB NAMES turbojpeg REQUIRED) +find_path(TURBOJPEG_INCLUDE NAMES turbojpeg.h REQUIRED) -target_include_directories(ppm_image_processor PRIVATE ${JPEG_INCLUDE_DIRS}) +add_executable(image_processor src/main.c) + +# 2. Include the directories for the header files +target_include_directories(image_processor PRIVATE ${TURBOJPEG_INCLUDE}) + +# 3. Link the actual turbojpeg library +target_link_libraries(image_processor PRIVATE ${TURBOJPEG_LIB}) -target_link_libraries(ppm_image_processor PRIVATE ${JPEG_LIBRARIES}) diff --git a/program b/program new file mode 100755 index 0000000000000000000000000000000000000000..4ec36b3d812a48ec78b6840827b871e536ad02da GIT binary patch literal 33960 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 #include #include +#include #define BYTE_A 0xFF000000 #define BYTE_R 0x00FF0000 @@ -35,7 +36,76 @@ typedef struct int width, height, len; const char* name; char fmt[3]; -} Image; +} PPM; + +typedef struct +{ + int width, height; + size_t len; + const char* name; +} JPEG; + +unsigned int* +jpeg_decode(JPEG* attr) +{ + printf("Starting Decode...\n"); + tjhandle tjdecompress = tj3Init(TJINIT_DECOMPRESS); + unsigned char* jpeg_buf = NULL; + FILE* infile = fopen(attr->name, "rb"); + if (!infile) return NULL; + fseek(infile, 0, SEEK_END); + attr->len = ftell(infile); + fseek(infile, 0, SEEK_SET); + jpeg_buf = (unsigned char*)malloc(attr->len); + fread(jpeg_buf, 1, attr->len, infile); + fclose(infile); + if (tj3DecompressHeader(tjdecompress, jpeg_buf, attr->len) < 0) + { + printf("Header error: %s\n", tj3GetErrorStr(tjdecompress)); + free(jpeg_buf); + return NULL; + } + attr->width = tj3Get(tjdecompress, TJPARAM_JPEGWIDTH); + attr->height = tj3Get(tjdecompress, TJPARAM_JPEGHEIGHT); + unsigned int* pixels = + malloc(attr->width * attr->height * sizeof(unsigned int)); + tj3Decompress8(tjdecompress, jpeg_buf, attr->len, + (unsigned char*)pixels, 0, TJPF_BGRA); + tj3Destroy(tjdecompress); + free(jpeg_buf); + printf("Decode Successful!\n"); + return pixels; +} + +void +jpeg_encode(unsigned int* src_buf, JPEG* attr, char* name) +{ + printf("Starting Decode...\n"); + tjhandle tjcompress = tj3Init(TJINIT_COMPRESS); + unsigned char* dst_buf = NULL; + size_t dst_size = 0; + tj3Set(tjcompress, TJPARAM_QUALITY, 80); + tj3Set(tjcompress, TJPARAM_SUBSAMP, TJSAMP_420); + if (tj3Compress8(tjcompress, (unsigned char*)src_buf, attr->width, 0, + attr->height, TJPF_BGRA, &dst_buf, &dst_size) < 0) + { + printf("TurboJPEG Error: %s\n", tj3GetErrorStr(tjcompress)); + } + FILE* fptr = fopen(name, "wb"); + if (!fptr || dst_buf == NULL || dst_size <= 0) + { + free(src_buf); + tj3Free(dst_buf); + return; + } + fwrite(dst_buf, 1, dst_size, fptr); + fclose(fptr); + + tj3Destroy(tjcompress); + tj3Free(dst_buf); + printf("Encode Successful!\n"); +} + typedef struct { @@ -118,7 +188,7 @@ apply_opacity(const unsigned clr_a, const unsigned int clr_b, const float ratio) } static inline unsigned int* -ppm_encode(const char* file, Image* img) +ppm_encode(const char* file, PPM* img) { printf("Starting encode...\n"); unsigned char red; @@ -128,19 +198,23 @@ ppm_encode(const char* file, Image* img) int max_val; FILE* fptr; fptr = fopen(file, "r"); - if (!fptr) return nullptr; + if (!fptr) + { + printf("Invalid file name: %s", file); + return NULL; + } fscanf(fptr, "%s", fmt); fscanf(fptr, "%d %d", &img->width, &img->height); img->len = img->width * img->height; fscanf(fptr, "%d", &max_val); fgetc(fptr); unsigned char* img_buf = malloc(img->len * 3); - if (!img_buf) return nullptr; + if (!img_buf) return NULL; unsigned int* clr_buf = malloc(img->len * sizeof(unsigned int)); if (!clr_buf) { free(img_buf); - return nullptr; + return NULL; } if (fmt[1] == '3') { @@ -170,7 +244,7 @@ ppm_encode(const char* file, Image* img) } static inline void -ppm_apply_brightness(unsigned int* buf, const Image img, const float factor) +ppm_apply_brightness(unsigned int* buf, const PPM img, const float factor) { for (int i = 0; i < img.len; i++) { @@ -179,7 +253,7 @@ ppm_apply_brightness(unsigned int* buf, const Image img, const float factor) } static inline void -ppm_decode(const unsigned int* buf, const Image img) +ppm_decode(unsigned int* buf, const PPM img) { unsigned char red, green, blue; unsigned char* dst_buf = malloc(img.len * 3); @@ -189,7 +263,11 @@ ppm_decode(const unsigned int* buf, const Image img) if (img.fmt[1] == '3') fptr = fopen(img.name, "w"); if (img.fmt[1] == '6') fptr = fopen(img.name, "wb"); - if (!fptr) return; + if (!fptr) + { + free(dst_buf); + return; + } fprintf(fptr, "%s\n%d %d\n255\n", img.fmt, img.width, img.height); if (img.fmt[1] == '3') @@ -218,6 +296,7 @@ ppm_decode(const unsigned int* buf, const Image img) } fclose(fptr); free(dst_buf); + free(buf); printf("Decode Done!\n"); } @@ -256,10 +335,10 @@ chromatic_circular_shift(const unsigned int clr, const int n) } static inline unsigned int* -horizontal_flip(unsigned int* buf, const Image img) +horizontal_flip(unsigned int* buf, const PPM img) { unsigned int* flip = malloc(img.len * sizeof(unsigned int)); - if (!flip) return nullptr; + if (!flip) return NULL; int idx = 0; for (int i = 0; i < img.height; i++) { @@ -275,10 +354,10 @@ horizontal_flip(unsigned int* buf, const Image img) } static inline unsigned int* -vertical_flip(unsigned int* buf, Image img) +vertical_flip(unsigned int* buf, PPM img) { unsigned int* flip = malloc(img.len * sizeof(unsigned int)); - if (!flip) return nullptr; + if (!flip) return NULL; int idx = 0; for (int i = img.height - 1; i >= 0; i--) @@ -308,7 +387,7 @@ constrast_adjustment(unsigned int clr, float factor) } static inline unsigned int* -rotate(unsigned int* buf, Image* img, int len) +rotate(unsigned int* buf, PPM* img, int len) { unsigned int* mask = malloc(len * sizeof(unsigned int)); int old_width = img->width; @@ -368,15 +447,97 @@ get_pixel_safe(unsigned int* buf, int x, int y, int width, int height) return 0; } -static inline unsigned int* -box_blur(unsigned int* src_buf, Image* img, int len) +static inline int +add_pixel(unsigned int pixel, unsigned int* red, unsigned int* green, + unsigned int* blue) { - unsigned int* dst_buf = malloc(len * sizeof(unsigned int)); - // Loop every pixel - for (int i = 0; i < len; i++) + if (pixel != 0) { - + *red += decode_r(pixel); + *green += decode_g(pixel); + *blue += decode_b(pixel); + return 1; } + return 0; +} + +static inline unsigned int* +box_blur(unsigned int* src_buf, PPM* img, int radius) +{ + unsigned int* tmp_buf = malloc(img->len * sizeof(unsigned int)); + if (!tmp_buf) return 0; + unsigned int* dst_buf = malloc(img->len * sizeof(unsigned int)); + if (!dst_buf) + { + free(tmp_buf); + return 0; + } + printf("Pass 1: ...\n"); + for (int y = 0; y < img->height; y++) + { + for (int x = 0; x < img->width; x++) + { + unsigned long cpi = 0, red = 0, green = 0, blue = 0; + int count = 0; + int edge = (x < radius || x >= img->width - radius); + if (edge) continue; + cpi = src_buf[y * img->width + x]; + + for (int dx = -radius; dx <= radius; dx++) + { + int px = x + dx; + if (px < 0 || px >= img->width) continue; + unsigned int p = src_buf[y * img->width + px]; + red += decode_r(p); + green += decode_g(p); + blue += decode_b(p); + count++; + } + + if (count > 0) + { + tmp_buf[y * img->width + x] = + encode((red / count), (green / count), + (blue / count)); + } + else tmp_buf[y * img->width + x] = cpi; + } + } + printf("Pass 1: Successful\n"); + printf("Pass 2: ...\n"); + for (int y = 0; y < img->height; y++) + { + for (int x = 0; x < img->width; x++) + { + unsigned long cpi = 0, red = 0, green = 0, blue = 0; + int count = 0; + int edge = (y < radius || y >= img->height - radius); + if (edge) continue; + cpi = src_buf[y * img->width + x]; + + for (int dy = -radius; dy <= radius; dy++) + { + int py = y + dy; + if (py < 0 || py >= img->height) + continue; + unsigned int p = tmp_buf[py * img->width + x]; + red += decode_r(p); + green += decode_g(p); + blue += decode_b(p); + count++; + } + + if (count > 0) + { + dst_buf[y * img->width + x] = + encode((red / count), (green / count), + (blue / count)); + } + else dst_buf[y * img->width + x] = cpi; + } + } + printf("Pass 2: Successful\n"); + free(tmp_buf); free(src_buf); return dst_buf; } @@ -384,17 +545,19 @@ box_blur(unsigned int* src_buf, Image* img, int len) int main() { - Image img = { .width = 3, + PPM img = { .width = 3, .height = 2, .name = "../color.ppm", .fmt = "P6", .len = 0 }; - unsigned int* buf = ppm_encode("../assets/wtest_p6.ppm.ppm", &img); + unsigned int* buf = ppm_encode("../assets/8ktest.ppm", &img); if (buf) { + printf("Applying Filter...\n"); + buf = box_blur(buf, &img, 40); + printf("Finished Applying Filter!\n"); ppm_decode(buf, img); - free(buf); } return 0; }