Coverage Report

Created: 2025-04-22 06:20

/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
                                          &copy_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(&params, 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, &params,&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
}