~macslow/cairo-countdown/trunk

« back to all changes in this revision

Viewing changes to gaussian-blur.c

  • Committer: Mirco Müller
  • Date: 2014-04-18 17:38:09 UTC
  • Revision ID: mirco.mueller@ubuntu.com-20140418173809-f9g2s6fjnr938few
Use pixman-convolution-based 2-pass 1D-gaussian-blur in ANSI-C version... started porting that to the Python version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
////////////////////////////////////////////////////////////////////////////////
2
 
//3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789
3
 
//      10        20        30        40        50        60        70        80
4
 
//
5
 
// raico-blur
6
 
//
7
 
// gaussian-blur.c - implements gaussian-blur function
8
 
//
9
 
// Copyright 2009 Canonical Ltd.
10
 
//
11
 
// Authors:
12
 
//    Mirco "MacSlow" Mueller <mirco.mueller@canonical.com>
13
 
//
14
 
// Notes:
15
 
//    based on filters in libpixman
16
 
//
17
 
// This program is free software: you can redistribute it and/or modify it
18
 
// under the terms of the GNU General Public License version 3, as published
19
 
// by the Free Software Foundation.
20
 
//
21
 
// This program is distributed in the hope that it will be useful, but
22
 
// WITHOUT ANY WARRANTY; without even the implied warranties of
23
 
// MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
24
 
// PURPOSE.  See the GNU General Public License for more details.
25
 
//
26
 
// You should have received a copy of the GNU General Public License along
27
 
// with this program.  If not, see <http://www.gnu.org/licenses/>.
28
 
//
29
 
////////////////////////////////////////////////////////////////////////////////
30
 
 
31
 
#include <math.h>
32
 
#include <pixman.h>
33
 
 
34
 
#include "gaussian-blur.h"
35
 
 
36
 
pixman_fixed_t*
37
 
create_gaussian_blur_kernel (gint    radius,
38
 
                             gdouble sigma,
39
 
                             gint*   length)
40
 
{
41
 
        const gdouble   scale2 = 2.0f * sigma * sigma;
42
 
        const gdouble   scale1 = 1.0f / (G_PI * scale2);
43
 
        const gint      size = 2 * radius + 1;
44
 
        const gint      n_params = size * size;
45
 
        pixman_fixed_t* params;
46
 
        gdouble*        tmp;
47
 
        gdouble         sum;
48
 
        gint            x;
49
 
        gint            y;
50
 
        gint            i;
51
 
 
52
 
        tmp = g_newa (double, n_params);
53
 
 
54
 
        // caluclate gaussian kernel in floating point format
55
 
        for (i = 0, sum = 0, x = -radius; x <= radius; ++x) {
56
 
                for (y = -radius; y <= radius; ++y, ++i) {
57
 
                        const gdouble u = x * x;
58
 
                        const gdouble v = y * y;
59
 
 
60
 
                        tmp[i] = scale1 * exp (-(u+v)/scale2);
61
 
 
62
 
                        sum += tmp[i];
63
 
                }
64
 
        }
65
 
 
66
 
        // normalize gaussian kernel and convert to fixed point format
67
 
        params = g_new (pixman_fixed_t, n_params + 2);
68
 
 
69
 
        params[0] = pixman_int_to_fixed (size);
70
 
        params[1] = pixman_int_to_fixed (size);
71
 
 
72
 
        for (i = 0; i < n_params; ++i)
73
 
                params[2 + i] = pixman_double_to_fixed (tmp[i] / sum);
74
 
 
75
 
        if (length)
76
 
                *length = n_params + 2;
77
 
 
78
 
        return params;
79
 
}
80
 
 
81
 
void
82
 
_blur_image_surface (cairo_surface_t* surface,
83
 
                     gint             radius,
84
 
                     gdouble          sigma /* pass 0.0f for auto-calculation */)
85
 
{
86
 
        pixman_fixed_t* params = NULL;
87
 
        gint            n_params;
88
 
        pixman_image_t* src;
89
 
        gint            w;
90
 
        gint            h;
91
 
        gint            s;
92
 
        gpointer        p;
93
 
        gdouble         radiusf;
94
 
 
95
 
        radiusf = fabs (radius) + 1.0f;
96
 
        if (sigma == 0.0f)
97
 
                sigma = sqrt (-(radiusf * radiusf) / (2.0f * log (1.0f / 255.0f)));
98
 
 
99
 
        w = cairo_image_surface_get_width (surface);
100
 
        h = cairo_image_surface_get_height (surface);
101
 
        s = cairo_image_surface_get_stride (surface);
102
 
 
103
 
        // create pixman image for cairo image surface
104
 
        p = cairo_image_surface_get_data (surface);
105
 
        src = pixman_image_create_bits (PIXMAN_a8r8g8b8, w, h, p, s);
106
 
 
107
 
        // attach gaussian kernel to pixman image
108
 
        params = create_gaussian_blur_kernel (radius, sigma, &n_params);
109
 
        pixman_image_set_filter (src,
110
 
                                 PIXMAN_FILTER_CONVOLUTION,
111
 
                                 params,
112
 
                                 n_params);
113
 
        g_free (params);
114
 
 
115
 
        // render blured image to new pixman image
116
 
        pixman_image_composite (PIXMAN_OP_SRC,
117
 
                                src,
118
 
                                NULL,
119
 
                                src,
120
 
                                0,
121
 
                                0,
122
 
                                0,
123
 
                                0,
124
 
                                0,
125
 
                                0,
126
 
                                w,
127
 
                                h);
128
 
        pixman_image_unref (src);
129
 
}
130
 
 
131
 
void
132
 
surface_gaussian_blur (cairo_surface_t* surface,
133
 
                       guint            radius)
134
 
{
135
 
        cairo_format_t format;
136
 
 
137
 
        // sanity checks are done in raico-blur.c
138
 
 
139
 
        // before we mess with the surface execute any pending drawing
140
 
        cairo_surface_flush (surface);
141
 
 
142
 
        format = cairo_image_surface_get_format (surface);
143
 
 
144
 
        switch (format)
145
 
        {
146
 
                case CAIRO_FORMAT_ARGB32:
147
 
                        _blur_image_surface (surface, radius, 0.0f);
148
 
                break;
149
 
 
150
 
                case CAIRO_FORMAT_RGB24:
151
 
                        // do nothing, for now
152
 
                break;
153
 
 
154
 
                case CAIRO_FORMAT_A8:
155
 
                        // do nothing, for now
156
 
                break;
157
 
 
158
 
                default :
159
 
                        // do nothing
160
 
                break;
161
 
        }
162
 
 
163
 
        // inform cairo we altered the surfaces contents
164
 
        cairo_surface_mark_dirty (surface);     
165
 
}
166