Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/base/gxdownscale.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2025 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.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
#include "gxdownscale.h"
18
#include "gserrors.h"
19
#include "string_.h"
20
#include "gdevprn.h"
21
#include "assert_.h"
22
#include "gsicc_cache.h"
23
24
#ifdef WITH_CAL
25
#include "cal_ets.h"
26
#else
27
#include "ets.h"
28
#endif
29
30
/* Nasty inline declaration, as gxht_thresh.h requires penum */
31
void gx_ht_threshold_row_bit_sub(byte *contone,  byte *threshold_strip,
32
                             int contone_stride, byte *halftone,
33
                             int dithered_stride, int width, int num_rows,
34
                             int offset_bits);
35
36
struct gx_downscale_liner_s {
37
    int  (*get_line)(gx_downscale_liner *, void *, int);
38
    void (*drop)(gx_downscale_liner *, gs_memory_t *);
39
};
40
41
enum
42
{
43
    MAX_ETS_PLANES = 8
44
};
45
46
/* Error diffusion data is stored in errors block.
47
 * We have 1 empty entry at each end to avoid overflow. When
48
 * moving left to right we read from entries 2->width+1 (inclusive), and
49
 * write to 1->width. When moving right to left we read from width->1 and
50
 * write to width+1->2.
51
 *
52
 * Minimum feature size data is stored in the mfs_data block.
53
 * We have 1 extra entry at the end to avoid overflow. When moving left to
54
 * right we read from entries 1->width (inclusive), and write to 0->width-1.
55
 * When moving right to left we read from width-1->0 and write to width->1.
56
 */
57
58
enum {
59
    mfs_clear           = 0,
60
    mfs_force_off       = 1,
61
    mfs_above_is_0      = 2,
62
    mfs_above_left_is_0 = 4,
63
};
64
65
/* Mono downscale/error diffusion/min feature size code */
66
67
/* Subsidiary function to pack the data from 8 bits to 1 */
68
static void pack_8to1(byte *outp, byte *inp, int w)
69
0
{
70
0
    int mask  = 128;
71
0
    int value = 0;
72
0
    for (; w > 0; w--)
73
0
    {
74
0
        if (*inp++)
75
0
            value |= mask;
76
0
        mask >>= 1;
77
0
        if (mask == 0) {
78
0
            mask = 128;
79
0
            *outp++= value;
80
0
            value = 0;
81
0
        }
82
0
    }
83
0
    if (mask != 128) {
84
0
        *outp++ = value;
85
0
    }
86
0
}
87
88
static void down_core(gx_downscaler_t *ds,
89
                      byte            *out_buffer,
90
                      byte            *in_buffer,
91
                      int              row,
92
                      int              plane,
93
                      int              span)
94
0
{
95
0
    int        x, xx, y, value;
96
0
    int        e_downleft, e_down, e_forward = 0;
97
0
    int        pad_white;
98
0
    byte      *inp, *outp;
99
0
    int        width     = ds->width;
100
0
    int        awidth    = ds->awidth;
101
0
    int        factor    = ds->factor;
102
0
    int       *errors    = ds->errors + (awidth+3)*plane;
103
0
    const int  threshold = factor*factor*128;
104
0
    const int  max_value = factor*factor*255;
105
106
0
    pad_white = (awidth - width) * factor;
107
0
    if (pad_white < 0)
108
0
        pad_white = 0;
109
110
0
    if (pad_white)
111
0
    {
112
0
        inp = in_buffer + width*factor;
113
0
        for (y = factor; y > 0; y--)
114
0
        {
115
0
            memset(inp, 0xFF, pad_white);
116
0
            inp += span;
117
0
        }
118
0
    }
119
120
0
    inp = in_buffer;
121
0
    if ((row & 1) == 0)
122
0
    {
123
        /* Left to Right pass (no min feature size) */
124
0
        const int back = span * factor - 1;
125
0
        errors += 2;
126
0
        outp = inp;
127
0
        for (x = awidth; x > 0; x--)
128
0
        {
129
0
            value = e_forward + *errors;
130
0
            for (xx = factor; xx > 0; xx--)
131
0
            {
132
0
                for (y = factor; y > 0; y--)
133
0
                {
134
0
                    value += *inp;
135
0
                    inp += span;
136
0
                }
137
0
                inp -= back;
138
0
            }
139
0
            if (value >= threshold)
140
0
            {
141
0
                *outp++ = 1;
142
0
                value -= max_value;
143
0
            }
144
0
            else
145
0
            {
146
0
                *outp++ = 0;
147
0
            }
148
0
            e_forward  = value * 7/16;
149
0
            e_downleft = value * 3/16;
150
0
            e_down     = value * 5/16;
151
0
            value     -= e_forward + e_downleft + e_down;
152
0
            errors[-2] += e_downleft;
153
0
            errors[-1] += e_down;
154
0
            *errors++   = value;
155
0
        }
156
0
        outp -= awidth;
157
0
    }
158
0
    else
159
0
    {
160
        /* Right to Left pass (no min feature size) */
161
0
        const int back = span * factor + 1;
162
0
        errors += awidth;
163
0
        inp += awidth*factor-1;
164
0
        outp = inp;
165
0
        for (x = awidth; x > 0; x--)
166
0
        {
167
0
            value = e_forward + *errors;
168
0
            for (xx = factor; xx > 0; xx--)
169
0
            {
170
0
                for (y = factor; y > 0; y--)
171
0
                {
172
0
                    value += *inp;
173
0
                    inp += span;
174
0
                }
175
0
                inp -= back;
176
0
            }
177
0
            if (value >= threshold)
178
0
            {
179
0
                *outp-- = 1;
180
0
                value -= max_value;
181
0
            }
182
0
            else
183
0
            {
184
0
                *outp-- = 0;
185
0
            }
186
0
            e_forward  = value * 7/16;
187
0
            e_downleft = value * 3/16;
188
0
            e_down     = value * 5/16;
189
0
            value     -= e_forward + e_downleft + e_down;
190
0
            errors[2] += e_downleft;
191
0
            errors[1] += e_down;
192
0
            *errors--   = value;
193
0
        }
194
0
        outp++;
195
0
    }
196
0
    pack_8to1(out_buffer, outp, awidth);
197
0
}
198
199
static void down_core_ets_1(gx_downscaler_t *ds,
200
                            byte            *out_buffer,
201
                            byte            *in_buffer,
202
                            int              row,
203
                            int              plane,
204
                            int              span)
205
0
{
206
0
    unsigned char *dest[MAX_ETS_PLANES];
207
0
    ETS_SrcPixel *src[MAX_ETS_PLANES];
208
0
    int pad_white, y;
209
0
    int factor = ds->factor;
210
211
0
    pad_white = (ds->awidth - ds->width) * factor * 4;
212
0
    if (pad_white < 0)
213
0
        pad_white = 0;
214
215
0
    if (pad_white)
216
0
    {
217
0
        unsigned char *inp = in_buffer + ds->width * factor * 4;
218
0
        for (y = factor; y > 0; y--)
219
0
        {
220
0
            memset(inp, 0xFF, pad_white);
221
0
            inp += span;
222
0
        }
223
0
    }
224
225
0
    if (ds->ets_downscale)
226
0
        ds->ets_downscale(ds, in_buffer, in_buffer, row, plane, span);
227
228
0
    src[0] = in_buffer;
229
0
    dest[0] = in_buffer;
230
0
    ets_line((ETS_Ctx *)ds->ets_config, dest, (const ETS_SrcPixel * const *)src);
231
232
0
    pack_8to1(out_buffer, in_buffer, ds->awidth);
233
0
}
234
235
static void down_core_1(gx_downscaler_t *ds,
236
                        byte            *out_buffer,
237
                        byte            *in_buffer,
238
                        int              row,
239
                        int              plane,
240
                        int              span)
241
0
{
242
0
    int        x, value;
243
0
    int        e_downleft, e_down, e_forward = 0;
244
0
    int        pad_white;
245
0
    byte      *inp, *outp;
246
0
    int        width     = ds->width;
247
0
    int        awidth    = ds->awidth;
248
0
    int       *errors    = ds->errors + (awidth+3)*plane;
249
0
    const int  threshold = 128;
250
0
    const int  max_value = 255;
251
252
0
    pad_white = (awidth - width);
253
0
    if (pad_white < 0)
254
0
        pad_white = 0;
255
256
0
    if (pad_white)
257
0
    {
258
0
        memset(in_buffer + width, 0xFF, pad_white);
259
0
    }
260
261
0
    inp = in_buffer;
262
0
    if ((row & 1) == 0)
263
0
    {
264
        /* Left to Right pass (no min feature size) */
265
0
        errors += 2;
266
0
        outp = inp;
267
0
        for (x = awidth; x > 0; x--)
268
0
        {
269
0
            value = e_forward + *errors + *inp++;
270
0
            if (value >= threshold)
271
0
            {
272
0
                *outp++ = 1;
273
0
                value -= max_value;
274
0
            }
275
0
            else
276
0
            {
277
0
                *outp++ = 0;
278
0
            }
279
0
            e_forward  = value * 7/16;
280
0
            e_downleft = value * 3/16;
281
0
            e_down     = value * 5/16;
282
0
            value     -= e_forward + e_downleft + e_down;
283
0
            errors[-2] += e_downleft;
284
0
            errors[-1] += e_down;
285
0
            *errors++   = value;
286
0
        }
287
0
        outp -= awidth;
288
0
    }
289
0
    else
290
0
    {
291
        /* Right to Left pass (no min feature size) */
292
0
        errors += awidth;
293
0
        inp += awidth-1;
294
0
        outp = inp;
295
0
        for (x = awidth; x > 0; x--)
296
0
        {
297
0
            value = e_forward + *errors + *inp--;
298
0
            if (value >= threshold)
299
0
            {
300
0
                *outp-- = 1;
301
0
                value -= max_value;
302
0
            }
303
0
            else
304
0
            {
305
0
                *outp-- = 0;
306
0
            }
307
0
            e_forward  = value * 7/16;
308
0
            e_downleft = value * 3/16;
309
0
            e_down     = value * 5/16;
310
0
            value     -= e_forward + e_downleft + e_down;
311
0
            errors[2] += e_downleft;
312
0
            errors[1] += e_down;
313
0
            *errors--   = value;
314
0
        }
315
0
        outp++;
316
0
    }
317
0
    pack_8to1(out_buffer, outp, awidth);
318
0
}
319
320
static void down_core_2(gx_downscaler_t *ds,
321
                        byte            *out_buffer,
322
                        byte            *in_buffer,
323
                        int              row,
324
                        int              plane,
325
                        int              span)
326
0
{
327
0
    int        x, value;
328
0
    int        e_downleft, e_down, e_forward = 0;
329
0
    int        pad_white;
330
0
    byte      *inp, *outp;
331
0
    int        width     = ds->width;
332
0
    int        awidth    = ds->awidth;
333
0
    int       *errors    = ds->errors + (awidth+3)*plane;
334
0
    const int  threshold = 2*2*128;
335
0
    const int  max_value = 2*2*255;
336
337
0
    pad_white = (awidth - width) * 2;
338
0
    if (pad_white < 0)
339
0
        pad_white = 0;
340
341
0
    if (pad_white)
342
0
    {
343
0
        inp = in_buffer + width*2;
344
0
        for (x = 2; x > 0; x--)
345
0
        {
346
0
            memset(inp, 0xFF, pad_white);
347
0
            inp += span;
348
0
        }
349
0
    }
350
351
0
    inp = in_buffer;
352
0
    if ((row & 1) == 0)
353
0
    {
354
        /* Left to Right pass (no min feature size) */
355
0
        errors += 2;
356
0
        outp = inp;
357
0
        for (x = awidth; x > 0; x--)
358
0
        {
359
0
            value = e_forward + *errors + inp[0] + inp[1] + inp[span] + inp[span+1];
360
0
            inp += 2;
361
0
            if (value >= threshold)
362
0
            {
363
0
                *outp++ = 1;
364
0
                value -= max_value;
365
0
            }
366
0
            else
367
0
            {
368
0
                *outp++ = 0;
369
0
            }
370
0
            e_forward  = value * 7/16;
371
0
            e_downleft = value * 3/16;
372
0
            e_down     = value * 5/16;
373
0
            value     -= e_forward + e_downleft + e_down;
374
0
            errors[-2] += e_downleft;
375
0
            errors[-1] += e_down;
376
0
            *errors++   = value;
377
0
        }
378
0
        outp -= awidth;
379
0
    }
380
0
    else
381
0
    {
382
        /* Right to Left pass (no min feature size) */
383
0
        errors += awidth;
384
0
        inp += (awidth-1)*2;
385
0
        outp = inp;
386
0
        for (x = awidth; x > 0; x--)
387
0
        {
388
0
            value = e_forward + *errors + inp[0] + inp[1] + inp[span] + inp[span+1];
389
0
            inp -= 2;
390
0
            if (value >= threshold)
391
0
            {
392
0
                *outp-- = 1;
393
0
                value -= max_value;
394
0
            }
395
0
            else
396
0
            {
397
0
                *outp-- = 0;
398
0
            }
399
0
            e_forward  = value * 7/16;
400
0
            e_downleft = value * 3/16;
401
0
            e_down     = value * 5/16;
402
0
            value     -= e_forward + e_downleft + e_down;
403
0
            errors[2] += e_downleft;
404
0
            errors[1] += e_down;
405
0
            *errors--   = value;
406
0
        }
407
0
        outp++;
408
0
    }
409
0
    pack_8to1(out_buffer, outp, awidth);
410
0
}
411
412
static void down_core_3(gx_downscaler_t *ds,
413
                        byte            *out_buffer,
414
                        byte            *in_buffer,
415
                        int              row,
416
                        int              plane,
417
                        int              span)
418
0
{
419
0
    int        x, value;
420
0
    int        e_downleft, e_down, e_forward = 0;
421
0
    int        pad_white;
422
0
    byte      *inp, *outp;
423
0
    int        width     = ds->width;
424
0
    int        awidth    = ds->awidth;
425
0
    int       *errors    = ds->errors + (awidth+3)*plane;
426
0
    const int  threshold = 3*3*128;
427
0
    const int  max_value = 3*3*255;
428
429
0
    pad_white = (awidth - width) * 3;
430
0
    if (pad_white < 0)
431
0
        pad_white = 0;
432
433
0
    if (pad_white)
434
0
    {
435
0
        inp = in_buffer + width*3;
436
0
        for (x = 3; x > 0; x--)
437
0
        {
438
0
            memset(inp, 0xFF, pad_white);
439
0
            inp += span;
440
0
        }
441
0
    }
442
443
0
    inp = in_buffer;
444
0
    if ((row & 1) == 0)
445
0
    {
446
        /* Left to Right pass (no min feature size) */
447
0
        errors += 2;
448
0
        outp = inp;
449
0
        for (x = awidth; x > 0; x--)
450
0
        {
451
0
            value = e_forward + *errors +
452
0
                    inp[     0] + inp[       1] + inp[       2] +
453
0
                    inp[span  ] + inp[span  +1] + inp[span  +2] +
454
0
                    inp[span*2] + inp[span*2+1] + inp[span*2+2];
455
0
            inp += 3;
456
0
            if (value >= threshold)
457
0
            {
458
0
                *outp++ = 1;
459
0
                value -= max_value;
460
0
            }
461
0
            else
462
0
            {
463
0
                *outp++ = 0;
464
0
            }
465
0
            e_forward  = value * 7/16;
466
0
            e_downleft = value * 3/16;
467
0
            e_down     = value * 5/16;
468
0
            value     -= e_forward + e_downleft + e_down;
469
0
            errors[-2] += e_downleft;
470
0
            errors[-1] += e_down;
471
0
            *errors++   = value;
472
0
        }
473
0
        outp -= awidth;
474
0
    }
475
0
    else
476
0
    {
477
        /* Right to Left pass (no min feature size) */
478
0
        errors += awidth;
479
0
        inp += (awidth-1)*3;
480
0
        outp = inp;
481
0
        for (x = awidth; x > 0; x--)
482
0
        {
483
0
            value = e_forward + *errors +
484
0
                    inp[     0] + inp[       1] + inp[       2] +
485
0
                    inp[span  ] + inp[span  +1] + inp[span  +2] +
486
0
                    inp[span*2] + inp[span*2+1] + inp[span*2+2];
487
0
            inp -= 3;
488
0
            if (value >= threshold)
489
0
            {
490
0
                *outp-- = 1;
491
0
                value -= max_value;
492
0
            }
493
0
            else
494
0
            {
495
0
                *outp-- = 0;
496
0
            }
497
0
            e_forward  = value * 7/16;
498
0
            e_downleft = value * 3/16;
499
0
            e_down     = value * 5/16;
500
0
            value     -= e_forward + e_downleft + e_down;
501
0
            errors[2] += e_downleft;
502
0
            errors[1] += e_down;
503
0
            *errors--   = value;
504
0
        }
505
0
        outp++;
506
0
    }
507
0
    pack_8to1(out_buffer, outp, awidth);
508
0
}
509
510
static void down_core_4(gx_downscaler_t *ds,
511
                        byte            *out_buffer,
512
                        byte            *in_buffer,
513
                        int              row,
514
                        int              plane,
515
                        int              span)
