Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/contrib/pcl3/eprn/eprnrend.c
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
  File:     $Id: eprnrend.c,v 1.15 2001/08/01 05:12:56 Martin Rel $
3
  Contents: Colour rendering functionality for the ghostscript device 'eprn'
4
  Author:   Martin Lottermoser, Greifswaldstrasse 28, 38124 Braunschweig,
5
            Germany. E-mail: Martin.Lottermoser@t-online.de.
6
7
*******************************************************************************
8
*                       *
9
* Copyright (C) 2000, 2001 by Martin Lottermoser            *
10
* All rights reserved                 *
11
*                       *
12
*******************************************************************************
13
14
  Preprocessor variables:
15
16
    EPRN_TRACE
17
        Define this to enable tracing. Only useful for development.
18
19
    EPRN_TRAILING_BIT_BUG_FIXED
20
        Define this to deactivate compensation for a bug in ghostscript which
21
        leads to the last pixel in an RGB line being black instead of white.
22
        This occurs at least in gs 6.01 and 6.50. The correction covers only
23
        the one-bit-per-colorant case and is equivalent to clipping the pixel.
24
25
*******************************************************************************
26
27
  The eprn device uses 'gx_color_index' values with varying interpretations,
28
  depending on the colour model and the rendering method, and stores them at
29
  different pixmaps depths, normally using the smallest depth which can
30
  accommodate all colorants at the same number of bits per colorant.
31
32
  To simplify matters, a field for the black component is always included, even
33
  for RGB and CMY, i.e., there are either 1 or 4 bit fields in a
34
  'gx_color_index' value. If there are 4, the interpretation is either YMCK or
35
  BGRK, looking from left to right (most to least significant). The width of
36
  the fields can be found in the 'bits_per_colorant' variable in the eprn part
37
  of the device instance.
38
39
  Within each colorant field, not all bits need be used. Except when using the
40
  *_max() colour mapping functions, the values returned by
41
  eprn_bits_for_levels() for the parameters 'black_levels' and
42
  'non_black_levels' determine the number of bits which are actually
43
  meaningful. Only the last (least significant) bits are used.
44
45
******************************************************************************/
46
47
/*****************************************************************************/
48
49
#ifndef _XOPEN_SOURCE
50
#define _XOPEN_SOURCE 500
51
#endif
52
53
/* Special Aladdin header, must be included before <sys/types.h> on some
54
   platforms (e.g., FreeBSD). */
55
#include "std.h"
56
57
/* Standard headers */
58
#include "assert_.h"
59
#include <stdlib.h>
60
61
/* Ghostscript headers */
62
#ifdef EPRN_TRACE
63
#include "gdebug.h"
64
#endif  /* EPRN_TRACE */
65
66
/* Special headers */
67
#include "gdeveprn.h"
68
69
/*****************************************************************************/
70
71
/* Macros for 'gx_color_index' values used mainly for non-monochrome modes and
72
   a pixmap depth of 4 */
73
74
/* Colorants bits, numbered from 0 on the right to 3 on the left */
75
0
#define COLORANT_0_BIT  1U
76
0
#define COLORANT_1_BIT  2U
77
0
#define COLORANT_2_BIT  4U
78
0
#define COLORANT_3_BIT  8U
79
80
/* Alias names for the bits in particular colour models */
81
0
#define BLACK_BIT COLORANT_0_BIT
82
0
#define CYAN_BIT  COLORANT_1_BIT
83
0
#define MAGENTA_BIT COLORANT_2_BIT
84
0
#define YELLOW_BIT  COLORANT_3_BIT
85
0
#define RED_BIT   COLORANT_1_BIT
86
0
#define GREEN_BIT COLORANT_2_BIT
87
0
#define BLUE_BIT  COLORANT_3_BIT
88
89
/* Bit plane indices for splitting */
90
0
#define COLORANT_0_INDEX  0
91
0
#define COLORANT_1_INDEX  1
92
0
#define COLORANT_2_INDEX  2
93
0
#define COLORANT_3_INDEX  3
94
95
/*  Macro to extract the dominant 8 bits from a 'gx_color_value'. This
96
    definition assumes that 'gx_color_value' uses the least significant 16 bits
97
    of the underlying type (unsigned short). Splitting this part off looks
98
    inefficient because left shifts will usually follow, but I'm relying on the
99
    compiler to be sufficiently intelligent to eliminate this inefficiency.
100
    This way the code is easier to check.
101
    The type cast is needed to prevent problems with negative values on
102
    platforms where 'gx_color_index' has more bits than 'int'.
103
 */
104
0
#define dominant_8bits(value) ((unsigned int)((value) >> 8))
105
106
/******************************************************************************
107
108
  Function: eprn_number_of_bitplanes
109
110
  Total number of bit planes returned by eprn_get_planes().
111
  This value is constant while the device is open.
112
113
******************************************************************************/
114
115
unsigned int eprn_number_of_bitplanes(eprn_Device *dev)
116
0
{
117
0
  return dev->eprn.output_planes;
118
0
}
119
120
/******************************************************************************
121
122
  Function: eprn_number_of_octets
123
124
  Maximal lengths, in terms of the number of 'eprn_Octet' instances, for each
125
  bit plane returned by eprn_get_planes() for this device. These values
126
  are constant while the device is open.
127
128
******************************************************************************/
129
130
void eprn_number_of_octets(eprn_Device *dev, unsigned int lenghts[])
131
0
{
132
0
  unsigned int j, length;
133
134
0
  length = (dev->eprn.octets_per_line + dev->color_info.depth - 1)/
135
0
      dev->color_info.depth;
136
   /* This results in length >= ceiling((number of pixels per line)/8)
137
      because:
138
              8 * octets_per_line >= pixels_per_line * depth
139
        <==>  octets_per_line/depth >= pixels_per_line/8
140
      where division is to be understood as exact.
141
    */
142
143
0
  for (j = 0; j < dev->eprn.output_planes; j++) lenghts[j] = length;
144
145
0
  return;
146
0
}
147
148
/******************************************************************************
149
150
  Function: eprn_map_rgb_color_for_RGB
151
152
  Colour mapping function for the process colour model 'DeviceRGB' and
153
  2 intensity levels per colorant.
154
155
******************************************************************************/
156
157
gx_color_index eprn_map_rgb_color_for_RGB(gx_device *device,
158
  const gx_color_value cv[])
