File: gaussian-blur.c

package info (click to toggle)
notify-osd 0.9.35%2B15.04.20150126-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, buster, stretch
  • size: 2,016 kB
  • ctags: 1,837
  • sloc: ansic: 17,819; python: 1,100; makefile: 457; cs: 335; sh: 103; xml: 48
file content (166 lines) | stat: -rw-r--r-- 4,516 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
////////////////////////////////////////////////////////////////////////////////
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
//      10        20        30        40        50        60        70        80
//
// raico-blur
//
// gaussian-blur.c - implements gaussian-blur function
//
// Copyright 2009 Canonical Ltd.
//
// Authors:
//    Mirco "MacSlow" Mueller <mirco.mueller@canonical.com>
//
// Notes:
//    based on filters in libpixman
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 3, as published
// by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranties of
// MERCHANTABILITY, SATISFACTORY QUALITY, 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, see <http://www.gnu.org/licenses/>.
//
////////////////////////////////////////////////////////////////////////////////

#include <math.h>
#include <pixman.h>

#include "gaussian-blur.h"

pixman_fixed_t*
create_gaussian_blur_kernel (gint    radius,
                             gdouble sigma,
                             gint*   length)
{
	const gdouble   scale2 = 2.0f * sigma * sigma;
	const gdouble   scale1 = 1.0f / (G_PI * scale2);
	const gint      size = 2 * radius + 1;
	const gint      n_params = size * size;
	pixman_fixed_t* params;
	gdouble*        tmp;
	gdouble         sum;
	gint            x;
	gint            y;
	gint            i;

        tmp = g_newa (double, n_params);

        // caluclate gaussian kernel in floating point format
        for (i = 0, sum = 0, x = -radius; x <= radius; ++x) {
                for (y = -radius; y <= radius; ++y, ++i) {
                        const gdouble u = x * x;
                        const gdouble v = y * y;

                        tmp[i] = scale1 * exp (-(u+v)/scale2);

                        sum += tmp[i];
                }
        }

        // normalize gaussian kernel and convert to fixed point format
        params = g_new (pixman_fixed_t, n_params + 2);

        params[0] = pixman_int_to_fixed (size);
        params[1] = pixman_int_to_fixed (size);

        for (i = 0; i < n_params; ++i)
                params[2 + i] = pixman_double_to_fixed (tmp[i] / sum);

        if (length)
                *length = n_params + 2;

        return params;
}

void
_blur_image_surface (cairo_surface_t* surface,
		     gint             radius,
		     gdouble          sigma /* pass 0.0f for auto-calculation */)
{
        pixman_fixed_t* params = NULL;
        gint            n_params;
        pixman_image_t* src;
        gint            w;
        gint            h;
        gint            s;
        gpointer        p;
	gdouble         radiusf;

	radiusf = fabs (radius) + 1.0f;
	if (sigma == 0.0f)
		sigma = sqrt (-(radiusf * radiusf) / (2.0f * log (1.0f / 255.0f)));

        w = cairo_image_surface_get_width (surface);
        h = cairo_image_surface_get_height (surface);
        s = cairo_image_surface_get_stride (surface);

	// create pixman image for cairo image surface
	p = cairo_image_surface_get_data (surface);
	src = pixman_image_create_bits (PIXMAN_a8r8g8b8, w, h, p, s);

	// attach gaussian kernel to pixman image
	params = create_gaussian_blur_kernel (radius, sigma, &n_params);
	pixman_image_set_filter (src,
				 PIXMAN_FILTER_CONVOLUTION,
				 params,
				 n_params);
	g_free (params);

        // render blured image to new pixman image
        pixman_image_composite (PIXMAN_OP_SRC,
				src,
				NULL,
				src,
				0,
				0,
				0,
				0,
				0,
				0,
				w,
				h);
	pixman_image_unref (src);
}

void
surface_gaussian_blur (cairo_surface_t* surface,
		       guint            radius)
{
	cairo_format_t format;

	// sanity checks are done in raico-blur.c

	// before we mess with the surface execute any pending drawing
	cairo_surface_flush (surface);

	format = cairo_image_surface_get_format (surface);

	switch (format)
	{
		case CAIRO_FORMAT_ARGB32:
			_blur_image_surface (surface, radius, 0.0f);
		break;

		case CAIRO_FORMAT_RGB24:
			// do nothing, for now
		break;

		case CAIRO_FORMAT_A8:
			// do nothing, for now
		break;

		default :
			// do nothing
		break;
	}

	// inform cairo we altered the surfaces contents
	cairo_surface_mark_dirty (surface);	
}