516
0
{
517
0
    int        x, value;
518
0
    int        e_downleft, e_down, e_forward = 0;
519
0
    int        pad_white;
520
0
    byte      *inp, *outp;
521
0
    int        width     = ds->width;
522
0
    int        awidth    = ds->awidth;
523
0
    int       *errors    = ds->errors + (awidth+3)*plane;
524
0
    const int  threshold = 4*4*128;
525
0
    const int  max_value = 4*4*255;
526
527
0
    pad_white = (awidth - width) * 4;
528
0
    if (pad_white < 0)
529
0
        pad_white = 0;
530
531
0
    if (pad_white)
532
0
    {
533
0
        inp = in_buffer + width*4;
534
0
        for (x = 4; x > 0; x--)
535
0
        {
536
0
            memset(inp, 0xFF, pad_white);
537
0
            inp += span;
538
0
        }
539
0
    }
540
541
0
    inp = in_buffer;
542
0
    if ((row & 1) == 0)
543
0
    {
544
        /* Left to Right pass (no min feature size) */
545
0
        errors += 2;
546
0
        outp = inp;
547
0
        for (x = awidth; x > 0; x--)
548
0
        {
549
0
            value = e_forward + *errors +
550
0
                    inp[     0] + inp[       1] + inp[       2] + inp[3       ] +
551
0
                    inp[span  ] + inp[span  +1] + inp[span  +2] + inp[span  +3] +
552
0
                    inp[span*2] + inp[span*2+1] + inp[span*2+2] + inp[span*2+3] +
553
0
                    inp[span*3] + inp[span*3+1] + inp[span*3+2] + inp[span*3+3];
554
0
            inp += 4;
555
0
            if (value >= threshold)
556
0
            {
557
0
                *outp++ = 1;
558
0
                value -= max_value;
559
0
            }
560
0
            else
561
0
            {
562
0
                *outp++ = 0;
563
0
            }
564
0
            e_forward  = value * 7/16;
565
0
            e_downleft = value * 3/16;
566
0
            e_down     = value * 5/16;
567
0
            value     -= e_forward + e_downleft + e_down;
568
0
            errors[-2] += e_downleft;
569
0
            errors[-1] += e_down;
570
0
            *errors++   = value;
571
0
        }
572
0
        outp -= awidth;
573
0
    }
574
0
    else
575
0
    {
576
        /* Right to Left pass (no min feature size) */
577
0
        errors += awidth;
578
0
        inp += (awidth-1)*4;
579
0
        outp = inp;
580
0
        for (x = awidth; x > 0; x--)
581
0
        {
582
0
            value = e_forward + *errors +
583
0
                    inp[     0] + inp[       1] + inp[       2] + inp[3       ] +
584
0
                    inp[span  ] + inp[span  +1] + inp[span  +2] + inp[span  +3] +
585
0
                    inp[span*2] + inp[span*2+1] + inp[span*2+2] + inp[span*2+3] +
586
0
                    inp[span*3] + inp[span*3+1] + inp[span*3+2] + inp[span*3+3];
587
0
            inp -= 4;
588
0
            if (value >= threshold)
589
0
            {
590
0
                *outp-- = 1;
591
0
                value -= max_value;
592
0
            }
593
0
            else
594
0
            {
595
0
                *outp-- = 0;
596
0
            }
597
0
            e_forward  = value * 7/16;
598
0
            e_downleft = value * 3/16;
599
0
            e_down     = value * 5/16;
600
0
            value     -= e_forward + e_downleft + e_down;
601
0
            errors[2] += e_downleft;
602
0
            errors[1] += e_down;
603
0
            *errors--   = value;
604
0
        }
605
0
        outp++;
606
0
    }
607
0
    pack_8to1(out_buffer, outp, awidth);
608
0
}
609
610
static void down_core_mfs(gx_downscaler_t *ds,
611
                          byte            *out_buffer,
612
                          byte            *in_buffer,
613
                          int              row,
614
                          int              plane,
615
                          int              span)
616
0
{
617
0
    int        x, xx, y, value;
618
0
    int        e_downleft, e_down, e_forward = 0;
619
0
    int        pad_white;
620
0
    byte      *inp, *outp;
621
0
    int        width     = ds->width;
622
0
    int        awidth    = ds->awidth;
623
0
    int        factor    = ds->factor;
624
0
    int       *errors    = ds->errors + (awidth+3)*plane;
625
0
    byte      *mfs_data  = ds->mfs_data + (awidth+1)*plane;
626
0
    const int  threshold = factor*factor*128;
627
0
    const int  max_value = factor*factor*255;
628
629
0
    pad_white = (awidth - width) * factor;
630
0
    if (pad_white < 0)
631
0
        pad_white = 0;
632
633
0
    if (pad_white)
634
0
    {
635
0
        inp = in_buffer + width*factor;
636
0
        for (y = factor; y > 0; y--)
637
0
        {
638
0
            memset(inp, 0xFF, pad_white);
639
0
            inp += span;
640
0
        }
641
0
    }
642
643
0
    inp = in_buffer;
644
0
    if ((row & 1) == 0)
645
0
    {
646
        /* Left to Right pass (with min feature size = 2) */
647
0
        const int back = span * factor -1;
648
0
        byte mfs, force_forward = 0;
649
0
        errors += 2;
650
0
        outp = inp;
651
0
        *mfs_data++ = mfs_clear;
652
0
        for (x = awidth; x > 0; x--)
653
0
        {
654
0
            value = e_forward + *errors;
655
0
            for (xx = factor; xx > 0; xx--)
656
0
            {
657
0
                for (y = factor; y > 0; y--)
658
0
                {
659
0
                    value += *inp;
660
0
                    inp += span;
661
0
                }
662
0
                inp -= back;
663
0
            }
664
0
            mfs = *mfs_data;
665
0
            *mfs_data++ = mfs_clear;
666
0
            if ((mfs & mfs_force_off) || force_forward)
667
0
            {
668
                /* We are being forced to be 0 */
669
0
                *outp++ = 0;
670
0
                force_forward = 0;
671
0
            }
672
0
            else if (value < threshold)
673
0
            {
674
                /* We want to be 0 anyway */
675
0
                *outp++ = 0;
676
0
                if ((mfs & (mfs_above_is_0 | mfs_above_left_is_0))
677
0
                        != (mfs_above_is_0 | mfs_above_left_is_0))
678
0
                {
679
                    /* We aren't in a group anyway, so must force other
680
                     * pixels. */
681
0
                    mfs_data[-2] |= mfs_force_off;
682
0
                    mfs_data[-1] |= mfs_force_off;
683
0
                    force_forward = 1;
684
0
                }
685
0
                else
686
0
                {
687
                    /* No forcing, but we need to tell other pixels that
688
                     * we were 0. */
689
0
                    mfs_data[-2] |= mfs_above_is_0;
690
0
                    mfs_data[-1] |= mfs_above_left_is_0;
691
0
                }
692
0
            }
693
0
            else
694
0
            {
695
0
                *outp++ = 1;
696
0
                value -= max_value;
697
0
            }
698
0
            e_forward  = value * 7/16;
699
0
            e_downleft = value * 3/16;
700
0
            e_down     = value * 5/16;
701
0
            value     -= e_forward + e_downleft + e_down;
702
0
            errors[-2] += e_downleft;
703
0
            errors[-1] += e_down;
704
0
            *errors++   = value;
705
0
        }
706
0
        outp -= awidth;
707
0
    }
708
0
    else
709
0
    {
710
        /* Right to Left pass (with min feature size = 2) */
711
0
        const int back = span * factor + 1;
712
0
        byte mfs, force_forward = 0;
713
0
        errors += awidth;
714
0
        mfs_data += awidth;
715
0
        inp += awidth*factor-1;
716
0
        outp = inp;
717
0
        *mfs_data-- = mfs_clear;
718
0
        for (x = awidth; x > 0; x--)
719
0
        {
720
0
            value = e_forward + *errors;
721
0
            for (xx = factor; xx > 0; xx--)
722
0
            {
723
0
                for (y = factor; y > 0; y--)
724
0
                {
725
0
                    value += *inp;
726
0
                    inp += span;
727
0
                }
728
0
                inp -= back;
729
0
            }
730
0
            mfs = *mfs_data;
731
0
            *mfs_data-- = mfs_clear;
732
0
            if ((mfs & mfs_force_off) || force_forward)
733
0
            {
734
                /* We are being forced to be 0 */
735
0
                *outp-- = 0;
736
0
                force_forward = 0;
737
0
            }
738
0
            else if (value < threshold)
739
0
            {
740
0
                *outp-- = 0;
741
0
                if ((mfs & (mfs_above_is_0 | mfs_above_left_is_0))
742
0
                        != (mfs_above_is_0 | mfs_above_left_is_0))
743
0
                {
744
                    /* We aren't in a group anyway, so must force other
745
                     * pixels. */
746
0
                    mfs_data[1] |= mfs_force_off;
747
0
                    mfs_data[2] |= mfs_force_off;
748
0
                    force_forward = 1;
749
0
                }
750
0
                else
751
0
                {
752
                    /* No forcing, but we need to tell other pixels that
753
                     * we were 0. */
754
0
                    mfs_data[1] |= mfs_above_is_0;
755
0
                    mfs_data[2] |= mfs_above_left_is_0;
756
0
                }
757
0
            }
758
0
            else
759
0
            {
760
0
                *outp-- = 1;
761
0
                value -= max_value;
762
0
            }
763
0
            e_forward  = value * 7/16;
764
0
            e_downleft = value * 3/16;
765
0
            e_down     = value * 5/16;
766
0
            value     -= e_forward + e_downleft + e_down;
767
0
            errors[2] += e_downleft;
768
0
            errors[1] += e_down;
769
0
            *errors--   = value;
770
0
        }
771
0
        outp++;
772
0
    }
773
0
    pack_8to1(out_buffer, outp, awidth);
774
0
}
775
776
/* CMYK 32 -> 4bit core */
777
static void down_core4(gx_downscaler_t *ds,
778
                       byte            *out_buffer,
779
                       byte            *in_buffer,
780
                       int              row,
781
                       int              plane /* unused */,
782
                       int              span)
783
0
{
784
0
    int        x, xx, y, value, comp;
785
0
    int        e_downleft, e_down, e_forward = 0;
786
0
    int        pad_white;
787
0
    byte      *inp, *outp;
788
0
    int        width     = ds->width;
789
0
    int        awidth    = ds->awidth;
790
0
    int        factor    = ds->factor;
791
0
    int       *errors    = ds->errors;
792
0
    const int  threshold = factor*factor*128;
793
0
    const int  max_value = factor*factor*255;
794
795
0
    pad_white = (awidth - width) * factor * 4;
796
0
    if (pad_white < 0)
797
0
        pad_white = 0;
798
799
0
    if (pad_white)
800
0
    {
801
0
        inp = in_buffer + width*factor * 4;
802
0
        for (y = factor; y > 0; y--)
803
0
        {
804
0
            memset(inp, 0xFF, pad_white);
805
0
            inp += span;
806
0
        }
807
0
    }
808
809
0
    if ((row & 1) == 0)
810
0
    {
811
        /* Left to Right pass (no min feature size) */
812
0
        const int back = span * factor - 4;
813
0
        for (comp = 0; comp < 4; comp++)
814
0
        {
815
0
            errors = ds->errors + (awidth+3)*comp + 2;
816
0
            inp = in_buffer + comp;
817
0
            outp = inp;
818
0
            for (x = awidth; x > 0; x--)
819
0
            {
820
0
                value = e_forward + *errors;
821
0
                for (xx = factor; xx > 0; xx--)
822
0
                {
823
0
                    for (y = factor; y > 0; y--)
824
0
                    {
825
0
                        value += *inp;
826
0
                        inp += span;
827
0
                    }
828
0
                    inp -= back;
829
0
                }
830
0
                if (value >= threshold)
831
0
                {
832
0
                    *outp = 1; outp += 4;
833
0
                    value -= max_value;
834
0
                }
835
0
                else
836
0
                {
837
0
                    *outp = 0; outp += 4;
838
0
                }
839
0
                e_forward  = value * 7/16;
840
0
                e_downleft = value * 3/16;
841
0
                e_down     = value * 5/16;
842
0
                value     -= e_forward + e_downleft + e_down;
843
0
                errors[-2] += e_downleft;
844
0
                errors[-1] += e_down;
845
0
                *errors++   = value;
846
0
            }
847
0
        }
848
0
        outp = in_buffer;
849
0
    }
850
0
    else
851
0
    {
852
        /* Right to Left pass (no min feature size) */
853
0
        const int back = span * factor + 4;
854
0
        for (comp = 0; comp < 4; comp++)
855
0
        {
856
0
            errors = ds->errors + (awidth+3)*comp + awidth;
857
0
            inp = in_buffer + awidth*factor*4 - 4 + comp;
858
0
            outp = inp;
859
0
            for (x = awidth; x > 0; x--)
860
0
            {
861
0
                value = e_forward + *errors;
862
0
                for (xx = factor; xx > 0; xx--)
863
0
                {
864
0
                    for (y = factor; y > 0; y--)
865
0
                    {
866
0
                        value += *inp;
867
0
                        inp += span;
868
0
                    }
869
0
                    inp -= back;
870
0
                }
871
0
                if (value >= threshold)
872
0
                {
873
0
                    *outp = 1; outp -= 4;
874
0
                    value -= max_value;
875
0
                }
876
0
                else
877
0
                {
878
0
                    *outp = 0; outp -= 4;
879
0
                }
880
0
                e_forward  = value * 7/16;
881
0
                e_downleft = value * 3/16;
882
0
                e_down     = value * 5/16;
883
0
                value     -= e_forward + e_downleft + e_down;
884
0
                errors[2] += e_downleft;
885
0
                errors[1] += e_down;
886
0
                *errors--   = value;
887
0
            }
888
0
        }
889
0
        outp = in_buffer + awidth*factor*4 - (awidth*4);
890
0
    }
891
0
    pack_8to1(out_buffer, outp, awidth*4);
892
0
}
893
894
static void down_core4_ht(gx_downscaler_t *ds,
895
                          byte            *out_buffer, /* Guaranteed aligned */
896
                          byte            *in_buffer,  /* Not guaranteed aligned */
897
                          int              row,
898
                          int              plane /* unused */,
899
                          int              span)
900
0
{
901
0
    int pad_white, y;
902
0
    int factor = ds->factor;
903
0
    int i;
904
0
    int nc = ds->early_cm ? ds->post_cm_num_comps : ds->num_comps;
905
0
    byte *downscaled_data = ds->inbuf;
906
907
0
    pad_white = (ds->awidth - ds->width) * factor * 4;
908
0
    if (pad_white < 0)
909
0
        pad_white = 0;
910
911
0
    if (pad_white)
912
0
    {
913
0
        unsigned char *inp = in_buffer + ds->width * factor * 4;
914
0
        for (y = factor; y > 0; y--)
915
0
        {
916
0
            memset(inp, 0xFF, pad_white);
917
0
            inp += span;
918
0
        }
919
0
    }
920
921
    /* Color conversion has already happened. Do any downscale required. */
922
0
    if (ds->ets_downscale)
923
0
        ds->ets_downscale(ds, downscaled_data, in_buffer, row, plane, span);
924
0
    else if ((31 & (intptr_t)in_buffer) == 0)
925
0
        downscaled_data = in_buffer; /* Already aligned! Yay! */
926
0
    else
927
0
        memcpy(downscaled_data, in_buffer,
928
0
               (size_t)nc*ds->width); /* Copy to align */
929
930
    /* Do the halftone */
931
0
    for (i = 0; i < nc; i++)
932
0
    {
933
        /* Make the expanded threshold row */
934
0
        byte *d = ds->htrow + i;
935
0
        int len = ds->width;
936
0
        const byte *srow = ds->ht[i].data + ds->ht[i].stride * ((row + ds->ht[i].y_phase) % ds->ht[i].h);
937
0
        {
938
0
            int o = ds->ht[i].x_phase;
939
0
            int run = ds->ht[i].w - o;
940
0
            const byte *s = &srow[o];
941
0
            if (run > len)
942
0
                run = len;
943
0
            len -= run;
944
0
            do {
945
0
                *d = *s++;
946
0
                d += nc;
947
0
            } while (--run);
948
0
        }
949
0
        while (len)
950
0
        {
951
0
            const byte *s = srow;
952
0
            int run = ds->ht[i].w;
953
0
            if (run > len)
954
0
                run = len;
955
0
            len -= run;
956
0
            do {
957
0
                *d = *s++;
958
0
                d += nc;
959
0
            }
960
0
            while (--run);
961
0
        }
962
0
    }
963
964
    /* Do the halftone */
965
0
    gx_ht_threshold_row_bit_sub(downscaled_data, ds->htrow, 0,
966
0
                                out_buffer, 0,
967
0
                                ds->width * nc, 1, 0);
968
0
}
969
970
static void down_core4_ets(gx_downscaler_t *ds,
971
                           byte            *out_buffer,
972
                           byte            *in_buffer,
973
                           int              row,
974
                           int              plane /* unused */,
975
                           int              span)
976
0
{
977
0
    unsigned char *dest[MAX_ETS_PLANES];
978
0
    ETS_SrcPixel *src[MAX_ETS_PLANES];
979
0
    int pad_white, y;
980
0
    int factor = ds->factor;
981
982
0
    pad_white = (ds->awidth - ds->width) * factor * 4;
983
0
    if (pad_white < 0)
984
0
        pad_white = 0;
985
986
0
    if (pad_white)
987
0
    {
988
0
        unsigned char *inp = in_buffer + ds->width * factor * 4;
989
0
        for (y = factor; y > 0; y--)
990
0
        {
991
0
            memset(inp, 0xFF, pad_white);
992
0
            inp += span;
993
0
        }
994
0
    }
995
996
0
    if (ds->ets_downscale)
997
0
        ds->ets_downscale(ds, in_buffer, in_buffer, row, plane, span);
998
999
0
    src[0] = in_buffer+3;
1000
0
    dest[0] = in_buffer+3;
1001
0
    src[1] = in_buffer+1;
1002
0
    dest[1] = in_buffer+1;
1003
0
    src[2] = in_buffer+0;
1004
0
    dest[2] = in_buffer+0;
1005
0
    src[3] = in_buffer+2;
1006
0
    dest[3] = in_buffer+2;
1007
0
    ets_line((ETS_Ctx *)ds->ets_config, dest, (const ETS_SrcPixel * const *)src);
1008
1009
0
    pack_8to1(out_buffer, in_buffer, ds->awidth * 4);
1010
0
}
1011
1012
static void down_core4_mfs(gx_downscaler_t *ds,
1013
                           byte            *out_buffer,
1014
                           byte            *in_buffer,
1015
                           int              row,
1016
                           int              plane /* unused */,
1017
                           int              span)
