From e3b2e7dd2fc0d32af4321427077a8a8b65fc2419 Mon Sep 17 00:00:00 2001 From: Andrew Haynes Date: Mon, 16 Mar 2026 09:31:27 -0400 Subject: [PATCH] Conversion from ppm to jpeg and vice versa added --- .DS_Store | Bin 6148 -> 6148 bytes src/main.c | 436 ++++++++++++++++++++++++++++------------------------- 2 files changed, 231 insertions(+), 205 deletions(-) diff --git a/.DS_Store b/.DS_Store index 8daf6bd50979bc144e7389bfcf3e44f90004fee2..7c52a3419ea0d3b3c2e4a3ba54ca5e93edbf1969 100644 GIT binary patch delta 53 zcmZoMXfc@J&&aniU^g=(-)0^bRVHy(h9rhkhD?SWhLp14qP(2^ymSTz2FA^LZ2K8E Jvvd6A2LN?*4hjGO delta 32 ocmZoMXfc@J&&azmU^g=(?`9qrRi@3}Y #include #include -#include #include +#include #define BYTE_A 0xFF000000 #define BYTE_R 0x00FF0000 @@ -24,10 +24,18 @@ #define decode_g(clr) (((clr) >> SHIFT_8) & BYTE) #define decode_b(clr) ((clr) & BYTE) -#define encode(r, g, b) \ +#define ENCODE_RGB(r, g, b) \ (((unsigned int)(MAX) << SHIFT_24) | ((unsigned int)(r) << SHIFT_16) | \ ((unsigned int)(g) << SHIFT_8) | (unsigned int)(b)) +#define ENCODE_ARGB(a, r, g, b) \ + (((unsigned int)(a) << SHIFT_24) | ((unsigned int)(r) << SHIFT_16) | \ + ((unsigned int)(g) << SHIFT_8) | (unsigned int)(b)) + +#define ENCODE_BGRA(b, g, r, a) \ + (((unsigned int)(b) << SHIFT_24) | ((unsigned int)(g) << SHIFT_16) | \ + ((unsigned int)(r) << SHIFT_8) | (unsigned int)(a)) + #define CLAMP_MAX(x) (((x) > MAX) ? MAX : (x)) #define CLAMP_MIN(x) (((x) < 0) ? 0 : (x)) @@ -35,78 +43,16 @@ typedef struct { int width, height, len; const char* name; - char fmt[3]; + char fmt[4]; } PPM; typedef struct { int width, height; size_t len; - const char* name; + 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 { unsigned int red, green, blue; @@ -147,8 +93,8 @@ static inline unsigned int apply_threshold(const unsigned int clr, const unsigned char limit) { unsigned int mask = 0; - if (decode_b(to_grayscale(clr)) < limit) mask = encode(0, 0, 0); - else mask = encode(MAX, MAX, MAX); + if (decode_b(to_grayscale(clr)) < limit) mask = ENCODE_RGB(0, 0, 0); + else mask = ENCODE_RGB(MAX, MAX, MAX); return BYTE_A | mask; } @@ -172,7 +118,7 @@ apply_tint(const unsigned int clr_a, const unsigned int clr_b) unsigned char green = (decode_g(clr_a) + decode_g(clr_b)) / 2; unsigned char red = (decode_r(clr_a) + decode_r(clr_b)) / 2; - return set_alpha(encode(red, green, blue), decode_a(clr_a)); + return set_alpha(ENCODE_RGB(red, green, blue), decode_a(clr_a)); } static inline unsigned int @@ -184,120 +130,7 @@ apply_opacity(const unsigned clr_a, const unsigned int clr_b, const float ratio) ((decode_g(clr_b) * ratio))); unsigned char red = (unsigned char)((decode_r(clr_a) * (1 - ratio)) + ((decode_r(clr_b) * ratio))); - return set_alpha(encode(red, green, blue), decode_a(clr_a)); -} - -static inline unsigned int* -ppm_encode(const char* file, PPM* img) -{ - printf("Starting encode...\n"); - unsigned char red; - unsigned char green; - unsigned char blue; - char fmt[3]; - int max_val; - FILE* fptr; - fptr = fopen(file, "r"); - 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 NULL; - unsigned int* clr_buf = malloc(img->len * sizeof(unsigned int)); - if (!clr_buf) - { - free(img_buf); - return NULL; - } - if (fmt[1] == '3') - { - for (int i = 0; i < img->len; i++) - { - fscanf(fptr, "%hhu %hhu %hhu", &red, &green, &blue); - clr_buf[i] = encode(red, green, blue); - } - } - else if (fmt[1] == '6') - { - fread(img_buf, 3, img->len, fptr); - - for (int i = 0; i < img->len; i++) - { - red = img_buf[i * 3]; - green = img_buf[i * 3 + 1]; - blue = img_buf[i * 3 + 2]; - clr_buf[i] = encode(red, green, blue); - } - } - - fclose(fptr); - free(img_buf); - printf("Encoding done!\n"); - return clr_buf; -} - -static inline void -ppm_apply_brightness(unsigned int* buf, const PPM img, const float factor) -{ - for (int i = 0; i < img.len; i++) - { - buf[i] = adjust_brightness(buf[i], factor); - } -} - -static inline void -ppm_decode(unsigned int* buf, const PPM img) -{ - unsigned char red, green, blue; - unsigned char* dst_buf = malloc(img.len * 3); - if (!dst_buf) return; - printf("Starting decode...\n"); - FILE* fptr; - - if (img.fmt[1] == '3') fptr = fopen(img.name, "w"); - if (img.fmt[1] == '6') fptr = fopen(img.name, "wb"); - 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') - { - for (int i = 0; i < img.len; i++) - { - red = decode_r(buf[i]); - green = decode_g(buf[i]); - blue = decode_b(buf[i]); - fprintf(fptr, "%d %d %d ", red, green, blue); - if (i % 7 == 0) - { - fprintf(fptr, "\n"); - } - } - } - if (img.fmt[1] == '6') - { - for (int i = 0; i < img.len; i++) - { - dst_buf[i * 3] = decode_r(buf[i]); - dst_buf[i * 3 + 1] = decode_g(buf[i]); - dst_buf[i * 3 + 2] = decode_b(buf[i]); - } - fwrite(dst_buf, 1, img.len * 3, fptr); - } - fclose(fptr); - free(dst_buf); - free(buf); - printf("Decode Done!\n"); + return set_alpha(ENCODE_RGB(red, green, blue), decode_a(clr_a)); } static inline unsigned int @@ -331,7 +164,7 @@ chromatic_circular_shift(const unsigned int clr, const int n) red = ((red << n) | (red >> (SHIFT_8 - n))) & BYTE; green = ((green << n) | (green >> (SHIFT_8 - n))) & BYTE; blue = ((blue << n) | (blue >> (SHIFT_8 - n))) & BYTE; - return encode(red, green, blue); + return ENCODE_RGB(red, green, blue); } static inline unsigned int* @@ -434,7 +267,7 @@ brightness_mirror(unsigned int clr) unsigned char red = decode_r(clr); unsigned char blue = decode_b(clr); unsigned char green = (red + blue) / 2; - return encode(red, green, blue); + return ENCODE_RGB(red, green, blue); } static inline unsigned int @@ -480,7 +313,7 @@ box_blur(unsigned int* src_buf, PPM* img, int radius) unsigned long cpi = 0, red = 0, green = 0, blue = 0; int count = 0; int edge = (x < radius || x >= img->width - radius); - if (edge) continue; + if (edge) continue; cpi = src_buf[y * img->width + x]; for (int dx = -radius; dx <= radius; dx++) @@ -497,8 +330,8 @@ box_blur(unsigned int* src_buf, PPM* img, int radius) if (count > 0) { tmp_buf[y * img->width + x] = - encode((red / count), (green / count), - (blue / count)); + ENCODE_RGB((red / count), (green / count), + (blue / count)); } else tmp_buf[y * img->width + x] = cpi; } @@ -512,14 +345,13 @@ box_blur(unsigned int* src_buf, PPM* img, int radius) unsigned long cpi = 0, red = 0, green = 0, blue = 0; int count = 0; int edge = (y < radius || y >= img->height - radius); - if (edge) continue; + 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; + if (py < 0 || py >= img->height) continue; unsigned int p = tmp_buf[py * img->width + x]; red += decode_r(p); green += decode_g(p); @@ -530,8 +362,8 @@ box_blur(unsigned int* src_buf, PPM* img, int radius) if (count > 0) { dst_buf[y * img->width + x] = - encode((red / count), (green / count), - (blue / count)); + ENCODE_RGB((red / count), (green / count), + (blue / count)); } else dst_buf[y * img->width + x] = cpi; } @@ -542,22 +374,216 @@ box_blur(unsigned int* src_buf, PPM* img, int radius) return dst_buf; } +static inline void +ppm_apply_brightness(unsigned int* buf, const PPM img, const float factor) +{ + for (int i = 0; i < img.len; i++) + { + buf[i] = adjust_brightness(buf[i], factor); + } +} + +static inline unsigned int* +ppm_decode(const char* file, PPM* img) +{ + printf("Starting decode...\n"); + unsigned char red; + unsigned char green; + unsigned char blue; + char fmt[3]; + int max_val; + FILE* fptr; + fptr = fopen(file, "r"); + 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 NULL; + unsigned int* clr_buf = malloc(img->len * sizeof(unsigned int)); + if (!clr_buf) + { + free(img_buf); + return NULL; + } + if (fmt[1] == '3') + { + for (int i = 0; i < img->len; i++) + { + fscanf(fptr, "%hhu %hhu %hhu", &red, &green, &blue); + clr_buf[i] = ENCODE_RGB(red, green, blue); + } + } + else if (fmt[1] == '6') + { + fread(img_buf, 3, img->len, fptr); + + for (int i = 0; i < img->len; i++) + { + red = img_buf[i * 3]; + green = img_buf[i * 3 + 1]; + blue = img_buf[i * 3 + 2]; + clr_buf[i] = ENCODE_RGB(red, green, blue); + } + } + + fclose(fptr); + free(img_buf); + printf("Decoding done!\n"); + return clr_buf; +} + +static inline void +ppm_encode(unsigned int* buf, const PPM img) +{ + if (!buf) return; + unsigned char red, green, blue; + unsigned char* dst_buf = malloc(img.len * 3); + if (!dst_buf) return; + printf("Starting encode...\n"); + FILE* fptr; + + if (img.fmt[1] == '3') fptr = fopen(img.name, "w"); + if (img.fmt[1] == '6') fptr = fopen(img.name, "wb"); + 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') + { + for (int i = 0; i < img.len; i++) + { + red = decode_r(buf[i]); + green = decode_g(buf[i]); + blue = decode_b(buf[i]); + fprintf(fptr, "%d %d %d ", red, green, blue); + if (i % 7 == 0) + { + fprintf(fptr, "\n"); + } + } + } + if (img.fmt[1] == '6') + { + for (int i = 0; i < img.len; i++) + { + dst_buf[i * 3] = decode_r(buf[i]); + dst_buf[i * 3 + 1] = decode_g(buf[i]); + dst_buf[i * 3 + 2] = decode_b(buf[i]); + } + fwrite(dst_buf, 1, img.len * 3, fptr); + } + fclose(fptr); + free(dst_buf); + free(buf); + printf("Encode Done!\n"); +} + +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); + if (src_buf) free(src_buf); + printf("Encode Successful!\n"); +} + +void +ppm_to_jpeg(PPM* in, JPEG* out) +{ + unsigned int* src_buf = ppm_decode(in->name, in); + // int jpeg_size = jpeg->width * jpeg->height; + out->width = in->width; + out->height = in->height; + jpeg_encode(src_buf, out, out->name); +} + +void +jpeg_to_ppm(JPEG* input, PPM* out) +{ + unsigned int* src_buf = jpeg_decode(input); + out->width = input->width; + out->height = input->height; + out->len = out->width * out->height; + ppm_encode(src_buf, *out); +} + int main() { - PPM img = { .width = 3, + PPM ppm = { .width = 3, + .height = 2, + .name = "../assets/8ktest.ppm", + .len = 0, + .fmt = "P6" }; + JPEG jpeg = { .width = 3, .height = 2, - .name = "../color.ppm", - .fmt = "P6", - .len = 0 }; + .len = 0, + .name = "../test.jpg" }; - 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); - } + // jpeg_to_ppm(&jpeg, &ppm); + ppm_to_jpeg(&ppm, &jpeg); return 0; }