159
0
{
160
0
  gx_color_value red = cv[0], green = cv[1], blue = cv[2];
161
0
  static const gx_color_value half = gx_max_color_value/2;
162
0
  gx_color_index value = 0;
163
164
#ifdef EPRN_TRACE
165
  if_debug3(EPRN_TRACE_CHAR,
166
    "! eprn_map_rgb_color_for_RGB() called for RGB = (%hu, %hu, %hu),\n",
167
    red, green, blue);
168
#endif
169
170
0
  assert(((eprn_Device *)device)->eprn.colour_model == eprn_DeviceRGB);
171
172
0
  if (red   > half) value |= RED_BIT;
173
0
  if (green > half) value |= GREEN_BIT;
174
0
  if (blue  > half) value |= BLUE_BIT;
175
176
#ifdef EPRN_TRACE
177
  if_debug1(EPRN_TRACE_CHAR, "  returning 0x%lX.\n", (unsigned long)value);
178
#endif
179
0
  return value;
180
0
}
181
182
/******************************************************************************
183
184
  Function: eprn_map_rgb_color_for_CMY_or_K
185
186
  Colour mapping function for the native colour spaces DeviceGray and DeviceRGB
187
  and a process colour model using a selection of CMYK colorants with at most
188
  2 intensity levels per colorant. This function must not be called for the
189
  process colour models 'DeviceRGB' and 'DeviceCMYK'.
190
191
******************************************************************************/
192
193
gx_color_index eprn_map_rgb_color_for_CMY_or_K(gx_device *device,
194
  const gx_color_value cv[])
195
0
{
196
0
  gx_color_value red = cv[0], green = cv[1], blue = cv[2];
197
0
  static const gx_color_value half = gx_max_color_value/2;
198
0
  gx_color_index value = (CYAN_BIT | MAGENTA_BIT | YELLOW_BIT);
199
0
  const eprn_Device *dev = (eprn_Device *)device;
200
201
#ifdef EPRN_TRACE
202
  if_debug3(EPRN_TRACE_CHAR,
203
    "! eprn_map_rgb_color_for_CMY_or_K() called for RGB = (%hu, %hu, %hu),\n",
204
    red, green, blue);
205
#endif
206
207
0
  assert((dev->eprn.colour_model == eprn_DeviceGray && red == green &&
208
0
          green == blue && (blue == 0 || blue == gx_max_color_value)) ||
209
0
         dev->eprn.colour_model == eprn_DeviceCMY ||
210
0
         dev->eprn.colour_model == eprn_DeviceCMY_plus_K);
211
212
  /* Map to CMY */
213
0
  if (red   > half) value &= ~CYAN_BIT;
214
0
  if (green > half) value &= ~MAGENTA_BIT;
215
0
  if (blue  > half) value &= ~YELLOW_BIT;
216
217
  /* Remap composite black to true black if available */
218
0
  if (dev->eprn.colour_model != eprn_DeviceCMY &&
219
0
      value == (CYAN_BIT | MAGENTA_BIT | YELLOW_BIT))
220
0
    value = BLACK_BIT;
221
222
#ifdef EPRN_TRACE
223
  if_debug1(EPRN_TRACE_CHAR, "  returning 0x%lX.\n", (unsigned long)value);
224
#endif
225
0
  return value;
226
0
}
227
228
/******************************************************************************
229
230
  Function: eprn_map_rgb_color_for_RGB_flex
231
232
  This is a 'map_rgb_color' method for the process colour model 'DeviceRGB'
233
  supporting any number of intensity levels.
234
235
******************************************************************************/
236
237
gx_color_index eprn_map_rgb_color_for_RGB_flex(gx_device *device,
238
  const gx_color_value cv[])
239
0
{
240
0
  gx_color_value red = cv[0], green = cv[1], blue = cv[2];
241
0
  gx_color_index value = 0;
242
0
  gx_color_value step;
243
0
  gx_color_index level;
244
0
  const eprn_Eprn *eprn = &((eprn_Device *)device)->eprn;
245
246
#ifdef EPRN_TRACE
247
  if_debug3(EPRN_TRACE_CHAR,
248
    "! eprn_map_rgb_color_for_RGB_flex() called for RGB = (%hu, %hu, %hu),\n",
249
    red, green, blue);
250
#endif
251
252
  /* See the discussion in eprn_map_cmyk_color_flex() below. */
253
254
0
  step = gx_max_color_value/eprn->non_black_levels;
255
256
  /* The order has to be BGR from left to right */
257
0
  level = blue/step;
258
0
  if (level >= eprn->non_black_levels) level = eprn->non_black_levels - 1;
259
0
  value = level << eprn->bits_per_colorant;
260
0
  level = green/step;
261
0
  if (level >= eprn->non_black_levels) level = eprn->non_black_levels - 1;
262
0
  value = (value | level) << eprn->bits_per_colorant;
263
0
  level = red/step;
264
0
  if (level >= eprn->non_black_levels) level = eprn->non_black_levels - 1;
265
0
  value = (value | level) << eprn->bits_per_colorant;
266
267
#ifdef EPRN_TRACE
268
  if_debug1(EPRN_TRACE_CHAR, "  returning 0x%lX.\n", (unsigned long)value);
269
#endif
270
0
  return value;
271
0
}
272
273
/******************************************************************************
274
275
  Function: eprn_map_rgb_color_for_CMY_or_K_flex
276
277
  This is a flexible 'map_rgb_color' method. It must not be called for the
278
  process colour models 'DeviceRGB' and 'DeviceCMYK'.
279
280
******************************************************************************/
281
282
gx_color_index eprn_map_rgb_color_for_CMY_or_K_flex(gx_device *device,
283
  const gx_color_value cv[])