1018
0
{
1019
0
    int        x, xx, y, value, comp;
1020
0
    int        e_downleft, e_down, e_forward = 0;
1021
0
    int        pad_white;
1022
0
    byte      *inp, *outp;
1023
0
    int        width     = ds->width;
1024
0
    int        awidth    = ds->awidth;
1025
0
    int        factor    = ds->factor;
1026
0
    int       *errors;
1027
0
    const int  threshold = factor*factor*128;
1028
0
    const int  max_value = factor*factor*255;
1029
0
    byte      *mfs_data;
1030
1031
0
    pad_white = (awidth - width) * factor * 4;
1032
0
    if (pad_white < 0)
1033
0
        pad_white = 0;
1034
1035
0
    if (pad_white)
1036
0
    {
1037
0
        inp = in_buffer + width*factor*4;
1038
0
        for (y = factor*4; y > 0; y--)
1039
0
        {
1040
0
            memset(inp, 0xFF, pad_white);
1041
0
            inp += span;
1042
0
        }
1043
0
    }
1044
1045
0
    if ((row & 1) == 0)
1046
0
    {
1047
        /* Left to Right pass (with min feature size = 2) */
1048
0
        const int back = span * factor - 4;
1049
0
        for (comp = 0; comp < 4; comp++)
1050
0
        {
1051
0
            byte mfs, force_forward = 0;
1052
0
            errors = ds->errors + (awidth+3)*comp + 2;
1053
0
            inp = in_buffer + comp;
1054
0
            outp = inp;
1055
0
            mfs_data = ds->mfs_data + (awidth+1)*comp;
1056
0
            *mfs_data++ = mfs_clear;
1057
0
            for (x = awidth; x > 0; x--)
1058
0
            {
1059
0
                value = e_forward + *errors;
1060
0
                for (xx = factor; xx > 0; xx--)
1061
0
                {
1062
0
                    for (y = factor; y > 0; y--)
1063
0
                    {
1064
0
                        value += *inp;
1065
0
                        inp += span;
1066
0
                    }
1067
0
                    inp -= back;
1068
0
                }
1069
0
                mfs = *mfs_data;
1070
0
                *mfs_data++ = mfs_clear;
1071
0
                if ((mfs & mfs_force_off) || force_forward)
1072
0
                {
1073
                    /* We are being forced to be 0 */
1074
0
                    *outp = 1; outp += 4;
1075
0
                    value -= max_value;
1076
0
                    force_forward = 0;
1077
0
                }
1078
0
                else if (value >= threshold)
1079
0
                {
1080
                    /* We want to be 1 anyway */
1081
0
                    *outp = 1; outp += 4;
1082
0
                    value -= max_value;
1083
0
                    if ((mfs & (mfs_above_is_0 | mfs_above_left_is_0))
1084
0
                            != (mfs_above_is_0 | mfs_above_left_is_0))
1085
0
                    {
1086
                        /* We aren't in a group anyway, so must force other
1087
                         * pixels. */
1088
0
                        mfs_data[-2] |= mfs_force_off;
1089
0
                        mfs_data[-1] |= mfs_force_off;
1090
0
                        force_forward = 1;
1091
0
                    }
1092
0
                    else
1093
0
                    {
1094
                        /* No forcing, but we need to tell other pixels that
1095
                         * we were 1. */
1096
0
                        mfs_data[-2] |= mfs_above_is_0;
1097
0
                        mfs_data[-1] |= mfs_above_left_is_0;
1098
0
                    }
1099
0
                }
1100
0
                else
1101
0
                {
1102
0
                    *outp = 0; outp += 4;
1103
0
                }
1104
0
                e_forward  = value * 7/16;
1105
0
                e_downleft = value * 3/16;
1106
0
                e_down     = value * 5/16;
1107
0
                value     -= e_forward + e_downleft + e_down;
1108
0
                errors[-2] += e_downleft;
1109
0
                errors[-1] += e_down;
1110
0
                *errors++   = value;
1111
0
            }
1112
0
        }
1113
0
        outp = in_buffer;
1114
0
    }
1115
0
    else
1116
0
    {
1117
        /* Right to Left pass (with min feature size = 2) */
1118
0
        const int back = span * factor + 4;
1119
0
        for (comp = 0; comp < 4; comp++)
1120
0
        {
1121
0
            byte mfs, force_forward = 0;
1122
0
            errors = ds->errors + (awidth+3)*comp + awidth;
1123
0
            inp = in_buffer + awidth*factor*4 - 4 + comp;
1124
0
            outp = inp;
1125
0
            mfs_data = ds->mfs_data + (awidth+1)*comp + awidth;
1126
0
            *mfs_data-- = mfs_clear;
1127
0
            for (x = awidth; x > 0; x--)
1128
0
            {
1129
0
                value = e_forward + *errors;
1130
0
                for (xx = factor; xx > 0; xx--)
1131
0
                {
1132
0
                    for (y = factor; y > 0; y--)
1133
0
                    {
1134
0
                        value += *inp;
1135
0
                        inp += span;
1136
0
                    }
1137
0
                    inp -= back;
1138
0
                }
1139
0
                mfs = *mfs_data;
1140
0
                *mfs_data-- = mfs_clear;
1141
0
                if ((mfs & mfs_force_off) || force_forward)
1142
0
                {
1143
                    /* We are being forced to be 0 */
1144
0
                    *outp = 1; outp -= 4;
1145
0
                    value -= max_value;
1146
0
                    force_forward = 0;
1147
0
                }
1148
0
                else if (value >= threshold)
1149
0
                {
1150
0
                    *outp = 1; outp -= 4;
1151
0
                    value -= max_value;
1152
0
                    if ((mfs & (mfs_above_is_0 | mfs_above_left_is_0))
1153
0
                            != (mfs_above_is_0 | mfs_above_left_is_0))
1154
0
                    {
1155
                        /* We aren't in a group anyway, so must force other
1156
                         * pixels. */
1157
0
                        mfs_data[1] |= mfs_force_off;
1158
0
                        mfs_data[2] |= mfs_force_off;
1159
0
                        force_forward = 1;
1160
0
                    }
1161
0
                    else
1162
0
                    {
1163
                        /* No forcing, but we need to tell other pixels that
1164
                         * we were 1. */
1165
0
                        mfs_data[1] |= mfs_above_is_0;
1166
0
                        mfs_data[2] |= mfs_above_left_is_0;
1167
0
                    }
1168
0
                }
1169
0
                else
1170
0
                {
1171
0
                    *outp = 0; outp -= 4;
1172
0
                }
1173
0
                e_forward  = value * 7/16;
1174
0
                e_downleft = value * 3/16;
1175
0
                e_down     = value * 5/16;
1176
0
                value     -= e_forward + e_downleft + e_down;
1177
0
                errors[2] += e_downleft;
1178
0
                errors[1] += e_down;
1179
0
                *errors--   = value;
1180
0
            }
1181
0
        }
1182
0
        outp = in_buffer + awidth*factor*4 - (awidth*4);
1183
0
    }
1184
0
    pack_8to1(out_buffer, outp, awidth*4);
1185
0
}
1186
1187
/* Grey (or planar) downscale code */
1188
static void down_core16(gx_downscaler_t *ds,
1189
                        byte            *outp,
1190
                        byte            *in_buffer,
1191
                        int              row,
1192
                        int              plane,
1193
                        int              span)
1194
0
{
1195
0
    int   x, xx, y, value;
1196
0
    int   pad_white;
1197
0
    byte *inp;
1198
0
    int   width  = ds->width;
1199
0
    int   awidth = ds->awidth;
1200
0
    int   factor = ds->factor;
1201
0
    int   div    = factor*factor;
1202
1203
0
    pad_white = (awidth - width) * factor;
1204
0
    if (pad_white < 0)
1205
0
        pad_white = 0;
1206
1207
0
    if (pad_white)
1208
0
    {
1209
0
        inp = in_buffer + width*2*factor;
1210
0
        for (y = factor; y > 0; y--)
1211
0
        {
1212
0
            memset(inp, 0xFF, pad_white*2);
1213
0
            inp += span;
1214
0
        }
1215
0
    }
1216
1217
0
    inp = in_buffer;
1218
0
    {
1219
        /* Left to Right pass (no min feature size) */
1220
0
        const int back = span * factor -2;
1221
0
        for (x = awidth; x > 0; x--)
1222
0
        {
1223
0
            value = 0;
1224
0
            for (xx = factor; xx > 0; xx--)
1225
0
            {
1226
0
                for (y = factor; y > 0; y--)
1227
0
                {
1228
0
                    value += inp[0]<<8;
1229
0
                    value += inp[1];
1230
0
                    inp += span;
1231
0
                }
1232
0
                inp -= back;
1233
0
            }
1234
0
            value = (value + (div>>1))/div;
1235
0
            outp[0] = value>>8;
1236
0
            outp[1] = value;
1237
0
            outp += 2;
1238
0
        }
1239
0
    }
1240
0
}
1241
1242
static void down_core8(gx_downscaler_t *ds,
1243
                       byte            *outp,
1244
                       byte            *in_buffer,
1245
                       int              row,
1246
                       int              plane,
1247
                       int              span)
1248
0
{
1249
0
    int   x, xx, y, value;
1250
0
    int   pad_white;
1251
0
    byte *inp;
1252
0
    int   width  = ds->width;
1253
0
    int   awidth = ds->awidth;
1254
0
    int   factor = ds->factor;
1255
0
    int   div    = factor*factor;
1256
1257
0
    pad_white = (awidth - width) * factor;
1258
0
    if (pad_white < 0)
1259
0
        pad_white = 0;
1260
1261
0
    if (pad_white)
1262
0
    {
1263
0
        inp = in_buffer + width*factor;
1264
0
        for (y = factor; y > 0; y--)
1265
0
        {
1266
0
            memset(inp, 0xFF, pad_white);
1267
0
            inp += span;
1268
0
        }
1269
0
    }
1270
1271
0
    inp = in_buffer;
1272
0
    {
1273
        /* Left to Right pass (no min feature size) */
1274
0
        const int back = span * factor -1;
1275
0
        for (x = awidth; x > 0; x--)
1276
0
        {
1277
0
            value = 0;
1278
0
            for (xx = factor; xx > 0; xx--)
1279
0
            {
1280
0
                for (y = factor; y > 0; y--)
1281
0
                {
1282
0
                    value += *inp;
1283
0
                    inp += span;
1284
0
                }
1285
0
                inp -= back;
1286
0
            }
1287
0
            *outp++ = (value+(div>>1))/div;
1288
0
        }
1289
0
    }
1290
0
}
1291
1292
static void down_core8_2(gx_downscaler_t *ds,
1293
                         byte            *outp,
1294
                         byte            *in_buffer,
1295
                         int              row,
1296
                         int              plane,
1297
                         int              span)
1298
0
{
1299
0
    int   x;
1300
0
    int   pad_white;
1301
0
    byte *inp;
1302
0
    int   width  = ds->width;
1303
0
    int   awidth = ds->awidth;
1304
1305
0
    pad_white = (awidth - width) * 2;
1306
0
    if (pad_white < 0)
1307
0
        pad_white = 0;
1308
1309
0
    if (pad_white)
1310
0
    {
1311
0
        inp = in_buffer + width*2;
1312
0
        for (x = 2; x > 0; x--)
1313
0
        {
1314
0
            memset(inp, 0xFF, pad_white);
1315
0
            inp += span;
1316
0
        }
1317
0
    }
1318
1319
0
    inp = in_buffer;
1320
1321
    /* Left to Right pass (no min feature size) */
1322
0
    for (x = awidth; x > 0; x--)
1323
0
    {
1324
0
        *outp++ = (inp[0] + inp[1] + inp[span] + inp[span+1] + 2)>>2;
1325
0
        inp += 2;
1326
0
    }
1327
0
}
1328
1329
static void down_core8_3(gx_downscaler_t *ds,
1330
                         byte            *outp,
1331
                         byte            *in_buffer,
1332
                         int              row,
1333
                         int              plane,
1334
                         int              span)
1335
0
{
1336
0
    int   x;
1337
0
    int   pad_white;
1338
0
    byte *inp;
1339
0
    int   width  = ds->width;
1340
0
    int   awidth = ds->awidth;
1341
1342
0
    pad_white = (awidth - width) * 3;
1343
0
    if (pad_white < 0)
1344
0
        pad_white = 0;
1345
1346
0
    if (pad_white)
1347
0
    {
1348
0
        inp = in_buffer + width*3;
1349
0
        for (x = 3; x > 0; x--)
1350
0
        {
1351
0
            memset(inp, 0xFF, pad_white);
1352
0
            inp += span;
1353
0
        }
1354
0
    }
1355
1356
0
    inp = in_buffer;
1357
1358
    /* Left to Right pass (no min feature size) */
1359
0
    for (x = awidth; x > 0; x--)
1360
0
    {
1361
0
        *outp++ = (inp[0     ] + inp[       1] + inp[       2] +
1362
0
                   inp[span  ] + inp[span  +1] + inp[span  +2] +
1363
0
                   inp[span*2] + inp[span*2+1] + inp[span*2+2] + 4)/9;
1364
0
        inp += 3;
1365
0
    }
1366
0
}
1367
1368
static void down_core8_4(gx_downscaler_t *ds,
1369
                         byte            *outp,
1370
                         byte            *in_buffer,
1371
                         int              row,
1372
                         int              plane,
1373
                         int              span)
1374
0
{
1375
0
    int   x;
1376
0
    int   pad_white;
1377
0
    byte *inp;
1378
0
    int   width  = ds->width;
1379
0
    int   awidth = ds->awidth;
1380
1381
0
    pad_white = (awidth - width) * 4;
1382
0
    if (pad_white < 0)
1383
0
        pad_white = 0;
1384
1385
0
    if (pad_white)
1386
0
    {
1387
0
        inp = in_buffer + width*4;
1388
0
        for (x = 4; x > 0; x--)
1389
0
        {
1390
0
            memset(inp, 0xFF, pad_white);
1391
0
            inp += span;
1392
0
        }
1393
0
    }
1394
1395
0
    inp = in_buffer;
1396
1397
    /* Left to Right pass (no min feature size) */
1398
0
    for (x = awidth; x > 0; x--)
1399
0
    {
1400
0
        *outp++ = (inp[0     ] + inp[       1] + inp[       2] + inp[       3] +
1401
0
                   inp[span  ] + inp[span  +1] + inp[span  +2] + inp[span  +3] +
1402
0
                   inp[span*2] + inp[span*2+1] + inp[span*2+2] + inp[span*2+3] +
1403
0
                   inp[span*3] + inp[span*3+1] + inp[span*3+2] + inp[span*3+3] +
1404
0
                   8)>>4;
1405
0
        inp += 4;
1406
0
    }
1407
0
}
1408
1409
static void down_core8_3_2(gx_downscaler_t *ds,
1410
                           byte            *outp,
1411
                           byte            *in_buffer,
1412
                           int              row,
1413
                           int              plane,
1414
                           int              span)
1415
0
{
1416
0
    int   x;
1417
0
    int   pad_white;
1418
0
    byte *inp;
1419
0
    int   width  = ds->width;
1420
0
    int   awidth = ds->awidth;
1421
0
    int   dspan  = ds->scaled_span;
1422
1423
0
    pad_white = (awidth - width) * 3 / 2;
1424
0
    if (pad_white < 0)
1425
0
        pad_white = 0;
1426
1427
0
    if (pad_white)
1428
0
    {
1429
0
        inp = in_buffer + width*3/2;
1430
0
        for (x = 2; x > 0; x--)
1431
0
        {
1432
0
            memset(inp, 0xFF, pad_white);
1433
0
            inp += span;
1434
0
        }
1435
0
    }
1436
1437
0
    inp = in_buffer;
1438
1439
    /* Left to Right pass (no min feature size) */
1440
0
    for (x = awidth/2; x > 0; x--)
1441
0
    {
1442
0
        int a = inp[       0];
1443
0
        int b = inp[       1];
1444
0
        int c = inp[       2];
1445
0
        int d = inp[  span+0];
1446
0
        int e = inp[  span+1];
1447
0
        int f = inp[  span+2];
1448
0
        int g = inp[2*span+0];
1449
0
        int h = inp[2*span+1];
1450
0
        int i = inp[2*span+2];
1451
0
        outp[0      ] = (4*a+2*b+2*d+e+4)/9;
1452
0
        outp[1      ] = (4*c+2*b+2*f+e+4)/9;
1453
0
        outp[dspan+0] = (4*g+2*h+2*d+e+4)/9;
1454
0
        outp[dspan+1] = (4*i+2*h+2*f+e+4)/9;
1455
0
        outp += 2;
1456
0
        inp += 3;
1457
0
    }
1458
0
}
1459
1460
static void down_core8_3_4(gx_downscaler_t *ds,
1461
                           byte            *outp,
1462
                           byte            *in_buffer,
1463
                           int              row,
1464
                           int              plane,
1465
                           int              span)
1466
0
{
1467
0
    int   x;
1468
0
    int   pad_white;
1469
0
    byte *inp;
1470
0
    int   width  = ds->width;
1471
0
    int   awidth = ds->awidth;
1472
0
    int   dspan  = ds->scaled_span;
1473
1474
0
    pad_white = (awidth - width) * 3 / 4;
1475
0
    if (pad_white < 0)
1476
0
        pad_white = 0;
1477
1478
0
    if (pad_white)
1479
0
    {
1480
0
        inp = in_buffer + width*3/4;
1481
0
        for (x = 4; x > 0; x--)
1482
0
        {
1483
0
            memset(inp, 0xFF, pad_white);
1484
0
            inp += span;
1485
0
        }
1486
0
    }
1487
1488
0
    inp = in_buffer;
1489
1490
    /* Left to Right pass (no min feature size) */
1491
0
    for (x = awidth/4; x > 0; x--)
1492
0
    {
1493
0
        int a = inp[       0];
1494
0
        int b = inp[       1];
1495
0
        int c = inp[       2];
1496
0
        int d = inp[  span+0];
1497
0
        int e = inp[  span+1];
1498
0
        int f = inp[  span+2];
1499
0
        int g = inp[2*span+0];
1500
0
        int h = inp[2*span+1];
1501
0
        int i = inp[2*span+2];
1502
0
        outp[        0] = a;
1503
0
        outp[        1] = (a+2*b+1)/3;
1504
0
        outp[        2] = (c+2*b+1)/3;
1505
0
        outp[        3] = c;
1506
0
        outp[  dspan+0] = (a+2*d+1)/3;
1507
0
        outp[  dspan+1] = (a+2*b+2*d+4*e+3)/9;
1508
0
        outp[  dspan+2] = (c+2*b+2*f+4*e+3)/9;
1509
0
        outp[  dspan+3] = (c+2*f+1)/3;
1510
0
        outp[2*dspan+0] = (g+2*d+1)/3;
1511
0
        outp[2*dspan+1] = (g+2*h+2*d+4*e+3)/9;
1512
0
        outp[2*dspan+2] = (i+2*h+2*f+4*e+3)/9;
1513
0
        outp[2*dspan+3] = (i+2*f+1)/3;
1514
0
        outp[3*dspan+0] = g;
1515
0
        outp[3*dspan+1] = (g+2*h+1)/3;
1516
0
        outp[3*dspan+2] = (i+2*h+1)/3;
1517
0
        outp[3*dspan+3] = i;
1518
0
        outp += 4;
1519
0
        inp += 3;
1520
0
    }
1521
0
}
1522
1523
/* RGB downscale (no error diffusion) code */
1524
1525
static void down_core24(gx_downscaler_t *ds,
1526
                        byte            *outp,
1527
                        byte            *in_buffer,
1528
                        int              row,
1529
                        int              plane,
1530
                        int              span)
