Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/contrib/pcl3/eprn/eprnfs.c
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
  File:     $Id: eprnfs.c,v 1.6 2001/05/01 07:02:01 Martin Rel $
3
  Contents: Floyd-Steinberg error diffusion for eprn
4
  Author:   Martin Lottermoser, Greifswaldstrasse 28, 38124 Braunschweig,
5
            Germany; e-mail: Martin.Lottermoser@t-online.de.
6
7
*******************************************************************************
8
*                       *
9
* Copyright (C) 2001 by Martin Lottermoser            *
10
* All rights reserved                 *
11
*                       *
12
*******************************************************************************
13
14
  Information about Floyd-Steinberg error diffusion should be available in a
15
  number of places. I've used:
16
17
    James D. Foley, Andries van Dam, Steven K. Feiner, John F. Hughes
18
    "Computer Graphics"
19
    Second edition in C
20
    Reading/Massachusetts, etc.: Addison-Wesley, 1996
21
    ISBN 0-201-84840-6
22
23
******************************************************************************/
24
25
/*****************************************************************************/
26
27
#ifndef _XOPEN_SOURCE
28
#define _XOPEN_SOURCE 500
29
#endif
30
31
#include "gdeveprn.h"
32
33
/*****************************************************************************/
34
35
/* Here follow some macros for code sections used in several routines. */
36
37
0
#define fit_to_octet(value) ((value) < 0? 0: (value) > 255? 255: (value))
38
39
#define FS_assign()       \
40
0
        new_value = *to + correction;   \
41
0
        if (new_value < 0) {     \
42
0
          *to = 0;        \
43
0
          remaining_error += new_value;   \
44
0
        }          \
45
0
        else if (255 < new_value) {   \
46
0
          *to = 255;        \
47
0
          remaining_error += new_value - 255; \
48
0
        }          \
49
0
        else *to = new_value;
50
51
#define error_propagation_Gray()        \
52
0
  if (error != 0) {           \
53
0
    remaining_error = error;          \
54
0
                                                                \
55
0
    /* 7/16 of the error goes to the right */     \
56
0
    correction = (7*error)/16;          \
57
0
    remaining_error -= correction;        \
58
0
    if (pixel < max_pixel) {         \
59
0
      to = from + 1;            \
60
0
      FS_assign()            \
61
0
      if (pixel == pixels - 1 && *to > 0) {     \
62
0
        pixels++;           \
63
0
        line->length++;           \
64
0
      }                \
65
0
    }               \
66
0
                                                                \
67
0
    /* 3/16 of the error goes to the left and below */    \
68
0
    correction = (3*error)/16;          \
69
0
    remaining_error -= correction;        \
70
0
    if (pixel > 0) {           \
71
0
      to = next_line->str + (pixel - 1);      \
72
0
      FS_assign()            \
73
0
      if (next_line->length < pixel && *to > 0) next_line->length = pixel; \
74
0
    }               \
75
0
                                                                \
76
0
    /* 5/16 of the error goes below */        \
77
0
    correction = (5*error)/16;          \
78
0
    remaining_error -= correction;        \
79
0
    to = next_line->str + pixel;        \
80
0
    FS_assign()              \
81
0
    if (next_line->length <= pixel && *to > 0) next_line->length = pixel + 1; \
82
0
                                                                \
83
0
    /* The remainder (about 1/16 of the error) is added to the right and */ \
84
0
    /* below. */            \
85
0
    if (pixel < max_pixel) {         \
86
0
      to = next_line->str + (pixel+1);        \
87
0
      new_value = *to + remaining_error;      \
88
0
      *to = fit_to_octet(new_value);        \
89
0
      if (next_line->length < pixel + 2 && *to > 0)   \
90
0
        next_line->length = pixel + 2;       \
91
0
    }               \
92
0
  }
