Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1996, 1997, 1998, 1999 Aladdin Enterprises.  All rights reserved.
2
 
3
  This software is provided AS-IS with no warranty, either express or
4
  implied.
5
 
6
  This software is distributed under license and may not be copied,
7
  modified or distributed except as expressly authorized under the terms
8
  of the license contained in the file LICENSE in this distribution.
9
 
10
  For more information about licensing, please refer to
11
  http://www.ghostscript.com/licensing/. For information on
12
  commercial licensing, go to http://www.artifex.com/licensing/ or
13
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15
*/
16
 
17
/* $Id: gxiscale.c,v 1.9 2005/06/20 08:59:23 igor Exp $ */
18
/* Interpolated image procedures */
19
#include "gx.h"
20
#include "math_.h"
21
#include "memory_.h"
22
#include "gpcheck.h"
23
#include "gserrors.h"
24
#include "gxfixed.h"
25
#include "gxfrac.h"
26
#include "gxarith.h"
27
#include "gxmatrix.h"
28
#include "gsccolor.h"
29
#include "gspaint.h"
30
#include "gxdevice.h"
31
#include "gxcmap.h"
32
#include "gxdcolor.h"
33
#include "gxistate.h"
34
#include "gxdevmem.h"
35
#include "gxcpath.h"
36
#include "gximage.h"
37
#include "stream.h"		/* for s_alloc_state */
38
#include "siinterp.h"		/* for spatial interpolation */
39
#include "siscale.h"		/* for Mitchell filtering */
40
 
41
/*
42
 * Define whether we are using Mitchell filtering or spatial
43
 * interpolation to implement Interpolate.  (The latter doesn't work yet.)
44
 */
45
#define USE_MITCHELL_FILTER
46
 
47
/* ------ Strategy procedure ------ */
48
 
49
/* Check the prototype. */
50
iclass_proc(gs_image_class_0_interpolate);
51
 
52
/* If we're interpolating, use special logic. */
53
private irender_proc(image_render_interpolate);
54
irender_proc_t
55
gs_image_class_0_interpolate(gx_image_enum * penum)
56
{
57
    const gs_imager_state *pis = penum->pis;
58
    gs_memory_t *mem = penum->memory;
59
    stream_image_scale_params_t iss;
60
    stream_image_scale_state *pss;
61
    const stream_template *template;
62
    byte *line;
63
    const gs_color_space *pcs = penum->pcs;
64
    const gs_color_space *pccs;
65
    gs_point dst_xy;
66
    uint in_size;
67
 
68
    if (!penum->interpolate) 
69
	return 0;
70
    if (penum->use_mask_color || penum->posture != image_portrait ||
71
    	penum->masked || penum->alpha ||
72
	(penum->dev->color_info.num_components == 1 &&
73
	 penum->dev->color_info.max_gray < 15) ||
74
        (penum->dev->color_info.num_components > 1 &&
75
         penum->dev->color_info.max_color < 15)
76
       ) {
77
	/* We can't handle these cases yet.  Punt. */
78
	penum->interpolate = false;
79
	return 0;
80
    }
81
/*
82
 * USE_CONSERVATIVE_INTERPOLATION_RULES is normally NOT defined since
83
 * the MITCHELL digital filter seems OK as long as we are going out to
84
 * a device that can produce > 15 shades.
85
 */
86
#if defined(USE_MITCHELL_FILTER) && defined(USE_CONSERVATIVE_INTERPOLATION_RULES)
87
    /*
88
     * We interpolate using a digital filter, rather than Adobe's
89
     * spatial interpolation algorithm: this produces very bad-looking
90
     * results if the input resolution is close to the output resolution,
91
     * especially if the input has low color resolution, so we resort to
92
     * some hack tests on the input color resolution and scale to suppress
93
     * interpolation if we think the result would look especially bad.
94
     * If we used Adobe's spatial interpolation approach, we wouldn't need
95
     * to do this, but the spatial interpolation filter doesn't work yet.
96
     */
97
    if (penum->bps < 4 || penum->bps * penum->spp < 8 ||
98
	(fabs(penum->matrix.xx) <= 5 && fabs(penum->matrix.yy <= 5))
99
	) {
100
	penum->interpolate = false;
101
	return 0;
102
    }
103
#endif
104
    /* Non-ANSI compilers require the following casts: */
105
    gs_distance_transform((float)penum->rect.w, (float)penum->rect.h,
106
			  &penum->matrix, &dst_xy);
107
    iss.BitsPerComponentOut = sizeof(frac) * 8;
108
    iss.MaxValueOut = frac_1;
109
    iss.WidthOut = (int)ceil(fabs(dst_xy.x));
110
    iss.HeightOut = (int)ceil(fabs(dst_xy.y));
111
    iss.WidthIn = penum->rect.w;
112
    iss.HeightIn = penum->rect.h;
113
    pccs = cs_concrete_space(pcs, pis);
114
    iss.Colors = cs_num_components(pccs);
115
    if (penum->bps <= 8 && penum->device_color) {
116
	iss.BitsPerComponentIn = 8;
117
	iss.MaxValueIn = 0xff;
118
	in_size =
119
	    (penum->matrix.xx < 0 ?
120
	     /* We need a buffer for reversing each scan line. */
121
	     iss.WidthIn * iss.Colors : 0);
122
    } else {
123
	iss.BitsPerComponentIn = sizeof(frac) * 8;
124
	iss.MaxValueIn = frac_1;
125
	in_size = round_up(iss.WidthIn * iss.Colors * sizeof(frac),
126
			   align_bitmap_mod);
127
    }
128
    /* Allocate a buffer for one source/destination line. */
129
    {
130
	uint out_size =
131
	    iss.WidthOut * max(iss.Colors * (iss.BitsPerComponentOut / 8),
132
			       arch_sizeof_color_index);
133
 
134
	line = gs_alloc_bytes(mem, in_size + out_size,
135
			      "image scale src+dst line");
136
    }
137
#ifdef USE_MITCHELL_FILTER
138
    template = &s_IScale_template;
139
#else
140
    template = &s_IIEncode_template;
141
#endif
142
    pss = (stream_image_scale_state *)
143
	s_alloc_state(mem, template->stype, "image scale state");
144
    if (line == 0 || pss == 0 ||
145
	(pss->params = iss, pss->template = template,
146
	 (*pss->template->init) ((stream_state *) pss) < 0)
147
	) {
148
	gs_free_object(mem, pss, "image scale state");
149
	gs_free_object(mem, line, "image scale src+dst line");
150
	/* Try again without interpolation. */
151
	penum->interpolate = false;
152
	return 0;
153
    }
154
    penum->line = line;
155
    penum->scaler = pss;
156
    penum->line_xy = 0;
157
    {
158
	gx_dda_fixed x0;
159
 
160
	x0 = penum->dda.pixel0.x;
161
	if (penum->matrix.xx < 0)
162
	    dda_advance(x0, penum->rect.w);
163
	penum->xyi.x = fixed2int_pixround(dda_current(x0));
164
    }
165
    penum->xyi.y = fixed2int_pixround(dda_current(penum->dda.pixel0.y));
166
    if_debug0('b', "[b]render=interpolate\n");
167
    return &image_render_interpolate;
168
}
169
 