284
0
{
285
0
  gx_color_value red = cv[0], green = cv[1], blue = cv[2];
286
0
  const eprn_Device *dev = (eprn_Device *)device;
287
288
#ifdef EPRN_TRACE
289
  if_debug3(EPRN_TRACE_CHAR,
290
    "! eprn_map_rgb_color_for_CMY_or_K_flex() called for "
291
      "RGB = (%hu, %hu, %hu).\n",
292
    red, green, blue);
293
#endif
294
295
  /* Treat pure grey levels differently if we have black. This implies that for
296
     CMY+K only "true" grey shades will be printed with black ink, all others
297
     will be mixed from CMY. */
298
0
  gx_color_value tmpcv[4];
299
0
  if (dev->eprn.colour_model != eprn_DeviceCMY && red == green && green == blue) {
300
0
    tmpcv[0] = 0; tmpcv[1] = 0; tmpcv[2] = 0;
301
0
    tmpcv[3] = gx_max_color_value - red;
302
0
    return eprn_map_cmyk_color_flex(device, tmpcv);
303
304
0
  }
305
0
  tmpcv[0] = gx_max_color_value - red;
306
0
  tmpcv[1] = gx_max_color_value - green;
307
0
  tmpcv[2] = gx_max_color_value - blue;
308
0
  tmpcv[3] = 0;
309
0
  return eprn_map_cmyk_color_flex(device, tmpcv);
310
0
}
311
312
/******************************************************************************
313
314
  Function: eprn_map_rgb_color_for_RGB_max
315
316
  Colour mapping function for the process colour model 'DeviceRGB' retaining as
317
  much information as possible.
318
319
******************************************************************************/
320
321
gx_color_index eprn_map_rgb_color_for_RGB_max(gx_device *device,
322
  const gx_color_value cv[])
323
0
{
324
0
  gx_color_value red = cv[0], green = cv[1], blue = cv[2];
325
0
  gx_color_index value;
326
327
#ifdef EPRN_TRACE
328
  if_debug3(EPRN_TRACE_CHAR,
329
    "! eprn_map_rgb_color_for_RGB_max() called for RGB = (%hu, %hu, %hu),\n",
330
    red, green, blue);
331
#endif
332
333
0
  value  = dominant_8bits(red)   <<  8;
334
0
  value |= dominant_8bits(green) << 16;
335
0
  value |= dominant_8bits(blue)  << 24;
336
337
#ifdef EPRN_TRACE
338
  if_debug1(EPRN_TRACE_CHAR, "  returning 0x%08lX.\n", (unsigned long)value);
339
#endif
340
0
  return value;
341
0
}
342
343
/******************************************************************************
344
345
  Function: eprn_map_rgb_color_for_CMY_or_K_max
346
347
  "Maximal" colour mapping function for the process colour models "DeviceGray",
348
  "DeviceCMY", and "CMY+K".
349
350
******************************************************************************/
351
352
gx_color_index eprn_map_rgb_color_for_CMY_or_K_max(gx_device *device,
353
  const gx_color_value cv[])
354
0
{
355
0
  gx_color_value red = cv[0], green = cv[1], blue = cv[2];
356
0
  const eprn_Device *dev = (eprn_Device *)device;
357
358
#ifdef EPRN_TRACE
359
  if_debug3(EPRN_TRACE_CHAR,
360
    "! eprn_map_rgb_color_for_CMY_or_K_max() called for "
361
      "RGB = (%hu, %hu, %hu).\n",
362
    red, green, blue);
363
#endif
364
365
0
  gx_color_value tmpcv[4];
366
0
  if (dev->eprn.colour_model == eprn_DeviceGray) {
367
0
    tmpcv[0] = 0; tmpcv[1] = 0; tmpcv[2] = 0;
368
0
    tmpcv[3] = gx_max_color_value - red;
369
0
    return eprn_map_cmyk_color_max(device, tmpcv);
370
0
  }
371
  /* Note that the conversion from composite black to true black for CMY+K can
372
     only happen at the output pixel level, not here. */
373
0
  tmpcv[0] = gx_max_color_value - red;
374
0
  tmpcv[1] = gx_max_color_value - green;
375
0
  tmpcv[2] = gx_max_color_value - blue;
376
0
  tmpcv[3] = 0;
377
0
  return eprn_map_cmyk_color_max(device, tmpcv);
378
0
}
379
380
/******************************************************************************
381
382
  Function: eprn_map_color_rgb
383
384
  This function is a 'map_color_rgb' method.
385
386
  Such a method should return an RGB triple for the specified 'color'. This is
387
  apparently intended for devices supporting colour maps.
388
389
  The function param_HWColorMap() in gsdparam.c tries to compile such a
390
  colour map by calling this method repeatedly for all values from 0 to
391
  2^color_info.depth - 1, provided the depth is less than or equal to 8 and
392
  the process colour model is not DeviceCMYK. If the function for one of these
393
  values returns a negative code, the assumption seems to be that there is no
394
  such colour map. Because there is a default method which always returns zero,
395
  such a colour map is always constructed if a device does not implement its
396
  own 'map_color_rgb' method. This can be seen in the appearance of the
397
  "HWColorMap" page device parameter.
398
399
  The key purpose of this function is therefore to return a negative code.
400
401
******************************************************************************/
402
403
int eprn_map_color_rgb(gx_device *device, gx_color_index color,
404
  gx_color_value rgb[3])
405
0
{
406
#ifdef EPRN_TRACE
407
  if_debug1(EPRN_TRACE_CHAR,
408
    "! eprn_map_color_rgb() called for 0x%lX.\n", (unsigned long)color);
409
#endif
410
411
  /* Just to be safe we return defined values (white) */
412
0
  if (((eprn_Device *)device)->eprn.colour_model == eprn_DeviceRGB)
413
0
    rgb[0] = rgb[1] = rgb[2] = gx_max_color_value;
414
0
  else
415
0
    rgb[0] = rgb[1] = rgb[2] = 0;
416
417
0
  return -1;
418
0
}
419
420
/******************************************************************************
421
422
  Function: eprn_map_cmyk_color
423
424
  Colour mapping function for a process colour model of 'DeviceCMYK' with
425
  2 intensity levels for all colorants.
426
427
******************************************************************************/
428
429
gx_color_index eprn_map_cmyk_color(gx_device *device,
430
  const gx_color_value cv[])