93
94
/* Number of octets per pixel for the non-monochrome cases */
95
0
#define OCTETS_PER_PIXEL  4
96
97
#define error_propagation_colour()        \
98
0
  if (error != 0) {           \
99
0
    remaining_error = error;          \
100
0
                                                                \
101
0
    /* 7/16 of the error goes to the right */     \
102
0
    correction = (7*error)/16;          \
103
0
    remaining_error -= correction;        \
104
0
    if (pixel < max_pixel) {         \
105
0
      to = from + OCTETS_PER_PIXEL;       \
106
0
      FS_assign()            \
107
0
      if (pixel == pixels - 1 && *to > 0) {     \
108
0
        pixels++;           \
109
0
        line->length += OCTETS_PER_PIXEL;     \
110
0
      }               \
111
0
    }               \
112
0
                                                                \
113
0
    /* 3/16 of the error goes to the left and below */    \
114
0
    correction = (3*error)/16;          \
115
0
    remaining_error -= correction;        \
116
0
    if (pixel > 0) {           \
117
0
      to = next_line->str + (pixel - 1)*OCTETS_PER_PIXEL + colorant; \
118
0
      FS_assign()            \
119
0
      if (next_line->length < pixel*OCTETS_PER_PIXEL && *to > 0) \
120
0
        next_line->length = pixel*OCTETS_PER_PIXEL;   \
121
0
    }               \
122
0
                                                                \
123
0
    /* 5/16 of the error goes below */        \
124
0
    correction = (5*error)/16;          \
125
0
    remaining_error -= correction;        \
126
0
    to = next_line->str + pixel*OCTETS_PER_PIXEL + colorant;  \
127
0
    FS_assign()              \
128
0
    if (next_line->length <= pixel*OCTETS_PER_PIXEL && *to > 0) \
129
0
      next_line->length = (pixel + 1)*OCTETS_PER_PIXEL;   \
130
0
                                                                \
131
0
    /* The remainder (about 1/16 of the error) is added to the right and */ \
132
0
    /* below. */            \
133
0
    if (pixel < max_pixel) {         \
134
0
      to = next_line->str + (pixel+1)*OCTETS_PER_PIXEL + colorant; \
135
0
      new_value = *to + remaining_error;      \
136
0
      *to = fit_to_octet(new_value);        \
137
0
      if (next_line->length < (pixel + 2)*OCTETS_PER_PIXEL && *to > 0) \
138
0
        next_line->length = (pixel + 2)*OCTETS_PER_PIXEL; \
139
0
    }               \
140
0
  }
141
142
/******************************************************************************
143
144
  Function: split_Gray_2
145
146
  Floyd-Steinberg error diffusion for the process colour model Gray and
147
  2 intensity levels.
148
149
******************************************************************************/
150
151
static void split_Gray_2(eprn_OctetString *line, eprn_OctetString *next_line,
152
  int max_octets, eprn_OctetString bitplanes[])
153
0
{
154
0
  const int
155
0
    max_pixel = max_octets - 1;
156
0
  int
157
0
    correction,
158
0
    error,
159
0
    new_value,
160
0
    pixel,
161
0
    pixel_mod_8,
162
0
    pixels = line->length,
163
0
    remaining_error;
164
0
  eprn_Octet
165
0
    approx,
166
0
    *from,
167
0
    *ptr,
168
0
    *to;
169
170
0
  ptr = bitplanes[0].str;
171
172
  /* Loop over pixels in the scan line. Note that 'pixels' may increase
173
     within the loop. */
174
0
  for (pixel = 0, pixel_mod_8 = 8; pixel < pixels; pixel++, pixel_mod_8++) {
175
0
    if (pixel_mod_8 == 8) {
176
0
      pixel_mod_8 = 0;
177
0
      *ptr = 0;
178
0
    }
179
180
    /* Determine approximation and error for this pixel */
181
0
    from = line->str + pixel;
182
0
    approx = *from >> 7;  /* take the most significant bit */
183
0
    error = *from - 255*approx;
184
     /* The sign of 'error' is chosen such that 'error' is positive if
185
        colorant intensity has to be added to the picture. */
186
187
    /* Insert the approximation into the output plane */
188
0
    *ptr = (*ptr << 1) | approx;
189
190
0
    error_propagation_Gray()
191
192
0
    if (pixel_mod_8 == 7) ptr++;
193
0
  }
194
195
0
  eprn_finalize(false, 0, 1, bitplanes, &ptr, pixels);
196
197
0
  return;
198
0
}
199
200
/******************************************************************************
201
202
  Function: split_Gray()
203
204
  Floyd-Steinberg error diffusion for the process colour model Gray and an
205
  arbitrary number of intensity levels.
206
207
******************************************************************************/
208
209
static void split_Gray(eprn_OctetString *line, eprn_OctetString *next_line,
210
  int max_octets, unsigned int black_levels, eprn_OctetString bitplanes[])
