[gs-cvs] rev 8536 - trunk/gs/src

leonardo at ghostscript.com leonardo at ghostscript.com
Wed Feb 20 13:02:49 PST 2008


Author: leonardo
Date: 2008-02-20 13:02:48 -0800 (Wed, 20 Feb 2008)
New Revision: 8536

Modified:
   trunk/gs/src/gdevm24.c
   trunk/gs/src/gsmatrix.c
   trunk/gs/src/gsmatrix.h
   trunk/gs/src/gxidata.c
   trunk/gs/src/gximono.c
   trunk/gs/src/gxipixel.c
   trunk/gs/src/lib.mak
Log:
Fix (images) : Improve coordinate precision when scaling an image (continued 5).

DETAILS :

Ghostscript Bug 687345 "Image interpolation problem at a band boundary"

This is a further improvement to image placement precision.
Debugged with a.pdf .

The old code provides insufficientg precision when computing 
transformation matrix for an image. This computation
include matrix inversion and matrix miltiplication.
The old code uses floats and causes a visible shift of subimages with banding.
The new code uses double precision.

We didn't test how it relates to the revision 7026 change, 
which dectreased the matrix precision for CPSI compatibility.
It should be a separate job.

In the new gsmatrix.c code we simply duplicate old code fragments
and replace types for double. We don't want to define a template
for now. Will see after the code passes enough practical work.

Besides that, in gxidata.c replaced fixed2int_pixround
with fixed2int_pixround_perfect. It is not related to a.pdf,
but we believe it is an useful change.

In gxipixel.c the patch replaces dda_advance with a repeated dda_next.
The old code appears implrecise due to loosing fraction pixels.
It eliminates a 1 pixel difference with Bug688789.pdf .

Minor changes : inserted debug printing and visual trace.

EXPECTED DIFFERENCES :

The patch eliminates banding/nobanding difference with :
a.pdf
"Altona.Page_3.2002-09-27.pdf" 
"Altona_Technical_1v1_x3.pdf" 
Bug688789.pdf
D-12-2025-9478-9.pdf,

Also it causes minor raster differences with following files :

"119-28.ps" 
"468-01.ps" 
"Bug687724.pdf" 
"Bug688308.ps" 
"FIG3.eps" 


Modified: trunk/gs/src/gdevm24.c
===================================================================
--- trunk/gs/src/gdevm24.c	2008-02-19 08:29:04 UTC (rev 8535)
+++ trunk/gs/src/gdevm24.c	2008-02-20 21:02:48 UTC (rev 8536)
@@ -108,6 +108,7 @@
     declare_unpack_color(r, g, b, color);
     declare_scan_ptr(dest);
 
+    if_debug2('b', "[b]device y=%d h=%d\n", y + mdev->band_y, h);
     /*
      * In order to avoid testing w > 0 and h > 0 twice, we defer
      * executing setup_rect, and use fit_fill_xywh instead of

Modified: trunk/gs/src/gsmatrix.c
===================================================================
--- trunk/gs/src/gsmatrix.c	2008-02-19 08:29:04 UTC (rev 8535)
+++ trunk/gs/src/gsmatrix.c	2008-02-20 21:02:48 UTC (rev 8536)
@@ -110,7 +110,42 @@
     }
     return 0;
 }
+int
+gs_matrix_multiply_double(const gs_matrix_double * pm1, const gs_matrix * pm2, gs_matrix_double * pmr)
+{
+    double xx1 = pm1->xx, yy1 = pm1->yy;
+    double tx1 = pm1->tx, ty1 = pm1->ty;
+    double xx2 = pm2->xx, yy2 = pm2->yy;
+    double xy2 = pm2->xy, yx2 = pm2->yx;
 
+    if (is_xxyy(pm1)) {
+	pmr->tx = tx1 * xx2 + pm2->tx;
+	pmr->ty = ty1 * yy2 + pm2->ty;
+	if (is_fzero(xy2))
+	    pmr->xy = 0;
+	else
+	    pmr->xy = xx1 * xy2,
+		pmr->ty += tx1 * xy2;
+	pmr->xx = xx1 * xx2;
+	if (is_fzero(yx2))
+	    pmr->yx = 0;
+	else
+	    pmr->yx = yy1 * yx2,
+		pmr->tx += ty1 * yx2;
+	pmr->yy = yy1 * yy2;
+    } else {
+	double xy1 = pm1->xy, yx1 = pm1->yx;
+
+	pmr->xx = xx1 * xx2 + xy1 * yx2;
+	pmr->xy = xx1 * xy2 + xy1 * yy2;
+	pmr->yy = yx1 * xy2 + yy1 * yy2;
+	pmr->yx = yx1 * xx2 + yy1 * yx2;
+	pmr->tx = tx1 * xx2 + ty1 * yx2 + pm2->tx;
+	pmr->ty = tx1 * xy2 + ty1 * yy2 + pm2->ty;
+    }
+    return 0;
+}
+
 /* Invert a matrix.  Return gs_error_undefinedresult if not invertible. */
 int
 gs_matrix_invert(const gs_matrix * pm, gs_matrix * pmr)