431
0
{
432
0
  gx_color_value cyan = cv[0], magenta = cv[1], yellow = cv[2], black = cv[3];
433
0
  gx_color_index value = 0;
434
0
  static const gx_color_value threshold = gx_max_color_value/2;
435
436
#ifdef EPRN_TRACE
437
  if_debug4(EPRN_TRACE_CHAR,
438
    "! eprn_map_cmyk_color() called for CMYK = (%hu, %hu, %hu, %hu),\n",
439
      cyan, magenta, yellow, black);
440
#endif
441
442
0
  if (cyan    > threshold) value |= CYAN_BIT;
443
0
  if (magenta > threshold) value |= MAGENTA_BIT;
444
0
  if (yellow  > threshold) value |= YELLOW_BIT;
445
0
  if (black   > threshold) value |= BLACK_BIT;
446
447
#ifdef EPRN_TRACE
448
  if_debug1(EPRN_TRACE_CHAR, "  returning 0x%lX.\n", (unsigned long)value);
449
#endif
450
0
  return value;
451
0
}
452
453
/******************************************************************************
454
455
  Function: eprn_map_cmyk_color_flex
456
457
  This is a 'map_cmyk_color' method supporting arbitrary numbers of intensity
458
  levels. It may be called for every colour model except DeviceRGB. Colorants
459
  not present in the model will be ignored.
460
461
******************************************************************************/
462
463
gx_color_index eprn_map_cmyk_color_flex(gx_device *device,
464
  const gx_color_value cv[])
465
0
{
466
0
  gx_color_value cyan = cv[0], magenta = cv[1], yellow = cv[2], black = cv[3];
467
0
  gx_color_index value = 0;
468
0
  gx_color_value step;
469
0
  gx_color_index level;
470
0
  const eprn_Eprn *eprn = &((eprn_Device *)device)->eprn;
471
472
#ifdef EPRN_TRACE
473
  if_debug4(EPRN_TRACE_CHAR,
474
    "! eprn_map_cmyk_color_flex() called for CMYK = (%hu, %hu, %hu, %hu),\n",
475
      cyan, magenta, yellow, black);
476
#endif
477
478
  /*  I can think of three linear methods to extract discrete values from a
479
      continuous intensity in the range [0, 1]:
480
      (a) multiply by the number of levels minus 1 and truncate,
481
      (b) multiply by the number of levels minus 1 and round, and
482
      (c) multiply by the number of levels and truncate, except for an
483
          intensity of 1 in which case one returns the number of levels minus 1.
484
      For intensity values which can be represented exactly, i.e.,
485
486
        intensity = i/(levels-1)  for some non-negative i < levels,
487
488
      these three methods are identical. (a) is however inappropriate here
489
      because for less than 32 levels ghostscript already provides intensity
490
      values which have been adjusted to a representable level. A rounding
491
      error could now result in a level which is too small by one. I prefer (c)
492
      because it gives equal shares to all levels.
493
494
      I'm using integer arithmetic here although floating point numbers would
495
      be more accurate. This routine may, however, be called quite frequently,
496
      and the loss in accuray is acceptable as long as the values determined
497
      for 'step' are large compared to the number of levels. If you consider
498
      "large" as meaning "10 times as large", the critical boundary is at about
499
      81 levels. The highest number of intensity levels at present supported by
500
      HP DeskJets is apparently 4.
501
502
      A more accurate implementation would determine 'step' as a floating point
503
      value, divide the intensity by it, and take the floor (entier) of the
504
      result as the component intensity.
505
  */
506
507
  /* The order has to be (YMC)(K) from left to right */
508
0
  if (eprn->colour_model != eprn_DeviceGray) {
509
0
    step = gx_max_color_value/eprn->non_black_levels;
510
511
0
    level = yellow/step;
512
0
    if (level >= eprn->non_black_levels) level = eprn->non_black_levels - 1;
513
0
    value = level << eprn->bits_per_colorant;
514
0
    level = magenta/step;
515
0
    if (level >= eprn->non_black_levels) level = eprn->non_black_levels - 1;
516
0
    value = (value | level) << eprn->bits_per_colorant;
517
0
    level = cyan/step;
518
0
    if (level >= eprn->non_black_levels) level = eprn->non_black_levels - 1;
519
0
    value = (value | level) << eprn->bits_per_colorant;
520
0
  }
521
0
  if (eprn->colour_model != eprn_DeviceCMY) {
522
0
    step = gx_max_color_value/eprn->black_levels;
523
0
    level = black/step;
524
0
    if (level >= eprn->black_levels) level = eprn->black_levels - 1;
525
0
    value |= level;
526
0
  }
527
528
#ifdef EPRN_TRACE
529
  if_debug1(EPRN_TRACE_CHAR, "  returning 0x%lX.\n", (unsigned long)value);
530
#endif
531
0
  return value;
532
0
}
533
534
/******************************************************************************
535
536
  Function: eprn_map_cmyk_color_max
537
538
  This is a 'map_cmyk_color' method retaining as much colour information as
539
  possible. The reduction to the printer's capabilities must happen in the
540
  output routine.
541
542
******************************************************************************/
543
544
gx_color_index eprn_map_cmyk_color_max(gx_device *device,
545
  const gx_color_value cv[])
546
0
{
547
0
  gx_color_value cyan = cv[0], magenta = cv[1], yellow = cv[2], black = cv[3];
548
0
  gx_color_index value;
549
550
#ifdef EPRN_TRACE
551
  if_debug4(EPRN_TRACE_CHAR,
552
    "! eprn_map_cmyk_color_max() called for CMYK = (%hu, %hu, %hu, %hu),\n",
553
      cyan, magenta, yellow, black);
554
#endif
555
556
0
  value = dominant_8bits(black);
557
0
  value |= dominant_8bits(cyan)    <<  8;
558
0
  value |= dominant_8bits(magenta) << 16;
559
0
  value |= dominant_8bits(yellow)  << 24;
560
561
#ifdef EPRN_TRACE
562
  if_debug1(EPRN_TRACE_CHAR, "  returning 0x%08lX.\n", (unsigned long)value);
563
#endif
564
0
  return value;
565
0
}
566
567
/******************************************************************************
568
569
  Function: eprn_map_cmyk_color_glob
570
571
  Global eprn_map_cmyk_color for all cases handled above used to
572
  be able to work together with ghostscript 8.15 and CMYK model.
573
574
******************************************************************************/
575
gx_color_index eprn_map_cmyk_color_glob(gx_device *device, const gx_color_value cv[])
576
0
{
577
0
  const eprn_Eprn *eprn = &((eprn_Device *)device)->eprn;
578
0
  if (eprn->intensity_rendering == eprn_IR_FloydSteinberg)
579
0
    return eprn_map_cmyk_color_max(device, cv);
580
0
  else if (device->color_info.max_gray > 1 || device->color_info.max_color > 1)
581
0
    return eprn_map_cmyk_color_flex(device, cv);
582
0
  else
583
0
    return eprn_map_cmyk_color(device, cv);
584
0
}
585
586
/******************************************************************************
587
588
  Function: eprn_finalize
589
590
  This function fills the last octet in a set of bit planes with white if
591
  needed and sets the lengths of all these planes.
592
593
  'is_RGB' denotes whether the colour model is eprn_DeviceRGB,
594
  'non_black_levels' is the number of intensity levels for non-black colorants,
595
  'planes' the number of bit planes,
596
  'plane' points to an array of at least 'planes' bit planes,
597
  'ptr' points to an array of at least 'planes' pointers into the bit planes,
598
  'pixels' is the number of pixels written to the group of bit planes.
599
600
  If 'pixels' is divisible by 8, the 'ptr' pointers point to octets after
601
  the last completely written octets. Otherwise, they point to the last
602
  incompletely written octet in which the pixels written so far occupy the
603
  least significant bits.
604
605
******************************************************************************/
606
607
void eprn_finalize(bool is_RGB, unsigned int non_black_levels,
608
  int planes, eprn_OctetString *plane, eprn_Octet **ptr, int pixels)