211
0
{
212
0
  const int
213
0
    max_pixel = max_octets - 1,
214
0
    planes = eprn_bits_for_levels(black_levels);
215
0
  int
216
0
    correction,
217
0
    error,
218
0
    new_value,
219
0
    pixel,
220
0
    pixel_mod_8,
221
0
    pixels = line->length,
222
0
    plane,
223
0
    remaining_error;
224
0
  eprn_Octet
225
0
    approx,
226
0
    *from,
227
0
    *ptr[8],
228
0
    *to;
229
0
  const unsigned int
230
0
    divisor = 256/black_levels,
231
0
    max_level = black_levels - 1;
232
233
0
  for (plane = 0; plane < planes; plane++) ptr[plane] = bitplanes[plane].str;
234
235
  /* Loop over pixels in the scan line. Note that 'pixels' may increase
236
     within the loop. */
237
0
  for (pixel = 0, pixel_mod_8 = 8; pixel < pixels; pixel++, pixel_mod_8++) {
238
0
    if (pixel_mod_8 == 8) {
239
0
      pixel_mod_8 = 0;
240
0
      for (plane = 0; plane < planes; plane++) *ptr[plane] = 0;
241
0
    }
242
243
    /* Determine approximation and error for this pixel */
244
0
    from = line->str + pixel;
245
0
    approx = *from/divisor;
246
0
    error = *from - (255*approx)/max_level;
247
     /* The sign of 'error' is chosen such that 'error' is positive if
248
        colorant intensity has to be added to the picture. */
249
250
    /* Distribute the approximation over the bit planes */
251
0
    for (plane = 0; plane < planes; plane++) {
252
0
      *ptr[plane] = (*ptr[plane] << 1) | (approx & 0x01);
253
0
      approx >>= 1;
254
0
    }
255
256
0
    error_propagation_Gray()
257
258
0
    if (pixel_mod_8 == 7)
259
0
      for (plane = 0; plane < planes; plane++) ptr[plane]++;
260
0
  }
261
262
0
  eprn_finalize(false, 0, planes, bitplanes, ptr, pixels);
263
264
0
  return;
265
0
}
266
267
/*****************************************************************************/
268
269
/* Index of the black colorant in a pixel value (gx_color_index) for the
270
   non-monochrome cases */
271
0
#define BLACK_INDEX   3
272
273
/******************************************************************************
274
275
  Function: split_colour_CMYK_2()
276
277
  Floyd-Steinberg error diffusion for the CMYK colour model using 2 intensity
278
  levels for all colorants.
279
280
  This function is about 14 % faster than split_colour_at_most_2(), and every
281
  bit helps.
282
283
******************************************************************************/
284
285
0
#define PLANES    4
286
287
static void split_colour_CMYK_2(eprn_OctetString *line,
288
  eprn_OctetString *next_line, int max_octets, eprn_OctetString bitplanes[])
