2 * Copyright 2012, Red Hat, Inc.
3 * Copyright 2012, Soren Sandmann
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
24 * Author: Soren Sandmann <soren.sandmann@gmail.com>
34 #include "pixman-private.h"
36 typedef double (* kernel_func_t
) (double x
);
40 pixman_kernel_t kernel
;
46 impulse_kernel (double x
)
48 return (x
== 0.0)? 1.0 : 0.0;
58 linear_kernel (double x
)
64 gaussian_kernel (double x
)
66 #define SQRT2 (1.4142135623730950488016887242096980785696718753769480)
67 #define SIGMA (SQRT2 / 2.0)
69 return exp (- x
* x
/ (2 * SIGMA
* SIGMA
)) / (SIGMA
* sqrt (2.0 * M_PI
));
78 return sin (M_PI
* x
) / (M_PI
* x
);
82 lanczos (double x
, int n
)
84 return sinc (x
) * sinc (x
* (1.0 / n
));
88 lanczos2_kernel (double x
)
90 return lanczos (x
, 2);
94 lanczos3_kernel (double x
)
96 return lanczos (x
, 3);
100 nice_kernel (double x
)
102 return lanczos3_kernel (x
* 0.75);
106 general_cubic (double x
, double B
, double C
)
112 return ((12 - 9 * B
- 6 * C
) * ax
* ax
* ax
+
113 (-18 + 12 * B
+ 6 * C
) * ax
* ax
+ (6 - 2 * B
)) / 6;
115 else if (ax
>= 1 && ax
< 2)
117 return ((-B
- 6 * C
) * ax
* ax
* ax
+
118 (6 * B
+ 30 * C
) * ax
* ax
+ (-12 * B
- 48 * C
) *
119 ax
+ (8 * B
+ 24 * C
)) / 6;
128 cubic_kernel (double x
)
130 /* This is the Mitchell-Netravali filter.
132 * (0.0, 0.5) would give us the Catmull-Rom spline,
133 * but that one seems to be indistinguishable from Lanczos2.
135 return general_cubic (x
, 1/3.0, 1/3.0);
138 static const filter_info_t filters
[] =
140 { PIXMAN_KERNEL_IMPULSE
, impulse_kernel
, 0.0 },
141 { PIXMAN_KERNEL_BOX
, box_kernel
, 1.0 },
142 { PIXMAN_KERNEL_LINEAR
, linear_kernel
, 2.0 },
143 { PIXMAN_KERNEL_CUBIC
, cubic_kernel
, 4.0 },
144 { PIXMAN_KERNEL_GAUSSIAN
, gaussian_kernel
, 6 * SIGMA
},
145 { PIXMAN_KERNEL_LANCZOS2
, lanczos2_kernel
, 4.0 },
146 { PIXMAN_KERNEL_LANCZOS3
, lanczos3_kernel
, 6.0 },
147 { PIXMAN_KERNEL_LANCZOS3_STRETCHED
, nice_kernel
, 8.0 },
150 /* This function scales @kernel2 by @scale, then
151 * aligns @x1 in @kernel1 with @x2 in @kernel2 and
152 * and integrates the product of the kernels across @width.
154 * This function assumes that the intervals are within
155 * the kernels in question. E.g., the caller must not
156 * try to integrate a linear kernel ouside of [-1:1]
159 integral (pixman_kernel_t kernel1
, double x1
,
160 pixman_kernel_t kernel2
, double scale
, double x2
,
163 /* If the integration interval crosses zero, break it into
164 * two separate integrals. This ensures that filters such
165 * as LINEAR that are not differentiable at 0 will still
166 * integrate properly.
168 if (x1
< 0 && x1
+ width
> 0)
171 integral (kernel1
, x1
, kernel2
, scale
, x2
, - x1
) +
172 integral (kernel1
, 0, kernel2
, scale
, x2
- x1
, width
+ x1
);
174 else if (x2
< 0 && x2
+ width
> 0)
177 integral (kernel1
, x1
, kernel2
, scale
, x2
, - x2
) +
178 integral (kernel1
, x1
- x2
, kernel2
, scale
, 0, width
+ x2
);
180 else if (kernel1
== PIXMAN_KERNEL_IMPULSE
)
182 assert (width
== 0.0);
183 return filters
[kernel2
].func (x2
* scale
);
185 else if (kernel2
== PIXMAN_KERNEL_IMPULSE
)
187 assert (width
== 0.0);
188 return filters
[kernel1
].func (x1
);
192 /* Integration via Simpson's rule */
193 #define N_SEGMENTS 128
194 #define SAMPLE(a1, a2) \
195 (filters[kernel1].func ((a1)) * filters[kernel2].func ((a2) * scale))
198 double h
= width
/ (double)N_SEGMENTS
;
203 for (i
= 1; i
< N_SEGMENTS
; i
+= 2)
205 double a1
= x1
+ h
* i
;
206 double a2
= x2
+ h
* i
;
208 s
+= 2 * SAMPLE (a1
, a2
);
210 if (i
>= 2 && i
< N_SEGMENTS
- 1)
211 s
+= 4 * SAMPLE (a1
, a2
);
214 s
+= SAMPLE (x1
+ width
, x2
+ width
);
216 return h
* s
* (1.0 / 3.0);
220 static pixman_fixed_t
*
221 create_1d_filter (int *width
,
222 pixman_kernel_t reconstruct
,
223 pixman_kernel_t sample
,
227 pixman_fixed_t
*params
, *p
;
232 size
= scale
* filters
[sample
].width
+ filters
[reconstruct
].width
;
233 *width
= ceil (size
);
235 p
= params
= malloc (*width
* n_phases
* sizeof (pixman_fixed_t
));
239 step
= 1.0 / n_phases
;
241 for (i
= 0; i
< n_phases
; ++i
)
243 double frac
= step
/ 2.0 + i
* step
;
244 pixman_fixed_t new_total
;
248 /* Sample convolution of reconstruction and sampling
249 * filter. See rounding.txt regarding the rounding
250 * and sample positions.
253 x1
= ceil (frac
- *width
/ 2.0 - 0.5);
257 for (x
= x1
; x
< x2
; ++x
)
259 double pos
= x
+ 0.5 - frac
;
260 double rlow
= - filters
[reconstruct
].width
/ 2.0;
261 double rhigh
= rlow
+ filters
[reconstruct
].width
;
262 double slow
= pos
- scale
* filters
[sample
].width
/ 2.0;
263 double shigh
= slow
+ scale
* filters
[sample
].width
;
267 if (rhigh
>= slow
&& rlow
<= shigh
)
269 ilow
= MAX (slow
, rlow
);
270 ihigh
= MIN (shigh
, rhigh
);
272 c
= integral (reconstruct
, ilow
,
273 sample
, 1.0 / scale
, ilow
- pos
,
278 *p
++ = (pixman_fixed_t
)(c
* 65536.0 + 0.5);
285 for (x
= x1
; x
< x2
; ++x
)
287 pixman_fixed_t t
= (*p
) * total
+ 0.5;
293 if (new_total
!= pixman_fixed_1
)
294 *(p
- *width
/ 2) += (pixman_fixed_1
- new_total
);
300 /* Create the parameter list for a SEPARABLE_CONVOLUTION filter
301 * with the given kernels and scale parameters
303 PIXMAN_EXPORT pixman_fixed_t
*
304 pixman_filter_create_separable_convolution (int *n_values
,
305 pixman_fixed_t scale_x
,
306 pixman_fixed_t scale_y
,
307 pixman_kernel_t reconstruct_x
,
308 pixman_kernel_t reconstruct_y
,
309 pixman_kernel_t sample_x
,
310 pixman_kernel_t sample_y
,
311 int subsample_bits_x
,
312 int subsample_bits_y
)
314 double sx
= fabs (pixman_fixed_to_double (scale_x
));
315 double sy
= fabs (pixman_fixed_to_double (scale_y
));
316 pixman_fixed_t
*horz
= NULL
, *vert
= NULL
, *params
= NULL
;
317 int subsample_x
, subsample_y
;
320 subsample_x
= (1 << subsample_bits_x
);
321 subsample_y
= (1 << subsample_bits_y
);
323 horz
= create_1d_filter (&width
, reconstruct_x
, sample_x
, sx
, subsample_x
);
324 vert
= create_1d_filter (&height
, reconstruct_y
, sample_y
, sy
, subsample_y
);
329 *n_values
= 4 + width
* subsample_x
+ height
* subsample_y
;
331 params
= malloc (*n_values
* sizeof (pixman_fixed_t
));
335 params
[0] = pixman_int_to_fixed (width
);
336 params
[1] = pixman_int_to_fixed (height
);
337 params
[2] = pixman_int_to_fixed (subsample_bits_x
);
338 params
[3] = pixman_int_to_fixed (subsample_bits_y
);
340 memcpy (params
+ 4, horz
,
341 width
* subsample_x
* sizeof (pixman_fixed_t
));
342 memcpy (params
+ 4 + width
* subsample_x
, vert
,
343 height
* subsample_y
* sizeof (pixman_fixed_t
));