609
0
{
610
0
  int j;
611
612
  /* Execute remaining left shifts in the last octet of the output planes when
613
     the number of pixels is not a multiple of 8, and fill with white on the
614
     right */
615
0
  if (pixels % 8 != 0) {
616
0
    int shift = 8 - pixels % 8;
617
618
0
    if (is_RGB) {
619
      /* White may be any intensity, but it's the same for all three colorants,
620
         and it's the highest. */
621
0
      eprn_Octet imax = non_black_levels - 1;
622
0
      int c, rgb_planes = eprn_bits_for_levels(non_black_levels);
623
624
0
      j = 0;  /* next output plane */
625
626
      /* Loop over RGB */
627
0
      for (c = 0; c < 3; c++) {
628
0
        eprn_Octet value = imax;
629
0
        int m;
630
631
        /* Loop over all planes for this colorant */
632
0
        for (m = 0; m < rgb_planes; m++, j++) {
633
0
          eprn_Octet bit = value & 1;
634
0
          int p;
635
636
0
          value = value >> 1;
637
638
          /* Put the bit into all remaining pixels for this plane */
639
0
          for (p = 0; p < shift; p++)
640
0
            *ptr[j] = (*ptr[j] << 1) | bit;
641
0
        }
642
0
      }
643
0
    }
644
0
    else /* White is zero */
645
0
      for (j = 0; j < planes; j++)
646
0
        *ptr[j] = *ptr[j] << shift;
647
648
    /* Advance all plane pointers by 1 */
649
0
    for (j = 0; j < planes; j++) ptr[j]++;
650
0
  }
651
652
  /* Set the lengths of the bit plane strings */
653
0
  for (j = 0; j < planes; j++) {
654
0
    if (pixels == 0) plane[j].length = 0;
655
0
    else plane[j].length = ptr[j] - plane[j].str;
656
0
  }
657
658
0
  return;
659
0
}
660
661
/******************************************************************************
662
663
  Function: split_line_le8
664
665
  This is the first of the "split_line implementations". See the body of
666
  eprn_get_planes() for the calling conventions common to them.
667
668
  This particular implementation has the following restrictions:
669
  - The pixmap depth must be a divisor of 8.
670
671
******************************************************************************/
672
673
static void split_line_le8(eprn_Device *dev, const eprn_Octet *line,
674
  int length, eprn_OctetString plane[])
675
0
{
676
0
  gx_color_index
677
0
    pixel;
678
0
  int
679
0
    black_planes, /* number of planes to send for black */
680
0
    non_black_planes, /* number of planes to send for each of CMY/RGB */
681
0
    j,
682
0
    k,
683
0
    pixels,   /* number of pixels transferred to bit planes */
684
0
    planes;   /* number of planes to send */
685
0
  eprn_Octet
686
0
    comp_mask = 0,  /* 'bits_per_component' 1s in the lowest part */
687
0
    pixel_mask = 0, /* 'depth' 1s in the lowest part */
688
0
    *ptr[8];    /* pointers into planes (next octet to write to) */
689
690
  /* Number of planes to send */
691
0
  black_planes = eprn_bits_for_levels(dev->eprn.black_levels);
692
0
  non_black_planes = eprn_bits_for_levels(dev->eprn.non_black_levels);
693
0
  planes = black_planes + 3*non_black_planes;
694
695
  /* Initialize the bit plane pointers */
696
0
  for (j = 0; j < planes; j++) ptr[j] = plane[j].str;
697
698
  /* Determine some bit masks */
699
0
  for (j = 0; j < dev->color_info.depth; j++)
700
0
    pixel_mask = (pixel_mask << 1) | 1;
701
0
  for (j = 0; j < dev->eprn.bits_per_colorant; j++)
702
0
    comp_mask = (comp_mask << 1) | 1;
703
704
  /* Copy from 'line' to 'plane[]', converting Z format to XY format */
705
0
  pixels = 0;
706
0
  k = 0; /* Next octet index in the input line */
707
0
  while (k < length) {
708
0
    int l, m, p;
709
710
    /* Initialize plane storage if it's a new output octet */
711
0
    if (pixels % 8 == 0) for (j = 0; j < planes; j++) *ptr[j] = 0;
712
713
    /* Loop over pixels within the input octet, starting at the leftmost
714
       pixel (highest-order bits) */
715
0
    p = 8/dev->color_info.depth - 1;
716
0
    do {
717
0
      eprn_Octet comp;
718
719
      /* Extract pixel */
720
0
      pixel = (line[k] >> p*dev->color_info.depth) & pixel_mask;
721
722
      /* Extract components from the pixel and distribute each over its planes
723
       */
724
0
      comp = pixel & comp_mask; /* black */
725
0
      for (j = 0; j < black_planes; j++) {
726
0
        *ptr[j] = (*ptr[j] << 1) | (comp & 1);
727
0
        comp >>= 1;
728
0
      }
729
0
      if (non_black_planes > 0) for (l = 1; l < 4; l++) {
730
0
        comp = (pixel >> l*dev->eprn.bits_per_colorant) & comp_mask;
731
0
        for (m = 0; m < non_black_planes; m++, j++) {
732
0
          *ptr[j] = (*ptr[j] << 1) | (comp & 1);
733
0
          comp >>= 1;
734
0
        }
735
0
      }
736
737
0
      pixels++;
738
0
      p--;
739
0
    } while (p >= 0);
740
0
    k++;
741
742
    /* Increase plane pointers if an output octet boundary has been reached */
743
0
    if (pixels % 8 == 0) for (j = 0; j < planes; j++) ptr[j]++;
744
0
  }
745
746
0
  eprn_finalize(dev->eprn.colour_model == eprn_DeviceRGB,
747
0
    dev->eprn.non_black_levels, planes, plane, ptr, pixels);
748
749
0
  return;
750
0
}
751
752
/******************************************************************************
753
754
  Function: split_line_ge8
755
756
  This split_line function has the following restrictions:
757
  - The pixmap depth must be a multiple of 8.
758
  - There may be at most 8 bits per colorant.
759
    (Hence the depth is at most 32.)
760
  - 'length' must be divisible by depth/8.
761
762
******************************************************************************/
763
764
static void split_line_ge8(eprn_Device *dev, const eprn_Octet *line,
765
  int length, eprn_OctetString plane[])