1531
0
{
1532
0
    int   x, xx, y, value;
1533
0
    int   pad_white;
1534
0
    byte *inp;
1535
0
    int   width  = ds->width;
1536
0
    int   awidth = ds->awidth;
1537
0
    int   factor = ds->factor;
1538
0
    int   div    = factor*factor;
1539
1540
0
    pad_white = (awidth - width) * factor * 3;
1541
0
    if (pad_white < 0)
1542
0
        pad_white = 0;
1543
1544
0
    if (pad_white)
1545
0
    {
1546
0
        inp = in_buffer + width*factor*3;
1547
0
        for (y = factor; y > 0; y--)
1548
0
        {
1549
0
            memset(inp, 0xFF, pad_white);
1550
0
            inp += span;
1551
0
        }
1552
0
    }
1553
1554
0
    inp = in_buffer;
1555
0
    {
1556
        /* Left to Right pass (no min feature size) */
1557
0
        const int back  = span * factor - 3;
1558
0
        const int back2 = factor * 3 - 1;
1559
0
        for (x = awidth; x > 0; x--)
1560
0
        {
1561
            /* R */
1562
0
            value = 0;
1563
0
            for (xx = factor; xx > 0; xx--)
1564
0
            {
1565
0
                for (y = factor; y > 0; y--)
1566
0
                {
1567
0
                    value += *inp;
1568
0
                    inp += span;
1569
0
                }
1570
0
                inp -= back;
1571
0
            }
1572
0
            inp -= back2;
1573
0
            *outp++ = (value+(div>>1))/div;
1574
            /* G */
1575
0
            value = 0;
1576
0
            for (xx = factor; xx > 0; xx--)
1577
0
            {
1578
0
                for (y = factor; y > 0; y--)
1579
0
                {
1580
0
                    value += *inp;
1581
0
                    inp += span;
1582
0
                }
1583
0
                inp -= back;
1584
0
            }
1585
0
            inp -= back2;
1586
0
            *outp++ = (value+(div>>1))/div;
1587
            /* B */
1588
0
            value = 0;
1589
0
            for (xx = factor; xx > 0; xx--)
1590
0
            {
1591
0
                for (y = factor; y > 0; y--)
1592
0
                {
1593
0
                    value += *inp;
1594
0
                    inp += span;
1595
0
                }
1596
0
                inp -= back;
1597
0
            }
1598
0
            inp -= 2;
1599
0
            *outp++ = (value+(div>>1))/div;
1600
0
        }
1601
0
    }
1602
0
}
1603
1604
/* CMYK downscale (no error diffusion) code */
1605
1606
static void down_core32(gx_downscaler_t *ds,
1607
                        byte            *outp,
1608
                        byte            *in_buffer,
1609
                        int              row,
1610
                        int              plane,
1611
                        int              span)
1612
0
{
1613
0
    int   x, xx, y, value;
1614
0
    int   pad_white;
1615
0
    byte *inp;
1616
0
    int   width  = ds->width;
1617
0
    int   awidth = ds->awidth;
1618
0
    int   factor = ds->factor;
1619
0
    int   div    = factor*factor;
1620
1621
0
    pad_white = (awidth - width) * factor * 4;
1622
0
    if (pad_white < 0)
1623
0
        pad_white = 0;
1624
1625
0
    if (pad_white)
1626
0
    {
1627
0
        inp = in_buffer + width*factor*4;
1628
0
        for (y = factor; y > 0; y--)
1629
0
        {
1630
0
            memset(inp, 0xFF, pad_white);
1631
0
            inp += span;
1632
0
        }
1633
0
    }
1634
1635
0
    inp = in_buffer;
1636
0
    {
1637
        /* Left to Right pass (no min feature size) */
1638
0
        const int back  = span * factor - 4;
1639
0
        const int back2 = factor * 4 - 1;
1640
0
        for (x = awidth; x > 0; x--)
1641
0
        {
1642
            /* C */
1643
0
            value = 0;
1644
0
            for (xx = factor; xx > 0; xx--)
1645
0
            {
1646
0
                for (y = factor; y > 0; y--)
1647
0
                {
1648
0
                    value += *inp;
1649
0
                    inp += span;
1650
0
                }
1651
0
                inp -= back;
1652
0
            }
1653
0
            inp -= back2;
1654
0
            *outp++ = (value+(div>>1))/div;
1655
            /* M */
1656
0
            value = 0;
1657
0
            for (xx = factor; xx > 0; xx--)
1658
0
            {
1659
0
                for (y = factor; y > 0; y--)
1660
0
                {
1661
0
                    value += *inp;
1662
0
                    inp += span;
1663
0
                }
1664
0
                inp -= back;
1665
0
            }
1666
0
            inp -= back2;
1667
0
            *outp++ = (value+(div>>1))/div;
1668
            /* Y */
1669
0
            value = 0;
1670
0
            for (xx = factor; xx > 0; xx--)
1671
0
            {
1672
0
                for (y = factor; y > 0; y--)
1673
0
                {
1674
0
                    value += *inp;
1675
0
                    inp += span;
1676
0
                }
1677
0
                inp -= back;
1678
0
            }
1679
0
            inp -= back2;
1680
0
            *outp++ = (value+(div>>1))/div;
1681
            /* K */
1682
0
            value = 0;
1683
0
            for (xx = factor; xx > 0; xx--)
1684
0
            {
1685
0
                for (y = factor; y > 0; y--)
1686
0
                {
1687
0
                    value += *inp;
1688
0
                    inp += span;
1689
0
                }
1690
0
                inp -= back;
1691
0
            }
1692
0
            inp -= 3;
1693
0
            *outp++ = (value+(div>>1))/div;
1694
0
        }
1695
0
    }
1696
0
}
1697
1698
void gx_downscaler_decode_factor(int factor, int *up, int *down)
1699
8.39M
{
1700
8.39M
    if (factor == 32)
1701
0
        *down = 3, *up = 2;
1702
8.39M
    else if (factor == 34)
1703
0
        *down = 3, *up = 4;
1704
8.39M
    else
1705
8.39M
        *down = factor, *up = 1;
1706
8.39M
}
1707
1708
int
1709
gx_downscaler_scale(int width, int factor)
1710
81.7k
{
1711
81.7k
    int up, down;
1712
1713
81.7k
    gx_downscaler_decode_factor(factor, &up, &down);
1714
81.7k
    return (width*up)/down;
1715
81.7k
}
1716
1717
int gx_downscaler_adjust_bandheight(int factor, int band_height)
1718
0
{
1719
0
    int up, down;
1720
1721
0
    gx_downscaler_decode_factor(factor, &up, &down);
1722
0
    return (band_height/down)*down;
1723
0
}
1724
1725
int
1726
gx_downscaler_scale_rounded(int width, int factor)
1727
0
{
1728
0
    int up, down;
1729
1730
0
    gx_downscaler_decode_factor(factor, &up, &down);
1731
0
    return (width*up + down-1)/down;
1732
0
}
1733
1734
typedef struct {
1735
    gx_downscale_liner    base;
1736
    ClapTrap             *claptrap;
1737
    int                   y;
1738
    int                   width;
1739
    int                   height;
1740
    int                   num_comps;
1741
    gs_get_bits_params_t *params;
1742
    gx_downscale_liner   *chain;
1743
} liner_claptrap_planar;
1744
1745
static int
1746
claptrap_planar_line(gx_downscale_liner *liner_, void *buffer, int row)
1747
0
{
1748
0
    liner_claptrap_planar *liner = (liner_claptrap_planar *)liner_;
1749
0
    gs_get_bits_params_t  *params = (gs_get_bits_params_t *)buffer;
1750
1751
0
    liner->params = params;
1752
0
    return ClapTrap_GetLinePlanar(liner->claptrap, params->data);
1753
0
}
1754
1755
static void
1756
claptrap_planar_drop(gx_downscale_liner *liner_, gs_memory_t *mem)
1757
0
{
1758
0
    liner_claptrap_planar *liner = (liner_claptrap_planar *)liner_;
1759
0
    gx_downscale_liner *next;
1760
1761
0
    if (!liner)
1762
0
        return;
1763
0
    ClapTrap_Fin(mem, liner->claptrap);
1764
0
    next = liner->chain;
1765
0
    gs_free_object(mem, liner, "liner_claptrap_planar");
1766
0
    if (next)
1767
0
        next->drop(next, mem);
1768
0
}
1769
1770
static int get_planar_line_for_trap(void *arg, unsigned char *buf)
1771
0
{
1772
0
    liner_claptrap_planar *ct = (liner_claptrap_planar *)arg;
1773
0
    gs_get_bits_params_t params;
1774
0
    int nc = ct->num_comps;
1775
0
    int i, code;
1776
0
    unsigned char *buf2;
1777
1778
0
    params = *ct->params;
1779
0
    buf2 = buf;
1780
0
    for (i = 0; i < nc; i++)
1781
0
    {
1782
0
        params.data[i] = buf2;
1783
0
        buf2 += ct->width;
1784
0
    }
1785
1786
0
    code = ct->chain->get_line(ct->chain, &params, ct->y++);
1787
    /* Allow for devices (like psdcmyk) that make several passes through
1788
     * the image. */
1789
0
    if (ct->y == ct->height)
1790
0
        ct->y = 0;
1791
1792
0
    return code;
1793
0
}
1794
1795
static int check_trapping(gs_memory_t *memory, int trap_w, int trap_h,
1796
                          int num_comps, const int *comp_order)
1797
11.6k
{
1798
11.6k
    if (trap_w < 0 || trap_h < 0)
1799
0
    {
1800
0
        dmprintf(memory, "Trapping range must be >= 0");
1801
0
        return_error(gs_error_rangecheck);
1802
0
    }
1803
1804
11.6k
    if (trap_w > 0 || trap_h > 0)
1805
0
    {
1806
0
        if (comp_order == NULL)
1807
0
        {
1808
0
            emprintf(memory, "Trapping cannot be used without comp_order being defined");
1809
0
            return_error(gs_error_rangecheck);
1810
0
        }
1811
1812
        /* Check that the comp_order we have been passed is sane */
1813
0
        {
1814
0
            char comps[GS_CLIENT_COLOR_MAX_COMPONENTS] = { 0 };
1815
0
            int i;
1816
1817
0
            for (i = 0; i < num_comps; i++)
1818
0
            {
1819
0
                int n = comp_order[i];
1820
0
                if (n < 0 || n >= num_comps || comps[n] != 0)
1821
0
                    break;
1822
0
                comps[n] = 1;
1823
0
            }
1824
0
            if (i != num_comps)
1825
0
            {
1826
0
                emprintf(memory, "Illegal component order passed to trapping");
1827
0
                return_error(gs_error_rangecheck);
1828
0
            }
1829
0
        }
1830
0
    }
1831
11.6k
    return 0;
1832
11.6k
}
1833
1834
static void
1835
find_aspect_ratio(float *res, int *a, int *b)
1836
0
{
1837
0
    float xres = res[0];
1838
0
    float yres = res[1];
1839
0
    float f;
1840
1841
0
    if (xres == yres) {
1842
0
        *a = *b = 1;
1843
0
        return;
1844
0
    }
1845
0
    else if (xres > yres)
1846
0
    {
1847
0
        xres /= yres;
1848
0
        f = xres - (int)xres;
1849
0
        if (f >= 0.2 && f < 0.3)
1850
0
            xres *= 4, yres = 4;
1851
0
        else if (f >= 0.3 && f < 0.4)
1852
0
            xres *= 3, yres = 3;
1853
0
        else if (f >= 0.4 && f < 0.6)
1854
0
            xres *= 2, yres = 2;
1855
0
        else if (f >= 0.6 && f < 0.7)
1856
0
            xres *= 3, yres = 3;
1857
0
        else if (f >= 0.7 && f < 0.8)
1858
0
            xres *= 4, yres = 4;
1859
0
        else
1860
0
            yres = 1;
1861
0
        *a = (int)(xres + 0.5);
1862
0
        *b = (int)yres;
1863
0
    }
1864
0
    else
1865
0
    {
1866
0
        yres /= xres;
1867
0
        f = yres - (int)yres;
1868
0
        if (f >= 0.2 && f < 0.3)
1869
0
            yres *= 4, xres = 4;
1870
0
        else if (f >= 0.3 && f < 0.4)
1871
0
            yres *= 3, xres = 3;
1872
0
        else if (f >= 0.4 && f < 0.6)
1873
0
            yres *= 2, xres = 2;
1874
0
        else if (f >= 0.6 && f < 0.7)
1875
0
            yres *= 3, xres = 3;
1876
0
        else if (f >= 0.7 && f < 0.8)
1877
0
            yres *= 4, xres = 4;
1878
0
        else
1879
0
            xres = 1;
1880
0
        *a = (int)xres;
1881
0
        *b = (int)(yres + 0.5);
1882
0
    }
1883
0
}
1884
1885
static int init_ets(gx_downscaler_t *ds, int num_planes, gx_downscale_core *downscale_core)
1886
0
{
1887
0
    ETS_Params params = { 0 };
1888
0
    int strengths[MAX_ETS_PLANES] = { 128, 51, 51, 13, 13, 13, 13, 13 };
1889
0
    int lut[ETS_SRC_MAX+1];
1890
0
    int *luts[MAX_ETS_PLANES];
1891
0
    int rs_lut[ETS_SRC_MAX+1];
1892
0
    int *rs_luts[MAX_ETS_PLANES];
1893
0
    int i;
1894
0
    int c1_scale[MAX_ETS_PLANES] = { 1, 1, 1, 1, 1, 1, 1, 1 };
1895
0
    ETS_POLARITY polarity = ETS_BLACK_IS_ONE;
1896
1897
0
    polarity = ETS_BLACK_IS_ONE;
1898
1899
0
    if (num_planes > MAX_ETS_PLANES)
1900
0
        return gs_error_rangecheck;
1901
1902
0
    ds->ets_downscale = downscale_core;
1903
1904
    /* Setup a simple gamma scale */
1905
0
    {
1906
0
        double scale = ETS_SRC_MAX;
1907
0
        for (i = 0; i < (ETS_SRC_MAX+1); i++)
1908
0
            lut[i] = (int)((1 << 24) * (pow (i / scale, 1.0)));
1909
0
    }
1910
0
    for (i = 0; i < (ETS_SRC_MAX+1); i++)
1911
0
        rs_lut[i] = 2 << 16;
1912
0
    for (i = 0; i < num_planes; i++)
1913
0
        luts[i] = lut;
1914
0
    for (i = 0; i < num_planes; i++)
1915
0
        rs_luts[i] = rs_lut;
1916
1917
#ifdef WITH_CAL
1918
    params.context = ds->dev->memory->gs_lib_ctx->core->cal_ctx;
1919
#endif
1920
0
    params.width = ds->width;
1921
0
    params.n_planes = num_planes;
1922
0
    params.levels = 2;
1923
0
    params.luts = luts;
1924
0
    params.distscale = 0;
1925
0
    find_aspect_ratio(ds->dev->HWResolution, &params.aspect_x, &params.aspect_y);
1926
0
    params.strengths = strengths;
1927
0
    params.rand_scale = 0;
1928
0
    params.c1_scale = c1_scale;
1929
0
    params.ets_bias = ETS_BIAS_REDUCE_POSITIVE;
1930
0
    params.r_style = ETS_RSTYLE_THRESHOLD;
1931
0
    params.dump_file = NULL;
1932
0
    params.dump_level = 0;
1933
0
    params.rand_scale_luts = rs_luts;
1934
0
    params.polarity = polarity;
1935
1936
0
    ds->ets_config = ets_create(ds->dev->memory, &params);
1937
0
    if (ds->ets_config == NULL)
1938
0
        return gs_note_error(gs_error_VMerror);
1939
1940
0
    return 0;
1941
0
}
1942
1943
static int init_ht(gx_downscaler_t *ds, int num_planes, gx_downscale_core *downscale_core)
1944
0
{
1945
0
    int nc = ds->early_cm ? ds->post_cm_num_comps : ds->num_comps;
1946
1947
0
    ds->ets_downscale = downscale_core;
1948
1949
    /* Allocate us a row (with padding for alignment) so we can hold the
1950
     * expanded threshold array. */
1951
0
    ds->htrow_alloc = gs_alloc_bytes(ds->dev->memory, ds->width * nc + 64,
1952
0
                                     "gx_downscaler(htrow)");
1953
0
    if (ds->htrow_alloc == NULL)
1954
0
        return gs_error_VMerror;
1955
    /* Make an aligned version */
1956
0
    ds->htrow = ds->htrow_alloc + ((32-(intptr_t)ds->htrow_alloc) & 31);
1957
1958
    /* Allocate us a row (with padding for alignment) for the downscaled data. */
1959
0
    ds->inbuf_alloc = gs_alloc_bytes(ds->dev->memory, ds->width * nc + 64,
1960
0
                                     "gx_downscaler(inbuf)");
1961
0
    if (ds->inbuf_alloc == NULL)
1962
0
    {
1963
0
        gs_free_object(ds->dev->memory, ds->htrow_alloc, "gx_downscaler(htrow)");
1964
0
        ds->htrow_alloc = ds->htrow = NULL;
1965
0
        return gs_error_VMerror;
1966
0
    }
1967
    /* Make an aligned version */
1968
0
    ds->inbuf = ds->inbuf_alloc + ((32-(intptr_t)ds->inbuf_alloc) & 31);
1969
1970
0
    return 0;
1971
0
}
1972
1973
int gx_downscaler_init_planar(gx_downscaler_t      *ds,
1974
                              gx_device            *dev,
1975
                              int                   src_bpc,
1976
                              int                   dst_bpc,
1977
                              int                   num_comps,
1978
                        const gx_downscaler_params *params,
1979
                        const gs_get_bits_params_t *gb_params)
