/src/ghostpdl/base/gxipixel.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2025 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* Common code for ImageType 1 and 4 initialization */ |
18 | | #include "gx.h" |
19 | | #include "math_.h" |
20 | | #include "memory_.h" |
21 | | #include "gpcheck.h" |
22 | | #include "gscdefs.h" /* for image class table */ |
23 | | #include "gserrors.h" |
24 | | #include "gsstruct.h" |
25 | | #include "gsutil.h" |
26 | | #include "gxfixed.h" |
27 | | #include "gxfrac.h" |
28 | | #include "gxarith.h" |
29 | | #include "gxmatrix.h" |
30 | | #include "gsccolor.h" |
31 | | #include "gspaint.h" |
32 | | #include "gzstate.h" |
33 | | #include "gxdevice.h" |
34 | | #include "gzpath.h" |
35 | | #include "gzcpath.h" |
36 | | #include "gxdevmem.h" |
37 | | #include "gximage.h" |
38 | | #include "gxiparam.h" |
39 | | #include "gdevmrop.h" |
40 | | #include "gscspace.h" |
41 | | #include "gscindex.h" |
42 | | #include "gsicc_cache.h" |
43 | | #include "gsicc_cms.h" |
44 | | #include "gsicc_manage.h" |
45 | | #include "gxdevsop.h" |
46 | | |
47 | | /* Structure descriptors */ |
48 | | private_st_gx_image_enum(); |
49 | | |
50 | | /* Image class procedures */ |
51 | | extern_gx_image_class_table(); |
52 | | |
53 | | /* Enumerator procedures */ |
54 | | static const gx_image_enum_procs_t image1_enum_procs = { |
55 | | gx_image1_plane_data, gx_image1_end_image, gx_image1_flush |
56 | | }; |
57 | | |
58 | | /* GC procedures */ |
59 | | gs_private_st_ptrs2(st_color_cache, gx_image_color_cache_t, "gx_image_color_cache", |
60 | | color_cache_enum_ptrs, color_cache_reloc_ptrs, |
61 | | is_transparent, device_contone); |
62 | | static |
63 | 2.50k | ENUM_PTRS_WITH(image_enum_enum_ptrs, gx_image_enum *eptr) |
64 | 924 | { |
65 | 924 | int bps; |
66 | 924 | gs_ptr_type_t ret; |
67 | | |
68 | | /* Enumerate the used members of clues.dev_color. */ |
69 | 924 | index -= gx_image_enum_num_ptrs; |
70 | 924 | bps = eptr->unpack_bps; |
71 | 924 | if (eptr->spp != 1) |
72 | 0 | bps = 8; |
73 | 924 | else if (bps > 8 || eptr->unpack == sample_unpack_copy) |
74 | 0 | bps = 1; |
75 | 924 | if (index >= (1 << bps) * st_device_color_max_ptrs) /* done */ |
76 | 132 | return 0; |
77 | | /* the clues may have been cleared by gx_image_free_enum, but not freed in that */ |
78 | | /* function due to being at a different save level. Only trace if dev_color.type != 0. */ |
79 | 792 | if (eptr->spp == 1) { |
80 | 792 | if (eptr->clues != NULL) { |
81 | 792 | if (eptr->clues[(index/st_device_color_max_ptrs) * |
82 | 792 | (255 / ((1 << bps) - 1))].dev_color.type != 0) { |
83 | 792 | ret = ENUM_USING(st_device_color, |
84 | 792 | &eptr->clues[(index / st_device_color_max_ptrs) * |
85 | 792 | (255 / ((1 << bps) - 1))].dev_color, |
86 | 792 | sizeof(eptr->clues[0].dev_color), |
87 | 792 | index % st_device_color_max_ptrs); |
88 | 792 | } else { |
89 | 0 | ret = 0; |
90 | 0 | } |
91 | 792 | } else { |
92 | 0 | ret = 0; |
93 | 0 | } |
94 | 792 | } else { |
95 | 0 | ret = 0; |
96 | 0 | } |
97 | 792 | if (ret == 0) /* don't stop early */ |
98 | 792 | ENUM_RETURN(0); |
99 | 0 | return ret; |
100 | 792 | } |
101 | | |
102 | 1.58k | #define e1(i,elt) ENUM_PTR(i,gx_image_enum,elt); |
103 | 2.50k | gx_image_enum_do_ptrs(e1) |
104 | 2.50k | #undef e1 |
105 | 2.50k | ENUM_PTRS_END |
106 | | |
107 | 132 | static RELOC_PTRS_WITH(image_enum_reloc_ptrs, gx_image_enum *eptr) |
108 | 132 | { |
109 | 132 | int i; |
110 | | |
111 | 1.58k | #define r1(i,elt) RELOC_PTR(gx_image_enum,elt); |
112 | 1.58k | gx_image_enum_do_ptrs(r1) |
113 | 132 | #undef r1 |
114 | 132 | { |
115 | 132 | int bps = eptr->unpack_bps; |
116 | | |
117 | 132 | if (eptr->spp != 1) |
118 | 0 | bps = 8; |
119 | 132 | else if (bps > 8 || eptr->unpack == sample_unpack_copy) |
120 | 0 | bps = 1; |
121 | 132 | if (eptr->spp == 1) { |
122 | 396 | for (i = 0; i <= 255; i += 255 / ((1 << bps) - 1)) |
123 | 264 | RELOC_USING(st_device_color, |
124 | 132 | &eptr->clues[i].dev_color, sizeof(gx_device_color)); |
125 | 132 | } |
126 | 132 | } |
127 | 132 | } |
128 | 132 | RELOC_PTRS_END |
129 | | |
130 | | /* Forward declarations */ |
131 | | static int color_draws_b_w(gx_device * dev, |
132 | | const gx_drawing_color * pdcolor); |
133 | | static int image_init_colors(gx_image_enum * penum, int bps, int spp, |
134 | | gs_image_format_t format, |
135 | | const float *decode, |
136 | | const gs_gstate * pgs, gx_device * dev, |
137 | | const gs_color_space * pcs, bool * pdcb); |
138 | | |
139 | | /* Procedures for unpacking the input data into bytes or fracs. */ |
140 | | /*extern SAMPLE_UNPACK_PROC(sample_unpack_copy); *//* declared above */ |
141 | | |
142 | | /* |
143 | | * Do common initialization for processing an ImageType 1 or 4 image. |
144 | | * Allocate the enumerator and fill in the following members: |
145 | | * rect |
146 | | */ |
147 | | int |
148 | | gx_image_enum_alloc(const gs_image_common_t * pic, |
149 | | const gs_int_rect * prect, gs_memory_t * mem, |
150 | | gx_image_enum **ppenum) |
151 | 2.28M | { |
152 | 2.28M | const gs_pixel_image_t *pim = (const gs_pixel_image_t *)pic; |
153 | 2.28M | int width = pim->Width, height = pim->Height; |
154 | 2.28M | int bpc = pim->BitsPerComponent; |
155 | 2.28M | gx_image_enum *penum; |
156 | | |
157 | 2.28M | if (width < 0 || height < 0) |
158 | 0 | return_error(gs_error_rangecheck); |
159 | 2.28M | switch (pim->format) { |
160 | 2.23M | case gs_image_format_chunky: |
161 | 2.28M | case gs_image_format_component_planar: |
162 | 2.28M | switch (bpc) { |
163 | 2.28M | case 1: case 2: case 4: case 8: case 12: case 16: break; |
164 | 2 | default: return_error(gs_error_rangecheck); |
165 | 2.28M | } |
166 | 2.28M | break; |
167 | 2.28M | case gs_image_format_bit_planar: |
168 | 0 | if (bpc < 1 || bpc > 8) |
169 | 0 | return_error(gs_error_rangecheck); |
170 | 2.28M | } |
171 | 2.28M | if (prect) { |
172 | 732k | if (prect->p.x < 0 || prect->p.y < 0 || |
173 | 732k | prect->q.x < prect->p.x || prect->q.y < prect->p.y || |
174 | 732k | prect->q.x > width || prect->q.y > height |
175 | 732k | ) |
176 | 0 | return_error(gs_error_rangecheck); |
177 | 732k | } |
178 | 2.28M | *ppenum = NULL; /* in case alloc fails and caller doesn't check code */ |
179 | 2.28M | penum = gs_alloc_struct(mem, gx_image_enum, &st_gx_image_enum, |
180 | 2.28M | "gx_default_begin_image"); |
181 | 2.28M | if (penum == 0) |
182 | 0 | return_error(gs_error_VMerror); |
183 | 2.28M | memset(penum, 0, sizeof(gx_image_enum)); /* in case of failure, no dangling pointers */ |
184 | 2.28M | if (prect) { |
185 | 732k | penum->rect.x = prect->p.x; |
186 | 732k | penum->rect.y = prect->p.y; |
187 | 732k | penum->rect.w = prect->q.x - prect->p.x; |
188 | 732k | penum->rect.h = prect->q.y - prect->p.y; |
189 | 1.54M | } else { |
190 | 1.54M | penum->rect.x = 0, penum->rect.y = 0; |
191 | 1.54M | penum->rect.w = width, penum->rect.h = height; |
192 | 1.54M | } |
193 | 2.28M | penum->rrect.x = penum->rect.x; |
194 | 2.28M | penum->rrect.y = penum->rect.y; |
195 | 2.28M | penum->rrect.w = penum->rect.w; |
196 | 2.28M | penum->rrect.h = penum->rect.h; |
197 | 2.28M | penum->drect.x = penum->rect.x; |
198 | 2.28M | penum->drect.y = penum->rect.y; |
199 | 2.28M | penum->drect.w = penum->rect.w; |
200 | 2.28M | penum->drect.h = penum->rect.h; |
201 | | #ifdef DEBUG |
202 | | if (gs_debug_c('b')) { |
203 | | dmlprintf2(mem, "[b]Image: w=%d h=%d", width, height); |
204 | | if (prect) |
205 | | dmprintf4(mem, " ((%d,%d),(%d,%d))", |
206 | | prect->p.x, prect->p.y, prect->q.x, prect->q.y); |
207 | | } |
208 | | #endif |
209 | 2.28M | *ppenum = penum; |
210 | 2.28M | return 0; |
211 | 2.28M | } |
212 | | |
213 | | /* Convert and restrict to a valid range. */ |
214 | 6.16M | static inline fixed float2fixed_rounded_boxed(double src) { |
215 | 6.16M | float v = floor(src*fixed_scale + 0.5); |
216 | | |
217 | 6.16M | if (v <= min_fixed) |
218 | 39.3k | return min_fixed; |
219 | 6.12M | else if (v >= max_fixed) |
220 | 71.1k | return max_fixed; |
221 | 6.05M | else |
222 | 6.05M | return (fixed)v; |
223 | 6.16M | } |
224 | | |
225 | | /* Compute the image matrix combining the ImageMatrix with either the pmat or the pgs ctm */ |
226 | | int |
227 | | gx_image_compute_mat(const gs_gstate *pgs, const gs_matrix *pmat, const gs_matrix *ImageMatrix, |
228 | | gs_matrix_double *rmat) |
229 | 3.22M | { |
230 | 3.22M | int code = 0; |
231 | | |
232 | 3.22M | if (pmat == 0) |
233 | 3.15M | pmat = &ctm_only(pgs); |
234 | 3.22M | if (ImageMatrix->xx == pmat->xx && ImageMatrix->xy == pmat->xy && |
235 | 3.22M | ImageMatrix->yx == pmat->yx && ImageMatrix->yy == pmat->yy) { |
236 | | /* Process common special case separately to accept singular matrix. */ |
237 | 1.43M | rmat->xx = rmat->yy = 1.; |
238 | 1.43M | rmat->xy = rmat->yx = 0.; |
239 | 1.43M | rmat->tx = pmat->tx - ImageMatrix->tx; |
240 | 1.43M | rmat->ty = pmat->ty - ImageMatrix->ty; |
241 | 1.79M | } else { |
242 | 1.79M | if ((code = gs_matrix_invert_to_double(ImageMatrix, rmat)) < 0 || |
243 | 1.79M | (code = gs_matrix_multiply_double(rmat, pmat, rmat)) < 0 |
244 | 1.79M | ) { |
245 | 125 | return code; |
246 | 125 | } |
247 | 1.79M | } |
248 | 3.22M | return code; |
249 | 3.22M | } |
250 | | |
251 | | /* |
252 | | * Finish initialization for processing an ImageType 1 or 4 image. |
253 | | * Assumes the following members of *penum are set in addition to those |
254 | | * set by gx_image_enum_alloc: |
255 | | * alpha, use_mask_color, mask_color (if use_mask_color is true), |
256 | | * masked, adjust |
257 | | */ |
258 | | int |
259 | | gx_image_enum_begin(gx_device * dev, const gs_gstate * pgs, |
260 | | const gs_matrix *pmat, const gs_image_common_t * pic, |
261 | | const gx_drawing_color * pdcolor, const gx_clip_path * pcpath, |
262 | | gs_memory_t * mem, gx_image_enum *penum) |
263 | 2.28M | { |
264 | 2.28M | const gs_pixel_image_t *pim = (const gs_pixel_image_t *)pic; |
265 | 2.28M | gs_image_format_t format = pim->format; |
266 | 2.28M | const int width = pim->Width; |
267 | 2.28M | const int height = pim->Height; |
268 | 2.28M | const int bps = pim->BitsPerComponent; |
269 | 2.28M | bool masked = penum->masked; |
270 | 2.28M | const float *decode = pim->Decode; |
271 | 2.28M | gs_matrix_double mat; |
272 | 2.28M | int index_bps; |
273 | 2.28M | gs_color_space *pcs = pim->ColorSpace; |
274 | 2.28M | gs_logical_operation_t lop = (pgs ? pgs->log_op : lop_default); |
275 | 2.28M | int code; |
276 | 2.28M | int log2_xbytes = (bps <= 8 ? 0 : arch_log2_sizeof_frac); |
277 | 2.28M | int spp, nplanes, spread; |
278 | 2.28M | uint bsize; |
279 | 2.28M | byte *buffer = NULL; |
280 | 2.28M | fixed mtx, mty; |
281 | 2.28M | gs_fixed_point row_extent, col_extent, x_extent, y_extent; |
282 | 2.28M | bool device_color = true; |
283 | 2.28M | gs_fixed_rect obox, cbox; |
284 | 2.28M | bool gridfitimages = 0; |
285 | 2.28M | bool in_pattern_accumulator; |
286 | 2.28M | bool in_smask; |
287 | 2.28M | int orthogonal; |
288 | 2.28M | int force_interpolation = 0; |
289 | | |
290 | 2.28M | penum->pcs = NULL; |
291 | 2.28M | penum->clues = NULL; |
292 | 2.28M | penum->icc_setup.has_transfer = false; |
293 | 2.28M | penum->icc_setup.is_lab = false; |
294 | 2.28M | penum->icc_setup.must_halftone = false; |
295 | 2.28M | penum->icc_setup.need_decode = false; |
296 | 2.28M | penum->Width = width; |
297 | 2.28M | penum->Height = height; |
298 | | |
299 | 2.28M | if ((code = gx_image_compute_mat(pgs, pmat, &(pim->ImageMatrix), &mat)) < 0) { |
300 | 102 | return code; |
301 | 102 | } |
302 | 2.28M | lop = lop_sanitize(lop); |
303 | | /* Grid fit: A common construction in postscript/PDF files is for images |
304 | | * to be constructed as a series of 'stacked' 1 pixel high images. |
305 | | * Furthermore, many of these are implemented as an imagemask plotted on |
306 | | * top of thin rectangles. The different fill rules for images and line |
307 | | * art produces problems; line art fills a pixel if any part of it is |
308 | | * touched - images only fill a pixel if the centre of the pixel is |
309 | | * covered. Bug 692666 is such a problem. |
310 | | * |
311 | | * As a workaround for this problem, the code below was introduced. The |
312 | | * concept is that orthogonal images can be 'grid fitted' (or 'stretch') |
313 | | * to entirely cover pixels that they touch. Initially I had this working |
314 | | * for all images regardless of type, but as testing has proceeded, this |
315 | | * showed more and more regressions, so I've cut the cases back in which |
316 | | * this code is used until it now only triggers on imagemasks that are |
317 | | * either 1 pixel high, or wide, and then not if we are rendering a |
318 | | * glyph (such as from a type3 font). |
319 | | */ |
320 | | |
321 | | /* Ask the device if we are in a pattern accumulator */ |
322 | 2.28M | in_pattern_accumulator = (dev_proc(dev, dev_spec_op)(dev, gxdso_in_pattern_accumulator, NULL, 0)); |
323 | 2.28M | if (in_pattern_accumulator < 0) |
324 | 1.61M | in_pattern_accumulator = 0; |
325 | | |
326 | | /* Figure out if we are orthogonal */ |
327 | 2.28M | if (mat.xy == 0 && mat.yx == 0) |
328 | 2.07M | orthogonal = 1; |
329 | 208k | else if (mat.xx == 0 && mat.yy == 0) |
330 | 92.8k | orthogonal = 2; |
331 | 115k | else |
332 | 115k | orthogonal = 0; |
333 | | |
334 | | /* If we are in a pattern accumulator, we choose to always grid fit |
335 | | * orthogonal images. We do this by asking the device whether we |
336 | | * should grid fit. This allows us to avoid nasty blank lines around |
337 | | * the edges of cells. Similarly, for smasks. |
338 | | */ |
339 | 2.28M | in_smask = (pim->override_in_smask || |
340 | 2.28M | (dev_proc(dev, dev_spec_op)(dev, gxdso_in_smask, NULL, 0)) > 0); |
341 | 2.28M | gridfitimages = (in_smask || in_pattern_accumulator) && orthogonal; |
342 | | |
343 | 2.28M | if (pgs != NULL && pgs->show_gstate != NULL) { |
344 | | /* If we're a graphics state, and we're in a text object, then we |
345 | | * must be in a type3 font. Don't fiddle with it. */ |
346 | 2.00M | } else if (!gridfitimages && |
347 | 2.00M | (!penum->masked || penum->image_parent_type != 0)) { |
348 | | /* Other than for images we are specifically looking to grid fit (such as |
349 | | * ones in a pattern device), we only grid fit imagemasks */ |
350 | 1.32M | } else if (gridfitimages && (penum->masked && penum->image_parent_type == 0)) { |
351 | | /* We don't gridfit imagemasks in a pattern accumulator */ |
352 | 681k | } else if (pgs != NULL && pgs->fill_adjust.x == 0 && pgs->fill_adjust.y == 0) { |
353 | | /* If fill adjust is disabled, so is grid fitting */ |
354 | 681k | } else if (orthogonal == 1) { |
355 | 569k | if (width == 1 || gridfitimages) { |
356 | 532k | if (mat.xx > 0) { |
357 | 531k | fixed ix0 = int2fixed(fixed2int(float2fixed(mat.tx))); |
358 | 531k | double x1 = mat.tx + mat.xx * width; |
359 | 531k | fixed ix1 = int2fixed(fixed2int_ceiling(float2fixed(x1))); |
360 | 531k | mat.tx = (double)fixed2float(ix0); |
361 | 531k | mat.xx = (double)(fixed2float(ix1 - ix0)/width); |
362 | 531k | } else if (mat.xx < 0) { |
363 | 251 | fixed ix0 = int2fixed(fixed2int_ceiling(float2fixed(mat.tx))); |
364 | 251 | double x1 = mat.tx + mat.xx * width; |
365 | 251 | fixed ix1 = int2fixed(fixed2int(float2fixed(x1))); |
366 | 251 | mat.tx = (double)fixed2float(ix0); |
367 | 251 | mat.xx = (double)(fixed2float(ix1 - ix0)/width); |
368 | 251 | } |
369 | 532k | } |
370 | 569k | if (height == 1 || gridfitimages) { |
371 | 532k | if (mat.yy > 0) { |
372 | 374k | fixed iy0 = int2fixed(fixed2int(float2fixed(mat.ty))); |
373 | 374k | double y1 = mat.ty + mat.yy * height; |
374 | 374k | fixed iy1 = int2fixed(fixed2int_ceiling(float2fixed(y1))); |
375 | 374k | mat.ty = (double)fixed2float(iy0); |
376 | 374k | mat.yy = (double)(fixed2float(iy1 - iy0)/height); |
377 | 374k | } else if (mat.yy < 0) { |
378 | 157k | fixed iy0 = int2fixed(fixed2int_ceiling(float2fixed(mat.ty))); |
379 | 157k | double y1 = mat.ty + mat.yy * height; |
380 | 157k | fixed iy1 = int2fixed(fixed2int(float2fixed(y1))); |
381 | 157k | mat.ty = (double)fixed2float(iy0); |
382 | 157k | mat.yy = ((double)fixed2float(iy1 - iy0)/height); |
383 | 157k | } |
384 | 532k | } |
385 | 569k | } else if (orthogonal == 2) { |
386 | 91.0k | if (height == 1 || gridfitimages) { |
387 | 0 | if (mat.yx > 0) { |
388 | 0 | fixed ix0 = int2fixed(fixed2int(float2fixed(mat.tx))); |
389 | 0 | double x1 = mat.tx + mat.yx * height; |
390 | 0 | fixed ix1 = int2fixed(fixed2int_ceiling(float2fixed(x1))); |
391 | 0 | mat.tx = (double)fixed2float(ix0); |
392 | 0 | mat.yx = (double)(fixed2float(ix1 - ix0)/height); |
393 | 0 | } else if (mat.yx < 0) { |
394 | 0 | fixed ix0 = int2fixed(fixed2int_ceiling(float2fixed(mat.tx))); |
395 | 0 | double x1 = mat.tx + mat.yx * height; |
396 | 0 | fixed ix1 = int2fixed(fixed2int(float2fixed(x1))); |
397 | 0 | mat.tx = (double)fixed2float(ix0); |
398 | 0 | mat.yx = (double)(fixed2float(ix1 - ix0)/height); |
399 | 0 | } |
400 | 0 | } |
401 | 91.0k | if (width == 1 || gridfitimages) { |
402 | 0 | if (mat.xy > 0) { |
403 | 0 | fixed iy0 = int2fixed(fixed2int(float2fixed(mat.ty))); |
404 | 0 | double y1 = mat.ty + mat.xy * width; |
405 | 0 | fixed iy1 = int2fixed(fixed2int_ceiling(float2fixed(y1))); |
406 | 0 | mat.ty = (double)fixed2float(iy0); |
407 | 0 | mat.xy = (double)(fixed2float(iy1 - iy0)/width); |
408 | 0 | } else if (mat.xy < 0) { |
409 | 0 | fixed iy0 = int2fixed(fixed2int_ceiling(float2fixed(mat.ty))); |
410 | 0 | double y1 = mat.ty + mat.xy * width; |
411 | 0 | fixed iy1 = int2fixed(fixed2int(float2fixed(y1))); |
412 | 0 | mat.ty = (double)fixed2float(iy0); |
413 | 0 | mat.xy = ((double)fixed2float(iy1 - iy0)/width); |
414 | 0 | } |
415 | 0 | } |
416 | 91.0k | } |
417 | | |
418 | | /* When rendering to a pattern accumulator, if we are downscaling |
419 | | * then enable interpolation, as otherwise dropouts can cause |
420 | | * serious problems. */ |
421 | 2.28M | if (in_pattern_accumulator) { |
422 | 479 | double ome = ((double)(fixed_1 - fixed_epsilon)) / (double)fixed_1; /* One Minus Epsilon */ |
423 | | |
424 | 479 | if (orthogonal == 1) { |
425 | 469 | if ((mat.xx > -ome && mat.xx < ome) || (mat.yy > -ome && mat.yy < ome)) { |
426 | 317 | force_interpolation = true; |
427 | 317 | } |
428 | 469 | } else if (orthogonal == 2) { |
429 | 0 | if ((mat.xy > -ome && mat.xy < ome) || (mat.yx > -ome && mat.yx < ome)) { |
430 | 0 | force_interpolation = true; |
431 | 0 | } |
432 | 0 | } |
433 | 479 | } |
434 | | |
435 | | /* Can we restrict the amount of image we need? */ |
436 | 2.28M | while (!pim->imagematrices_are_untrustworthy) /* So we can break out of it */ |
437 | 2.28M | { |
438 | 2.28M | gs_rect rect, rect_src; |
439 | 2.28M | gs_matrix mi; |
440 | 2.28M | const gs_matrix *m = pgs != NULL ? &ctm_only(pgs) : NULL; |
441 | 2.28M | gs_int_rect irect; |
442 | 2.28M | if (m == NULL || (code = gs_matrix_invert(m, &mi)) < 0 || |
443 | 2.28M | (code = gs_matrix_multiply(&mi, &pic->ImageMatrix, &mi)) < 0) { |
444 | | /* Give up trying to shrink the render box, but continue processing */ |
445 | 4.17k | break; |
446 | 4.17k | } |
447 | 2.27M | if (pcpath) |
448 | 730k | { |
449 | 730k | gs_fixed_rect obox; |
450 | 730k | gx_cpath_outer_box(pcpath, &obox); |
451 | 730k | rect.p.x = fixed2float(obox.p.x); |
452 | 730k | rect.p.y = fixed2float(obox.p.y); |
453 | 730k | rect.q.x = fixed2float(obox.q.x); |
454 | 730k | rect.q.y = fixed2float(obox.q.y); |
455 | 730k | } |
456 | 1.54M | else |
457 | 1.54M | { |
458 | 1.54M | rect.p.x = 0; |
459 | 1.54M | rect.p.y = 0; |
460 | 1.54M | rect.q.x = dev->width; |
461 | 1.54M | rect.q.y = dev->height; |
462 | 1.54M | } |
463 | | /* rect is in destination space. Calculate rect_src, in source space. */ |
464 | 2.27M | code = gs_bbox_transform(&rect, &mi, &rect_src); |
465 | 2.27M | if (code < 0) { |
466 | | /* Give up trying to shrink the render/decode boxes, but continue processing */ |
467 | 0 | break; |
468 | 0 | } |
469 | | /* Need to expand the region to allow for the fact that the mitchell |
470 | | * scaler reads multiple pixels in. */ |
471 | | /* If mi.{xx,yy} > 1 then we are downscaling. During downscaling, |
472 | | * the support increases to ensure that we don't lose pixels contributions |
473 | | * entirely. */ |
474 | 2.27M | if (pim->Interpolate) |
475 | 37 | { |
476 | 37 | float support = any_abs(mi.xx); |
477 | 37 | int isupport; |
478 | 37 | if (any_abs(mi.yy) > support) |
479 | 0 | support = any_abs(mi.yy); |
480 | 37 | if (any_abs(mi.xy) > support) |
481 | 1 | support = any_abs(mi.xy); |
482 | 37 | if (any_abs(mi.yx) > support) |
483 | 0 | support = any_abs(mi.yx); |
484 | | /* If upscaling (support < 1) then we need 2 extra lines on each side of the source region |
485 | | * (2 being the maximum support for mitchell scaling). |
486 | | * If downscaling, then the number of lines is increased to avoid individual |
487 | | * contributions dropping out. */ |
488 | 37 | isupport = 2; /* Mitchell support. */ |
489 | 37 | if (support > 1) |
490 | 1 | isupport = (int)ceil(isupport * support); |
491 | 37 | rect_src.p.x -= isupport; |
492 | 37 | rect_src.p.y -= isupport; |
493 | 37 | rect_src.q.x += isupport; |
494 | 37 | rect_src.q.y += isupport+1; /* +1 is a fudge! */ |
495 | 37 | } |
496 | 2.27M | irect.p.x = (int)floor(rect_src.p.x); |
497 | 2.27M | irect.p.y = (int)floor(rect_src.p.y); |
498 | 2.27M | irect.q.x = (int)ceil(rect_src.q.x); |
499 | 2.27M | irect.q.y = (int)ceil(rect_src.q.y); |
500 | | /* We therefore only need to render within irect. Restrict rrect to this. */ |
501 | 2.27M | if (penum->rrect.x < irect.p.x) { |
502 | 90.0k | penum->rrect.w -= irect.p.x - penum->rrect.x; |
503 | 90.0k | if (penum->rrect.w < 0) |
504 | 80.0k | penum->rrect.w = 0; |
505 | 90.0k | penum->rrect.x = irect.p.x; |
506 | 90.0k | } |
507 | 2.27M | if (penum->rrect.x + penum->rrect.w > irect.q.x) { |
508 | 206k | penum->rrect.w = irect.q.x - penum->rrect.x; |
509 | 206k | if (penum->rrect.w < 0) |
510 | 178k | penum->rrect.w = 0; |
511 | 206k | } |
512 | 2.27M | if (penum->rrect.y < irect.p.y) { |
513 | 256k | penum->rrect.h -= irect.p.y - penum->rrect.y; |
514 | 256k | if (penum->rrect.h < 0) |
515 | 89.9k | penum->rrect.h = 0; |
516 | 256k | penum->rrect.y = irect.p.y; |
517 | 256k | } |
518 | 2.27M | if (penum->rrect.y + penum->rrect.h > irect.q.y) { |
519 | 209k | penum->rrect.h = irect.q.y - penum->rrect.y; |
520 | 209k | if (penum->rrect.h < 0) |
521 | 37.9k | penum->rrect.h = 0; |
522 | 209k | } |
523 | 2.27M | if (penum->drect.x < irect.p.x) { |
524 | 90.0k | penum->drect.w -= irect.p.x - penum->drect.x; |
525 | 90.0k | if (penum->drect.w < 0) |
526 | 80.0k | penum->drect.w = 0; |
527 | 90.0k | penum->drect.x = irect.p.x; |
528 | 90.0k | } |
529 | 2.27M | if (penum->drect.x + penum->drect.w > irect.q.x) { |
530 | 206k | penum->drect.w = irect.q.x - penum->drect.x; |
531 | 206k | if (penum->drect.w < 0) |
532 | 178k | penum->drect.w = 0; |
533 | 206k | } |
534 | 2.27M | if (penum->drect.y < irect.p.y) { |
535 | 256k | penum->drect.h -= irect.p.y - penum->drect.y; |
536 | 256k | if (penum->drect.h < 0) |
537 | 89.9k | penum->drect.h = 0; |
538 | 256k | penum->drect.y = irect.p.y; |
539 | 256k | } |
540 | 2.27M | if (penum->drect.y + penum->drect.h > irect.q.y) { |
541 | 209k | penum->drect.h = irect.q.y - penum->drect.y; |
542 | 209k | if (penum->drect.h < 0) |
543 | 37.9k | penum->drect.h = 0; |
544 | 209k | } |
545 | 2.27M | break; /* Out of the while */ |
546 | 2.27M | } |
547 | | /* Check for the intersection being null */ |
548 | 2.28M | if (penum->drect.x + penum->drect.w <= penum->rect.x || |
549 | 2.28M | penum->rect.x + penum->rect.w <= penum->drect.x || |
550 | 2.28M | penum->drect.y + penum->drect.h <= penum->rect.y || |
551 | 2.28M | penum->rect.y + penum->rect.h <= penum->drect.y) |
552 | 283k | { |
553 | | /* Something may have gone wrong with the floating point above. |
554 | | * set the region to something sane. */ |
555 | 283k | penum->drect.x = penum->rect.x; |
556 | 283k | penum->drect.y = penum->rect.y; |
557 | 283k | penum->drect.w = 0; |
558 | 283k | penum->drect.h = 0; |
559 | 283k | } |
560 | 2.28M | if (penum->rrect.x + penum->rrect.w <= penum->drect.x || |
561 | 2.28M | penum->drect.x + penum->drect.w <= penum->rrect.x || |
562 | 2.28M | penum->rrect.y + penum->rrect.h <= penum->drect.y || |
563 | 2.28M | penum->drect.y + penum->drect.h <= penum->rrect.y) |
564 | 283k | { |
565 | | /* Something may have gone wrong with the floating point above. |
566 | | * set the region to something sane. */ |
567 | 283k | penum->rrect.x = penum->drect.x; |
568 | 283k | penum->rrect.y = penum->drect.y; |
569 | 283k | penum->rrect.w = 0; |
570 | 283k | penum->rrect.h = 0; |
571 | 283k | } |
572 | | |
573 | | /*penum->matrix = mat;*/ |
574 | 2.28M | penum->matrix.xx = mat.xx; |
575 | 2.28M | penum->matrix.xy = mat.xy; |
576 | 2.28M | penum->matrix.yx = mat.yx; |
577 | 2.28M | penum->matrix.yy = mat.yy; |
578 | 2.28M | penum->matrix.tx = mat.tx; |
579 | 2.28M | penum->matrix.ty = mat.ty; |
580 | 2.28M | if_debug6m('b', mem, " [%g %g %g %g %g %g]\n", |
581 | 2.28M | mat.xx, mat.xy, mat.yx, mat.yy, mat.tx, mat.ty); |
582 | | /* following works for 1, 2, 4, 8, 12, 16 */ |
583 | 2.28M | index_bps = (bps < 8 ? bps >> 1 : (bps >> 2) + 1); |
584 | | /* |
585 | | * Compute extents with distance transformation. |
586 | | */ |
587 | 2.28M | if (mat.tx > 0) |
588 | 1.83M | mtx = float2fixed(mat.tx); |
589 | 446k | else { /* Use positive values to ensure round down. */ |
590 | 446k | int f = (int)-mat.tx + 1; |
591 | | |
592 | 446k | mtx = float2fixed(mat.tx + f) - int2fixed(f); |
593 | 446k | } |
594 | 2.28M | if (mat.ty > 0) |
595 | 656k | mty = float2fixed(mat.ty); |
596 | 1.62M | else { /* Use positive values to ensure round down. */ |
597 | 1.62M | int f = (int)-mat.ty + 1; |
598 | | |
599 | 1.62M | mty = float2fixed(mat.ty + f) - int2fixed(f); |
600 | 1.62M | } |
601 | | |
602 | 2.28M | row_extent.x = float2fixed_rounded_boxed(width * mat.xx); |
603 | 2.28M | row_extent.y = |
604 | 2.28M | (is_fzero(mat.xy) ? fixed_0 : |
605 | 2.28M | float2fixed_rounded_boxed(width * mat.xy)); |
606 | 2.28M | col_extent.x = |
607 | 2.28M | (is_fzero(mat.yx) ? fixed_0 : |
608 | 2.28M | float2fixed_rounded_boxed(height * mat.yx)); |
609 | 2.28M | col_extent.y = float2fixed_rounded_boxed(height * mat.yy); |
610 | 2.28M | gx_image_enum_common_init((gx_image_enum_common_t *)penum, |
611 | 2.28M | (const gs_data_image_t *)pim, |
612 | 2.28M | &image1_enum_procs, dev, |
613 | 2.28M | (masked ? 1 : (penum->alpha ? cs_num_components(pcs)+1 : cs_num_components(pcs))), |
614 | 2.28M | format); |
615 | 2.28M | if (penum->rect.w == width && penum->rect.h == height) { |
616 | 1.64M | x_extent = row_extent; |
617 | 1.64M | y_extent = col_extent; |
618 | 1.64M | } else { |
619 | 636k | int rw = penum->rect.w, rh = penum->rect.h; |
620 | | |
621 | 636k | x_extent.x = float2fixed_rounded_boxed(rw * mat.xx); |
622 | 636k | x_extent.y = |
623 | 636k | (is_fzero(mat.xy) ? fixed_0 : |
624 | 636k | float2fixed_rounded_boxed(rw * mat.xy)); |
625 | 636k | y_extent.x = |
626 | 636k | (is_fzero(mat.yx) ? fixed_0 : |
627 | 636k | float2fixed_rounded_boxed(rh * mat.yx)); |
628 | 636k | y_extent.y = float2fixed_rounded_boxed(rh * mat.yy); |
629 | 636k | } |
630 | | /* Set icolor0 and icolor1 to point to image clues locations if we have |
631 | | 1spp or an imagemask, otherwise image clues is not used and |
632 | | we have these values point to other member variables */ |
633 | 2.28M | if (masked || cs_num_components(pcs) == 1) { |
634 | | /* Go ahead and allocate now if not already done. For a mask |
635 | | we really should only do 2 values. For now, the goal is to |
636 | | eliminate the 256 bytes for the >8bpp image enumerator */ |
637 | 992k | penum->clues = (gx_image_clue*) gs_alloc_bytes(mem, sizeof(gx_image_clue)*256, |
638 | 992k | "gx_image_enum_begin"); |
639 | 992k | if (penum->clues == NULL) { |
640 | 0 | code = gs_error_VMerror; |
641 | 0 | goto fail; |
642 | 0 | } |
643 | 992k | penum->icolor0 = &(penum->clues[0].dev_color); |
644 | 992k | penum->icolor1 = &(penum->clues[255].dev_color); |
645 | 1.28M | } else { |
646 | 1.28M | penum->icolor0 = &(penum->icolor0_val); |
647 | 1.28M | penum->icolor1 = &(penum->icolor1_val); |
648 | 1.28M | } |
649 | 2.28M | penum->icolor0->tag = penum->icolor1->tag = device_current_tag(dev); |
650 | | |
651 | 2.28M | if (masked) { /* This is imagemask. */ |
652 | 429k | if (bps != 1 || pcs != NULL || penum->alpha || decode[0] == decode[1]) { |
653 | 54 | code = gs_error_rangecheck; |
654 | 54 | goto fail; |
655 | 54 | } |
656 | | /* Initialize color entries 0 and 255. */ |
657 | 429k | set_nonclient_dev_color(penum->icolor0, gx_no_color_index); |
658 | 429k | set_nonclient_dev_color(penum->icolor1, gx_no_color_index); |
659 | 429k | *(penum->icolor1) = *pdcolor; |
660 | 429k | memcpy(&penum->map[0].table.lookup4x1to32[0], |
661 | 429k | (decode[0] < decode[1] ? lookup4x1to32_inverted : |
662 | 429k | lookup4x1to32_identity), |
663 | 429k | 16 * 4); |
664 | 429k | penum->map[0].decoding = sd_none; |
665 | 429k | spp = 1; |
666 | 429k | lop = rop3_know_S_0(lop); |
667 | 1.85M | } else { /* This is image, not imagemask. */ |
668 | 1.85M | const gs_color_space_type *pcst = pcs->type; |
669 | 1.85M | int b_w_color; |
670 | | |
671 | 1.85M | spp = cs_num_components(pcs); |
672 | 1.85M | if (spp < 0) { /* Pattern not allowed */ |
673 | 0 | code = gs_error_rangecheck; |
674 | 0 | goto fail; |
675 | 0 | } |
676 | 1.85M | if (penum->alpha) |
677 | 0 | ++spp; |
678 | | /* Use a less expensive format if possible. */ |
679 | 1.85M | switch (format) { |
680 | 0 | case gs_image_format_bit_planar: |
681 | 0 | if (bps > 1) |
682 | 0 | break; |
683 | 0 | format = gs_image_format_component_planar; |
684 | 46.5k | case gs_image_format_component_planar: |
685 | 46.5k | if (spp == 1) |
686 | 0 | format = gs_image_format_chunky; |
687 | 1.85M | default: /* chunky */ |
688 | 1.85M | break; |
689 | 1.85M | } |
690 | | |
691 | 1.85M | if (pcs->cmm_icc_profile_data != NULL) { |
692 | 1.82M | device_color = false; |
693 | 1.82M | } else { |
694 | 23.8k | device_color = (*pcst->concrete_space) (pcs, pgs) == pcs; |
695 | 23.8k | } |
696 | | |
697 | 1.85M | code = image_init_colors(penum, bps, spp, format, decode, pgs, dev, |
698 | 1.85M | pcs, &device_color); |
699 | 1.85M | if (code < 0) { |
700 | 5 | gs_free_object(mem, penum->clues, "gx_image_enum_begin"); |
701 | 5 | gs_free_object(mem, penum, "gx_default_begin_image"); |
702 | 5 | return gs_throw(code, "Image colors initialization failed"); |
703 | 5 | } |
704 | | /* If we have a CIE based color space and the icc equivalent profile |
705 | | is not yet set, go ahead and handle that now. It may already |
706 | | be done due to the above init_colors which may go through remap. */ |
707 | 1.85M | if (gs_color_space_is_PSCIE(pcs) && pcs->icc_equivalent == NULL) { |
708 | 0 | code = gs_colorspace_set_icc_equivalent((gs_color_space *)pcs, &(penum->icc_setup.is_lab), |
709 | 0 | pgs->memory); |
710 | 0 | if (code < 0) |
711 | 0 | goto fail; |
712 | 0 | if (penum->icc_setup.is_lab) { |
713 | | /* Free what ever profile was created and use the icc manager's |
714 | | cielab profile */ |
715 | 0 | gs_color_space *curr_pcs = (gs_color_space *)pcs; |
716 | 0 | rc_decrement(curr_pcs->icc_equivalent,"gx_image_enum_begin"); |
717 | 0 | gsicc_adjust_profile_rc(curr_pcs->cmm_icc_profile_data, -1,"gx_image_enum_begin"); |
718 | 0 | curr_pcs->cmm_icc_profile_data = pgs->icc_manager->lab_profile; |
719 | 0 | gsicc_adjust_profile_rc(curr_pcs->cmm_icc_profile_data, 1,"gx_image_enum_begin"); |
720 | 0 | } |
721 | 0 | } |
722 | | /* Try to transform non-default RasterOps to something */ |
723 | | /* that we implement less expensively. */ |
724 | 1.85M | if (!pim->CombineWithColor) |
725 | 1.85M | lop = rop3_know_T_0(lop); |
726 | 0 | else if ((rop3_uses_T(lop) && color_draws_b_w(dev, pdcolor) == 0)) |
727 | 0 | lop = rop3_know_T_0(lop); |
728 | | |
729 | 1.85M | if (lop != rop3_S && /* if best case, no more work needed */ |
730 | 1.85M | !rop3_uses_T(lop) && bps == 1 && spp == 1 && |
731 | 1.85M | (b_w_color = |
732 | 0 | color_draws_b_w(dev, penum->icolor0)) >= 0 && |
733 | 1.85M | color_draws_b_w(dev, penum->icolor1) == (b_w_color ^ 1) |
734 | 1.85M | ) { |
735 | 0 | if (b_w_color) { /* Swap the colors and invert the RasterOp source. */ |
736 | 0 | gx_device_color dcolor; |
737 | |
|
738 | 0 | dcolor = *(penum->icolor0); |
739 | 0 | *(penum->icolor0) = *(penum->icolor1); |
740 | 0 | *(penum->icolor1) = dcolor; |
741 | 0 | lop = rop3_invert_S(lop); |
742 | 0 | } |
743 | | /* |
744 | | * At this point, we know that the source pixels |
745 | | * correspond directly to the S input for the raster op, |
746 | | * i.e., icolor0 is black and icolor1 is white. |
747 | | */ |
748 | 0 | switch (lop) { |
749 | 0 | case rop3_D & rop3_S: |
750 | | /* Implement this as an inverted mask writing 0s. */ |
751 | 0 | *(penum->icolor1) = *(penum->icolor0); |
752 | | /* (falls through) */ |
753 | 0 | case rop3_D | rop3_not(rop3_S): |
754 | | /* Implement this as an inverted mask writing 1s. */ |
755 | 0 | memcpy(&penum->map[0].table.lookup4x1to32[0], |
756 | 0 | lookup4x1to32_inverted, 16 * 4); |
757 | 0 | rmask: /* Fill in the remaining parameters for a mask. */ |
758 | 0 | penum->masked = masked = true; |
759 | 0 | set_nonclient_dev_color(penum->icolor0, gx_no_color_index); |
760 | 0 | penum->map[0].decoding = sd_none; |
761 | 0 | lop = rop3_T; |
762 | 0 | break; |
763 | 0 | case rop3_D & rop3_not(rop3_S): |
764 | | /* Implement this as a mask writing 0s. */ |
765 | 0 | *(penum->icolor1) = *(penum->icolor0); |
766 | | /* (falls through) */ |
767 | 0 | case rop3_D | rop3_S: |
768 | | /* Implement this as a mask writing 1s. */ |
769 | 0 | memcpy(&penum->map[0].table.lookup4x1to32[0], |
770 | 0 | lookup4x1to32_identity, 16 * 4); |
771 | 0 | goto rmask; |
772 | 0 | default: |
773 | 0 | ; |
774 | 0 | } |
775 | 0 | } |
776 | 1.85M | } |
777 | 2.28M | penum->device_color = device_color; |
778 | | /* |
779 | | * Adjust width upward for unpacking up to 7 trailing bits in |
780 | | * the row, plus 1 byte for end-of-run, plus up to 7 leading |
781 | | * bits for data_x offset within a packed byte. |
782 | | */ |
783 | 2.28M | bsize = ((bps > 8 ? width * 2 : width) + 15) * spp; |
784 | 2.28M | buffer = gs_alloc_bytes(mem, bsize, "image buffer"); |
785 | 2.28M | if (buffer == 0) { |
786 | 5 | code = gs_error_VMerror; |
787 | 5 | goto fail; |
788 | 5 | } |
789 | 2.28M | penum->bps = bps; |
790 | 2.28M | penum->unpack_bps = bps; |
791 | 2.28M | penum->log2_xbytes = log2_xbytes; |
792 | 2.28M | penum->spp = spp; |
793 | 2.28M | switch (format) { |
794 | 2.23M | case gs_image_format_chunky: |
795 | 2.23M | nplanes = 1; |
796 | 2.23M | spread = 1 << log2_xbytes; |
797 | 2.23M | break; |
798 | 46.5k | case gs_image_format_component_planar: |
799 | 46.5k | nplanes = spp; |
800 | 46.5k | spread = spp << log2_xbytes; |
801 | 46.5k | break; |
802 | 0 | case gs_image_format_bit_planar: |
803 | 0 | nplanes = spp * bps; |
804 | 0 | spread = spp << log2_xbytes; |
805 | 0 | break; |
806 | 0 | default: |
807 | | /* No other cases are possible (checked by gx_image_enum_alloc). */ |
808 | 0 | return_error(gs_error_Fatal); |
809 | 2.28M | } |
810 | 2.28M | penum->num_planes = nplanes; |
811 | 2.28M | penum->spread = spread; |
812 | | /* |
813 | | * If we're asked to interpolate in a partial image, we have to |
814 | | * assume that the client either really only is interested in |
815 | | * the given sub-image, or else is constructing output out of |
816 | | * overlapping pieces. |
817 | | */ |
818 | 2.28M | penum->interpolate = force_interpolation ? interp_force : pim->Interpolate ? interp_on : interp_off; |
819 | 2.28M | penum->x_extent = x_extent; |
820 | 2.28M | penum->y_extent = y_extent; |
821 | 2.28M | penum->posture = |
822 | 2.28M | ((x_extent.y | y_extent.x) == 0 ? image_portrait : |
823 | 2.28M | (x_extent.x | y_extent.y) == 0 ? image_landscape : |
824 | 208k | image_skewed); |
825 | 2.28M | penum->pgs = pgs; |
826 | 2.28M | if (pgs != NULL) |
827 | 2.28M | penum->pgs_level = pgs->level; |
828 | 2.28M | penum->pcs = pcs; |
829 | 2.28M | rc_increment_cs(pcs); /* Grab a ref (will decrement in gx_image1_end_image() */ |
830 | 2.28M | penum->memory = mem; |
831 | 2.28M | penum->buffer = buffer; |
832 | 2.28M | penum->buffer_size = bsize; |
833 | 2.28M | penum->line = NULL; |
834 | 2.28M | penum->icc_link = NULL; |
835 | 2.28M | penum->color_cache = NULL; |
836 | 2.28M | penum->ht_buffer = NULL; |
837 | 2.28M | penum->thresh_buffer = NULL; |
838 | 2.28M | penum->use_cie_range = false; |
839 | 2.28M | penum->line_size = 0; |
840 | 2.28M | penum->use_rop = lop != (masked ? rop3_T : rop3_S); |
841 | | #ifdef DEBUG |
842 | | if (gs_debug_c('*')) { |
843 | | if (penum->use_rop) |
844 | | dmprintf1(mem, "[%03x]", lop); |
845 | | dmprintf5(mem, "%c%d%c%dx%d ", |
846 | | (masked ? (color_is_pure(pdcolor) ? 'm' : 'h') : 'i'), |
847 | | bps, |
848 | | (penum->posture == image_portrait ? ' ' : |
849 | | penum->posture == image_landscape ? 'L' : 'T'), |
850 | | width, height); |
851 | | } |
852 | | #endif |
853 | 2.28M | penum->slow_loop = 0; |
854 | 2.28M | if (pcpath == 0) { |
855 | 1.54M | (*dev_proc(dev, get_clipping_box)) (dev, &obox); |
856 | 1.54M | cbox = obox; |
857 | 1.54M | penum->clip_image = 0; |
858 | 1.54M | } else |
859 | 734k | penum->clip_image = |
860 | 734k | (gx_cpath_outer_box(pcpath, &obox) | /* not || */ |
861 | 734k | gx_cpath_inner_box(pcpath, &cbox) ? |
862 | 732k | 0 : image_clip_region); |
863 | 2.28M | penum->clip_outer = obox; |
864 | 2.28M | penum->clip_inner = cbox; |
865 | 2.28M | penum->log_op = rop3_T; /* rop device takes care of this */ |
866 | 2.28M | penum->clip_dev = 0; /* in case we bail out */ |
867 | 2.28M | penum->rop_dev = 0; /* ditto */ |
868 | 2.28M | penum->scaler = 0; /* ditto */ |
869 | | /* |
870 | | * If all four extrema of the image fall within the clipping |
871 | | * rectangle, clipping is never required. When making this check, |
872 | | * we must carefully take into account the fact that we only care |
873 | | * about pixel centers. |
874 | | */ |
875 | 2.28M | { |
876 | 2.28M | fixed |
877 | 2.28M | epx = min(row_extent.x, 0) + min(col_extent.x, 0), |
878 | 2.28M | eqx = max(row_extent.x, 0) + max(col_extent.x, 0), |
879 | 2.28M | epy = min(row_extent.y, 0) + min(col_extent.y, 0), |
880 | 2.28M | eqy = max(row_extent.y, 0) + max(col_extent.y, 0); |
881 | | |
882 | 2.28M | { |
883 | 2.28M | int hwx, hwy; |
884 | | |
885 | 2.28M | switch (penum->posture) { |
886 | 2.07M | case image_portrait: |
887 | 2.07M | hwx = width, hwy = height; |
888 | 2.07M | break; |
889 | 92.8k | case image_landscape: |
890 | 92.8k | hwx = height, hwy = width; |
891 | 92.8k | break; |
892 | 115k | default: |
893 | 115k | hwx = hwy = 0; |
894 | 2.28M | } |
895 | | /* |
896 | | * If the image is only 1 sample wide or high, |
897 | | * and is less than 1 device pixel wide or high, |
898 | | * move it slightly so that it covers pixel centers. |
899 | | * This is a hack to work around a bug in some old |
900 | | * versions of TeX/dvips, which use 1-bit-high images |
901 | | * to draw horizontal and vertical lines without |
902 | | * positioning them properly. |
903 | | */ |
904 | 2.28M | if (hwx == 1 && eqx - epx < fixed_1) { |
905 | 22 | fixed diff = |
906 | 22 | arith_rshift_1(row_extent.x + col_extent.x); |
907 | | |
908 | 22 | mtx = (((mtx + diff) | fixed_half) & -fixed_half) - diff; |
909 | 22 | } |
910 | 2.28M | if (hwy == 1 && eqy - epy < fixed_1) { |
911 | 17 | fixed diff = |
912 | 17 | arith_rshift_1(row_extent.y + col_extent.y); |
913 | | |
914 | 17 | mty = (((mty + diff) | fixed_half) & -fixed_half) - diff; |
915 | 17 | } |
916 | 2.28M | } |
917 | 2.28M | if_debug5m('b', mem, "[b]Image: %sspp=%d, bps=%d, mt=(%g,%g)\n", |
918 | 2.28M | (masked? "masked, " : ""), spp, bps, |
919 | 2.28M | fixed2float(mtx), fixed2float(mty)); |
920 | 2.28M | if_debug9m('b', mem, |
921 | 2.28M | "[b] cbox=(%g,%g),(%g,%g), obox=(%g,%g),(%g,%g), clip_image=0x%x\n", |
922 | 2.28M | fixed2float(cbox.p.x), fixed2float(cbox.p.y), |
923 | 2.28M | fixed2float(cbox.q.x), fixed2float(cbox.q.y), |
924 | 2.28M | fixed2float(obox.p.x), fixed2float(obox.p.y), |
925 | 2.28M | fixed2float(obox.q.x), fixed2float(obox.q.y), |
926 | 2.28M | penum->clip_image); |
927 | | /* These DDAs enumerate the starting position of each source pixel |
928 | | * row in device space. */ |
929 | 2.28M | dda_init(penum->dda.row.x, mtx, col_extent.x, height); |
930 | 2.28M | dda_init(penum->dda.row.y, mty, col_extent.y, height); |
931 | 2.28M | if (dda_will_overflow(penum->dda.row.x) || |
932 | 2.28M | dda_will_overflow(penum->dda.row.y)) |
933 | 0 | { |
934 | 0 | code = gs_error_rangecheck; |
935 | 0 | goto fail; |
936 | 0 | } |
937 | 2.28M | if (penum->posture == image_portrait) { |
938 | 2.07M | penum->dst_width = row_extent.x; |
939 | 2.07M | penum->dst_height = col_extent.y; |
940 | 2.07M | } else { |
941 | 208k | penum->dst_width = col_extent.x; |
942 | 208k | penum->dst_height = row_extent.y; |
943 | 208k | } |
944 | | /* For gs_image_class_0_interpolate. */ |
945 | 2.28M | penum->yi0 = fixed2int_pixround_perfect(dda_current(penum->dda.row.y)); /* For gs_image_class_0_interpolate. */ |
946 | 2.28M | if (penum->rect.y) { |
947 | 574k | int y = penum->rect.y; |
948 | | |
949 | 78.6M | while (y--) { |
950 | 78.1M | dda_next(penum->dda.row.x); |
951 | 78.1M | dda_next(penum->dda.row.y); |
952 | 78.1M | } |
953 | 574k | } |
954 | 2.28M | penum->cur.x = penum->prev.x = dda_current(penum->dda.row.x); |
955 | 2.28M | penum->cur.y = penum->prev.y = dda_current(penum->dda.row.y); |
956 | | /* These DDAs enumerate the starting positions of each row of our |
957 | | * source pixel data, in the subrectangle ('strip') that we are |
958 | | * actually rendering. */ |
959 | 2.28M | dda_init(penum->dda.strip.x, penum->cur.x, row_extent.x, width); |
960 | 2.28M | dda_init(penum->dda.strip.y, penum->cur.y, row_extent.y, width); |
961 | 2.28M | if (dda_will_overflow(penum->dda.strip.x) || |
962 | 2.28M | dda_will_overflow(penum->dda.strip.y)) |
963 | 0 | { |
964 | 0 | code = gs_error_rangecheck; |
965 | 0 | goto fail; |
966 | 0 | } |
967 | 2.28M | if (penum->rect.x) { |
968 | 8.24k | dda_advance(penum->dda.strip.x, penum->rect.x); |
969 | 8.24k | dda_advance(penum->dda.strip.y, penum->rect.x); |
970 | 8.24k | } |
971 | 2.28M | { |
972 | 2.28M | fixed ox = dda_current(penum->dda.strip.x); |
973 | 2.28M | fixed oy = dda_current(penum->dda.strip.y); |
974 | | |
975 | 2.28M | if (!penum->clip_image) /* i.e., not clip region */ |
976 | 2.27M | penum->clip_image = |
977 | 2.27M | (fixed_pixround(ox + epx) < fixed_pixround(cbox.p.x) ? |
978 | 2.17M | image_clip_xmin : 0) + |
979 | 2.27M | (fixed_pixround(ox + eqx) >= fixed_pixround(cbox.q.x) ? |
980 | 1.62M | image_clip_xmax : 0) + |
981 | 2.27M | (fixed_pixround(oy + epy) < fixed_pixround(cbox.p.y) ? |
982 | 1.65M | image_clip_ymin : 0) + |
983 | 2.27M | (fixed_pixround(oy + eqy) >= fixed_pixround(cbox.q.y) ? |
984 | 1.84M | image_clip_ymax : 0); |
985 | 2.28M | } |
986 | 2.28M | } |
987 | 0 | penum->y = 0; |
988 | 2.28M | penum->used.x = 0; |
989 | 2.28M | penum->used.y = 0; |
990 | 2.28M | if (penum->clip_image && pcpath) { /* Set up the clipping device. */ |
991 | 583k | gx_device_clip *cdev = |
992 | 583k | gs_alloc_struct(mem, gx_device_clip, |
993 | 583k | &st_device_clip, "image clipper"); |
994 | | |
995 | 583k | if (cdev == NULL) { |
996 | 0 | code = gs_error_VMerror; |
997 | 0 | goto fail; |
998 | 0 | } |
999 | 583k | gx_make_clip_device_in_heap(cdev, pcpath, dev, mem); |
1000 | 583k | penum->clip_dev = cdev; |
1001 | 583k | penum->dev = (gx_device *)cdev; /* Will restore this in a mo. Hacky! */ |
1002 | 583k | } |
1003 | 2.28M | if (penum->use_rop) { /* Set up the RasterOp source device. */ |
1004 | 0 | gx_device_rop_texture *rtdev; |
1005 | |
|
1006 | 0 | code = gx_alloc_rop_texture_device(&rtdev, mem, |
1007 | 0 | "image RasterOp"); |
1008 | 0 | if (code < 0) |
1009 | 0 | goto fail; |
1010 | | /* The 'target' must not be NULL for gx_make_rop_texture_device */ |
1011 | 0 | if (!penum->clip_dev && !dev) |
1012 | 0 | return_error(gs_error_undefined); |
1013 | | |
1014 | 0 | gx_make_rop_texture_device(rtdev, |
1015 | 0 | (penum->clip_dev != 0 ? |
1016 | 0 | (gx_device *) penum->clip_dev : |
1017 | 0 | dev), lop, pdcolor); |
1018 | 0 | gx_device_retain((gx_device *)rtdev, true); |
1019 | 0 | penum->rop_dev = rtdev; |
1020 | 0 | penum->dev = (gx_device *)rtdev; /* Will restore this in a mo. Hacky! */ |
1021 | 0 | } |
1022 | 2.28M | { |
1023 | 2.28M | static sample_unpack_proc_t procs[2][6] = { |
1024 | 2.28M | { sample_unpack_1, sample_unpack_2, |
1025 | 2.28M | sample_unpack_4, sample_unpack_8, |
1026 | 2.28M | sample_unpack_12, sample_unpack_16 |
1027 | 2.28M | }, |
1028 | 2.28M | { sample_unpack_1_interleaved, sample_unpack_2_interleaved, |
1029 | 2.28M | sample_unpack_4_interleaved, sample_unpack_8_interleaved, |
1030 | 2.28M | sample_unpack_12, sample_unpack_16 |
1031 | 2.28M | }}; |
1032 | 2.28M | int num_planes = penum->num_planes; |
1033 | 2.28M | bool interleaved = (num_planes == 1 && penum->plane_depths[0] != penum->bps); |
1034 | 2.28M | irender_proc_t render_fn = NULL; |
1035 | 2.28M | int i; |
1036 | | |
1037 | 2.28M | if (interleaved) { |
1038 | 1.24M | int num_components = penum->plane_depths[0] / penum->bps; |
1039 | | |
1040 | 3.77M | for (i = 1; i < num_components; i++) { |
1041 | 2.53M | if (decode[0] != decode[i * 2 + 0] || |
1042 | 2.53M | decode[1] != decode[i * 2 + 1]) |
1043 | 8 | break; |
1044 | 2.53M | } |
1045 | 1.24M | if (i == num_components) |
1046 | 1.24M | interleaved = false; /* Use single table. */ |
1047 | 1.24M | } |
1048 | 2.28M | penum->unpack = procs[interleaved][index_bps]; |
1049 | | |
1050 | 2.28M | if_debug1m('b', mem, "[b]unpack=%d\n", bps); |
1051 | | /* Set up pixel0 for image class procedures. */ |
1052 | 2.28M | penum->dda.pixel0 = penum->dda.strip; |
1053 | 2.28M | penum->skip_next_line = NULL; |
1054 | 9.84M | for (i = 0; i < gx_image_class_table_count; ++i) { |
1055 | 9.84M | code = gx_image_class_table[i](penum, &render_fn); |
1056 | 9.84M | if (code < 0) |
1057 | 0 | goto fail; |
1058 | | |
1059 | 9.84M | if (render_fn != NULL) { |
1060 | 2.28M | penum->render = render_fn; |
1061 | 2.28M | break; |
1062 | 2.28M | } |
1063 | 9.84M | } |
1064 | 2.28M | penum->dev = dev; /* Restore this (in case it was changed to cdev or rtdev) */ |
1065 | 2.28M | if (i == gx_image_class_table_count) { |
1066 | | /* No available class can handle this image. */ |
1067 | 0 | return_error(gs_error_rangecheck); |
1068 | 0 | } |
1069 | 2.28M | } |
1070 | 2.28M | return 0; |
1071 | | |
1072 | 59 | fail: |
1073 | 59 | gs_free_object(mem, buffer, "image buffer"); |
1074 | 59 | gs_free_object(mem, penum->clues, "gx_image_enum_begin"); |
1075 | 59 | if (penum->clip_dev != NULL) { |
1076 | 0 | rc_decrement(penum->clip_dev, "error in gx_begin_image1"); |
1077 | 0 | penum->clip_dev = NULL; |
1078 | 0 | } |
1079 | 59 | gs_free_object(mem, penum->clip_dev, "image clipper"); |
1080 | 59 | rc_decrement_cs(penum->pcs, "error in gx_begin_image1"); |
1081 | 59 | penum->pcs = NULL; |
1082 | 59 | gs_free_object(mem, penum, "gx_begin_image1"); |
1083 | 59 | return code; |
1084 | 2.28M | } |
1085 | | |
1086 | | /* If a drawing color is black or white, return 0 or 1 respectively, */ |
1087 | | /* otherwise return -1. */ |
1088 | | static int |
1089 | | color_draws_b_w(gx_device * dev, const gx_drawing_color * pdcolor) |
1090 | 0 | { |
1091 | 0 | if (color_is_pure(pdcolor)) { |
1092 | 0 | gx_color_value rgb[3]; |
1093 | |
|
1094 | 0 | (*dev_proc(dev, map_color_rgb)) (dev, gx_dc_pure_color(pdcolor), |
1095 | 0 | rgb); |
1096 | 0 | if (!(rgb[0] | rgb[1] | rgb[2])) |
1097 | 0 | return 0; |
1098 | 0 | if ((rgb[0] & rgb[1] & rgb[2]) == gx_max_color_value) |
1099 | 0 | return 1; |
1100 | 0 | } |
1101 | 0 | return -1; |
1102 | 0 | } |
1103 | | |
1104 | | |
1105 | | static void |
1106 | | image_cache_decode(gx_image_enum *penum, byte input, byte *output, bool scale) |
1107 | 0 | { |
1108 | 0 | float temp; |
1109 | |
|
1110 | 0 | switch ( penum->map[0].decoding ) { |
1111 | 0 | case sd_none: |
1112 | 0 | *output = input; |
1113 | 0 | break; |
1114 | 0 | case sd_lookup: |
1115 | 0 | temp = penum->map[0].decode_lookup[input >> 4]*255.0f; |
1116 | 0 | if (temp > 255) temp = 255; |
1117 | 0 | if (temp < 0 ) temp = 0; |
1118 | 0 | *output = (unsigned char) temp; |
1119 | 0 | break; |
1120 | 0 | case sd_compute: |
1121 | 0 | temp = penum->map[0].decode_base + |
1122 | 0 | (float) input * penum->map[0].decode_factor; |
1123 | 0 | if (scale) { |
1124 | 0 | temp = temp * 255.0; |
1125 | 0 | } |
1126 | 0 | if (temp > 255) temp = 255; |
1127 | 0 | if (temp < 0 ) temp = 0; |
1128 | 0 | *output = (unsigned char) temp; |
1129 | 0 | break; |
1130 | 0 | default: |
1131 | 0 | *output = 0; |
1132 | 0 | break; |
1133 | 0 | } |
1134 | 0 | } |
1135 | | |
1136 | | static bool |
1137 | | decode_range_needed(gx_image_enum *penum) |
1138 | 0 | { |
1139 | 0 | bool scale = true; |
1140 | |
|
1141 | 0 | if (penum->map[0].decoding == sd_compute) { |
1142 | 0 | if (!(gs_color_space_is_ICC(penum->pcs) || |
1143 | 0 | gs_color_space_is_PSCIE(penum->pcs))) { |
1144 | 0 | scale = false; |
1145 | 0 | } |
1146 | 0 | } |
1147 | 0 | return scale; |
1148 | 0 | } |
1149 | | |
1150 | | /* A special case where we go ahead and initialize the whole index cache with |
1151 | | contone. Device colors. If we are halftoning we will then go ahead and |
1152 | | apply the thresholds to the device contone values. Only used for gray, |
1153 | | rgb or cmyk source colors (No DeviceN for now) */ |
1154 | | /* TO DO Add in PSCIE decoder */ |
1155 | | int |
1156 | | image_init_color_cache(gx_image_enum * penum, int bps, int spp) |
1157 | 85.3k | { |
1158 | 85.3k | int num_des_comp = penum->dev->color_info.num_components; |
1159 | 85.3k | int num_src_comp; |
1160 | 85.3k | int num_entries = 1 << bps; |
1161 | 85.3k | bool need_decode = penum->icc_setup.need_decode; |
1162 | 85.3k | bool has_transfer = penum->icc_setup.has_transfer; |
1163 | 85.3k | byte value; |
1164 | 85.3k | bool decode_scale = true; |
1165 | 85.3k | int k, kk; |
1166 | 85.3k | byte psrc[4]; |
1167 | 85.3k | byte *temp_buffer; |
1168 | 85.3k | byte *byte_ptr; |
1169 | 85.3k | bool is_indexed = (gs_color_space_get_index(penum->pcs) == |
1170 | 85.3k | gs_color_space_index_Indexed); |
1171 | 85.3k | bool free_temp_buffer = true; |
1172 | 85.3k | gsicc_bufferdesc_t input_buff_desc; |
1173 | 85.3k | gsicc_bufferdesc_t output_buff_desc; |
1174 | 85.3k | gx_color_value conc[GX_DEVICE_COLOR_MAX_COMPONENTS]; |
1175 | 85.3k | int code; |
1176 | | |
1177 | 85.3k | if (penum->icc_link == NULL) { |
1178 | 0 | return gs_rethrow(-1, "ICC Link not created during image render color"); |
1179 | 0 | } |
1180 | 85.3k | if (is_indexed) { |
1181 | 1.77k | num_src_comp = gs_color_space_num_components(penum->pcs->base_space); |
1182 | 83.6k | } else { |
1183 | | /* Detect case where cache is not needed. Colors are already in the |
1184 | | device space. Need to fast track this one and halftone row directly. |
1185 | | Detected in gximono.c by looking if penum->color_cache is NULL */ |
1186 | 83.6k | if (penum->icc_link->is_identity && !need_decode && !has_transfer) { |
1187 | 83.3k | return 0; |
1188 | 83.3k | } |
1189 | 227 | num_src_comp = 1; |
1190 | 227 | } |
1191 | | /* Allocate cache of device contone values */ |
1192 | 2.00k | penum->color_cache = gs_alloc_struct(penum->memory, gx_image_color_cache_t, |
1193 | 2.00k | &st_color_cache, |
1194 | 2.00k | "image_init_color_cache"); |
1195 | 2.00k | if (penum->color_cache == NULL) |
1196 | 0 | return_error(gs_error_VMerror); |
1197 | | |
1198 | 2.00k | penum->color_cache->device_contone = (byte*) gs_alloc_bytes(penum->memory, |
1199 | 2.00k | num_des_comp * num_entries * sizeof(byte), "image_init_color_cache"); |
1200 | 2.00k | penum->color_cache->is_transparent = (bool*) gs_alloc_bytes(penum->memory, |
1201 | 2.00k | num_entries * sizeof(bool), "image_init_color_cache"); |
1202 | 2.00k | if (penum->color_cache->device_contone == NULL || penum->color_cache->is_transparent == NULL) { |
1203 | 0 | gs_free_object(penum->memory, penum->color_cache->device_contone, "image_init_color_cache"); |
1204 | 0 | gs_free_object(penum->memory, penum->color_cache->is_transparent, "image_init_color_cache"); |
1205 | 0 | gs_free_object(penum->memory, penum->color_cache, "image_init_color_cache"); |
1206 | 0 | penum->color_cache = NULL; |
1207 | 0 | return_error(gs_error_VMerror); |
1208 | 0 | } |
1209 | | /* Initialize */ |
1210 | 2.00k | memset(penum->color_cache->is_transparent,0,num_entries * sizeof(bool)); |
1211 | | /* Depending upon if we need decode and ICC CM, fill the cache a couple |
1212 | | different ways. If the link is the identity, then we don't need to do any |
1213 | | color conversions except for potentially a decode. This is written in |
1214 | | the manner shown below so that the common case of no decode and indexed |
1215 | | image with a look-up-table uses the table data directly or does as many |
1216 | | operations with memcpy as we can */ |
1217 | | /* Need to check the decode output range so we know how we need to scale. |
1218 | | We want 8 bit output */ |
1219 | 2.00k | if (need_decode) { |
1220 | 0 | decode_scale = decode_range_needed(penum); |
1221 | 0 | } |
1222 | 2.00k | if (penum->icc_link->is_identity) { |
1223 | | /* No CM needed. */ |
1224 | 0 | if (need_decode || has_transfer) { |
1225 | | /* Slower case. This could be sped up later to avoid the tests |
1226 | | within the loop by use of specialized loops. */ |
1227 | 0 | for (k = 0; k < num_entries; k++) { |
1228 | | /* Data is in k */ |
1229 | 0 | if (need_decode) { |
1230 | 0 | image_cache_decode(penum, k, &value, decode_scale); |
1231 | 0 | } else { |
1232 | 0 | value = k; |
1233 | 0 | } |
1234 | | /* Data is in value */ |
1235 | 0 | if (is_indexed) { |
1236 | 0 | gs_cspace_indexed_lookup_bytes(penum->pcs, value, psrc); |
1237 | 0 | } else { |
1238 | 0 | psrc[0] = value; |
1239 | 0 | } |
1240 | | /* Data is in psrc */ |
1241 | | /* These silly transforms need to go away. ToDo. */ |
1242 | 0 | if (has_transfer) { |
1243 | 0 | for (kk = 0; kk < num_des_comp; kk++) { |
1244 | 0 | conc[kk] = gx_color_value_from_byte(psrc[kk]); |
1245 | 0 | } |
1246 | 0 | cmap_transfer(&(conc[0]), penum->pgs, penum->dev); |
1247 | 0 | for (kk = 0; kk < num_des_comp; kk++) { |
1248 | 0 | psrc[kk] = gx_color_value_to_byte(conc[kk]); |
1249 | 0 | } |
1250 | 0 | } |
1251 | 0 | memcpy(&(penum->color_cache->device_contone[k * num_des_comp]), |
1252 | 0 | psrc, num_des_comp); |
1253 | 0 | } |
1254 | 0 | } else { |
1255 | | /* Indexing only. No CM, decode or transfer functions. */ |
1256 | 0 | for (k = 0; k < num_entries; k++) { |
1257 | 0 | gs_cspace_indexed_lookup_bytes(penum->pcs, (float)k, psrc); |
1258 | 0 | memcpy(&(penum->color_cache->device_contone[k * num_des_comp]), |
1259 | 0 | psrc, num_des_comp); |
1260 | 0 | } |
1261 | 0 | } |
1262 | 2.00k | } else { |
1263 | | /* Need CM */ |
1264 | | /* We need to worry about if the source is indexed and if we need |
1265 | | to decode first. Then we can apply CM. Create a temp buffer in |
1266 | | the source space and then transform it with one call */ |
1267 | 2.00k | temp_buffer = (byte*) gs_alloc_bytes(penum->memory, |
1268 | 2.00k | (size_t)num_entries * num_src_comp, |
1269 | 2.00k | "image_init_color_cache"); |
1270 | 2.00k | if (temp_buffer == NULL) |
1271 | 0 | return_error(gs_error_VMerror); |
1272 | | |
1273 | 2.00k | if (need_decode) { |
1274 | 0 | if (is_indexed) { |
1275 | | /* Decode and lookup in index */ |
1276 | 0 | for (k = 0; k < num_entries; k++) { |
1277 | 0 | image_cache_decode(penum, k, &value, decode_scale); |
1278 | 0 | gs_cspace_indexed_lookup_bytes(penum->pcs, value, psrc); |
1279 | 0 | memcpy(&(temp_buffer[k * num_src_comp]), psrc, num_src_comp); |
1280 | 0 | } |
1281 | 0 | } else { |
1282 | | /* Decode only */ |
1283 | 0 | for (k = 0; k < num_entries; k++) { |
1284 | 0 | image_cache_decode(penum, k, &(temp_buffer[k]), decode_scale); |
1285 | 0 | } |
1286 | 0 | } |
1287 | 2.00k | } else { |
1288 | | /* No Decode */ |
1289 | 2.00k | if (is_indexed) { |
1290 | | /* If index uses a num_entries sized table then just use its pointer */ |
1291 | 1.77k | if (penum->pcs->params.indexed.use_proc || |
1292 | 1.77k | penum->pcs->params.indexed.hival < (num_entries - 1)) { |
1293 | | /* Have to do the slow way */ |
1294 | 6.84k | for (k = 0; k <= penum->pcs->params.indexed.hival; k++) { |
1295 | 6.66k | gs_cspace_indexed_lookup_bytes(penum->pcs, (float)k, psrc); |
1296 | 6.66k | memcpy(&(temp_buffer[k * num_src_comp]), psrc, num_src_comp); |
1297 | 6.66k | } |
1298 | | /* just use psrc results from converting 'hival' to fill the remaining slots */ |
1299 | 40.1k | for (; k < num_entries; k++) { |
1300 | 39.9k | memcpy(&(temp_buffer[k * num_src_comp]), psrc, num_src_comp); |
1301 | 39.9k | } |
1302 | 1.59k | } else { |
1303 | | /* Use the index table directly. */ |
1304 | 1.59k | gs_free_object(penum->memory, temp_buffer, "image_init_color_cache"); |
1305 | 1.59k | free_temp_buffer = false; |
1306 | 1.59k | temp_buffer = (byte *)(penum->pcs->params.indexed.lookup.table.data); |
1307 | 1.59k | } |
1308 | 1.77k | } else { |
1309 | | /* CM only */ |
1310 | 58.3k | for (k = 0; k < num_entries; k++) { |
1311 | 58.1k | temp_buffer[k] = k; |
1312 | 58.1k | } |
1313 | 227 | } |
1314 | 2.00k | } |
1315 | | /* Set up the buffer descriptors. */ |
1316 | 2.00k | gsicc_init_buffer(&input_buff_desc, num_src_comp, 1, false, false, false, |
1317 | 2.00k | 0, num_entries * num_src_comp, 1, num_entries); |
1318 | 2.00k | gsicc_init_buffer(&output_buff_desc, num_des_comp, 1, false, false, false, |
1319 | 2.00k | 0, num_entries * num_des_comp, |
1320 | 2.00k | 1, num_entries); |
1321 | 2.00k | code = (penum->icc_link->procs.map_buffer)(penum->dev, penum->icc_link, |
1322 | 2.00k | &input_buff_desc, &output_buff_desc, |
1323 | 2.00k | (void*) temp_buffer, |
1324 | 2.00k | (void*) penum->color_cache->device_contone); |
1325 | 2.00k | if (code < 0) |
1326 | 0 | return gs_rethrow(code, "Failure to map color buffer"); |
1327 | | |
1328 | | /* Check if we need to apply any transfer functions. If so then do it now */ |
1329 | 2.00k | if (has_transfer) { |
1330 | 0 | for (k = 0; k < num_entries; k++) { |
1331 | 0 | byte_ptr = |
1332 | 0 | &(penum->color_cache->device_contone[k * num_des_comp]); |
1333 | 0 | for (kk = 0; kk < num_des_comp; kk++) { |
1334 | 0 | conc[kk] = gx_color_value_from_byte(byte_ptr[kk]); |
1335 | 0 | } |
1336 | 0 | cmap_transfer(&(conc[0]), penum->pgs, penum->dev); |
1337 | 0 | for (kk = 0; kk < num_des_comp; kk++) { |
1338 | 0 | byte_ptr[kk] = gx_color_value_to_byte(conc[kk]); |
1339 | 0 | } |
1340 | 0 | } |
1341 | 0 | } |
1342 | 2.00k | if (free_temp_buffer) |
1343 | 409 | gs_free_object(penum->memory, temp_buffer, "image_init_color_cache"); |
1344 | 2.00k | } |
1345 | 2.00k | return 0; |
1346 | 2.00k | } |
1347 | | |
1348 | | /* Export this for use by image_render_ functions */ |
1349 | | void |
1350 | | image_init_clues(gx_image_enum * penum, int bps, int spp) |
1351 | 1.18M | { |
1352 | | /* Initialize the color table */ |
1353 | 1.18M | #define ictype(i)\ |
1354 | 1.18M | penum->clues[i].dev_color.type |
1355 | | |
1356 | 1.18M | switch ((spp == 1 ? bps : 8)) { |
1357 | 999k | case 8: /* includes all color images */ |
1358 | 999k | { |
1359 | 999k | register gx_image_clue *pcht = &penum->clues[0]; |
1360 | 999k | register int n = 64; /* 8 bits means 256 clues, do */ |
1361 | | /* 4 at a time for efficiency */ |
1362 | 63.9M | do { |
1363 | 63.9M | pcht[0].dev_color.type = |
1364 | 63.9M | pcht[1].dev_color.type = |
1365 | 63.9M | pcht[2].dev_color.type = |
1366 | 63.9M | pcht[3].dev_color.type = |
1367 | 63.9M | gx_dc_type_none; |
1368 | 63.9M | pcht[0].key = pcht[1].key = |
1369 | 63.9M | pcht[2].key = pcht[3].key = 0; |
1370 | 63.9M | pcht += 4; |
1371 | 63.9M | } |
1372 | 63.9M | while (--n > 0); |
1373 | 999k | penum->clues[0].key = 1; /* guarantee no hit */ |
1374 | 999k | break; |
1375 | 0 | } |
1376 | 664 | case 4: |
1377 | 664 | ictype(17) = ictype(2 * 17) = ictype(3 * 17) = |
1378 | 664 | ictype(4 * 17) = ictype(6 * 17) = ictype(7 * 17) = |
1379 | 664 | ictype(8 * 17) = ictype(9 * 17) = ictype(11 * 17) = |
1380 | 664 | ictype(12 * 17) = ictype(13 * 17) = ictype(14 * 17) = |
1381 | 664 | gx_dc_type_none; |
1382 | | /* falls through */ |
1383 | 1.80k | case 2: |
1384 | 1.80k | ictype(5 * 17) = ictype(10 * 17) = gx_dc_type_none; |
1385 | 1.18M | #undef ictype |
1386 | 1.18M | } |
1387 | 1.18M | } |
1388 | | |
1389 | | /* Initialize the color mapping tables for a non-mask image. */ |
1390 | | static int |
1391 | | image_init_colors(gx_image_enum * penum, int bps, int spp, |
1392 | | gs_image_format_t format, const float *decode /*[spp*2] */ , |
1393 | | const gs_gstate * pgs, gx_device * dev, |
1394 | | const gs_color_space * pcs, bool * pdcb) |
1395 | 1.85M | { |
1396 | 1.85M | int ci, decode_type, code; |
1397 | 1.85M | static const float default_decode[] = { |
1398 | 1.85M | 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0 |
1399 | 1.85M | }; |
1400 | | |
1401 | | /* Clues are only used with image_mono_render */ |
1402 | 1.85M | if (spp == 1) { |
1403 | 563k | image_init_clues(penum, bps, spp); |
1404 | 563k | } |
1405 | 1.85M | decode_type = 3; /* 0=custom, 1=identity, 2=inverted, 3=impossible */ |
1406 | 4.99M | for (ci = 0; ci < spp; ci +=2 ) { |
1407 | 3.14M | decode_type &= (decode[ci] == 0. && decode[ci + 1] == 1.) | |
1408 | 3.14M | (decode[ci] == 1. && decode[ci + 1] == 0.) << 1; |
1409 | 3.14M | } |
1410 | | |
1411 | | /* Initialize the maps from samples to intensities. */ |
1412 | 6.37M | for (ci = 0; ci < spp; ci++) { |
1413 | 4.52M | sample_map *pmap = &penum->map[ci]; |
1414 | | |
1415 | | /* If the decoding is [0 1] or [1 0], we can fold it */ |
1416 | | /* into the expansion of the sample values; */ |
1417 | | /* otherwise, we have to use the floating point method. */ |
1418 | | |
1419 | 4.52M | const float *this_decode = &decode[ci * 2]; |
1420 | 4.52M | const float *map_decode; /* decoding used to */ |
1421 | | /* construct the expansion map */ |
1422 | 4.52M | const float *real_decode; /* decoding for expanded samples */ |
1423 | | |
1424 | 4.52M | map_decode = real_decode = this_decode; |
1425 | 4.52M | if (!(decode_type & 1)) { |
1426 | 7.06k | if ((decode_type & 2) && bps <= 8) { |
1427 | 476 | real_decode = default_decode; |
1428 | 6.58k | } else { |
1429 | 6.58k | *pdcb = false; |
1430 | 6.58k | map_decode = default_decode; |
1431 | 6.58k | } |
1432 | 7.06k | } |
1433 | 4.52M | if (bps > 2 || format != gs_image_format_chunky) { |
1434 | 4.50M | if (bps <= 8) |
1435 | 4.50M | image_init_map(&pmap->table.lookup8[0], 1 << bps, |
1436 | 4.50M | map_decode); |
1437 | 4.50M | } else { /* The map index encompasses more than one pixel. */ |
1438 | 21.1k | byte map[4]; |
1439 | 21.1k | register int i; |
1440 | | |
1441 | 21.1k | image_init_map(&map[0], 1 << bps, map_decode); |
1442 | 21.1k | switch (bps) { |
1443 | 20.5k | case 1: |
1444 | 20.5k | { |
1445 | 20.5k | register bits32 *p = &pmap->table.lookup4x1to32[0]; |
1446 | | |
1447 | 20.5k | if (map[0] == 0 && map[1] == 0xff) |
1448 | 20.5k | memcpy((byte *) p, lookup4x1to32_identity, 16 * 4); |
1449 | 38 | else if (map[0] == 0xff && map[1] == 0) |
1450 | 38 | memcpy((byte *) p, lookup4x1to32_inverted, 16 * 4); |
1451 | 0 | else |
1452 | 0 | for (i = 0; i < 16; i++, p++) |
1453 | 0 | ((byte *) p)[0] = map[i >> 3], |
1454 | 0 | ((byte *) p)[1] = map[(i >> 2) & 1], |
1455 | 0 | ((byte *) p)[2] = map[(i >> 1) & 1], |
1456 | 0 | ((byte *) p)[3] = map[i & 1]; |
1457 | 20.5k | } |
1458 | 20.5k | break; |
1459 | 574 | case 2: |
1460 | 574 | { |
1461 | 574 | register bits16 *p = &pmap->table.lookup2x2to16[0]; |
1462 | | |
1463 | 9.75k | for (i = 0; i < 16; i++, p++) |
1464 | 9.18k | ((byte *) p)[0] = map[i >> 2], |
1465 | 9.18k | ((byte *) p)[1] = map[i & 3]; |
1466 | 574 | } |
1467 | 574 | break; |
1468 | 21.1k | } |
1469 | 21.1k | } |
1470 | 4.52M | pmap->decode_base /* = decode_lookup[0] */ = real_decode[0]; |
1471 | 4.52M | pmap->decode_factor = |
1472 | 4.52M | (real_decode[1] - real_decode[0]) / |
1473 | 4.52M | (bps <= 8 ? 255.0 : (float)frac_1); |
1474 | 4.52M | pmap->decode_max /* = decode_lookup[15] */ = real_decode[1]; |
1475 | 4.52M | if (decode_type) { |
1476 | 4.52M | pmap->decoding = sd_none; |
1477 | 4.52M | pmap->inverted = map_decode[0] != 0; |
1478 | 4.52M | } else if (bps <= 4) { |
1479 | 633 | int step = 15 / ((1 << bps) - 1); |
1480 | 633 | int i; |
1481 | | |
1482 | 633 | pmap->decoding = sd_lookup; |
1483 | 3.20k | for (i = 15 - step; i > 0; i -= step) |
1484 | 2.56k | pmap->decode_lookup[i] = pmap->decode_base + |
1485 | 2.56k | i * (255.0 / 15) * pmap->decode_factor; |
1486 | 633 | pmap->inverted = 0; |
1487 | 5.95k | } else { |
1488 | 5.95k | pmap->decoding = sd_compute; |
1489 | 5.95k | pmap->inverted = 0; |
1490 | 5.95k | } |
1491 | 4.52M | if (spp == 1) { /* and ci == 0 *//* Pre-map entries 0 and 255. */ |
1492 | 563k | gs_client_color cc; |
1493 | | |
1494 | | /* Image clues are used in this case */ |
1495 | 563k | cc.paint.values[0] = real_decode[0]; |
1496 | 563k | code = (*pcs->type->remap_color) (&cc, pcs, penum->icolor0, |
1497 | 563k | pgs, dev, gs_color_select_source); |
1498 | 563k | if (code < 0) |
1499 | 5 | return code; |
1500 | 563k | cc.paint.values[0] = real_decode[1]; |
1501 | 563k | code = (*pcs->type->remap_color) (&cc, pcs, penum->icolor1, |
1502 | 563k | pgs, dev, gs_color_select_source); |
1503 | 563k | if (code < 0) |
1504 | 0 | return code; |
1505 | 563k | } |
1506 | 4.52M | } |
1507 | 1.85M | return 0; |
1508 | 1.85M | } |
1509 | | /* Construct a mapping table for sample values. */ |
1510 | | /* map_size is 2, 4, 16, or 256. Note that 255 % (map_size - 1) == 0, */ |
1511 | | /* so the division 0xffffL / (map_size - 1) is always exact. */ |
1512 | | void |
1513 | | image_init_map(byte * map, int map_size, const float *decode) |
1514 | 4.53M | { |
1515 | 4.53M | float min_v = decode[0]; |
1516 | 4.53M | float diff_v = decode[1] - min_v; |
1517 | | |
1518 | 4.53M | if (diff_v == 1 || diff_v == -1) { /* We can do the stepping with integers, without overflow. */ |
1519 | 4.53M | byte *limit = map + map_size; |
1520 | 4.53M | uint value = (uint)(min_v * 0xffffL); |
1521 | 4.53M | int diff = (int)(diff_v * (0xffffL / (map_size - 1))); |
1522 | | |
1523 | 1.15G | for (; map != limit; map++, value += diff) |
1524 | 1.15G | *map = value >> 8; |
1525 | 4.53M | } else { /* Step in floating point, with clamping. */ |
1526 | 0 | int i; |
1527 | |
|
1528 | 0 | for (i = 0; i < map_size; ++i) { |
1529 | 0 | int value = (int)((min_v + diff_v * i / (map_size - 1)) * 255); |
1530 | |
|
1531 | 0 | map[i] = (value < 0 ? 0 : value > 255 ? 255 : value); |
1532 | 0 | } |
1533 | 0 | } |
1534 | 4.53M | } |
1535 | | |
1536 | | /* |
1537 | | * Scale a pair of mask_color values to match the scaling of each sample to |
1538 | | * a full byte, and complement and swap them if the map incorporates |
1539 | | * a Decode = [1 0] inversion. |
1540 | | */ |
1541 | | void |
1542 | | gx_image_scale_mask_colors(gx_image_enum *penum, int component_index) |
1543 | 500 | { |
1544 | 500 | uint scale = 255 / ((1 << penum->bps) - 1); |
1545 | 500 | uint *values = &penum->mask_color.values[component_index * 2]; |
1546 | 500 | uint v0 = values[0] *= scale; |
1547 | 500 | uint v1 = values[1] *= scale; |
1548 | | |
1549 | 500 | if (penum->map[component_index].decoding == sd_none && |
1550 | 500 | penum->map[component_index].inverted |
1551 | 500 | ) { |
1552 | 0 | values[0] = 255 - v1; |
1553 | 0 | values[1] = 255 - v0; |
1554 | 0 | } |
1555 | 500 | } |
1556 | | |
1557 | | /* Used to indicate for ICC procesing if we have decoding to do */ |
1558 | | bool |
1559 | | gx_has_transfer(const gs_gstate *pgs, int num_comps) |
1560 | 1.54M | { |
1561 | 1.54M | int k; |
1562 | | |
1563 | 4.65M | for (k = 0; k < num_comps; k++) { |
1564 | 3.57M | if (pgs->effective_transfer[k]->proc != gs_identity_transfer) { |
1565 | 464k | return(true); |
1566 | 464k | } |
1567 | 3.57M | } |
1568 | 1.08M | return(false); |
1569 | 1.54M | } |