diff --git a/blur.c b/blur.c new file mode 100644 index 0000000..feb2a53 --- /dev/null +++ b/blur.c @@ -0,0 +1,97 @@ +#include +#include +#include +#include + +#include "blur.h" + +void _blur_bitmap(uint8_t bytes_per_pixel, uint8_t *source, uint8_t *result, + uint32_t width, uint32_t height, int ksize) { + uint32_t *temp; + int px; + + temp = malloc(sizeof(uint32_t) * bytes_per_pixel * width * height); + + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + px = bytes_per_pixel * (x + width * y); + for (int i = 0; i < bytes_per_pixel; ++i) { + temp[px + i] = source[px + i]; + if (x != 0) + temp[px + i] += temp[px - bytes_per_pixel + i]; + if (y != 0) + temp[px + i] += temp[px - bytes_per_pixel * width + i]; + if (x != 0 && y != 0) + temp[px + i] -= temp[px - bytes_per_pixel * (width + 1) + i]; + } + } + } + + double filter = (double)1 / (4 * ksize * ksize); + uint32_t t; + + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + int x_min, x_max, y_min, y_max; + + if ((x_min = x - ksize) < 0) + x_min = 0; + if ((x_max = x + ksize) > width - 1) + x_max = width - 1; + if ((y_min = y - ksize) < 0) + y_min = 0; + if ((y_max = y + ksize) > height - 1) + y_max = height - 1; + + px = bytes_per_pixel * (x + width * y); + + for (int i = 0; i < bytes_per_pixel; ++i) { + t = temp[bytes_per_pixel * (x_min + width * y_min) + i]; + t += temp[bytes_per_pixel * (x_max + width * y_max) + i]; + t -= temp[bytes_per_pixel * (x_max + width * y_min) + i]; + t -= temp[bytes_per_pixel * (x_min + width * y_max) + i]; + t *= filter; + result[px + i] = t; + } + } + } + + free(temp); +} + +void blur_surface(cairo_surface_t *img, int kernel_size) { + unsigned char *data, *temp; + + uint32_t width, height; + uint8_t bytes_per_pixel; + + cairo_format_t pixel_format = cairo_image_surface_get_format(img); + width = cairo_image_surface_get_width(img); + height = cairo_image_surface_get_height(img); + data = cairo_image_surface_get_data(img); + + switch (pixel_format) { + case CAIRO_FORMAT_RGB24: + case CAIRO_FORMAT_ARGB32: + bytes_per_pixel = 4; + break; + default: + // We don't handle other formats + return; + } + + temp = malloc(bytes_per_pixel * sizeof(uint8_t) * width * height); + + cairo_surface_flush(img); + + // 3 times would be enough, but doing it equal number of times so we + // get result in right buffer + _blur_bitmap(bytes_per_pixel, data, temp, width, height, kernel_size); + _blur_bitmap(bytes_per_pixel, temp, data, width, height, kernel_size); + _blur_bitmap(bytes_per_pixel, data, temp, width, height, kernel_size); + _blur_bitmap(bytes_per_pixel, temp, data, width, height, kernel_size); + + cairo_surface_mark_dirty(img); + + free(temp); +} diff --git a/blur.h b/blur.h new file mode 100644 index 0000000..4a105a6 --- /dev/null +++ b/blur.h @@ -0,0 +1,4 @@ +#ifndef __JS_BLUR +#define __JS_BLUR +void blur_surface(cairo_surface_t *img, int kernel_size); +#endif diff --git a/i3lock.c b/i3lock.c index 8f59230..e78f804 100644 --- a/i3lock.c +++ b/i3lock.c @@ -30,6 +30,7 @@ #include #include "i3lock.h" +#include "blur.h" #include "xcb.h" #include "cursors.h" #include "unlock_indicator.h" @@ -66,7 +67,7 @@ extern unlock_state_t unlock_state; extern pam_state_t pam_state; int failed_attempts = 0; bool show_failed_attempts = false; -bool blur = false; +int blur = 0; static struct xkb_state *xkb_state; static struct xkb_context *xkb_context; @@ -749,7 +750,7 @@ int main(int argc, char *argv[]) { {"version", no_argument, NULL, 'v'}, {"nofork", no_argument, NULL, 'n'}, {"beep", no_argument, NULL, 'b'}, - {"blur", no_argument, NULL, 0}, + {"blur", required_argument, NULL, 0}, {"dpms", no_argument, NULL, 'd'}, {"color", required_argument, NULL, 'c'}, {"pointer", required_argument, NULL, 'p'}, @@ -825,8 +826,12 @@ int main(int argc, char *argv[]) { case 0: if (strcmp(longopts[optind].name, "debug") == 0) debug_mode = true; - if (strcmp(longopts[optind].name, "blur") == 0) - blur = true; + if (strcmp(longopts[optind].name, "blur") == 0) { + int kernel = 0; + if (sscanf(optarg, "%d", &kernel) != 1 || time < 0) + errx(EXIT_FAILURE, "invalid kernel size, it must be a positive integer\n"); + blur = kernel; + } break; case 'f': show_failed_attempts = true; @@ -938,8 +943,8 @@ int main(int argc, char *argv[]) { } } - if(blur && img != NULL) { - // blur handling goes here + if(blur > 0 && img != NULL) { + blur_surface(img, blur); } /* Pixmap on which the image is rendered to (if any) */