1980
7.31k
{
1981
7.31k
    return gx_downscaler_init_planar_cm(ds, dev, src_bpc, dst_bpc,
1982
7.31k
                                        num_comps, params, gb_params,
1983
7.31k
                                        NULL, NULL, num_comps);
1984
7.31k
}
1985
1986
typedef struct {
1987
    gx_downscale_liner  base;
1988
    gx_device          *dev;
1989
} liner_getbits_chunky;
1990
1991
static int
1992
getbits_chunky_line(gx_downscale_liner *liner_, void *buffer, int row)
1993
8.28M
{
1994
8.28M
    liner_getbits_chunky *liner = (liner_getbits_chunky *)liner_;
1995
8.28M
    gs_int_rect rect;
1996
8.28M
    gs_get_bits_params_t params;
1997
1998
8.28M
    rect.p.x = 0;
1999
8.28M
    rect.p.y = row;
2000
8.28M
    rect.q.x = liner->dev->width;
2001
8.28M
    rect.q.y = row+1;
2002
8.28M
    params.x_offset = 0;
2003
8.28M
    params.raster = bitmap_raster(liner->dev->width * liner->dev->color_info.depth);
2004
8.28M
    params.options = (GB_ALIGN_ANY |
2005
8.28M
                      GB_RETURN_COPY |
2006
8.28M
                      GB_OFFSET_0 |
2007
8.28M
                      GB_RASTER_STANDARD | GB_PACKING_CHUNKY |
2008
8.28M
                      GB_COLORS_NATIVE | GB_ALPHA_NONE);
2009
8.28M
    params.data[0] = buffer;
2010
8.28M
    return (*dev_proc(liner->dev, get_bits_rectangle))(liner->dev, &rect, &params);
2011
8.28M
}
2012
2013
static void
2014
getbits_chunky_drop(gx_downscale_liner *liner_, gs_memory_t *mem)
2015
4.34k
{
2016
4.34k
    liner_getbits_chunky *liner = (liner_getbits_chunky *)liner_;
2017
2018
4.34k
    gs_free_object(mem, liner, "liner_getbits_chunky");
2019
4.34k
}
2020
2021
typedef struct {
2022
    gx_downscale_liner  base;
2023
    gx_device          *dev;
2024
    int                 raster;
2025
    int                 num_comps;
2026
} liner_getbits_planar;
2027
2028
static int
2029
getbits_planar_line(gx_downscale_liner *liner_, void *output, int row)
2030
9.51k
{
2031
9.51k
    liner_getbits_planar *liner = (liner_getbits_planar *)liner_;
2032
9.51k
    gs_get_bits_params_t *params = (gs_get_bits_params_t *)output;
2033
9.51k
    gs_get_bits_params_t  params2;
2034
9.51k
    gs_int_rect           rect;
2035
9.51k
    int i, code, n;
2036
2037
9.51k
    rect.p.x = 0;
2038
9.51k
    rect.p.y = row;
2039
9.51k
    rect.q.x = liner->dev->width;
2040
9.51k
    rect.q.y = row+1;
2041
2042
9.51k
    n = liner->dev->width;
2043
9.51k
    if (liner->dev->color_info.depth > liner->dev->color_info.num_components * 8 + 8)
2044
0
        n *= 2;
2045
2046
9.51k
    params2 = *params;
2047
2048
9.51k
    code = (*dev_proc(liner->dev, get_bits_rectangle))(liner->dev, &rect, &params2);
2049
2050
    /* If our caller can't accept a pointer, we need to do some work. */
2051
9.51k
    if (params->options & GB_RETURN_POINTER) {
2052
48.2k
        for (i = 0; i < liner->num_comps; i++)
2053
38.7k
            params->data[i] = params2.data[i];
2054
9.51k
    } else {
2055
        /* get_bits_rectangle doesn't like doing planar copies, only return
2056
         * pointers. This is a problem for us, so fudge it here. */
2057
0
        for (i = 0; i < liner->num_comps; i++)
2058
0
            if (params->data[i] != params2.data[i])
2059
0
                memcpy(params->data[i], params2.data[i], n);
2060
0
    }
2061
2062
9.51k
    return code;
2063
9.51k
}
2064
2065
static void
2066
getbits_planar_drop(gx_downscale_liner *liner_, gs_memory_t *mem)
2067
7.31k
{
2068
7.31k
    liner_getbits_planar *liner = (liner_getbits_planar *)liner_;
2069
2070
7.31k
    gs_free_object(mem, liner, "liner_getbits_planar");
2071
7.31k
}
2072
2073
typedef struct {
2074
    gx_downscale_liner  base;
2075
    ClapTrap           *claptrap;
2076
    int                 y;
2077
    int                 height;
2078
    gx_downscale_liner *chain;
2079
} liner_claptrap;
2080
2081
static int
2082
claptrap_line(gx_downscale_liner *liner_, void *buffer, int row)
2083
0
{
2084
0
    liner_claptrap *liner = (liner_claptrap *)liner_;
2085
2086
0
    return ClapTrap_GetLine(liner->claptrap, buffer);
2087
0
}
2088
2089
static void
2090
claptrap_drop(gx_downscale_liner *liner_, gs_memory_t *mem)
2091
0
{
2092
0
    liner_claptrap *liner = (liner_claptrap *)liner_;
2093
0
    gx_downscale_liner *next;
2094
2095
0
    if (!liner)
2096
0
        return;
2097
0
    ClapTrap_Fin(mem, liner->claptrap);
2098
0
    next = liner->chain;
2099
0
    gs_free_object(mem, liner, "liner_claptrap");
2100
0
    if (next)
2101
0
        next->drop(next, mem);
2102
0
}
2103
2104
#ifdef WITH_CAL
2105
static unsigned char bg0[GX_DEVICE_COLOR_MAX_COMPONENTS] = {0};
2106
static unsigned char bg1[GX_DEVICE_COLOR_MAX_COMPONENTS] = {
2107
    0xFF, 0xFF, 0xFF, 0xFF };
2108
2109
typedef struct {
2110
    gx_downscale_liner   base;
2111
    cal_deskewer        *deskewer[GX_DEVICE_COLOR_MAX_COMPONENTS];
2112
    cal_deskewer_bander *bander[GX_DEVICE_COLOR_MAX_COMPONENTS];
2113
    int                  height;
2114
    int                  get_row;
2115
    int                  got_row;
2116
    int                  num_planes;
2117
    gx_downscale_liner  *chain;
2118
} liner_skew;
2119
2120
static int
2121
skew_line(gx_downscale_liner *liner_, void *buffer, int row)
2122
{
2123
    liner_skew *liner = (liner_skew *)liner_;
2124
    int code;
2125
2126
    if (row < liner->got_row)
2127
       liner->get_row = 0;
2128
2129
    liner->got_row = row;
2130
2131
    while (1) {
2132
        code = cal_deskewer_band_pull(liner->bander[0], buffer);
2133
        if (code == 1)
2134
            return 0; /* We got a line! */
2135
2136
        code = liner->chain->get_line(liner->chain,
2137
                                      buffer,
2138
                                      liner->get_row++);
2139
        if (code < 0)
2140
            return code;
2141
        code = cal_deskewer_band_push(liner->bander[0],
2142
                                      buffer);
2143
        if (code < 0)
2144
            return code;
2145
    }
2146
}
2147
2148
static void
2149
skew_drop(gx_downscale_liner *liner_, gs_memory_t *mem)
2150
{
2151
    liner_skew *liner = (liner_skew *)liner_;
2152
    gx_downscale_liner *next;
2153
    int i;
2154
2155
    if (!liner)
2156
        return;
2157
    for (i = 0; i < liner->num_planes; i++) {
2158
        cal_deskewer_band_end(liner->bander[i], mem);
2159
        cal_deskewer_fin(liner->deskewer[i], mem);
2160
    }
2161
    next = liner->chain;
2162
    gs_free_object(mem, liner, "liner_skew");
2163
    if (next)
2164
        next->drop(next, mem);
2165
}
2166
2167
static int
2168
planar_skew_line(gx_downscale_liner *liner_, void *params_, int row)
2169
{
2170
    liner_skew *liner = (liner_skew *)liner_;
2171
    int code = 0;
2172
    gs_get_bits_params_t *params = (gs_get_bits_params_t *)params_;
2173
    int i;
2174
2175
    if (row < liner->got_row)
2176
       liner->get_row = 0;
2177
2178
    liner->got_row = row;
2179
2180
    while (1) {
2181
        for (i = 0; i < liner->num_planes; i++) {
2182
            code = cal_deskewer_band_pull(liner->bander[i], params->data[i]);
2183
            if (code < 0)
2184
                return code;
2185
        }
2186
        if (code == 1)
2187
            return 0; /* We got a line! */
2188
2189
        code = liner->chain->get_line(liner->chain,
2190
                                      params,
2191
                                      liner->get_row++);
2192
        if (code < 0)
2193
            return code;
2194
2195
        for (i = 0; i < liner->num_planes; i++) {
2196
            code = cal_deskewer_band_push(liner->bander[i],
2197
                                          params->data[i]);
2198
            if (code < 0)
2199
                return code;
2200
        }
2201
    }
2202
}
2203
2204
static void
2205
planar_skew_drop(gx_downscale_liner *liner_, gs_memory_t *mem)
2206
{
2207
    liner_skew *liner = (liner_skew *)liner_;
2208
    gx_downscale_liner *next;
2209
    int i;
2210
2211
    if (!liner)
2212
        return;
2213
    for (i = 0; i < liner->num_planes; i++) {
2214
        cal_deskewer_band_end(liner->bander[i], mem);
2215
        cal_deskewer_fin(liner->deskewer[i], mem);
2216
    }
2217
    next = liner->chain;
2218
    gs_free_object(mem, liner, "liner_skew");
2219
    if (next)
2220
        next->drop(next, mem);
2221
}
2222
#endif
2223
2224
#define alloc_liner(mem, type, get, drop, res) \
2225
11.6k
    do_alloc_liner(mem, sizeof(type), #type, get, drop,\
2226
11.6k
                   (gx_downscale_liner **)res)
2227
2228
static int
2229
do_alloc_liner(gs_memory_t *mem, size_t size, const char *type,
2230
               int (*get_line)(gx_downscale_liner *, void *, int),
2231
               void (*drop)(gx_downscale_liner *, gs_memory_t *),
2232
               gx_downscale_liner **res)
2233
11.6k
{
2234
11.6k
    gx_downscale_liner *liner;
2235
2236
11.6k
    liner = (gx_downscale_liner *)gs_alloc_bytes(mem, size, type);
2237
11.6k
    *res = liner;
2238
11.6k
    if (liner == NULL)
2239
0
        return_error(gs_error_VMerror);
2240
11.6k
    liner->get_line = get_line;
2241
11.6k
    liner->drop = drop;
2242
11.6k
    return 0;
2243
11.6k
}
2244
2245
int gx_downscaler_init_planar_cm(gx_downscaler_t      *ds,
2246
                                 gx_device            *dev,
2247
                                 int                   src_bpc,
2248
                                 int                   dst_bpc,
2249
                                 int                   num_comps,
2250
                           const gx_downscaler_params *params,
2251
                           const gs_get_bits_params_t *gb_params,
2252
                                 gx_downscale_cm_fn   *apply_cm,
2253
                                 void                 *apply_cm_arg,
2254
                                 int                   post_cm_num_comps)
2255
7.31k
{
2256
7.31k
    int                span = bitmap_raster(dev->width * src_bpc);
2257
7.31k
    int                post_span = bitmap_raster(dev->width * src_bpc);
2258
7.31k
    int                width;
2259
7.31k
    int                code;
2260
7.31k
    gx_downscale_core *core;
2261
7.31k
    int                i;
2262
7.31k
    int                upfactor, downfactor;
2263
7.31k
    int                factor = params->downscale_factor;
2264
7.31k
    int                mfs = params->min_feature_size;
2265
2266
7.31k
    gx_downscaler_decode_factor(factor, &upfactor, &downfactor);
2267
2268
    /* width = scaled width */
2269
7.31k
    width = (dev->width*upfactor)/downfactor;
2270
7.31k
    memset(ds, 0, sizeof(*ds));
2271
7.31k
    ds->dev               = dev;
2272
7.31k
    ds->width             = width;
2273
7.31k
    ds->awidth            = width;
2274
7.31k
    ds->span              = span;
2275
7.31k
    ds->factor            = factor;
2276
7.31k
    ds->num_planes        = num_comps;
2277
7.31k
    ds->src_bpc           = src_bpc;
2278
7.31k
    ds->dst_bpc           = dst_bpc;
2279
7.31k
    ds->scaled_data       = NULL;
2280
7.31k
    ds->scaled_span       = bitmap_raster((dst_bpc*dev->width*upfactor + downfactor-1)/downfactor);
2281
7.31k
    ds->apply_cm          = apply_cm;
2282
7.31k
    ds->apply_cm_arg      = apply_cm_arg;
2283
7.31k
    ds->early_cm          = dst_bpc < src_bpc || (dst_bpc == src_bpc && post_cm_num_comps < num_comps);
2284
7.31k
    ds->post_cm_num_comps = post_cm_num_comps;
2285
7.31k
    ds->do_skew_detection = params->do_skew_detection;
2286
2287
7.31k
    if (apply_cm) {
2288
0
        ds->post_cm[0] = gs_alloc_bytes(dev->memory,
2289
0
                                        (size_t)post_span * downfactor * post_cm_num_comps,
2290
0
                                        "gx_downscaler(planar_data)");
2291
0
        if (ds->post_cm[0] == NULL) {
2292
0
            code = gs_note_error(gs_error_VMerror);
2293
0
            goto cleanup;
2294
0
        }
2295
0
        for (i = 1; i < post_cm_num_comps; i++) {
2296
0
            ds->post_cm[i] = ds->post_cm[i-1] + (size_t)post_span * downfactor;
2297
0
        }
2298
0
    }
2299
2300
    /* The primary line source for planar comes always from
2301
    * get_bits_rectangle. */
2302
7.31k
    {
2303
7.31k
        liner_getbits_planar *gb_liner;
2304
2305
7.31k
        code = alloc_liner(dev->memory,
2306
7.31k
                           liner_getbits_planar,
2307
7.31k
                           getbits_planar_line,
2308
7.31k
                           getbits_planar_drop,
2309
7.31k
                           &gb_liner);
2310
7.31k
        if (code < 0)
2311
0
            goto cleanup;
2312
7.31k
        gb_liner->dev = dev;
2313
7.31k
        gb_liner->num_comps = num_comps;
2314
7.31k
        ds->liner = &gb_liner->base;
2315
7.31k
    }
2316
2317
0
    memcpy(&ds->params, gb_params, sizeof(*gb_params));
2318
7.31k
    ds->params.raster = span;
2319
7.31k
    ds->pre_cm[0] = gs_alloc_bytes(dev->memory,
2320
7.31k
                                   (size_t)span * downfactor * num_comps,
2321
7.31k
                                   "gx_downscaler(planar_data)");
2322
2323
7.31k
    if (ds->pre_cm[0] == NULL) {
2324
0
        code = gs_note_error(gs_error_VMerror);
2325
0
        goto cleanup;
2326
0
    }
2327
2328
29.9k
    for (i = 1; i < num_comps; i++) {
2329
22.5k
        ds->pre_cm[i] = ds->pre_cm[i-1] + (size_t)span * downfactor;
2330
22.5k
    }
2331
2332
#ifdef WITH_CAL
2333
    if (ds->do_skew_detection) {
2334
        /* Do a skew detection pass */
2335
        int j;
2336
        int w = ds->dev->width;
2337
        int h = ds->dev->height;
2338
        cal_skew *skew;
2339
2340
        for (i = 0; i < num_comps; i++) {
2341
            ds->params.data[i] = ds->pre_cm[i];
2342
        }
2343
2344
        skew = cal_skew_init(ds->dev->memory->gs_lib_ctx->core->cal_ctx,
2345
                             ds->dev->memory,
2346
                             w, h);
2347
        if (skew == NULL)
2348
            code = gs_error_VMerror;
2349
        for (j = 0; code >= 0 && j < h; j++) {
2350
            gs_get_bits_params_t params2 = ds->params;
2351
            code = ds->liner->get_line(ds->liner, &params2, j);
2352
            /* Craply turn that into "greyscale" - this assumes 8 bit. */
2353
            if (num_comps > 1) {
2354
                int i, k;
2355
                byte *dst = ds->params.data[0];
2356
                for (i = 0; i < w; i++) {
2357
                    int v = 0;
2358
                    for (k = num_comps-1; k > 0; k--)
2359
                        v += ((unsigned char *)params2.data[k])[i];
2360
                    *dst++ = (v+(num_comps>>1))/num_comps;
2361
                 }
2362
            }
2363
            code = cal_skew_process(skew, ds->dev->memory, ds->params.data[0]);
2364
        }
2365
        if (code >= 0) {
2366
            ds->skew_angle = cal_skew_detect(skew, ds->dev->memory);
2367
            if (ds->skew_angle < -45 || ds->skew_angle > 45)
2368
                ds->skew_angle = 0;
2369
        }
2370
        cal_skew_fin(skew, ds->dev->memory);
2371
        if (code < 0)
2372
            goto cleanup;
2373
2374
        if (ds->skew_angle != 0) {
2375
            liner_skew *sk_liner;
2376
            unsigned int dw, dh;
2377
2378
            code = alloc_liner(dev->memory,
2379
                               liner_skew,
2380
                               planar_skew_line,
2381
                               planar_skew_drop,
2382
                               &sk_liner);
2383
            if (code < 0)
2384
                goto cleanup;
2385
            sk_liner->chain = ds->liner;
2386
            sk_liner->get_row = 0;
2387
            sk_liner->got_row = 0;
2388
            sk_liner->height = dev->height;
2389
            sk_liner->num_planes = num_comps;
2390
            ds->liner = &sk_liner->base;
2391
            for (i = 0; i < num_comps; i++)
2392
            {
2393
                sk_liner->deskewer[i] = cal_deskewer_init(
2394
                             ds->dev->memory->gs_lib_ctx->core->cal_ctx,
2395
                             ds->dev->memory,
2396
                             ds->dev->width, ds->dev->height,
2397
                             &dw,
2398
                             &dh,
2399
                             ds->skew_angle,
2400
                             1, /* Keep the page size constant */
2401
                             1.0, 1.0, 1.0, 1.0,
2402
                             bg0,
2403
                             1);
2404
                if (sk_liner->deskewer[i] == NULL) {
2405
                    emprintf(dev->memory, "Deskewer initialisation failed");
2406
                    code = gs_note_error(gs_error_VMerror);
2407
                    goto cleanup;
2408
                }
2409
                sk_liner->bander[i] = cal_deskewer_band_begin(sk_liner->deskewer[i],
2410
                                                              ds->dev->memory,
2411
                                                              0, 0);
2412
                if (sk_liner->bander[i] == NULL) {
2413
                    emprintf(dev->memory, "Deskewer initialisation(2) failed");
2414
                    code = gs_note_error(gs_error_VMerror);
2415
                    goto cleanup;
2416
                }
2417
            }
2418
        }
2419
    }
2420
#endif
2421
2422
7.31k
    code = check_trapping(dev->memory, params->trap_w, params->trap_h,
2423
7.31k
                          num_comps, params->trap_order);
2424
7.31k
    if (code < 0)
2425
0
        return code;
2426
2427
7.31k
    if (params->trap_w > 0 || params->trap_h > 0) {
2428
0
        liner_claptrap_planar *ct_liner;
2429
2430
0
        code = alloc_liner(dev->memory,
2431
0
                           liner_claptrap_planar,
2432
0
                           claptrap_planar_line,
2433
0
                           claptrap_planar_drop,
2434
0
                           &ct_liner);
2435
0
        if (code < 0)
2436
0
            goto cleanup;
2437
0
        ct_liner->chain     = ds->liner;
2438
0
        ct_liner->y         = 0;
2439
0
        ct_liner->height    = dev->height;
2440
0
        ct_liner->num_comps = ds->num_comps;
2441
0
        ct_liner->width     = dev->width;
2442
0
        ds->liner = &ct_liner->base;
2443
0
        ct_liner->claptrap = ClapTrap_Init(dev->memory,
2444
0
                                           dev->width,
2445
0
                                           dev->height,
2446
0
                                           num_comps,
2447
0
                                           params->trap_order,
2448
0
                                           params->trap_w,
2449
0
                                           params->trap_h,
2450
0
                                           get_planar_line_for_trap,
2451
0
                                           ct_liner);
2452
0
        if (ct_liner->claptrap == NULL) {
2453
0
            emprintf(dev->memory, "Trapping initialisation failed");
2454
0
            code = gs_note_error(gs_error_VMerror);
2455
0
            goto cleanup;
2456
0
        }
2457
0
    }
2458
2459
7.31k
    if (upfactor > 1) {
2460
0
        ds->scaled_data = gs_alloc_bytes(dev->memory,
2461
0
                                         (size_t)ds->scaled_span * upfactor * num_comps,
2462
0
                                         "gx_downscaler(scaled_data)");
2463
0
        if (ds->scaled_data == NULL) {
2464
0
            code = gs_note_error(gs_error_VMerror);
2465
0
            goto cleanup;
2466
0
        }
2467
0
    }
2468
2469
7.31k
    if ((src_bpc == 8) && (dst_bpc == 8) && (factor == 32)) {
2470
0
        core = &down_core8_3_2;
2471
7.31k
    } else if ((src_bpc == 8) && (dst_bpc == 8) && (factor == 34)) {
2472
0
        core = &down_core8_3_4;
2473
7.31k
    } else if (factor > 8) {
2474
0
        code = gs_note_error(gs_error_rangecheck);
2475
0
        goto cleanup;
2476
7.31k
    } else if (dst_bpc == 1) {
2477
0
        if (src_bpc == dst_bpc)
2478
0
            core = NULL;
2479
0
        else if (mfs > 1)
2480
0
            core = &down_core_mfs;
2481
0
        else if (factor == 4)
2482
0
            core = &down_core_4;
2483
0
        else if (factor == 3)
2484
0
            core = &down_core_3;
2485
0
        else if (factor == 2)
2486
0
            core = &down_core_2;
2487
0
        else if (factor == 1)
2488
0
            core = &down_core_1;
2489
0
        else
2490
0
            core = &down_core;
2491
7.31k
    } else if (factor == 1)
2492
7.31k
        core = NULL;
2493
0
    else if (src_bpc == 16)
2494
0
        core = &down_core16;
2495
0
    else if (factor == 4)
2496
0
        core = &down_core8_4;
2497
0
    else if (factor == 3)
2498
0
        core = &down_core8_3;
2499
0
    else if (factor == 2)
2500
0
        core = &down_core8_2;
2501
0
    else
2502
0
        core = &down_core8;
2503
7.31k
    ds->down_core = core;
2504
2505
7.31k
    if (mfs > 1) {
2506
0
        ds->mfs_data = (byte *)gs_alloc_bytes(dev->memory,
2507
0
                                              (size_t)(width+1) * num_comps,
2508
0
                                              "gx_downscaler(mfs)");
2509
0
        if (ds->mfs_data == NULL) {
2510
0
            code = gs_note_error(gs_error_VMerror);
2511
0
            goto cleanup;
2512
0
        }
2513
0
        memset(ds->mfs_data, 0, (size_t)num_comps * (width+1));
2514
0
    }
2515
7.31k
    if (dst_bpc == 1) {
2516
0
        ds->errors = (int *)gs_alloc_bytes(dev->memory,
2517
0
                                           (size_t)num_comps*(width+3)*sizeof(int),
2518
0
                                           "gx_downscaler(errors)");
2519
0
        if (ds->errors == NULL) {
2520
0
            code = gs_note_error(gs_error_VMerror);
2521
0
            goto cleanup;
2522
0
        }
2523
0
        memset(ds->errors, 0, (size_t)num_comps * (width+3) * sizeof(int));
2524
0
    }
2525
2526
7.31k
    return 0;
2527
2528
0
  cleanup:
2529
0
    gx_downscaler_fin(ds);
2530
0
    return code;
2531
7.31k
}
2532
2533
static int get_line_for_trap(void *arg, unsigned char *buf)
2534
0
{
2535
0
    liner_claptrap *ct = (liner_claptrap *)arg;
2536
2537
    /* Allow for devices (like psdcmyk) that make several passes through
2538
     * the image. This is a bit crap cos it assumes that we will pass
2539
     * through strictly from top to bottom (possibly repeatedly). */
2540
0
    if (ct->y == ct->height)
2541
0
        ct->y = 0;
2542
2543
0
    return ct->chain->get_line(ct->chain, buf, ct->y++);
2544
0
}
2545
2546
int gx_downscaler_init(gx_downscaler_t      *ds,
2547
                       gx_device            *dev,
2548
                       int                   src_bpc,
2549
                       int                   dst_bpc,
2550
                       int                   num_comps,
2551
                 const gx_downscaler_params *params,
2552
                       int                 (*adjust_width_proc)(int, int),
2553
                       int                   adjust_width)
