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 0000000..4ec36b3 Binary files /dev/null and b/program differ diff --git a/src/main.c b/src/main.c index 7b3a5e8..5184fc0 100644 --- a/src/main.c +++ b/src/main.c @@ -3,6 +3,7 @@ #include #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; }