289
0
{
290
0
  const int
291
0
    max_pixel = max_octets/OCTETS_PER_PIXEL - 1;
292
0
  int
293
0
    colorant,
294
0
    correction,
295
0
    error,
296
0
    new_value,
297
0
    pixel,
298
0
    pixel_mod_8,
299
0
    pixels = line->length/OCTETS_PER_PIXEL,
300
0
    plane,
301
0
    remaining_error;
302
0
  eprn_Octet
303
0
    approx,
304
0
    *from,
305
0
    *ptr[4],
306
0
    *to;
307
308
0
  for (plane = 0; plane < PLANES; plane++) ptr[plane] = bitplanes[plane].str;
309
310
  /* Loop over pixels in the scan line. Note that 'pixels' may increase
311
     within the loop. */
312
0
  for (pixel = 0, pixel_mod_8 = 8; pixel < pixels; pixel++, pixel_mod_8++) {
313
0
    if (pixel_mod_8 == 8) {
314
0
      pixel_mod_8 = 0;
315
0
      for (plane = 0; plane < PLANES; plane++) *ptr[plane] = 0;
316
0
    }
317
318
    /* Loop over colorants within a scan line. Remember that the order within
319
       a pixel is YMCK. */
320
0
    for (colorant = BLACK_INDEX; colorant >= 0; colorant--) {
321
0
      from = line->str + pixel*OCTETS_PER_PIXEL + colorant;
322
323
      /* Determine approximation and error for this pixel */
324
0
      approx = *from >> 7;
325
0
      error = *from - 255*approx;
326
       /* The sign of 'error' is chosen such that 'error' is positive if
327
          colorant intensity has to be added to the picture. */
328
329
      /* Insert the approximation in the bit plane */
330
0
      plane = BLACK_INDEX - colorant;
331
0
      *ptr[plane] = (*ptr[plane] << 1) | approx;
332
333
0
      error_propagation_colour()
334
0
    }
335
336
0
    if (pixel_mod_8 == 7)
337
0
      for (plane = 0; plane < PLANES; plane++) ptr[plane]++;
338
0
  }
339
340
0
  eprn_finalize(false, 2, PLANES, bitplanes, ptr, pixels);
341
342
0
  return;
343
0
}
344
345
/******************************************************************************
346
347
  Function: split_colour_at_most_2()
348
349
  Floyd-Steinberg error diffusion for the non-monochrome process colour models
350
  using 2 intensity levels for the CMY colorants and at most 2 for the black
351
  colorant.
352
353
******************************************************************************/
354
355
static void split_colour_at_most_2(eprn_OctetString *line,
356
  eprn_OctetString *next_line, int max_octets, eprn_ColourModel colour_model,
357
  eprn_OctetString bitplanes[])
358
0
{
359
0
  const int
360
0
    last_colorant =
361
0
      colour_model == eprn_DeviceCMY_plus_K || colour_model == eprn_DeviceCMYK?
362
0
        BLACK_INDEX: 2,
363
0
    max_pixel = max_octets/OCTETS_PER_PIXEL - 1,
364
0
    planes =
365
0
      colour_model == eprn_DeviceCMY_plus_K || colour_model == eprn_DeviceCMYK?
366
0
        4: 3;
367
0
  int
368
0
    colorant,
369
0
    correction,
370
0
    error,
371
0
    new_value,
372
0
    pixel,
373
0
    pixel_mod_8,
374
0
    pixels = line->length/OCTETS_PER_PIXEL,
375
0
    plane,
376
0
    remaining_error;
377
0
  eprn_Octet
378
0
    approx[4],
379
0
    *from,
380
0
    *ptr[4],
381
0
    *to;
382
383
0
  for (plane = 0; plane < planes; plane++) ptr[plane] = bitplanes[plane].str;
384
385
  /* Loop over pixels in the scan line. Note that 'pixels' may increase
386
     within the loop. */
387
0
  for (pixel = 0, pixel_mod_8 = 8; pixel < pixels; pixel++, pixel_mod_8++) {
388
0
    if (pixel_mod_8 == 8) {
389
0
      pixel_mod_8 = 0;
390
0
      for (plane = 0; plane < planes; plane++) *ptr[plane] = 0;
391
0
    }
392
393
    /* Loop over colorants within a scan line. Remember that the order within
394
       a pixel is YMCK or BGR-. */
395
0
    for (colorant = last_colorant; colorant >= 0; colorant--) {
396
0
      from = line->str + pixel*OCTETS_PER_PIXEL + colorant;
397
398
      /* Determine approximation and error for this pixel */
399
0
      approx[colorant] = *from >> 7;
400
0
      error = *from - 255*approx[colorant];
401
       /* The sign of 'error' is chosen such that 'error' is positive if
402
          colorant intensity has to be added to the picture. */
403
404
0
      error_propagation_colour()
405
0
    }
406
407
    /* Determine the black component for CMY+K */
408
0
    if (colour_model == eprn_DeviceCMY_plus_K &&
409
0
        approx[0] == approx[1] && approx[1] == approx[2] && approx[0] > 0) {
410
0
      approx[BLACK_INDEX] = approx[0];
411
0
      approx[0] = approx[1] = approx[2] = 0;
412
0
    }
413
414
    /* Distribute the approximation over the bit planes */
415
0
    for (colorant = last_colorant, plane = 0; colorant >= 0;
416
0
        colorant--, plane++) {
417
0
      *ptr[plane] = (*ptr[plane] << 1) | approx[colorant];
418
0
    }
419
420
0
    if (pixel_mod_8 == 7)
421
0
      for (plane = 0; plane < planes; plane++) ptr[plane]++;
422
0
  }
423
424
0
  eprn_finalize(colour_model == eprn_DeviceRGB, 2, planes, bitplanes, ptr,
425
0
    pixels);
426
427
0
  return;
428
0
}
429
430
/******************************************************************************
431
432
  Function: split_colour()
433
434
  Floyd-Steinberg error diffusion for the non-monochrome process colour models
435
  and an arbitrary number of intensity levels.
436
437
******************************************************************************/
438
439
static void split_colour(eprn_OctetString *line, eprn_OctetString *next_line,
440
  int max_octets, eprn_ColourModel colour_model,
441
  unsigned int black_levels, unsigned int non_black_levels,
442
  eprn_OctetString bitplanes[])