766
0
{
767
0
  gx_color_index
768
0
    pixel;
769
0
  int
770
0
    black_planes, /* number of planes to send for black */
771
0
    non_black_planes, /* number of planes to send for each of CMY/RGB */
772
0
    j,
773
0
    k,
774
0
    octets_per_pixel = dev->color_info.depth/8,
775
0
    pixels,   /* number of pixels transferred to bit planes */
776
0
    planes;   /* number of planes to send */
777
0
  eprn_Octet
778
0
    comp_mask = 0,  /* bits_per_component 1s in the lowest part */
779
0
    *ptr[32];   /* pointers into planes (next octet to write to) */
780
781
  /* Number of planes to send */
782
0
  black_planes = eprn_bits_for_levels(dev->eprn.black_levels);
783
0
  non_black_planes = eprn_bits_for_levels(dev->eprn.non_black_levels);
784
0
  planes = black_planes + 3*non_black_planes;
785
786
  /* Initialize the bit plane pointers */
787
0
  for (j = 0; j < planes; j++) ptr[j] = plane[j].str;
788
789
  /* Determine the component mask */
790
0
  for (j = 0; j < dev->eprn.bits_per_colorant; j++)
791
0
    comp_mask = (comp_mask << 1) | 1;
792
793
  /* Copy from 'line' to 'plane[]', converting Z format to XY format */
794
0
  pixels = 0;
795
0
  k = 0; /* Next octet index in the input line */
796
0
  while (k < length) {
797
0
    eprn_Octet comp;
798
0
    int l, m;
799
800
    /* Initialize plane storage if it's a new octet */
801
0
    if (pixels % 8 == 0) for (j = 0; j < planes; j++) *ptr[j] = 0;
802
803
    /* Reconstruct pixel from several octets */
804
0
    j = 0;
805
0
    pixel = line[k];
806
0
    do {
807
0
      j++; k++;
808
0
      if (j >= octets_per_pixel) break;
809
0
      pixel = (pixel << 8) | line[k]; /* MSB (Big Endian) */
810
0
    } while (1);
811
812
    /* Split and distribute over planes */
813
0
    comp = pixel & comp_mask; /* black */
814
0
    for (j = 0; j < black_planes; j++) {
815
0
      *ptr[j] = (*ptr[j] << 1) | (comp & 1);
816
0
      comp >>= 1;
817
0
    }
818
0
    for (l = 1; l < 4; l++) {
819
0
      comp = (pixel >> l*dev->eprn.bits_per_colorant) & comp_mask;
820
0
      for (m = 0; m < non_black_planes; m++, j++) {
821
0
        *ptr[j] = (*ptr[j] << 1) | (comp & 1);
822
0
        comp >>= 1;
823
0
      }
824
0
    }
825
826
0
    pixels++;
827
828
    /* Increase plane pointers if an octet boundary has been reached */
829
0
    if (pixels % 8 == 0) for (j = 0; j < planes; j++) ptr[j]++;
830
0
  }
831
832
0
  eprn_finalize(dev->eprn.colour_model == eprn_DeviceRGB,
833
0
    dev->eprn.non_black_levels, planes, plane, ptr, pixels);
834
835
0
  return;
836
0
}
837
838
/******************************************************************************
839
840
  Function: split_line_3or4x1
841
842
  This function is a split_line() implementation for a non-monochrome colour
843
  model (3 or 4 components) with 1 bit per component.
844
845
******************************************************************************/
846
847
static void split_line_3or4x1(eprn_Device *dev, const eprn_Octet *line,
848
  int length, eprn_OctetString plane[])
