[Pixman] [PATCH pixman 14/15] pixman-filter: Gaussian fixes
The SIGMA term drops out on simplification. Expanded the size slightly (from ~4.25 to 5) to make the cutoff less noticable. The filter is truncated at a value of .001 instead of .006, this new value is less than 1/2 of 1/255, rather than greater than it. --- pixman/pixman-filter.c |7 ++- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c index bf9dce3..7d7b381 100644 --- a/pixman/pixman-filter.c +++ b/pixman/pixman-filter.c @@ -63,10 +63,7 @@ linear_kernel (double x) static double gaussian_kernel (double x) { -#define SQRT2 (1.4142135623730950488016887242096980785696718753769480) -#define SIGMA (SQRT2 / 2.0) - -return exp (- x * x / (2 * SIGMA * SIGMA)) / (SIGMA * sqrt (2.0 * M_PI)); +return exp (- x * x) / sqrt (M_PI); } static double @@ -139,7 +136,7 @@ static const filter_info_t filters[] = { PIXMAN_KERNEL_BOX, box_kernel, 1.0 }, { PIXMAN_KERNEL_LINEAR,linear_kernel,2.0 }, { PIXMAN_KERNEL_CUBIC, cubic_kernel, 4.0 }, -{ PIXMAN_KERNEL_GAUSSIAN, gaussian_kernel, 6 * SIGMA }, +{ PIXMAN_KERNEL_GAUSSIAN, gaussian_kernel, 5.0 }, { PIXMAN_KERNEL_LANCZOS2, lanczos2_kernel, 4.0 }, { PIXMAN_KERNEL_LANCZOS3, lanczos3_kernel, 6.0 }, { PIXMAN_KERNEL_LANCZOS3_STRETCHED, nice_kernel, 8.0 }, -- 1.7.9.5 ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
[Pixman] [PATCH pixman 07/15] pixman-filter: Speed up the BOX+BOX filter
This is easy as the caller already intersected the two boxes, so the width is the integral. --- pixman/pixman-filter.c |5 + 1 file changed, 5 insertions(+) diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c index 4aafa51..782f73d 100644 --- a/pixman/pixman-filter.c +++ b/pixman/pixman-filter.c @@ -182,6 +182,11 @@ integral (pixman_kernel_t reconstruct, double x1, assert (width == 0.0); return filters[sample].func (x2 / scale); } +else if (reconstruct == PIXMAN_KERNEL_BOX sample == PIXMAN_KERNEL_BOX) +{ + assert (width = 1.0); + return width; +} else if (sample == PIXMAN_KERNEL_IMPULSE) { assert (width == 0.0); -- 1.7.9.5 ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
[Pixman] [PATCH pixman 12/15] pixman-filter: Turn off subsampling when not necessary
If sample is IMPULSE and reconstruct is BOX or IMPULSE the sub-pixel position of the sample is not relevant, so only one subsample is needed. --- pixman/pixman-filter.c | 12 +++- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c index 64981cd..7e10108 100644 --- a/pixman/pixman-filter.c +++ b/pixman/pixman-filter.c @@ -230,6 +230,8 @@ filter_width (pixman_kernel_t reconstruct, pixman_kernel_t sample, double scale) { +if (reconstruct == PIXMAN_KERNEL_BOX sample == PIXMAN_KERNEL_IMPULSE) + return 0; return ceil (scale * filters[sample].width + filters[reconstruct].width); } @@ -323,13 +325,13 @@ pixman_filter_create_separable_convolution (int *n_values, int subsample_x, subsample_y; int width, height; -subsample_x = (1 subsample_bits_x); -subsample_y = (1 subsample_bits_y); - width = filter_width (reconstruct_x, sample_x, sx); -if (width 1) width = 1; +if (width 1) { width = 1; subsample_bits_x = 0; } height = filter_width (reconstruct_y, sample_y, sy); -if (height 1) height = 1; +if (height 1) { height = 1; subsample_bits_y = 0; } + +subsample_x = (1 subsample_bits_x); +subsample_y = (1 subsample_bits_y); *n_values = 4 + width * subsample_x + height * subsample_y; -- 1.7.9.5 ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
[Pixman] [PATCH pixman 10/15] pixman-filter: don't range-check impulse filter
The other filters don't range-check, so there is no need for this one to either. It is only called with x==0. --- pixman/pixman-filter.c |2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c index fbc657d..00126cd 100644 --- a/pixman/pixman-filter.c +++ b/pixman/pixman-filter.c @@ -45,7 +45,7 @@ typedef struct static double impulse_kernel (double x) { -return (x == 0.0)? 1.0 : 0.0; +return 1; } static double -- 1.7.9.5 ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
[Pixman] [PATCH pixman 06/15] pixman-filter: reduced number of samples in Simpson's integration
With the cubic fix this is plenty accurate enough, far in excess of the pixman fixed-point error limit. Likely even 16 samples is too many. --- pixman/pixman-filter.c |2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c index 7c1da0d..4aafa51 100644 --- a/pixman/pixman-filter.c +++ b/pixman/pixman-filter.c @@ -190,7 +190,7 @@ integral (pixman_kernel_t reconstruct, double x1, else { /* Integration via Simpson's rule */ -#define N_SEGMENTS 128 +#define N_SEGMENTS 16 #define SAMPLE(a1, a2) \ (filters[reconstruct].func ((a1)) * filters[sample].func ((a2) / scale)) -- 1.7.9.5 ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
[Pixman] [PATCH pixman 02/15] demos/scale: Added pulldown to choose PIXMAN_FILTER_* value
This allows testing of GOOD/BEST and to do comparisons between the basic filters and PIXMAN_FILTER_SEPARABLE_CONVOLUTION settings. --- demos/scale.c | 14 +- demos/scale.ui | 40 ++-- 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/demos/scale.c b/demos/scale.c index 71c7791..203168f 100644 --- a/demos/scale.c +++ b/demos/scale.c @@ -68,6 +68,15 @@ typedef struct intvalue; } named_int_t; +static const named_int_t filter_types[] = +{ +{ Separable, PIXMAN_FILTER_SEPARABLE_CONVOLUTION }, +{ Nearest, PIXMAN_FILTER_NEAREST }, +{ Bilinear, PIXMAN_FILTER_BILINEAR }, +{ Good, PIXMAN_FILTER_GOOD }, +{ Best, PIXMAN_FILTER_BEST }, +}; + static const named_int_t filters[] = { { Box, PIXMAN_KERNEL_BOX }, @@ -201,7 +210,9 @@ rescale (GtkWidget *may_be_null, app_t *app) gtk_adjustment_get_value (app-subsample_adjustment), gtk_adjustment_get_value (app-subsample_adjustment)); -pixman_image_set_filter (app-original, PIXMAN_FILTER_SEPARABLE_CONVOLUTION, params, n_params); +pixman_image_set_filter (app-original, + get_value (app, filter_types, filter_combo_box), + params, n_params); pixman_image_set_repeat ( app-original, get_value (app, repeats, repeat_combo_box)); @@ -343,6 +354,7 @@ app_new (pixman_image_t *original) widget = get_widget (app, drawing_area); g_signal_connect (widget, expose_event, G_CALLBACK (on_expose), app); +set_up_combo_box (app, filter_combo_box, G_N_ELEMENTS (filter_types), filter_types); set_up_filter_box (app, reconstruct_x_combo_box); set_up_filter_box (app, reconstruct_y_combo_box); set_up_filter_box (app, sample_x_combo_box); diff --git a/demos/scale.ui b/demos/scale.ui index ee985dd..b62cbfb 100644 --- a/demos/scale.ui +++ b/demos/scale.ui @@ -191,12 +191,23 @@ property name=column_spacing8/property property name=row_spacing6/property child + object class=GtkLabel id=labelF +property name=visibleTrue/property +property name=xalign1/property +property name=label translatable=yeslt;bgt;Filter:lt;/bgt;/property +property name=use_markupTrue/property + /object +/child +child object class=GtkLabel id=label4 property name=visibleTrue/property property name=xalign1/property property name=label translatable=yeslt;bgt;Reconstruct X:lt;/bgt;/property property name=use_markupTrue/property /object + packing +property name=top_attach1/property + /packing /child child object class=GtkLabel id=label5 @@ -206,7 +217,7 @@ property name=use_markupTrue/property /object packing -property name=top_attach1/property +property name=top_attach2/property /packing /child child @@ -217,7 +228,7 @@ property name=use_markupTrue/property /object packing -property name=top_attach2/property +property name=top_attach3/property /packing /child child @@ -228,7 +239,7 @@ property name=use_markupTrue/property /object packing -property name=top_attach3/property +property name=top_attach4/property /packing /child child @@ -239,7 +250,7 @@ property name=use_markupTrue/property /object packing -property name=top_attach4/property +property name=top_attach5/property /packing /child child @@ -250,7 +261,15 @@ property name=use_markupTrue/property /object packing -property name=top_attach5/property +property name=top_attach6/property + /packing +/child +child + object class=GtkComboBox id=filter_combo_box +
[Pixman] [PATCH pixman] V4 Implement PIXMAN_FILTER_GOOD/BEST
This supersedes my previous set of patches. Changes are to fix some rebase errors so that it compiles after each patch applies, and some further rebasing to rearrange the patches and split them into a more logical order. ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
[Pixman] [PATCH pixman 04/15] pixman-filter: reduce amount of malloc/free/memcpy to generate filter
Rearranged so that the entire block of memory for the filter pair is allocated first, and then filled in. Previous version allocated and freed two temporary buffers for each filter and did an extra memcpy. --- pixman/pixman-filter.c | 59 1 file changed, 25 insertions(+), 34 deletions(-) diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c index 05bc345..15f9069 100644 --- a/pixman/pixman-filter.c +++ b/pixman/pixman-filter.c @@ -217,25 +217,25 @@ integral (pixman_kernel_t reconstruct, double x1, } } -static pixman_fixed_t * -create_1d_filter (int *width, +static int +filter_width (pixman_kernel_t reconstruct, + pixman_kernel_t sample, + double scale) +{ +return ceil (scale * filters[sample].width + filters[reconstruct].width); +} + +static void +create_1d_filter (int width, pixman_kernel_t reconstruct, pixman_kernel_t sample, double scale, - int n_phases) + int n_phases, + pixman_fixed_t *p) { -pixman_fixed_t *params, *p; double step; -double size; int i; -size = scale * filters[sample].width + filters[reconstruct].width; -*width = ceil (size); - -p = params = malloc (*width * n_phases * sizeof (pixman_fixed_t)); -if (!params) -return NULL; - step = 1.0 / n_phases; for (i = 0; i n_phases; ++i) @@ -250,8 +250,8 @@ create_1d_filter (int *width, * and sample positions. */ - x1 = ceil (frac - *width / 2.0 - 0.5); -x2 = x1 + *width; + x1 = ceil (frac - width / 2.0 - 0.5); +x2 = x1 + width; total = 0; for (x = x1; x x2; ++x) @@ -279,7 +279,7 @@ create_1d_filter (int *width, } /* Normalize */ - p -= *width; + p -= width; total = 1 / total; new_total = 0; for (x = x1; x x2; ++x) @@ -291,10 +291,8 @@ create_1d_filter (int *width, } if (new_total != pixman_fixed_1) - *(p - *width / 2) += (pixman_fixed_1 - new_total); + *(p - width / 2) += (pixman_fixed_1 - new_total); } - -return params; } /* Create the parameter list for a SEPARABLE_CONVOLUTION filter @@ -313,38 +311,31 @@ pixman_filter_create_separable_convolution (int *n_values, { double sx = fabs (pixman_fixed_to_double (scale_x)); double sy = fabs (pixman_fixed_to_double (scale_y)); -pixman_fixed_t *horz = NULL, *vert = NULL, *params = NULL; +pixman_fixed_t *params; int subsample_x, subsample_y; int width, height; subsample_x = (1 subsample_bits_x); subsample_y = (1 subsample_bits_y); -horz = create_1d_filter (width, reconstruct_x, sample_x, sx, subsample_x); -vert = create_1d_filter (height, reconstruct_y, sample_y, sy, subsample_y); +width = filter_width (reconstruct_x, sample_x, sx); +height = filter_width (reconstruct_y, sample_y, sy); -if (!horz || !vert) -goto out; - *n_values = 4 + width * subsample_x + height * subsample_y; - + params = malloc (*n_values * sizeof (pixman_fixed_t)); if (!params) -goto out; +return NULL; params[0] = pixman_int_to_fixed (width); params[1] = pixman_int_to_fixed (height); params[2] = pixman_int_to_fixed (subsample_bits_x); params[3] = pixman_int_to_fixed (subsample_bits_y); -memcpy (params + 4, horz, - width * subsample_x * sizeof (pixman_fixed_t)); -memcpy (params + 4 + width * subsample_x, vert, - height * subsample_y * sizeof (pixman_fixed_t)); - -out: -free (horz); -free (vert); +create_1d_filter (width, reconstruct_x, sample_x, sx, subsample_x, + params + 4); +create_1d_filter (height, reconstruct_y, sample_y, sy, subsample_y, + params + 4 + width * subsample_x); return params; } -- 1.7.9.5 ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
[Pixman] [PATCH pixman 08/15] pixman-filter: Don't recurse unnecessarily.
Only LINEAR is not differentiable at zero, so only do the recursive split of the integral for it. --- pixman/pixman-filter.c | 34 +- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c index 782f73d..0cd4a68 100644 --- a/pixman/pixman-filter.c +++ b/pixman/pixman-filter.c @@ -160,38 +160,38 @@ integral (pixman_kernel_t reconstruct, double x1, pixman_kernel_t sample, double scale, double x2, double width) { +if (reconstruct == PIXMAN_KERNEL_IMPULSE) +{ + assert (width == 0.0); + return filters[sample].func (x2 / scale); +} +else if (reconstruct == PIXMAN_KERNEL_BOX sample == PIXMAN_KERNEL_BOX) +{ + assert (width = 1.0); + return width; +} +else if (sample == PIXMAN_KERNEL_IMPULSE) +{ + assert (width == 0.0); + return filters[reconstruct].func (x1); +} /* If the integration interval crosses zero, break it into * two separate integrals. This ensures that filters such * as LINEAR that are not differentiable at 0 will still * integrate properly. */ -if (x1 0 x1 + width 0) +else if (reconstruct == PIXMAN_KERNEL_LINEAR x1 0 x1 + width 0) { return integral (reconstruct, x1, sample, scale, x2, - x1) + integral (reconstruct, 0, sample, scale, x2 - x1, width + x1); } -else if (x2 0 x2 + width 0) +else if (sample == PIXMAN_KERNEL_LINEAR x2 0 x2 + width 0) { return integral (reconstruct, x1, sample, scale, x2, - x2) + integral (reconstruct, x1 - x2, sample, scale, 0, width + x2); } -else if (reconstruct == PIXMAN_KERNEL_IMPULSE) -{ - assert (width == 0.0); - return filters[sample].func (x2 / scale); -} -else if (reconstruct == PIXMAN_KERNEL_BOX sample == PIXMAN_KERNEL_BOX) -{ - assert (width = 1.0); - return width; -} -else if (sample == PIXMAN_KERNEL_IMPULSE) -{ - assert (width == 0.0); - return filters[reconstruct].func (x1); -} else { /* Integration via Simpson's rule */ -- 1.7.9.5 ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
[Pixman] [PATCH pixman 13/15] pixman-filter: refactor cubic polynominal and don't range check
The other filters do not check for x being in range, so there is no reason for cubic to do so. --- pixman/pixman-filter.c | 16 +++- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c index 7e10108..bf9dce3 100644 --- a/pixman/pixman-filter.c +++ b/pixman/pixman-filter.c @@ -109,18 +109,16 @@ general_cubic (double x, double B, double C) if (ax 1) { - return ((12 - 9 * B - 6 * C) * ax * ax * ax + - (-18 + 12 * B + 6 * C) * ax * ax + (6 - 2 * B)) / 6; -} -else if (ax = 1 ax 2) -{ - return ((-B - 6 * C) * ax * ax * ax + - (6 * B + 30 * C) * ax * ax + (-12 * B - 48 * C) * - ax + (8 * B + 24 * C)) / 6; + return (((12 - 9 * B - 6 * C) * ax + +(-18 + 12 * B + 6 * C)) * ax * ax + + (6 - 2 * B)) / 6; } else { - return 0; + return -B - 6 * C) * ax + +(6 * B + 30 * C)) * ax + + (-12 * B - 48 * C)) * ax + + (8 * B + 24 * C)) / 6; } } -- 1.7.9.5 ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman
[Pixman] [PATCH pixman 01/15] demos/scale: Compute filter size using boundary of xformed ellipse, not rectangle
This is much more accurate and less blurry. In particular the filtering does not change as the image is rotated. --- demos/scale.c | 43 ++- 1 file changed, 2 insertions(+), 41 deletions(-) diff --git a/demos/scale.c b/demos/scale.c index d00307e..71c7791 100644 --- a/demos/scale.c +++ b/demos/scale.c @@ -55,50 +55,11 @@ get_widget (app_t *app, const char *name) return widget; } -static double -min4 (double a, double b, double c, double d) -{ -double m1, m2; - -m1 = MIN (a, b); -m2 = MIN (c, d); -return MIN (m1, m2); -} - -static double -max4 (double a, double b, double c, double d) -{ -double m1, m2; - -m1 = MAX (a, b); -m2 = MAX (c, d); -return MAX (m1, m2); -} - static void compute_extents (pixman_f_transform_t *trans, double *sx, double *sy) { -double min_x, max_x, min_y, max_y; -pixman_f_vector_t v[4] = -{ - { { 1, 1, 1 } }, - { { -1, 1, 1 } }, - { { -1, -1, 1 } }, - { { 1, -1, 1 } }, -}; - -pixman_f_transform_point (trans, v[0]); -pixman_f_transform_point (trans, v[1]); -pixman_f_transform_point (trans, v[2]); -pixman_f_transform_point (trans, v[3]); - -min_x = min4 (v[0].v[0], v[1].v[0], v[2].v[0], v[3].v[0]); -max_x = max4 (v[0].v[0], v[1].v[0], v[2].v[0], v[3].v[0]); -min_y = min4 (v[0].v[1], v[1].v[1], v[2].v[1], v[3].v[1]); -max_y = max4 (v[0].v[1], v[1].v[1], v[2].v[1], v[3].v[1]); - -*sx = (max_x - min_x) / 2.0; -*sy = (max_y - min_y) / 2.0; +*sx = hypot (trans-m[0][0], trans-m[0][1]) / trans-m[2][2]; +*sy = hypot (trans-m[1][0], trans-m[1][1]) / trans-m[2][2]; } typedef struct -- 1.7.9.5 ___ Pixman mailing list Pixman@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/pixman