/src/ghostpdl/pcl/pcl/rtraster.c
Line | Count | Source |
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 | | /* rtraster.c - raster transfer commands */ |
18 | | |
19 | | #include "memory_.h" |
20 | | #include "strimpl.h" |
21 | | #include "scfx.h" |
22 | | #include "scf.h" |
23 | | #include "stream.h" |
24 | | #include "gx.h" |
25 | | #include "gsmatrix.h" |
26 | | #include "gscoord.h" |
27 | | #include "gspath.h" |
28 | | #include "gspath2.h" |
29 | | #include "gsimage.h" |
30 | | #include "gsiparam.h" |
31 | | #include "gsiparm4.h" |
32 | | #include "gsdevice.h" |
33 | | #include "gsrop.h" |
34 | | #include "pcstate.h" |
35 | | #include "pcpalet.h" |
36 | | #include "pcpage.h" |
37 | | #include "pcindxed.h" |
38 | | #include "pcwhtidx.h" |
39 | | #include "pcdraw.h" |
40 | | #include "plvalue.h" |
41 | | #include "rtgmode.h" |
42 | | #include "rtrstcmp.h" |
43 | | #include "rtraster.h" |
44 | | |
45 | | /* |
46 | | * The maximum number of planes for which seed rows need to be kept. This is the |
47 | | * larger of the maximum number of bits per index (for pixel encoding mode 0 - |
48 | | * indexed by plane) or maximum of the sum over the primaries of the number of |
49 | | * bits per primary for pixel encoding mode 2 (direct by plane). For all |
50 | | * current PCL printers, the effective bound is the the former, and is 8. |
51 | | */ |
52 | | #define MAX_PLANES 8 |
53 | | |
54 | | /* |
55 | | * Structure to describe a PCL raster |
56 | | */ |
57 | | typedef struct pcl_raster_s |
58 | | { |
59 | | |
60 | | /* memory used to allocate this structure */ |
61 | | gs_memory_t *pmem; |
62 | | |
63 | | byte nplanes; /* # of planes (seed rows) */ |
64 | | byte bits_per_plane; /* bits per plane */ |
65 | | byte nsrcs; /* # of data sources, 1 or 3 */ |
66 | | |
67 | | uint transparent:1; /* 1 ==> source transparency */ |
68 | | uint src_height_set:1; /* source height was set */ |
69 | | uint indexed:1; /* != 0 ==> indexed color space */ |
70 | | uint zero_is_white:1; /* all planes 0 ==> white */ |
71 | | uint zero_is_black:1; /* all planes 0 ==> solid color */ |
72 | | uint interpolate:1; /* enable interpolation */ |
73 | | int wht_indx; /* white index, for indexed color |
74 | | space only */ |
75 | | const void *remap_ary; /* remap array, if needed */ |
76 | | |
77 | | pcl_state_t *pcs; /* to avoid n extra operand */ |
78 | | pcl_cs_indexed_t *pindexed; /* color space */ |
79 | | |
80 | | gs_image_enum *pen; /* image enumerator */ |
81 | | uint plane_index; /* next plane to be received */ |
82 | | uint rows_rendered; /* # of source rows rendered */ |
83 | | uint src_width; /* usable raster width */ |
84 | | uint src_height; /* remaining usable raster height */ |
85 | | |
86 | | /* objects required for opaque source/transparent pattern case */ |
87 | | gs_image_enum *mask_pen; /* enumerator for mask */ |
88 | | pcl_cs_indexed_t *mask_pindexed; /* special color space for mask */ |
89 | | ulong white_val; /* value interpreted as white */ |
90 | | void (*gen_mask_row) (struct pcl_raster_s * prast); |
91 | | |
92 | | /* buffers */ |
93 | | pcl_seed_row_t *pseed_rows; /* seed rows, one per plane */ |
94 | | byte *cons_buff; /* consolidation buffer */ |
95 | | byte *mask_buff; /* buffer for mask row, if needed */ |
96 | | |
97 | | } pcl_raster_t; |
98 | | |
99 | | gs_private_st_simple(st_seed_row_t_element, pcl_seed_row_t, |
100 | | "PCL seed row array"); |
101 | | gs_private_st_simple(st_raster_t, pcl_raster_t, "PCL raster object"); |
102 | | |
103 | | /* forward declaration */ |
104 | | static int process_zero_rows(pcl_raster_t * prast, int nrows); |
105 | | |
106 | | /* |
107 | | * Clear the consolidation buffer, allocating it if it does not already |
108 | | * exist. |
109 | | * |
110 | | * Returns 0 on success, < 0 in the event of an error. |
111 | | */ |
112 | | static int |
113 | | clear_cons_buff(pcl_raster_t * prast) |
114 | 17.1k | { |
115 | 17.1k | byte *pcons = prast->cons_buff; |
116 | 17.1k | int npixels = prast->src_width; |
117 | | |
118 | 17.1k | if (pcons == 0) { |
119 | 743 | pcons = gs_alloc_bytes(prast->pmem, |
120 | 743 | npixels, "PCL raster consolidation buff"); |
121 | 743 | if (pcons == 0) |
122 | 0 | return e_Memory; |
123 | 743 | prast->cons_buff = pcons; |
124 | 743 | } |
125 | 17.1k | memset(pcons, 0, npixels); |
126 | | |
127 | 17.1k | return 0; |
128 | 17.1k | } |
129 | | |
130 | | /* |
131 | | * Clear the mask buffer, allocating it if it does not exist. |
132 | | * |
133 | | * Returns 0 on success, < 0 in the event of an error. |
134 | | */ |
135 | | static int |
136 | | clear_mask_buff(pcl_raster_t * prast) |
137 | 0 | { |
138 | 0 | byte *pmask = prast->mask_buff; |
139 | 0 | int nbytes = (prast->src_width + 7) / 8; |
140 | |
|
141 | 0 | if (pmask == 0) { |
142 | 0 | pmask = gs_alloc_bytes(prast->pmem, nbytes, "PCL raster mask buffer"); |
143 | 0 | if (pmask == 0) |
144 | 0 | return e_Memory; |
145 | 0 | prast->mask_buff = pmask; |
146 | 0 | } |
147 | 0 | memset(pmask, 0, nbytes); |
148 | |
|
149 | 0 | return 0; |
150 | |
|
151 | 0 | } |
152 | | |
153 | | /* |
154 | | * Generate a mask row in case there are multiple data sources (in the graphic |
155 | | * library sense). This code takes much advantage of the knowledge that the |
156 | | * mutliple source case is always direct and one bit per pixel. |
157 | | */ |
158 | | static void |
159 | | gen_mask_multisrc(pcl_raster_t * prast) |
160 | 0 | { |
161 | 0 | byte *ip0 = prast->pseed_rows[0].pdata; |
162 | 0 | byte *ip1 = prast->pseed_rows[1].pdata; |
163 | 0 | byte *ip2 = prast->pseed_rows[2].pdata; |
164 | 0 | byte *op = prast->mask_buff; |
165 | 0 | uint m0 = (prast->white_val >> 16) & 0xff; |
166 | 0 | uint m1 = (prast->white_val >> 8) & 0xff; |
167 | 0 | uint m2 = prast->white_val & 0xff; |
168 | 0 | int nbytes = prast->pseed_rows[0].size; |
169 | 0 | int i; |
170 | |
|
171 | 0 | for (i = 0; i < nbytes; i++) |
172 | 0 | *op++ = (*ip0++ ^ m0) & (*ip1++ ^ m1) & (*ip2++ ^ m2); |
173 | 0 | } |
174 | | |
175 | | /* |
176 | | * Generate a mask from input data that is less than one byte. For PCL rasters |
177 | | * as implemented by this routine, such situations only occur when an integral |
178 | | * number of pixels fit within one byte, and this routine takes advantage of |
179 | | * that situation. |
180 | | */ |
181 | | static void |
182 | | gen_mask_subbyte(pcl_raster_t * prast) |
183 | 0 | { |
184 | 0 | byte *ip = prast->pseed_rows[0].pdata; |
185 | 0 | byte *op = prast->mask_buff; |
186 | 0 | int ishift = prast->bits_per_plane; |
187 | 0 | uint targ = prast->white_val; |
188 | 0 | int size = prast->src_width; |
189 | 0 | uint ival, oval, imask, omask; |
190 | 0 | int i; |
191 | |
|
192 | 0 | for (i = 0, ival = 0, oval = 0, imask = 0, omask = 0x80; i < size; i++) { |
193 | 0 | if ((imask >>= ishift) == 0) { |
194 | 0 | imask = 0xff - (0xff >> ishift); |
195 | 0 | ival = *ip++; |
196 | 0 | } |
197 | 0 | if (((ival ^ targ) & imask) == 0) |
198 | 0 | oval |= omask; |
199 | 0 | if ((omask >>= 1) == 0) { |
200 | 0 | *op++ = oval; |
201 | 0 | omask = 0x80; |
202 | 0 | oval = 0; |
203 | 0 | } |
204 | 0 | } |
205 | 0 | if (omask != 0x80) |
206 | 0 | *op++ = oval; |
207 | 0 | } |
208 | | |
209 | | /* |
210 | | * Generate a mask from input data that has one byte per pixel. |
211 | | */ |
212 | | static void |
213 | | gen_mask_1byte(pcl_raster_t * prast) |
214 | 0 | { |
215 | 0 | byte *ip = (prast->nplanes == 1 ? prast->pseed_rows[0].pdata |
216 | 0 | : prast->cons_buff); |
217 | 0 | byte *op = prast->mask_buff; |
218 | 0 | uint targ = prast->white_val; |
219 | 0 | int size = prast->src_width; |
220 | 0 | uint oval, omask; |
221 | 0 | int i; |
222 | |
|
223 | 0 | for (i = 0, oval = 0, omask = 0x80; i < size; i++) { |
224 | 0 | if (*ip++ == targ) |
225 | 0 | oval |= omask; |
226 | 0 | if ((omask >>= 1) == 0) { |
227 | 0 | *op++ = oval; |
228 | 0 | omask = 0x80; |
229 | 0 | oval = 0; |
230 | 0 | } |
231 | 0 | } |
232 | 0 | if (omask != 0x80) |
233 | 0 | *op++ = oval; |
234 | 0 | } |
235 | | |
236 | | /* |
237 | | * Generate a mask row in the case that more than one byte is required per |
238 | | * pixel. The only possible such case in PCL is 8-bits per primary 3 color, |
239 | | * so this routine handles only that case. |
240 | | */ |
241 | | static void |
242 | | gen_mask_multibyte(pcl_raster_t * prast) |
243 | 0 | { |
244 | 0 | byte *ip = prast->pseed_rows[0].pdata; |
245 | 0 | byte *op = prast->mask_buff; |
246 | 0 | int size = prast->src_width; |
247 | 0 | ulong targ = prast->white_val; |
248 | 0 | uint oval, omask; |
249 | 0 | int i; |
250 | |
|
251 | 0 | for (i = 0, oval = 0, omask = 0x80; i < size; i++, ip += 3) { |
252 | 0 | ulong ival = (((ulong) ip[0]) << 16) | (((ulong) ip[1]) << 8) | ip[2]; |
253 | |
|
254 | 0 | if (ival == targ) |
255 | 0 | oval |= omask; |
256 | 0 | if ((omask >>= 1) == 0) { |
257 | 0 | *op++ = oval; |
258 | 0 | omask = 0x80; |
259 | 0 | oval = 0; |
260 | 0 | } |
261 | 0 | } |
262 | 0 | if (omask != 0x80) |
263 | 0 | *op++ = oval; |
264 | 0 | } |
265 | | |
266 | | /* |
267 | | * Consolidate a set of seed rows into the consolidated row buffer. |
268 | | * |
269 | | * This routine will only be called if: |
270 | | * |
271 | | * prast->nplanes > 1 |
272 | | * prast->bits_per_plane = 1 |
273 | | * prast->nsrcs = 1 |
274 | | * |
275 | | * The output is always packed 8 bits per pixel, even if ferwer are required. |
276 | | * |
277 | | * Returns 0 on success, < 0 in the event of an error. |
278 | | */ |
279 | | static int |
280 | | consolidate_row(pcl_raster_t * prast) |
281 | 17.1k | { |
282 | 17.1k | byte *pcons; |
283 | 17.1k | uint nplanes = prast->nplanes; |
284 | 17.1k | uint npixels = prast->src_width; |
285 | 17.1k | int code, i; |
286 | | |
287 | | /* clear the consolidation buffer */ |
288 | 17.1k | if ((code = clear_cons_buff(prast)) < 0) |
289 | 0 | return code; |
290 | 17.1k | pcons = prast->cons_buff; |
291 | | |
292 | | /* for each plane, "or" in the appropriate bit */ |
293 | 68.4k | for (i = 0; i < nplanes; i++) { |
294 | 51.3k | if (!prast->pseed_rows[i].is_blank) { |
295 | 14.4k | const byte *ip = prast->pseed_rows[i].pdata; |
296 | 14.4k | byte *op = pcons; |
297 | 14.4k | int cnt = npixels; |
298 | | |
299 | 1.72M | for (; cnt >= 8; ip++, op += 8, cnt -= 8) { |
300 | 1.70M | uint val = *ip; |
301 | | |
302 | | /* |
303 | | * cons_buff was allocated with gs_alloc_bytes, so we know |
304 | | * it is aligned for (at least) bits32 access. |
305 | | */ |
306 | | #if ARCH_IS_BIG_ENDIAN |
307 | | static const bits32 spread[16] = { |
308 | | 0x00000000, 0x00000001, 0x00000100, 0x00000101, |
309 | | 0x00010000, 0x00010001, 0x00010100, 0x00010101, |
310 | | 0x01000000, 0x01000001, 0x01000100, 0x01000101, |
311 | | 0x01010000, 0x01010001, 0x01010100, 0x01010101 |
312 | | }; |
313 | | #else |
314 | 1.70M | static const bits32 spread[16] = { |
315 | 1.70M | 0x00000000, 0x01000000, 0x00010000, 0x01010000, |
316 | 1.70M | 0x00000100, 0x01000100, 0x00010100, 0x01010100, |
317 | 1.70M | 0x00000001, 0x01000001, 0x00010001, 0x01010001, |
318 | 1.70M | 0x00000101, 0x01000101, 0x00010101, 0x01010101 |
319 | 1.70M | }; |
320 | 1.70M | #endif |
321 | 1.70M | ((bits32 *) op)[0] |= spread[val >> 4] << i; |
322 | 1.70M | ((bits32 *) op)[1] |= spread[val & 0xf] << i; |
323 | 1.70M | } |
324 | 14.4k | if (cnt) { |
325 | 14.2k | uint ishift = 7; |
326 | 14.2k | uint val = *ip; |
327 | | |
328 | 40.1k | do { |
329 | 40.1k | *op++ |= ((val >> ishift--) & 0x1) << i; |
330 | 40.1k | } while (--cnt > 0); |
331 | 14.2k | } |
332 | 14.4k | } |
333 | 51.3k | } |
334 | | |
335 | 17.1k | return 0; |
336 | 17.1k | } |
337 | | |
338 | | /* |
339 | | * Create an enumerator for the mask portion of an image (if required). |
340 | | * |
341 | | * Returns 0 on success, < 0 in the event of an error. |
342 | | */ |
343 | | static int |
344 | | create_mask_enumerator(pcl_raster_t * prast) |
345 | 0 | { |
346 | 0 | int transparent = prast->transparent; |
347 | | |
348 | | /* |
349 | | * Most elements of gs_image1_t and gs_image4_t are identical. The only exception |
350 | | * that we care about is MaskColor in gs_image_type4_t. |
351 | | */ |
352 | 0 | union |
353 | 0 | { |
354 | 0 | gs_image1_t i1; |
355 | 0 | gs_image4_t i4; |
356 | 0 | } image; |
357 | |
|
358 | 0 | gs_image_enum *pen = gs_image_enum_alloc(prast->pmem, |
359 | 0 | "Create image for PCL raster"); |
360 | 0 | int code = 0; |
361 | 0 | const byte *pcolor = 0; |
362 | 0 | gx_image_enum_common_t *pie = 0; |
363 | 0 | pcl_state_t *pcs = prast->pcs; |
364 | |
|
365 | 0 | if (pen == 0) |
366 | 0 | return e_Memory; |
367 | | |
368 | 0 | code = pcl_set_drawing_color(pcs, pcl_pattern_solid_white, 0, true); |
369 | 0 | if (code < 0) |
370 | 0 | return code; |
371 | | |
372 | | /* generate the special two entry indexed color space required */ |
373 | 0 | if (prast->indexed) |
374 | 0 | pcolor = prast->pindexed->palette.data + 3 * prast->wht_indx; |
375 | 0 | else { |
376 | 0 | static const byte cwhite[3] = { 1, 1, 1 }; |
377 | |
|
378 | 0 | pcolor = cwhite; |
379 | 0 | } |
380 | 0 | code = pcl_cs_indexed_build_special(&(prast->mask_pindexed), |
381 | 0 | prast->pindexed->pbase, |
382 | 0 | pcolor, prast->pmem); |
383 | |
|
384 | 0 | if (code >= 0) { |
385 | 0 | if (transparent) |
386 | 0 | gs_image4_t_init((gs_image4_t *) & image, |
387 | 0 | prast->mask_pindexed->pcspace); |
388 | 0 | else |
389 | 0 | gs_image_t_init_adjust((gs_image_t *) & image, |
390 | 0 | prast->mask_pindexed->pcspace, 0); |
391 | 0 | image.i1.Width = prast->src_width; |
392 | 0 | image.i1.Height = prast->src_height; |
393 | |
|
394 | 0 | if (pcs->personality == pcl5e) |
395 | 0 | image.i1.CombineWithColor = false; |
396 | 0 | else |
397 | 0 | image.i1.CombineWithColor = true; |
398 | 0 | image.i1.format = gs_image_format_chunky; |
399 | 0 | image.i1.BitsPerComponent = 1; |
400 | 0 | image.i1.Decode[0] = 0.0; |
401 | 0 | image.i1.Decode[1] = 1.0; |
402 | 0 | if (transparent) |
403 | 0 | image.i4.MaskColor[0] = 0; |
404 | |
|
405 | 0 | code = gs_image_begin_typed((const gs_image_common_t *)&image, |
406 | 0 | pcs->pgs, true, false, &pie); |
407 | |
|
408 | 0 | if (code >= 0) |
409 | 0 | code = gs_image_common_init(pen, |
410 | 0 | pie, |
411 | 0 | (gs_data_image_t *) & image, |
412 | 0 | gs_currentdevice_inline(pcs->pgs) |
413 | 0 | ); |
414 | 0 | } |
415 | |
|
416 | 0 | if (code < 0) |
417 | 0 | gs_free_object(prast->pmem, pen, "Create image for PCL raster"); |
418 | 0 | else |
419 | 0 | prast->mask_pen = pen; |
420 | |
|
421 | 0 | if (code >= 0) |
422 | 0 | code = pcl_set_drawing_color(pcs, pcs->pattern_type, pcs->pattern_id, true); |
423 | |
|
424 | 0 | return code; |
425 | 0 | } |
426 | | |
427 | | /* |
428 | | * Create the graphic library image object needed to represent a raster. |
429 | | * |
430 | | * If the image does not use transparency then we need to use image type 1 processing. |
431 | | * Otherwise we need to use image type 4. Most of the setup is the same for both |
432 | | * cases. Thus rather than split this into two routines with a lot redundant code |
433 | | * I am keeping one routine with a union structure (image) and some conditionals. |
434 | | * |
435 | | * Returns 0 on success, < 0 in the event of an error. |
436 | | */ |
437 | | static int |
438 | | create_image_enumerator(pcl_raster_t * prast) |
439 | 4.43k | { |
440 | 4.43k | int nplanes = prast->nplanes; |
441 | 4.43k | int b_per_p = prast->bits_per_plane; |
442 | 4.43k | int num_comps = (prast->indexed ? 1 : 3); |
443 | 4.43k | int nsrcs = prast->nsrcs; |
444 | | |
445 | | /* |
446 | | * Most elements of gs_image1_t and gs_image4_t are identical. The only exception |
447 | | * that we care about is MaskColor in gs_image_type4_t. |
448 | | */ |
449 | 4.43k | int use_image4 = prast->transparent; |
450 | | |
451 | 4.43k | union |
452 | 4.43k | { |
453 | 4.43k | gs_image1_t i1; |
454 | 4.43k | gs_image4_t i4; |
455 | 4.43k | } image; |
456 | 4.43k | gs_image_enum *pen = gs_image_enum_alloc(prast->pmem, |
457 | 4.43k | "Create image for PCL raster"); |
458 | 4.43k | gx_image_enum_common_t *pie = 0; |
459 | 4.43k | gs_color_space *pcspace = (prast->indexed |
460 | 4.43k | ? prast->pindexed->pcspace |
461 | 4.43k | : prast->pindexed->pbase->pcspace); |
462 | 4.43k | int code = 0; |
463 | | |
464 | 4.43k | if (pen == 0) |
465 | 0 | return e_Memory; |
466 | | |
467 | | /* |
468 | | * There is one more case in which we will not use image type 4 processing. |
469 | | * If our color specifications are indexed and the wht_index value is greater |
470 | | * then the largest possible value given the number of index bits, then it is |
471 | | * not possible to ever get a 'white' (transparent) value. Thus skip |
472 | | * transparency in this case. |
473 | | */ |
474 | 4.43k | if ((prast->indexed) && (prast->wht_indx >= 1 << (nplanes * b_per_p))) |
475 | 0 | use_image4 = 0; |
476 | | |
477 | | /* we also don't use an image type 4 if the user has requested |
478 | | interpolation */ |
479 | 4.43k | if (prast->interpolate) |
480 | 0 | use_image4 = 0; |
481 | | |
482 | 4.43k | if (use_image4) |
483 | 4.30k | gs_image4_t_init((gs_image4_t *) & image, pcspace); |
484 | 133 | else |
485 | 133 | gs_image_t_init_adjust((gs_image_t *) & image, pcspace, 0); |
486 | 4.43k | image.i1.Width = prast->src_width; |
487 | 4.43k | image.i1.Height = prast->src_height; |
488 | 4.43k | image.i1.CombineWithColor = true; |
489 | 4.43k | image.i1.format = (nsrcs > 1 ? gs_image_format_component_planar |
490 | 4.43k | : gs_image_format_chunky); |
491 | | |
492 | 4.43k | if (nplanes > nsrcs) |
493 | 743 | image.i1.BitsPerComponent = 8; /* always 8 bits per pixel if consolidated */ |
494 | 3.69k | else |
495 | 3.69k | image.i1.BitsPerComponent = (nplanes * b_per_p) / num_comps; |
496 | | |
497 | 4.43k | image.i1.Interpolate = prast->interpolate; |
498 | | |
499 | 4.43k | if (prast->indexed) { |
500 | 4.43k | if (use_image4) |
501 | 4.30k | image.i4.MaskColor[0] = prast->wht_indx; |
502 | 4.43k | image.i1.Decode[0] = 0.0; |
503 | 4.43k | image.i1.Decode[1] = (float)((1 << image.i1.BitsPerComponent) - 1); |
504 | 4.43k | } else { |
505 | 0 | int i; |
506 | |
|
507 | 0 | for (i = 0; i < num_comps; i++) { |
508 | 0 | image.i1.Decode[2 * i] = prast->pindexed->Decode[2 * i]; |
509 | 0 | image.i1.Decode[2 * i + 1] = prast->pindexed->Decode[2 * i + 1]; |
510 | |
|
511 | 0 | if (use_image4) { |
512 | 0 | image.i4.MaskColor[i] = (1 << image.i1.BitsPerComponent); |
513 | 0 | if (image.i1.Decode[2 * i] == 1.0) |
514 | 0 | image.i4.MaskColor[i] = 0; |
515 | 0 | else if (image.i1.Decode[2 * i + 1] == 1.0) |
516 | 0 | image.i4.MaskColor[i] = |
517 | 0 | (1 << image.i1.BitsPerComponent) - 1; |
518 | 0 | } |
519 | 0 | } |
520 | 0 | } |
521 | | |
522 | 4.43k | code = gs_image_begin_typed((const gs_image_common_t *)&image, |
523 | 4.43k | prast->pcs->pgs, true, false, &pie); |
524 | 4.43k | if (code >= 0) |
525 | 4.43k | code = gs_image_common_init(pen, |
526 | 4.43k | pie, |
527 | 4.43k | (gs_data_image_t *) & image, |
528 | 4.43k | gs_currentdevice_inline(prast->pcs->pgs) |
529 | 4.43k | ); |
530 | 4.43k | if (code < 0) { |
531 | 0 | gs_free_object(prast->pmem, pen, "Create image for PCL raster"); |
532 | 0 | return code; |
533 | 0 | } |
534 | 4.43k | prast->pen = pen; |
535 | 4.43k | return 0; |
536 | 4.43k | } |
537 | | |
538 | | /* |
539 | | * Close the image being used to represent a raster. If the second argument is |
540 | | * true, complete the raster as well. |
541 | | * |
542 | | * This routine does NOT clear the seed rows, as their content may be needed |
543 | | * for the next row of the raster. |
544 | | * |
545 | | * NB: This routine may re-invoke itself recursively when completing the raster, |
546 | | * as this routine will call process_zero_rows, which may once again invoke |
547 | | * this routine. The recursion can only extend to one additional level, |
548 | | * however, as process_zero_rows will call this routine with complete set |
549 | | * set to false. |
550 | | */ |
551 | | static void |
552 | | close_raster(gs_gstate * pgs, pcl_raster_t * prast, bool complete) |
553 | 5.63k | { |
554 | | /* see if we need to fill in any missing rows */ |
555 | 5.63k | if (complete && |
556 | 5.63k | (prast->src_height > prast->rows_rendered) && prast->src_height_set) |
557 | 0 | (void)process_zero_rows(prast, |
558 | 0 | prast->src_height - prast->rows_rendered); |
559 | 5.63k | if (prast->pen != 0) { |
560 | 4.43k | gs_image_cleanup(prast->pen, pgs); |
561 | 4.43k | gs_free_object(prast->pmem, prast->pen, "Close PCL raster"); |
562 | 4.43k | prast->pen = 0; |
563 | 4.43k | } |
564 | 5.63k | if (prast->mask_pen != 0) { |
565 | 0 | gs_image_cleanup(prast->mask_pen, pgs); |
566 | 0 | gs_free_object(prast->pmem, prast->mask_pen, "Close PCL raster"); |
567 | 0 | prast->mask_pen = 0; |
568 | 0 | } |
569 | 5.63k | gs_translate(prast->pcs->pgs, 0.0, (double) (prast->rows_rendered)); |
570 | 5.63k | prast->src_height -= prast->rows_rendered; |
571 | 5.63k | prast->rows_rendered = 0; |
572 | 5.63k | } |
573 | | |
574 | | /* |
575 | | * Generate the white-mask corresponding to an image scanline. This is |
576 | | * necessary to implement the opaque source/transparent texture case. |
577 | | * |
578 | | * HP's specification of transparency includes one unintuitive case: opaque |
579 | | * source and transparent texture. In this case, the texture applies only to |
580 | | * the non-white portion of the source; the white portion should be rendered |
581 | | * in a solid white. |
582 | | * |
583 | | * Since the graphic library does not support mutliple textures in a single |
584 | | * rendering operation, it is necessary to split objects that have both a |
585 | | * foreground and a background into two transparent objects: one having just |
586 | | * the foreground, the other just the background. In the case of rasters it |
587 | | * is necessary to form a mask object that is the inverse of the background, |
588 | | * and "paint" it with "white". The following code accomplishes this task. |
589 | | * |
590 | | * It is, unfortunately, not possible to use the graphic libraries image mask |
591 | | * feature to implement the "white mask", because image masks in the graphic |
592 | | * library are not implemented as mask objects. Rather, they are implemented |
593 | | * as transparent colored patterns, with the foreground color taken from the |
594 | | * current color at the time the image mask is begun. Instead, a two entry |
595 | | * transparent colored image is used, whose foreground color is the current |
596 | | * white and whose background color is a transparent white. |
597 | | * |
598 | | * As always, what is considered "white" is evaluated in the source color space; |
599 | | * this varies from HP's practice, and can give unexpected results if an |
600 | | * inverting color lookup table is used. |
601 | | */ |
602 | | static int |
603 | | process_mask_row(pcl_raster_t * prast) |
604 | 0 | { |
605 | 0 | int code = clear_mask_buff(prast); |
606 | 0 | gs_image_enum *pen = prast->mask_pen; |
607 | |
|
608 | 0 | if ((code >= 0) && |
609 | 0 | ((pen != 0) || ((code = create_mask_enumerator(prast)) >= 0))) { |
610 | 0 | uint dummy; |
611 | 0 | pcl_state_t *pcs = prast->pcs; |
612 | |
|
613 | 0 | pen = prast->mask_pen; |
614 | 0 | code = pcl_set_drawing_color(pcs, pcl_pattern_solid_white, 0, true); |
615 | 0 | if (code < 0) return code; |
616 | 0 | prast->gen_mask_row(prast); |
617 | 0 | code = gs_image_next(pen, |
618 | 0 | prast->mask_buff, |
619 | 0 | (prast->src_width + 7) / 8, &dummy); |
620 | 0 | if (code < 0) return code; |
621 | 0 | code = pcl_set_drawing_color(pcs, pcs->pattern_type, pcs->pattern_id, true); |
622 | 0 | } |
623 | 0 | return code; |
624 | 0 | } |
625 | | |
626 | | static int |
627 | | process_zero_mask_rows(pcl_raster_t * prast, int nrows) |
628 | 0 | { |
629 | 0 | int code = clear_mask_buff(prast); |
630 | 0 | gs_image_enum *pen = prast->mask_pen; |
631 | |
|
632 | 0 | if ((code >= 0) && |
633 | 0 | ((pen != 0) || ((code = create_mask_enumerator(prast)) >= 0))) { |
634 | 0 | uint dummy; |
635 | 0 | pcl_state_t *pcs = prast->pcs; |
636 | |
|
637 | 0 | int nbytes = (prast->src_width + 7) / 8; |
638 | |
|
639 | 0 | pen = prast->mask_pen; |
640 | 0 | memset(prast->mask_buff, 0xff, nbytes); |
641 | 0 | code = pcl_set_drawing_color(pcs, pcl_pattern_solid_white, 0, true); |
642 | 0 | if (code < 0) |
643 | 0 | return code; |
644 | 0 | code = check_rasterops(pcs, (gs_rop3_t) rop3_know_S_1((int)0xff)); |
645 | 0 | if (code >= 0) { |
646 | 0 | code = gs_setrasterop(pcs->pgs, (gs_rop3_t) rop3_know_S_1((int)0xff)); |
647 | 0 | if (code < 0) |
648 | 0 | return code; |
649 | 0 | } |
650 | 0 | while ((nrows-- > 0) && (code >= 0)) |
651 | 0 | code = gs_image_next(pen, prast->mask_buff, nbytes, &dummy); |
652 | |
|
653 | 0 | if (code < 0) |
654 | 0 | code = pcl_set_drawing_color(pcs, pcs->pattern_type, pcs->pattern_id, true); |
655 | 0 | } |
656 | 0 | return code; |
657 | 0 | } |
658 | | |
659 | | /* |
660 | | * Process some number of zero-ed out rows, either as rasters or as a rectangle. |
661 | | * |
662 | | * Ideally, any sufficiently large regions of zero value would be rendered as |
663 | | * a rectangle, but doing so runs afoul of PCL's graphic model. Rectangles are |
664 | | * mask objects, whose value is provided by the current color/pattern/texture. |
665 | | * Images are colored objects, whose interaction with the the current color/ |
666 | | * texture/raster is established by the current raster operation. |
667 | | * |
668 | | * In many cases, it is possible to emulate the effect of a colored object by |
669 | | * use of a mask object and modifications to the current pattern/color/texture |
670 | | * and the current raster operation. For the most part, however, situations in |
671 | | * which such modifications are useful do not occur often enough to be worth |
672 | | * special handling. |
673 | | * |
674 | | * There is one case that does arise with some frequency and is simple to |
675 | | * handle: 0 is white, and source transparency is on. In this case, no work |
676 | | * is necessary: just leave the output as is. |
677 | | * |
678 | | * The other case that is likely to arise often enough to be worth special |
679 | | * handling is when 0 is white but source transparency is off. In this case, |
680 | | * the current raster operation must be inverted relative to the source |
681 | | * component and a solid rectangle output. A similar situation with a black |
682 | | * rectangle does not occur very frequently, but can be handled by the same |
683 | | * technique (without inverting the raster operation), so it is handled here |
684 | | * as well. |
685 | | * |
686 | | * Zero regions of less than a kilo byte are not given special handling, so |
687 | | * as to avoid the overhead of closing and then restarting an image. |
688 | | * |
689 | | * Returns 0 on success, < 0 in the event of an error. |
690 | | */ |
691 | | static int |
692 | | process_zero_rows(pcl_raster_t * prast, int nrows) |
693 | 3 | { |
694 | 3 | int npixels = prast->src_width; |
695 | 3 | int nbytes = (npixels * prast->bits_per_plane + 7) / 8; |
696 | 3 | int nplanes = prast->nplanes; |
697 | 3 | int rem_rows = prast->src_height - prast->rows_rendered; |
698 | 3 | pcl_seed_row_t *pseed_rows = prast->pseed_rows; |
699 | 3 | int code = 0; |
700 | 3 | int i; |
701 | 3 | int moveto_nrows = nrows; |
702 | | |
703 | | /* don't bother going beyond the end of the image */ |
704 | 3 | if (nrows > rem_rows) { |
705 | 2 | nrows = rem_rows; |
706 | 2 | } |
707 | | |
708 | | /* if clipping the whole raster, just update rendered rows */ |
709 | 3 | if (prast->pcs->raster_state.clip_all) { |
710 | 0 | prast->rows_rendered += nrows; |
711 | 0 | return 0; |
712 | 0 | } |
713 | | |
714 | | /* clear the seed rows */ |
715 | 6 | for (i = 0; i < nplanes; i++) { |
716 | 3 | if (!pseed_rows[i].is_blank) { |
717 | 1 | memset(prast->pseed_rows[i].pdata, 0, nbytes); |
718 | 1 | pseed_rows[i].is_blank = true; |
719 | 1 | } |
720 | 3 | } |
721 | | |
722 | | /* render as raster or rectangle */ |
723 | 3 | if (((nrows * nbytes > 1024) || (prast->pen == 0)) && |
724 | 3 | (prast->zero_is_white || prast->zero_is_black)) { |
725 | 3 | gs_gstate *pgs = prast->pcs->pgs; |
726 | | |
727 | 3 | close_raster(pgs, prast, false); |
728 | 3 | if ((prast->zero_is_black) || !prast->pcs->source_transparent) { |
729 | 0 | gs_rect tmp_rect; |
730 | 0 | bool invert = prast->zero_is_white; |
731 | |
|
732 | 0 | tmp_rect.p.x = 0.0; |
733 | 0 | tmp_rect.p.y = 0.0; |
734 | 0 | tmp_rect.q.x = (double)npixels; |
735 | 0 | tmp_rect.q.y = (double)nrows; |
736 | 0 | if (invert) { |
737 | 0 | code = check_rasterops(prast->pcs, (gs_rop3_t) |
738 | 0 | rop3_invert_S(gs_currentrasterop(pgs))); |
739 | 0 | if (code >= 0) { |
740 | 0 | code = gs_setrasterop(pgs, |
741 | 0 | (gs_rop3_t) |
742 | 0 | rop3_invert_S(gs_currentrasterop(pgs)) |
743 | 0 | ); |
744 | 0 | if (code < 0) |
745 | 0 | return code; |
746 | 0 | } |
747 | | |
748 | 0 | code = gs_rectfill(pgs, &tmp_rect, 1); |
749 | 0 | if (code < 0) |
750 | 0 | return code; |
751 | | |
752 | 0 | code = check_rasterops(prast->pcs, (gs_rop3_t) |
753 | 0 | rop3_invert_S(gs_currentrasterop(pgs))); |
754 | 0 | if (code >= 0) { |
755 | 0 | code = gs_setrasterop(pgs, |
756 | 0 | (gs_rop3_t) |
757 | 0 | rop3_invert_S(gs_currentrasterop(pgs)) |
758 | 0 | ); |
759 | 0 | if (code < 0) |
760 | 0 | return code; |
761 | 0 | } else |
762 | 0 | code = 0; |
763 | 0 | } else { |
764 | 0 | code = gs_rectfill(pgs, &tmp_rect, 1); |
765 | 0 | if (code < 0) |
766 | 0 | return code; |
767 | 0 | } |
768 | |
|
769 | 0 | } |
770 | | |
771 | 3 | prast->src_height -= nrows; |
772 | | /* NB HP bug CET21.04 pg 7 */ |
773 | | /* NB text cap move to moveto_nrows, but raster cap moveto nrows */ |
774 | 3 | gs_translate(pgs, 0.0, (double) moveto_nrows); |
775 | | |
776 | 3 | return 0; |
777 | | |
778 | 3 | } else { |
779 | 0 | int nsrcs = prast->nsrcs; |
780 | 0 | gs_image_enum *pen = prast->pen; |
781 | 0 | int cnt = 0; |
782 | 0 | uint size = 0; |
783 | 0 | const byte *pb; |
784 | |
|
785 | 0 | if (pen == 0) { |
786 | 0 | if ((code = create_image_enumerator(prast)) < 0) |
787 | 0 | return code; |
788 | 0 | pen = prast->pen; |
789 | 0 | } |
790 | | |
791 | 0 | if (nplanes > nsrcs) { |
792 | 0 | if ((code = clear_cons_buff(prast)) < 0) |
793 | 0 | return code; |
794 | 0 | cnt = nrows; |
795 | 0 | size = npixels; |
796 | 0 | pb = prast->cons_buff; |
797 | 0 | } else { |
798 | 0 | cnt = nrows * nsrcs; |
799 | 0 | size = nbytes; |
800 | 0 | pb = prast->pseed_rows[0].pdata; |
801 | 0 | } |
802 | | |
803 | 0 | for (i = 0; i < cnt; i++) { |
804 | 0 | uint dummy; |
805 | |
|
806 | 0 | if ((code = gs_image_next(pen, pb, size, &dummy)) < 0) |
807 | 0 | return code; |
808 | 0 | } |
809 | 0 | prast->rows_rendered += nrows; |
810 | |
|
811 | 0 | if (prast->gen_mask_row != 0) |
812 | 0 | code = process_zero_mask_rows(prast, nrows); |
813 | |
|
814 | 0 | return code; |
815 | 0 | } |
816 | 3 | } |
817 | | |
818 | | /* |
819 | | * Process the next raster row. |
820 | | * |
821 | | * The compression mode is provided to allow this routine to fill in any |
822 | | * missing rows. For adaptive compression (mode 5), this will be 0. |
823 | | */ |
824 | | static int |
825 | | process_row(pcl_raster_t * prast, int comp_mode /* modified compression mode */ |
826 | | ) |
827 | 78.4k | { |
828 | 78.4k | int nplanes = prast->nplanes; |
829 | 78.4k | gs_image_enum *pen = prast->pen; |
830 | 78.4k | int i; |
831 | 78.4k | int code = 0; |
832 | | |
833 | | /* check if there is anything to do */ |
834 | 78.4k | if (prast->rows_rendered >= prast->src_height) |
835 | 2.02k | return 0; |
836 | 76.3k | else if (prast->pcs->raster_state.clip_all) { |
837 | 6.02k | prast->rows_rendered++; |
838 | 6.02k | return 0; |
839 | 6.02k | } |
840 | | |
841 | | /* handle any planes not provided */ |
842 | 104k | for (i = prast->plane_index; i < nplanes; i++) { |
843 | 34.2k | static const byte dummy = 0; |
844 | | |
845 | 34.2k | (void)pcl_decomp_proc[comp_mode] (prast->pseed_rows + i, &dummy, 0); |
846 | 34.2k | } |
847 | | |
848 | | /* create the image enumerator if it does not already exist */ |
849 | 70.3k | if (pen == 0) { |
850 | 4.43k | if ((code = create_image_enumerator(prast)) < 0) |
851 | 0 | return code; |
852 | 4.43k | pen = prast->pen; |
853 | 4.43k | } |
854 | | |
855 | | /* update the raster parameters */ |
856 | 70.3k | prast->rows_rendered++; |
857 | 70.3k | prast->plane_index = 0; |
858 | | |
859 | 70.3k | if (prast->nsrcs == 1) { |
860 | 70.3k | byte *pb; |
861 | 70.3k | int nbytes, b_per_p; |
862 | 70.3k | uint dummy; |
863 | | |
864 | | /* consolidate the planes if necessary */ |
865 | 70.3k | if (nplanes > prast->nsrcs) { |
866 | 17.1k | if ((code = consolidate_row(prast)) < 0) |
867 | 0 | return code; |
868 | 17.1k | pb = prast->cons_buff; |
869 | 17.1k | b_per_p = 8; |
870 | 17.1k | nbytes = prast->src_width; |
871 | 53.2k | } else { |
872 | 53.2k | pb = prast->pseed_rows[0].pdata; |
873 | 53.2k | nbytes = prast->pseed_rows[0].size; |
874 | 53.2k | b_per_p = prast->bits_per_plane; |
875 | 53.2k | } |
876 | | |
877 | | /* |
878 | | * Remap the planes, if this is required. |
879 | | * |
880 | | * Remapping is only required for indexed color spaces. The indexed |
881 | | * by plane case will have been collapsed to an indexed by pixel case |
882 | | * by this point. |
883 | | * |
884 | | */ |
885 | 70.3k | if (prast->remap_ary) |
886 | 0 | pcl_cmap_apply_remap_ary(prast->remap_ary, |
887 | 0 | pb, b_per_p, prast->src_width); |
888 | | |
889 | 70.3k | code = gs_image_next(pen, pb, nbytes, &dummy); |
890 | | |
891 | 70.3k | } else { |
892 | 0 | uint dummy; |
893 | 0 | int nsrcs = prast->nsrcs; |
894 | |
|
895 | 0 | for (i = 0; (i < nsrcs) && (code >= 0); i++) |
896 | 0 | code = gs_image_next(pen, |
897 | 0 | prast->pseed_rows[i].pdata, |
898 | 0 | prast->pseed_rows[i].size, &dummy); |
899 | 0 | } |
900 | | |
901 | 70.3k | if ((prast->gen_mask_row != 0) && (code >= 0)) |
902 | 0 | code = process_mask_row(prast); |
903 | 70.3k | prast->pcs->page_marked = true; |
904 | 70.3k | return code; |
905 | 70.3k | } |
906 | | |
907 | | /* |
908 | | * Process an input data buffer using no compression with blocks (multiple rows) |
909 | | */ |
910 | | |
911 | | static int |
912 | | process_block_nocompress(gs_gstate * pgs, |
913 | | pcl_raster_t * prast, const byte * pin, uint insize) |
914 | 0 | { |
915 | 0 | uint32 row_bytes, nrows; |
916 | 0 | pcl_seed_row_t *pseed_row = prast->pseed_rows; |
917 | 0 | byte *p; |
918 | | |
919 | | /* the size of the rows are stored in the first 4 bytes */ |
920 | 0 | if (insize < 4) { |
921 | 0 | return gs_throw(e_Range, "Size of raster cannot be determined\n"); |
922 | 0 | } |
923 | | |
924 | 0 | row_bytes = (pl_get_uint32(pin) * prast->bits_per_plane + 7) / 8; |
925 | | |
926 | | /* the remaining data after the row size should be divisible by |
927 | | the row length to have equal sized rows */ |
928 | 0 | if (row_bytes == 0 || ((insize - 4) % row_bytes)) |
929 | 0 | return gs_throw(e_Range, "Non integral number of rows in raster\n"); |
930 | | |
931 | 0 | nrows = insize / row_bytes; |
932 | |
|
933 | 0 | for (p = (byte *) pin + 4; nrows > 0; p += row_bytes, nrows--) { |
934 | 0 | int code; |
935 | |
|
936 | 0 | pcl_decomp_proc[0] (pseed_row, p, row_bytes); |
937 | 0 | prast->plane_index = 1; |
938 | 0 | code = process_row(prast, 0); |
939 | 0 | if (code < 0) |
940 | 0 | return gs_rethrow(code, "Raster row processing failed\n"); |
941 | 0 | } |
942 | 0 | return 0; |
943 | 0 | } |
944 | | |
945 | | static int |
946 | | pcl_ccitt_error(stream_state * st, const char *str) |
947 | 0 | { |
948 | 0 | (void)gs_throw1(-1, "%s", str); |
949 | 0 | return 0; |
950 | 0 | } |
951 | | |
952 | | |
953 | | static int |
954 | | process_ccitt_compress(gs_gstate * pgs, |
955 | | pcl_raster_t * prast, |
956 | | const byte * pin, |
957 | | uint insize, pcl_rast_buff_type_t comp) |
958 | 4 | { |
959 | 4 | stream_CFD_state state; |
960 | 4 | stream_cursor_read scr; |
961 | 4 | stream_cursor_write scw; |
962 | 4 | pcl_seed_row_t *pout = prast->pseed_rows; |
963 | 4 | uint wrsize; |
964 | 4 | byte *temp_buffer; |
965 | | |
966 | 4 | if (insize < 4) |
967 | 0 | return gs_throw(e_Range, "raster row size not specified"); |
968 | | |
969 | 4 | if ((int)pl_get_uint32(pin) < 0) |
970 | 0 | return gs_throw(e_Range, "Image columns overflow CFD filter"); |
971 | | |
972 | 4 | s_init_state((stream_state *) & state, &s_CFD_template, prast->pmem); |
973 | 4 | state.report_error = pcl_ccitt_error; |
974 | 4 | s_CFD_template.set_defaults((stream_state *) & state); |
975 | 4 | state.BlackIs1 = true; |
976 | 4 | state.EndOfLine = false; |
977 | 4 | state.EndOfBlock = false; |
978 | 4 | state.Columns = pl_get_uint32(pin); |
979 | 4 | if (state.Columns == 0 || state.Columns > cfe_max_width) |
980 | 0 | return_error(e_Range); |
981 | 4 | state.Rows = 0; /* undetermined */ |
982 | 4 | if (comp == CCITT_GR3_1D_COMPRESS) |
983 | 0 | state.K = 0; |
984 | 4 | else if (comp == CCITT_GR3_2D_COMPRESS) |
985 | 0 | state.K = 1; |
986 | 4 | else |
987 | 4 | state.K = -1; |
988 | 4 | s_CFD_template.init((stream_state *) & state); |
989 | 4 | scr.ptr = pin + 4 - 1; |
990 | 4 | scr.limit = scr.ptr + insize - 4; |
991 | | |
992 | 4 | wrsize = (state.Columns + 7) / 8; |
993 | 4 | temp_buffer = gs_alloc_bytes(prast->pmem, wrsize, "CCITT temp_buffer"); |
994 | 4 | if (temp_buffer == 0) |
995 | 0 | return_error(e_Memory); |
996 | 4 | memset(temp_buffer, 0, wrsize); |
997 | | |
998 | 4 | scw.ptr = temp_buffer - 1; |
999 | 4 | scw.limit = scw.ptr + wrsize; |
1000 | | |
1001 | 8 | while (1) { |
1002 | 8 | int code = |
1003 | 8 | s_CFD_template.process((stream_state *) & state, &scr, &scw, |
1004 | 8 | true); |
1005 | 8 | switch (code) { |
1006 | | |
1007 | 4 | case 1: /* need output, process the scanline and continue. */ |
1008 | 4 | memcpy(pout->pdata, temp_buffer, min(pout->size, wrsize)); |
1009 | 4 | code = process_row(prast, 0); |
1010 | 4 | if (code < 0) { |
1011 | 0 | s_CFD_template.release((stream_state *) & state); |
1012 | 0 | return gs_rethrow(code, "CCITT decompression failed\n"); |
1013 | 0 | } |
1014 | 4 | memset(temp_buffer, 0, wrsize); |
1015 | 4 | scw.ptr = temp_buffer - 1; |
1016 | 4 | scw.limit = scw.ptr + wrsize; |
1017 | 4 | break; |
1018 | 0 | case EOFC: /* all done */ |
1019 | 0 | s_CFD_template.release((stream_state *) & state); |
1020 | 0 | return 0; |
1021 | 1 | case 0: /* need input is an error - we've given it all the data */ |
1022 | 4 | case ERRC: /* error */ |
1023 | 4 | s_CFD_template.release((stream_state *) & state); |
1024 | 4 | return gs_rethrow(e_Range, "CCITT decompression failed\n"); |
1025 | 0 | default: |
1026 | 0 | return gs_throw(e_Range, |
1027 | 8 | "unknown code CCITT decompression\n"); |
1028 | 8 | } |
1029 | 8 | } |
1030 | | /* not reached */ |
1031 | 0 | return -1; |
1032 | 4 | } |
1033 | | |
1034 | | |
1035 | | |
1036 | | |
1037 | | /* |
1038 | | * Process an input data buffer using adpative compression. |
1039 | | */ |
1040 | | static int |
1041 | | process_adaptive_compress(pcl_raster_t * prast, const byte * pin, uint insize, bool mono) |
1042 | 34 | { |
1043 | 34 | pcl_seed_row_t *pseed_row = prast->pseed_rows; |
1044 | 34 | byte *pdata = pseed_row->pdata; |
1045 | 34 | uint row_size = pseed_row->size; |
1046 | 34 | int code = 0; |
1047 | 34 | int cmd = NO_COMPRESS; |
1048 | 34 | uint param = 0; |
1049 | | |
1050 | 34 | prast->plane_index = 0; |
1051 | 229 | while ((insize >= 3) && (code >= 0)) { |
1052 | 205 | cmd = *pin++; |
1053 | 205 | param = *pin++; |
1054 | | |
1055 | 205 | param = (param << 8) + *pin++; |
1056 | 205 | insize -= 3; |
1057 | 205 | if (cmd <= 3) { |
1058 | 193 | uint cnt = min(insize, param); |
1059 | | |
1060 | 193 | pcl_decomp_proc[cmd] (pseed_row, pin, cnt); |
1061 | 193 | insize -= cnt; |
1062 | 193 | pin += cnt; |
1063 | 193 | prast->plane_index = 1; |
1064 | 193 | code = process_row(prast, 0); |
1065 | 193 | } else if (cmd == 4) |
1066 | 2 | code = process_zero_rows(prast, param); |
1067 | 10 | else if (cmd == 5) { |
1068 | 0 | uint rem_rows = prast->src_height - prast->rows_rendered; |
1069 | 0 | gs_image_enum *pen = prast->pen; |
1070 | |
|
1071 | 0 | if (param > rem_rows) |
1072 | 0 | param = rem_rows; |
1073 | | |
1074 | | /* if clipping the raster, just update lines rendered */ |
1075 | 0 | if (prast->pcs->raster_state.clip_all) { |
1076 | 0 | prast->rows_rendered += param; |
1077 | 0 | continue; |
1078 | 0 | } |
1079 | | |
1080 | | /* create the image enumerator if it does not already exist */ |
1081 | 0 | if (pen == 0) { |
1082 | 0 | if ((code = create_image_enumerator(prast)) < 0) |
1083 | 0 | return code; |
1084 | 0 | pen = prast->pen; |
1085 | 0 | } |
1086 | | |
1087 | 0 | if (prast->nplanes == 1) { |
1088 | 0 | prast->rows_rendered += param; |
1089 | 0 | while ((param-- > 0) && (code >= 0)) { |
1090 | 0 | uint dummy; |
1091 | |
|
1092 | 0 | code = gs_image_next(pen, pdata, row_size, &dummy); |
1093 | 0 | if ((prast->gen_mask_row != 0) && (code >= 0)) |
1094 | 0 | code = process_mask_row(prast); |
1095 | 0 | } |
1096 | 0 | } else { |
1097 | 0 | prast->plane_index = 1; |
1098 | 0 | while ((param-- > 0) && ((code = process_row(prast, 0) >= 0))) |
1099 | 0 | prast->plane_index = 1; |
1100 | 0 | prast->plane_index = 0; |
1101 | 0 | } |
1102 | 0 | } else |
1103 | 10 | break; |
1104 | 205 | } |
1105 | | |
1106 | | /* On monochrome printers tested HP clears the seed row of delta |
1107 | | row compression after each block, color printers leave it |
1108 | | intact. */ |
1109 | 34 | if (mono) { |
1110 | 34 | memset(pdata, 0, row_size); |
1111 | 34 | pseed_row->is_blank = true; |
1112 | 34 | } |
1113 | | |
1114 | 34 | return code; |
1115 | 34 | } |
1116 | | |
1117 | | /* |
1118 | | * Add a raster plane. The bool end_row operand indicates whether or not this is the |
1119 | | * final plane of a row. |
1120 | | */ |
1121 | | static int |
1122 | | add_raster_plane(const byte * pdata, |
1123 | | uint nbytes, bool end_row, pcl_state_t * pcs) |
1124 | 78.3k | { |
1125 | 78.3k | pcl_raster_t *prast = (pcl_raster_t *) pcs->raster_state.pcur_raster; |
1126 | 78.3k | int comp_mode = pcs->raster_state.compression_mode; |
1127 | 78.3k | int nplanes = 0; |
1128 | 78.3k | int plane_index = 0; |
1129 | 78.3k | int code = 0; |
1130 | | |
1131 | | /* enter raster mode implicitly if not already there */ |
1132 | 78.3k | if (prast == 0) { |
1133 | 4.38k | if ((code = pcl_enter_graphics_mode(pcs, IMPLICIT)) != 0) |
1134 | 49 | return code; |
1135 | 4.33k | prast = (pcl_raster_t *) pcs->raster_state.pcur_raster; |
1136 | 4.33k | } |
1137 | | |
1138 | | /* |
1139 | | * Adaptive compression (mode 5) is only available for single-plane |
1140 | | * encodings, and then only if used with a transfer row (ESC * b # W) |
1141 | | * command. The latter behavior matches that of the HP Color LaserJet 5/5M, |
1142 | | * but not that of the DeskJet 1600C/CM, which has somewhat erratic |
1143 | | * behavior in this case. |
1144 | | */ |
1145 | 78.2k | nplanes = prast->nplanes; |
1146 | 78.2k | if ((comp_mode == ADAPTIVE_COMPRESS) && !end_row) |
1147 | 0 | return e_Range; |
1148 | | |
1149 | | /* |
1150 | | * If all the rows that can be output have already been rendered, just |
1151 | | * return. |
1152 | | */ |
1153 | 78.2k | if (prast->rows_rendered >= prast->src_height) |
1154 | 2.02k | return 0; |
1155 | | |
1156 | | /* |
1157 | | * If all planes for this row have been entered, just ignore the current |
1158 | | * data (but don't return yet, as we may still need to output the current |
1159 | | * raster row). |
1160 | | */ |
1161 | 76.2k | plane_index = prast->plane_index; |
1162 | 76.2k | if (plane_index < nplanes) { |
1163 | 70.9k | pcl_seed_row_t *pseed = prast->pseed_rows + plane_index; |
1164 | | |
1165 | 70.9k | prast->plane_index++; |
1166 | 70.9k | if (!PCL_BLOCK_COMP(comp_mode)) |
1167 | 70.8k | (void)pcl_decomp_proc[comp_mode] (pseed, pdata, nbytes); |
1168 | 38 | else if (comp_mode == NO_COMPRESS_BLOCK) |
1169 | 0 | return process_block_nocompress(pcs->pgs, prast, pdata, nbytes); |
1170 | 38 | else if (comp_mode == ADAPTIVE_COMPRESS) |
1171 | 34 | return process_adaptive_compress(prast, pdata, nbytes, pcs->personality == pcl5e); |
1172 | 4 | else |
1173 | 4 | return process_ccitt_compress(pcs->pgs, prast, pdata, nbytes, |
1174 | 4 | comp_mode); |
1175 | | |
1176 | 70.9k | } |
1177 | 76.1k | return 0; |
1178 | 76.2k | } |
1179 | | |
1180 | | /* |
1181 | | * Create a PCL raster object. This procedure is called when entering graphics |
1182 | | * mode. |
1183 | | * |
1184 | | * Note that a raster must be considered "transparent" if either source or |
1185 | | * pattern transparency is in effect. If only pattern transparency is set, an |
1186 | | * addition mask object must be created to fill the "white" regions of the |
1187 | | * raster. This object does not use the current texture; it sets the texture |
1188 | | * to opaque white when it is rendered. This is in conformance with HP's |
1189 | | * somewhat unintuitive interpretation of the opaque source/transparent |
1190 | | * pattern situation. |
1191 | | * |
1192 | | * Returns 0 on success, < 0 in the event of an error. |
1193 | | */ |
1194 | | int |
1195 | | pcl_start_raster(uint src_width, uint src_height, pcl_state_t * pcs) |
1196 | 5.63k | { |
1197 | 5.63k | pcl_raster_t *prast = (pcl_raster_t *) pcs->raster_state.pcur_raster; |
1198 | 5.63k | pcl_palette_t *ppalet = pcs->ppalet; |
1199 | 5.63k | pcl_cs_indexed_t *pindexed = ppalet->pindexed; |
1200 | 5.63k | pcl_encoding_type_t penc = pcl_cs_indexed_get_encoding(pindexed); |
1201 | 5.63k | pcl_seed_row_t *pseed_rows = 0; |
1202 | 5.63k | int pattern_could_be_transparent = |
1203 | 5.63k | pcs->pattern_transparent && |
1204 | 5.07k | pcs->pattern_type != pcl_pattern_solid_frgrnd; |
1205 | | |
1206 | | /* there can only be one raster object present at a time */ |
1207 | 5.63k | if (prast != 0) |
1208 | 0 | pcl_complete_raster(pcs); |
1209 | | |
1210 | 5.63k | prast = gs_alloc_struct(pcs->memory, |
1211 | 5.63k | pcl_raster_t, &st_raster_t, "start PCL raster"); |
1212 | 5.63k | if (prast == 0) |
1213 | 0 | return e_Memory; |
1214 | | |
1215 | 5.63k | prast->pmem = pcs->memory; |
1216 | | |
1217 | 5.63k | if (pcs->source_transparent || pattern_could_be_transparent) |
1218 | 5.46k | prast->transparent = true; |
1219 | 165 | else |
1220 | 165 | prast->transparent = false; |
1221 | | |
1222 | 5.63k | prast->interpolate = pcs->interpolate; |
1223 | 5.63k | prast->src_height_set = pcs->raster_state.src_height_set; |
1224 | 5.63k | prast->pcs = pcs; |
1225 | 5.63k | pcl_cs_indexed_init_from(prast->pindexed, pindexed); |
1226 | | |
1227 | 5.63k | prast->pen = 0; |
1228 | 5.63k | prast->plane_index = 0; |
1229 | 5.63k | prast->rows_rendered = 0; |
1230 | 5.63k | prast->src_width = src_width; |
1231 | 5.63k | prast->src_height = src_height; |
1232 | 5.63k | prast->mask_pen = 0; |
1233 | 5.63k | prast->mask_pindexed = 0; |
1234 | 5.63k | prast->gen_mask_row = 0; |
1235 | | |
1236 | | /* the conslidation and mask buffers are created when first needed */ |
1237 | 5.63k | prast->cons_buff = 0; |
1238 | 5.63k | prast->mask_buff = 0; |
1239 | | |
1240 | 5.63k | if (penc <= pcl_penc_indexed_by_pixel) { |
1241 | 5.63k | int b_per_i = pcl_cs_indexed_get_bits_per_index(pindexed); |
1242 | | |
1243 | 5.63k | if (penc == pcl_penc_indexed_by_plane) { |
1244 | 5.63k | prast->nplanes = b_per_i; |
1245 | 5.63k | prast->bits_per_plane = 1; |
1246 | 5.63k | } else { /* penc == pcl_penc_indexed_by_pixel */ |
1247 | 0 | prast->nplanes = 1; |
1248 | 0 | prast->bits_per_plane = b_per_i; |
1249 | 0 | } |
1250 | 5.63k | prast->nsrcs = 1; |
1251 | 5.63k | prast->indexed = true; |
1252 | 5.63k | prast->zero_is_white = pcl_cs_indexed_0_is_white(pindexed); |
1253 | 5.63k | prast->zero_is_black = pcl_cs_indexed_0_is_black(pindexed); |
1254 | 5.63k | prast->remap_ary = pcl_cmap_create_remap_ary(pcs, &(prast->wht_indx)); |
1255 | | |
1256 | 5.63k | } else { /* penc >= pcl_penc_direct_by_plane */ |
1257 | 0 | int b_per_primary = pcl_cs_indexed_get_bits_per_primary(pindexed, 0); |
1258 | |
|
1259 | 0 | if (penc == pcl_penc_direct_by_plane) { |
1260 | 0 | prast->nplanes = 3; |
1261 | 0 | prast->bits_per_plane = b_per_primary; |
1262 | 0 | prast->nsrcs = 3; |
1263 | 0 | } else { /* penc == pcl_penc_direct_by_pixel */ |
1264 | 0 | prast->nplanes = 1; |
1265 | 0 | prast->bits_per_plane = 3 * b_per_primary; |
1266 | 0 | prast->nsrcs = 1; |
1267 | 0 | } |
1268 | 0 | prast->indexed = false; |
1269 | 0 | prast->zero_is_white = false; |
1270 | 0 | prast->zero_is_black = true; |
1271 | 0 | prast->wht_indx = 1; /* not significant */ |
1272 | 0 | prast->remap_ary = 0; |
1273 | 0 | } |
1274 | | |
1275 | | /* allocate the seed row buffers */ |
1276 | 5.63k | pseed_rows = gs_alloc_struct_array(prast->pmem, |
1277 | 5.63k | prast->nplanes, |
1278 | 5.63k | pcl_seed_row_t, |
1279 | 5.63k | &st_seed_row_t_element, |
1280 | 5.63k | "start PCL raster"); |
1281 | 5.63k | if (pseed_rows != 0) { |
1282 | 5.63k | size_t seed_row_bytes = ((size_t)prast->src_width * prast->bits_per_plane + 7) |
1283 | 5.63k | / 8; |
1284 | | |
1285 | 5.63k | int nplanes = prast->nplanes; |
1286 | 5.63k | int i, j; |
1287 | 12.9k | for (i = 0; i < nplanes; i++) { |
1288 | 7.31k | byte *pdata = gs_alloc_bytes(prast->pmem, |
1289 | 7.31k | seed_row_bytes, |
1290 | 7.31k | "start PCL raster"); |
1291 | | |
1292 | 7.31k | if (pdata == 0) |
1293 | 0 | break; |
1294 | 7.31k | pseed_rows[i].size = seed_row_bytes; |
1295 | 7.31k | pseed_rows[i].pdata = pdata; |
1296 | 7.31k | memset(pseed_rows[i].pdata, 0, seed_row_bytes); |
1297 | 7.31k | pseed_rows[i].is_blank = true; |
1298 | 7.31k | } |
1299 | | |
1300 | | /* check if everything was successful */ |
1301 | 5.63k | if (i < nplanes) { |
1302 | | |
1303 | | /* memory exhaustion; release the already allocated seed rows */ |
1304 | 0 | for (j = 0; j < i; j++) |
1305 | 0 | gs_free_object(prast->pmem, |
1306 | 0 | pseed_rows[j].pdata, "start PCL raster"); |
1307 | 0 | gs_free_object(prast->pmem, pseed_rows, "start PCL raster"); |
1308 | 0 | pseed_rows = 0; |
1309 | 0 | } |
1310 | 5.63k | } |
1311 | | |
1312 | | /* check for memory exhaustion */ |
1313 | 5.63k | if (pseed_rows == 0) { |
1314 | 0 | pcl_cs_indexed_release(prast->pindexed); |
1315 | 0 | gs_free_object(prast->pmem, prast, "start PCL raster"); |
1316 | 0 | return e_Memory; |
1317 | 0 | } |
1318 | | |
1319 | 5.63k | prast->pseed_rows = pseed_rows; |
1320 | 5.63k | pcs->raster_state.pcur_raster = (pcl_raster_type *) prast; |
1321 | | |
1322 | | /* see if a mask is required */ |
1323 | 5.63k | if (!pcs->source_transparent && |
1324 | 165 | pattern_could_be_transparent && |
1325 | 0 | (!prast->indexed || |
1326 | 0 | (prast->wht_indx < (1 << prast->nplanes * prast->bits_per_plane)))) { |
1327 | |
|
1328 | 0 | if (!prast->indexed) { |
1329 | 0 | ulong white_val = 0UL; |
1330 | | |
1331 | | /* direct by plane or by pixel, one or 8 bits per primary */ |
1332 | 0 | prast->gen_mask_row = (prast->nsrcs > 1 ? gen_mask_multisrc |
1333 | 0 | : gen_mask_multibyte); |
1334 | 0 | if (prast->pindexed->Decode[1] == 1.0) |
1335 | 0 | white_val |= ((ulong) 0xff) << 16; |
1336 | 0 | if (prast->pindexed->Decode[3] == 1.0) |
1337 | 0 | white_val |= ((ulong) 0xff) << 8; |
1338 | 0 | if (prast->pindexed->Decode[5] == 1.0) |
1339 | 0 | white_val |= 0xff; |
1340 | 0 | prast->white_val = white_val; |
1341 | |
|
1342 | 0 | } else if ((prast->nplanes > 1) || (prast->bits_per_plane == 8)) { |
1343 | | |
1344 | | /* indexed by plane or direct by pixel, 8 bits per pixel */ |
1345 | 0 | prast->gen_mask_row = gen_mask_1byte; |
1346 | 0 | prast->white_val = prast->wht_indx; |
1347 | |
|
1348 | 0 | } else { |
1349 | 0 | ulong white_val = prast->wht_indx; |
1350 | 0 | int n = 8 / prast->bits_per_plane; |
1351 | | |
1352 | | /* indexed by pixel, < 8 bits per pixel */ |
1353 | 0 | prast->gen_mask_row = gen_mask_subbyte; |
1354 | 0 | while (n-- > 0) |
1355 | 0 | white_val |= (white_val << prast->bits_per_plane); |
1356 | 0 | prast->white_val = white_val; |
1357 | 0 | } |
1358 | 0 | } |
1359 | | |
1360 | 5.63k | return 0; |
1361 | 5.63k | } |
1362 | | |
1363 | | /* |
1364 | | * Complete a raster. This is called when exiting graphics mode. |
1365 | | */ |
1366 | | void |
1367 | | pcl_complete_raster(pcl_state_t * pcs) |
1368 | 10.1k | { |
1369 | 10.1k | pcl_raster_t *prast = (pcl_raster_t *) pcs->raster_state.pcur_raster; |
1370 | 10.1k | int i; |
1371 | | |
1372 | | /* if already in raster mode, ignore */ |
1373 | 10.1k | if (prast == 0) |
1374 | 4.52k | return; |
1375 | | |
1376 | | /* close the current raster */ |
1377 | 5.63k | close_raster(pcs->pgs, prast, true); |
1378 | | |
1379 | | /* free associated objects */ |
1380 | 5.63k | if (prast->remap_ary != 0) { |
1381 | 0 | gs_free_object(prast->pmem, |
1382 | 0 | (void *)prast->remap_ary, "Complete PCL raster"); |
1383 | 0 | prast->remap_ary = 0; |
1384 | 0 | } |
1385 | | |
1386 | 5.63k | if (prast->pindexed != 0) { |
1387 | 5.63k | pcl_cs_indexed_release(prast->pindexed); |
1388 | 5.63k | prast->pindexed = 0; |
1389 | 5.63k | } |
1390 | 5.63k | if (prast->mask_pindexed != 0) { |
1391 | 0 | pcl_cs_indexed_release(prast->mask_pindexed); |
1392 | 0 | prast->mask_pindexed = 0; |
1393 | 0 | } |
1394 | | |
1395 | 5.63k | if (prast->pseed_rows != 0) { |
1396 | 12.9k | for (i = 0; i < prast->nplanes; i++) { |
1397 | 7.31k | if (prast->pseed_rows[i].pdata != 0) |
1398 | 7.31k | gs_free_object(prast->pmem, |
1399 | 7.31k | prast->pseed_rows[i].pdata, |
1400 | 7.31k | "Complete PCL raster"); |
1401 | 7.31k | } |
1402 | 5.63k | gs_free_object(prast->pmem, prast->pseed_rows, "Complete PCL raster"); |
1403 | 5.63k | prast->pseed_rows = 0; |
1404 | 5.63k | } |
1405 | | |
1406 | 5.63k | if (prast->cons_buff != 0) |
1407 | 743 | gs_free_object(prast->pmem, prast->cons_buff, "Complete PCL raster"); |
1408 | 5.63k | if (prast->mask_buff != 0) |
1409 | 0 | gs_free_object(prast->pmem, prast->mask_buff, "Complete PCL raster"); |
1410 | | |
1411 | | /* free the PCL raster robject itself */ |
1412 | 5.63k | gs_free_object(prast->pmem, prast, "Complete PCL raster"); |
1413 | 5.63k | pcs->raster_state.pcur_raster = 0; |
1414 | 5.63k | } |
1415 | | |
1416 | | /* |
1417 | | * ESC * b # V |
1418 | | * |
1419 | | * Add a plane buffer to the current set. |
1420 | | */ |
1421 | | static int |
1422 | | transfer_raster_plane(pcl_args_t * pargs, pcl_state_t * pcs) |
1423 | 10 | { |
1424 | | #ifdef DEBUG |
1425 | | if (gs_debug_c('i')) { |
1426 | | pcl_debug_dump_data(pcs->memory, arg_data(pargs), uint_arg(pargs)); |
1427 | | } |
1428 | | #endif |
1429 | 10 | return add_raster_plane(arg_data(pargs), arg_data_size(pargs), false, |
1430 | 10 | pcs); |
1431 | 10 | } |
1432 | | |
1433 | | /* |
1434 | | * <esc> * b # W |
1435 | | * |
1436 | | * Add a plane buffer to the current buffered set, and complete the current |
1437 | | * raster row. |
1438 | | */ |
1439 | | static int |
1440 | | transfer_raster_row(pcl_args_t * pargs, pcl_state_t * pcs) |
1441 | 78.3k | { |
1442 | 78.3k | const byte *pdata = arg_data(pargs); |
1443 | 78.3k | int comp_mode = pcs->raster_state.compression_mode; |
1444 | 78.3k | int code = 0; |
1445 | | |
1446 | | #ifdef DEBUG |
1447 | | if (gs_debug_c('i')) { |
1448 | | pcl_debug_dump_data(pcs->memory, arg_data(pargs), uint_arg(pargs)); |
1449 | | } |
1450 | | #endif |
1451 | | |
1452 | 78.3k | code = add_raster_plane(pdata, arg_data_size(pargs), true, pcs); |
1453 | | |
1454 | | /* complete the row (execpt for adaptive compression) */ |
1455 | 78.3k | if (!PCL_BLOCK_COMP(comp_mode) && code == 0) |
1456 | 78.2k | code = |
1457 | 78.2k | process_row((pcl_raster_t *) pcs->raster_state.pcur_raster, |
1458 | 78.2k | comp_mode); |
1459 | | |
1460 | 78.3k | if (code < 0) |
1461 | 0 | (void)pcl_grestore(pcs); |
1462 | | |
1463 | 78.3k | return code; |
1464 | 78.3k | } |
1465 | | |
1466 | | /* |
1467 | | * <esc> * b # Y |
1468 | | * |
1469 | | * Skip (zero-fill) a number of raster rows. This command is ignored outside |
1470 | | * of raster mode. |
1471 | | * |
1472 | | * Note that any incomplete plane data for the current row is discarded by this |
1473 | | * command. |
1474 | | */ |
1475 | | static int |
1476 | | raster_y_offset(pcl_args_t * pargs, pcl_state_t * pcs) |
1477 | 7 | { |
1478 | 7 | pcl_raster_t *prast = (pcl_raster_t *) pcs->raster_state.pcur_raster; |
1479 | | |
1480 | | /* ignored outside of graphics mode */ |
1481 | 7 | if ((prast != 0) && (uint_arg(pargs) > 0)) { |
1482 | 1 | return process_zero_rows(prast, uint_arg(pargs)); |
1483 | 1 | } else |
1484 | 6 | return 0; |
1485 | 7 | } |
1486 | | |
1487 | | /* |
1488 | | * ESC * b <direction> L |
1489 | | * |
1490 | | * set raster print direction |
1491 | | */ |
1492 | | static int |
1493 | | set_line_path(pcl_args_t * pargs, pcl_state_t * pcs) |
1494 | 28 | { |
1495 | 28 | uint i = uint_arg(pargs); |
1496 | | |
1497 | 28 | if (i <= 1) |
1498 | 21 | pcs->raster_state.y_advance = (i == 1 ? -1 : 1); |
1499 | 28 | return 0; |
1500 | 28 | } |
1501 | | |
1502 | | /* |
1503 | | * There is no specific copy code for this module, as both entry to and exit |
1504 | | * from a macro must end graphics mode (and thus are handled by the parser). |
1505 | | * There is also no explicit reset routine, as the required work is handled |
1506 | | * at a higher level. |
1507 | | */ |
1508 | | static int |
1509 | | raster_do_registration(pcl_parser_state_t * pcl_parser_state, gs_memory_t * pmem /* ignored */ |
1510 | | ) |
1511 | 8.97k | { |
1512 | 8.97k | DEFINE_CLASS('*') { |
1513 | 8.97k | 'b', 'V', |
1514 | 8.97k | PCL_COMMAND("Transfer Raster Plane", |
1515 | 8.97k | transfer_raster_plane, |
1516 | 8.97k | pca_raster_graphics | pca_bytes | pca_in_rtl) |
1517 | 8.97k | }, { |
1518 | 8.97k | 'b', 'W', |
1519 | 8.97k | PCL_COMMAND("Transfer Raster Row", |
1520 | 8.97k | transfer_raster_row, |
1521 | 8.97k | pca_raster_graphics | pca_bytes | pca_in_rtl) |
1522 | 8.97k | }, { |
1523 | 8.97k | 'b', 'Y', |
1524 | 8.97k | PCL_COMMAND("Raster Y Offset", |
1525 | 8.97k | raster_y_offset, |
1526 | 8.97k | pca_raster_graphics | pca_neg_ok | pca_big_clamp | |
1527 | 8.97k | pca_in_rtl) |
1528 | 8.97k | }, { |
1529 | | /* NB this command should *only* be exectuted in rtl but we |
1530 | | use it in both rtl and pcl5 */ |
1531 | 8.97k | 'b', 'L', |
1532 | 8.97k | PCL_COMMAND("Line Path", |
1533 | 8.97k | set_line_path, |
1534 | 8.97k | pca_neg_ok | pca_big_ignore | pca_in_rtl) |
1535 | 8.97k | }, END_CLASS return 0; |
1536 | 8.97k | } |
1537 | | |
1538 | | static int |
1539 | | raster_do_reset(pcl_state_t * pcs, pcl_reset_type_t type) |
1540 | 35.3k | { |
1541 | 35.3k | if ((type & pcl_reset_initial) != 0) |
1542 | 8.97k | pcs->raster_state.pcur_raster = 0; |
1543 | 35.3k | return 0; |
1544 | 35.3k | } |
1545 | | |
1546 | | const pcl_init_t rtraster_init = |
1547 | | { raster_do_registration, raster_do_reset, 0 }; |