[Pixman] [PATCH v12 11/14] pixman-filter: Negative subsample values produces scaled result

spitzak at gmail.com spitzak at gmail.com
Mon Feb 8 09:06:59 CET 2016


From: Bill Spitzak <spitzak at gmail.com>

The intention here is to produce approximately the same number of samples for
each filter size (ie width*samples is the same). This means the caller can
pass a constant rather than a different value for each size. To avoid conflict
with existing code, negative numbers are used to indicate that -n samples are
needed at size==1.

For larger size the width of a BOX.BOX filter is used (the number of samples
is scaled by 2/(size+1)). This may be more than are needed for other filters
which increase in width faster.

For smaller filters it seems 1/size would be needed to keep the same number
of samples on the high-frequency portions. But it appears to be acceptable to
reduce them, I used 2/((size+1)*size) which makes about 1/2 as many samples
as size approaches zero.

These functions were arrived at experimentally by testing for visible
artifacts in the scaling of the zone plate image.

The computed value is then rounded up to the next power of 2 to get the
subsample_bits.

The scale demo is modified to allow these negative numbers, and initially
uses -12.

v11: Put subsample calculation in it's own function
     Minor changes to comments
v12: More info in the commit message

Signed-off-by: Bill Spitzak <spitzak at gmail.com>
---
 demos/scale.ui         |  5 +++--
 pixman/pixman-filter.c | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/demos/scale.ui b/demos/scale.ui
index b62cbfb..1e77f56 100644
--- a/demos/scale.ui
+++ b/demos/scale.ui
@@ -24,12 +24,12 @@
     <property name="page_size">10</property>
   </object>
   <object class="GtkAdjustment" id="subsample_adjustment">
-    <property name="lower">0</property>
+    <property name="lower">-256</property>
     <property name="upper">12</property>
     <property name="step_increment">1</property>
     <property name="page_increment">1</property>
     <property name="page_size">0</property>
-    <property name="value">4</property>
+    <property name="value">-12</property>
   </object>
   <object class="GtkWindow" id="main">
     <child>
@@ -321,6 +321,7 @@
                       <object class="GtkSpinButton" id="subsample_spin_button">
                         <property name="visible">True</property>
 			<property name="adjustment">subsample_adjustment</property>
+			<property name="value">-12</property>
                       </object>
                       <packing>
                         <property name="left_attach">1</property>
diff --git a/pixman/pixman-filter.c b/pixman/pixman-filter.c
index 56e25b1..e57b154 100644
--- a/pixman/pixman-filter.c
+++ b/pixman/pixman-filter.c
@@ -346,6 +346,37 @@ filter_width (pixman_kernel_t reconstruct, pixman_kernel_t sample, double size)
     return ceil (filters[reconstruct].width + size * filters[sample].width);
 }
 
+/* Turn negative number into approximately ceil(ln2(-n / size))
+ * Actual function is somewhat non-linear. For size > 1 it uses
+ * the width/2 of BOX.BOX instead of size. For size < 1 it reduces
+ * the samples by 1/2 as size approaches zero.
+ */
+static int
+subsample_bits (int subsample_bits, pixman_kernel_t sample, double size)
+{
+    if (subsample_bits < 0)
+    {
+	/* The intention was to do -n / size rounded up to the next power of 2,
+	   but this non-linear function seems to work better. For large size
+	   it is the width of the BOX.BOX filter. For small size it reduces
+	   samples by 2 at maximum. */
+	double desired_samples = -subsample_bits;
+	if (sample == PIXMAN_KERNEL_IMPULSE)
+	    ; /* For x.IMPULSE no scaling is done */
+	else if (size >= 1.0)
+	    desired_samples *= 2.0 / (size + 1.0);
+	else
+	    desired_samples *= 2.0 / ((size + 1.0) * size);
+	if (desired_samples <= 1.0)
+	    subsample_bits = 0;
+	else if (desired_samples >= 256.0)
+	    subsample_bits = 8;
+	else
+	    subsample_bits = (int) ceil (log2(desired_samples) - .01);
+    }
+    return subsample_bits;
+}
+
 /* Create the parameter list for a SEPARABLE_CONVOLUTION filter
  * with the given kernels and size parameters
  */
@@ -367,9 +398,11 @@ pixman_filter_create_separable_convolution (int             *n_values,
     int width, height;
 
     width = filter_width (reconstruct_x, sample_x, sx);
+    subsample_bits_x = subsample_bits (subsample_bits_x, sample_x, sx);
     subsample_x = (1 << subsample_bits_x);
 
     height = filter_width (reconstruct_y, sample_y, sy);
+    subsample_bits_y = subsample_bits (subsample_bits_y, sample_y, sy);
     subsample_y = (1 << subsample_bits_y);
 
     *n_values = 4 + width * subsample_x + height * subsample_y;
-- 
1.9.1



More information about the Pixman mailing list