added working jpeg
This commit is contained in:
+17
-5
@@ -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})
|
||||
|
||||
+185
-22
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user