added working jpeg

This commit is contained in:
Andrew Haynes
2026-03-10 16:17:14 -04:00
parent f6bc756839
commit 4782c3e876
3 changed files with 202 additions and 27 deletions
+17 -5
View File
@@ -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})
Executable
BIN
View File
Binary file not shown.
+185 -22
View File
@@ -3,6 +3,7 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <turbojpeg.h>
#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;
}