#include // #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; }