Files
libimg/src/filters.c
T

218 lines
4.8 KiB
C

#include <stdlib.h>
// #include "utils.h"
#include "image/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;
}