2 |
- |
1 |
/* Copyright (C) 1989, 1995, 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: gxipixel.c,v 1.12 2005/07/21 19:32:06 alexcher Exp $ */
|
|
|
18 |
/* Common code for ImageType 1 and 4 initialization */
|
|
|
19 |
#include "gx.h"
|
|
|
20 |
#include "math_.h"
|
|
|
21 |
#include "memory_.h"
|
|
|
22 |
#include "gpcheck.h"
|
|
|
23 |
#include "gscdefs.h" /* for image class table */
|
|
|
24 |
#include "gserrors.h"
|
|
|
25 |
#include "gsstruct.h"
|
|
|
26 |
#include "gsutil.h"
|
|
|
27 |
#include "gxfixed.h"
|
|
|
28 |
#include "gxfrac.h"
|
|
|
29 |
#include "gxarith.h"
|
|
|
30 |
#include "gxmatrix.h"
|
|
|
31 |
#include "gsccolor.h"
|
|
|
32 |
#include "gspaint.h"
|
|
|
33 |
#include "gzstate.h"
|
|
|
34 |
#include "gxdevice.h"
|
|
|
35 |
#include "gzpath.h"
|
|
|
36 |
#include "gzcpath.h"
|
|
|
37 |
#include "gxdevmem.h"
|
|
|
38 |
#include "gximage.h"
|
|
|
39 |
#include "gxiparam.h"
|
|
|
40 |
#include "gdevmrop.h"
|
|
|
41 |
|
|
|
42 |
/* Structure descriptors */
|
|
|
43 |
private_st_gx_image_enum();
|
|
|
44 |
|
|
|
45 |
/* Image class procedures */
|
|
|
46 |
extern_gx_image_class_table();
|
|
|
47 |
|
|
|
48 |
/* Enumerator procedures */
|
|
|
49 |
private const gx_image_enum_procs_t image1_enum_procs = {
|
|
|
50 |
gx_image1_plane_data, gx_image1_end_image, gx_image1_flush
|
|
|
51 |
};
|
|
|
52 |
|
|
|
53 |
/* GC procedures */
|
|
|
54 |
private
|
|
|
55 |
ENUM_PTRS_WITH(image_enum_enum_ptrs, gx_image_enum *eptr)
|
|
|
56 |
{
|
|
|
57 |
int bps;
|
|
|
58 |
gs_ptr_type_t ret;
|
|
|
59 |
|
|
|
60 |
/* Enumerate the used members of clues.dev_color. */
|
|
|
61 |
index -= gx_image_enum_num_ptrs;
|
|
|
62 |
bps = eptr->unpack_bps;
|
|
|
63 |
if (eptr->spp != 1)
|
|
|
64 |
bps = 8;
|
|
|
65 |
else if (bps > 8 || eptr->unpack == sample_unpack_copy)
|
|
|
66 |
bps = 1;
|
|
|
67 |
if (index >= (1 << bps) * st_device_color_max_ptrs) /* done */
|
|
|
68 |
return 0;
|
|
|
69 |
ret = ENUM_USING(st_device_color,
|
|
|
70 |
&eptr->clues[(index / st_device_color_max_ptrs) *
|
|
|
71 |
(255 / ((1 << bps) - 1))].dev_color,
|
|
|
72 |
sizeof(eptr->clues[0].dev_color),
|
|
|
73 |
index % st_device_color_max_ptrs);
|
|
|
74 |
if (ret == 0) /* don't stop early */
|
|
|
75 |
ENUM_RETURN(0);
|
|
|
76 |
return ret;
|
|
|
77 |
}
|
|
|
78 |
#define e1(i,elt) ENUM_PTR(i,gx_image_enum,elt);
|
|
|
79 |
gx_image_enum_do_ptrs(e1)
|
|
|
80 |
#undef e1
|
|
|
81 |
ENUM_PTRS_END
|
|
|
82 |
private RELOC_PTRS_WITH(image_enum_reloc_ptrs, gx_image_enum *eptr)
|
|
|
83 |
{
|
|
|
84 |
int i;
|
|
|
85 |
|
|
|
86 |
#define r1(i,elt) RELOC_PTR(gx_image_enum,elt);
|
|
|
87 |
gx_image_enum_do_ptrs(r1)
|
|
|
88 |
#undef r1
|
|
|
89 |
{
|
|
|
90 |
int bps = eptr->unpack_bps;
|
|
|
91 |
|
|
|
92 |
if (eptr->spp != 1)
|
|
|
93 |
bps = 8;
|
|
|
94 |
else if (bps > 8 || eptr->unpack == sample_unpack_copy)
|
|
|
95 |
bps = 1;
|
|
|
96 |
for (i = 0; i <= 255; i += 255 / ((1 << bps) - 1))
|
|
|
97 |
RELOC_USING(st_device_color,
|
|
|
98 |
&eptr->clues[i].dev_color, sizeof(gx_device_color));
|
|
|
99 |
}
|
|
|
100 |
}
|
|
|
101 |
RELOC_PTRS_END
|
|
|
102 |
|
|
|
103 |
/* Forward declarations */
|
|
|
104 |
private int color_draws_b_w(gx_device * dev,
|
|
|
105 |
const gx_drawing_color * pdcolor);
|
|
|
106 |
private void image_init_map(byte * map, int map_size, const float *decode);
|
|
|
107 |
private void image_init_colors(gx_image_enum * penum, int bps, int spp,
|
|
|
108 |
gs_image_format_t format,
|
|
|
109 |
const float *decode,
|
|
|
110 |
const gs_imager_state * pis, gx_device * dev,
|
|
|
111 |
const gs_color_space * pcs, bool * pdcb);
|
|
|
112 |
|
|
|
113 |
/* Procedures for unpacking the input data into bytes or fracs. */
|
|
|
114 |
/*extern SAMPLE_UNPACK_PROC(sample_unpack_copy); *//* declared above */
|
|
|
115 |
|
|
|
116 |
/*
|
|
|
117 |
* Do common initialization for processing an ImageType 1 or 4 image.
|
|
|
118 |
* Allocate the enumerator and fill in the following members:
|
|
|
119 |
* rect
|
|
|
120 |
*/
|
|
|
121 |
int
|
|
|
122 |
gx_image_enum_alloc(const gs_image_common_t * pic,
|
|
|
123 |
const gs_int_rect * prect, gs_memory_t * mem,
|
|
|
124 |
gx_image_enum **ppenum)
|
|
|
125 |
{
|
|
|
126 |
const gs_pixel_image_t *pim = (const gs_pixel_image_t *)pic;
|
|
|
127 |
int width = pim->Width, height = pim->Height;
|
|
|
128 |
int bpc = pim->BitsPerComponent;
|
|
|
129 |
gx_image_enum *penum;
|
|
|
130 |
|
|
|
131 |
if (width < 0 || height < 0)
|
|
|
132 |
return_error(gs_error_rangecheck);
|
|
|
133 |
switch (pim->format) {
|
|
|
134 |
case gs_image_format_chunky:
|
|
|
135 |
case gs_image_format_component_planar:
|
|
|
136 |
switch (bpc) {
|
|
|
137 |
case 1: case 2: case 4: case 8: case 12: case 16: break;
|
|
|
138 |
default: return_error(gs_error_rangecheck);
|
|
|
139 |
}
|
|
|
140 |
break;
|
|
|
141 |
case gs_image_format_bit_planar:
|
|
|
142 |
if (bpc < 1 || bpc > 8)
|
|
|
143 |
return_error(gs_error_rangecheck);
|
|
|
144 |
}
|
|
|
145 |
if (prect) {
|
|
|
146 |
if (prect->p.x < 0 || prect->p.y < 0 ||
|
|
|
147 |
prect->q.x < prect->p.x || prect->q.y < prect->p.y ||
|
|
|
148 |
prect->q.x > width || prect->q.y > height
|
|
|
149 |
)
|
|
|
150 |
return_error(gs_error_rangecheck);
|
|
|
151 |
}
|
|
|
152 |
penum = gs_alloc_struct(mem, gx_image_enum, &st_gx_image_enum,
|
|
|
153 |
"gx_default_begin_image");
|
|
|
154 |
if (penum == 0)
|
|
|
155 |
return_error(gs_error_VMerror);
|
|
|
156 |
if (prect) {
|
|
|
157 |
penum->rect.x = prect->p.x;
|
|
|
158 |
penum->rect.y = prect->p.y;
|
|
|
159 |
penum->rect.w = prect->q.x - prect->p.x;
|
|
|
160 |
penum->rect.h = prect->q.y - prect->p.y;
|
|
|
161 |
} else {
|
|
|
162 |
penum->rect.x = 0, penum->rect.y = 0;
|
|
|
163 |
penum->rect.w = width, penum->rect.h = height;
|
|
|
164 |
}
|
|
|
165 |
#ifdef DEBUG
|
|
|
166 |
if (gs_debug_c('b')) {
|
|
|
167 |
dlprintf2("[b]Image: w=%d h=%d", width, height);
|
|
|
168 |
if (prect)
|
|
|
169 |
dprintf4(" ((%d,%d),(%d,%d))",
|
|
|
170 |
prect->p.x, prect->p.y, prect->q.x, prect->q.y);
|
|
|
171 |
}
|
|
|
172 |
#endif
|
|
|
173 |
*ppenum = penum;
|
|
|
174 |
return 0;
|
|
|
175 |
}
|
|
|
176 |
|
|
|
177 |
/*
|
|
|
178 |
* Finish initialization for processing an ImageType 1 or 4 image.
|
|
|
179 |
* Assumes the following members of *penum are set in addition to those
|
|
|
180 |
* set by gx_image_enum_alloc:
|
|
|
181 |
* alpha, use_mask_color, mask_color (if use_mask_color is true),
|
|
|
182 |
* masked, adjust
|
|
|
183 |
*/
|
|
|
184 |
int
|
|
|
185 |
gx_image_enum_begin(gx_device * dev, const gs_imager_state * pis,
|
|
|
186 |
const gs_matrix *pmat, const gs_image_common_t * pic,
|
|
|
187 |
const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
|
|
|
188 |
gs_memory_t * mem, gx_image_enum *penum)
|
|
|
189 |
{
|
|
|
190 |
const gs_pixel_image_t *pim = (const gs_pixel_image_t *)pic;
|
|
|
191 |
gs_image_format_t format = pim->format;
|
|
|
192 |
const int width = pim->Width;
|
|
|
193 |
const int height = pim->Height;
|
|
|
194 |
const int bps = pim->BitsPerComponent;
|
|
|
195 |
bool masked = penum->masked;
|
|
|
196 |
const float *decode = pim->Decode;
|
|
|
197 |
gs_matrix mat;
|
|
|
198 |
int index_bps;
|
|
|
199 |
const gs_color_space *pcs = pim->ColorSpace;
|
|
|
200 |
gs_logical_operation_t lop = (pis ? pis->log_op : lop_default);
|
|
|
201 |
int code;
|
|
|
202 |
int log2_xbytes = (bps <= 8 ? 0 : arch_log2_sizeof_frac);
|
|
|
203 |
int spp, nplanes, spread;
|
|
|
204 |
uint bsize;
|
|
|
205 |
byte *buffer;
|
|
|
206 |
fixed mtx, mty;
|
|
|
207 |
gs_fixed_point row_extent, col_extent, x_extent, y_extent;
|
|
|
208 |
bool device_color;
|
|
|
209 |
gs_fixed_rect obox, cbox;
|
|
|
210 |
|
|
|
211 |
if (pmat == 0)
|
|
|
212 |
pmat = &ctm_only(pis);
|
|
|
213 |
if ((code = gs_matrix_invert(&pim->ImageMatrix, &mat)) < 0 ||
|
|
|
214 |
(code = gs_matrix_multiply(&mat, pmat, &mat)) < 0
|
|
|
215 |
) {
|
|
|
216 |
gs_free_object(mem, penum, "gx_default_begin_image");
|
|
|
217 |
return code;
|
|
|
218 |
}
|
|
|
219 |
penum->matrix = mat;
|
|
|
220 |
if_debug6('b', " [%g %g %g %g %g %g]\n",
|
|
|
221 |
mat.xx, mat.xy, mat.yx, mat.yy, mat.tx, mat.ty);
|
|
|
222 |
/* following works for 1, 2, 4, 8, 12, 16 */
|
|
|
223 |
index_bps = (bps < 8 ? bps >> 1 : (bps >> 2) + 1);
|
|
|
224 |
mtx = float2fixed(mat.tx);
|
|
|
225 |
mty = float2fixed(mat.ty);
|
|
|
226 |
row_extent.x = float2fixed(width * mat.xx + mat.tx) - mtx;
|
|
|
227 |
row_extent.y =
|
|
|
228 |
(is_fzero(mat.xy) ? fixed_0 :
|
|
|
229 |
float2fixed(width * mat.xy + mat.ty) - mty);
|
|
|
230 |
col_extent.x =
|
|
|
231 |
(is_fzero(mat.yx) ? fixed_0 :
|
|
|
232 |
float2fixed(height * mat.yx + mat.tx) - mtx);
|
|
|
233 |
col_extent.y = float2fixed(height * mat.yy + mat.ty) - mty;
|
|
|
234 |
gx_image_enum_common_init((gx_image_enum_common_t *)penum,
|
|
|
235 |
(const gs_data_image_t *)pim,
|
|
|
236 |
&image1_enum_procs, dev,
|
|
|
237 |
(masked ? 1 : cs_num_components(pcs)),
|
|
|
238 |
format);
|
|
|
239 |
if (penum->rect.w == width && penum->rect.h == height) {
|
|
|
240 |
x_extent = row_extent;
|
|
|
241 |
y_extent = col_extent;
|
|
|
242 |
} else {
|
|
|
243 |
int rw = penum->rect.w, rh = penum->rect.h;
|
|
|
244 |
|
|
|
245 |
x_extent.x = float2fixed(rw * mat.xx + mat.tx) - mtx;
|
|
|
246 |
x_extent.y =
|
|
|
247 |
(is_fzero(mat.xy) ? fixed_0 :
|
|
|
248 |
float2fixed(rw * mat.xy + mat.ty) - mty);
|
|
|
249 |
y_extent.x =
|
|
|
250 |
(is_fzero(mat.yx) ? fixed_0 :
|
|
|
251 |
float2fixed(rh * mat.yx + mat.tx) - mtx);
|
|
|
252 |
y_extent.y = float2fixed(rh * mat.yy + mat.ty) - mty;
|
|
|
253 |
}
|
|
|
254 |
if (masked) { /* This is imagemask. */
|
|
|
255 |
if (bps != 1 || pcs != NULL || penum->alpha || decode[0] == decode[1]) {
|
|
|
256 |
gs_free_object(mem, penum, "gx_default_begin_image");
|
|
|
257 |
return_error(gs_error_rangecheck);
|
|
|
258 |
}
|
|
|
259 |
/* Initialize color entries 0 and 255. */
|
|
|
260 |
set_nonclient_dev_color(&penum->icolor0, gx_no_color_index);
|
|
|
261 |
penum->icolor1 = *pdcolor;
|
|
|
262 |
memcpy(&penum->map[0].table.lookup4x1to32[0],
|
|
|
263 |
(decode[0] < decode[1] ? lookup4x1to32_inverted :
|
|
|
264 |
lookup4x1to32_identity),
|
|
|
265 |
16 * 4);
|
|
|
266 |
penum->map[0].decoding = sd_none;
|
|
|
267 |
spp = 1;
|
|
|
268 |
lop = rop3_know_S_0(lop);
|
|
|
269 |
} else { /* This is image, not imagemask. */
|
|
|
270 |
const gs_color_space_type *pcst = pcs->type;
|
|
|
271 |
int b_w_color;
|
|
|
272 |
|
|
|
273 |
spp = cs_num_components(pcs);
|
|
|
274 |
if (spp < 0) { /* Pattern not allowed */
|
|
|
275 |
gs_free_object(mem, penum, "gx_default_begin_image");
|
|
|
276 |
return_error(gs_error_rangecheck);
|
|
|
277 |
}
|
|
|
278 |
if (penum->alpha)
|
|
|
279 |
++spp;
|
|
|
280 |
/* Use a less expensive format if possible. */
|
|
|
281 |
switch (format) {
|
|
|
282 |
case gs_image_format_bit_planar:
|
|
|
283 |
if (bps > 1)
|
|
|
284 |
break;
|
|
|
285 |
format = gs_image_format_component_planar;
|
|
|
286 |
case gs_image_format_component_planar:
|
|
|
287 |
if (spp == 1)
|
|
|
288 |
format = gs_image_format_chunky;
|
|
|
289 |
default: /* chunky */
|
|
|
290 |
break;
|
|
|
291 |
}
|
|
|
292 |
device_color = (*pcst->concrete_space) (pcs, pis) == pcs;
|
|
|
293 |
image_init_colors(penum, bps, spp, format, decode, pis, dev,
|
|
|
294 |
pcs, &device_color);
|
|
|
295 |
/* Try to transform non-default RasterOps to something */
|
|
|
296 |
/* that we implement less expensively. */
|
|
|
297 |
if (!pim->CombineWithColor)
|
|
|
298 |
lop = rop3_know_T_0(lop) & ~lop_T_transparent;
|
|
|
299 |
else {
|
|
|
300 |
if (rop3_uses_T(lop))
|
|
|
301 |
switch (color_draws_b_w(dev, pdcolor)) {
|
|
|
302 |
case 0:
|
|
|
303 |
lop = rop3_know_T_0(lop);
|
|
|
304 |
break;
|
|
|
305 |
case 1:
|
|
|
306 |
lop = rop3_know_T_1(lop);
|
|
|
307 |
break;
|
|
|
308 |
default:
|
|
|
309 |
;
|
|
|
310 |
}
|
|
|
311 |
}
|
|
|
312 |
if (lop != rop3_S && /* if best case, no more work needed */
|
|
|
313 |
!rop3_uses_T(lop) && bps == 1 && spp == 1 &&
|
|
|
314 |
(b_w_color =
|
|
|
315 |
color_draws_b_w(dev, &penum->icolor0)) >= 0 &&
|
|
|
316 |
color_draws_b_w(dev, &penum->icolor1) == (b_w_color ^ 1)
|
|
|
317 |
) {
|
|
|
318 |
if (b_w_color) { /* Swap the colors and invert the RasterOp source. */
|
|
|
319 |
gx_device_color dcolor;
|
|
|
320 |
|
|
|
321 |
dcolor = penum->icolor0;
|
|
|
322 |
penum->icolor0 = penum->icolor1;
|
|
|
323 |
penum->icolor1 = dcolor;
|
|
|
324 |
lop = rop3_invert_S(lop);
|
|
|
325 |
}
|
|
|
326 |
/*
|
|
|
327 |
* At this point, we know that the source pixels
|
|
|
328 |
* correspond directly to the S input for the raster op,
|
|
|
329 |
* i.e., icolor0 is black and icolor1 is white.
|
|
|
330 |
*/
|
|
|
331 |
switch (lop) {
|
|
|
332 |
case rop3_D & rop3_S:
|
|
|
333 |
/* Implement this as an inverted mask writing 0s. */
|
|
|
334 |
penum->icolor1 = penum->icolor0;
|
|
|
335 |
/* (falls through) */
|
|
|
336 |
case rop3_D | rop3_not(rop3_S):
|
|
|
337 |
/* Implement this as an inverted mask writing 1s. */
|
|
|
338 |
memcpy(&penum->map[0].table.lookup4x1to32[0],
|
|
|
339 |
lookup4x1to32_inverted, 16 * 4);
|
|
|
340 |
rmask: /* Fill in the remaining parameters for a mask. */
|
|
|
341 |
penum->masked = masked = true;
|
|
|
342 |
set_nonclient_dev_color(&penum->icolor0, gx_no_color_index);
|
|
|
343 |
penum->map[0].decoding = sd_none;
|
|
|
344 |
lop = rop3_T;
|
|
|
345 |
break;
|
|
|
346 |
case rop3_D & rop3_not(rop3_S):
|
|
|
347 |
/* Implement this as a mask writing 0s. */
|
|
|
348 |
penum->icolor1 = penum->icolor0;
|
|
|
349 |
/* (falls through) */
|
|
|
350 |
case rop3_D | rop3_S:
|
|
|
351 |
/* Implement this as a mask writing 1s. */
|
|
|
352 |
memcpy(&penum->map[0].table.lookup4x1to32[0],
|
|
|
353 |
lookup4x1to32_identity, 16 * 4);
|
|
|
354 |
goto rmask;
|
|
|
355 |
default:
|
|
|
356 |
;
|
|
|
357 |
}
|
|
|
358 |
}
|
|
|
359 |
}
|
|
|
360 |
penum->device_color = device_color;
|
|
|
361 |
/*
|
|
|
362 |
* Adjust width upward for unpacking up to 7 trailing bits in
|
|
|
363 |
* the row, plus 1 byte for end-of-run, plus up to 7 leading
|
|
|
364 |
* bits for data_x offset within a packed byte.
|
|
|
365 |
*/
|
|
|
366 |
bsize = ((bps > 8 ? width * 2 : width) + 15) * spp;
|
|
|
367 |
buffer = gs_alloc_bytes(mem, bsize, "image buffer");
|
|
|
368 |
if (buffer == 0) {
|
|
|
369 |
gs_free_object(mem, penum, "gx_default_begin_image");
|
|
|
370 |
return_error(gs_error_VMerror);
|
|
|
371 |
}
|
|
|
372 |
penum->bps = bps;
|
|
|
373 |
penum->unpack_bps = bps;
|
|
|
374 |
penum->log2_xbytes = log2_xbytes;
|
|
|
375 |
penum->spp = spp;
|
|
|
376 |
switch (format) {
|
|
|
377 |
case gs_image_format_chunky:
|
|
|
378 |
nplanes = 1;
|
|
|
379 |
spread = 1 << log2_xbytes;
|
|
|
380 |
break;
|
|
|
381 |
case gs_image_format_component_planar:
|
|
|
382 |
nplanes = spp;
|
|
|
383 |
spread = spp << log2_xbytes;
|
|
|
384 |
break;
|
|
|
385 |
case gs_image_format_bit_planar:
|
|
|
386 |
nplanes = spp * bps;
|
|
|
387 |
spread = spp << log2_xbytes;
|
|
|
388 |
break;
|
|
|
389 |
default:
|
|
|
390 |
/* No other cases are possible (checked by gx_image_enum_alloc). */
|
|
|
391 |
return_error(gs_error_Fatal);
|
|
|
392 |
}
|
|
|
393 |
penum->num_planes = nplanes;
|
|
|
394 |
penum->spread = spread;
|
|
|
395 |
/*
|
|
|
396 |
* If we're asked to interpolate in a partial image, we have to
|
|
|
397 |
* assume that the client either really only is interested in
|
|
|
398 |
* the given sub-image, or else is constructing output out of
|
|
|
399 |
* overlapping pieces.
|
|
|
400 |
*/
|
|
|
401 |
penum->interpolate = pim->Interpolate;
|
|
|
402 |
penum->x_extent = x_extent;
|
|
|
403 |
penum->y_extent = y_extent;
|
|
|
404 |
penum->posture =
|
|
|
405 |
((x_extent.y | y_extent.x) == 0 ? image_portrait :
|
|
|
406 |
(x_extent.x | y_extent.y) == 0 ? image_landscape :
|
|
|
407 |
image_skewed);
|
|
|
408 |
penum->pis = pis;
|
|
|
409 |
penum->pcs = pcs;
|
|
|
410 |
penum->memory = mem;
|
|
|
411 |
penum->buffer = buffer;
|
|
|
412 |
penum->buffer_size = bsize;
|
|
|
413 |
penum->line = 0;
|
|
|
414 |
penum->line_size = 0;
|
|
|
415 |
penum->use_rop = lop != (masked ? rop3_T : rop3_S);
|
|
|
416 |
#ifdef DEBUG
|
|
|
417 |
if (gs_debug_c('*')) {
|
|
|
418 |
if (penum->use_rop)
|
|
|
419 |
dprintf1("[%03x]", lop);
|
|
|
420 |
dprintf5("%c%d%c%dx%d ",
|
|
|
421 |
(masked ? (color_is_pure(pdcolor) ? 'm' : 'h') : 'i'),
|
|
|
422 |
bps,
|
|
|
423 |
(penum->posture == image_portrait ? ' ' :
|
|
|
424 |
penum->posture == image_landscape ? 'L' : 'T'),
|
|
|
425 |
width, height);
|
|
|
426 |
}
|
|
|
427 |
#endif
|
|
|
428 |
penum->slow_loop = 0;
|
|
|
429 |
if (pcpath == 0) {
|
|
|
430 |
(*dev_proc(dev, get_clipping_box)) (dev, &obox);
|
|
|
431 |
cbox = obox;
|
|
|
432 |
penum->clip_image = 0;
|
|
|
433 |
} else
|
|
|
434 |
penum->clip_image =
|
|
|
435 |
(gx_cpath_outer_box(pcpath, &obox) | /* not || */
|
|
|
436 |
gx_cpath_inner_box(pcpath, &cbox) ?
|
|
|
437 |
|
|
|
438 |
penum->clip_outer = obox;
|
|
|
439 |
penum->clip_inner = cbox;
|
|
|
440 |
penum->log_op = rop3_T; /* rop device takes care of this */
|
|
|
441 |
penum->clip_dev = 0; /* in case we bail out */
|
|
|
442 |
penum->rop_dev = 0; /* ditto */
|
|
|
443 |
penum->scaler = 0; /* ditto */
|
|
|
444 |
/*
|
|
|
445 |
* If all four extrema of the image fall within the clipping
|
|
|
446 |
* rectangle, clipping is never required. When making this check,
|
|
|
447 |
* we must carefully take into account the fact that we only care
|
|
|
448 |
* about pixel centers.
|
|
|
449 |
*/
|
|
|
450 |
{
|
|
|
451 |
fixed
|
|
|
452 |
epx = min(row_extent.x, 0) + min(col_extent.x, 0),
|
|
|
453 |
eqx = max(row_extent.x, 0) + max(col_extent.x, 0),
|
|
|
454 |
epy = min(row_extent.y, 0) + min(col_extent.y, 0),
|
|
|
455 |
eqy = max(row_extent.y, 0) + max(col_extent.y, 0);
|
|
|
456 |
|
|
|
457 |
{
|
|
|
458 |
int hwx, hwy;
|
|
|
459 |
|
|
|
460 |
switch (penum->posture) {
|
|
|
461 |
case image_portrait:
|
|
|
462 |
hwx = width, hwy = height;
|
|
|
463 |
break;
|
|
|
464 |
case image_landscape:
|
|
|
465 |
hwx = height, hwy = width;
|
|
|
466 |
break;
|
|
|
467 |
default:
|
|
|
468 |
hwx = hwy = 0;
|
|
|
469 |
}
|
|
|
470 |
/*
|
|
|
471 |
* If the image is only 1 sample wide or high,
|
|
|
472 |
* and is less than 1 device pixel wide or high,
|
|
|
473 |
* move it slightly so that it covers pixel centers.
|
|
|
474 |
* This is a hack to work around a bug in some old
|
|
|
475 |
* versions of TeX/dvips, which use 1-bit-high images
|
|
|
476 |
* to draw horizontal and vertical lines without
|
|
|
477 |
* positioning them properly.
|
|
|
478 |
*/
|
|
|
479 |
if (hwx == 1 && eqx - epx < fixed_1) {
|
|
|
480 |
fixed diff =
|
|
|
481 |
arith_rshift_1(row_extent.x + col_extent.x);
|
|
|
482 |
|
|
|
483 |
mtx = (((mtx + diff) | fixed_half) & -fixed_half) - diff;
|
|
|
484 |
}
|
|
|
485 |
if (hwy == 1 && eqy - epy < fixed_1) {
|
|
|
486 |
fixed diff =
|
|
|
487 |
arith_rshift_1(row_extent.y + col_extent.y);
|
|
|
488 |
|
|
|
489 |
mty = (((mty + diff) | fixed_half) & -fixed_half) - diff;
|
|
|
490 |
}
|
|
|
491 |
}
|
|
|
492 |
if_debug5('b', "[b]Image: %sspp=%d, bps=%d, mt=(%g,%g)\n",
|
|
|
493 |
(masked? "masked, " : ""), spp, bps,
|
|
|
494 |
fixed2float(mtx), fixed2float(mty));
|
|
|
495 |
if_debug9('b',
|
|
|
496 |
"[b] cbox=(%g,%g),(%g,%g), obox=(%g,%g),(%g,%g), clip_image=0x%x\n",
|
|
|
497 |
fixed2float(cbox.p.x), fixed2float(cbox.p.y),
|
|
|
498 |
fixed2float(cbox.q.x), fixed2float(cbox.q.y),
|
|
|
499 |
fixed2float(obox.p.x), fixed2float(obox.p.y),
|
|
|
500 |
fixed2float(obox.q.x), fixed2float(obox.q.y),
|
|
|
501 |
penum->clip_image);
|
|
|
502 |
dda_init(penum->dda.row.x, mtx, col_extent.x, height);
|
|
|
503 |
dda_init(penum->dda.row.y, mty, col_extent.y, height);
|
|
|
504 |
if (penum->rect.y) {
|
|
|
505 |
dda_advance(penum->dda.row.x, penum->rect.y);
|
|
|
506 |
dda_advance(penum->dda.row.y, penum->rect.y);
|
|
|
507 |
}
|
|
|
508 |
penum->cur.x = penum->prev.x = dda_current(penum->dda.row.x);
|
|
|
509 |
penum->cur.y = penum->prev.y = dda_current(penum->dda.row.y);
|
|
|
510 |
dda_init(penum->dda.strip.x, penum->cur.x, row_extent.x, width);
|
|
|
511 |
dda_init(penum->dda.strip.y, penum->cur.y, row_extent.y, width);
|
|
|
512 |
if (penum->rect.x) {
|
|
|
513 |
dda_advance(penum->dda.strip.x, penum->rect.x);
|
|
|
514 |
dda_advance(penum->dda.strip.y, penum->rect.x);
|
|
|
515 |
} {
|
|
|
516 |
fixed ox = dda_current(penum->dda.strip.x);
|
|
|
517 |
fixed oy = dda_current(penum->dda.strip.y);
|
|
|
518 |
|
|
|
519 |
if (!penum->clip_image) /* i.e., not clip region */
|
|
|
520 |
penum->clip_image =
|
|
|
521 |
(fixed_pixround(ox + epx) < fixed_pixround(cbox.p.x) ?
|
|
|
522 |
image_clip_xmin : 0) +
|
|
|
523 |
(fixed_pixround(ox + eqx) >= fixed_pixround(cbox.q.x) ?
|
|
|
524 |
image_clip_xmax : 0) +
|
|
|
525 |
(fixed_pixround(oy + epy) < fixed_pixround(cbox.p.y) ?
|
|
|
526 |
image_clip_ymin : 0) +
|
|
|
527 |
(fixed_pixround(oy + eqy) >= fixed_pixround(cbox.q.y) ?
|
|
|
528 |
image_clip_ymax : 0);
|
|
|
529 |
}
|
|
|
530 |
}
|
|
|
531 |
penum->y = 0;
|
|
|
532 |
penum->used.x = 0;
|
|
|
533 |
penum->used.y = 0;
|
|
|
534 |
{
|
|
|
535 |
static sample_unpack_proc_t procs[2][6] = {
|
|
|
536 |
{ sample_unpack_1, sample_unpack_2,
|
|
|
537 |
sample_unpack_4, sample_unpack_8,
|
|
|
538 |
0, 0
|
|
|
539 |
},
|
|
|
540 |
{ sample_unpack_1_interleaved, sample_unpack_2_interleaved,
|
|
|
541 |
sample_unpack_4_interleaved, sample_unpack_8_interleaved,
|
|
|
542 |
0, 0
|
|
|
543 |
}};
|
|
|
544 |
int num_planes = penum->num_planes;
|
|
|
545 |
bool interleaved = (num_planes == 1 && penum->plane_depths[0] != penum->bps);
|
|
|
546 |
int i;
|
|
|
547 |
|
|
|
548 |
procs[0][4] = procs[1][4] = sample_unpack_12_proc;
|
|
|
549 |
procs[0][5] = procs[1][5] = sample_unpack_16_proc;
|
|
|
550 |
if (interleaved) {
|
|
|
551 |
int num_components = penum->plane_depths[0] / penum->bps;
|
|
|
552 |
|
|
|
553 |
for (i = 1; i < num_components; i++) {
|
|
|
554 |
if (decode[0] != decode[i * 2 + 0] ||
|
|
|
555 |
decode[1] != decode[i * 2 + 1])
|
|
|
556 |
break;
|
|
|
557 |
}
|
|
|
558 |
if (i == num_components)
|
|
|
559 |
interleaved = false; /* Use single table. */
|
|
|
560 |
}
|
|
|
561 |
if (index_bps >= 4) {
|
|
|
562 |
if ((penum->unpack = procs[interleaved][index_bps]) == 0) { /* bps case not supported. */
|
|
|
563 |
gx_default_end_image(dev,
|
|
|
564 |
(gx_image_enum_common_t *) penum,
|
|
|
565 |
false);
|
|
|
566 |
return_error(gs_error_rangecheck);
|
|
|
567 |
}
|
|
|
568 |
} else {
|
|
|
569 |
penum->unpack = procs[interleaved][index_bps];
|
|
|
570 |
}
|
|
|
571 |
if_debug1('b', "[b]unpack=%d\n", bps);
|
|
|
572 |
/* Set up pixel0 for image class procedures. */
|
|
|
573 |
penum->dda.pixel0 = penum->dda.strip;
|
|
|
574 |
for (i = 0; i < gx_image_class_table_count; ++i)
|
|
|
575 |
if ((penum->render = gx_image_class_table[i](penum)) != 0)
|
|
|
576 |
break;
|
|
|
577 |
if (i == gx_image_class_table_count) {
|
|
|
578 |
/* No available class can handle this image. */
|
|
|
579 |
gx_default_end_image(dev, (gx_image_enum_common_t *) penum,
|
|
|
580 |
false);
|
|
|
581 |
return_error(gs_error_rangecheck);
|
|
|
582 |
}
|
|
|
583 |
}
|
|
|
584 |
if (penum->clip_image && pcpath) { /* Set up the clipping device. */
|
|
|
585 |
gx_device_clip *cdev =
|
|
|
586 |
gs_alloc_struct(mem, gx_device_clip,
|
|
|
587 |
&st_device_clip, "image clipper");
|
|
|
588 |
|
|
|
589 |
if (cdev == 0) {
|
|
|
590 |
gx_default_end_image(dev,
|
|
|
591 |
(gx_image_enum_common_t *) penum,
|
|
|
592 |
false);
|
|
|
593 |
return_error(gs_error_VMerror);
|
|
|
594 |
}
|
|
|
595 |
gx_make_clip_translate_device(cdev, gx_cpath_list(pcpath), 0, 0, mem);
|
|
|
596 |
gx_device_retain((gx_device *)cdev, true); /* will free explicitly */
|
|
|
597 |
gx_device_set_target((gx_device_forward *)cdev, dev);
|
|
|
598 |
(*dev_proc(cdev, open_device)) ((gx_device *) cdev);
|
|
|
599 |
penum->clip_dev = cdev;
|
|
|
600 |
}
|
|
|
601 |
if (penum->use_rop) { /* Set up the RasterOp source device. */
|
|
|
602 |
gx_device_rop_texture *rtdev;
|
|
|
603 |
|
|
|
604 |
code = gx_alloc_rop_texture_device(&rtdev, mem,
|
|
|
605 |
"image RasterOp");
|
|
|
606 |
if (code < 0) {
|
|
|
607 |
gx_default_end_image(dev, (gx_image_enum_common_t *) penum,
|
|
|
608 |
false);
|
|
|
609 |
return code;
|
|
|
610 |
}
|
|
|
611 |
gx_make_rop_texture_device(rtdev,
|
|
|
612 |
(penum->clip_dev != 0 ?
|
|
|
613 |
(gx_device *) penum->clip_dev :
|
|
|
614 |
dev), lop, pdcolor);
|
|
|
615 |
penum->rop_dev = rtdev;
|
|
|
616 |
}
|
|
|
617 |
return 0;
|
|
|
618 |
}
|
|
|
619 |
|
|
|
620 |
/* If a drawing color is black or white, return 0 or 1 respectively, */
|
|
|
621 |
/* otherwise return -1. */
|
|
|
622 |
private int
|
|
|
623 |
color_draws_b_w(gx_device * dev, const gx_drawing_color * pdcolor)
|
|
|
624 |
{
|
|
|
625 |
if (color_is_pure(pdcolor)) {
|
|
|
626 |
gx_color_value rgb[3];
|
|
|
627 |
|
|
|
628 |
(*dev_proc(dev, map_color_rgb)) (dev, gx_dc_pure_color(pdcolor),
|
|
|
629 |
rgb);
|
|
|
630 |
if (!(rgb[0] | rgb[1] | rgb[2]))
|
|
|
631 |
return 0;
|
|
|
632 |
if ((rgb[0] & rgb[1] & rgb[2]) == gx_max_color_value)
|
|
|
633 |
return 1;
|
|
|
634 |
}
|
|
|
635 |
return -1;
|
|
|
636 |
}
|
|
|
637 |
|
|
|
638 |
/* Export this for use by image_render_ functions */
|
|
|
639 |
void
|
|
|
640 |
image_init_clues(gx_image_enum * penum, int bps, int spp)
|
|
|
641 |
{
|
|
|
642 |
/* Initialize the color table */
|
|
|
643 |
#define ictype(i)\
|
|
|
644 |
penum->clues[i].dev_color.type
|
|
|
645 |
|
|
|
646 |
switch ((spp == 1 ? bps : 8)) {
|
|
|
647 |
case 8: /* includes all color images */
|
|
|
648 |
{
|
|
|
649 |
register gx_image_clue *pcht = &penum->clues[0];
|
|
|
650 |
register int n = 64; /* 8 bits means 256 clues, do */
|
|
|
651 |
/* 4 at a time for efficiency */
|
|
|
652 |
do {
|
|
|
653 |
pcht[0].dev_color.type =
|
|
|
654 |
pcht[1].dev_color.type =
|
|
|
655 |
pcht[2].dev_color.type =
|
|
|
656 |
pcht[3].dev_color.type =
|
|
|
657 |
gx_dc_type_none;
|
|
|
658 |
pcht[0].key = pcht[1].key =
|
|
|
659 |
pcht[2].key = pcht[3].key = 0;
|
|
|
660 |
pcht += 4;
|
|
|
661 |
}
|
|
|
662 |
while (--n > 0);
|
|
|
663 |
penum->clues[0].key = 1; /* guarantee no hit */
|
|
|
664 |
break;
|
|
|
665 |
}
|
|
|
666 |
case 4:
|
|
|
667 |
ictype(17) = ictype(2 * 17) = ictype(3 * 17) =
|
|
|
668 |
ictype(4 * 17) = ictype(6 * 17) = ictype(7 * 17) =
|
|
|
669 |
ictype(8 * 17) = ictype(9 * 17) = ictype(11 * 17) =
|
|
|
670 |
ictype(12 * 17) = ictype(13 * 17) = ictype(14 * 17) =
|
|
|
671 |
gx_dc_type_none;
|
|
|
672 |
/* falls through */
|
|
|
673 |
case 2:
|
|
|
674 |
ictype(5 * 17) = ictype(10 * 17) = gx_dc_type_none;
|
|
|
675 |
#undef ictype
|
|
|
676 |
}
|
|
|
677 |
}
|
|
|
678 |
|
|
|
679 |
/* Initialize the color mapping tables for a non-mask image. */
|
|
|
680 |
private void
|
|
|
681 |
image_init_colors(gx_image_enum * penum, int bps, int spp,
|
|
|
682 |
gs_image_format_t format, const float *decode /*[spp*2] */ ,
|
|
|
683 |
const gs_imager_state * pis, gx_device * dev,
|
|
|
684 |
const gs_color_space * pcs, bool * pdcb)
|
|
|
685 |
{
|
|
|
686 |
int ci;
|
|
|
687 |
static const float default_decode[] = {
|
|
|
688 |
0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0
|
|
|
689 |
};
|
|
|
690 |
|
|
|
691 |
image_init_clues(penum, bps, spp);
|
|
|
692 |
|
|
|
693 |
/* Initialize the maps from samples to intensities. */
|
|
|
694 |
for (ci = 0; ci < spp; ci++) {
|
|
|
695 |
sample_map *pmap = &penum->map[ci];
|
|
|
696 |
|
|
|
697 |
/* If the decoding is [0 1] or [1 0], we can fold it */
|
|
|
698 |
/* into the expansion of the sample values; */
|
|
|
699 |
/* otherwise, we have to use the floating point method. */
|
|
|
700 |
|
|
|
701 |
const float *this_decode = &decode[ci * 2];
|
|
|
702 |
const float *map_decode; /* decoding used to */
|
|
|
703 |
/* construct the expansion map */
|
|
|
704 |
const float *real_decode; /* decoding for expanded samples */
|
|
|
705 |
|
|
|
706 |
bool no_decode;
|
|
|
707 |
|
|
|
708 |
map_decode = real_decode = this_decode;
|
|
|
709 |
if (map_decode[0] == 0.0 && map_decode[1] == 1.0)
|
|
|
710 |
no_decode = true;
|
|
|
711 |
else if (map_decode[0] == 1.0 && map_decode[1] == 0.0 && bps <= 8) {
|
|
|
712 |
no_decode = true;
|
|
|
713 |
real_decode = default_decode;
|
|
|
714 |
} else {
|
|
|
715 |
no_decode = false;
|
|
|
716 |
*pdcb = false;
|
|
|
717 |
map_decode = default_decode;
|
|
|
718 |
}
|
|
|
719 |
if (bps > 2 || format != gs_image_format_chunky) {
|
|
|
720 |
if (bps <= 8)
|
|
|
721 |
image_init_map(&pmap->table.lookup8[0], 1 << bps,
|
|
|
722 |
map_decode);
|
|
|
723 |
} else { /* The map index encompasses more than one pixel. */
|
|
|
724 |
byte map[4];
|
|
|
725 |
register int i;
|
|
|
726 |
|
|
|
727 |
image_init_map(&map[0], 1 << bps, map_decode);
|
|
|
728 |
switch (bps) {
|
|
|
729 |
case 1:
|
|
|
730 |
{
|
|
|
731 |
register bits32 *p = &pmap->table.lookup4x1to32[0];
|
|
|
732 |
|
|
|
733 |
if (map[0] == 0 && map[1] == 0xff)
|
|
|
734 |
memcpy((byte *) p, lookup4x1to32_identity, 16 * 4);
|
|
|
735 |
else if (map[0] == 0xff && map[1] == 0)
|
|
|
736 |
memcpy((byte *) p, lookup4x1to32_inverted, 16 * 4);
|
|
|
737 |
else
|
|
|
738 |
for (i = 0; i < 16; i++, p++)
|
|
|
739 |
((byte *) p)[0] = map[i >> 3],
|
|
|
740 |
((byte *) p)[1] = map[(i >> 2) & 1],
|
|
|
741 |
((byte *) p)[2] = map[(i >> 1) & 1],
|
|
|
742 |
((byte *) p)[3] = map[i & 1];
|
|
|
743 |
}
|
|
|
744 |
break;
|
|
|
745 |
case 2:
|
|
|
746 |
{
|
|
|
747 |
register bits16 *p = &pmap->table.lookup2x2to16[0];
|
|
|
748 |
|
|
|
749 |
for (i = 0; i < 16; i++, p++)
|
|
|
750 |
((byte *) p)[0] = map[i >> 2],
|
|
|
751 |
((byte *) p)[1] = map[i & 3];
|
|
|
752 |
}
|
|
|
753 |
break;
|
|
|
754 |
}
|
|
|
755 |
}
|
|
|
756 |
pmap->decode_base /* = decode_lookup[0] */ = real_decode[0];
|
|
|
757 |
pmap->decode_factor =
|
|
|
758 |
(real_decode[1] - real_decode[0]) /
|
|
|
759 |
(bps <= 8 ? 255.0 : (float)frac_1);
|
|
|
760 |
pmap->decode_max /* = decode_lookup[15] */ = real_decode[1];
|
|
|
761 |
if (no_decode) {
|
|
|
762 |
pmap->decoding = sd_none;
|
|
|
763 |
pmap->inverted = map_decode[0] != 0;
|
|
|
764 |
} else if (bps <= 4) {
|
|
|
765 |
int step = 15 / ((1 << bps) - 1);
|
|
|
766 |
int i;
|
|
|
767 |
|
|
|
768 |
pmap->decoding = sd_lookup;
|
|
|
769 |
for (i = 15 - step; i > 0; i -= step)
|
|
|
770 |
pmap->decode_lookup[i] = pmap->decode_base +
|
|
|
771 |
i * (255.0 / 15) * pmap->decode_factor;
|
|
|
772 |
} else
|
|
|
773 |
pmap->decoding = sd_compute;
|
|
|
774 |
if (spp == 1) { /* and ci == 0 *//* Pre-map entries 0 and 255. */
|
|
|
775 |
gs_client_color cc;
|
|
|
776 |
|
|
|
777 |
cc.paint.values[0] = real_decode[0];
|
|
|
778 |
(*pcs->type->remap_color) (&cc, pcs, &penum->icolor0,
|
|
|
779 |
pis, dev, gs_color_select_source);
|
|
|
780 |
cc.paint.values[0] = real_decode[1];
|
|
|
781 |
(*pcs->type->remap_color) (&cc, pcs, &penum->icolor1,
|
|
|
782 |
pis, dev, gs_color_select_source);
|
|
|
783 |
}
|
|
|
784 |
}
|
|
|
785 |
|
|
|
786 |
}
|
|
|
787 |
/* Construct a mapping table for sample values. */
|
|
|
788 |
/* map_size is 2, 4, 16, or 256. Note that 255 % (map_size - 1) == 0, */
|
|
|
789 |
/* so the division 0xffffL / (map_size - 1) is always exact. */
|
|
|
790 |
private void
|
|
|
791 |
image_init_map(byte * map, int map_size, const float *decode)
|
|
|
792 |
{
|
|
|
793 |
float min_v = decode[0];
|
|
|
794 |
float diff_v = decode[1] - min_v;
|
|
|
795 |
|
|
|
796 |
if (diff_v == 1 || diff_v == -1) { /* We can do the stepping with integers, without overflow. */
|
|
|
797 |
byte *limit = map + map_size;
|
|
|
798 |
uint value = (uint)(min_v * 0xffffL);
|
|
|
799 |
int diff = (int)(diff_v * (0xffffL / (map_size - 1)));
|
|
|
800 |
|
|
|
801 |
for (; map != limit; map++, value += diff)
|
|
|
802 |
*map = value >> 8;
|
|
|
803 |
} else { /* Step in floating point, with clamping. */
|
|
|
804 |
int i;
|
|
|
805 |
|
|
|
806 |
for (i = 0; i < map_size; ++i) {
|
|
|
807 |
int value = (int)((min_v + diff_v * i / (map_size - 1)) * 255);
|
|
|
808 |
|
|
|
809 |
map[i] = (value < 0 ? 0 : value > 255 ? 255 : value);
|
|
|
810 |
}
|
|
|
811 |
}
|
|
|
812 |
}
|
|
|
813 |
|
|
|
814 |
/*
|
|
|
815 |
* Scale a pair of mask_color values to match the scaling of each sample to
|
|
|
816 |
* a full byte, and complement and swap them if the map incorporates
|
|
|
817 |
* a Decode = [1 0] inversion.
|
|
|
818 |
*/
|
|
|
819 |
void
|
|
|
820 |
gx_image_scale_mask_colors(gx_image_enum *penum, int component_index)
|
|
|
821 |
{
|
|
|
822 |
uint scale = 255 / ((1 << penum->bps) - 1);
|
|
|
823 |
uint *values = &penum->mask_color.values[component_index * 2];
|
|
|
824 |
uint v0 = values[0] *= scale;
|
|
|
825 |
uint v1 = values[1] *= scale;
|
|
|
826 |
|
|
|
827 |
if (penum->map[component_index].decoding == sd_none &&
|
|
|
828 |
penum->map[component_index].inverted
|
|
|
829 |
) {
|
|
|
830 |
values[0] = 255 - v1;
|
|
|
831 |
values[1] = 255 - v0;
|
|
|
832 |
}
|
|
|
833 |
}
|