2554
4.34k
{
2555
4.34k
    return gx_downscaler_init_cm(ds, dev, src_bpc, dst_bpc, num_comps,
2556
4.34k
                                 params, adjust_width_proc, adjust_width,
2557
4.34k
                                 NULL, NULL, 0);
2558
4.34k
}
2559
2560
static gx_downscaler_ht_t bogus_ets_halftone;
2561
2562
int gx_downscaler_init_cm(gx_downscaler_t      *ds,
2563
                          gx_device            *dev,
2564
                          int                   src_bpc,
2565
                          int                   dst_bpc,
2566
                          int                   num_comps,
2567
                    const gx_downscaler_params *params,
2568
                          int                 (*adjust_width_proc)(int, int),
2569
                          int                   adjust_width,
2570
                          gx_downscale_cm_fn   *apply_cm,
2571
                          void                 *apply_cm_arg,
2572
                          int                   post_cm_num_comps)
2573
4.34k
{
2574
4.34k
    return gx_downscaler_init_cm_halftone(ds, dev, src_bpc, dst_bpc,
2575
4.34k
                                          num_comps, params,
2576
4.34k
                                          adjust_width_proc, adjust_width,
2577
4.34k
                                          apply_cm, apply_cm_arg,
2578
4.34k
                                          post_cm_num_comps,
2579
4.34k
                                          params->ets ? &bogus_ets_halftone : NULL);
2580
4.34k
}
2581
2582
static gx_downscale_core *
2583
select_8_to_8_core(int nc, int factor)
2584
0
{
2585
0
    if (factor == 1)
2586
0
        return NULL; /* No sense doing anything */
2587
0
    if (nc == 1)
2588
0
    {
2589
0
        if (factor == 4)
2590
0
            return &down_core8_4;
2591
0
        else if (factor == 3)
2592
0
            return &down_core8_3;
2593
0
        else if (factor == 2)
2594
0
            return &down_core8_2;
2595
0
        else
2596
0
            return &down_core8;
2597
0
    }
2598
0
    else if (nc == 3)
2599
0
        return &down_core24;
2600
0
    else if (nc == 4)
2601
0
        return &down_core32;
2602
2603
0
    return NULL;
2604
0
}
2605
2606
int
2607
gx_downscaler_init_cm_halftone(gx_downscaler_t      *ds,
2608
                               gx_device            *dev,
2609
                               int                   src_bpc,
2610
                               int                   dst_bpc,
2611
                               int                   num_comps,
2612
                         const gx_downscaler_params *params,
2613
                               int                 (*adjust_width_proc)(int, int),
2614
                               int                   adjust_width,
2615
                               gx_downscale_cm_fn   *apply_cm,
2616
                               void                 *apply_cm_arg,
2617
                               int                   post_cm_num_comps,
2618
                               gx_downscaler_ht_t   *ht)
2619
4.34k
{
2620
4.34k
    int                size;
2621
4.34k
    int                post_size;
2622
4.34k
    int                span;
2623
4.34k
    int                width;
2624
4.34k
    int                awidth;
2625
4.34k
    int                pad_white;
2626
4.34k
    int                code = 0;
2627
4.34k
    gx_downscale_core *core;
2628
4.34k
    int                upfactor;
2629
4.34k
    int                downfactor;
2630
4.34k
    int                nc;
2631
4.34k
    int                factor = params->downscale_factor;
2632
4.34k
    int                mfs = params->min_feature_size;
2633
2634
4.34k
    size = gdev_mem_bytes_per_scan_line((gx_device *)dev);
2635
4.34k
    post_size = bitmap_raster(dev->width * src_bpc * post_cm_num_comps);
2636
2637
4.34k
    gx_downscaler_decode_factor(factor, &upfactor, &downfactor);
2638
2639
    /* width = scaled width */
2640
4.34k
    width = (dev->width * upfactor)/downfactor;
2641
4.34k
    awidth = width;
2642
4.34k
    if (adjust_width_proc != NULL)
2643
0
        awidth = (*adjust_width_proc)(width, adjust_width);
2644
4.34k
    pad_white = awidth - width;
2645
4.34k
    if (pad_white < 0)
2646
0
        pad_white = 0;
2647
2648
    /* size = unscaled size. span = unscaled size + padding */
2649
4.34k
    span = size + pad_white*downfactor*num_comps/upfactor + downfactor-1;
2650
4.34k
    memset(ds, 0, sizeof(*ds));
2651
4.34k
    ds->dev               = dev;
2652
4.34k
    ds->width             = width;
2653
4.34k
    ds->awidth            = awidth;
2654
4.34k
    ds->span              = span;
2655
4.34k
    ds->factor            = factor;
2656
4.34k
    ds->num_planes        = 0;
2657
4.34k
    ds->src_bpc           = src_bpc;
2658
4.34k
    ds->apply_cm          = apply_cm;
2659
4.34k
    ds->apply_cm_arg      = apply_cm_arg;
2660
4.34k
    ds->early_cm          = dst_bpc < src_bpc;
2661
4.34k
    ds->post_cm_num_comps = post_cm_num_comps;
2662
4.34k
    ds->ht                = ht;
2663
4.34k
    ds->dst_bpc           = dst_bpc;
2664
4.34k
    ds->num_comps         = num_comps;
2665
4.34k
    ds->do_skew_detection = params->do_skew_detection;
2666
2667
    /* The primary line source comes always from getbits. */
2668
4.34k
    {
2669
4.34k
        liner_getbits_chunky *gb_liner;
2670
2671
4.34k
        code = alloc_liner(dev->memory,
2672
4.34k
                           liner_getbits_chunky,
2673
4.34k
                           getbits_chunky_line,
2674
4.34k
                           getbits_chunky_drop,
2675
4.34k
                           &gb_liner);
2676
4.34k
        if (code < 0)
2677
0
            goto cleanup;
2678
4.34k
        gb_liner->dev = dev;
2679
4.34k
        ds->liner = &gb_liner->base;
2680
4.34k
    }
2681
2682
#ifdef WITH_CAL
2683
    if (ds->do_skew_detection) {
2684
        /* Do a skew detection pass */
2685
        int j;
2686
        int w = ds->dev->width;
2687
        int h = ds->dev->height;
2688
        int n = ds->dev->color_info.num_components;
2689
        cal_skew *skew;
2690
        byte *buffer = gs_alloc_bytes(ds->dev->memory, w*n, "skew_row");
2691
        if (buffer == NULL)
2692
            return_error(gs_error_VMerror);
2693
        skew = cal_skew_init(ds->dev->memory->gs_lib_ctx->core->cal_ctx,
2694
                             ds->dev->memory,
2695
                             w, h);
2696
        if (skew == NULL)
2697
            code = gs_error_VMerror;
2698
        for (j = 0; code >= 0 && j < h; j++) {
2699
            code = ds->liner->get_line(ds->liner, buffer, j);
2700
            /* Craply turn that into "greyscale" */
2701
            if (n > 1) {
2702
                int i, k;
2703
                const byte *src = buffer;
2704
                byte *dst = buffer;
2705
                for (i = w; i > 0; i--) {
2706
                    int v = 0;
2707
                    for (k = n; k > 0; k--)
2708
                        v += *src++;
2709
                    *dst++ = (v+(n>>1))/n;
2710
                 }
2711
            }
2712
            code = cal_skew_process(skew, ds->dev->memory, buffer);
2713
        }
2714
        if (code >= 0)
2715
            ds->skew_angle = cal_skew_detect(skew, ds->dev->memory);
2716
        gs_free_object(ds->dev->memory, buffer, "skew_row");
2717
        cal_skew_fin(skew, ds->dev->memory);
2718
        if (code < 0)
2719
            goto cleanup;
2720
2721
        if (ds->skew_angle != 0) {
2722
            liner_skew *sk_liner;
2723
            unsigned int dw, dh;
2724
2725
            code = alloc_liner(dev->memory,
2726
                               liner_skew,
2727
                               skew_line,
2728
                               skew_drop,
2729
                               &sk_liner);
2730
            if (code < 0)
2731
                goto cleanup;
2732
            sk_liner->chain = ds->liner;
2733
            sk_liner->get_row = 0;
2734
            sk_liner->got_row = 0;
2735
            sk_liner->height = dev->height;
2736
            sk_liner->num_planes = 1;
2737
            ds->liner = &sk_liner->base;
2738
            sk_liner->deskewer[0] = cal_deskewer_init(
2739
                             ds->dev->memory->gs_lib_ctx->core->cal_ctx,
2740
                             ds->dev->memory,
2741
                             ds->dev->width, ds->dev->height,
2742
                             &dw,
2743
                             &dh,
2744
                             ds->skew_angle,
2745
                             1, /* Keep the page size constant */
2746
                             1.0, 1.0, 1.0, 1.0,
2747
                             (ds->num_comps <= 3 ? bg1 : bg0),
2748
                             ds->num_comps);
2749
            if (sk_liner->deskewer[0] == NULL) {
2750
                emprintf(dev->memory, "Deskewer initialisation failed");
2751
                code = gs_note_error(gs_error_VMerror);
2752
                goto cleanup;
2753
            }
2754
            sk_liner->bander[0] = cal_deskewer_band_begin(sk_liner->deskewer[0],
2755
                                                       ds->dev->memory,
2756
                                                       0, 0);
2757
            if (sk_liner->bander[0] == NULL) {
2758
                emprintf(dev->memory, "Deskewer initialisation(2) failed");
2759
                code = gs_note_error(gs_error_VMerror);
2760
                goto cleanup;
2761
            }
2762
        }
2763
    }
2764
#endif
2765
2766
0
    code = check_trapping(dev->memory, params->trap_w, params->trap_h,
2767
4.34k
                          num_comps, params->trap_order);
2768
4.34k
    if (code < 0)
2769
0
        return code;
2770
2771
4.34k
    if (params->trap_w > 0 || params->trap_h > 0) {
2772
0
        liner_claptrap *ct_liner;
2773
2774
0
        code = alloc_liner(dev->memory,
2775
0
                           liner_claptrap,
2776
0
                           claptrap_line,
2777
0
                           claptrap_drop,
2778
0
                           &ct_liner);
2779
0
        if (code < 0)
2780
0
            goto cleanup;
2781
0
        ct_liner->chain  = ds->liner;
2782
0
        ct_liner->y      = 0;
2783
0
        ct_liner->height = dev->height;
2784
0
        ds->liner = &ct_liner->base;
2785
0
        ct_liner->claptrap = ClapTrap_Init(dev->memory,
2786
0
                                           width,
2787
0
                                           dev->height,
2788
0
                                           num_comps,
2789
0
                                           params->trap_order,
2790
0
                                           params->trap_w,
2791
0
                                           params->trap_h,
2792
0
                                           get_line_for_trap,
2793
0
                                           ct_liner);
2794
0
        if (ct_liner->claptrap == NULL) {
2795
0
            emprintf(dev->memory, "Trapping initialisation failed");
2796
0
            code = gs_note_error(gs_error_VMerror);
2797
0
            goto cleanup;
2798
0
        }
2799
0
    }
2800
2801
    /* Choose an appropriate core. Try to honour our early_cm
2802
     * choice, and fallback to late cm if we can't. */
2803
4.34k
    core = NULL;
2804
4.34k
    while (1)
2805
4.34k
    {
2806
4.34k
        nc = ds->early_cm ? post_cm_num_comps : num_comps;
2807
2808
4.34k
        if (factor > 8) {
2809
0
            code = gs_note_error(gs_error_rangecheck);
2810
0
            goto cleanup;
2811
0
        }
2812
4.34k
        else if ((src_bpc == 16) && (dst_bpc == 16) && (nc == 1))
2813
0
        {
2814
0
            core = &down_core16;
2815
0
        }
2816
4.34k
        else if ((src_bpc == 8) && (dst_bpc == 1) && (nc == 4))
2817
0
        {
2818
0
            if (mfs > 1)
2819
0
                core = &down_core4_mfs;
2820
0
            else if (ht == &bogus_ets_halftone)
2821
0
            {
2822
0
                code = init_ets(ds, 4, select_8_to_8_core(nc, factor));
2823
0
                if (code)
2824
0
                    goto cleanup;
2825
0
                core = &down_core4_ets;
2826
0
            }
2827
0
            else if (ht != NULL)
2828
0
            {
2829
0
                code = init_ht(ds, 4, select_8_to_8_core(nc, factor));
2830
0
                if (code)
2831
0
                    goto cleanup;
2832
0
                core = &down_core4_ht;
2833
0
            }
2834
0
            else
2835
0
                core = &down_core4;
2836
0
        }
2837
4.34k
        else if ((src_bpc == 8) && (dst_bpc == 1) && (nc == 1))
2838
0
        {
2839
0
            if (mfs > 1)
2840
0
                core = &down_core_mfs;
2841
0
            else if (ht == &bogus_ets_halftone)
2842
0
            {
2843
0
                code = init_ets(ds, 1, select_8_to_8_core(nc, factor));
2844
0
                if (code)
2845
0
                    goto cleanup;
2846
0
                core = &down_core_ets_1;
2847
0
            }
2848
0
            else if (factor == 4)
2849
0
                core = &down_core_4;
2850
0
            else if (factor == 3)
2851
0
                core = &down_core_3;
2852
0
            else if (factor == 2)
2853
0
                core = &down_core_2;
2854
0
            else if (factor == 1)
2855
0
                core = &down_core_1;
2856
0
            else
2857
0
                core = &down_core;
2858
0
        }
2859
4.34k
        else if ((factor == 1) && (src_bpc == dst_bpc))
2860
4.34k
            break;
2861
0
        else if (src_bpc == 8 && dst_bpc == 8)
2862
0
            core = select_8_to_8_core(nc, factor);
2863
2864
        /* If we found one, or we have nothing to fallback to, exit */
2865
0
        if (core || !ds->early_cm)
2866
0
            break;
2867
2868
        /* Fallback */
2869
0
        ds->early_cm = false;
2870
0
    }
2871
4.34k
    if (factor == 1 && src_bpc == dst_bpc) {
2872
        /* core can permissibly be NULL */
2873
4.34k
    } else if (core == NULL) {
2874
0
        code = gs_note_error(gs_error_rangecheck);
2875
0
        goto cleanup;
2876
0
    }
2877
4.34k
    ds->down_core = core;
2878
2879
4.34k
    if (apply_cm) {
2880
0
        ds->post_cm[0] = gs_alloc_bytes(dev->memory,
2881
0
                                        (size_t)post_size * downfactor,
2882
0
                                        "gx_downscaler(data)");
2883
0
        if (ds->post_cm[0] == NULL) {
2884
0
            code = gs_note_error(gs_error_VMerror);
2885
0
            goto cleanup;
2886
0
        }
2887
0
    }
2888
2889
4.34k
    if (core != NULL || apply_cm) {
2890
0
        ds->pre_cm[0] = gs_alloc_bytes(dev->memory,
2891
0
                                       (size_t)span * downfactor,
2892
0
                                       "gx_downscaler(data)");
2893
0
        if (ds->pre_cm[0] == NULL) {
2894
0
            code = gs_note_error(gs_error_VMerror);
2895
0
            goto cleanup;
2896
0
        }
2897
0
    }
2898
4.34k
    if (core != NULL) {
2899
0
        if (mfs > 1) {
2900
0
            ds->mfs_data = (byte *)gs_alloc_bytes(dev->memory,
2901
0
                                                  (size_t)(awidth+1)*nc,
2902
0
                                                  "gx_downscaler(mfs)");
2903
0
            if (ds->mfs_data == NULL) {
2904
0
                code = gs_note_error(gs_error_VMerror);
2905
0
                goto cleanup;
2906
0
            }
2907
0
            memset(ds->mfs_data, 0, (size_t)nc*(awidth+1));
2908
0
        }
2909
0
        if (dst_bpc == 1) {
2910
0
            ds->errors = (int *)gs_alloc_bytes(dev->memory,
2911
0
                                               (size_t)nc*(awidth+3)*sizeof(int),
2912
0
                                               "gx_downscaler(errors)");
2913
0
            if (ds->errors == NULL) {
2914
0
                code = gs_note_error(gs_error_VMerror);
2915
0
                goto cleanup;
2916
0
            }
2917
0
            memset(ds->errors, 0, (size_t)nc * (awidth+3) * sizeof(int));
2918
0
        }
2919
0
    }
2920
2921
4.34k
    return 0;
2922
2923
0
  cleanup:
2924
0
    gx_downscaler_fin(ds);
2925
0
    return code;
2926
4.34k
}
2927
2928
void gx_downscaler_fin(gx_downscaler_t *ds)
2929
11.6k
{
2930
11.6k
    if (ds->dev == NULL)
2931
0
        return;
2932
2933
11.6k
    gs_free_object(ds->dev->memory, ds->pre_cm[0],
2934
11.6k
                   "gx_downscaler(planar_data)");
2935
11.6k
    gs_free_object(ds->dev->memory, ds->post_cm[0],
2936
11.6k
                   "gx_downscaler(planar_data)");
2937
11.6k
    ds->pre_cm[0] = NULL;
2938
11.6k
    ds->post_cm[0] = NULL;
2939
11.6k
    ds->num_planes = 0;
2940
2941
11.6k
    gs_free_object(ds->dev->memory, ds->mfs_data, "gx_downscaler(mfs)");
2942
11.6k
    ds->mfs_data = NULL;
2943
11.6k
    gs_free_object(ds->dev->memory, ds->errors, "gx_downscaler(errors)");
2944
11.6k
    ds->errors = NULL;
2945
11.6k
    gs_free_object(ds->dev->memory, ds->scaled_data, "gx_downscaler(scaled_data)");
2946
11.6k
    ds->scaled_data = NULL;
2947
11.6k
    gs_free_object(ds->dev->memory, ds->htrow_alloc, "gx_downscaler(htrow)");
2948
11.6k
    ds->htrow = NULL;
2949
11.6k
    ds->htrow_alloc = NULL;
2950
2951
11.6k
    if (ds->liner)
2952
11.6k
        ds->liner->drop(ds->liner, ds->dev->memory);
2953
11.6k
    ds->liner = NULL;
2954
2955
11.6k
    if (ds->ets_config)
2956
0
        ets_destroy(ds->dev->memory, ds->ets_config);
2957
11.6k
    ds->ets_config = NULL;
2958
11.6k
}
2959
2960
/* Chunky case */
2961
int gx_downscaler_getbits(gx_downscaler_t *ds,
2962
                          byte            *out_data,
2963
                          int              row)
