API: moved functions to files to make it easier to import to other projects
This commit is contained in:
+217
@@ -0,0 +1,217 @@
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
// #include "utils.h"
|
||||
#include "filters.h"
|
||||
|
||||
unsigned int
|
||||
u32_put_alpha(const unsigned int clr, const unsigned char alpha)
|
||||
{
|
||||
return (clr & BYTE_RGB) | alpha << SHIFT_24;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
u32_invert(const unsigned int clr)
|
||||
{
|
||||
return ((~clr) & BYTE_RGB) | (clr & BYTE_A);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
u32_swap_rb(const unsigned int clr)
|
||||
{
|
||||
return (clr & 0xFF00FF00) | ((clr & BYTE_R) >> SHIFT_16) |
|
||||
((clr & BYTE_B) << SHIFT_16);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
u32_grayscale(const unsigned int clr)
|
||||
{
|
||||
unsigned int red = DECODE_R(clr);
|
||||
unsigned int green = DECODE_G(clr);
|
||||
unsigned int blue = DECODE_B(clr);
|
||||
unsigned int gray =
|
||||
((red * 77) + (green * 150) + (blue * 29)) >> SHIFT_8;
|
||||
|
||||
return (clr & BYTE_A) | (gray << SHIFT_16) | (gray << SHIFT_8) | gray;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
u32_step(const unsigned int clr, const unsigned char max)
|
||||
{
|
||||
if (DECODE_B(u32_grayscale(clr)) < max)
|
||||
{
|
||||
return ENCODE_ARGB(0, 0, 0, 0);
|
||||
}
|
||||
return ENCODE_ARGB(MAX, MAX, MAX, MAX);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
u32_brighten(const unsigned int clr, const float factor)
|
||||
{
|
||||
unsigned int alpha = (clr & BYTE_A);
|
||||
unsigned int red = CLAMP_MAX(DECODE_R(clr) * factor);
|
||||
unsigned int green = CLAMP_MAX(DECODE_G(clr) * factor);
|
||||
unsigned int blue = CLAMP_MAX(DECODE_B(clr) * factor);
|
||||
return (clr & BYTE_A) | (red << SHIFT_16) | (green << SHIFT_8) | blue;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
u32_mix(const unsigned int clr_a, const unsigned int clr_b)
|
||||
{
|
||||
unsigned char blue = (DECODE_B(clr_a) + DECODE_B(clr_b)) / 2;
|
||||
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 ENCODE_ARGB(DECODE_A(clr_a), red, green, blue);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
u32_lerp(const unsigned clr_a, const unsigned int clr_b, const float ratio)
|
||||
{
|
||||
unsigned char blue =
|
||||
((DECODE_B(clr_a) * (1 - ratio)) + ((DECODE_B(clr_b) * ratio)));
|
||||
unsigned char green =
|
||||
((DECODE_G(clr_a) * (1 - ratio)) + ((DECODE_G(clr_b) * ratio)));
|
||||
unsigned char red =
|
||||
((DECODE_R(clr_a) * (1 - ratio)) + ((DECODE_R(clr_b) * ratio)));
|
||||
return ENCODE_ARGB(DECODE_A(clr_a), red, green, blue);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
u32_mask(const unsigned int clr, const char keep)
|
||||
{
|
||||
switch (keep)
|
||||
{
|
||||
case 'r':
|
||||
return clr & (BYTE_A | BYTE_R);
|
||||
break;
|
||||
case 'g':
|
||||
return clr & (BYTE_A | BYTE_G);
|
||||
break;
|
||||
case 'b':
|
||||
return clr & (BYTE_A | BYTE_B);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
u32_rotl(const unsigned int clr, const int n)
|
||||
{
|
||||
if (n > 8)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
unsigned int red = DECODE_R(clr);
|
||||
unsigned int green = DECODE_G(clr);
|
||||
unsigned int blue = DECODE_B(clr);
|
||||
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_RGB(red, green, blue);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
u32_contrast(const unsigned int clr, const float factor)
|
||||
{
|
||||
int red = CLAMP_MIN(CLAMP_MAX(
|
||||
(int)(factor * (float)(int)(DECODE_R(clr) - HALF_MAX)) + HALF_MAX));
|
||||
int green = CLAMP_MIN(CLAMP_MAX(
|
||||
(int)(factor * (float)(int)(DECODE_G(clr) - HALF_MAX)) + HALF_MAX));
|
||||
int blue = CLAMP_MIN(CLAMP_MAX(
|
||||
(int)(factor * (float)(int)(DECODE_B(clr) - HALF_MAX)) + HALF_MAX));
|
||||
return BYTE_A | (red << SHIFT_16) | (green << SHIFT_8) | blue;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
u32_avg_gb(const unsigned int clr)
|
||||
{
|
||||
unsigned char red = DECODE_R(clr);
|
||||
unsigned char blue = DECODE_B(clr);
|
||||
unsigned char green = (red + blue) / 2;
|
||||
return ENCODE_RGB(red, green, blue);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
blur_col(const unsigned int* src, const int x, const int y, const PPM* img,
|
||||
const int radius)
|
||||
{
|
||||
unsigned long pt = 0, cnt = 0;
|
||||
|
||||
for (int dx = -radius; dx <= radius; dx++)
|
||||
{
|
||||
int px = x + dx;
|
||||
if (px >= 0 && px < img->width)
|
||||
{
|
||||
pt += u32to_u64(src[y * img->width + px]);
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
if (cnt > 0)
|
||||
{
|
||||
return u64to_u32(pt, cnt);
|
||||
}
|
||||
return src[y * img->width + x];
|
||||
}
|
||||
|
||||
unsigned int
|
||||
blur_row(const unsigned int* src, const int x, const int y, const PPM* img,
|
||||
const int radius)
|
||||
{
|
||||
unsigned long pt = 0, cnt = 0;
|
||||
|
||||
for (int dy = -radius; dy <= radius; dy++)
|
||||
{
|
||||
int py = y + dy;
|
||||
if (py >= 0 && py < img->height)
|
||||
{
|
||||
pt += u32to_u64(src[py * img->width + x]);
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
if (cnt > 0)
|
||||
{
|
||||
return u64to_u32(pt, cnt);
|
||||
}
|
||||
return src[y * img->width + x];
|
||||
}
|
||||
|
||||
unsigned int*
|
||||
box_blur(const unsigned int* src_buf, const PPM* img, const int radius)
|
||||
{
|
||||
unsigned int* first_pass = malloc(img->len * sizeof(unsigned int));
|
||||
if (!first_pass)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
unsigned int* dst_buf = malloc(img->len * sizeof(unsigned int));
|
||||
if (!dst_buf)
|
||||
{
|
||||
free(first_pass);
|
||||
return 0;
|
||||
}
|
||||
for (int y = 0; y < img->height; y++)
|
||||
{
|
||||
for (int x = 0; x < img->width; x++)
|
||||
{
|
||||
first_pass[y * img->width + x] =
|
||||
blur_col(src_buf, x, y, img, radius);
|
||||
}
|
||||
}
|
||||
for (int y = 0; y < img->height; y++)
|
||||
{
|
||||
for (int x = 0; x < img->width; x++)
|
||||
{
|
||||
dst_buf[y * img->width + x] =
|
||||
blur_row(first_pass, x, y, img, radius);
|
||||
}
|
||||
}
|
||||
free(first_pass);
|
||||
return dst_buf;
|
||||
}
|
||||
+208
@@ -0,0 +1,208 @@
|
||||
#include "imgio.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <turbojpeg.h>
|
||||
|
||||
unsigned int*
|
||||
ppm_load(const char* file, PPM* m_attr)
|
||||
{
|
||||
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\n", file);
|
||||
return NULL;
|
||||
}
|
||||
fscanf(fptr, "%s", fmt);
|
||||
m_attr->fmt = fmt[1];
|
||||
fscanf(fptr, "%d %d", &m_attr->width, &m_attr->height);
|
||||
m_attr->len = m_attr->width * m_attr->height;
|
||||
fscanf(fptr, "%d", &max_val);
|
||||
fgetc(fptr);
|
||||
unsigned char* img_buf = malloc(m_attr->len * 3);
|
||||
if (!img_buf)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
unsigned int* clr_buf = malloc(m_attr->len * sizeof(unsigned int));
|
||||
if (!clr_buf)
|
||||
{
|
||||
free(img_buf);
|
||||
return NULL;
|
||||
}
|
||||
if (m_attr->fmt == '3')
|
||||
{
|
||||
for (int i = 0; i < m_attr->len; i++)
|
||||
{
|
||||
fscanf(fptr, "%hhu %hhu %hhu", &red, &green, &blue);
|
||||
clr_buf[i] = ENCODE_RGB(red, green, blue);
|
||||
}
|
||||
}
|
||||
else if (m_attr->fmt == '6')
|
||||
{
|
||||
fread(img_buf, 3, m_attr->len, fptr);
|
||||
|
||||
for (int i = 0; i < m_attr->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;
|
||||
}
|
||||
|
||||
int
|
||||
ppm_save(const unsigned int* buf, const PPM img)
|
||||
{
|
||||
if (!buf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
unsigned char red, green, blue;
|
||||
unsigned char* dst_buf = malloc(img.len * 3);
|
||||
if (!dst_buf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
printf("Starting encode...\n");
|
||||
FILE* fptr;
|
||||
|
||||
if (img.fmt == '3')
|
||||
{
|
||||
fptr = fopen(img.name, "w");
|
||||
}
|
||||
if (img.fmt == '6')
|
||||
{
|
||||
fptr = fopen(img.name, "wb");
|
||||
}
|
||||
if (!fptr)
|
||||
{
|
||||
free(dst_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(fptr, "P%c\n%d %d\n255\n", img.fmt, img.width, img.height);
|
||||
if (img.fmt == '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 == '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);
|
||||
printf("Encode Done!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned int*
|
||||
jpeg_load(JPEG* m_attr)
|
||||
{
|
||||
printf("Starting Decode...\n");
|
||||
tjhandle tjdecompress = tj3Init(TJINIT_DECOMPRESS);
|
||||
unsigned char* jpeg_buf = NULL;
|
||||
FILE* infile = fopen(m_attr->name, "rb");
|
||||
if (!infile)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
fseek(infile, 0, SEEK_END);
|
||||
m_attr->len = ftell(infile);
|
||||
fseek(infile, 0, SEEK_SET);
|
||||
jpeg_buf = (unsigned char*)malloc(m_attr->len);
|
||||
fread(jpeg_buf, 1, m_attr->len, infile);
|
||||
fclose(infile);
|
||||
if (tj3DecompressHeader(tjdecompress, jpeg_buf, m_attr->len) < 0)
|
||||
{
|
||||
printf("Header error: %s\n", tj3GetErrorStr(tjdecompress));
|
||||
free(jpeg_buf);
|
||||
return NULL;
|
||||
}
|
||||
m_attr->width = tj3Get(tjdecompress, TJPARAM_JPEGWIDTH);
|
||||
m_attr->height = tj3Get(tjdecompress, TJPARAM_JPEGHEIGHT);
|
||||
unsigned int* pixels =
|
||||
malloc(m_attr->width * m_attr->height * sizeof(unsigned int));
|
||||
tj3Decompress8(tjdecompress, jpeg_buf, m_attr->len,
|
||||
(unsigned char*)pixels, 0, TJPF_BGRA);
|
||||
tj3Destroy(tjdecompress);
|
||||
free(jpeg_buf);
|
||||
printf("Decode Successful!\n");
|
||||
return pixels;
|
||||
}
|
||||
|
||||
int
|
||||
jpeg_save(const unsigned int* src_buf, const JPEG* attr, const 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)
|
||||
{
|
||||
tj3Free(dst_buf);
|
||||
return 0;
|
||||
}
|
||||
fwrite(dst_buf, 1, dst_size, fptr);
|
||||
fclose(fptr);
|
||||
|
||||
tj3Destroy(tjcompress);
|
||||
tj3Free(dst_buf);
|
||||
printf("Encode Successful!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
ppm_to_jpeg(PPM* in, JPEG* out)
|
||||
{
|
||||
unsigned int* src_buf = ppm_load(in->name, in);
|
||||
out->width = in->width;
|
||||
out->height = in->height;
|
||||
jpeg_save(src_buf, out, out->name);
|
||||
}
|
||||
|
||||
void
|
||||
jpeg_to_ppm(JPEG* input, PPM* out)
|
||||
{
|
||||
unsigned int* src_buf = jpeg_load(input);
|
||||
out->width = input->width;
|
||||
out->height = input->height;
|
||||
out->len = out->width * out->height;
|
||||
ppm_save(src_buf, *out);
|
||||
}
|
||||
+7
-560
@@ -1,560 +1,9 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <turbojpeg.h>
|
||||
|
||||
#define BYTE_A 0xFF000000
|
||||
#define BYTE_R 0x00FF0000
|
||||
#define BYTE_G 0x0000FF00
|
||||
#define BYTE_B 0x000000FF
|
||||
#define BYTE_RGB 0x00FFFFFF
|
||||
#define BYTE 0xFF
|
||||
#define LONG_BYTE 0xFFFF
|
||||
|
||||
#define SHIFT_8 8
|
||||
#define SHIFT_16 16
|
||||
#define SHIFT_24 24
|
||||
|
||||
#define MAX 255
|
||||
#define HALF_MAX ((int)(MAX / 2) + 1)
|
||||
|
||||
#define DECODE_A(clr) (((clr) >> SHIFT_24) & BYTE)
|
||||
#define DECODE_R(clr) (((clr) >> SHIFT_16) & BYTE)
|
||||
#define DECODE_G(clr) (((clr) >> SHIFT_8) & BYTE)
|
||||
#define DECODE_B(clr) ((clr) & BYTE)
|
||||
|
||||
#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))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int width, height;
|
||||
int len;
|
||||
char* name;
|
||||
char fmt;
|
||||
} PPM;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int width, height;
|
||||
int len;
|
||||
char* name;
|
||||
} JPEG;
|
||||
|
||||
static inline unsigned long
|
||||
u32to_u64(const unsigned int clr)
|
||||
{
|
||||
unsigned long mask = 0;
|
||||
unsigned long alpha = DECODE_A(clr);
|
||||
unsigned long red = DECODE_R(clr);
|
||||
unsigned long green = DECODE_G(clr);
|
||||
unsigned long blue = DECODE_B(clr);
|
||||
return (alpha << 48) | (red << 32) | (green << 16) | (blue);
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
u64to_u32(const unsigned long clr, const unsigned long u64_div)
|
||||
{
|
||||
unsigned int a = ((clr >> 48) & LONG_BYTE);
|
||||
unsigned int r = ((clr >> 32) & LONG_BYTE);
|
||||
unsigned int g = ((clr >> 16) & LONG_BYTE);
|
||||
unsigned int b = (clr & LONG_BYTE);
|
||||
return ENCODE_ARGB((a / u64_div), (r / u64_div), (g / u64_div),
|
||||
(b / u64_div));
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
u32_put_alpha(const unsigned int clr, const unsigned char alpha)
|
||||
{
|
||||
return (clr & BYTE_RGB) | alpha << SHIFT_24;
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
u32_invert(const unsigned int clr)
|
||||
{
|
||||
return ((~clr) & BYTE_RGB) | (clr & BYTE_A);
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
u32_swap_rb(const unsigned int clr)
|
||||
{
|
||||
return (clr & 0xFF00FF00) | ((clr & BYTE_R) >> SHIFT_16) |
|
||||
((clr & BYTE_B) << SHIFT_16);
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
u32_grayscale(const unsigned int clr)
|
||||
{
|
||||
unsigned int red = DECODE_R(clr);
|
||||
unsigned int green = DECODE_G(clr);
|
||||
unsigned int blue = DECODE_B(clr);
|
||||
unsigned int gray =
|
||||
((red * 77) + (green * 150) + (blue * 29)) >> SHIFT_8;
|
||||
|
||||
return (clr & BYTE_A) | (gray << SHIFT_16) | (gray << SHIFT_8) | gray;
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
u32_step(const unsigned int clr, const unsigned char max)
|
||||
{
|
||||
if (DECODE_B(u32_grayscale(clr)) < max)
|
||||
{
|
||||
return ENCODE_ARGB(0, 0, 0, 0);
|
||||
}
|
||||
return ENCODE_ARGB(MAX, MAX, MAX, MAX);
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
u32_brighten(const unsigned int clr, const float factor)
|
||||
{
|
||||
unsigned int alpha = (clr & BYTE_A);
|
||||
unsigned int red = CLAMP_MAX(DECODE_R(clr) * factor);
|
||||
unsigned int green = CLAMP_MAX(DECODE_G(clr) * factor);
|
||||
unsigned int blue = CLAMP_MAX(DECODE_B(clr) * factor);
|
||||
return (clr & BYTE_A) | (red << SHIFT_16) | (green << SHIFT_8) | blue;
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
u32_mix(const unsigned int clr_a, const unsigned int clr_b)
|
||||
{
|
||||
unsigned char blue = (DECODE_B(clr_a) + DECODE_B(clr_b)) / 2;
|
||||
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 ENCODE_ARGB(DECODE_A(clr_a), red, green, blue);
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
u32_lerp(const unsigned clr_a, const unsigned int clr_b, const float ratio)
|
||||
{
|
||||
unsigned char blue =
|
||||
((DECODE_B(clr_a) * (1 - ratio)) + ((DECODE_B(clr_b) * ratio)));
|
||||
unsigned char green =
|
||||
((DECODE_G(clr_a) * (1 - ratio)) + ((DECODE_G(clr_b) * ratio)));
|
||||
unsigned char red =
|
||||
((DECODE_R(clr_a) * (1 - ratio)) + ((DECODE_R(clr_b) * ratio)));
|
||||
return ENCODE_ARGB(DECODE_A(clr_a), red, green, blue);
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
u32_mask(const unsigned int clr, const char keep)
|
||||
{
|
||||
switch (keep)
|
||||
{
|
||||
case 'r':
|
||||
return clr & (BYTE_A | BYTE_R);
|
||||
break;
|
||||
case 'g':
|
||||
return clr & (BYTE_A | BYTE_G);
|
||||
break;
|
||||
case 'b':
|
||||
return clr & (BYTE_A | BYTE_B);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
u32_rotl(const unsigned int clr, const int n)
|
||||
{
|
||||
if (n > 8)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
unsigned int red = DECODE_R(clr);
|
||||
unsigned int green = DECODE_G(clr);
|
||||
unsigned int blue = DECODE_B(clr);
|
||||
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_RGB(red, green, blue);
|
||||
}
|
||||
|
||||
static inline unsigned int*
|
||||
ppm_flip_h(const unsigned int* buf, const PPM img)
|
||||
{
|
||||
unsigned int* flip = malloc(img.len * sizeof(unsigned int));
|
||||
if (!flip)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
int idx = 0;
|
||||
for (int i = 0; i < img.height; i++)
|
||||
{
|
||||
for (int k = img.width - 1; k >= 0; k--)
|
||||
{
|
||||
flip[idx] = buf[(i * img.width) + k];
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
return flip;
|
||||
}
|
||||
|
||||
static inline unsigned int*
|
||||
ppm_flip_v(const unsigned int* buf, const PPM img)
|
||||
{
|
||||
unsigned int* flip = malloc(img.len * sizeof(unsigned int));
|
||||
if (!flip)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int idx = 0;
|
||||
for (int i = img.height - 1; i >= 0; i--)
|
||||
{
|
||||
for (int k = 0; k < img.width; k++)
|
||||
{
|
||||
flip[idx] = buf[(i * img.width) + k];
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
return flip;
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
u32_contrast(const unsigned int clr, const float factor)
|
||||
{
|
||||
int red = CLAMP_MIN(CLAMP_MAX(
|
||||
(int)(factor * (float)(int)(DECODE_R(clr) - HALF_MAX)) + HALF_MAX));
|
||||
int green = CLAMP_MIN(CLAMP_MAX(
|
||||
(int)(factor * (float)(int)(DECODE_G(clr) - HALF_MAX)) + HALF_MAX));
|
||||
int blue = CLAMP_MIN(CLAMP_MAX(
|
||||
(int)(factor * (float)(int)(DECODE_B(clr) - HALF_MAX)) + HALF_MAX));
|
||||
return BYTE_A | (red << SHIFT_16) | (green << SHIFT_8) | blue;
|
||||
}
|
||||
|
||||
static inline unsigned int*
|
||||
u32_rotate(const unsigned int* buf, PPM* m_img, const int len)
|
||||
{
|
||||
unsigned int* mask = malloc(len * sizeof(unsigned int));
|
||||
int old_width = m_img->width;
|
||||
int old_height = m_img->height;
|
||||
for (int row = 0; row < old_height; row++)
|
||||
{
|
||||
for (int col = 0; col < old_width; col++)
|
||||
{
|
||||
int new_height = col;
|
||||
int new_width = (old_height - 1 - row);
|
||||
|
||||
mask[(new_height * old_height) + new_width] =
|
||||
buf[(row * old_width) + col];
|
||||
}
|
||||
}
|
||||
m_img->width = old_height;
|
||||
m_img->height = old_width;
|
||||
return mask;
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
u32_avg_gb(const unsigned int clr)
|
||||
{
|
||||
unsigned char red = DECODE_R(clr);
|
||||
unsigned char blue = DECODE_B(clr);
|
||||
unsigned char green = (red + blue) / 2;
|
||||
return ENCODE_RGB(red, green, blue);
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
blur_col(const unsigned int* src, const int x, const int y, const PPM* img,
|
||||
const int radius)
|
||||
{
|
||||
unsigned long pt = 0, cnt = 0;
|
||||
|
||||
for (int dx = -radius; dx <= radius; dx++)
|
||||
{
|
||||
int px = x + dx;
|
||||
if (px >= 0 && px < img->width)
|
||||
{
|
||||
pt += u32to_u64(src[y * img->width + px]);
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
if (cnt > 0)
|
||||
{
|
||||
return u64to_u32(pt, cnt);
|
||||
}
|
||||
return src[y * img->width + x];
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
blur_row(const unsigned int* src, const int x, const int y, const PPM* img,
|
||||
const int radius)
|
||||
{
|
||||
unsigned long pt = 0, cnt = 0;
|
||||
|
||||
for (int dy = -radius; dy <= radius; dy++)
|
||||
{
|
||||
int py = y + dy;
|
||||
if (py >= 0 && py < img->height)
|
||||
{
|
||||
pt += u32to_u64(src[py * img->width + x]);
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
if (cnt > 0)
|
||||
{
|
||||
return u64to_u32(pt, cnt);
|
||||
}
|
||||
return src[y * img->width + x];
|
||||
}
|
||||
|
||||
unsigned int*
|
||||
box_blur(const unsigned int* src_buf, const PPM* img, const int radius)
|
||||
{
|
||||
unsigned int* first_pass = malloc(img->len * sizeof(unsigned int));
|
||||
if (!first_pass)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
unsigned int* dst_buf = malloc(img->len * sizeof(unsigned int));
|
||||
if (!dst_buf)
|
||||
{
|
||||
free(first_pass);
|
||||
return 0;
|
||||
}
|
||||
for (int y = 0; y < img->height; y++)
|
||||
{
|
||||
for (int x = 0; x < img->width; x++)
|
||||
{
|
||||
first_pass[y * img->width + x] =
|
||||
blur_col(src_buf, x, y, img, radius);
|
||||
}
|
||||
}
|
||||
for (int y = 0; y < img->height; y++)
|
||||
{
|
||||
for (int x = 0; x < img->width; x++)
|
||||
{
|
||||
dst_buf[y * img->width + x] =
|
||||
blur_row(first_pass, x, y, img, radius);
|
||||
}
|
||||
}
|
||||
free(first_pass);
|
||||
return dst_buf;
|
||||
}
|
||||
|
||||
static inline unsigned int*
|
||||
ppm_load(const char* file, PPM* m_attr)
|
||||
{
|
||||
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\n", file);
|
||||
return NULL;
|
||||
}
|
||||
fscanf(fptr, "%s", fmt);
|
||||
m_attr->fmt = fmt[1];
|
||||
fscanf(fptr, "%d %d", &m_attr->width, &m_attr->height);
|
||||
m_attr->len = m_attr->width * m_attr->height;
|
||||
fscanf(fptr, "%d", &max_val);
|
||||
fgetc(fptr);
|
||||
unsigned char* img_buf = malloc(m_attr->len * 3);
|
||||
if (!img_buf)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
unsigned int* clr_buf = malloc(m_attr->len * sizeof(unsigned int));
|
||||
if (!clr_buf)
|
||||
{
|
||||
free(img_buf);
|
||||
return NULL;
|
||||
}
|
||||
if (m_attr->fmt == '3')
|
||||
{
|
||||
for (int i = 0; i < m_attr->len; i++)
|
||||
{
|
||||
fscanf(fptr, "%hhu %hhu %hhu", &red, &green, &blue);
|
||||
clr_buf[i] = ENCODE_RGB(red, green, blue);
|
||||
}
|
||||
}
|
||||
else if (m_attr->fmt == '6')
|
||||
{
|
||||
fread(img_buf, 3, m_attr->len, fptr);
|
||||
|
||||
for (int i = 0; i < m_attr->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 int
|
||||
ppm_save(const unsigned int* buf, const PPM img)
|
||||
{
|
||||
if (!buf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
unsigned char red, green, blue;
|
||||
unsigned char* dst_buf = malloc(img.len * 3);
|
||||
if (!dst_buf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
printf("Starting encode...\n");
|
||||
FILE* fptr;
|
||||
|
||||
if (img.fmt == '3')
|
||||
{
|
||||
fptr = fopen(img.name, "w");
|
||||
}
|
||||
if (img.fmt == '6')
|
||||
{
|
||||
fptr = fopen(img.name, "wb");
|
||||
}
|
||||
if (!fptr)
|
||||
{
|
||||
free(dst_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(fptr, "P%c\n%d %d\n255\n", img.fmt, img.width, img.height);
|
||||
if (img.fmt == '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 == '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);
|
||||
printf("Encode Done!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned int*
|
||||
jpeg_load(JPEG* m_attr)
|
||||
{
|
||||
printf("Starting Decode...\n");
|
||||
tjhandle tjdecompress = tj3Init(TJINIT_DECOMPRESS);
|
||||
unsigned char* jpeg_buf = NULL;
|
||||
FILE* infile = fopen(m_attr->name, "rb");
|
||||
if (!infile)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
fseek(infile, 0, SEEK_END);
|
||||
m_attr->len = ftell(infile);
|
||||
fseek(infile, 0, SEEK_SET);
|
||||
jpeg_buf = (unsigned char*)malloc(m_attr->len);
|
||||
fread(jpeg_buf, 1, m_attr->len, infile);
|
||||
fclose(infile);
|
||||
if (tj3DecompressHeader(tjdecompress, jpeg_buf, m_attr->len) < 0)
|
||||
{
|
||||
printf("Header error: %s\n", tj3GetErrorStr(tjdecompress));
|
||||
free(jpeg_buf);
|
||||
return NULL;
|
||||
}
|
||||
m_attr->width = tj3Get(tjdecompress, TJPARAM_JPEGWIDTH);
|
||||
m_attr->height = tj3Get(tjdecompress, TJPARAM_JPEGHEIGHT);
|
||||
unsigned int* pixels =
|
||||
malloc(m_attr->width * m_attr->height * sizeof(unsigned int));
|
||||
tj3Decompress8(tjdecompress, jpeg_buf, m_attr->len,
|
||||
(unsigned char*)pixels, 0, TJPF_BGRA);
|
||||
tj3Destroy(tjdecompress);
|
||||
free(jpeg_buf);
|
||||
printf("Decode Successful!\n");
|
||||
return pixels;
|
||||
}
|
||||
|
||||
int
|
||||
jpeg_save(const unsigned int* src_buf, const JPEG* attr, const 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)
|
||||
{
|
||||
tj3Free(dst_buf);
|
||||
return 0;
|
||||
}
|
||||
fwrite(dst_buf, 1, dst_size, fptr);
|
||||
fclose(fptr);
|
||||
|
||||
tj3Destroy(tjcompress);
|
||||
tj3Free(dst_buf);
|
||||
printf("Encode Successful!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
ppm_to_jpeg(PPM* in, JPEG* out)
|
||||
{
|
||||
unsigned int* src_buf = ppm_load(in->name, in);
|
||||
out->width = in->width;
|
||||
out->height = in->height;
|
||||
jpeg_save(src_buf, out, out->name);
|
||||
}
|
||||
|
||||
void
|
||||
jpeg_to_ppm(JPEG* input, PPM* out)
|
||||
{
|
||||
unsigned int* src_buf = jpeg_load(input);
|
||||
out->width = input->width;
|
||||
out->height = input->height;
|
||||
out->len = out->width * out->height;
|
||||
ppm_save(src_buf, *out);
|
||||
}
|
||||
#include "utils.h"
|
||||
#include "filters.h"
|
||||
// #include "transformations.h"
|
||||
#include "imgio.h"
|
||||
|
||||
int
|
||||
main()
|
||||
@@ -564,11 +13,9 @@ main()
|
||||
};
|
||||
|
||||
unsigned int* src_buf = ppm_load("../assets/8ktest.ppm", &out);
|
||||
unsigned int* flip = ppm_flip_h(src_buf, out);
|
||||
// unsigned int* blurred = box_blur(src_buf, &out, 10);
|
||||
ppm_save(flip, out);
|
||||
unsigned int* blurred = box_blur(src_buf, &out, 10);
|
||||
ppm_save(blurred, out);
|
||||
free(src_buf);
|
||||
// free(blurred);
|
||||
free(flip);
|
||||
free(blurred);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
#include <stdlib.h>
|
||||
#include "transformations.h"
|
||||
|
||||
unsigned int*
|
||||
ppm_flip_h(const unsigned int* buf, const PPM img)
|
||||
{
|
||||
unsigned int* flip = malloc(img.len * sizeof(unsigned int));
|
||||
if (!flip)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
int idx = 0;
|
||||
for (int i = 0; i < img.height; i++)
|
||||
{
|
||||
for (int k = img.width - 1; k >= 0; k--)
|
||||
{
|
||||
flip[idx] = buf[(i * img.width) + k];
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
return flip;
|
||||
}
|
||||
|
||||
unsigned int*
|
||||
ppm_flip_v(const unsigned int* buf, const PPM img)
|
||||
{
|
||||
unsigned int* flip = malloc(img.len * sizeof(unsigned int));
|
||||
if (!flip)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int idx = 0;
|
||||
for (int i = img.height - 1; i >= 0; i--)
|
||||
{
|
||||
for (int k = 0; k < img.width; k++)
|
||||
{
|
||||
flip[idx] = buf[(i * img.width) + k];
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
return flip;
|
||||
}
|
||||
|
||||
unsigned int*
|
||||
u32_rotate(const unsigned int* buf, PPM* m_img, const int len)
|
||||
{
|
||||
unsigned int* mask = malloc(len * sizeof(unsigned int));
|
||||
int old_width = m_img->width;
|
||||
int old_height = m_img->height;
|
||||
for (int row = 0; row < old_height; row++)
|
||||
{
|
||||
for (int col = 0; col < old_width; col++)
|
||||
{
|
||||
int new_height = col;
|
||||
int new_width = (old_height - 1 - row);
|
||||
|
||||
mask[(new_height * old_height) + new_width] =
|
||||
buf[(row * old_width) + col];
|
||||
}
|
||||
}
|
||||
m_img->width = old_height;
|
||||
m_img->height = old_width;
|
||||
return mask;
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
#include "utils.h"
|
||||
|
||||
unsigned long
|
||||
u32to_u64(const unsigned int clr)
|
||||
{
|
||||
unsigned long mask = 0;
|
||||
unsigned long alpha = DECODE_A(clr);
|
||||
unsigned long red = DECODE_R(clr);
|
||||
unsigned long green = DECODE_G(clr);
|
||||
unsigned long blue = DECODE_B(clr);
|
||||
return (alpha << 48) | (red << 32) | (green << 16) | (blue);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
u64to_u32(const unsigned long clr, const unsigned long u64_div)
|
||||
{
|
||||
unsigned int a = ((clr >> 48) & LONG_BYTE);
|
||||
unsigned int r = ((clr >> 32) & LONG_BYTE);
|
||||
unsigned int g = ((clr >> 16) & LONG_BYTE);
|
||||
unsigned int b = (clr & LONG_BYTE);
|
||||
return ENCODE_ARGB((a / u64_div), (r / u64_div), (g / u64_div),
|
||||
(b / u64_div));
|
||||
}
|
||||
Reference in New Issue
Block a user