@@ -143,7 +178,38 @@
     }
     return 0;
 }
+int
+gs_matrix_invert_to_double(const gs_matrix * pm, gs_matrix_double * pmr)
+{				/* We have to be careful about fetch/store order, */
+    /* because pm might be the same as pmr. */
+    if (is_xxyy(pm)) {
+	if (is_fzero(pm->xx) || is_fzero(pm->yy))
+	    return_error(gs_error_undefinedresult);
+	pmr->tx = -(pmr->xx = 1.0 / pm->xx) * pm->tx;
+	pmr->xy = 0.0;
+	pmr->yx = 0.0;
+	pmr->ty = -(pmr->yy = 1.0 / pm->yy) * pm->ty;
+    } else {
+	double mxx = pm->xx, myy = pm->yy, mxy = pm->xy, myx = pm->yx;
+        double mtx = pm->tx, mty = pm->ty;
+	double det = (mxx * myy) - (mxy * myx);
 
+        /*
+         * We are doing the math as floats instead of doubles to reproduce
+	 * the results in page 1 of CET 10-09.ps
+         */
+	if (det == 0)
+	    return_error(gs_error_undefinedresult);
+	pmr->xx = myy / det;
+	pmr->xy = -mxy / det;
+	pmr->yx = -myx / det;
+	pmr->yy = mxx / det;
+	pmr->tx = (((mty * myx) - (mtx * myy))) / det;
+	pmr->ty = (((mtx * mxy) - (mty * mxx))) / det;
+    }
+    return 0;
+}
+
 /* Translate a matrix, possibly in place. */
 int
 gs_matrix_translate(const gs_matrix * pm, floatp dx, floatp dy, gs_matrix * pmr)

Modified: trunk/gs/src/gsmatrix.h
===================================================================
--- trunk/gs/src/gsmatrix.h	2008-02-19 08:29:04 UTC (rev 8535)
+++ trunk/gs/src/gsmatrix.h	2008-02-20 21:02:48 UTC (rev 8536)
@@ -26,11 +26,18 @@
 struct gs_matrix_s {
     _matrix_body;
 };
+struct gs_matrix_double_s {
+  double xx, xy, yx, yy, tx, ty;
+};
 
 #ifndef gs_matrix_DEFINED
 #  define gs_matrix_DEFINED
 typedef struct gs_matrix_s gs_matrix;
 #endif
+#ifndef gs_matrix_double_DEFINED
+#  define gs_matrix_double_DEFINED
+typedef struct gs_matrix_double_s gs_matrix_double;
+#endif
 
 /* Macro for initializing constant matrices */
 #define constant_matrix_body(xx, xy, yx, yy, tx, ty)\
@@ -54,7 +61,9 @@
 
 /* Matrix arithmetic */
 int gs_matrix_multiply(const gs_matrix *, const gs_matrix *, gs_matrix *),
+    gs_matrix_multiply_double(const gs_matrix_double *, const gs_matrix *, gs_matrix_double *),
     gs_matrix_invert(const gs_matrix *, gs_matrix *),
+    gs_matrix_invert_to_double(const gs_matrix *, gs_matrix_double *),
     gs_matrix_translate(const gs_matrix *, floatp, floatp, gs_matrix *),
     gs_matrix_scale(const gs_matrix *, floatp, floatp, gs_matrix *),
     gs_matrix_rotate(const gs_matrix *, floatp, gs_matrix *);

Modified: trunk/gs/src/gxidata.c
===================================================================
--- trunk/gs/src/gxidata.c	2008-02-19 08:29:04 UTC (rev 8535)
+++ trunk/gs/src/gxidata.c	2008-02-20 21:02:48 UTC (rev 8536)
@@ -156,8 +156,8 @@
 			yn += adjust;
 			if (yn <= penum->clip_outer.p.y)
 			    goto mt;