2964
8.28M
{
2965
8.28M
    int   code = 0;
2966
8.28M
    int   y, y_end;
2967
8.28M
    byte *data_ptr;
2968
8.28M
    int   upfactor, downfactor;
2969
2970
8.28M
    gx_downscaler_decode_factor(ds->factor, &upfactor, &downfactor);
2971
2972
    /* Check for the simple case */
2973
8.28M
    if (ds->down_core == NULL) {
2974
8.28M
        code = ds->liner->get_line(ds->liner,
2975
8.28M
                                   ds->apply_cm ? ds->pre_cm[0] : out_data,
2976
8.28M
                                   row);
2977
8.28M
        if (code < 0)
2978
0
            return code;
2979
8.28M
        if (ds->apply_cm) {
2980
0
            data_ptr = out_data;
2981
0
            return ds->apply_cm(ds->apply_cm_arg, &data_ptr, ds->pre_cm, ds->width, 1, 0);
2982
0
        }
2983
8.28M
        return 0;
2984
8.28M
    }
2985
2986
    /* Get factor rows worth of data */
2987
0
    y        = row * downfactor;
2988
0
    y_end    = y + downfactor;
2989
0
    data_ptr = ds->pre_cm[0];
2990
0
    do {
2991
0
        code = ds->liner->get_line(ds->liner, data_ptr, y);
2992
0
        if (code < 0)
2993
0
            return code;
2994
0
        data_ptr += ds->span;
2995
0
        y++;
2996
0
    } while (y < y_end);
2997
2998
0
    if (ds->apply_cm) {
2999
0
        if (ds->early_cm) {
3000
0
            code = ds->apply_cm(ds->apply_cm_arg, ds->post_cm, ds->pre_cm, ds->dev->width, 1, 0);
3001
0
            if (code < 0)
3002
0
                return code;
3003
0
            (ds->down_core)(ds, out_data, ds->post_cm[0], row, 0, ds->span);
3004
0
        } else {
3005
0
            data_ptr = out_data;
3006
0
            (ds->down_core)(ds, ds->post_cm[0], ds->pre_cm[0], row, 0, ds->span);
3007
0
            code = ds->apply_cm(ds->apply_cm_arg, &out_data, ds->post_cm, ds->width, 1, 0);
3008
0
            if (code < 0)
3009
0
                return code;
3010
0
        }
3011
0
    } else
3012
0
        (ds->down_core)(ds, out_data, ds->pre_cm[0], row, 0, ds->span);
3013
3014
0
    return code;
3015
0
}
3016
3017
/* Planar case */
3018
int gx_downscaler_get_bits_rectangle(gx_downscaler_t      *ds,
3019
                                     gs_get_bits_params_t *params,
3020
                                     int                   row)
3021
9.51k
{
3022
9.51k
    int                   code = 0;
3023
9.51k
    gs_int_rect           rect;
3024
9.51k
    int                   plane;
3025
9.51k
    int                   factor = ds->factor;
3026
9.51k
    gs_get_bits_params_t  params2;
3027
9.51k
    int                   upfactor, downfactor;
3028
9.51k
    int                   subrow;
3029
9.51k
    int                   copy = (ds->dev->width * ds->src_bpc + 7)>>3;
3030
9.51k
    int                   i, j, n;
3031
9.51k
    int                   num_planes_to_downscale;
3032
3033
9.51k
    n = ds->dev->width;
3034
9.51k
    if (ds->dev->color_info.depth > ds->dev->color_info.num_components*8+8)
3035
0
       n *= 2;
3036
3037
9.51k
    n = (n*ds->src_bpc+7)/8;
3038
3039
9.51k
    gx_downscaler_decode_factor(factor, &upfactor, &downfactor);
3040
3041
9.51k
    subrow = row % upfactor;
3042
9.51k
    if (subrow) {
3043
        /* Just copy a previous row from our stored buffer */
3044
0
        for (plane=0; plane < ds->num_planes; plane++)
3045
0
            params->data[plane] = ds->scaled_data + (upfactor * plane + subrow) * ds->scaled_span;
3046
0
        return 0;
3047
0
    }
3048
3049
9.51k
    rect.p.x = 0;
3050
9.51k
    rect.p.y = (row/upfactor) * downfactor;
3051
9.51k
    rect.q.x = ds->dev->width;
3052
9.51k
    rect.q.y = ((row/upfactor) + 1) * downfactor;
3053
3054
    /* Check for the simple case */
3055
9.51k
    if (ds->down_core == NULL) {
3056
9.51k
        gs_get_bits_params_t saved;
3057
9.51k
        if (ds->apply_cm) {
3058
            /* Always do the request giving our own workspace,
3059
             * and be prepared to accept a pointer */
3060
0
            saved = *params;
3061
0
            for (i = 0; i < ds->num_planes; i++)
3062
0
                params->data[i] = ds->pre_cm[i];
3063
0
            params->options |= GB_RETURN_POINTER;
3064
0
        }
3065
9.51k
        code = ds->liner->get_line(ds->liner, params, row);
3066
9.51k
        if (code < 0)
3067
0
            return code;
3068
9.51k
        if (ds->apply_cm) {
3069
0
            byte **buffer;
3070
0
            if (saved.options & GB_RETURN_COPY) {
3071
                /* They will accept a copy. Let's use the buffer they supplied */
3072
0
                params->options &= ~GB_RETURN_POINTER;
3073
0
                buffer = saved.data;
3074
0
            } else
3075
0
                buffer = ds->post_cm;
3076
0
            code = ds->apply_cm(ds->apply_cm_arg, buffer, params->data, ds->dev->width, rect.q.y - rect.p.y, params->raster);
3077
0
            for (i = 0; i < ds->post_cm_num_comps; i++)
3078
0
                params->data[i] = buffer[i];
3079
0
        }
3080
9.51k
        return code;
3081
9.51k
    }
3082
3083
    /* Copy the params, because get_bits_rectangle can helpfully overwrite
3084
     * them. */
3085
0
    memcpy(&params2, &ds->params, sizeof(params2));
3086
0
    for (i = 0; i < ds->num_planes; i++)
3087
0
         params2.data[i] = ds->pre_cm[i];
3088
3089
    /* Get downfactor rows worth of data - we always work a line at a
3090
     * time now. */
3091
0
    for (i = 0; i < downfactor; i++) {
3092
0
        rect.q.y = rect.p.y+1;
3093
0
        if (rect.q.y > ds->dev->height)
3094
0
            break;
3095
0
        memcpy(&params2, &ds->params, sizeof(params2));
3096
0
        for (j = 0; j < ds->num_planes; j++)
3097
0
            params2.data[j] = ds->pre_cm[j] + i * ds->span;
3098
0
        code = ds->liner->get_line(ds->liner, &params2, rect.p.y);
3099
0
        if (code < 0)
3100
0
            break;
3101
0
        for (j = 0; j < ds->num_planes; j++) {
3102
0
            byte *tgt = ds->pre_cm[j] + i * ds->span;
3103
0
            if (params2.data[j] != tgt)
3104
0
                memcpy(tgt, params2.data[j], n);
3105
0
        }
3106
0
        rect.p.y++;
3107
0
    }
3108
0
    if (i == 0)
3109
0
        return code;
3110
0
    if (code < 0)
3111
0
        return code;
3112
    /* If we still haven't got enough, we've hit the end of the page; just
3113
     * duplicate the last line we did get. */
3114
0
    for (; i < downfactor; i++)
3115
0
        for (j = 0; j < ds->num_planes; j++)
3116
0
            memcpy(ds->pre_cm[j] + i*ds->span, ds->pre_cm[j] + (i-1)*ds->span, copy);
3117
3118
    /* All the data is now in ds->pre_cm. Update params2.data so that this points to
3119
     * it. From here on in, we will keep params2.data pointing to whereever the
3120
     * latest processed version of the data is. */
3121
0
    for (j = 0; j < ds->num_planes; j++)
3122
0
        params2.data[j] = ds->pre_cm[j];
3123
3124
0
    num_planes_to_downscale = ds->num_planes;
3125
0
    if (ds->early_cm && ds->apply_cm) {
3126
0
        code = ds->apply_cm(ds->apply_cm_arg, ds->post_cm, params2.data, ds->dev->width, downfactor, ds->span);
3127
0
        if (code < 0)
3128
0
            return code;
3129
0
        for (j = 0; j < ds->post_cm_num_comps; j++)
3130
0
            params2.data[j] = ds->post_cm[j];
3131
0
        num_planes_to_downscale = ds->post_cm_num_comps;
3132
0
    }
3133
3134
0
    if (upfactor > 1) {
3135
        /* Downscale the block of lines into our output buffer */
3136
0
        for (plane=0; plane < num_planes_to_downscale; plane++) {
3137
0
            byte *scaled = ds->scaled_data + upfactor * plane * ds->scaled_span;
3138
0
            (ds->down_core)(ds, scaled, params2.data[plane], row, plane, params2.raster);
3139
0
            params2.data[plane] = scaled;
3140
0
        }
3141
0
    } else if (ds->down_core != NULL) {
3142
        /* Downscale direct into output buffer */
3143
0
        for (plane=0; plane < num_planes_to_downscale; plane++) {
3144
0
            (ds->down_core)(ds, params->data[plane], params2.data[plane], row, plane, params2.raster);
3145
0
            params2.data[plane] = params->data[plane];
3146
0
        }
3147
0
    } else {
3148
        /* Copy into output buffer */
3149
        /* No color management can be required here */
3150
0
        assert(!ds->early_cm || ds->apply_cm == NULL);
3151
0
        for (plane=0; plane < num_planes_to_downscale; plane++) {
3152
0
            memcpy(params->data[plane], params2.data[plane], params2.raster);
3153
0
            params2.data[plane] = params->data[plane];
3154
0
        }
3155
0
    }
3156
3157
0
    if (!ds->early_cm && ds->apply_cm) {
3158
0
        code = ds->apply_cm(ds->apply_cm_arg, params->data, params2.data, ds->width, 1, params->raster);
3159
0
        if (code < 0)
3160
0
            return code;
3161
0
        for (plane=0; plane < num_planes_to_downscale; plane++)
3162
0
            params2.data[plane] = params->data[plane];
3163
0
    }
3164
3165
0
    for (plane=0; plane < num_planes_to_downscale; plane++)
3166
0
        params->data[plane] = params2.data[plane];
3167
3168
0
    return code;
3169
0
}
3170
3171
typedef struct downscaler_process_page_arg_s
3172
{
3173
    gx_process_page_options_t *orig_options;
3174
    int upfactor;
3175
    int downfactor;
3176
    gx_downscaler_t ds;
3177
}
3178
downscaler_process_page_arg_t;
3179
3180
typedef struct downscaler_process_page_buffer_s
3181
{
3182
    gx_device *bdev;
3183
    void *orig_buffer;
3184
}
3185
downscaler_process_page_buffer_t;
3186
3187
static int downscaler_init_fn(void *arg_, gx_device *dev, gs_memory_t *memory, int w, int h, void **pbuffer)
3188
0
{
3189
0
    downscaler_process_page_arg_t *arg = (downscaler_process_page_arg_t *)arg_;
3190
0
    downscaler_process_page_buffer_t *buffer;
3191
0
    int code = 0;
3192
3193
0
    buffer = (downscaler_process_page_buffer_t *)gs_alloc_bytes(memory, sizeof(*buffer), "downscaler process_page buffer");
3194
0
    if (buffer == NULL)
3195
0
        return_error(gs_error_VMerror);
3196
0
    memset(buffer, 0, sizeof(*buffer));
3197
3198
0
    if (arg->upfactor > arg->downfactor) {
3199
0
        code = gx_default_create_buf_device(&buffer->bdev, dev,
3200
0
                          (h*arg->upfactor + arg->downfactor-1)/arg->downfactor,
3201
0
                          NULL, memory, NULL);
3202
0
        if (code < 0) {
3203
0
            gs_free_object(memory, buffer, "downscaler process_page buffer");
3204
0
            return code;
3205
0
        }
3206
0
    }
3207
3208
0
    if (arg->orig_options && arg->orig_options->init_buffer_fn) {
3209
0
        code = arg->orig_options->init_buffer_fn(arg->orig_options->arg, dev, memory,
3210
0
                                                 (w * arg->upfactor + arg->downfactor-1)/arg->downfactor,
3211
0
                                                 (h * arg->upfactor + arg->downfactor-1)/arg->downfactor,
3212
0
                                                 &buffer->orig_buffer);
3213
0
        if (code < 0) {
3214
0
            if (buffer->bdev)
3215
0
                dev_proc(dev, close_device)(dev);
3216
0
            gs_free_object(memory, buffer, "downscaler process_page buffer");
3217
0
            return code;
3218
0
        }
3219
0
    }
3220
3221
0
    *pbuffer = (void *)buffer;
3222
0
    return code;
3223
0
}
3224
3225
static int downscaler_process_fn(void *arg_, gx_device *dev, gx_device *bdev, const gs_int_rect *rect, void *buffer_)
3226
0
{
3227
0
    downscaler_process_page_arg_t *arg = (downscaler_process_page_arg_t *)arg_;
3228
0
    downscaler_process_page_buffer_t *buffer = (downscaler_process_page_buffer_t *)buffer_;
3229
0
    int code, raster_in, raster_out;
3230
0
    gs_get_bits_params_t params;
3231
0
    gs_int_rect in_rect, out_rect;
3232
0
    byte *in_ptr, *out_ptr;
3233
3234
0
    in_rect.p.x = 0;
3235
0
    in_rect.p.y = 0;
3236
0
    in_rect.q.x = rect->q.x - rect->p.x;
3237
0
    in_rect.q.y = rect->q.y - rect->p.y;
3238
0
    out_rect.p.x = 0;
3239
0
    out_rect.p.y = 0;
3240
0
    out_rect.q.x = (in_rect.q.x * arg->upfactor + arg->downfactor-1) / arg->downfactor;
3241
0
    out_rect.q.y = (in_rect.q.y * arg->upfactor + arg->downfactor-1) / arg->downfactor;
3242
3243
    /* Where do we get the data from? */
3244
0
    params.options = GB_COLORS_NATIVE | GB_ALPHA_NONE | GB_PACKING_CHUNKY | GB_RETURN_POINTER | GB_ALIGN_ANY | GB_OFFSET_0 | GB_RASTER_ANY;
3245
0
    code = dev_proc(bdev, get_bits_rectangle)(bdev, &in_rect, &params);
3246
0
    if (code < 0)
3247
0
        return code;
3248
0
    raster_in = params.raster;
3249
0
    in_ptr = params.data[0];
3250
3251
    /* Where do we write it to? */
3252
0
    if (buffer->bdev) {
3253
0
        code = dev_proc(bdev, get_bits_rectangle)(buffer->bdev, &out_rect, &params);
3254
0
        if (code < 0)
3255
0
            return code;
3256
0
        raster_out = params.raster;
3257
0
        out_ptr = params.data[0];
3258
0
    } else {
3259
0
        raster_out = raster_in;
3260
0
        out_ptr = params.data[0];
3261
0
    }
3262
3263
    /* Do the downscale */
3264
0
    if (arg->ds.down_core) {
3265
0
        int y;
3266
0
        for (y = rect->p.y; y < rect->q.y; y += arg->downfactor)
3267
0
        {
3268
0
            arg->ds.down_core(&arg->ds, out_ptr, in_ptr, y, 0, arg->ds.span);
3269
0
            in_ptr += arg->ds.span * arg->downfactor;
3270
0
            out_ptr += raster_out * arg->upfactor;
3271
0
        }
3272
0
    }
3273
3274
    /* Pass on to further processing */
3275
0
    if (arg->orig_options && arg->orig_options->process_fn) {
3276
0
        out_rect.p.y = rect->p.y*arg->upfactor/arg->downfactor;
3277
0
        out_rect.q.y += out_rect.p.y;
3278
0
        code = arg->orig_options->process_fn(arg->orig_options->arg, dev,
3279
0
                                             (buffer->bdev ? buffer->bdev : bdev),
3280
0
                                             &out_rect, buffer->orig_buffer);
3281
0
    }
3282
0
    return code;
3283
0
}
3284
3285
static void
3286
downscaler_free_fn(void *arg_, gx_device *dev, gs_memory_t *memory, void *buffer_)
3287
0
{
3288
0
    downscaler_process_page_arg_t *arg = (downscaler_process_page_arg_t *)arg_;
3289
0
    downscaler_process_page_buffer_t *buffer = (downscaler_process_page_buffer_t *)buffer_;
3290
3291
0
    if (arg->orig_options && arg->orig_options->free_buffer_fn)
3292
0
        arg->orig_options->free_buffer_fn(arg->orig_options->arg, dev, memory,
3293
0
                                          buffer->orig_buffer);
3294
0
    if (buffer->bdev)
3295
0
        dev_proc(dev, close_device)(dev);
3296
0
    gs_free_object(memory, buffer, "downscaler process_page buffer");
3297
0
}
3298
3299
static int
3300
downscaler_output_fn(void *arg_, gx_device *dev, void *buffer_)
3301
0
{
3302
0
    downscaler_process_page_arg_t *arg = (downscaler_process_page_arg_t *)arg_;
3303
0
    downscaler_process_page_buffer_t *buffer = (downscaler_process_page_buffer_t *)buffer_;
3304
3305
0
    return arg->orig_options->output_fn(arg->orig_options->arg, dev,
3306
0
                                        buffer->orig_buffer);
3307
0
}
3308
3309
/* No error diffusion with process_page as bands need to be handled
3310
 * separately. */
