/src/libspectre/ghostscript/devices/gdevplib.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2020 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., 1305 Grant Avenue - Suite 200, Novato, |
13 | | CA 94945, U.S.A., +1(415)492-9861, for further information. |
14 | | */ |
15 | | |
16 | | /* PLanar Interlaced Banded device */ |
17 | | #include "gdevprn.h" |
18 | | #include "gscdefs.h" |
19 | | #include "gscspace.h" /* For pnm_begin_typed_image(..) */ |
20 | | #include "gxgetbit.h" |
21 | | #include "gxlum.h" |
22 | | #include "gxiparam.h" /* For pnm_begin_typed_image(..) */ |
23 | | #include "gdevmpla.h" |
24 | | #include "gdevplnx.h" |
25 | | #include "gdevppla.h" |
26 | | #include "gdevplib.h" /* Band donor functions */ |
27 | | #include "gdevmem.h" |
28 | | |
29 | | /* This file defines 5 different devices: |
30 | | * |
31 | | * plib 24 bit RGB (8 bits per channel) |
32 | | * plibg 8 bit Grayscale |
33 | | * plibm 1 bit Monochrome |
34 | | * plibc 32 bit CMYK (8 bits per channel) |
35 | | * plibk 4 bit CMYK (1 bit per channel) |
36 | | * |
37 | | * It is intended that this device will be built on top of a 'Band Donor' |
38 | | * that will be responsible for allocating and pass us band buffers for us |
39 | | * to fill, and to process them as it wishes on completion. |
40 | | * |
41 | | * If the band_donor functions are not thread safe, or modify the device, then |
42 | | * the gdev_prn_bg_output_page should be changed to use gdev_prn_output_page. |
43 | | * |
44 | | * For debugging/QA purposes this file can be built with the following |
45 | | * define enabled, and stub versions of these band donor functions will |
46 | | * be included here. |
47 | | */ |
48 | | #define TESTING_WITH_NO_BAND_DONOR |
49 | | |
50 | | /* Define DEBUG_PRINT to enable some debugging printfs. */ |
51 | | #undef DEBUG_PRINT |
52 | | |
53 | | /* Define DEBUG_DUMP to dump the data to the output stream. */ |
54 | | #define DEBUG_DUMP |
55 | | |
56 | | /* Define HT_RAW_DUMP to store the output as a raw CMYK buffer with the |
57 | | data size packed into the file name. Photoshop does not handle pam |
58 | | cmyk properly so we resort to this for debugging */ |
59 | | #define HT_RAW_DUMP |
60 | | |
61 | | /* Define SHORTSTOP_MEMCPY_ETC to enable braindead implementations of memcpy |
62 | | * and memset etc in this file. This serves to help profiling on some |
63 | | * systems, though it should be noted that our implementations here are NOT |
64 | | * anywhere near as efficient as typical C libraries ones. */ |
65 | | #undef SHORTSTOP_MEMCPY_ETC |
66 | | |
67 | | #ifdef SHORTSTOP_MEMCPY_ETC |
68 | | |
69 | | void *memset(void *s_, int c, size_t n) |
70 | | { |
71 | | byte *s = (byte *)s_; |
72 | | while (n--) |
73 | | *s++ = (unsigned char)c; |
74 | | return s; |
75 | | } |
76 | | |
77 | | void __aebi_memset8(void *dest, size_t n, int c) |
78 | | { |
79 | | memset(dest, c,n); |
80 | | } |
81 | | void __aebi_memset4(void *dest, size_t n, int c) |
82 | | { |
83 | | memset(dest, c,n); |
84 | | } |
85 | | void __aebi_memset(void *dest, size_t n, int c) |
86 | | { |
87 | | memset(dest, c,n); |
88 | | } |
89 | | |
90 | | void __aebi_memclr8(void *dest, size_t n) |
91 | | { |
92 | | memset(dest, 0,n); |
93 | | } |
94 | | void __aebi_memclr4(void *dest, size_t n) |
95 | | { |
96 | | memset(dest, 0,n); |
97 | | } |
98 | | void __aebi_memclr(void *dest, size_t n) |
99 | | { |
100 | | memset(dest, 0,n); |
101 | | } |
102 | | |
103 | | void *memcpy(void *s_, const void *t_, size_t n) |
104 | | { |
105 | | byte *s = (byte *)s_; |
106 | | const byte *t = (const byte *)t_; |
107 | | while (n--) |
108 | | *s++ = *t++; |
109 | | return s; |
110 | | } |
111 | | |
112 | | void __aebi_memcpy8(void *dest, const void *src, size_t n) |
113 | | { |
114 | | memcpy(dest, src,n); |
115 | | } |
116 | | void __aebi_memcpy4(void *dest, const void *src, size_t n) |
117 | | { |
118 | | memcpy(dest, src,n); |
119 | | } |
120 | | void __aebi_memcpy(void *dest, const void *src, size_t n) |
121 | | { |
122 | | memcpy(dest, src,n); |
123 | | } |
124 | | |
125 | | void *memmove(void *s_, const void *t_, size_t n) |
126 | | { |
127 | | byte *s = (byte *)s_; |
128 | | const byte *t = (const byte *)t_; |
129 | | |
130 | | if (s < t) { |
131 | | while (n--) |
132 | | *s++ = *t++; |
133 | | } else { |
134 | | s += n; |
135 | | t += n; |
136 | | while (n--) |
137 | | *--s = *--t; |
138 | | } |
139 | | return s; |
140 | | } |
141 | | |
142 | | void __aebi_memmove8(void *dest, const void *src, size_t n) |
143 | | { |
144 | | memmove(dest, src,n); |
145 | | } |
146 | | void __aebi_memcmove4(void *dest, const void *src, size_t n) |
147 | | { |
148 | | memmove(dest, src,n); |
149 | | } |
150 | | void __aebi_memmove(void *dest, const void *src, size_t n) |
151 | | { |
152 | | memmove(dest, src,n); |
153 | | } |
154 | | |
155 | | #endif |
156 | | |
157 | | #ifdef TESTING_WITH_NO_BAND_DONOR |
158 | | |
159 | | #include <malloc_.h> |
160 | | |
161 | | static void *my_buffer; |
162 | | |
163 | | int gs_band_donor_init(void **opaque, |
164 | | gs_memory_t *mem) |
165 | 0 | { |
166 | | #ifdef DEBUG_PRINT |
167 | | emprintf(mem, "gs_band_donor_init\n"); |
168 | | #endif |
169 | 0 | *opaque = NULL; |
170 | 0 | return 0; |
171 | 0 | } |
172 | | |
173 | | void *gs_band_donor_band_get(void *opaque, |
174 | | uint uWidth, |
175 | | uint uHeight, |
176 | | uint uBitDepth, |
177 | | uint uComponents, |
178 | | uint uStride, |
179 | | uint uBandHeight) |
180 | 0 | { |
181 | | #ifdef DEBUG_PRINT |
182 | | eprintf6("gs_band_donor_band_get[%dx%dx%dx%d (stride=%d bandHeight=%d)]\n", |
183 | | uWidth, uHeight, uBitDepth, uComponents, uStride, uBandHeight); |
184 | | #endif |
185 | 0 | my_buffer = (void *)malloc(uStride * uComponents * uBandHeight); |
186 | |
|
187 | | #ifdef DEBUG_PRINT |
188 | | q = my_buffer; |
189 | | for (y = uBandHeight; y > 0; y--) { |
190 | | for (p = 0; p < uComponents; p++) { |
191 | | memset(q, 0x10+p, uStride); |
192 | | q += uStride; |
193 | | } |
194 | | } |
195 | | #endif |
196 | 0 | return my_buffer; |
197 | 0 | } |
198 | | |
199 | | int gs_band_donor_band_full(void *opaque, uint nLines) |
200 | 0 | { |
201 | | #ifdef DEBUG_PRINT |
202 | | eprintf1("gs_band_donor_band_full[%d]\n", nLines); |
203 | | #endif |
204 | 0 | return 0; |
205 | 0 | } |
206 | | |
207 | | int gs_band_donor_band_release(void *opaque) |
208 | 0 | { |
209 | | #ifdef DEBUG_PRINT |
210 | | eprintf("gs_band_donor_band_release\n"); |
211 | | #endif |
212 | 0 | free(my_buffer); |
213 | 0 | my_buffer = NULL; |
214 | 0 | return 0; |
215 | 0 | } |
216 | | |
217 | | void gs_band_donor_fin(void *opaque) |
218 | 0 | { |
219 | | #ifdef DEBUG_PRINT |
220 | | eprintf("gs_band_donor_fin\n"); |
221 | | #endif |
222 | 0 | } |
223 | | #endif |
224 | | |
225 | | /* Sanit requires us to work in bands of at least 200 lines */ |
226 | 0 | #define MINBANDHEIGHT 200 |
227 | | |
228 | | /* Structure for plib devices, which extend the generic printer device. */ |
229 | | |
230 | | struct gx_device_plib_s { |
231 | | gx_device_common; |
232 | | gx_prn_device_common; |
233 | | /* Additional state for plib device */ |
234 | | void *opaque; |
235 | | }; |
236 | | typedef struct gx_device_plib_s gx_device_plib; |
237 | | |
238 | | /* ------ The device descriptors ------ */ |
239 | | |
240 | | /* |
241 | | * Default X and Y resolution. |
242 | | */ |
243 | | #define X_DPI 600 |
244 | | #define Y_DPI 600 |
245 | | |
246 | | /* For all but mono, we need our own color mapping and alpha procedures. */ |
247 | | static dev_proc_decode_color(plib_decode_color); |
248 | | static dev_proc_encode_color(plibg_encode_color); |
249 | | static dev_proc_decode_color(plibg_decode_color); |
250 | | static dev_proc_decode_color(plibc_decode_color); |
251 | | static dev_proc_encode_color(plibc_encode_color); |
252 | | static dev_proc_map_color_rgb(plibc_map_color_rgb); |
253 | | |
254 | | static dev_proc_open_device(plib_open); |
255 | | static dev_proc_close_device(plib_close); |
256 | | |
257 | | static dev_proc_put_params(plib_put_params); |
258 | | |
259 | | /* And of course we need our own print-page routines. */ |
260 | | static dev_proc_print_page(plib_print_page); |
261 | | |
262 | | static int plib_print_page(gx_device_printer * pdev, gp_file * pstream); |
263 | | static int plibm_print_page(gx_device_printer * pdev, gp_file * pstream); |
264 | | static int plibg_print_page(gx_device_printer * pdev, gp_file * pstream); |
265 | | static int plibc_print_page(gx_device_printer * pdev, gp_file * pstream); |
266 | | static int plibk_print_page(gx_device_printer * pdev, gp_file * pstream); |
267 | | |
268 | | /* The device procedures */ |
269 | | |
270 | | /* See gdevprn.h for the template for the following. */ |
271 | | #define pgpm_procs(p_color_rgb, p_encode_color, p_decode_color) {\ |
272 | | plib_open,\ |
273 | | NULL, /* get_initial_matrix */ \ |
274 | | NULL, /* sync output */ \ |
275 | | /* Since the print_page doesn't alter the device, this device can print in the background */\ |
276 | | gdev_prn_bg_output_page, \ |
277 | | plib_close,\ |
278 | | NULL, /* map_rgb_color */ \ |
279 | | p_color_rgb, /* map_color_rgb */ \ |
280 | | NULL, /* fill_rectangle */ \ |
281 | | NULL, /* tile_rectangle */ \ |
282 | | NULL, /* copy_mono */ \ |
283 | | NULL, /* copy_color */ \ |
284 | | NULL, /* draw_line */ \ |
285 | | NULL, /* get_bits */ \ |
286 | | gdev_prn_get_params, \ |
287 | | plib_put_params,\ |
288 | | NULL, /* map_cmyk_color */ \ |
289 | | NULL, /* get_xfont_procs */ \ |
290 | | NULL, /* get_xfont_device */ \ |
291 | | NULL, /* map_rgb_alpha_color */ \ |
292 | | gx_page_device_get_page_device, \ |
293 | | NULL, /* get_alpha_bits */\ |
294 | | NULL, /* copy_alpha */\ |
295 | | NULL, /* get_band */\ |
296 | | NULL, /* copy_rop */\ |
297 | | NULL, /* fill_path */\ |
298 | | NULL, /* stroke_path */\ |
299 | | NULL, /* fill_mask */\ |
300 | | NULL, /* fill_trapezoid */\ |
301 | | NULL, /* fill_parallelogram */\ |
302 | | NULL, /* fill_triangle */\ |
303 | | NULL, /* draw_thin_line */\ |
304 | | NULL, /* begin_image */\ |
305 | | NULL, /* image_data */\ |
306 | | NULL, /* end_image */\ |
307 | | NULL, /* strip_tile_rectangle */\ |
308 | | NULL, /* strip_copy_rop */\ |
309 | | NULL, /* get_clipping_box */\ |
310 | | NULL, /* begin_typed_image */\ |
311 | | NULL, /* get_bits_rectangle */\ |
312 | | NULL, /* map_color_rgb_alpha */\ |
313 | | NULL, /* create_compositor */\ |
314 | | NULL, /* get_hardware_params */\ |
315 | | NULL, /* text_begin */\ |
316 | | NULL, /* finish_copydevice */\ |
317 | | NULL, /* begin_transparency_group */\ |
318 | | NULL, /* end_transparency_group */\ |
319 | | NULL, /* begin_transparency_mask */\ |
320 | | NULL, /* end_transparency_mask */\ |
321 | | NULL, /* discard_transparency_layer */\ |
322 | | NULL, /* get_color_mapping_procs */\ |
323 | | NULL, /* get_color_comp_index */\ |
324 | | p_encode_color, /* encode_color */\ |
325 | | p_decode_color, /* decode_color */\ |
326 | | NULL, /* pattern_manage */\ |
327 | | NULL, /* fill_rectangle_hl_color */\ |
328 | | NULL, /* include_color_space */\ |
329 | | NULL, /* fill_linear_color_scanline */\ |
330 | | NULL, /* fill_linear_color_trapezoid */\ |
331 | | NULL, /* fill_linear_color_triangle */\ |
332 | | NULL, /* update spot */\ |
333 | | NULL, /* DevN params */\ |
334 | | NULL, /* fill page */\ |
335 | | NULL, /* push_transparency_state */\ |
336 | | NULL, /* pop_transparency_state */\ |
337 | | NULL, /* put_image */\ |
338 | | NULL /* dev_spec_op */\ |
339 | | } |
340 | | |
341 | | static const gx_device_procs plibm_procs = |
342 | | pgpm_procs(NULL, gdev_prn_map_rgb_color, gdev_prn_map_color_rgb); |
343 | | static const gx_device_procs plibg_procs = |
344 | | pgpm_procs(NULL, plibg_encode_color, plibg_decode_color); |
345 | | static const gx_device_procs plib_procs = |
346 | | pgpm_procs(NULL, gx_default_rgb_map_rgb_color, plib_decode_color); |
347 | | static const gx_device_procs plibc_procs = |
348 | | pgpm_procs(plibc_map_color_rgb, plibc_encode_color, plibc_decode_color); |
349 | | static const gx_device_procs plibk_procs = |
350 | | pgpm_procs(plibc_map_color_rgb, plibc_encode_color, plibc_decode_color); |
351 | | |
352 | | /* Macro for generating device descriptors. */ |
353 | | /* Ideally we'd use something like: |
354 | | * #define plib_prn_device(procs, dev_name, num_comp, depth, max_gray, max_rgb, print_page) \ |
355 | | * { prn_device_body(gx_device_plib, procs, dev_name,\ |
356 | | * DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, X_DPI, Y_DPI,\ |
357 | | * 0, 0, 0, 0,\ |
358 | | * num_comp, depth, max_gray, max_rgb, max_gray + 1, max_rgb + 1,\ |
359 | | * print_page)\ |
360 | | * } |
361 | | * But that doesn't let us override the band space params. So we have to do |
362 | | * it the large way. |
363 | | */ |
364 | | #define plib_prn_device(procs, dev_name, num_comp, depth, max_gray, max_rgb, print_page) \ |
365 | | { std_device_full_body_type(gx_device_plib, &procs, dev_name, &st_device_printer,\ |
366 | | (int)((float)(DEFAULT_WIDTH_10THS) * (X_DPI) / 10 + 0.5),\ |
367 | | (int)((float)(DEFAULT_HEIGHT_10THS) * (Y_DPI) / 10 + 0.5),\ |
368 | | X_DPI, Y_DPI,\ |
369 | | num_comp, depth, max_gray, max_rgb, max_gray + 1, max_rgb + 1,\ |
370 | | (float)(0), (float)(0),\ |
371 | | (float)(0), (float)(0),\ |
372 | | (float)(0), (float)(0)\ |
373 | | ),\ |
374 | | prn_device_body_rest2_(print_page, gx_default_print_page_copies, -1)} |
375 | | |
376 | | /* The device descriptors themselves */ |
377 | | const gx_device_plib gs_plib_device = |
378 | | plib_prn_device(plib_procs, "plib", 3, 24, 255, 255, plib_print_page); |
379 | | const gx_device_plib gs_plibg_device = |
380 | | plib_prn_device(plibg_procs, "plibg", 1, 8, 255, 0, plibg_print_page); |
381 | | const gx_device_plib gs_plibm_device = |
382 | | plib_prn_device(plibm_procs, "plibm", 1, 1, 1, 0, plibm_print_page); |
383 | | const gx_device_plib gs_plibk_device = |
384 | | plib_prn_device(plibk_procs, "plibk", 4, 4, 1, 1, plibk_print_page); |
385 | | const gx_device_plib gs_plibc_device = |
386 | | plib_prn_device(plibc_procs, "plibc", 4, 32, 255, 255, plibc_print_page); |
387 | | |
388 | | /* ------ Initialization ------ */ |
389 | | |
390 | | /* |
391 | | * We need to create custom memory buffer devices that just point into the |
392 | | * bandBuffer we've got from the digicolor system. |
393 | | */ |
394 | | static byte *bandBufferBase = NULL; |
395 | | static int bandBufferStride = 0; |
396 | | |
397 | | #ifdef DEBUG_DUMP |
398 | | static int dump_w; |
399 | | static int dump_nc; |
400 | | static int dump_l2bits; |
401 | | |
402 | | static void dump_start(int w, int h, int num_comps, int log2bits, |
403 | | gp_file *dump_file) |
404 | 0 | { |
405 | 0 | if ((num_comps == 3) && (log2bits == 3)) { |
406 | | /* OK */ |
407 | 0 | } else if ((num_comps == 1) && (log2bits == 0)) { |
408 | | /* OK */ |
409 | 0 | } else if ((num_comps == 1) && (log2bits == 3)) { |
410 | | /* OK */ |
411 | 0 | } else if ((num_comps == 4) && (log2bits == 0)) { |
412 | | /* OK */ |
413 | 0 | } else if ((num_comps == 4) && (log2bits == 3)) { |
414 | | /* OK */ |
415 | 0 | } else |
416 | 0 | return; |
417 | 0 | dump_nc = num_comps; |
418 | 0 | dump_l2bits = log2bits; |
419 | 0 | if (dump_file == NULL) |
420 | 0 | return; |
421 | 0 | if (dump_nc == 3) |
422 | 0 | gp_fprintf(dump_file, "P6 %d %d 255\n", w, h); |
423 | 0 | else if (dump_nc == 4) { |
424 | 0 | gp_fprintf(dump_file, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 4\n" |
425 | 0 | "MAXVAL 255\nTUPLTYPE CMYK\nENDHDR\n", w, h); |
426 | 0 | } else if (log2bits == 0) |
427 | 0 | gp_fprintf(dump_file, "P4 %d %d\n", w, h); |
428 | 0 | else |
429 | 0 | gp_fprintf(dump_file, "P5 %d %d 255\n", w, h); |
430 | 0 | dump_w = w; |
431 | 0 | } |
432 | | |
433 | | static void dump_band(int y, gp_file *dump_file) |
434 | 0 | { |
435 | 0 | byte *r = bandBufferBase; |
436 | 0 | byte *g = r + bandBufferStride; |
437 | 0 | byte *b = g + bandBufferStride; |
438 | 0 | byte *k = b + bandBufferStride; |
439 | |
|
440 | 0 | if (dump_file == NULL) |
441 | 0 | return; |
442 | 0 | if (dump_nc == 3) { |
443 | 0 | while (y--) { |
444 | 0 | int w = dump_w; |
445 | 0 | while (w--) { |
446 | 0 | gp_fputc(*r++, dump_file); |
447 | 0 | gp_fputc(*g++, dump_file); |
448 | 0 | gp_fputc(*b++, dump_file); |
449 | 0 | } |
450 | 0 | r += bandBufferStride*3-dump_w; |
451 | 0 | g += bandBufferStride*3-dump_w; |
452 | 0 | b += bandBufferStride*3-dump_w; |
453 | 0 | } |
454 | 0 | } else if (dump_nc == 4) { |
455 | 0 | if (dump_l2bits == 0) { |
456 | 0 | while (y--) { |
457 | 0 | int w = dump_w; |
458 | 0 | while (w) { |
459 | 0 | byte C = *r++; |
460 | 0 | byte M = *g++; |
461 | 0 | byte Y = *b++; |
462 | 0 | byte K = *k++; |
463 | 0 | int s; |
464 | 0 | for (s=7; s>=0; s--) { |
465 | 0 | gp_fputc(255*((C>>s)&1), dump_file); |
466 | 0 | gp_fputc(255*((M>>s)&1), dump_file); |
467 | 0 | gp_fputc(255*((Y>>s)&1), dump_file); |
468 | 0 | gp_fputc(255*((K>>s)&1), dump_file); |
469 | 0 | w--; |
470 | 0 | if (w == 0) break; |
471 | 0 | } |
472 | 0 | } |
473 | 0 | r += bandBufferStride*4-((dump_w+7)>>3); |
474 | 0 | g += bandBufferStride*4-((dump_w+7)>>3); |
475 | 0 | b += bandBufferStride*4-((dump_w+7)>>3); |
476 | 0 | k += bandBufferStride*4-((dump_w+7)>>3); |
477 | 0 | } |
478 | 0 | } else { |
479 | 0 | while (y--) { |
480 | 0 | int w = dump_w; |
481 | 0 | while (w--) { |
482 | 0 | gp_fputc(*r++, dump_file); |
483 | 0 | gp_fputc(*g++, dump_file); |
484 | 0 | gp_fputc(*b++, dump_file); |
485 | 0 | gp_fputc(*k++, dump_file); |
486 | 0 | } |
487 | 0 | r += bandBufferStride*4-dump_w; |
488 | 0 | g += bandBufferStride*4-dump_w; |
489 | 0 | b += bandBufferStride*4-dump_w; |
490 | 0 | k += bandBufferStride*4-dump_w; |
491 | 0 | } |
492 | 0 | } |
493 | 0 | } else { |
494 | 0 | if (dump_l2bits == 0) { |
495 | 0 | while (y--) { |
496 | 0 | int w = (dump_w+7)>>3; |
497 | 0 | while (w--) { |
498 | 0 | gp_fputc(*r++, dump_file); |
499 | 0 | } |
500 | 0 | r += bandBufferStride - ((dump_w+7)>>3); |
501 | 0 | } |
502 | 0 | } else { |
503 | 0 | while (y--) { |
504 | 0 | int w = dump_w; |
505 | 0 | while (w--) { |
506 | 0 | gp_fputc(*r++, dump_file); |
507 | 0 | } |
508 | 0 | r += bandBufferStride - dump_w; |
509 | 0 | } |
510 | 0 | } |
511 | 0 | } |
512 | 0 | } |
513 | | #endif |
514 | | |
515 | | int |
516 | | plib_put_params(gx_device * pdev, gs_param_list * plist) |
517 | 0 | { |
518 | 0 | int ecode = 0; |
519 | 0 | int code; |
520 | 0 | gx_device_printer * const ppdev = (gx_device_printer *)pdev; |
521 | | |
522 | | /* Assumed to be valid on entry - remember it */ |
523 | 0 | int bandHeight = ppdev->space_params.band.BandHeight; |
524 | |
|
525 | 0 | code = gdev_prn_put_params(pdev, plist); |
526 | | /* Note that 0 means "default". This will encounter a future check in "open" */ |
527 | 0 | if (ppdev->space_params.band.BandHeight != 0 && |
528 | 0 | ppdev->space_params.band.BandHeight < MINBANDHEIGHT) { |
529 | 0 | emprintf2(pdev->memory, "BandHeight of %d not valid, BandHeight minimum is %d\n", |
530 | 0 | ppdev->space_params.band.BandHeight, MINBANDHEIGHT); |
531 | 0 | ecode = gs_error_rangecheck; |
532 | | /* Restore to the previous (possibly default == 0) value */ |
533 | 0 | ppdev->space_params.band.BandHeight = bandHeight; |
534 | 0 | } |
535 | 0 | if (ecode >= 0) |
536 | 0 | ecode = code; |
537 | 0 | return ecode; |
538 | 0 | } |
539 | | |
540 | | /* |
541 | | * Set up the scan line pointers of a memory device. |
542 | | * See gxdevmem.h for the detailed specification. |
543 | | * Sets or uses line_ptrs, base, raster; uses width, color_info.depth, |
544 | | * num_planes, plane_depths, plane_depth. |
545 | | */ |
546 | | static int |
547 | | set_line_ptrs(gx_device_memory * mdev, byte * base, int raster, |
548 | | byte **line_ptrs, int setup_height) |
549 | 0 | { |
550 | 0 | int num_planes = mdev->color_info.num_components; |
551 | 0 | int pi; |
552 | |
|
553 | 0 | if (num_planes) { |
554 | 0 | if (base && !mdev->plane_depth) |
555 | 0 | return_error(gs_error_rangecheck); |
556 | 0 | } else { |
557 | 0 | num_planes = 1; |
558 | 0 | } |
559 | 0 | if (line_ptrs) { |
560 | 0 | mdev->line_ptrs = line_ptrs; |
561 | 0 | for (pi = 0; pi < num_planes; ++pi) { |
562 | 0 | byte **pend = line_ptrs + setup_height; |
563 | 0 | byte *scan_line = base; |
564 | |
|
565 | 0 | while (line_ptrs < pend) { |
566 | 0 | *line_ptrs++ = scan_line; |
567 | 0 | scan_line += raster * num_planes; |
568 | 0 | } |
569 | 0 | base += raster; |
570 | 0 | } |
571 | 0 | } |
572 | |
|
573 | 0 | return 0; |
574 | 0 | } |
575 | | |
576 | | static int |
577 | | plib_setup_buf_device(gx_device *bdev, byte *buffer, int bytes_per_line, |
578 | | byte **line_ptrs, int y, int setup_height, |
579 | | int full_height) |
580 | 0 | { |
581 | 0 | gx_device_memory *mdev = (gx_device_memory *)bdev; |
582 | 0 | int code; |
583 | | |
584 | | /* buffer is the buffer used by clist writing. We could use that as the |
585 | | * page buffer, but we'd rather use the buffer given to us by the |
586 | | * digicolor code. b */ |
587 | |
|
588 | 0 | if (line_ptrs == NULL) { |
589 | | /* Free any existing line pointers array */ |
590 | 0 | if (mdev->line_ptrs != NULL) |
591 | 0 | gs_free_object(mdev->line_pointer_memory, mdev->line_ptrs, |
592 | 0 | "mem_close"); |
593 | | /* |
594 | | * Allocate line pointers now; free them when we close the device. |
595 | | * Note that for multi-planar devices, we have to allocate using |
596 | | * full_height rather than setup_height. |
597 | | */ |
598 | 0 | line_ptrs = (byte **) |
599 | 0 | gs_alloc_byte_array(mdev->memory, |
600 | 0 | (mdev->is_planar ? |
601 | 0 | full_height * mdev->color_info.num_components : |
602 | 0 | setup_height), |
603 | 0 | sizeof(byte *), "setup_buf_device"); |
604 | 0 | if (line_ptrs == 0) |
605 | 0 | return_error(gs_error_VMerror); |
606 | 0 | mdev->line_pointer_memory = mdev->memory; |
607 | 0 | mdev->foreign_line_pointers = false; |
608 | 0 | mdev->line_ptrs = line_ptrs; |
609 | 0 | mdev->raster = bandBufferStride * (mdev->is_planar ? mdev->color_info.num_components : 1); |
610 | 0 | } |
611 | 0 | mdev->height = full_height; |
612 | 0 | code = set_line_ptrs(mdev, |
613 | 0 | bandBufferBase + bandBufferStride*(mdev->is_planar ? mdev->color_info.num_components : 1)*y, |
614 | 0 | bandBufferStride, |
615 | 0 | line_ptrs, |
616 | 0 | setup_height); |
617 | 0 | mdev->height = setup_height; |
618 | 0 | bdev->height = setup_height; /* do here in case mdev == bdev */ |
619 | 0 | return code; |
620 | 0 | } |
621 | | |
622 | | static int |
623 | | plib_get_bits_rectangle_mem(gx_device *pdev, const gs_int_rect *prect, |
624 | | gs_get_bits_params_t *params, gs_int_rect **pprect) |
625 | 0 | { |
626 | 0 | gx_device_memory *mdev = (gx_device_memory *)pdev; |
627 | 0 | int x = prect->p.x, y = prect->p.y, h = prect->q.y - y; |
628 | | /* First off, see if we can satisfy get_bits_rectangle with just returning |
629 | | * pointers to the existing data. */ |
630 | 0 | { |
631 | 0 | gs_get_bits_params_t copy_params; |
632 | 0 | byte **base = &scan_line_base(mdev, y); |
633 | 0 | int code; |
634 | |
|
635 | 0 | copy_params.options = |
636 | 0 | GB_COLORS_NATIVE | GB_PACKING_PLANAR | GB_ALPHA_NONE | |
637 | 0 | (mdev->raster == |
638 | 0 | bitmap_raster(mdev->width * mdev->color_info.depth) ? |
639 | 0 | GB_RASTER_STANDARD : GB_RASTER_SPECIFIED); |
640 | 0 | copy_params.raster = mdev->raster; |
641 | 0 | code = gx_get_bits_return_pointer(pdev, x, h, params, |
642 | 0 | ©_params, base); |
643 | 0 | if (code >= 0) |
644 | 0 | return code; |
645 | 0 | } |
646 | 0 | return mem_get_bits_rectangle(pdev, prect, params, pprect); |
647 | 0 | } |
648 | | |
649 | | static int |
650 | | plib_create_buf_device(gx_device **pbdev, gx_device *target, int y, |
651 | | const gx_render_plane_t *render_plane, gs_memory_t *mem, |
652 | | gx_color_usage_t *color_usage) |
653 | 0 | { |
654 | 0 | int code = gdev_prn_create_buf_planar(pbdev, target, y, render_plane, |
655 | 0 | mem, color_usage); |
656 | 0 | if (code < 0) |
657 | 0 | return code; |
658 | 0 | if (dev_proc((*pbdev), get_bits_rectangle) == mem_get_bits_rectangle) |
659 | 0 | set_dev_proc((*pbdev), get_bits_rectangle, plib_get_bits_rectangle_mem); |
660 | 0 | return 0; |
661 | 0 | } |
662 | | |
663 | | static int |
664 | | plib_size_buf_device(gx_device_buf_space_t *space, gx_device *target, |
665 | | const gx_render_plane_t *render_plane, |
666 | | int height, bool for_band) |
667 | 0 | { |
668 | 0 | return gdev_prn_size_buf_planar(space, target, render_plane, |
669 | 0 | height, for_band); |
670 | 0 | } |
671 | | |
672 | | /* |
673 | | * Define a special open procedure that changes create_buf_device to use |
674 | | * a planar device. |
675 | | */ |
676 | | static int |
677 | | plib_open(gx_device * pdev) |
678 | 0 | { |
679 | 0 | gx_device_plib * const bdev = (gx_device_plib *)pdev; |
680 | 0 | gx_device_printer * const ppdev = (gx_device_printer *)pdev; |
681 | 0 | int code; |
682 | |
|
683 | | #ifdef DEBUG_PRINT |
684 | | emprintf(pdev->memory, "plib_open\n"); |
685 | | #endif |
686 | 0 | bdev->printer_procs.buf_procs.create_buf_device = plib_create_buf_device; |
687 | 0 | bdev->printer_procs.buf_procs.setup_buf_device = plib_setup_buf_device; |
688 | 0 | bdev->printer_procs.buf_procs.size_buf_device = plib_size_buf_device; |
689 | 0 | pdev->is_planar = 1; |
690 | |
|
691 | 0 | bdev->space_params.banding_type = BandingAlways; |
692 | | |
693 | | /* You might expect us to call gdev_prn_open_planar rather than |
694 | | * gdev_prn_open, but if we do that, it overwrites the 2 function |
695 | | * pointers we've just overwritten! */ |
696 | 0 | code = gdev_prn_open(pdev); |
697 | 0 | if (code < 0) |
698 | 0 | return code; |
699 | 0 | if (ppdev->space_params.band.BandHeight < MINBANDHEIGHT) { |
700 | 0 | emprintf2(pdev->memory, "BandHeight of %d not valid, BandHeight minimum is %d\n", |
701 | 0 | ((gx_device_printer *)pdev)->space_params.band.BandHeight, |
702 | 0 | MINBANDHEIGHT); |
703 | |
|
704 | 0 | return_error(gs_error_rangecheck); |
705 | 0 | } |
706 | 0 | pdev->color_info.separable_and_linear = GX_CINFO_SEP_LIN; |
707 | 0 | set_linear_color_bits_mask_shift(pdev); |
708 | | |
709 | | /* Start the actual job. */ |
710 | | #ifdef DEBUG_PRINT |
711 | | emprintf(pdev->memory, "calling job_begin\n"); |
712 | | #endif |
713 | 0 | code = gs_band_donor_init(&bdev->opaque, pdev->memory); |
714 | | #ifdef DEBUG_PRINT |
715 | | emprintf(pdev->memory, "called\n"); |
716 | | #endif |
717 | |
|
718 | 0 | return code; |
719 | 0 | } |
720 | | |
721 | | static int |
722 | | plib_close(gx_device *pdev) |
723 | 0 | { |
724 | 0 | gx_device_plib *pldev = (gx_device_plib *)pdev; |
725 | |
|
726 | | #ifdef DEBUG_PRINT |
727 | | emprintf(pdev->memory, "plib_close\n"); |
728 | | #endif |
729 | 0 | gs_band_donor_fin(pldev->opaque); |
730 | 0 | pldev->opaque = NULL; |
731 | |
|
732 | 0 | return gdev_prn_close(pdev); |
733 | 0 | } |
734 | | |
735 | | /* ------ Color mapping routines ------ */ |
736 | | |
737 | | /* Map an RGB color to a gray value. */ |
738 | | static gx_color_index |
739 | | plibg_encode_color(gx_device * pdev, const gx_color_value cv[]) |
740 | 0 | { /* We round the value rather than truncating it. */ |
741 | 0 | gx_color_value gray; |
742 | 0 | gx_color_value r, g, b; |
743 | |
|
744 | 0 | r = cv[0]; g = cv[0]; b = cv[0]; |
745 | 0 | gray = ((r * (ulong) lum_red_weight) + |
746 | 0 | (g * (ulong) lum_green_weight) + |
747 | 0 | (b * (ulong) lum_blue_weight) + |
748 | 0 | (lum_all_weights / 2)) / lum_all_weights |
749 | 0 | * pdev->color_info.max_gray / gx_max_color_value; |
750 | |
|
751 | 0 | return gray; |
752 | 0 | } |
753 | | |
754 | | /* Map a gray value back to an RGB color. */ |
755 | | static int |
756 | | plibg_decode_color(gx_device * dev, gx_color_index color, |
757 | | gx_color_value prgb[3]) |
758 | 0 | { |
759 | 0 | gx_color_value gray = |
760 | 0 | color * gx_max_color_value / dev->color_info.max_gray; |
761 | |
|
762 | 0 | prgb[0] = gray; |
763 | 0 | prgb[1] = gray; |
764 | 0 | prgb[2] = gray; |
765 | 0 | return 0; |
766 | 0 | } |
767 | | |
768 | | /* Map an rgb color tuple back to an RGB color. */ |
769 | | static int |
770 | | plib_decode_color(gx_device * dev, gx_color_index color, |
771 | | gx_color_value prgb[3]) |
772 | 0 | { |
773 | 0 | uint bitspercolor = dev->color_info.depth / 3; |
774 | 0 | uint colormask = (1 << bitspercolor) - 1; |
775 | 0 | uint max_rgb = dev->color_info.max_color; |
776 | |
|
777 | 0 | prgb[0] = ((color >> (bitspercolor * 2)) & colormask) * |
778 | 0 | (ulong) gx_max_color_value / max_rgb; |
779 | 0 | prgb[1] = ((color >> bitspercolor) & colormask) * |
780 | 0 | (ulong) gx_max_color_value / max_rgb; |
781 | 0 | prgb[2] = (color & colormask) * |
782 | 0 | (ulong) gx_max_color_value / max_rgb; |
783 | 0 | return 0; |
784 | 0 | } |
785 | | |
786 | | /* Map a cmyk color tuple back to CMYK colorants. */ |
787 | | static int |
788 | | plibc_decode_color(gx_device * dev, gx_color_index color, |
789 | | gx_color_value prgb[4]) |
790 | 0 | { |
791 | 0 | uint bitspercolor = dev->color_info.depth / 4; |
792 | 0 | uint colormask = (1 << bitspercolor) - 1; |
793 | 0 | uint c, m, y, k; |
794 | |
|
795 | 0 | #define cvalue(c) ((gx_color_value)((ulong)(c) * gx_max_color_value / colormask)) |
796 | |
|
797 | 0 | k = color & colormask; |
798 | 0 | color >>= bitspercolor; |
799 | 0 | y = color & colormask; |
800 | 0 | color >>= bitspercolor; |
801 | 0 | m = color & colormask; |
802 | 0 | c = color >> bitspercolor; |
803 | 0 | prgb[0] = cvalue(c); |
804 | 0 | prgb[1] = cvalue(m); |
805 | 0 | prgb[2] = cvalue(y); |
806 | 0 | prgb[3] = cvalue(k); |
807 | 0 | return 0; |
808 | 0 | } |
809 | | |
810 | | /* Map CMYK to color. */ |
811 | | static gx_color_index |
812 | | plibc_encode_color(gx_device * dev, const gx_color_value cv[]) |
813 | 0 | { |
814 | 0 | int bpc = dev->color_info.depth / 4; |
815 | 0 | gx_color_index color; |
816 | 0 | COLROUND_VARS; |
817 | |
|
818 | 0 | COLROUND_SETUP(bpc); |
819 | 0 | color = ((((((COLROUND_ROUND(cv[0]) << bpc) + |
820 | 0 | COLROUND_ROUND(cv[1])) << bpc) + |
821 | 0 | COLROUND_ROUND(cv[2])) << bpc) + |
822 | 0 | COLROUND_ROUND(cv[3])); |
823 | | |
824 | | /* The bitcmyk device does this: |
825 | | * return (color == gx_no_color_index ? color ^ 1 : color); |
826 | | * But I don't understand why. |
827 | | */ |
828 | 0 | return color; |
829 | 0 | } |
830 | | |
831 | | /* Map a cmyk color back to an rgb tuple. */ |
832 | | static int |
833 | | plibc_map_color_rgb(gx_device * dev, gx_color_index color, |
834 | | gx_color_value prgb[3]) |
835 | 0 | { |
836 | 0 | uint bitspercolor = dev->color_info.depth / 4; |
837 | 0 | uint colormask = (1 << bitspercolor) - 1; |
838 | 0 | uint c, m, y, k; |
839 | |
|
840 | 0 | #define cvalue(c) ((gx_color_value)((ulong)(c) * gx_max_color_value / colormask)) |
841 | |
|
842 | 0 | k = color & colormask; |
843 | 0 | color >>= bitspercolor; |
844 | 0 | y = color & colormask; |
845 | 0 | color >>= bitspercolor; |
846 | 0 | m = color & colormask; |
847 | 0 | c = color >> bitspercolor; |
848 | 0 | k = colormask - k; |
849 | 0 | prgb[0] = cvalue((colormask - c) * k / colormask); |
850 | 0 | prgb[1] = cvalue((colormask - m) * k / colormask); |
851 | 0 | prgb[2] = cvalue((colormask - y) * k / colormask); |
852 | 0 | return 0; |
853 | 0 | } |
854 | | |
855 | | /* ------ Internal routines ------ */ |
856 | | |
857 | | /* Print a page using a given row printing routine. */ |
858 | | static int |
859 | | plib_print_page_loop(gx_device_printer * pdev, int log2bits, int numComps, |
860 | | gp_file *pstream) |
861 | 0 | { |
862 | 0 | gx_device_plib *pldev = (gx_device_plib *)pdev; |
863 | 0 | int lnum; |
864 | 0 | int code = 0; |
865 | 0 | byte *buffer; |
866 | 0 | int stride = bitmap_raster(pdev->width * (1<<log2bits)); |
867 | 0 | int bandHeight = pdev->space_params.band.BandHeight; |
868 | |
|
869 | | #ifdef DEBUG_PRINT |
870 | | emprintf(pdev->memory, "Calling page_begin\n"); |
871 | | #endif |
872 | 0 | buffer = gs_band_donor_band_get(pldev->opaque, |
873 | 0 | pdev->width, |
874 | 0 | pdev->height, |
875 | 0 | 1<<log2bits, |
876 | 0 | numComps, |
877 | 0 | stride, |
878 | 0 | bandHeight); |
879 | | #ifdef DEBUG_PRINT |
880 | | emprintf1(pdev->memory, "Called page_begin %x\n", buffer); |
881 | | #endif |
882 | 0 | if (buffer == NULL) |
883 | 0 | return_error(gs_error_VMerror); |
884 | | |
885 | | /* Write these into the globals here so the setup_buf_device code can |
886 | | * find it later. Nasty. */ |
887 | 0 | bandBufferBase = buffer; |
888 | 0 | bandBufferStride = stride; |
889 | |
|
890 | 0 | #ifdef DEBUG_DUMP |
891 | 0 | dump_start(pdev->width, pdev->height, numComps, log2bits, pstream); |
892 | 0 | #endif |
893 | 0 | for (lnum = 0; lnum < pdev->height; lnum += bandHeight) { |
894 | 0 | gs_int_rect *unread, rect; |
895 | 0 | gs_get_bits_params_t params; |
896 | |
|
897 | 0 | rect.p.x = 0; |
898 | 0 | rect.p.y = lnum; |
899 | 0 | rect.q.x = pdev->width; |
900 | 0 | rect.q.y = lnum+bandHeight; |
901 | 0 | if (rect.q.y > pdev->height) |
902 | 0 | rect.q.y = pdev->height; |
903 | 0 | memset(¶ms, 0, sizeof(params)); |
904 | 0 | params.options = GB_ALIGN_ANY | |
905 | 0 | GB_RETURN_POINTER | |
906 | 0 | GB_OFFSET_0 | |
907 | 0 | GB_RASTER_STANDARD | |
908 | 0 | GB_PACKING_PLANAR | |
909 | 0 | GB_COLORS_NATIVE | |
910 | 0 | GB_ALPHA_NONE; |
911 | 0 | params.x_offset = 0; |
912 | 0 | code = (*dev_proc(pdev, get_bits_rectangle))((gx_device *)pdev, &rect, ¶ms,&unread); |
913 | 0 | if (code < 0) |
914 | 0 | break; |
915 | 0 | #ifdef DEBUG_DUMP |
916 | 0 | dump_band(rect.q.y-rect.p.y, pstream); |
917 | 0 | #endif |
918 | | #ifdef DEBUG_PRINT |
919 | | emprintf3(pdev->memory, "Calling band_full (%d->%d) of %d\n", |
920 | | rect.p.y, rect.q.y, pdev->height); |
921 | | #endif |
922 | 0 | gs_band_donor_band_full(pldev->opaque, rect.q.y-rect.p.y); |
923 | | #ifdef DEBUG_PRINT |
924 | | emprintf(pdev->memory, "Called band_full\n"); |
925 | | #endif |
926 | 0 | } |
927 | | #ifdef DEBUG_PRINT |
928 | | emprintf(pdev->memory, "Calling band_release\n"); |
929 | | #endif |
930 | 0 | gs_band_donor_band_release(pldev->opaque); |
931 | | #ifdef DEBUG_PRINT |
932 | | emprintf(pdev->memory, "Called band_release\n"); |
933 | | #endif |
934 | 0 | return (code < 0 ? code : 0); |
935 | 0 | } |
936 | | |
937 | | /* ------ Individual page printing routines ------ */ |
938 | | |
939 | | /* Print a monobit page. */ |
940 | | static int |
941 | | plibm_print_page(gx_device_printer * pdev, gp_file * pstream) |
942 | 0 | { |
943 | | #ifdef DEBUG_PRINT |
944 | | emprintf(pdev->memory, "plibm_print_page\n"); |
945 | | #endif |
946 | 0 | return plib_print_page_loop(pdev, 0, 1, pstream); |
947 | 0 | } |
948 | | |
949 | | /* Print a gray-mapped page. */ |
950 | | static int |
951 | | plibg_print_page(gx_device_printer * pdev, gp_file * pstream) |
952 | 0 | { |
953 | | #ifdef DEBUG_PRINT |
954 | | emprintf(pdev->memory, "plibg_print_page\n"); |
955 | | #endif |
956 | 0 | return plib_print_page_loop(pdev, 3, 1, pstream); |
957 | 0 | } |
958 | | |
959 | | /* Print a color-mapped page. */ |
960 | | static int |
961 | | plib_print_page(gx_device_printer * pdev, gp_file * pstream) |
962 | 0 | { |
963 | | #ifdef DEBUG_PRINT |
964 | | emprintf(pdev->memory, "plibc_print_page\n"); |
965 | | #endif |
966 | 0 | return plib_print_page_loop(pdev, 3, 3, pstream); |
967 | 0 | } |
968 | | |
969 | | /* Print a 1 bit CMYK page. */ |
970 | | static int |
971 | | plibk_print_page(gx_device_printer * pdev, gp_file * pstream) |
972 | 0 | { |
973 | | #ifdef DEBUG_PRINT |
974 | | emprintf(pdev->memory, "plibk_print_page\n"); |
975 | | #endif |
976 | 0 | return plib_print_page_loop(pdev, 0, 4, pstream); |
977 | 0 | } |
978 | | |
979 | | /* Print an 8bpc CMYK page. */ |
980 | | static int |
981 | | plibc_print_page(gx_device_printer * pdev, gp_file * pstream) |
982 | 0 | { |
983 | | #ifdef DEBUG_PRINT |
984 | | emprintf(pdev->memory, "plibc_print_page\n"); |
985 | | #endif |
986 | 0 | return plib_print_page_loop(pdev, 3, 4, pstream); |
987 | 0 | } |