849
0
{
850
0
  int
851
0
    from = (dev->eprn.colour_model == eprn_DeviceRGB ||
852
0
      dev->eprn.colour_model == eprn_DeviceCMY? 1: 0),
853
0
    j,
854
0
    k,
855
0
    l;
856
0
  eprn_Octet *ptr[4]; /* pointers into planes, indexed KCMY/-RGB */
857
858
0
  ptr[0] = NULL;  /* defensive programming */
859
0
  for (j = from; j < 4; j++) ptr[j] = plane[j-from].str;
860
861
  /*  Loop over the input line, taking four octets (8 pixels) at a time, as far
862
      as available, and split them into four output octets, one for each
863
      colorant.
864
  */
865
0
  k = 0;
866
0
  while (k < length) {
867
0
    eprn_Octet octet[4] = {0, 0, 0, 0};
868
869
0
    for (l = 0; l < 4 && k < length; l++, k++) {
870
0
      eprn_Octet part;
871
0
#define treat_quartet()           \
872
0
      octet[COLORANT_0_INDEX] <<= 1;        \
873
0
      if (part & COLORANT_0_BIT) octet[COLORANT_0_INDEX] |= 1; \
874
0
      octet[COLORANT_1_INDEX] <<= 1;        \
875
0
      if (part & COLORANT_1_BIT) octet[COLORANT_1_INDEX] |= 1; \
876
0
      octet[COLORANT_2_INDEX] <<= 1;        \
877
0
      if (part & COLORANT_2_BIT) octet[COLORANT_2_INDEX] |= 1; \
878
0
      octet[COLORANT_3_INDEX] <<= 1;        \
879
0
      if (part & COLORANT_3_BIT) octet[COLORANT_3_INDEX] |= 1;
880
881
      /* Upper four bits */
882
0
      part = (line[k] >> 4) & 0x0F;
883
0
      treat_quartet()
884
885
      /* Lower four bits */
886
0
      part = line[k] & 0x0F;
887
0
      treat_quartet()
888
889
0
#undef treat_quartet
890
0
    }
891
0
    if (l < 4) {
892
0
      for (j = from; j < 4; j++) octet[j] <<= 8 - 2*l;
893
0
      if (dev->eprn.colour_model == eprn_DeviceRGB) {
894
        /* Add white in the last 8 - 2*l pixels */
895
0
        for (j = 1; j < 4; j++) {
896
0
          int k;
897
          /* We add two pixels at a time */
898
0
          for (k = 3 - l; k >= 0; k--) octet[j] |= 0x03 << k;
899
0
        }
900
0
      }
901
0
    }
902
0
    for (j = from; j < 4; j++) *(ptr[j]++) = octet[j];
903
0
  }
904
905
  /* Set the lengths of the bit plane strings */
906
0
  for (j = 0; j < dev->eprn.output_planes; j++) {
907
0
    if (length == 0) plane[j].length = 0;
908
0
    else plane[j].length = ptr[from + j] - plane[j].str;
909
0
  }
910
911
0
  return;
912
0
}
913
914
/******************************************************************************
915
916
  Function: split_line_4x2
917
918
  This is a split_line() implementation for 4 colour components (i.e., CMYK)
919
  with 3 or 4 levels each (2 bit planes to send for each component).
920
921
******************************************************************************/
922
923
static void split_line_4x2(eprn_Device *dev, const eprn_Octet *line,
924
  int length, eprn_OctetString plane[])