443
0
{
444
0
  const int
445
0
    black_planes = eprn_bits_for_levels(black_levels),
446
0
    last_colorant = black_levels > 0? BLACK_INDEX: 2,
447
0
    max_pixel = max_octets/OCTETS_PER_PIXEL - 1,
448
0
    non_black_planes = eprn_bits_for_levels(non_black_levels),
449
0
    planes = black_planes + 3*non_black_planes;
450
0
  int
451
0
    colorant,
452
0
    correction,
453
0
    error,
454
0
    new_value,
455
0
    next_plane[4],
456
0
    pixel,
457
0
    pixel_mod_8,
458
0
    pixels = line->length/OCTETS_PER_PIXEL,
459
0
    plane,
460
0
    remaining_error;
461
0
  eprn_Octet
462
0
    approx[4],
463
0
    *from,
464
0
    *ptr[32],
465
0
    *to;
466
0
  unsigned int
467
0
    divisor[4],
468
0
    max_level[4];
469
470
0
  if (black_levels > 0) {
471
0
    divisor[BLACK_INDEX] = 256/black_levels;
472
0
    max_level[BLACK_INDEX] = black_levels - 1;
473
0
  }
474
0
  else {
475
0
    divisor[BLACK_INDEX] = 0;
476
0
    max_level[BLACK_INDEX] = 0;
477
0
  }
478
0
  next_plane[BLACK_INDEX] = black_planes;
479
480
0
  for (colorant = 0; colorant < BLACK_INDEX; colorant++) {
481
0
    divisor[colorant] = 256/non_black_levels;
482
0
    max_level[colorant] = non_black_levels - 1;
483
0
    next_plane[colorant] = (3 - colorant)*non_black_planes + black_planes;
484
0
  }
485
486
0
  for (plane = 0; plane < planes; plane++) ptr[plane] = bitplanes[plane].str;
487
488
  /* Loop over pixels in the scan line. Note that 'pixels' may increase
489
     within the loop. */
490
0
  for (pixel = 0, pixel_mod_8 = 8; pixel < pixels; pixel++, pixel_mod_8++) {
491
0
    if (pixel_mod_8 == 8) {
492
0
      pixel_mod_8 = 0;
493
0
      for (plane = 0; plane < planes; plane++) *ptr[plane] = 0;
494
0
    }
495
496
    /* Loop over colorants within a scan line */
497
0
    for (colorant = last_colorant; colorant >= 0; colorant--) {
498
0
      from = line->str + pixel*OCTETS_PER_PIXEL + colorant;
499
500
      /* Determine approximation and error for this pixel */
501
0
      approx[colorant] = *from/divisor[colorant];
502
0
      error = *from - (255*approx[colorant])/max_level[colorant];
503
       /* The sign of 'error' is chosen such that 'error' is positive if
504
          colorant intensity has to be added to the picture. */
505
506
0
      error_propagation_colour()
507
0
    }
508
509
    /* Determine the black component for CMY+K */
510
0
    if (colour_model == eprn_DeviceCMY_plus_K &&
511
0
        approx[0] == approx[1] && approx[1] == approx[2] && approx[0] > 0) {
512
0
      int value = approx[0]*(black_levels - 1);
513
0
      if (value % (non_black_levels - 1) == 0) {
514
        /* Black does have a level at the same intensity as the CMY levels */
515
0
        approx[BLACK_INDEX] = value/(non_black_levels - 1);
516
0
        approx[0] = approx[1] = approx[2] = 0;
517
0
      }
518
0
    }
519
520
    /* Distribute the approximation over the bit planes */
521
0
    plane = 0;
522
0
    for (colorant = last_colorant; colorant >= 0; colorant--) {
523
0
      while (plane < next_plane[colorant]) {
524
0
        *ptr[plane] = (*ptr[plane] << 1) | (approx[colorant] & 0x01);
525
0
        approx[colorant] >>= 1;
526
0
        plane++;
527
0
      }
528
0
    }
529
530
0
    if (pixel_mod_8 == 7) {
531
0
      int j;
532
0
      for (j = 0; j < planes; j++) ptr[j]++;
533
0
    }
534
0
  }
535
536
0
  eprn_finalize(colour_model == eprn_DeviceRGB, non_black_levels, planes,
537
0
    bitplanes, ptr, pixels);
538
539
0
  return;
540
0
}
541
542
/******************************************************************************
543
544
  Function: eprn_split_FS
545
546
  This function performs Floyd-Steinberg error diffusion on a scan line
547
  and returns the result as bitplanes.
548
549
  'line' points to the scan line to be split, 'next_line' to the following one.
550
  Both lines will be modified by this process. This modification assumes that
551
  the function is called successively for all lines, starting with the first.
552
  All octets up to 'max_octets' must be available in the input lines and, as
553
  far as they have not been included in the length fields, must be zero.
554
  The parameter 'colour_model' specifies the process colour model used.
555
  'black_levels' is the number of intensity levels for the black colorant,
556
  'non_black_levels' the corresponding number for the other colorants.
557
  'bitplanes' is an array of bitplanes into which the result will be stored
558
  in the usual format.
559
560
******************************************************************************/
561
562
void eprn_split_FS(eprn_OctetString *line, eprn_OctetString *next_line,
563
  int max_octets, eprn_ColourModel colour_model,
564
  unsigned int black_levels, unsigned int non_black_levels,
565
  eprn_OctetString bitplanes[])
566
0
{
567
0
  if (colour_model == eprn_DeviceGray) {
568
0
    if (black_levels == 2)
569
0
      split_Gray_2(line, next_line, max_octets, bitplanes);
570
0
    else
571
0
      split_Gray(line, next_line, max_octets, black_levels, bitplanes);
572
0
  }
573
0
  else if (colour_model == eprn_DeviceCMYK &&
574
0
      black_levels == 2 && non_black_levels == 2)
575
0
    split_colour_CMYK_2(line, next_line, max_octets, bitplanes);
576
0
  else {
577
0
    if (black_levels <= 2 && non_black_levels == 2)
578
0
      split_colour_at_most_2(line, next_line, max_octets, colour_model,
579
0
        bitplanes);
580
0
    else
581
0
      split_colour(line, next_line, max_octets, colour_model, black_levels,
582
0
        non_black_levels, bitplanes);
583
0
  }
584
585
0
  return;
586
0
}