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