925
0
{
926
0
  gx_color_index
927
0
    pixel;
928
0
  int
929
0
    j,
930
0
    k;
931
0
  eprn_Octet
932
0
    *ptr[8];    /* pointers into planes (next octet to write to) */
933
934
  /* Initialize the bit plane pointers */
935
0
  for (j = 0; j < 8; j++) ptr[j] = plane[j].str;
936
937
  /* Copy from 'line' to 'plane[]', converting Z format to XY format */
938
0
  for (k = 0; k < length; k++) {
939
    /* k is the index of the next octet in the input line and the number of
940
       pixels processed so far. */
941
942
    /* Initialize plane storage if it's a new octet */
943
0
    if (k % 8 == 0) for (j = 0; j < 8; j++) *ptr[j] = 0;
944
945
    /* Fetch pixel */
946
0
    pixel = line[k];
947
948
    /* Split and distribute over planes */
949
0
    *ptr[0] = (*ptr[0] << 1) | (pixel & 0x01);
950
0
#define assign_bit(index) \
951
0
    *ptr[index] = (*ptr[index] << 1) | ((pixel >> index) & 0x01)
952
0
    assign_bit(1);
953
0
    assign_bit(2);
954
0
    assign_bit(3);
955
0
    assign_bit(4);
956
0
    assign_bit(5);
957
0
    assign_bit(6);
958
0
    assign_bit(7);
959
0
#undef assign_bit
960
961
    /* Increase plane pointers if an output octet boundary has been reached */
962
0
    if (k % 8 == 7) for (j = 0; j < 8; j++) ptr[j]++;
963
0
  }
964
965
  /* Execute remaining left shifts in the last octet of the output planes when
966
     the number of pixels is not a multiple of 8 */
967
0
  k = length % 8;
968
0
  if (k != 0) {
969
0
    int shift = 8 - k;
970
0
    for (j = 0; j < 8; j++)
971
0
      *(ptr[j]++) <<= shift;
972
0
  }
973
974
  /* Set the lengths of the bit plane strings */
975
0
  for (j = 0; j < 8; j++) {
976
0
    if (length == 0) plane[j].length = 0;
977
0
    else plane[j].length = ptr[j] - plane[j].str;
978
0
  }
979
980
0
  return;
981
0
}
982
983
/******************************************************************************
984
985
  Function: eprn_fetch_scan_line
986
987
  If there is a next scan line with y coordinate 'dev->eprn.next_y', this
988
  function fetches it into '*line' and returns zero. Otherwise the function
989
  returns a non-zero value.
990
991
  The storage allocated for 'line->str' must be at least of size
992
  'dev->eprn.octets_per_line'.
993
994
  On success, the 'length' field in 'line' does not include trailing zero
995
  pixels.
996
997
******************************************************************************/
998
999
int eprn_fetch_scan_line(eprn_Device *dev, eprn_OctetString *line)
1000
0
{
1001
0
  int rc;
1002
0
  const eprn_Octet *str;
1003
1004
0
  rc = gdev_prn_copy_scan_lines((gx_device_printer *)dev, dev->eprn.next_y,
1005
0
    line->str, dev->eprn.octets_per_line);
1006
   /* gdev_prn_copy_scan_lines() returns the number of scan lines it fetched
1007
      or a negative value on error. The number of lines to fetch is the value
1008
      of the last argument divided by the length of a single line, hence in
1009
      this case 1. */
1010
0
  if (rc != 1) return 1;
1011
1012
  /* Set the length to ignore trailing zero octets in the scan line */
1013
0
  str = line->str + (dev->eprn.octets_per_line - 1);
1014
0
  while (str > line->str && *str == 0) str--;
1015
0
  if (*str == 0) line->length = 0;
1016
0
  else line->length = str - line->str + 1;
1017
1018
  /* Ensure we have an integral number of pixels in the line */
1019
0
  if (dev->color_info.depth > 8) {
1020
0
    int rem;
1021
0
    unsigned int octets_per_pixel = dev->color_info.depth/8;
1022
      /* If the depth is larger than 8, it is a multiple of 8. */
1023
0
    rem = line->length % octets_per_pixel;
1024
0
    if (rem != 0) line->length += octets_per_pixel - rem;
1025
0
  }
1026
1027
#if 0 && defined(EPRN_TRACE)
1028
  if (gs_debug_c(EPRN_TRACE_CHAR)) {
1029
    int j;
1030
    dmlprintf(dev->memory, "! eprn_fetch_scan_line(): Fetched ");
1031
    if (line->length == 0) dmprintf(dev->memory, "empty scan line.");
1032
    else {
1033
      dmprintf(dev->memory, "scan line: 0x");
1034
      for (j = 0; j < line->length; j++) dmprintf1(dev->memory, "%02X", line->str[j]);
1035
    }
1036
    dmlprintf(dev->memory, "\n");
1037
  }
1038
#endif
1039
1040
0
  return 0;
1041
0
}
1042
1043
/******************************************************************************
1044
1045
  Function: eprn_get_planes
1046
1047
  For the description of this function, see gdeveprn.h.
1048
1049
******************************************************************************/
1050
1051
int eprn_get_planes(eprn_Device *dev, eprn_OctetString bitplanes[])
1052
0
{
1053
0
  eprn_OctetString *line; /* where to copy the scan line from the prn device */
1054
0
  int
1055
0
    j,
1056
0
    rc;
1057
1058
  /* Avoid a copying step for a depth of 1 */
1059
0
  if (dev->color_info.depth == 1) line = bitplanes;
1060
0
  else line = &dev->eprn.scan_line;
1061
1062
  /* Fetch the scan line if available */
1063
0
  if (dev->eprn.intensity_rendering == eprn_IR_FloydSteinberg &&
1064
0
      dev->eprn.next_y == 0) return 1;
1065
0
  rc = eprn_fetch_scan_line(dev, line);
1066
0
  if (rc == 0) dev->eprn.next_y++;
1067
0
  else {
1068
0
    if (dev->eprn.intensity_rendering != eprn_IR_FloydSteinberg) return 1;
1069
0
    dev->eprn.next_y = 0;
1070
0
  }
1071
1072
0
  if (dev->color_info.depth == 1) return 0;
1073
1074
0
  if (dev->eprn.intensity_rendering == eprn_IR_FloydSteinberg) {
1075
0
    eprn_OctetString tmp;
1076
1077
0
    eprn_split_FS(&dev->eprn.next_scan_line, &dev->eprn.scan_line,
1078
0
      dev->eprn.octets_per_line,
1079
0
      dev->eprn.colour_model,
1080
0
      dev->eprn.black_levels, dev->eprn.non_black_levels,
1081
0
      bitplanes);
1082
1083
    /* Switch 'next_scan_line' to refer to what is currently 'scan_line' */
1084
0
    tmp = dev->eprn.next_scan_line;
1085
0
    dev->eprn.next_scan_line = dev->eprn.scan_line;
1086
0
    dev->eprn.scan_line = tmp;
1087
0
  }
1088
0
  else {
1089
    /*  Here we split multi-bit pixels which are already adapted to the
1090
        printer's capabilities.
1091
1092
        All the functions called here have the following signature:
1093
1094
          static void split_line...(eprn_Device *dev, const eprn_Octet *line,
1095
            int length, eprn_OctetString plane[])
1096
1097
        Such a "split_line implementation" must take the scan line of length
1098
        'length', pointed to by 'line', split it into bit planes according to
1099
        the state of 'dev', and return these planes via 'plane'. The length
1100
        fields of the planes must be set. Trailing zero octets should not be
1101
        removed because it's done here afterwards anyway.
1102
    */
1103
1104
0
    if (dev->eprn.colour_model == eprn_DeviceGray)
1105
0
      split_line_le8(dev, line->str, line->length, bitplanes);
1106
0
    else {
1107
0
      if (dev->eprn.bits_per_colorant == 1) {
1108
0
#ifndef EPRN_TRAILING_BIT_BUG_FIXED
1109
0
        if (dev->eprn.colour_model == eprn_DeviceRGB &&
1110
0
            line->length == dev->eprn.octets_per_line) {
1111
         /* At least gs 6.01 and 6.50 sometimes generate pixel lines where the
1112
            last pixel is not white but black (last octet in 'line' is 0xE0
1113
            instead of 0xEE; with pcl3 it shows up for A6 and A4, but not for
1114
            A3, A5, US Letter, or US Legal).
1115
            I'm overwriting it with white. */
1116
#ifdef EPRN_TRACE
1117
          if (gs_debug_c(EPRN_TRACE_CHAR)) {
1118
            static bool already_noted = false;
1119
            if (!already_noted && line->str[line->length - 1] != 0xEE) {
1120
              dmlprintf1(dev->memory, "! eprn_get_planes(): "
1121
                         "Line-terminating octet is 0x%02X.\n",
1122
                         line->str[line->length - 1]);
1123
              already_noted = true;
1124
            }
1125
          }
1126
#endif  /* EPRN_TRACE */
1127
0
          line->str[line->length - 1] |= RED_BIT | GREEN_BIT | BLUE_BIT;
1128
0
        }
1129
0
#endif  /* EPRN_TRAILING_BIT_BUG_FIXED */
1130
0
        split_line_3or4x1(dev, line->str, line->length, bitplanes);
1131
0
      }
1132
0
      else if (dev->eprn.bits_per_colorant == 2 && dev->eprn.black_levels > 2 &&
1133
0
          dev->eprn.non_black_levels > 2)
1134
0
        split_line_4x2(dev, line->str, line->length, bitplanes);
1135
0
      else if (dev->color_info.depth < 8)
1136
0
        split_line_le8(dev, line->str, line->length, bitplanes);
1137
0
      else split_line_ge8(dev, line->str, line->length, bitplanes);
1138
0
    }
1139
0
  }
1140
1141
  /* Reduce the lengths of the individual bit planes to not include trailing
1142
     zero octets */
1143
0
  for (j = 0; j < dev->eprn.output_planes; j++) {
1144
0
    if (bitplanes[j].length > 0) {
1145
0
      const eprn_Octet *str = bitplanes[j].str + (bitplanes[j].length - 1);
1146
0
      while (str > bitplanes[j].str && *str == 0) str--;
1147
0
      if (*str == 0) bitplanes[j].length = 0;
1148
0
      else bitplanes[j].length = (str - bitplanes[j].str) + 1;
1149
0
    }
1150
0
  }
1151
1152
0
  return 0;
1153
0
}