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: gxclimag.c,v 1.13 2005/10/10 18:58:18 leonardo Exp $ */
|
|
|
18 |
/* Higher-level image operations for band lists */
|
|
|
19 |
#include "math_.h"
|
|
|
20 |
#include "memory_.h"
|
|
|
21 |
#include "gx.h"
|
|
|
22 |
#include "gserrors.h"
|
|
|
23 |
#include "gscspace.h"
|
|
|
24 |
#include "gscdefs.h" /* for image type table */
|
|
|
25 |
#include "gxarith.h"
|
|
|
26 |
#include "gxcspace.h"
|
|
|
27 |
#include "gxdevice.h"
|
|
|
28 |
#include "gxdevmem.h" /* must precede gxcldev.h */
|
|
|
29 |
#include "gxcldev.h"
|
|
|
30 |
#include "gxclpath.h"
|
|
|
31 |
#include "gxfmap.h"
|
|
|
32 |
#include "gxiparam.h"
|
|
|
33 |
#include "gxpath.h"
|
|
|
34 |
#include "stream.h"
|
|
|
35 |
#include "strimpl.h" /* for sisparam.h */
|
|
|
36 |
#include "sisparam.h"
|
|
|
37 |
#include "gxcomp.h"
|
|
|
38 |
#include "gsserial.h"
|
|
|
39 |
#include "gxdhtserial.h"
|
|
|
40 |
|
|
|
41 |
extern_gx_image_type_table();
|
|
|
42 |
|
|
|
43 |
/* Define whether we should use high-level images. */
|
|
|
44 |
/* (See below for additional restrictions.) */
|
|
|
45 |
static const bool USE_HL_IMAGES = true;
|
|
|
46 |
|
|
|
47 |
/* Forward references */
|
|
|
48 |
private int cmd_put_set_data_x(gx_device_clist_writer * cldev,
|
|
|
49 |
gx_clist_state * pcls, int data_x);
|
|
|
50 |
private bool check_rect_for_trivial_clip(
|
|
|
51 |
const gx_clip_path *pcpath, /* May be NULL, clip to evaluate */
|
|
|
52 |
int px, int py, int qx, int qy /* corners of box to test */
|
|
|
53 |
);
|
|
|
54 |
|
|
|
55 |
/* ------ Driver procedures ------ */
|
|
|
56 |
|
|
|
57 |
int
|
|
|
58 |
clist_fill_mask(gx_device * dev,
|
|
|
59 |
const byte * data, int data_x, int raster, gx_bitmap_id id,
|
|
|
60 |
int x, int y, int width, int height,
|
|
|
61 |
const gx_drawing_color * pdcolor, int depth,
|
|
|
62 |
gs_logical_operation_t lop, const gx_clip_path * pcpath)
|
|
|
63 |
{
|
|
|
64 |
gx_device_clist_writer * const cdev =
|
|
|
65 |
&((gx_device_clist *)dev)->writer;
|
|
|
66 |
const byte *orig_data = data; /* for writing tile */
|
|
|
67 |
int orig_data_x = data_x; /* ditto */
|
|
|
68 |
int orig_x = x; /* ditto */
|
|
|
69 |
int orig_width = width; /* ditto */
|
|
|
70 |
int orig_height = height; /* ditto */
|
|
|
71 |
int log2_depth = ilog2(depth);
|
|
|
72 |
int y0;
|
|
|
73 |
int data_x_bit;
|
|
|
74 |
byte copy_op =
|
|
|
75 |
(depth > 1 ? cmd_op_copy_color_alpha :
|
|
|
76 |
cmd_op_copy_mono + cmd_copy_ht_color);
|
|
|
77 |
bool slow_rop =
|
|
|
78 |
cmd_slow_rop(dev, lop_know_S_0(lop), pdcolor) ||
|
|
|
79 |
cmd_slow_rop(dev, lop_know_S_1(lop), pdcolor);
|
|
|
80 |
|
|
|
81 |
/* If depth > 1, this call will be translated to a copy_alpha call. */
|
|
|
82 |
/* if the target device can't perform copy_alpha, exit now. */
|
|
|
83 |
if (depth > 1 && (cdev->disable_mask & clist_disable_copy_alpha) != 0)
|
|
|
84 |
return_error(gs_error_unknownerror);
|
|
|
85 |
|
|
|
86 |
fit_copy(dev, data, data_x, raster, id, x, y, width, height);
|
|
|
87 |
y0 = y; /* must do after fit_copy */
|
|
|
88 |
|
|
|
89 |
/* If non-trivial clipping & complex clipping disabled, default */
|
|
|
90 |
/* Also default for uncached bitmap or non-defaul lop; */
|
|
|
91 |
/* We could handle more RasterOp cases here directly, but it */
|
|
|
92 |
/* doesn't seem worth the trouble right now. */
|
|
|
93 |
/* Lastly, the command list will translate calls with depth > 1 to */
|
|
|
94 |
/* copy_alpha calls, so the device color must be pure */
|
|
|
95 |
if (((cdev->disable_mask & clist_disable_complex_clip) &&
|
|
|
96 |
!check_rect_for_trivial_clip(pcpath, x, y, x + width, y + height)) ||
|
|
|
97 |
gs_debug_c('`') || id == gx_no_bitmap_id || lop != lop_default ||
|
|
|
98 |
(depth > 1 && !color_writes_pure(pdcolor, lop))
|
|
|
99 |
)
|
|
|
100 |
copy:
|
|
|
101 |
return gx_default_fill_mask(dev, data, data_x, raster, id,
|
|
|
102 |
x, y, width, height, pdcolor, depth,
|
|
|
103 |
lop, pcpath);
|
|
|
104 |
|
|
|
105 |
if (cmd_check_clip_path(cdev, pcpath))
|
|
|
106 |
cmd_clear_known(cdev, clip_path_known);
|
|
|
107 |
data_x_bit = data_x << log2_depth;
|
|
|
108 |
FOR_RECTS {
|
|
|
109 |
int code;
|
|
|
110 |
ulong offset_temp;
|
|
|
111 |
|
|
|
112 |
TRY_RECT {
|
|
|
113 |
code = cmd_update_lop(cdev, pcls, lop);
|
|
|
114 |
} HANDLE_RECT(code);
|
|
|
115 |
if (depth > 1 && !pcls->color_is_alpha) {
|
|
|
116 |
byte *dp;
|
|
|
117 |
|
|
|
118 |
TRY_RECT {
|
|
|
119 |
code =
|
|
|
120 |
set_cmd_put_op(dp, cdev, pcls, cmd_opv_set_copy_alpha, 1);
|
|
|
121 |
} HANDLE_RECT(code);
|
|
|
122 |
pcls->color_is_alpha = 1;
|
|
|
123 |
}
|
|
|
124 |
TRY_RECT {
|
|
|
125 |
code = cmd_do_write_unknown(cdev, pcls, clip_path_known);
|
|
|
126 |
if (code >= 0)
|
|
|
127 |
code = cmd_do_enable_clip(cdev, pcls, pcpath != NULL);
|
|
|
128 |
} HANDLE_RECT(code);
|
|
|
129 |
TRY_RECT {
|
|
|
130 |
code = cmd_put_drawing_color(cdev, pcls, pdcolor);
|
|
|
131 |
if (depth > 1 && code >= 0)
|
|
|
132 |
code = cmd_set_color1(cdev, pcls, pdcolor->colors.pure);
|
|
|
133 |
} HANDLE_RECT(code);
|
|
|
134 |
pcls->colors_used.slow_rop |= slow_rop;
|
|
|
135 |
|
|
|
136 |
/* Put it in the cache if possible. */
|
|
|
137 |
if (!cls_has_tile_id(cdev, pcls, id, offset_temp)) {
|
|
|
138 |
gx_strip_bitmap tile;
|
|
|
139 |
|
|
|
140 |
tile.data = (byte *) orig_data; /* actually const */
|
|
|
141 |
tile.raster = raster;
|
|
|
142 |
tile.size.x = tile.rep_width = orig_width;
|
|
|
143 |
tile.size.y = tile.rep_height = orig_height;
|
|
|
144 |
tile.rep_shift = tile.shift = 0;
|
|
|
145 |
tile.id = id;
|
|
|
146 |
TRY_RECT {
|
|
|
147 |
code = clist_change_bits(cdev, pcls, &tile, depth);
|
|
|
148 |
} HANDLE_RECT_UNLESS(code,
|
|
|
149 |
(code != gs_error_VMerror || !cdev->error_is_retryable) );
|
|
|
150 |
if (code < 0) {
|
|
|
151 |
/* Something went wrong; just copy the bits. */
|
|
|
152 |
goto copy;
|
|
|
153 |
}
|
|
|
154 |
}
|
|
|
155 |
{
|
|
|
156 |
gx_cmd_rect rect;
|
|
|
157 |
int rsize;
|
|
|
158 |
byte op = copy_op + cmd_copy_use_tile;
|
|
|
159 |
|
|
|
160 |
/* Output a command to copy the entire character. */
|
|
|
161 |
/* It will be truncated properly per band. */
|
|
|
162 |
rect.x = orig_x, rect.y = y0;
|
|
|
163 |
rect.width = orig_width, rect.height = yend - y0;
|
|
|
164 |
rsize = 1 + cmd_sizexy(rect);
|
|
|
165 |
TRY_RECT {
|
|
|
166 |
code = (orig_data_x ?
|
|
|
167 |
cmd_put_set_data_x(cdev, pcls, orig_data_x) : 0);
|
|
|
168 |
if (code >= 0) {
|
|
|
169 |
byte *dp;
|
|
|
170 |
|
|
|
171 |
code = set_cmd_put_op(dp, cdev, pcls, op, rsize);
|
|
|
172 |
/*
|
|
|
173 |
* The following conditional is unnecessary: the two
|
|
|
174 |
* statements inside it should go outside the
|
|
|
175 |
* HANDLE_RECT. They are here solely to pacify
|
|
|
176 |
* stupid compilers that don't understand that dp
|
|
|
177 |
* will always be set if control gets past the
|
|
|
178 |
* HANDLE_RECT.
|
|
|
179 |
*/
|
|
|
180 |
if (code >= 0) {
|
|
|
181 |
dp++;
|
|
|
182 |
cmd_putxy(rect, dp);
|
|
|
183 |
}
|
|
|
184 |
}
|
|
|
185 |
} HANDLE_RECT(code);
|
|
|
186 |
pcls->rect = rect;
|
|
|
187 |
goto end;
|
|
|
188 |
}
|
|
|
189 |
end:
|
|
|
190 |
;
|
|
|
191 |
} END_RECTS;
|
|
|
192 |
return 0;
|
|
|
193 |
}
|
|
|
194 |
|
|
|
195 |
/* ------ Bitmap image driver procedures ------ */
|
|
|
196 |
|
|
|
197 |
/* Define the structure for keeping track of progress through an image. */
|
|
|
198 |
typedef struct clist_image_enum_s {
|
|
|
199 |
gx_image_enum_common;
|
|
|
200 |
/* Arguments of begin_image */
|
|
|
201 |
gs_memory_t *memory;
|
|
|
202 |
gs_pixel_image_t image; /* only uses Width, Height, Interpolate */
|
|
|
203 |
gx_drawing_color dcolor; /* only pure right now */
|
|
|
204 |
gs_int_rect rect;
|
|
|
205 |
const gs_imager_state *pis;
|
|
|
206 |
const gx_clip_path *pcpath;
|
|
|
207 |
/* Set at creation time */
|
|
|
208 |
gs_image_format_t format;
|
|
|
209 |
gs_int_point support; /* extra source pixels for interpolation */
|
|
|
210 |
int bits_per_plane; /* bits per pixel per plane */
|
|
|
211 |
gs_matrix matrix; /* image space -> device space */
|
|
|
212 |
bool uses_color;
|
|
|
213 |
clist_color_space_t color_space;
|
|
|
214 |
int ymin, ymax;
|
|
|
215 |
gx_colors_used_t colors_used;
|
|
|
216 |
/* begin_image command prepared & ready to output */
|
|
|
217 |
/****** SIZE COMPUTATION IS WRONG, TIED TO gximage.c, gsmatrix.c ******/
|
|
|
218 |
byte begin_image_command[3 +
|
|
|
219 |
/* Width, Height */
|
|
|
220 |
2 * cmd_sizew_max +
|
|
|
221 |
/* ImageMatrix */
|
|
|
222 |
1 + 6 * sizeof(float) +
|
|
|
223 |
/* Decode */
|
|
|
224 |
(GS_IMAGE_MAX_COMPONENTS + 3) / 4 +
|
|
|
225 |
GS_IMAGE_MAX_COMPONENTS * 2 * sizeof(float) +
|
|
|
226 |
/* MaskColors */
|
|
|
227 |
GS_IMAGE_MAX_COMPONENTS * cmd_sizew_max +
|
|
|
228 |
/* rect */
|
|
|
229 |
4 * cmd_sizew_max];
|
|
|
230 |
int begin_image_command_length;
|
|
|
231 |
/* Updated dynamically */
|
|
|
232 |
int y;
|
|
|
233 |
bool color_map_is_known;
|
|
|
234 |
} clist_image_enum;
|
|
|
235 |
gs_private_st_suffix_add3(st_clist_image_enum, clist_image_enum,
|
|
|
236 |
"clist_image_enum", clist_image_enum_enum_ptrs,
|
|
|
237 |
clist_image_enum_reloc_ptrs, st_gx_image_enum_common,
|
|
|
238 |
pis, pcpath, color_space.space);
|
|
|
239 |
|
|
|
240 |
private image_enum_proc_plane_data(clist_image_plane_data);
|
|
|
241 |
private image_enum_proc_end_image(clist_image_end_image);
|
|
|
242 |
private const gx_image_enum_procs_t clist_image_enum_procs =
|
|
|
243 |
{
|
|
|
244 |
clist_image_plane_data, clist_image_end_image
|
|
|
245 |
};
|
|
|
246 |
|
|
|
247 |
/* Forward declarations */
|
|
|
248 |
private bool image_band_box(gx_device * dev, const clist_image_enum * pie,
|
|
|
249 |
int y, int h, gs_int_rect * pbox);
|
|
|
250 |
private int begin_image_command(byte *buf, uint buf_size,
|
|
|
251 |
const gs_image_common_t *pic);
|
|
|
252 |
private int cmd_image_plane_data(gx_device_clist_writer * cldev,
|
|
|
253 |
gx_clist_state * pcls,
|
|
|
254 |
const gx_image_plane_t * planes,
|
|
|
255 |
const gx_image_enum_common_t * pie,
|
|
|
256 |
uint bytes_per_plane,
|
|
|
257 |
const uint * offsets, int dx, int h);
|
|
|
258 |
private uint clist_image_unknowns(gx_device *dev,
|
|
|
259 |
const clist_image_enum *pie);
|
|
|
260 |
private int write_image_end_all(gx_device *dev,
|
|
|
261 |
const clist_image_enum *pie);
|
|
|
262 |
|
|
|
263 |
/*
|
|
|
264 |
* Since currently we are limited to writing a single subrectangle of the
|
|
|
265 |
* image for each band, images that are rotated by angles other than
|
|
|
266 |
* multiples of 90 degrees may wind up writing many copies of the data.
|
|
|
267 |
* Eventually we will fix this by breaking up the image into multiple
|
|
|
268 |
* subrectangles, but for now, don't use the high-level approach if it would
|
|
|
269 |
* cause the data to explode because of this.
|
|
|
270 |
*/
|
|
|
271 |
private bool
|
|
|
272 |
image_matrix_ok_to_band(const gs_matrix * pmat)
|
|
|
273 |
{
|
|
|
274 |
double t;
|
|
|
275 |
|
|
|
276 |
/* Don't band if the matrix is (nearly) singular. */
|
|
|
277 |
if (fabs(pmat->xx * pmat->yy - pmat->xy * pmat->yx) < 0.001)
|
|
|
278 |
return false;
|
|
|
279 |
if (is_xxyy(pmat) || is_xyyx(pmat))
|
|
|
280 |
return true;
|
|
|
281 |
t = (fabs(pmat->xx) + fabs(pmat->yy)) /
|
|
|
282 |
(fabs(pmat->xy) + fabs(pmat->yx));
|
|
|
283 |
return (t < 0.2 || t > 5);
|
|
|
284 |
}
|
|
|
285 |
|
|
|
286 |
/* Start processing an image. */
|
|
|
287 |
int
|
|
|
288 |
clist_begin_typed_image(gx_device * dev,
|
|
|
289 |
const gs_imager_state * pis, const gs_matrix * pmat,
|
|
|
290 |
const gs_image_common_t * pic, const gs_int_rect * prect,
|
|
|
291 |
const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
|
|
|
292 |
gs_memory_t * mem, gx_image_enum_common_t ** pinfo)
|
|
|
293 |
{
|
|
|
294 |
const gs_pixel_image_t * const pim = (const gs_pixel_image_t *)pic;
|
|
|
295 |
gx_device_clist_writer * const cdev =
|
|
|
296 |
&((gx_device_clist *)dev)->writer;
|
|
|
297 |
clist_image_enum *pie = 0;
|
|
|
298 |
int base_index;
|
|
|
299 |
bool indexed;
|
|
|
300 |
bool masked = false;
|
|
|
301 |
bool has_alpha = false;
|
|
|
302 |
int num_components;
|
|
|
303 |
int bits_per_pixel;
|
|
|
304 |
bool uses_color;
|
|
|
305 |
bool varying_depths = false;
|
|
|
306 |
gs_matrix mat;
|
|
|
307 |
gs_rect sbox, dbox;
|
|
|
308 |
gs_image_format_t format;
|
|
|
309 |
gx_color_index colors_used = 0;
|
|
|
310 |
int code;
|
|
|
311 |
|
|
|
312 |
/* We can only handle a limited set of image types. */
|
|
|
313 |
switch ((gs_debug_c('`') ? -1 : pic->type->index)) {
|
|
|
314 |
case 1:
|
|
|
315 |
masked = ((const gs_image1_t *)pim)->ImageMask;
|
|
|
316 |
has_alpha = ((const gs_image1_t *)pim)->Alpha != 0;
|
|
|
317 |
case 4:
|
|
|
318 |
if (pmat == 0)
|
|
|
319 |
break;
|
|
|
320 |
default:
|
|
|
321 |
goto use_default;
|
|
|
322 |
}
|
|
|
323 |
format = pim->format;
|
|
|
324 |
/* See above for why we allocate the enumerator as immovable. */
|
|
|
325 |
pie = gs_alloc_struct_immovable(mem, clist_image_enum,
|
|
|
326 |
&st_clist_image_enum,
|
|
|
327 |
"clist_begin_typed_image");
|
|
|
328 |
if (pie == 0)
|
|
|
329 |
return_error(gs_error_VMerror);
|
|
|
330 |
pie->memory = mem;
|
|
|
331 |
*pinfo = (gx_image_enum_common_t *) pie;
|
|
|
332 |
/* num_planes and plane_depths[] are set later, */
|
|
|
333 |
/* by gx_image_enum_common_init. */
|
|
|
334 |
if (masked) {
|
|
|
335 |
base_index = gs_color_space_index_DeviceGray; /* arbitrary */
|
|
|
336 |
indexed = false;
|
|
|
337 |
num_components = 1;
|
|
|
338 |
uses_color = true;
|
|
|
339 |
/* cmd_put_drawing_color handles colors_used */
|
|
|
340 |
} else {
|
|
|
341 |
const gs_color_space *pcs = pim->ColorSpace;
|
|
|
342 |
|
|
|
343 |
base_index = gs_color_space_get_index(pcs);
|
|
|
344 |
if (base_index == gs_color_space_index_Indexed) {
|
|
|
345 |
const gs_color_space *pbcs =
|
|
|
346 |
gs_color_space_indexed_base_space(pcs);
|
|
|
347 |
|
|
|
348 |
indexed = true;
|
|
|
349 |
base_index = gs_color_space_get_index(pbcs);
|
|
|
350 |
num_components = 1;
|
|
|
351 |
} else {
|
|
|
352 |
indexed = false;
|
|
|
353 |
num_components = gs_color_space_num_components(pcs);
|
|
|
354 |
}
|
|
|
355 |
uses_color = pim->CombineWithColor && rop3_uses_T(pis->log_op);
|
|
|
356 |
}
|
|
|
357 |
code = gx_image_enum_common_init((gx_image_enum_common_t *) pie,
|
|
|
358 |
(const gs_data_image_t *) pim,
|
|
|
359 |
&clist_image_enum_procs, dev,
|
|
|
360 |
num_components, format);
|
|
|
361 |
{
|
|
|
362 |
int i;
|
|
|
363 |
|
|
|
364 |
for (i = 1; i < pie->num_planes; ++i)
|
|
|
365 |
varying_depths |= pie->plane_depths[i] != pie->plane_depths[0];
|
|
|
366 |
}
|
|
|
367 |
if (code < 0 ||
|
|
|
368 |
!USE_HL_IMAGES || /* Always use the default. */
|
|
|
369 |
(cdev->disable_mask & clist_disable_hl_image) ||
|
|
|
370 |
cdev->image_enum_id != gs_no_id || /* Can't handle nested images */
|
|
|
371 |
/****** CAN'T HANDLE CIE COLOR YET ******/
|
|
|
372 |
base_index > gs_color_space_index_DeviceCMYK ||
|
|
|
373 |
/****** CAN'T HANDLE NON-PURE COLORS YET ******/
|
|
|
374 |
(uses_color && !gx_dc_is_pure(pdcolor)) ||
|
|
|
375 |
/****** CAN'T HANDLE IMAGES WITH ALPHA YET ******/
|
|
|
376 |
has_alpha ||
|
|
|
377 |
/****** CAN'T HANDLE IMAGES WITH IRREGULAR DEPTHS ******/
|
|
|
378 |
varying_depths ||
|
|
|
379 |
(code = gs_matrix_invert(&pim->ImageMatrix, &mat)) < 0 ||
|
|
|
380 |
(code = gs_matrix_multiply(&mat, &ctm_only(pis), &mat)) < 0 ||
|
|
|
381 |
!(cdev->disable_mask & clist_disable_nonrect_hl_image ?
|
|
|
382 |
(is_xxyy(&mat) || is_xyyx(&mat)) :
|
|
|
383 |
image_matrix_ok_to_band(&mat))
|
|
|
384 |
)
|
|
|
385 |
goto use_default;
|
|
|
386 |
{
|
|
|
387 |
int bytes_per_plane, bytes_per_row;
|
|
|
388 |
|
|
|
389 |
bits_per_pixel = pim->BitsPerComponent * num_components;
|
|
|
390 |
pie->image = *pim;
|
|
|
391 |
pie->dcolor = *pdcolor;
|
|
|
392 |
if (prect)
|
|
|
393 |
pie->rect = *prect;
|
|
|
394 |
else {
|
|
|
395 |
pie->rect.p.x = 0, pie->rect.p.y = 0;
|
|
|
396 |
pie->rect.q.x = pim->Width, pie->rect.q.y = pim->Height;
|
|
|
397 |
}
|
|
|
398 |
pie->pis = pis;
|
|
|
399 |
pie->pcpath = pcpath;
|
|
|
400 |
pie->format = format;
|
|
|
401 |
pie->bits_per_plane = bits_per_pixel / pie->num_planes;
|
|
|
402 |
pie->matrix = mat;
|
|
|
403 |
pie->uses_color = uses_color;
|
|
|
404 |
if (masked) {
|
|
|
405 |
pie->color_space.byte1 = 0; /* arbitrary */
|
|
|
406 |
pie->color_space.space = 0;
|
|
|
407 |
pie->color_space.id = gs_no_id;
|
|
|
408 |
} else {
|
|
|
409 |
pie->color_space.byte1 = (base_index << 4) |
|
|
|
410 |
(indexed ? (pim->ColorSpace->params.indexed.use_proc ? 12 : 8) : 0);
|
|
|
411 |
pie->color_space.id =
|
|
|
412 |
(pie->color_space.space = pim->ColorSpace)->id;
|
|
|
413 |
}
|
|
|
414 |
pie->y = pie->rect.p.y;
|
|
|
415 |
|
|
|
416 |
/* Image row has to fit in cmd writer's buffer */
|
|
|
417 |
bytes_per_plane =
|
|
|
418 |
(pim->Width * pie->bits_per_plane + 7) >> 3;
|
|
|
419 |
bytes_per_row = bytes_per_plane * pie->num_planes;
|
|
|
420 |
bytes_per_row = max(bytes_per_row, 1);
|
|
|
421 |
if (cmd_largest_size + bytes_per_row > cdev->cend - cdev->cbuf)
|
|
|
422 |
goto use_default;
|
|
|
423 |
}
|
|
|
424 |
if (pim->Interpolate)
|
|
|
425 |
pie->support.x = pie->support.y = MAX_ISCALE_SUPPORT + 1;
|
|
|
426 |
else
|
|
|
427 |
pie->support.x = pie->support.y = 0;
|
|
|
428 |
sbox.p.x = pie->rect.p.x - pie->support.x;
|
|
|
429 |
sbox.p.y = pie->rect.p.y - pie->support.y;
|
|
|
430 |
sbox.q.x = pie->rect.q.x + pie->support.x;
|
|
|
431 |
sbox.q.y = pie->rect.q.y + pie->support.y;
|
|
|
432 |
gs_bbox_transform(&sbox, &mat, &dbox);
|
|
|
433 |
|
|
|
434 |
if (cdev->disable_mask & clist_disable_complex_clip)
|
|
|
435 |
if (!check_rect_for_trivial_clip(pcpath,
|
|
|
436 |
(int)floor(dbox.p.x), (int)floor(dbox.p.y),
|
|
|
437 |
(int)ceil(dbox.q.x), (int)ceil(dbox.q.y)))
|
|
|
438 |
goto use_default;
|
|
|
439 |
/* Create the begin_image command. */
|
|
|
440 |
if ((pie->begin_image_command_length =
|
|
|
441 |
begin_image_command(pie->begin_image_command,
|
|
|
442 |
sizeof(pie->begin_image_command), pic)) < 0)
|
|
|
443 |
goto use_default;
|
|
|
444 |
if (!masked) {
|
|
|
445 |
/*
|
|
|
446 |
* Calculate (conservatively) the set of colors that this image
|
|
|
447 |
* might generate. For single-component images with up to 4 bits
|
|
|
448 |
* per pixel, standard Decode values, and no Interpolate, we
|
|
|
449 |
* generate all the possible colors now; otherwise, we assume that
|
|
|
450 |
* any color might be generated. It is possible to do better than
|
|
|
451 |
* this, but we won't bother unless there's evidence that it's
|
|
|
452 |
* worthwhile.
|
|
|
453 |
*/
|
|
|
454 |
gx_color_index all =
|
|
|
455 |
((gx_color_index)1 << dev->color_info.depth) - 1;
|
|
|
456 |
|
|
|
457 |
if (bits_per_pixel > 4 || pim->Interpolate || num_components > 1)
|
|
|
458 |
colors_used = all;
|
|
|
459 |
else {
|
|
|
460 |
int max_value = (1 << bits_per_pixel) - 1;
|
|
|
461 |
float dmin = pim->Decode[0], dmax = pim->Decode[1];
|
|
|
462 |
float dtemp;
|
|
|
463 |
|
|
|
464 |
if (dmax < dmin)
|
|
|
465 |
dtemp = dmax, dmax = dmin, dmin = dtemp;
|
|
|
466 |
if (dmin != 0 ||
|
|
|
467 |
dmax != (indexed ? max_value : 1)
|
|
|
468 |
) {
|
|
|
469 |
colors_used = all;
|
|
|
470 |
} else {
|
|
|
471 |
/* Enumerate the possible pixel values. */
|
|
|
472 |
const gs_color_space *pcs = pim->ColorSpace;
|
|
|
473 |
cs_proc_remap_color((*remap_color)) = pcs->type->remap_color;
|
|
|
474 |
gs_client_color cc;
|
|
|
475 |
gx_drawing_color dcolor;
|
|
|
476 |
int i;
|
|
|
477 |
double denom = (indexed ? 1 : max_value);
|
|
|
478 |
|
|
|
479 |
for (i = 0; i <= max_value; ++i) {
|
|
|
480 |
cc.paint.values[0] = (double)i / denom;
|
|
|
481 |
remap_color(&cc, pcs, &dcolor, pis, dev,
|
|
|
482 |
gs_color_select_source);
|
|
|
483 |
colors_used |= cmd_drawing_colors_used(cdev, &dcolor);
|
|
|
484 |
}
|
|
|
485 |
}
|
|
|
486 |
}
|
|
|
487 |
}
|
|
|
488 |
|
|
|
489 |
pie->colors_used.or = colors_used;
|
|
|
490 |
pie->colors_used.slow_rop =
|
|
|
491 |
cmd_slow_rop(dev, pis->log_op, (uses_color ? pdcolor : NULL));
|
|
|
492 |
pie->color_map_is_known = false;
|
|
|
493 |
/*
|
|
|
494 |
* Calculate a (slightly conservative) Y bounding interval for the image
|
|
|
495 |
* in device space.
|
|
|
496 |
*/
|
|
|
497 |
{
|
|
|
498 |
int y0 = (int)floor(dbox.p.y - 0.51); /* adjust + rounding slop */
|
|
|
499 |
int y1 = (int)ceil(dbox.q.y + 0.51); /* ditto */
|
|
|
500 |
|
|
|
501 |
pie->ymin = max(y0, 0);
|
|
|
502 |
pie->ymax = min(y1, dev->height);
|
|
|
503 |
}
|
|
|
504 |
|
|
|
505 |
/*
|
|
|
506 |
* Make sure the CTM, color space, and clipping region (and, for
|
|
|
507 |
* masked images or images with CombineWithColor, the current color)
|
|
|
508 |
* are known at the time of the begin_image command.
|
|
|
509 |
*/
|
|
|
510 |
cmd_clear_known(cdev, clist_image_unknowns(dev, pie) | begin_image_known);
|
|
|
511 |
|
|
|
512 |
cdev->image_enum_id = pie->id;
|
|
|
513 |
return 0;
|
|
|
514 |
|
|
|
515 |
/*
|
|
|
516 |
* We couldn't handle the image. Use the default algorithms, which
|
|
|
517 |
* break the image up into rectangles or small pixmaps.
|
|
|
518 |
*/
|
|
|
519 |
use_default:
|
|
|
520 |
gs_free_object(mem, pie, "clist_begin_typed_image");
|
|
|
521 |
return gx_default_begin_typed_image(dev, pis, pmat, pic, prect,
|
|
|
522 |
pdcolor, pcpath, mem, pinfo);
|
|
|
523 |
}
|
|
|
524 |
|
|
|
525 |
/* Process the next piece of an image. */
|
|
|
526 |
private int
|
|
|
527 |
clist_image_plane_data(gx_image_enum_common_t * info,
|
|
|
528 |
const gx_image_plane_t * planes, int yh,
|
|
|
529 |
int *rows_used)
|
|
|
530 |
{
|
|
|
531 |
gx_device *dev = info->dev;
|
|
|
532 |
gx_device_clist_writer * const cdev =
|
|
|
533 |
&((gx_device_clist *)dev)->writer;
|
|
|
534 |
clist_image_enum *pie = (clist_image_enum *) info;
|
|
|
535 |
gs_rect sbox, dbox;
|
|
|
536 |
int y_orig = pie->y;
|
|
|
537 |
int yh_used = min(yh, pie->rect.q.y - y_orig);
|
|
|
538 |
int y0, y1;
|
|
|
539 |
int y, height; /* for BEGIN/END_RECT */
|
|
|
540 |
int code;
|
|
|
541 |
|
|
|
542 |
#ifdef DEBUG
|
|
|
543 |
if (pie->id != cdev->image_enum_id) {
|
|
|
544 |
lprintf2("end_image id = %lu != clist image id = %lu!\n",
|
|
|
545 |
(ulong) pie->id, (ulong) cdev->image_enum_id);
|
|
|
546 |
*rows_used = 0;
|
|
|
547 |
return_error(gs_error_Fatal);
|
|
|
548 |
}
|
|
|
549 |
#endif
|
|
|
550 |
/****** CAN'T HANDLE VARYING data_x VALUES YET ******/
|
|
|
551 |
{
|
|
|
552 |
int i;
|
|
|
553 |
|
|
|
554 |
for (i = 1; i < info->num_planes; ++i)
|
|
|
555 |
if (planes[i].data_x != planes[0].data_x) {
|
|
|
556 |
*rows_used = 0;
|
|
|
557 |
return_error(gs_error_rangecheck);
|
|
|
558 |
}
|
|
|
559 |
}
|
|
|
560 |
sbox.p.x = pie->rect.p.x - pie->support.x;
|
|
|
561 |
sbox.p.y = (y0 = y_orig) - pie->support.y;
|
|
|
562 |
sbox.q.x = pie->rect.q.x + pie->support.x;
|
|
|
563 |
sbox.q.y = (y1 = pie->y += yh_used) + pie->support.y;
|
|
|
564 |
gs_bbox_transform(&sbox, &pie->matrix, &dbox);
|
|
|
565 |
/*
|
|
|
566 |
* In order to keep the band list consistent, we must write out
|
|
|
567 |
* the image data in precisely those bands whose begin_image
|
|
|
568 |
* Y range includes the respective image scan lines. Because of
|
|
|
569 |
* rounding, we must expand the dbox by a little extra, and then
|
|
|
570 |
* use image_band_box to calculate the precise range for each band.
|
|
|
571 |
* This is slow, but we don't see any faster way to do it in the
|
|
|
572 |
* general case.
|
|
|
573 |
*/
|
|
|
574 |
{
|
|
|
575 |
int ry0 = (int)floor(dbox.p.y) - 2;
|
|
|
576 |
int ry1 = (int)ceil(dbox.q.y) + 2;
|
|
|
577 |
int band_height = cdev->page_band_height;
|
|
|
578 |
|
|
|
579 |
/*
|
|
|
580 |
* Make sure we don't go into any bands beyond the Y range
|
|
|
581 |
* determined at begin_image time.
|
|
|
582 |
*/
|
|
|
583 |
if (ry0 < pie->ymin)
|
|
|
584 |
ry0 = pie->ymin;
|
|
|
585 |
if (ry1 > pie->ymax)
|
|
|
586 |
ry1 = pie->ymax;
|
|
|
587 |
/*
|
|
|
588 |
* If the image extends off the page in the Y direction,
|
|
|
589 |
* we may have ry0 > ry1. Check for this here.
|
|
|
590 |
*/
|
|
|
591 |
if (ry0 >= ry1)
|
|
|
592 |
goto done;
|
|
|
593 |
/* Expand the range out to band boundaries. */
|
|
|
594 |
y = ry0 / band_height * band_height;
|
|
|
595 |
height = min(ROUND_UP(ry1, band_height), dev->height) - y;
|
|
|
596 |
}
|
|
|
597 |
|
|
|
598 |
FOR_RECTS {
|
|
|
599 |
/*
|
|
|
600 |
* Just transmit the subset of the data that intersects this band.
|
|
|
601 |
* Note that y and height always define a complete band.
|
|
|
602 |
*/
|
|
|
603 |
gs_int_rect ibox;
|
|
|
604 |
gs_int_rect entire_box;
|
|
|
605 |
|
|
|
606 |
if (!image_band_box(dev, pie, y, height, &ibox))
|
|
|
607 |
continue;
|
|
|
608 |
/*
|
|
|
609 |
* The transmitted subrectangle has to be computed at the time
|
|
|
610 |
* we write the begin_image command; this in turn controls how
|
|
|
611 |
* much of each scan line we write out.
|
|
|
612 |
*/
|
|
|
613 |
{
|
|
|
614 |
int band_ymax = min(band_end, pie->ymax);
|
|
|
615 |
int band_ymin = max(band_end - band_height, pie->ymin);
|
|
|
616 |
|
|
|
617 |
if (!image_band_box(dev, pie, band_ymin,
|
|
|
618 |
band_ymax - band_ymin, &entire_box))
|
|
|
619 |
continue;
|
|
|
620 |
}
|
|
|
621 |
|
|
|
622 |
pcls->colors_used.or |= pie->colors_used.or;
|
|
|
623 |
pcls->colors_used.slow_rop |= pie->colors_used.slow_rop;
|
|
|
624 |
|
|
|
625 |
/* Write out begin_image & its preamble for this band */
|
|
|
626 |
if (!(pcls->known & begin_image_known)) {
|
|
|
627 |
gs_logical_operation_t lop = pie->pis->log_op;
|
|
|
628 |
byte *dp;
|
|
|
629 |
byte *bp = pie->begin_image_command +
|
|
|
630 |
pie->begin_image_command_length;
|
|
|
631 |
uint len;
|
|
|
632 |
byte image_op = cmd_opv_begin_image;
|
|
|
633 |
|
|
|
634 |
/* Make sure the imager state is up to date. */
|
|
|
635 |
TRY_RECT {
|
|
|
636 |
code = (pie->color_map_is_known ? 0 :
|
|
|
637 |
cmd_put_color_mapping(cdev, pie->pis));
|
|
|
638 |
pie->color_map_is_known = true;
|
|
|
639 |
if (code >= 0) {
|
|
|
640 |
uint want_known = ctm_known | clip_path_known |
|
|
|
641 |
op_bm_tk_known | opacity_alpha_known |
|
|
|
642 |
shape_alpha_known | alpha_known |
|
|
|
643 |
(pie->color_space.id == gs_no_id ? 0 :
|
|
|
644 |
color_space_known);
|
|
|
645 |
|
|
|
646 |
code = cmd_do_write_unknown(cdev, pcls, want_known);
|
|
|
647 |
}
|
|
|
648 |
if (code >= 0)
|
|
|
649 |
code = cmd_do_enable_clip(cdev, pcls, pie->pcpath != NULL);
|
|
|
650 |
if (code >= 0)
|
|
|
651 |
code = cmd_update_lop(cdev, pcls, lop);
|
|
|
652 |
} HANDLE_RECT(code);
|
|
|
653 |
if (pie->uses_color) {
|
|
|
654 |
TRY_RECT {
|
|
|
655 |
code = cmd_put_drawing_color(cdev, pcls, &pie->dcolor);
|
|
|
656 |
} HANDLE_RECT(code);
|
|
|
657 |
}
|
|
|
658 |
if (entire_box.p.x != 0 || entire_box.p.y != 0 ||
|
|
|
659 |
entire_box.q.x != pie->image.Width ||
|
|
|
660 |
entire_box.q.y != pie->image.Height
|
|
|
661 |
) {
|
|
|
662 |
image_op = cmd_opv_begin_image_rect;
|
|
|
663 |
cmd_put2w(entire_box.p.x, entire_box.p.y, bp);
|
|
|
664 |
cmd_put2w(pie->image.Width - entire_box.q.x,
|
|
|
665 |
pie->image.Height - entire_box.q.y, bp);
|
|
|
666 |
}
|
|
|
667 |
len = bp - pie->begin_image_command;
|
|
|
668 |
TRY_RECT {
|
|
|
669 |
code =
|
|
|
670 |
set_cmd_put_op(dp, cdev, pcls, image_op, 1 + len);
|
|
|
671 |
} HANDLE_RECT(code);
|
|
|
672 |
memcpy(dp + 1, pie->begin_image_command, len);
|
|
|
673 |
|
|
|
674 |
/* Mark band's begin_image as known */
|
|
|
675 |
pcls->known |= begin_image_known;
|
|
|
676 |
}
|
|
|
677 |
|
|
|
678 |
/*
|
|
|
679 |
* The data that we write out must use the X values set by
|
|
|
680 |
* begin_image, which may cover a larger interval than the ones
|
|
|
681 |
* actually needed for these particular scan lines if the image is
|
|
|
682 |
* rotated.
|
|
|
683 |
*/
|
|
|
684 |
{
|
|
|
685 |
/*
|
|
|
686 |
* image_band_box ensures that b{x,y}{0,1} fall within
|
|
|
687 |
* pie->rect.
|
|
|
688 |
*/
|
|
|
689 |
int bx0 = entire_box.p.x, bx1 = entire_box.q.x;
|
|
|
690 |
int by0 = ibox.p.y, by1 = ibox.q.y;
|
|
|
691 |
int bpp = pie->bits_per_plane;
|
|
|
692 |
int num_planes = pie->num_planes;
|
|
|
693 |
uint offsets[gs_image_max_planes];
|
|
|
694 |
int i, iy, ih, xskip, xoff, nrows;
|
|
|
695 |
uint bytes_per_plane, bytes_per_row, rows_per_cmd;
|
|
|
696 |
|
|
|
697 |
if (by0 < y0)
|
|
|
698 |
by0 = y0;
|
|
|
699 |
if (by1 > y1)
|
|
|
700 |
by1 = y1;
|
|
|
701 |
/*
|
|
|
702 |
* Make sure we're skipping an integral number of pixels, by
|
|
|
703 |
* truncating the initial X coordinate to the next lower
|
|
|
704 |
* value that is an exact multiple of a byte.
|
|
|
705 |
*/
|
|
|
706 |
xoff = bx0 - pie->rect.p.x;
|
|
|
707 |
xskip = xoff & -(int)"\001\010\004\010\002\010\004\010"[bpp & 7];
|
|
|
708 |
for (i = 0; i < num_planes; ++i)
|
|
|
709 |
offsets[i] =
|
|
|
710 |
(by0 - y0) * planes[i].raster + ((xskip * bpp) >> 3);
|
|
|
711 |
bytes_per_plane = ((bx1 - (pie->rect.p.x + xskip)) * bpp + 7) >> 3;
|
|
|
712 |
bytes_per_row = bytes_per_plane * pie->num_planes;
|
|
|
713 |
rows_per_cmd =
|
|
|
714 |
(cbuf_size - cmd_largest_size) / max(bytes_per_row, 1);
|
|
|
715 |
|
|
|
716 |
if (rows_per_cmd == 0) {
|
|
|
717 |
/* The reader will have to buffer a row separately. */
|
|
|
718 |
rows_per_cmd = 1;
|
|
|
719 |
}
|
|
|
720 |
for (iy = by0, ih = by1 - by0; ih > 0; iy += nrows, ih -= nrows) {
|
|
|
721 |
nrows = min(ih, rows_per_cmd);
|
|
|
722 |
TRY_RECT {
|
|
|
723 |
code = cmd_image_plane_data(cdev, pcls, planes, info,
|
|
|
724 |
bytes_per_plane, offsets,
|
|
|
725 |
xoff - xskip, nrows);
|
|
|
726 |
} HANDLE_RECT(code);
|
|
|
727 |
for (i = 0; i < num_planes; ++i)
|
|
|
728 |
offsets[i] += planes[i].raster * nrows;
|
|
|
729 |
}
|
|
|
730 |
}
|
|
|
731 |
} END_RECTS_ON_ERROR(
|
|
|
732 |
BEGIN
|
|
|
733 |
++cdev->ignore_lo_mem_warnings;
|
|
|
734 |
NEST_RECT {
|
|
|
735 |
code = write_image_end_all(dev, pie);
|
|
|
736 |
} UNNEST_RECT;
|
|
|
737 |
--cdev->ignore_lo_mem_warnings;
|
|
|
738 |
/* Update sub-rect */
|
|
|
739 |
if (!pie->image.Interpolate)
|
|
|
740 |
pie->rect.p.y += yh_used; /* interpolate & mem recovery currently incompat */
|
|
|
741 |
END,
|
|
|
742 |
(code < 0 ? (band_code = code) : code) >= 0,
|
|
|
743 |
(cmd_clear_known(cdev,
|
|
|
744 |
clist_image_unknowns(dev, pie) | begin_image_known),
|
|
|
745 |
pie->color_map_is_known = false,
|
|
|
746 |
cdev->image_enum_id = pie->id, true)
|
|
|
747 |
);
|
|
|
748 |
done:
|
|
|
749 |
*rows_used = pie->y - y_orig;
|
|
|
750 |
return pie->y >= pie->rect.q.y;
|
|
|
751 |
}
|
|
|
752 |
|
|
|
753 |
/* Clean up by releasing the buffers. */
|
|
|
754 |
private int
|
|
|
755 |
clist_image_end_image(gx_image_enum_common_t * info, bool draw_last)
|
|
|
756 |
{
|
|
|
757 |
gx_device *dev = info->dev;
|
|
|
758 |
gx_device_clist_writer * const cdev =
|
|
|
759 |
&((gx_device_clist *)dev)->writer;
|
|
|
760 |
clist_image_enum *pie = (clist_image_enum *) info;
|
|
|
761 |
int code;
|
|
|
762 |
|
|
|
763 |
#ifdef DEBUG
|
|
|
764 |
if (pie->id != cdev->image_enum_id) {
|
|
|
765 |
lprintf2("end_image id = %lu != clist image id = %lu!\n",
|
|
|
766 |
(ulong) pie->id, (ulong) cdev->image_enum_id);
|
|
|
767 |
return_error(gs_error_Fatal);
|
|
|
768 |
}
|
|
|
769 |
#endif
|
|
|
770 |
NEST_RECT {
|
|
|
771 |
do {
|
|
|
772 |
code = write_image_end_all(dev, pie);
|
|
|
773 |
} while (code < 0 && cdev->error_is_retryable &&
|
|
|
774 |
(code = clist_VMerror_recover(cdev, code)) >= 0
|
|
|
775 |
);
|
|
|
776 |
/* if couldn't write successsfully, do a hard flush */
|
|
|
777 |
if (code < 0 && cdev->error_is_retryable) {
|
|
|
778 |
int retry_code;
|
|
|
779 |
++cdev->ignore_lo_mem_warnings;
|
|
|
780 |
retry_code = write_image_end_all(dev, pie); /* force it out */
|
|
|
781 |
--cdev->ignore_lo_mem_warnings;
|
|
|
782 |
if (retry_code >= 0 && cdev->driver_call_nesting == 0)
|
|
|
783 |
code = clist_VMerror_recover_flush(cdev, code);
|
|
|
784 |
}
|
|
|
785 |
} UNNEST_RECT;
|
|
|
786 |
cdev->image_enum_id = gs_no_id;
|
|
|
787 |
gs_free_object(pie->memory, pie, "clist_image_end_image");
|
|
|
788 |
return code;
|
|
|
789 |
}
|
|
|
790 |
|
|
|
791 |
/* Create a compositor device. */
|
|
|
792 |
int
|
|
|
793 |
clist_create_compositor(gx_device * dev,
|
|
|
794 |
gx_device ** pcdev, const gs_composite_t * pcte,
|
|
|
795 |
gs_imager_state * pis, gs_memory_t * mem)
|
|
|
796 |
{
|
|
|
797 |
byte * dp;
|
|
|
798 |
uint size = 0;
|
|
|
799 |
int code = pcte->type->procs.write(pcte, 0, &size);
|
|
|
800 |
|
|
|
801 |
/* determine the amount of space required */
|
|
|
802 |
if (code < 0 && code != gs_error_rangecheck)
|
|
|
803 |
return code;
|
|
|
804 |
size += 2 + 1; /* 2 bytes for the command code, one for the id */
|
|
|
805 |
|
|
|
806 |
/* Create a compositor device for clist writing (if needed) */
|
|
|
807 |
code = pcte->type->procs.clist_compositor_write_update(pcte, dev,
|
|
|
808 |
pcdev, pis, mem);
|
|
|
809 |
if (code < 0)
|
|
|
810 |
return code;
|
|
|
811 |
|
|
|
812 |
if (pcte->type->comp_id == GX_COMPOSITOR_PDF14_TRANS) {
|
|
|
813 |
gx_device_clist_writer * const cldev =
|
|
|
814 |
&((gx_device_clist *)dev)->writer;
|
|
|
815 |
int len = cmd_write_ctm_return_length(cldev, &ctm_only(pis));
|
|
|
816 |
|
|
|
817 |
code = set_cmd_put_all_op(dp, (gx_device_clist_writer *)dev,
|
|
|
818 |
cmd_opv_set_ctm, len + 1);
|
|
|
819 |
if (code < 0)
|
|
|
820 |
return code;
|
|
|
821 |
/* fixme: would like to set pcls->known for covered bands. */
|
|
|
822 |
code = cmd_write_ctm(&ctm_only(pis), dp, len);
|
|
|
823 |
if (code < 0)
|
|
|
824 |
return code;
|
|
|
825 |
}
|
|
|
826 |
|
|
|
827 |
/* overprint applies to all bands */
|
|
|
828 |
/* fixme: optimize: the pdf14 compositor could be applied
|
|
|
829 |
only to bands covered by the pcte->params.bbox. */
|
|
|
830 |
code = set_cmd_put_all_op( dp,
|
|
|
831 |
(gx_device_clist_writer *)dev,
|
|
|
832 |
cmd_opv_extend,
|
|
|
833 |
size );
|
|
|
834 |
if (code < 0)
|
|
|
835 |
return code;
|
|
|
836 |
|
|
|
837 |
/* insert the command and compositor identifier */
|
|
|
838 |
dp[1] = cmd_opv_ext_create_compositor;
|
|
|
839 |
dp[2] = pcte->type->comp_id;
|
|
|
840 |
|
|
|
841 |
/* serialize the remainder of the compositor */
|
|
|
842 |
if ((code = pcte->type->procs.write(pcte, dp + 3, &size)) < 0)
|
|
|
843 |
((gx_device_clist_writer *)dev)->cnext = dp;
|
|
|
844 |
return code;
|
|
|
845 |
}
|
|
|
846 |
|
|
|
847 |
/* ------ Utilities ------ */
|
|
|
848 |
|
|
|
849 |
/* Add a command to set data_x. */
|
|
|
850 |
private int
|
|
|
851 |
cmd_put_set_data_x(gx_device_clist_writer * cldev, gx_clist_state * pcls,
|
|
|
852 |
int data_x)
|
|
|
853 |
{
|
|
|
854 |
byte *dp;
|
|
|
855 |
int code;
|
|
|
856 |
|
|
|
857 |
if (data_x > 0x1f) {
|
|
|
858 |
int dx_msb = data_x >> 5;
|
|
|
859 |
|
|
|
860 |
code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_misc,
|
|
|
861 |
2 + cmd_size_w(dx_msb));
|
|
|
862 |
if (code >= 0) {
|
|
|
863 |
dp[1] = cmd_set_misc_data_x + 0x20 + (data_x & 0x1f);
|
|
|
864 |
cmd_put_w(dx_msb, dp + 2);
|
|
|
865 |
}
|
|
|
866 |
} else {
|
|
|
867 |
code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_set_misc, 2);
|
|
|
868 |
if (code >= 0)
|
|
|
869 |
dp[1] = cmd_set_misc_data_x + data_x;
|
|
|
870 |
}
|
|
|
871 |
return code;
|
|
|
872 |
}
|
|
|
873 |
|
|
|
874 |
/* Add commands to represent a full (device) halftone. */
|
|
|
875 |
int
|
|
|
876 |
cmd_put_halftone(gx_device_clist_writer * cldev, const gx_device_halftone * pdht)
|
|
|
877 |
{
|
|
|
878 |
uint ht_size = 0, req_size;
|
|
|
879 |
byte * dp;
|
|
|
880 |
byte * dp0 = 0;
|
|
|
881 |
byte * pht_buff = 0;
|
|
|
882 |
int code = gx_ht_write(pdht, (gx_device *)cldev, 0, &ht_size);
|
|
|
883 |
|
|
|
884 |
/*
|
|
|
885 |
* Determine the required size, and if necessary allocate a buffer.
|
|
|
886 |
*
|
|
|
887 |
* The full serialized representation consists of:
|
|
|
888 |
* command code (2 bytes)
|
|
|
889 |
* length of serialized halftone (enc_u_sizew(ht_size)
|
|
|
890 |
* one or more halfton segments, which consist of:
|
|
|
891 |
* command code (2 bytes)
|
|
|
892 |
* segment size (enc_u_sizew(seg_size) (seg_size < cbuf_ht_seg_max_size)
|
|
|
893 |
* the serialized halftone segment (seg_size)
|
|
|
894 |
*
|
|
|
895 |
* Serialized halftones may be larger than the command buffer, so it
|
|
|
896 |
* is sent in segments. The cmd_opv_extend/cmd_opv_ext_put_halftone
|
|
|
897 |
* combination indicates that a device halftone is being sent, and
|
|
|
898 |
* provides the length of the entire halftone. This is followed by
|
|
|
899 |
* one or more cmd_opv_extend/cmd_opv_ext_ht_seg commands, which
|
|
|
900 |
* convey the segments of the serialized hafltone. The reader can
|
|
|
901 |
* identify the final segment by adding segment lengths.
|
|
|
902 |
*
|
|
|
903 |
* This complexity is hidden from the serialization code. If the
|
|
|
904 |
* halftone is larger than a single halftone buffer, we allocate a
|
|
|
905 |
* buffer to hold the entire representation, and divided into
|
|
|
906 |
* segments in this routine.
|
|
|
907 |
*/
|
|
|
908 |
if (code < 0 && code != gs_error_rangecheck)
|
|
|
909 |
return code;
|
|
|
910 |
req_size = 2 + enc_u_sizew(ht_size);
|
|
|
911 |
|
|
|
912 |
/* output the "put halftone" command */
|
|
|
913 |
if ((code = set_cmd_put_all_op(dp, cldev, cmd_opv_extend, req_size)) < 0)
|
|
|
914 |
return code;
|
|
|
915 |
dp[1] = cmd_opv_ext_put_halftone;
|
|
|
916 |
dp += 2;
|
|
|
917 |
enc_u_putw(ht_size, dp);
|
|
|
918 |
|
|
|
919 |
/* see if a spearate allocated buffer is required */
|
|
|
920 |
if (ht_size > cbuf_ht_seg_max_size) {
|
|
|
921 |
pht_buff = gs_alloc_bytes( cldev->bandlist_memory,
|
|
|
922 |
ht_size,
|
|
|
923 |
"cmd_put_halftone" );
|
|
|
924 |
if (pht_buff == 0)
|
|
|
925 |
return_error(gs_error_VMerror);
|
|
|
926 |
} else {
|
|
|
927 |
/* send the only segment command */
|
|
|
928 |
req_size += ht_size;
|
|
|
929 |
code = set_cmd_put_all_op(dp, cldev, cmd_opv_extend, req_size);
|
|
|
930 |
if (code < 0)
|
|
|
931 |
return code;
|
|
|
932 |
dp0 = dp;
|
|
|
933 |
dp[1] = cmd_opv_ext_put_ht_seg;
|
|
|
934 |
dp += 2;
|
|
|
935 |
enc_u_putw(ht_size, dp);
|
|
|
936 |
pht_buff = dp;
|
|
|
937 |
}
|
|
|
938 |
|
|
|
939 |
/* serialize the halftone */
|
|
|
940 |
code = gx_ht_write(pdht, (gx_device *)cldev, pht_buff, &ht_size);
|
|
|
941 |
if (code < 0) {
|
|
|
942 |
if (ht_size > cbuf_ht_seg_max_size)
|
|
|
943 |
gs_free_object( cldev->bandlist_memory,
|
|
|
944 |
pht_buff,
|
|
|
945 |
"cmd_put_halftone" );
|
|
|
946 |
else
|
|
|
947 |
cldev->cnext = dp0;
|
|
|
948 |
return code;
|
|
|
949 |
}
|
|
|
950 |
|
|
|
951 |
/*
|
|
|
952 |
* If the halftone fit into a single command buffer, we are done.
|
|
|
953 |
* Otherwise, process the individual segments.
|
|
|
954 |
*
|
|
|
955 |
* If bandlist memory is exhausted while processing the segments,
|
|
|
956 |
* we do not make any attempt to recover the partially submitted
|
|
|
957 |
* halftone. The reader will discard any partially sent hafltone
|
|
|
958 |
* when it receives the next cmd_opv_extend/
|
|
|
959 |
* cmd_opv_ext_put_halftone combination.
|
|
|
960 |
*/
|
|
|
961 |
if (ht_size > cbuf_ht_seg_max_size) {
|
|
|
962 |
byte * pbuff = pht_buff;
|
|
|
963 |
|
|
|
964 |
while (ht_size > 0 && code >= 0) {
|
|
|
965 |
int seg_size, tmp_size;
|
|
|
966 |
|
|
|
967 |
seg_size = ( ht_size > cbuf_ht_seg_max_size ? cbuf_ht_seg_max_size
|
|
|
968 |
: ht_size );
|
|
|
969 |
tmp_size = 2 + enc_u_sizew(seg_size) + seg_size;
|
|
|
970 |
code = set_cmd_put_all_op(dp, cldev, cmd_opv_extend, tmp_size);
|
|
|
971 |
if (code >= 0) {
|
|
|
972 |
dp[1] = cmd_opv_ext_put_ht_seg;
|
|
|
973 |
dp += 2;
|
|
|
974 |
enc_u_putw(seg_size, dp);
|
|
|
975 |
memcpy(dp, pbuff, seg_size);
|
|
|
976 |
ht_size -= seg_size;
|
|
|
977 |
pbuff += seg_size;
|
|
|
978 |
}
|
|
|
979 |
}
|
|
|
980 |
gs_free_object( cldev->bandlist_memory, pht_buff, "cmd_put_halftone");
|
|
|
981 |
pht_buff = 0;
|
|
|
982 |
}
|
|
|
983 |
|
|
|
984 |
if (code >= 0)
|
|
|
985 |
cldev->device_halftone_id = pdht->id;
|
|
|
986 |
|
|
|
987 |
return code;
|
|
|
988 |
}
|
|
|
989 |
|
|
|
990 |
/* Write out any necessary color mapping data. */
|
|
|
991 |
int
|
|
|
992 |
cmd_put_color_mapping(gx_device_clist_writer * cldev,
|
|
|
993 |
const gs_imager_state * pis)
|
|
|
994 |
{
|
|
|
995 |
int code;
|
|
|
996 |
const gx_device_halftone *pdht = pis->dev_ht;
|
|
|
997 |
|
|
|
998 |
/* Put out the halftone. */
|
|
|
999 |
if (pdht->id != cldev->device_halftone_id) {
|
|
|
1000 |
code = cmd_put_halftone(cldev, pdht);
|
|
|
1001 |
if (code < 0)
|
|
|
1002 |
return code;
|
|
|
1003 |
cldev->device_halftone_id = pdht->id;
|
|
|
1004 |
}
|
|
|
1005 |
/* Put the under color removal and black generation functions */
|
|
|
1006 |
code = cmd_put_color_map(cldev, cmd_map_black_generation,
|
|
|
1007 |
0, pis->black_generation,
|
|
|
1008 |
&cldev->black_generation_id);
|
|
|
1009 |
if (code < 0)
|
|
|
1010 |
return code;
|
|
|
1011 |
code = cmd_put_color_map(cldev, cmd_map_undercolor_removal,
|
|
|
1012 |
0, pis->undercolor_removal,
|
|
|
1013 |
&cldev->undercolor_removal_id);
|
|
|
1014 |
if (code < 0)
|
|
|
1015 |
return code;
|
|
|
1016 |
/* Now put out the transfer functions. */
|
|
|
1017 |
{
|
|
|
1018 |
uint which = 0;
|
|
|
1019 |
bool all_same = true;
|
|
|
1020 |
bool send_default_comp = false;
|
|
|
1021 |
int i;
|
|
|
1022 |
gs_id default_comp_id, xfer_ids[4];
|
|
|
1023 |
|
|
|
1024 |
/*
|
|
|
1025 |
* Determine the ids for the transfer functions that we currently
|
|
|
1026 |
* have in the set_transfer structure. The halftone xfer funcs
|
|
|
1027 |
* are sent in cmd_put_halftone.
|
|
|
1028 |
*/
|
|
|
1029 |
#define get_id(pis, color, color_num) \
|
|
|
1030 |
((pis->set_transfer.color != NULL && pis->set_transfer.color_num >= 0) \
|
|
|
1031 |
? pis->set_transfer.color->id\
|
|
|
1032 |
: pis->set_transfer.gray->id)
|
|
|
1033 |
|
|
|
1034 |
xfer_ids[0] = get_id(pis, red, red_component_num);
|
|
|
1035 |
xfer_ids[1] = get_id(pis, green, green_component_num);
|
|
|
1036 |
xfer_ids[2] = get_id(pis, blue, blue_component_num);
|
|
|
1037 |
xfer_ids[3] = default_comp_id = pis->set_transfer.gray->id;
|
|
|
1038 |
#undef get_id
|
|
|
1039 |
|
|
|
1040 |
for (i = 0; i < countof(cldev->transfer_ids); ++i) {
|
|
|
1041 |
if (xfer_ids[i] != cldev->transfer_ids[i])
|
|
|
1042 |
which |= 1 << i;
|
|
|
1043 |
if (xfer_ids[i] != default_comp_id)
|
|
|
1044 |
all_same = false;
|
|
|
1045 |
if (xfer_ids[i] == default_comp_id &&
|
|
|
1046 |
cldev->transfer_ids[i] != default_comp_id)
|
|
|
1047 |
send_default_comp = true;
|
|
|
1048 |
}
|
|
|
1049 |
/* There are 3 cases for transfer functions: nothing to write, */
|
|
|
1050 |
/* a single function, and multiple functions. */
|
|
|
1051 |
if (which == 0)
|
|
|
1052 |
return 0;
|
|
|
1053 |
/*
|
|
|
1054 |
* Send default transfer function if changed or we need it for a
|
|
|
1055 |
* component
|
|
|
1056 |
*/
|
|
|
1057 |
if (send_default_comp || cldev->transfer_ids[0] != default_comp_id) {
|
|
|
1058 |
gs_id dummy = gs_no_id;
|
|
|
1059 |
|
|
|
1060 |
code = cmd_put_color_map(cldev, cmd_map_transfer, 0,
|
|
|
1061 |
pis->set_transfer.gray, &dummy);
|
|
|
1062 |
if (code < 0)
|
|
|
1063 |
return code;
|
|
|
1064 |
/* Sending a default will force all xfers to default */
|
|
|
1065 |
for (i = 0; i < countof(cldev->transfer_ids); ++i)
|
|
|
1066 |
cldev->transfer_ids[i] = default_comp_id;
|
|
|
1067 |
}
|
|
|
1068 |
/* Send any transfer functions which have changed */
|
|
|
1069 |
if (cldev->transfer_ids[0] != xfer_ids[0]) {
|
|
|
1070 |
code = cmd_put_color_map(cldev, cmd_map_transfer_0,
|
|
|
1071 |
pis->set_transfer.red_component_num,
|
|
|
1072 |
pis->set_transfer.red, &cldev->transfer_ids[0]);
|
|
|
1073 |
if (code < 0)
|
|
|
1074 |
return code;
|
|
|
1075 |
}
|
|
|
1076 |
if (cldev->transfer_ids[1] != xfer_ids[1]) {
|
|
|
1077 |
code = cmd_put_color_map(cldev, cmd_map_transfer_1,
|
|
|
1078 |
pis->set_transfer.green_component_num,
|
|
|
1079 |
pis->set_transfer.green, &cldev->transfer_ids[1]);
|
|
|
1080 |
if (code < 0)
|
|
|
1081 |
return code;
|
|
|
1082 |
}
|
|
|
1083 |
if (cldev->transfer_ids[2] != xfer_ids[2]) {
|
|
|
1084 |
code = cmd_put_color_map(cldev, cmd_map_transfer_2,
|
|
|
1085 |
pis->set_transfer.blue_component_num,
|
|
|
1086 |
pis->set_transfer.blue, &cldev->transfer_ids[2]);
|
|
|
1087 |
if (code < 0)
|
|
|
1088 |
return code;
|
|
|
1089 |
}
|
|
|
1090 |
}
|
|
|
1091 |
|
|
|
1092 |
return 0;
|
|
|
1093 |
}
|
|
|
1094 |
|
|
|
1095 |
/*
|
|
|
1096 |
* Compute the subrectangle of an image that intersects a band;
|
|
|
1097 |
* return false if it is empty.
|
|
|
1098 |
* It is OK for this to be too large; in fact, with the present
|
|
|
1099 |
* algorithm, it will be quite a bit too large if the transformation isn't
|
|
|
1100 |
* well-behaved ("well-behaved" meaning either xy = yx = 0 or xx = yy = 0).
|
|
|
1101 |
*/
|
|
|
1102 |
#define I_FLOOR(x) ((int)floor(x))
|
|
|
1103 |
#define I_CEIL(x) ((int)ceil(x))
|
|
|
1104 |
private void
|
|
|
1105 |
box_merge_point(gs_int_rect * pbox, floatp x, floatp y)
|
|
|
1106 |
{
|
|
|
1107 |
int t;
|
|
|
1108 |
|
|
|
1109 |
if ((t = I_FLOOR(x)) < pbox->p.x)
|
|
|
1110 |
pbox->p.x = t;
|
|
|
1111 |
if ((t = I_CEIL(x)) > pbox->q.x)
|
|
|
1112 |
pbox->q.x = t;
|
|
|
1113 |
if ((t = I_FLOOR(y)) < pbox->p.y)
|
|
|
1114 |
pbox->p.y = t;
|
|
|
1115 |
if ((t = I_CEIL(y)) > pbox->q.y)
|
|
|
1116 |
pbox->q.y = t;
|
|
|
1117 |
}
|
|
|
1118 |
private bool
|
|
|
1119 |
image_band_box(gx_device * dev, const clist_image_enum * pie, int y, int h,
|
|
|
1120 |
gs_int_rect * pbox)
|
|
|
1121 |
{
|
|
|
1122 |
fixed by0 = int2fixed(y);
|
|
|
1123 |
fixed by1 = int2fixed(y + h);
|
|
|
1124 |
int
|
|
|
1125 |
px = pie->rect.p.x, py = pie->rect.p.y,
|
|
|
1126 |
qx = pie->rect.q.x, qy = pie->rect.q.y;
|
|
|
1127 |
gs_fixed_rect cbox; /* device clipping box */
|
|
|
1128 |
gs_rect bbox; /* cbox intersected with band */
|
|
|
1129 |
|
|
|
1130 |
/* Intersect the device clipping box and the band. */
|
|
|
1131 |
(*dev_proc(dev, get_clipping_box)) (dev, &cbox);
|
|
|
1132 |
/* The fixed_half here is to allow for adjustment. */
|
|
|
1133 |
bbox.p.x = fixed2float(cbox.p.x - fixed_half);
|
|
|
1134 |
bbox.q.x = fixed2float(cbox.q.x + fixed_half);
|
|
|
1135 |
bbox.p.y = fixed2float(max(cbox.p.y, by0) - fixed_half);
|
|
|
1136 |
bbox.q.y = fixed2float(min(cbox.q.y, by1) + fixed_half);
|
|
|
1137 |
#ifdef DEBUG
|
|
|
1138 |
if (gs_debug_c('b')) {
|
|
|
1139 |
dlprintf6("[b]band box for (%d,%d),(%d,%d), band (%d,%d) =>\n",
|
|
|
1140 |
px, py, qx, qy, y, y + h);
|
|
|
1141 |
dlprintf10(" (%g,%g),(%g,%g), matrix=[%g %g %g %g %g %g]\n",
|
|
|
1142 |
bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y,
|
|
|
1143 |
pie->matrix.xx, pie->matrix.xy, pie->matrix.yx,
|
|
|
1144 |
pie->matrix.yy, pie->matrix.tx, pie->matrix.ty);
|
|
|
1145 |
}
|
|
|
1146 |
#endif
|
|
|
1147 |
if (is_xxyy(&pie->matrix) || is_xyyx(&pie->matrix)) {
|
|
|
1148 |
/*
|
|
|
1149 |
* The inverse transform of the band is a rectangle aligned with
|
|
|
1150 |
* the coordinate axes, so we can just intersect it with the
|
|
|
1151 |
* image subrectangle.
|
|
|
1152 |
*/
|
|
|
1153 |
gs_rect ibox; /* bbox transformed back to image space */
|
|
|
1154 |
|
|
|
1155 |
if (gs_bbox_transform_inverse(&bbox, &pie->matrix, &ibox) < 0)
|
|
|
1156 |
return false;
|
|
|
1157 |
pbox->p.x = max(px, I_FLOOR(ibox.p.x));
|
|
|
1158 |
pbox->q.x = min(qx, I_CEIL(ibox.q.x));
|
|
|
1159 |
pbox->p.y = max(py, I_FLOOR(ibox.p.y));
|
|
|
1160 |
pbox->q.y = min(qy, I_CEIL(ibox.q.y));
|
|
|
1161 |
} else {
|
|
|
1162 |
/*
|
|
|
1163 |
* The inverse transform of the band is not aligned with the
|
|
|
1164 |
* axes, i.e., is a general parallelogram. To compute an exact
|
|
|
1165 |
* bounding box, we need to find the intersections of this
|
|
|
1166 |
* parallelogram with the image subrectangle.
|
|
|
1167 |
*
|
|
|
1168 |
* There is probably a much more efficient way to do this
|
|
|
1169 |
* computation, but we don't know what it is.
|
|
|
1170 |
*/
|
|
|
1171 |
gs_point rect[4];
|
|
|
1172 |
gs_point corners[5];
|
|
|
1173 |
int i;
|
|
|
1174 |
|
|
|
1175 |
/* Store the corners of the image rectangle. */
|
|
|
1176 |
rect[0].x = rect[3].x = px;
|
|
|
1177 |
rect[1].x = rect[2].x = qx;
|
|
|
1178 |
rect[0].y = rect[1].y = py;
|
|
|
1179 |
rect[2].y = rect[3].y = qy;
|
|
|
1180 |
/*
|
|
|
1181 |
* Compute the corners of the clipped band in image space. If
|
|
|
1182 |
* the matrix is singular or an overflow occurs, the result will
|
|
|
1183 |
* be nonsense: in this case, there isn't anything useful we
|
|
|
1184 |
* can do, so return an empty intersection.
|
|
|
1185 |
*/
|
|
|
1186 |
if (gs_point_transform_inverse(bbox.p.x, bbox.p.y, &pie->matrix,
|
|
|
1187 |
&corners[0]) < 0 ||
|
|
|
1188 |
gs_point_transform_inverse(bbox.q.x, bbox.p.y, &pie->matrix,
|
|
|
1189 |
&corners[1]) < 0 ||
|
|
|
1190 |
gs_point_transform_inverse(bbox.q.x, bbox.q.y, &pie->matrix,
|
|
|
1191 |
&corners[2]) < 0 ||
|
|
|
1192 |
gs_point_transform_inverse(bbox.p.x, bbox.q.y, &pie->matrix,
|
|
|
1193 |
&corners[3]) < 0
|
|
|
1194 |
) {
|
|
|
1195 |
if_debug0('b', "[b]can't inverse-transform a band corner!\n");
|
|
|
1196 |
return false;
|
|
|
1197 |
}
|
|
|
1198 |
corners[4] = corners[0];
|
|
|
1199 |
pbox->p.x = qx, pbox->p.y = qy;
|
|
|
1200 |
pbox->q.x = px, pbox->q.y = py;
|
|
|
1201 |
/*
|
|
|
1202 |
* We iterate over both the image rectangle and the band
|
|
|
1203 |
* parallelogram in a single loop for convenience, even though
|
|
|
1204 |
* there is no coupling between the two.
|
|
|
1205 |
*/
|
|
|
1206 |
for (i = 0; i < 4; ++i) {
|
|
|
1207 |
gs_point pa, pt;
|
|
|
1208 |
double dx, dy;
|
|
|
1209 |
|
|
|
1210 |
/* Check the image corner for being inside the band. */
|
|
|
1211 |
pa = rect[i];
|
|
|
1212 |
gs_point_transform(pa.x, pa.y, &pie->matrix, &pt);
|
|
|
1213 |
if (pt.x >= bbox.p.x && pt.x <= bbox.q.x &&
|
|
|
1214 |
pt.y >= bbox.p.y && pt.y <= bbox.q.y
|
|
|
1215 |
)
|
|
|
1216 |
box_merge_point(pbox, pa.x, pa.y);
|
|
|
1217 |
/* Check the band corner for being inside the image. */
|
|
|
1218 |
pa = corners[i];
|
|
|
1219 |
if (pa.x >= px && pa.x <= qx && pa.y >= py && pa.y <= qy)
|
|
|
1220 |
box_merge_point(pbox, pa.x, pa.y);
|
|
|
1221 |
/* Check for intersections of band edges with image edges. */
|
|
|
1222 |
dx = corners[i + 1].x - pa.x;
|
|
|
1223 |
dy = corners[i + 1].y - pa.y;
|
|
|
1224 |
#define in_range(t, tc, p, q)\
|
|
|
1225 |
(0 <= t && t <= 1 && (t = tc) >= p && t <= q)
|
|
|
1226 |
if (dx != 0) {
|
|
|
1227 |
double t = (px - pa.x) / dx;
|
|
|
1228 |
|
|
|
1229 |
if_debug3('b', " (px) t=%g => (%d,%g)\n",
|
|
|
1230 |
t, px, pa.y + t * dy);
|
|
|
1231 |
if (in_range(t, pa.y + t * dy, py, qy))
|
|
|
1232 |
box_merge_point(pbox, (floatp) px, t);
|
|
|
1233 |
t = (qx - pa.x) / dx;
|
|
|
1234 |
if_debug3('b', " (qx) t=%g => (%d,%g)\n",
|
|
|
1235 |
t, qx, pa.y + t * dy);
|
|
|
1236 |
if (in_range(t, pa.y + t * dy, py, qy))
|
|
|
1237 |
box_merge_point(pbox, (floatp) qx, t);
|
|
|
1238 |
}
|
|
|
1239 |
if (dy != 0) {
|
|
|
1240 |
double t = (py - pa.y) / dy;
|
|
|
1241 |
|
|
|
1242 |
if_debug3('b', " (py) t=%g => (%g,%d)\n",
|
|
|
1243 |
t, pa.x + t * dx, py);
|
|
|
1244 |
if (in_range(t, pa.x + t * dx, px, qx))
|
|
|
1245 |
box_merge_point(pbox, t, (floatp) py);
|
|
|
1246 |
t = (qy - pa.y) / dy;
|
|
|
1247 |
if_debug3('b', " (qy) t=%g => (%g,%d)\n",
|
|
|
1248 |
t, pa.x + t * dx, qy);
|
|
|
1249 |
if (in_range(t, pa.x + t * dx, px, qx))
|
|
|
1250 |
box_merge_point(pbox, t, (floatp) qy);
|
|
|
1251 |
}
|
|
|
1252 |
#undef in_range
|
|
|
1253 |
}
|
|
|
1254 |
}
|
|
|
1255 |
if_debug4('b', " => (%d,%d),(%d,%d)\n", pbox->p.x, pbox->p.y,
|
|
|
1256 |
pbox->q.x, pbox->q.y);
|
|
|
1257 |
/*
|
|
|
1258 |
* If necessary, add pixels around the edges so we will have
|
|
|
1259 |
* enough information to do interpolation.
|
|
|
1260 |
*/
|
|
|
1261 |
if ((pbox->p.x -= pie->support.x) < pie->rect.p.x)
|
|
|
1262 |
pbox->p.x = pie->rect.p.x;
|
|
|
1263 |
if ((pbox->p.y -= pie->support.y) < pie->rect.p.y)
|
|
|
1264 |
pbox->p.y = pie->rect.p.y;
|
|
|
1265 |
if ((pbox->q.x += pie->support.x) > pie->rect.q.x)
|
|
|
1266 |
pbox->q.x = pie->rect.q.x;
|
|
|
1267 |
if ((pbox->q.y += pie->support.y) > pie->rect.q.y)
|
|
|
1268 |
pbox->q.y = pie->rect.q.y;
|
|
|
1269 |
return (pbox->p.x < pbox->q.x && pbox->p.y < pbox->q.y);
|
|
|
1270 |
}
|
|
|
1271 |
|
|
|
1272 |
/* Determine which image-related properties are unknown */
|
|
|
1273 |
private uint /* mask of unknown properties(see pcls->known) */
|
|
|
1274 |
clist_image_unknowns(gx_device *dev, const clist_image_enum *pie)
|
|
|
1275 |
{
|
|
|
1276 |
gx_device_clist_writer * const cdev =
|
|
|
1277 |
&((gx_device_clist *)dev)->writer;
|
|
|
1278 |
const gs_imager_state *const pis = pie->pis;
|
|
|
1279 |
uint unknown = 0;
|
|
|
1280 |
|
|
|
1281 |
/*
|
|
|
1282 |
* Determine if the CTM, color space, and clipping region (and, for
|
|
|
1283 |
* masked images or images with CombineWithColor, the current color)
|
|
|
1284 |
* are unknown. Set the device state in anticipation of the values
|
|
|
1285 |
* becoming known.
|
|
|
1286 |
*/
|
|
|
1287 |
if (cdev->imager_state.ctm.xx != pis->ctm.xx ||
|
|
|
1288 |
cdev->imager_state.ctm.xy != pis->ctm.xy ||
|
|
|
1289 |
cdev->imager_state.ctm.yx != pis->ctm.yx ||
|
|
|
1290 |
cdev->imager_state.ctm.yy != pis->ctm.yy ||
|
|
|
1291 |
cdev->imager_state.ctm.tx != pis->ctm.tx ||
|
|
|
1292 |
cdev->imager_state.ctm.ty != pis->ctm.ty
|
|
|
1293 |
) {
|
|
|
1294 |
unknown |= ctm_known;
|
|
|
1295 |
cdev->imager_state.ctm = pis->ctm;
|
|
|
1296 |
}
|
|
|
1297 |
if (pie->color_space.id == gs_no_id) { /* masked image */
|
|
|
1298 |
cdev->color_space.space = 0; /* for GC */
|
|
|
1299 |
} else { /* not masked */
|
|
|
1300 |
if (cdev->color_space.id == pie->color_space.id) {
|
|
|
1301 |
/* The color space pointer might not be valid: update it. */
|
|
|
1302 |
cdev->color_space.space = pie->color_space.space;
|
|
|
1303 |
} else {
|
|
|
1304 |
unknown |= color_space_known;
|
|
|
1305 |
cdev->color_space = pie->color_space;
|
|
|
1306 |
}
|
|
|
1307 |
}
|
|
|
1308 |
if (cmd_check_clip_path(cdev, pie->pcpath))
|
|
|
1309 |
unknown |= clip_path_known;
|
|
|
1310 |
/*
|
|
|
1311 |
* Note: overprint and overprint_mode are implemented via a compositor
|
|
|
1312 |
* device, which is passed separately through the command list. Hence,
|
|
|
1313 |
* though both parameters are passed in the state as well, this usually
|
|
|
1314 |
* has no effect.
|
|
|
1315 |
*/
|
|
|
1316 |
if (cdev->imager_state.overprint != pis->overprint ||
|
|
|
1317 |
cdev->imager_state.overprint_mode != pis->overprint_mode ||
|
|
|
1318 |
cdev->imager_state.blend_mode != pis->blend_mode ||
|
|
|
1319 |
cdev->imager_state.text_knockout != pis->text_knockout) {
|
|
|
1320 |
unknown |= op_bm_tk_known;
|
|
|
1321 |
cdev->imager_state.overprint = pis->overprint;
|
|
|
1322 |
cdev->imager_state.overprint_mode = pis->overprint_mode;
|
|
|
1323 |
cdev->imager_state.blend_mode = pis->blend_mode;
|
|
|
1324 |
cdev->imager_state.text_knockout = pis->text_knockout;
|
|
|
1325 |
}
|
|
|
1326 |
if (cdev->imager_state.opacity.alpha != pis->opacity.alpha) {
|
|
|
1327 |
unknown |= opacity_alpha_known;
|
|
|
1328 |
cdev->imager_state.opacity.alpha = pis->opacity.alpha;
|
|
|
1329 |
}
|
|
|
1330 |
if (cdev->imager_state.shape.alpha != pis->shape.alpha) {
|
|
|
1331 |
unknown |= shape_alpha_known;
|
|
|
1332 |
cdev->imager_state.shape.alpha = pis->shape.alpha;
|
|
|
1333 |
}
|
|
|
1334 |
if (cdev->imager_state.alpha != pis->alpha) {
|
|
|
1335 |
unknown |= alpha_known;
|
|
|
1336 |
cdev->imager_state.alpha = pis->alpha;
|
|
|
1337 |
}
|
|
|
1338 |
return unknown;
|
|
|
1339 |
}
|
|
|
1340 |
|
|
|
1341 |
/* Construct the begin_image command. */
|
|
|
1342 |
private int
|
|
|
1343 |
begin_image_command(byte *buf, uint buf_size, const gs_image_common_t *pic)
|
|
|
1344 |
{
|
|
|
1345 |
int i;
|
|
|
1346 |
stream s;
|
|
|
1347 |
const gs_color_space *ignore_pcs;
|
|
|
1348 |
int code;
|
|
|
1349 |
|
|
|
1350 |
for (i = 0; i < gx_image_type_table_count; ++i)
|
|
|
1351 |
if (gx_image_type_table[i] == pic->type)
|
|
|
1352 |
break;
|
|
|
1353 |
if (i >= gx_image_type_table_count)
|
|
|
1354 |
return_error(gs_error_rangecheck);
|
|
|
1355 |
s_init(&s, NULL);
|
|
|
1356 |
swrite_string(&s, buf, buf_size);
|
|
|
1357 |
sputc(&s, (byte)i);
|
|
|
1358 |
code = pic->type->sput(pic, &s, &ignore_pcs);
|
|
|
1359 |
return (code < 0 ? code : stell(&s));
|
|
|
1360 |
}
|
|
|
1361 |
|
|
|
1362 |
/* Write data for a partial image. */
|
|
|
1363 |
private int
|
|
|
1364 |
cmd_image_plane_data(gx_device_clist_writer * cldev, gx_clist_state * pcls,
|
|
|
1365 |
const gx_image_plane_t * planes,
|
|
|
1366 |
const gx_image_enum_common_t * pie,
|
|
|
1367 |
uint bytes_per_plane, const uint * offsets,
|
|
|
1368 |
int dx, int h)
|
|
|
1369 |
{
|
|
|
1370 |
int data_x = planes[0].data_x + dx;
|
|
|
1371 |
uint nbytes = bytes_per_plane * pie->num_planes * h;
|
|
|
1372 |
uint len = 1 + cmd_size2w(h, bytes_per_plane) + nbytes;
|
|
|
1373 |
byte *dp;
|
|
|
1374 |
uint offset = 0;
|
|
|
1375 |
int plane, i;
|
|
|
1376 |
int code;
|
|
|
1377 |
|
|
|
1378 |
if (data_x) {
|
|
|
1379 |
code = cmd_put_set_data_x(cldev, pcls, data_x);
|
|
|
1380 |
if (code < 0)
|
|
|
1381 |
return code;
|
|
|
1382 |
offset = ((data_x & ~7) * cldev->color_info.depth) >> 3;
|
|
|
1383 |
}
|
|
|
1384 |
code = set_cmd_put_op(dp, cldev, pcls, cmd_opv_image_data, len);
|
|
|
1385 |
if (code < 0)
|
|
|
1386 |
return code;
|
|
|
1387 |
dp++;
|
|
|
1388 |
cmd_put2w(h, bytes_per_plane, dp);
|
|
|
1389 |
for (plane = 0; plane < pie->num_planes; ++plane)
|
|
|
1390 |
for (i = 0; i < h; ++i) {
|
|
|
1391 |
memcpy(dp,
|
|
|
1392 |
planes[plane].data + i * planes[plane].raster +
|
|
|
1393 |
offsets[plane] + offset,
|
|
|
1394 |
bytes_per_plane);
|
|
|
1395 |
dp += bytes_per_plane;
|
|
|
1396 |
}
|
|
|
1397 |
return 0;
|
|
|
1398 |
}
|
|
|
1399 |
|
|
|
1400 |
/* Write image_end commands into all bands */
|
|
|
1401 |
private int /* ret 0 ok, else -ve error status */
|
|
|
1402 |
write_image_end_all(gx_device *dev, const clist_image_enum *pie)
|
|
|
1403 |
{
|
|
|
1404 |
gx_device_clist_writer * const cdev =
|
|
|
1405 |
&((gx_device_clist *)dev)->writer;
|
|
|
1406 |
int code;
|
|
|
1407 |
int y = pie->ymin;
|
|
|
1408 |
int height = pie->ymax - y;
|
|
|
1409 |
|
|
|
1410 |
/*
|
|
|
1411 |
* We need to check specially for images lying entirely outside the
|
|
|
1412 |
* page, since FOR_RECTS doesn't do this.
|
|
|
1413 |
*/
|
|
|
1414 |
if (height <= 0)
|
|
|
1415 |
return 0;
|
|
|
1416 |
FOR_RECTS {
|
|
|
1417 |
byte *dp;
|
|
|
1418 |
|
|
|
1419 |
if (!(pcls->known & begin_image_known))
|
|
|
1420 |
continue;
|
|
|
1421 |
TRY_RECT {
|
|
|
1422 |
if_debug1('L', "[L]image_end for band %d\n", band);
|
|
|
1423 |
code = set_cmd_put_op(dp, cdev, pcls, cmd_opv_image_data, 2);
|
|
|
1424 |
} HANDLE_RECT(code);
|
|
|
1425 |
dp[1] = 0; /* EOD */
|
|
|
1426 |
pcls->known ^= begin_image_known;
|
|
|
1427 |
} END_RECTS;
|
|
|
1428 |
return 0;
|
|
|
1429 |
}
|
|
|
1430 |
|
|
|
1431 |
/*
|
|
|
1432 |
* Compare a rectangle vs. clip path. Return true if there is no clipping
|
|
|
1433 |
* path, if the rectangle is unclipped, or if the clipping path is a
|
|
|
1434 |
* rectangle and intersects the given rectangle.
|
|
|
1435 |
*/
|
|
|
1436 |
private bool
|
|
|
1437 |
check_rect_for_trivial_clip(
|
|
|
1438 |
const gx_clip_path *pcpath, /* May be NULL, clip to evaluate */
|
|
|
1439 |
int px, int py, int qx, int qy /* corners of box to test */
|
|
|
1440 |
)
|
|
|
1441 |
{
|
|
|
1442 |
gs_fixed_rect obox;
|
|
|
1443 |
gs_fixed_rect imgbox;
|
|
|
1444 |
|
|
|
1445 |
if (!pcpath)
|
|
|
1446 |
return true;
|
|
|
1447 |
|
|
|
1448 |
imgbox.p.x = int2fixed(px);
|
|
|
1449 |
imgbox.p.y = int2fixed(py);
|
|
|
1450 |
imgbox.q.x = int2fixed(qx);
|
|
|
1451 |
imgbox.q.y = int2fixed(qy);
|
|
|
1452 |
if (gx_cpath_includes_rectangle(pcpath,
|
|
|
1453 |
imgbox.p.x, imgbox.p.y,
|
|
|
1454 |
imgbox.q.x, imgbox.q.y))
|
|
|
1455 |
return true;
|
|
|
1456 |
|
|
|
1457 |
return (gx_cpath_outer_box(pcpath, &obox) /* cpath is rectangle */ &&
|
|
|
1458 |
obox.p.x <= imgbox.q.x && obox.q.x >= imgbox.p.x &&
|
|
|
1459 |
obox.p.y <= imgbox.q.y && obox.q.y >= imgbox.p.y );
|
|
|
1460 |
}
|