3311
int gx_downscaler_process_page(gx_device                 *dev,
3312
                               gx_process_page_options_t *options,
3313
                               int                        factor)
3314
0
{
3315
0
    downscaler_process_page_arg_t arg = { 0 };
3316
0
    gx_process_page_options_t my_options = { 0 };
3317
0
    int num_comps = dev->color_info.num_components;
3318
0
    int src_bpc = dev->color_info.comp_bits[0];
3319
0
    int scaled_w;
3320
0
    gx_downscale_core *core;
3321
3322
0
    arg.orig_options = options;
3323
0
    gx_downscaler_decode_factor(factor, &arg.upfactor, &arg.downfactor);
3324
0
    arg.ds.dev = dev;
3325
0
    arg.ds.width = (dev->width * arg.upfactor + arg.downfactor-1)/arg.downfactor;
3326
0
    arg.ds.awidth = arg.ds.width;
3327
0
    arg.ds.span = bitmap_raster(dev->width * num_comps * src_bpc);
3328
0
    scaled_w = (dev->width * arg.upfactor + arg.downfactor-1)/arg.downfactor;
3329
0
    arg.ds.factor = factor;
3330
0
    arg.ds.src_bpc = src_bpc;
3331
0
    arg.ds.scaled_span = bitmap_raster(scaled_w * num_comps * src_bpc);
3332
0
    arg.ds.num_planes = 0;
3333
3334
    /* Choose an appropriate core */
3335
0
    if (factor > 8)
3336
0
    {
3337
0
        return gs_note_error(gs_error_rangecheck);
3338
0
    }
3339
0
    else if ((src_bpc == 16) && (num_comps == 1))
3340
0
    {
3341
0
        core = &down_core16;
3342
0
    }
3343
0
    else if (factor == 1)
3344
0
        core = NULL;
3345
0
    else if ((src_bpc == 8) && (num_comps == 1))
3346
0
    {
3347
0
        if (factor == 4)
3348
0
            core = &down_core8_4;
3349
0
        else if (factor == 3)
3350
0
            core = &down_core8_3;
3351
0
        else if (factor == 2)
3352
0
            core = &down_core8_2;
3353
0
        else
3354
0
            core = &down_core8;
3355
0
    }
3356
0
    else if ((src_bpc == 8) && (num_comps == 3))
3357
0
        core = &down_core24;
3358
0
    else if ((src_bpc == 8) && (num_comps == 4))
3359
0
         core = &down_core32;
3360
0
    else {
3361
0
        return gs_note_error(gs_error_rangecheck);
3362
0
    }
3363
0
    arg.ds.down_core = core;
3364
3365
0
    my_options.init_buffer_fn = downscaler_init_fn;
3366
0
    my_options.process_fn = downscaler_process_fn;
3367
0
    my_options.output_fn = options->output_fn ? downscaler_output_fn : NULL;
3368
0
    my_options.free_buffer_fn = downscaler_free_fn;
3369
0
    my_options.arg = &arg;
3370
3371
0
    return dev_proc(dev, process_page)(dev, &my_options);
3372
0
}
3373
3374
int gx_downscaler_read_params(gs_param_list        *plist,
3375
                              gx_downscaler_params *params,
3376
                              int                   features)
3377
190k
{
3378
190k
    int code;
3379
190k
    int downscale, mfs, ets;
3380
190k
    bool deskew;
3381
190k
    int trap_w, trap_h;
3382
190k
    const char *param_name;
3383
190k
    gs_param_int_array trap_order;
3384
3385
190k
    trap_order.data = NULL;
3386
3387
190k
    switch (code = param_read_int(plist,
3388
190k
                                   (param_name = "DownScaleFactor"),
3389
190k
                                   &downscale)) {
3390
177k
        case 1:
3391
177k
            break;
3392
12.5k
        case 0:
3393
12.5k
            if (downscale >= 1) {
3394
12.5k
                params->downscale_factor = downscale;
3395
12.5k
                break;
3396
12.5k
            }
3397
0
            code = gs_error_rangecheck;
3398
0
        default:
3399
0
            param_signal_error(plist, param_name, code);
3400
0
            return code;
3401
190k
    }
3402
3403
190k
    switch (code = param_read_bool(plist,
3404
190k
                                   (param_name = "Deskew"),
3405
190k
                                   &deskew)) {
3406
177k
        case 1:
3407
177k
            break;
3408
12.5k
        case 0:
3409
12.5k
            if (deskew >= 0) {
3410
12.5k
                params->do_skew_detection = deskew;
3411
12.5k
                break;
3412
12.5k
            }
3413
0
            code = gs_error_rangecheck;
3414
0
        default:
3415
0
            param_signal_error(plist, param_name, code);
3416
0
            return code;
3417
190k
    }
3418
3419
190k
    if (features & GX_DOWNSCALER_PARAMS_MFS)
3420
40.9k
    {
3421
40.9k
        switch (code = param_read_int(plist, (param_name = "MinFeatureSize"), &mfs)) {
3422
37.1k
            case 1:
3423
37.1k
                break;
3424
3.86k
            case 0:
3425
3.86k
                if ((mfs >= 0) && (mfs <= 4)) {
3426
3.86k
                    params->min_feature_size = mfs;
3427
3.86k
                    break;
3428
3.86k
                }
3429
0
                code = gs_error_rangecheck;
3430
0
            default:
3431
0
                param_signal_error(plist, param_name, code);
3432
0
                return code;
3433
40.9k
        }
3434
40.9k
    }
3435
3436
190k
    if (features & GX_DOWNSCALER_PARAMS_TRAP)
3437
137k
    {
3438
137k
        switch (code = param_read_int(plist,
3439
137k
                                      (param_name = "TrapX"),
3440
137k
                                      &trap_w)) {
3441
128k
            case 1:
3442
128k
                break;
3443
8.68k
            case 0:
3444
8.68k
                if (trap_w >= 0)
3445
8.68k
                {
3446
8.68k
                    params->trap_w = trap_w;
3447
8.68k
                    break;
3448
8.68k
                }
3449
0
                code = gs_error_rangecheck;
3450
0
            default:
3451
0
                param_signal_error(plist, param_name, code);
3452
0
                return code;
3453
137k
        }
3454
137k
        switch (code = param_read_int(plist,
3455
137k
                                      (param_name = "TrapY"),
3456
137k
                                      &trap_h)) {
3457
128k
            case 1:
3458
128k
                break;
3459
8.68k
            case 0:
3460
8.68k
                if (trap_h >= 0)
3461
8.68k
                {
3462
8.68k
                    params->trap_h = trap_h;
3463
8.68k
                    break;
3464
8.68k
                }
3465
0
                code = gs_error_rangecheck;
3466
0
            default:
3467
0
                param_signal_error(plist, param_name, code);
3468
0
                return code;
3469
137k
        }
3470
137k
        switch (code = param_read_int_array(plist, (param_name = "TrapOrder"), &trap_order)) {
3471
8.68k
            case 0:
3472
8.68k
                break;
3473
128k
            case 1:
3474
128k
                trap_order.data = 0;          /* mark as not filled */
3475
128k
                break;
3476
0
            default:
3477
0
                param_signal_error(plist, param_name, code);
3478
0
                return code;
3479
137k
        }
3480
3481
137k
        if (trap_order.data != NULL)
3482
8.68k
        {
3483
8.68k
            int i;
3484
8.68k
            int n = trap_order.size;
3485
3486
8.68k
            if (n > GS_CLIENT_COLOR_MAX_COMPONENTS)
3487
0
                n = GS_CLIENT_COLOR_MAX_COMPONENTS;
3488
3489
564k
            for (i = 0; i < n; i++)
3490
555k
            {
3491
555k
                params->trap_order[i] = trap_order.data[i];
3492
555k
            }
3493
8.68k
            for (; i < GS_CLIENT_COLOR_MAX_COMPONENTS; i++)
3494
0
            {
3495
0
                params->trap_order[i] = i;
3496
0
            }
3497
8.68k
        }
3498
128k
        else
3499
128k
        {
3500
            /* Set some sane defaults */
3501
128k
            int i;
3502
3503
128k
            params->trap_order[0] = 3; /* K */
3504
128k
            params->trap_order[1] = 1; /* M */
3505
128k
            params->trap_order[2] = 0; /* C */
3506
128k
            params->trap_order[3] = 2; /* Y */
3507
3508
7.83M
            for (i = 4; i < GS_CLIENT_COLOR_MAX_COMPONENTS; i++)
3509
7.70M
            {
3510
7.70M
                params->trap_order[i] = i;
3511
7.70M
            }
3512
128k
        }
3513
137k
    }
3514
190k
    if (features & GX_DOWNSCALER_PARAMS_ETS)
3515
0
    {
3516
0
        switch (code = param_read_int(plist,
3517
0
                                      (param_name = "DownScaleETS"),
3518
0
                                      &ets)) {
3519
0
            case 1:
3520
0
                break;
3521
0
            case 0:
3522
0
                if (ets >= 0)
3523
0
                {
3524
0
                    params->ets = ets;
3525
0
                    break;
3526
0
                }
3527
0
                code = gs_error_rangecheck;
3528
0
            default:
3529
0
                param_signal_error(plist, param_name, code);
3530
0
                return code;
3531
0
        }
3532
0
    }
3533
3534
190k
    return 0;
3535
190k
}
3536
3537
int gx_downscaler_write_params(gs_param_list        *plist,
3538
                               gx_downscaler_params *params,
3539
                               int                   features)
3540
654k
{
3541
654k
    int code;
3542
654k
    int ecode = 0;
3543
654k
    gs_param_int_array trap_order;
3544
3545
654k
    trap_order.data = params->trap_order;
3546
654k
    trap_order.size = GS_CLIENT_COLOR_MAX_COMPONENTS;
3547
654k
    trap_order.persistent = false;
3548
3549
654k
    if ((code = param_write_int(plist, "DownScaleFactor", &params->downscale_factor)) < 0)
3550
0
        ecode = code;
3551
654k
    if ((code = param_write_bool(plist, "Deskew", &params->do_skew_detection)) < 0)
3552
0
        ecode = code;
3553
654k
    if (features & GX_DOWNSCALER_PARAMS_MFS)
3554
132k
    {
3555
132k
        if ((code = param_write_int(plist, "MinFeatureSize", &params->min_feature_size)) < 0)
3556
0
            ecode = code;
3557
132k
    }
3558
654k
    if (features & GX_DOWNSCALER_PARAMS_TRAP)
3559
469k
    {
3560
469k
        if ((code = param_write_int(plist, "TrapX", &params->trap_w)) < 0)
3561
0
            ecode = code;
3562
469k
        if ((code = param_write_int(plist, "TrapY", &params->trap_h)) < 0)
3563
0
            ecode = code;
3564
469k
        if ((code = param_write_int_array(plist, "TrapOrder", &trap_order)) < 0)
3565
0
            ecode = code;
3566
469k
    }
3567
654k
    if (features & GX_DOWNSCALER_PARAMS_ETS)
3568
0
    {
3569
0
        if ((code = param_write_int(plist, "DownScaleETS", &params->ets)) < 0)
3570
0
            ecode = code;
3571
0
    }
3572
3573
654k
    return ecode;
3574
654k
}
3575
3576
/* ETS relies on some malloc wrappers */
3577
void *ets_malloc(void *malloc_arg, int size)
3578
0
{
3579
0
    return gs_alloc_bytes((gs_memory_t *)malloc_arg, size, "ets_malloc");
3580
0
}
3581
3582
void *ets_calloc(void *malloc_arg, int count, int size)
3583
0
{
3584
0
    void *p = ets_malloc(malloc_arg, (size_t)count * size);
3585
0
    if (p)
3586
0
        memset(p, 0, (size_t)count * size);
3587
0
    return p;
3588
0
}
3589
3590
void ets_free(void *malloc_arg, void *p)
3591
0
{
3592
0
    if (!p)
3593
0
        return;
3594
3595
0
    gs_free_object((gs_memory_t *)malloc_arg, p, "ets_malloc");
3596
0
}
3597
3598
int gx_downscaler_create_post_render_link(gx_device *dev, gsicc_link_t **link)
3599
0
{
3600
0
    cmm_dev_profile_t *profile_struct;
3601
0
    gsicc_rendering_param_t rendering_params;
3602
0
    int code = dev_proc(dev, get_profile)(dev, &profile_struct);
3603
0
    if (code < 0)
3604
0
        return_error(gs_error_undefined);
3605
3606
0
    *link = NULL;
3607
0
    if (profile_struct->postren_profile == NULL)
3608
0
        return 0;
3609
3610
0
    rendering_params.black_point_comp = gsBLACKPTCOMP_ON;
3611
0
    rendering_params.graphics_type_tag = GS_UNKNOWN_TAG;
3612
0
    rendering_params.override_icc = false;
3613
0
    rendering_params.preserve_black = gsBLACKPRESERVE_OFF;
3614
0
    rendering_params.rendering_intent = gsRELATIVECOLORIMETRIC;
3615
0
    rendering_params.cmm = gsCMM_DEFAULT;
3616
0
    *link = gsicc_alloc_link_dev(dev->memory,
3617
0
                                 profile_struct->device_profile[GS_DEFAULT_DEVICE_PROFILE],
3618
0
                                 profile_struct->postren_profile,
3619
0
                                 &rendering_params);
3620
0
    if (*link == NULL)
3621
0
        return_error(gs_error_VMerror);
3622
3623
    /* If it is identity, release it now and set link to NULL */
3624
0
    if ((*link)->is_identity) {
3625
0
        gsicc_free_link_dev(*link);
3626
0
        *link = NULL;
3627
0
    }
3628
0
    return 0;
3629
0
}
3630
3631
int gx_downscaler_create_icc_link(gx_device *dev, gsicc_link_t **link, cmm_profile_t *icc_profile)
3632
0
{
3633
0
    gsicc_rendering_param_t rendering_params;
3634
0
    cmm_dev_profile_t *profile_struct;
3635
0
    int code = dev_proc(dev, get_profile)(dev, &profile_struct);
3636
3637
0
    *link = NULL;
3638
3639
0
    if (code < 0)
3640
0
        return code;
3641
3642
0
    if (icc_profile == NULL)
3643
0
        return 0; /* Should be an error, maybe? */
3644
3645
0
    rendering_params.black_point_comp = gsBLACKPTCOMP_ON;
3646
0
    rendering_params.graphics_type_tag = GS_UNKNOWN_TAG;
3647
0
    rendering_params.override_icc = false;
3648
0
    rendering_params.preserve_black = gsBLACKPRESERVE_OFF;
3649
0
    rendering_params.rendering_intent = gsRELATIVECOLORIMETRIC;
3650
0
    rendering_params.cmm = gsCMM_DEFAULT;
3651
0
    *link = gsicc_alloc_link_dev(dev->memory,
3652
0
                                 profile_struct->device_profile[GS_DEFAULT_DEVICE_PROFILE],
3653
0
                                 icc_profile,
3654
0
                                 &rendering_params);
3655
0
    if (*link == NULL)
3656
0
        return_error(gs_error_VMerror);
3657
3658
    /* If it is identity, release it now and set link to NULL */
3659
0
    if ((*link)->is_identity) {
3660
0
        gsicc_free_link_dev(*link);
3661
0
        *link = NULL;
3662
0
    }
3663
0
    return 0;
3664
0
}