170
/* ------ Rendering for interpolated images ------ */
171
 
172
private int
173
image_render_interpolate(gx_image_enum * penum, const byte * buffer,
174
			 int data_x, uint iw, int h, gx_device * dev)
175
{
176
    stream_image_scale_state *pss = penum->scaler;
177
    const gs_imager_state *pis = penum->pis;
178
    const gs_color_space *pcs = penum->pcs;
179
    gs_logical_operation_t lop = penum->log_op;
180
    int c = pss->params.Colors;
181
    stream_cursor_read r;
182
    stream_cursor_write w;
183
    byte *out = penum->line;
184
 
185
    if (h != 0) {
186
	/* Convert the unpacked data to concrete values in */
187
	/* the source buffer. */
188
	int sizeofPixelIn = pss->params.BitsPerComponentIn / 8;
189
	uint row_size = pss->params.WidthIn * c * sizeofPixelIn;
190
	const byte *bdata = buffer + data_x * c * sizeofPixelIn;
191
 
192
	if (sizeofPixelIn == 1) {
193
	    /* Easy case: 8-bit device color values. */
194
	    if (penum->matrix.xx >= 0) {
195
		/* Use the input data directly. */
196
		r.ptr = bdata - 1;
197
	    } else {
198
		/* Mirror the data in X. */
199
		const byte *p = bdata + row_size - c;
200
		byte *q = out;
201
		int i;
202
 
203
		for (i = 0; i < pss->params.WidthIn; p -= c, q += c, ++i)
204
		    memcpy(q, p, c);
205
		r.ptr = out - 1;
206
		out = q;
207
	    }
208
	} else {
209
	    /* Messy case: concretize each sample. */
210
	    int bps = penum->bps;
211
	    int dc = penum->spp;
212
	    const byte *pdata = bdata;
213
	    frac *psrc = (frac *) penum->line;
214
	    gs_client_color cc;
215
	    int i;
216
 
217
	    r.ptr = (byte *) psrc - 1;
218
	    if_debug0('B', "[B]Concrete row:\n[B]");
219
	    for (i = 0; i < pss->params.WidthIn; i++, psrc += c) {
220
		int j;
221
 
222
		if (bps <= 8)
223
		    for (j = 0; j < dc; ++pdata, ++j) {
224
			decode_sample(*pdata, cc, j);
225
		} else		/* bps == 12 */
226
		    for (j = 0; j < dc; pdata += sizeof(frac), ++j) {
227
			decode_frac(*(const frac *)pdata, cc, j);
228
		    }
229
		(*pcs->type->concretize_color) (&cc, pcs, psrc, pis);
230
#ifdef DEBUG
231
		if (gs_debug_c('B')) {
232
		    int ci;
233
 
234
		    for (ci = 0; ci < c; ++ci)
235
			dprintf2("%c%04x", (ci == 0 ? ' ' : ','), psrc[ci]);
236
		}
237
#endif
238
	    }
239
	    out += round_up(pss->params.WidthIn * c * sizeof(frac),
240
			    align_bitmap_mod);
241
	    if_debug0('B', "\n");
242
	}
243
	r.limit = r.ptr + row_size;
244
    } else			/* h == 0 */
245
	r.ptr = 0, r.limit = 0;
246
 
247
    /*
248
     * Process input and/or collect output.  By construction, the pixels are
249
     * 1-for-1 with the device, but the Y coordinate might be inverted.
250
     */
251
 
252
    {
253
	int xo = penum->xyi.x;
254
	int yo = penum->xyi.y;
255
	int width = pss->params.WidthOut;
256
	int sizeofPixelOut = pss->params.BitsPerComponentOut / 8;
257
	int dy;
258
	const gs_color_space *pconcs = cs_concrete_space(pcs, pis);
259
	int bpp = dev->color_info.depth;
260
	uint raster = bitmap_raster(width * bpp);
261
 
262
	if (penum->matrix.yy > 0)
263
	    dy = 1;
264
	else
265
	    dy = -1, yo--;
266
	for (;;) {
267
	    int ry = yo + penum->line_xy * dy;
268
	    int x;
269
	    const frac *psrc;
270
	    gx_device_color devc;
271
	    int status, code;
272
 
273
	    DECLARE_LINE_ACCUM_COPY(out, bpp, xo);
274
 
275
	    w.limit = out + width *
276
		max(c * sizeofPixelOut, arch_sizeof_color_index) - 1;
277
	    w.ptr = w.limit - width * c * sizeofPixelOut;
278
	    psrc = (const frac *)(w.ptr + 1);
279
	    status = (*pss->template->process)
280
		((stream_state *) pss, &r, &w, h == 0);
281
	    if (status < 0 && status != EOFC)
282
		return_error(gs_error_ioerror);
283
	    if (w.ptr == w.limit) {
284
		int xe = xo + width;
285
 
286
		if_debug1('B', "[B]Interpolated row %d:\n[B]",
287
			  penum->line_xy);
288
		for (x = xo; x < xe;) {
289
#ifdef DEBUG
290
		    if (gs_debug_c('B')) {
291
			int ci;
292
 
293
			for (ci = 0; ci < c; ++ci)
294
			    dprintf2("%c%04x", (ci == 0 ? ' ' : ','),
295
				     psrc[ci]);
296
		    }
297
#endif
298
		    code = (*pconcs->type->remap_concrete_color)
299
			(psrc, pcs, &devc, pis, dev, gs_color_select_source);
300
		    if (code < 0)
301
			return code;
302
		    if (color_is_pure(&devc)) {
303
			/* Just pack colors into a scan line. */
304
			gx_color_index color = devc.colors.pure;
305
 
306
			/* Skip RGB runs quickly. */
307
			if (c == 3) {
308
			    do {
309
				LINE_ACCUM(color, bpp);
310
				x++, psrc += 3;
311
			    } while (x < xe && psrc[-3] == psrc[0] &&
312
				     psrc[-2] == psrc[1] &&
313
				     psrc[-1] == psrc[2]);
314
			} else {
315
			    LINE_ACCUM(color, bpp);
316
			    x++, psrc += c;
317
			}
318
		    } else {
319
			int rcode;
320
 
321
			LINE_ACCUM_COPY(dev, out, bpp, xo, x, raster, ry);
322
			rcode = gx_fill_rectangle_device_rop(x, ry,
323
						     1, 1, &devc, dev, lop);
324
			if (rcode < 0)
325
			    return rcode;
326
			LINE_ACCUM_SKIP(bpp);
327
			l_xprev = x + 1;
328
			x++, psrc += c;
329
		    }
330
		}
331
		LINE_ACCUM_COPY(dev, out, bpp, xo, x, raster, ry);
332
		penum->line_xy++;
333
		if_debug0('B', "\n");
334
	    }
335
	    if ((status == 0 && r.ptr == r.limit) || status == EOFC)
336
		break;
337
	}
338
    }
339
 
340
    return (h == 0 ? 0 : 1);
341
}