[gs-cvs] rev 8522 - trunk/gs/src
leonardo at ghostscript.com
leonardo at ghostscript.com
Tue Feb 12 12:30:18 PST 2008
Author: leonardo
Date: 2008-02-12 12:30:17 -0800 (Tue, 12 Feb 2008)
New Revision: 8522
Modified:
trunk/gs/src/gxdda.h
trunk/gs/src/gximage.h
trunk/gs/src/gxipixel.c
trunk/gs/src/gxiscale.c
trunk/gs/src/lib.mak
trunk/gs/src/siscale.c
trunk/gs/src/sisparam.h
Log:
Fix (images) : Improve coordinate precision when scaling an image (continued).
DETAILS :
Ghostscript Bug 687345 "Image interpolation problem at a band boundary"
This is another partial fix for the bug 687345 for portrait images with Interpolate=true.
Debugged with CET 148-13.
1. The old code inprecisely computes the scaling factor
when interpolating images with Mitchel filter.
The computation was done with the subimage rectangle,
which is different for different bands.
The new code always computes the scale from the entire image rectangle,
which's size is same for all bands.
2. New fields are inserted into gx_image_enum_s and stream_image_scale_params_s
to provide data delivery for (1).
3. In calculate_contrib in siscale.c the variable input_index
is renamed into starting_output_index for a better reflection of its semantics.
4. In calculate_contrib in siscale.c the new variable dst_offset_fraction
is added for a preciser positioning of the filter center,
when it fails between device pixel rows. The old code missed fractional
pixels when stepping to a next band. The expression for its value
was created empirically, so it may need further improvements.
5. Inserted visual trace instructions for easier debugging.
6. Improved the debug trace printing.
EXPECTED DIFFERENCES :
The patch eliminates banding/nobanding difference with C-12-2706-0239-9-001.pdf,
and with the box 148-13 in 148-1.ps .
Minor differences (a small shift of an image due to better scale precision) :
"148-11.ps"
"289-01.ps"
"A-12-3480-0109-5.pdf"
"B-12-3077-1831-7-001.pdf"
"C-12-2706-0239-9-001.pdf"
"D-12-2025-9478-9.pdf"
"E-12-1866-0406-7.pdf"
"FIG3.eps"
Modified: trunk/gs/src/gxdda.h
===================================================================
--- trunk/gs/src/gxdda.h 2008-02-12 19:03:19 UTC (rev 8521)
+++ trunk/gs/src/gxdda.h 2008-02-12 20:30:17 UTC (rev 8522)
@@ -151,5 +151,5 @@
((dstate).Q += (delta))
#define dda_translate(dda, delta)\
dda_state_translate((dda).state, delta)
-
+
#endif /* gxdda_INCLUDED */
Modified: trunk/gs/src/gximage.h
===================================================================
--- trunk/gs/src/gximage.h 2008-02-12 19:03:19 UTC (rev 8521)
+++ trunk/gs/src/gximage.h 2008-02-12 20:30:17 UTC (rev 8522)
@@ -164,6 +164,8 @@
/* We really want the map structure to be long-aligned, */
/* so we choose shorter types for some flags. */
/* Following are set at structure initialization */
+ int Width; /* Full image width */
+ int Height; /* Full image height */
byte bps; /* bits per sample: 1, 2, 4, 8, 12 */
byte unpack_bps; /* bps for computing unpack proc, */
/* set to 8 if no unpacking */
@@ -191,6 +193,10 @@
struct r_ {
int x, y, w, h; /* subrectangle being rendered */
} rect;
+ fixed dst_height; /* Full image height in the device space for siscale.c only;
+ assumes posture == image_portrait. */
+ fixed dst_width; /* Full image width in the device space for siscale.c only;
+ assumes posture == image_portrait. */
gs_fixed_point x_extent, y_extent; /* extent of one row of rect */
SAMPLE_UNPACK_PROC((*unpack));
irender_proc((*render));
Modified: trunk/gs/src/gxipixel.c
===================================================================
--- trunk/gs/src/gxipixel.c 2008-02-12 19:03:19 UTC (rev 8521)
+++ trunk/gs/src/gxipixel.c 2008-02-12 20:30:17 UTC (rev 8522)
@@ -205,6 +205,8 @@
bool device_color = true;
gs_fixed_rect obox, cbox;
+ penum->Width = width;
+ penum->Height = height;
if (pmat == 0)
pmat = &ctm_only(pis);
if ((code = gs_matrix_invert(&pim->ImageMatrix, &mat)) < 0 ||
@@ -547,6 +549,8 @@
penum->clip_image);
dda_init(penum->dda.row.x, mtx, col_extent.x, height);
dda_init(penum->dda.row.y, mty, col_extent.y, height);
+ penum->dst_width = row_extent.x;
+ penum->dst_height = col_extent.y;
if (penum->rect.y) {
dda_advance(penum->dda.row.x, penum->rect.y);
dda_advance(penum->dda.row.y, penum->rect.y);
Modified: trunk/gs/src/gxiscale.c
===================================================================
--- trunk/gs/src/gxiscale.c 2008-02-12 19:03:19 UTC (rev 8521)
+++ trunk/gs/src/gxiscale.c 2008-02-12 20:30:17 UTC (rev 8522)
@@ -35,6 +35,7 @@
#include "siinterp.h" /* for spatial interpolation */
#include "siscale.h" /* for Mitchell filtering */
#include "sidscale.h" /* for special case downscale filter */
+#include "vdtrace.h"
/*
* Define whether we are using Mitchell filtering or spatial
@@ -103,6 +104,9 @@
iss.HeightOut = (int)ceil(fabs(dst_xy.y));
iss.WidthIn = penum->rect.w;
iss.HeightIn = penum->rect.h;
+ iss.xscale = any_abs((float)penum->dst_width / penum->Width / fixed_1);
+ iss.yscale = any_abs((float)penum->dst_height / penum->Height / fixed_1);
+ iss.dst_y_offset = penum->rect.y * iss.yscale;
pccs = cs_concrete_space(pcs, pis);
iss.Colors = cs_num_components(pccs);
if (penum->bps <= 8 && penum->device_color) {
@@ -330,6 +334,7 @@
case 1:
do {
LINE_ACCUM(color, bpp);
+ vd_pixel(int2fixed(x), int2fixed(ry), color);
x++, psrc += 1;
} while (x < xe && psrc[-1] == psrc[0]);
break;
Modified: trunk/gs/src/lib.mak
===================================================================
--- trunk/gs/src/lib.mak 2008-02-12 19:03:19 UTC (rev 8521)
+++ trunk/gs/src/lib.mak 2008-02-12 20:30:17 UTC (rev 8522)
@@ -2289,7 +2289,7 @@
$(gxarith_h) $(gxcmap_h) $(gxcpath_h) $(gxdcolor_h) $(gxdevice_h)\
$(gxdevmem_h) $(gxfixed_h) $(gxfrac_h) $(gximage_h) $(gxistate_h)\
$(gxmatrix_h)\
- $(siinterp_h) $(siscale_h) $(stream_h)
+ $(siinterp_h) $(siscale_h) $(stream_h) $(vdtrace_h)
$(GLCC) $(GLO_)gxiscale.$(OBJ) $(C_) $(GLSRC)gxiscale.c
# ---------------- Display Postscript / Level 2 support ---------------- #
Modified: trunk/gs/src/siscale.c
===================================================================
--- trunk/gs/src/siscale.c 2008-02-12 19:03:19 UTC (rev 8521)
+++ trunk/gs/src/siscale.c 2008-02-12 20:30:17 UTC (rev 8522)
@@ -78,6 +78,7 @@
int src_y;
uint src_offset, src_size;
int dst_y;
+ float dst_y_offset;
uint dst_offset, dst_size;
CLIST dst_next_list; /* for next output value */
int dst_last_index; /* highest index used in list */
@@ -158,8 +159,10 @@
CONTRIB * items,
/* The output image is scaled by 'scale' relative to the input. */
double scale,
- /* Start generating weights for input pixel 'input_index'. */
- int input_index,
+ /* Start generating weights for input pixel 'starting_output_index'. */
+ int starting_output_index,
+ /* Offset of output pixel from the output image start. */
+ float dst_offset,
/* Generate 'size' weight lists. */
int size,
/* Limit pixel indices to 'limit', for clamping at the edges */
@@ -181,6 +184,7 @@
int i, j;
int last_index = -1;
+ if_debug1('w', "[w]calculate_contrib scale=%lg\n", scale);
if (scale < 1.0) {
double clamped_scale = max(scale, min_scale);
@@ -196,7 +200,7 @@
for (i = 0; i < size; ++i) {
#if 0
- double center = (input_index + i) / scale;
+ double center = (starting_output_index + i) / scale;
int left = (int)ceil(center - WidthIn);
int right = (int)floor(center + WidthIn);
@@ -221,7 +225,9 @@
int first_pixel = min(lmin, rmin);
int last_pixel = max(lmax, rmax);
#else
- double center = (input_index + i) / scale - 0.5;
+ float dst_offset_fraction = ceil(dst_offset) - dst_offset; /* Compensate
+ rounding for penum->xyi.y in gs_image_class_0_interpolate. */
+ double center = (starting_output_index + i + dst_offset_fraction) / scale - 0.5;
int left = (int)ceil(center - WidthIn);
int right = (int)floor(center + WidthIn);
#define clamp_pixel(j) (j < 0 ? 0 : j >= limit ? limit - 1 : j)
@@ -230,6 +236,8 @@
#endif
CONTRIB *p;
+ if_debug4('W', "[W]i=%d, i+offset=%g scale=%lg center=%lg : ", starting_output_index + i,
+ starting_output_index + i + dst_offset, scale, center);
if (last_pixel > last_index)
last_index = last_pixel;
contrib[i].first_pixel = (first_pixel % modulus) * stride;
@@ -249,6 +257,7 @@
p[k].weight +=
(PixelWeight) (weight * scaled_factor);
+ if_debug2('W', " %d %f", k, (float)p[k].weight);
}
} else {
@@ -262,8 +271,10 @@
p[k].weight +=
(PixelWeight) (weight * scaled_factor);
+ if_debug2('W', " %d %f", k, (float)p[k].weight);
}
}
+ if_debug0('W', "\n");
}
return last_index;
}
@@ -310,7 +321,7 @@
}\
}\
{ PixelIn2 pixel = unscale_AccumTmp(weight, fraction_bits);\
- if_debug1('W', " %ld", (long)pixel);\
+ if_debug1('W', " %lx", (long)pixel);\
*tp =\
(PixelTmp)CLAMP(pixel, minPixelTmp, maxPixelTmp);\
}\
@@ -363,7 +374,7 @@
weight += *pp * cp->weight;\
}\
{ PixelTmp2 pixel = unscale_AccumTmp(weight, fraction_bits);\
- if_debug1('W', " %d", pixel);\
+ if_debug1('W', " %lx", (long)pixel);\
((PixelOut *)dst)[kc] =\
(PixelOut)CLAMP(pixel, 0, max_weight);\
}\
@@ -392,32 +403,31 @@
uint row_size = ss->params.WidthOut * ss->params.Colors;
int last_index =
calculate_contrib(&ss->dst_next_list, ss->dst_items, ss->yscale,
- y, 1, ss->params.HeightIn, MAX_ISCALE_SUPPORT, row_size,
+ y, ss->dst_y_offset, 1, ss->params.HeightIn, MAX_ISCALE_SUPPORT, row_size,
(double)ss->params.MaxValueOut / (fixedScaleFactor * unitPixelTmp) );
int first_index_mod = ss->dst_next_list.first_pixel / row_size;
+ if_debug2('w', "[w]calculate_dst_contrib for y = %d, y+offset=%d\n", y, y + ss->dst_y_offset);
ss->dst_last_index = last_index;
last_index %= MAX_ISCALE_SUPPORT;
if (last_index < first_index_mod) { /* Shuffle the indices to account for wraparound. */
CONTRIB shuffle[MAX_ISCALE_SUPPORT];
int i;
- for (i = 0; i < MAX_ISCALE_SUPPORT; ++i)
+ for (i = 0; i < MAX_ISCALE_SUPPORT; ++i) {
shuffle[i].weight =
(i <= last_index ?
ss->dst_items[i + MAX_ISCALE_SUPPORT - first_index_mod].weight :
i >= first_index_mod ?
ss->dst_items[i - first_index_mod].weight :
0);
+ if_debug1('W', " %f", shuffle[i].weight);
+ }
memcpy(ss->dst_items, shuffle, MAX_ISCALE_SUPPORT * sizeof(CONTRIB));
ss->dst_next_list.n = MAX_ISCALE_SUPPORT;
ss->dst_next_list.first_pixel = 0;
}
-#ifdef DEBUG
- if (gs_debug_c('w')) {
- dprintf1("[w]calc dest contrib for y = %d\n", y);
- }
-#endif
+ if_debug0('w', "\n");
}
/* Set default parameter values (actually, just clear pointers). */
@@ -442,13 +452,14 @@
ss->sizeofPixelIn = ss->params.BitsPerComponentIn / 8;
ss->sizeofPixelOut = ss->params.BitsPerComponentOut / 8;
- ss->xscale = (double)ss->params.WidthOut / (double)ss->params.WidthIn;
- ss->yscale = (double)ss->params.HeightOut / (double)ss->params.HeightIn;
+ ss->xscale = ss->params.xscale;
+ ss->yscale = ss->params.yscale;
ss->src_y = 0;
ss->src_size = ss->params.WidthIn * ss->sizeofPixelIn * ss->params.Colors;
ss->src_offset = 0;
ss->dst_y = 0;
+ ss->dst_y_offset = ss->params.dst_y_offset;
ss->dst_size = ss->params.WidthOut * ss->sizeofPixelOut * ss->params.Colors;
ss->dst_offset = 0;
@@ -477,7 +488,7 @@
}
/* Pre-calculate filter contributions for a row. */
calculate_contrib(ss->contrib, ss->items, ss->xscale,
- 0, ss->params.WidthOut, ss->params.WidthIn, ss->params.WidthIn,
+ 0, 0, ss->params.WidthOut, ss->params.WidthIn, ss->params.WidthIn,
ss->params.Colors, (double)unitPixelTmp * fixedScaleFactor / ss->params.MaxValueIn);
/* Prepare the weights for the first output row. */
Modified: trunk/gs/src/sisparam.h
===================================================================
--- trunk/gs/src/sisparam.h 2008-02-12 19:03:19 UTC (rev 8521)
+++ trunk/gs/src/sisparam.h 2008-02-12 20:30:17 UTC (rev 8522)
@@ -56,6 +56,9 @@
/* 0 < MaxValueOut < 1 << BitsPerComponentOut*/
int WidthOut, HeightOut; /* > 0 */
bool ColorPolarityAdditive; /* needed by SpecialDownScale filter */
+ double xscale; /* X scaling factor when the image covers fractional pixels. */
+ double yscale; /* Y scaling factor when the image covers fractional pixels. */
+ float dst_y_offset; /* Offset of the subimage due to grid fitting. */
} stream_image_scale_params_t;
/* Define a generic image scaling stream state. */
More information about the gs-cvs
mailing list