diff options
Diffstat (limited to 'mate-screenshot/screenshot-shadow.c')
-rw-r--r-- | mate-screenshot/screenshot-shadow.c | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/mate-screenshot/screenshot-shadow.c b/mate-screenshot/screenshot-shadow.c new file mode 100644 index 00000000..913429db --- /dev/null +++ b/mate-screenshot/screenshot-shadow.c @@ -0,0 +1,231 @@ +/* screenshot-shadow.c - part of MATE Screenshot + * + * Copyright (C) 2001-2006 Jonathan Blandford <[email protected]> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + */ + +/* Shadow code from anders */ + +#include "screenshot-shadow.h" +#include <math.h> + +#define BLUR_RADIUS 5 +#define SHADOW_OFFSET (BLUR_RADIUS * 4 / 5) +#define SHADOW_OPACITY 0.5 + +#define OUTLINE_RADIUS 1 +#define OUTLINE_OFFSET 0 +#define OUTLINE_OPACITY 1.0 + +#define dist(x0, y0, x1, y1) sqrt(((x0) - (x1))*((x0) - (x1)) + ((y0) - (y1))*((y0) - (y1))) + +typedef struct { + int size; + double *data; +} ConvFilter; + +static double +gaussian (double x, double y, double r) +{ + return ((1 / (2 * M_PI * r)) * + exp ((- (x * x + y * y)) / (2 * r * r))); +} + +static ConvFilter * +create_blur_filter (int radius) +{ + ConvFilter *filter; + int x, y; + double sum; + + filter = g_new0 (ConvFilter, 1); + filter->size = radius * 2 + 1; + filter->data = g_new (double, filter->size * filter->size); + + sum = 0.0; + + for (y = 0 ; y < filter->size; y++) + { + for (x = 0 ; x < filter->size; x++) + { + sum += filter->data[y * filter->size + x] = gaussian (x - (filter->size >> 1), + y - (filter->size >> 1), + radius); + } + } + + for (y = 0; y < filter->size; y++) + { + for (x = 0; x < filter->size; x++) + { + filter->data[y * filter->size + x] /= sum; + } + } + + return filter; + +} + +static ConvFilter * +create_outline_filter (int radius) +{ + ConvFilter *filter; + double *iter; + + filter = g_new0 (ConvFilter, 1); + filter->size = radius * 2 + 1; + filter->data = g_new (double, filter->size * filter->size); + + for (iter = filter->data; + iter < filter->data + (filter->size * filter->size); + iter++) + { + *iter = 1.0; + } + + return filter; +} + +static GdkPixbuf * +create_effect (GdkPixbuf *src, + ConvFilter const *filter, + int radius, + int offset, + double opacity) +{ + GdkPixbuf *dest; + int x, y, i, j; + int src_x, src_y; + int suma; + int dest_width, dest_height; + int src_width, src_height; + int src_rowstride, dest_rowstride; + gboolean src_has_alpha; + + guchar *src_pixels, *dest_pixels; + + src_has_alpha = gdk_pixbuf_get_has_alpha (src); + + src_width = gdk_pixbuf_get_width (src); + src_height = gdk_pixbuf_get_height (src); + dest_width = src_width + 2 * radius + offset; + dest_height = src_height + 2 * radius + offset; + + dest = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src), + TRUE, + gdk_pixbuf_get_bits_per_sample (src), + dest_width, dest_height); + + gdk_pixbuf_fill (dest, 0); + + src_pixels = gdk_pixbuf_get_pixels (src); + src_rowstride = gdk_pixbuf_get_rowstride (src); + + dest_pixels = gdk_pixbuf_get_pixels (dest); + dest_rowstride = gdk_pixbuf_get_rowstride (dest); + + for (y = 0; y < dest_height; y++) + { + for (x = 0; x < dest_width; x++) + { + suma = 0; + + src_x = x - radius; + src_y = y - radius; + + /* We don't need to compute effect here, since this pixel will be + * discarded when compositing */ + if (src_x >= 0 && src_x < src_width && + src_y >= 0 && src_y < src_height && + (!src_has_alpha || + src_pixels [src_y * src_rowstride + src_x * 4 + 3] == 0xFF)) + continue; + + for (i = 0; i < filter->size; i++) + { + for (j = 0; j < filter->size; j++) + { + src_y = -(radius + offset) + y - (filter->size >> 1) + i; + src_x = -(radius + offset) + x - (filter->size >> 1) + j; + + if (src_y < 0 || src_y >= src_height || + src_x < 0 || src_x >= src_width) + continue; + + suma += ( src_has_alpha ? + src_pixels [src_y * src_rowstride + src_x * 4 + 3] : + 0xFF ) * filter->data [i * filter->size + j]; + } + } + + dest_pixels [y * dest_rowstride + x * 4 + 3] = CLAMP (suma * opacity, 0x00, 0xFF); + } + } + + return dest; +} + +void +screenshot_add_shadow (GdkPixbuf **src) +{ + GdkPixbuf *dest; + static ConvFilter *filter = NULL; + + if (!filter) + filter = create_blur_filter (BLUR_RADIUS); + + dest = create_effect (*src, filter, + BLUR_RADIUS, + SHADOW_OFFSET, SHADOW_OPACITY); + + if (dest == NULL) + return; + + gdk_pixbuf_composite (*src, dest, + BLUR_RADIUS, BLUR_RADIUS, + gdk_pixbuf_get_width (*src), + gdk_pixbuf_get_height (*src), + BLUR_RADIUS, BLUR_RADIUS, 1.0, 1.0, + GDK_INTERP_BILINEAR, 255); + g_object_unref (*src); + *src = dest; +} + +void +screenshot_add_border (GdkPixbuf **src) +{ + GdkPixbuf *dest; + static ConvFilter *filter = NULL; + + if (!filter) + filter = create_outline_filter (OUTLINE_RADIUS); + + dest = create_effect (*src, filter, + OUTLINE_RADIUS, + OUTLINE_OFFSET, OUTLINE_OPACITY); + + if (dest == NULL) + return; + + gdk_pixbuf_composite (*src, dest, + OUTLINE_RADIUS, OUTLINE_RADIUS, + gdk_pixbuf_get_width (*src), + gdk_pixbuf_get_height (*src), + OUTLINE_RADIUS, OUTLINE_RADIUS, 1.0, 1.0, + GDK_INTERP_BILINEAR, 255); + g_object_unref (*src); + *src = dest; +} |