-			penum->yci = fixed2int_pixround(yc);
-			penum->hci = fixed2int_pixround(yn) - penum->yci;
+			penum->yci = fixed2int_pixround_perfect(yc);
+			penum->hci = fixed2int_pixround_perfect(yn) - penum->yci;
 			if (penum->hci == 0)
 			    goto mt;
 			if_debug2('b', "[b]yci=%d, hci=%d\n",
@@ -181,8 +181,8 @@
 			xn += adjust;
 			if (xn <= penum->clip_outer.p.x)
 			    goto mt;
-			penum->xci = fixed2int_pixround(xc);
-			penum->wci = fixed2int_pixround(xn) - penum->xci;
+			penum->xci = fixed2int_pixround_perfect(xc);
+			penum->wci = fixed2int_pixround_perfect(xn) - penum->xci;
 			if (penum->wci == 0)
 			    goto mt;
 			if_debug2('b', "[b]xci=%d, wci=%d\n",

Modified: trunk/gs/src/gximono.c
===================================================================
--- trunk/gs/src/gximono.c	2008-02-19 08:29:04 UTC (rev 8535)
+++ trunk/gs/src/gximono.c	2008-02-20 21:02:48 UTC (rev 8536)
@@ -32,6 +32,7 @@
 #include "gxcpath.h"
 #include "gximage.h"
 #include "gzht.h"
+#include "vdtrace.h"
 
 /* ------ Strategy procedure ------ */
 
@@ -416,8 +417,10 @@
 	    dev_proc(dev, fill_rectangle);
 	int xmin = fixed2int_pixround(penum->clip_outer.p.x);
 	int xmax = fixed2int_pixround(penum->clip_outer.q.x);
+#define xl dda_current(next.x)
 
-#define xl dda_current(next.x)
+	if_debug2('b', "[b]image y=%d  dda.y.Q=%lg\n", penum->y + penum->rect.y, 
+		    penum->dda.row.y.state.Q / 256.);
 	/* Fold the adjustment into xrun and xl, */
 	/* including the +0.5-epsilon for rounding. */
 	xrun = xrun - xa + (fixed_half - fixed_epsilon);
@@ -495,7 +498,8 @@
 			    }
                             code = gx_fill_rectangle_device_rop(xi, yt, wi, iht,
                                                                  pdevc, dev, lop);
-
+			    vd_rect(int2fixed(xi), int2fixed(yt), int2fixed(xi + wi), int2fixed(yt + iht),
+				0, pdevc->colors.pure /* wrong with halftones */);
 		    }
 		    if (code < 0)
 			goto err;

Modified: trunk/gs/src/gxipixel.c
===================================================================
--- trunk/gs/src/gxipixel.c	2008-02-19 08:29:04 UTC (rev 8535)
+++ trunk/gs/src/gxipixel.c	2008-02-20 21:02:48 UTC (rev 8536)
@@ -191,7 +191,7 @@
     const int bps = pim->BitsPerComponent;
     bool masked = penum->masked;
     const float *decode = pim->Decode;
-    gs_matrix mat;
+    gs_matrix_double mat;
     int index_bps;
     const gs_color_space *pcs = pim->ColorSpace;
     gs_logical_operation_t lop = (pis ? pis->log_op : lop_default);
@@ -209,13 +209,19 @@
     penum->Height = height;
     if (pmat == 0)
 	pmat = &ctm_only(pis);
-    if ((code = gs_matrix_invert(&pim->ImageMatrix, &mat)) < 0 ||
-	(code = gs_matrix_multiply(&mat, pmat, &mat)) < 0
+    if ((code = gs_matrix_invert_to_double(&pim->ImageMatrix, &mat)) < 0 ||
+	(code = gs_matrix_multiply_double(&mat, pmat, &mat)) < 0
 	) {
 	gs_free_object(mem, penum, "gx_default_begin_image");
 	return code;
     }
-    penum->matrix = mat;
+    /*penum->matrix = mat;*/
+    penum->matrix.xx = mat.xx;
+    penum->matrix.xy = mat.xy;
+    penum->matrix.yx = mat.yx;
+    penum->matrix.yy = mat.yy;
+    penum->matrix.tx = mat.tx;
+    penum->matrix.ty = mat.ty;
     if_debug6('b', " [%g %g %g %g %g %g]\n",
 	      mat.xx, mat.xy, mat.yx, mat.yy, mat.tx, mat.ty);
     /* following works for 1, 2, 4, 8, 12, 16 */
@@ -520,8 +526,12 @@
 	penum->dst_height = col_extent.y;
 	penum->yi0 = fixed2int_pixround_perfect(dda_current(penum->dda.row.y)); /* For gs_image_class_0_interpolate. */
 	if (penum->rect.y) {
-	    dda_advance(penum->dda.row.x, penum->rect.y);
-	    dda_advance(penum->dda.row.y, penum->rect.y);
+	    int y = penum->rect.y;
+
+	    while (y--) {
+		dda_next(penum->dda.row.x);
+		dda_next(penum->dda.row.y);
+	    }
 	}
 	penum->cur.x = penum->prev.x = dda_current(penum->dda.row.x);
 	penum->cur.y = penum->prev.y = dda_current(penum->dda.row.y);

Modified: trunk/gs/src/lib.mak
===================================================================
--- trunk/gs/src/lib.mak	2008-02-19 08:29:04 UTC (rev 8535)
+++ trunk/gs/src/lib.mak	2008-02-20 21:02:48 UTC (rev 8536)
@@ -659,7 +659,7 @@
  $(gdevmem_h) $(gsccolor_h) $(gspaint_h) $(gsutil_h)\
  $(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h)\
  $(gxdevmem_h) $(gxfixed_h) $(gximage_h) $(gxistate_h) $(gxmatrix_h)\
- $(gzht_h)
+ $(gzht_h) $(vdtrace_h)
 	$(GLCC) $(GLO_)gximono.$(OBJ) $(C_) $(GLSRC)gximono.c
 
 $(GLOBJ)gximask.$(OBJ) : $(GLSRC)gximask.c $(GXERR) $(memory__h) $(gserrors_h)\



More information about the gs-cvs mailing list