Skip to content

Commit

Permalink
Add the Gaussian function to blur a pixmap
Browse files Browse the repository at this point in the history
Use Pascal's Triangle to approximate a 5x5 Gaussian Kernel, and apply
Gaussian blur on the 'twin_pixmap_t' to implement the blurring
technique.

See: sysprog21#34
  • Loading branch information
weihsinyeh committed Oct 6, 2024
1 parent 980bd4c commit 00ecebe
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 1 deletion.
2 changes: 2 additions & 0 deletions include/twin.h
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,8 @@ void twin_fill(twin_pixmap_t *dst,

void twin_premultiply_alpha(twin_pixmap_t *px);

void twin_gaussian_blur(twin_pixmap_t *px);

/*
* event.c
*/
Expand Down
15 changes: 15 additions & 0 deletions include/twin_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,21 @@ void _twin_button_init(twin_button_t *button,

/* utility */

#define min(x, y) \
({ \
typeof(x) _x = (x); \
typeof(y) _y = (y); \
(void) (&_x == &_y); \
_x < _y ? _x : _y; \
})

#define max(x, y) \
({ \
typeof(x) _x = (x); \
typeof(y) _y = (y); \
(void) (&_x == &_y); \
_x > _y ? _x : _y; \
})
#ifdef _MSC_VER
#include <intrin.h>
static inline int twin_clz(uint32_t v)
Expand Down
3 changes: 2 additions & 1 deletion mk/common.mk
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ RM := rm -rf
MKDIR := mkdir -p

__CFLAGS := -Wall -Wextra
__CFLAGS += -O2
__CFLAGS += -O2 -pipe -g
__CFLAGS += -fsanitize=address -static-libasan
__CFLAGS += $(CFLAGS)

uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
Expand Down
49 changes: 49 additions & 0 deletions src/draw.c
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,55 @@ void twin_premultiply_alpha(twin_pixmap_t *px)
}
}

static twin_argb32_t _twin_apply_gaussian(twin_argb32_t v,
uint8_t wght,
twin_argb32_t *r,
twin_argb32_t *g,
twin_argb32_t *b)
{
*r += ((((v & 0x00ff0000) >> 16) * (twin_argb32_t) wght) << 8) & 0x00ff0000;
*g += (((v & 0x0000ff00) >> 8) * (twin_argb32_t) wght) & 0x0000ff00;
*b += ((((v & 0x000000ff) >> 0) * (twin_argb32_t) wght) >> 8) & 0x000000ff;
}

void twin_gaussian_blur(twin_pixmap_t *px)
{
if (px->format != TWIN_ARGB32)
return;

uint8_t kernel[5][5] = {{0x01, 0x04, 0x06, 0x04, 0x01},
{0x04, 0x10, 0x18, 0x10, 0x04},
{0x06, 0x18, 0x24, 0x18, 0x06},
{0x04, 0x10, 0x18, 0x10, 0x04},
{0x01, 0x04, 0x06, 0x04, 0x01}};
twin_pointer_t ptr, tmp_ptr;
twin_pixmap_t *tmp_px =
twin_pixmap_create(px->format, px->width, px->height);
memcpy(tmp_px->p.v, px->p.v,
px->width * px->height * twin_bytes_per_pixel(px->format));

int radius = 2, _y, _x;
twin_argb32_t r, g, b;
for (int screen_y = 0; screen_y < px->height; screen_y++)
for (int screen_x = 0; screen_x < px->width; screen_x++) {
r = 0, g = 0, b = 0;
ptr = twin_pixmap_pointer(px, screen_x, screen_y);
for (int y = -radius; y <= radius; y++) {
_y = min(max(screen_y + y, 0), px->height - 1);
for (int x = -radius; x <= radius; x++) {
_x = min(max(screen_x + x, 0), px->width - 1);
tmp_ptr = twin_pixmap_pointer(tmp_px, _x, _y);
_twin_apply_gaussian(*tmp_ptr.argb32,
kernel[x + radius][y + radius], &r, &g,
&b);
}
}
*ptr.argb32 = (*ptr.argb32 & 0xff000000) | r | g | b;
}

twin_pixmap_destroy(tmp_px);
}

/*
* array primary index is OVER SOURCE
* array secondary index is ARGB32 RGB16 A8
Expand Down
1 change: 1 addition & 0 deletions src/image-png.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ twin_pixmap_t *_twin_png_to_pixmap(const char *filepath, twin_format_t fmt)
_convertBGRtoARGB(pix->p.b, width, height);
#endif
twin_premultiply_alpha(pix);
twin_gaussian_blur(pix);
}

bail_free:
Expand Down

0 comments on commit 00ecebe

Please sign in to comment.