Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/base/gxdownscale.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2022 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
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
659k
{
1700
659k
    if (factor == 32)
1701
0
        *down = 3, *up = 2;
1702
659k
    else if (factor == 34)
1703
0
        *down = 3, *up = 4;
1704
659k
    else
1705
659k
        *down = factor, *up = 1;
1706
659k
}
1707
1708
int
1709
gx_downscaler_scale(int width, int factor)
1710
11.6k
{
1711
11.6k
    int up, down;
1712
1713
11.6k
    gx_downscaler_decode_factor(factor, &up, &down);
1714
11.6k
    return (width*up)/down;
1715
11.6k
}
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
4.32k
{
1798
4.32k
    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
4.32k
    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
4.32k
    return 0;
1832
4.32k
}
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
3.99k
{
1981
3.99k
    return gx_downscaler_init_planar_cm(ds, dev, src_bpc, dst_bpc,
1982
3.99k
                                        num_comps, params, gb_params,
1983
3.99k
                                        NULL, NULL, num_comps);
1984
3.99k
}
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
639k
{
1994
639k
    liner_getbits_chunky *liner = (liner_getbits_chunky *)liner_;
1995
639k
    gs_int_rect rect;
1996
639k
    gs_get_bits_params_t params;
1997
1998
639k
    rect.p.x = 0;
1999
639k
    rect.p.y = row;
2000
639k
    rect.q.x = liner->dev->width;
2001
639k
    rect.q.y = row+1;
2002
639k
    params.x_offset = 0;
2003
639k
    params.raster = bitmap_raster(liner->dev->width * liner->dev->color_info.depth);
2004
639k
    params.options = (GB_ALIGN_ANY |
2005
639k
                      GB_RETURN_COPY |
2006
639k
                      GB_OFFSET_0 |
2007
639k
                      GB_RASTER_STANDARD | GB_PACKING_CHUNKY |
2008
639k
                      GB_COLORS_NATIVE | GB_ALPHA_NONE);
2009
639k
    params.data[0] = buffer;
2010
639k
    return (*dev_proc(liner->dev, get_bits_rectangle))(liner->dev, &rect, &params);
2011
639k
}
2012
2013
static void
2014
getbits_chunky_drop(gx_downscale_liner *liner_, gs_memory_t *mem)
2015
326
{
2016
326
    liner_getbits_chunky *liner = (liner_getbits_chunky *)liner_;
2017
2018
326
    gs_free_object(mem, liner, "liner_getbits_chunky");
2019
326
}
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
3.99k
{
2031
3.99k
    liner_getbits_planar *liner = (liner_getbits_planar *)liner_;
2032
3.99k
    gs_get_bits_params_t *params = (gs_get_bits_params_t *)output;
2033
3.99k
    gs_get_bits_params_t  params2;
2034
3.99k
    gs_int_rect           rect;
2035
3.99k
    int i, code, n;
2036
2037
3.99k
    rect.p.x = 0;
2038
3.99k
    rect.p.y = row;
2039
3.99k
    rect.q.x = liner->dev->width;
2040
3.99k
    rect.q.y = row+1;
2041
2042
3.99k
    n = liner->dev->width;
2043
3.99k
    if (liner->dev->color_info.depth > liner->dev->color_info.num_components * 8 + 8)
2044
0
        n *= 2;
2045
2046
3.99k
    params2 = *params;
2047
2048
3.99k
    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
3.99k
    if (params->options & GB_RETURN_POINTER) {
2052
20.0k
        for (i = 0; i < liner->num_comps; i++)
2053
16.0k
            params->data[i] = params2.data[i];
2054
3.99k
    } 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
3.99k
    return code;
2063
3.99k
}
2064
2065
static void
2066
getbits_planar_drop(gx_downscale_liner *liner_, gs_memory_t *mem)
2067
3.99k
{
2068
3.99k
    liner_getbits_planar *liner = (liner_getbits_planar *)liner_;
2069
2070
3.99k
    gs_free_object(mem, liner, "liner_getbits_planar");
2071
3.99k
}
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
4.32k
    do_alloc_liner(mem, sizeof(type), #type, get, drop,\
2226
4.32k
                   (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
4.32k
{
2234
4.32k
    gx_downscale_liner *liner;
2235
2236
4.32k
    liner = (gx_downscale_liner *)gs_alloc_bytes(mem, size, type);
2237
4.32k
    *res = liner;
2238
4.32k
    if (liner == NULL)
2239
0
        return_error(gs_error_VMerror);
2240
4.32k
    liner->get_line = get_line;
2241
4.32k
    liner->drop = drop;
2242
4.32k
    return 0;
2243
4.32k
}
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
3.99k
{
2256
3.99k
    int                span = bitmap_raster(dev->width * src_bpc);
2257
3.99k
    int                post_span = bitmap_raster(dev->width * src_bpc);
2258
3.99k
    int                width;
2259
3.99k
    int                code;
2260
3.99k
    gx_downscale_core *core;
2261
3.99k
    int                i;
2262
3.99k
    int                upfactor, downfactor;
2263
3.99k
    int                factor = params->downscale_factor;
2264
3.99k
    int                mfs = params->min_feature_size;
2265
2266
3.99k
    gx_downscaler_decode_factor(factor, &upfactor, &downfactor);
2267
2268
    /* width = scaled width */
2269
3.99k
    width = (dev->width*upfactor)/downfactor;
2270
3.99k
    memset(ds, 0, sizeof(*ds));
2271
3.99k
    ds->dev               = dev;
2272
3.99k
    ds->width             = width;
2273
3.99k
    ds->awidth            = width;
2274
3.99k
    ds->span              = span;
2275
3.99k
    ds->factor            = factor;
2276
3.99k
    ds->num_planes        = num_comps;
2277
3.99k
    ds->src_bpc           = src_bpc;
2278
3.99k
    ds->dst_bpc           = dst_bpc;
2279
3.99k
    ds->scaled_data       = NULL;
2280
3.99k
    ds->scaled_span       = bitmap_raster((dst_bpc*dev->width*upfactor + downfactor-1)/downfactor);
2281
3.99k
    ds->apply_cm          = apply_cm;
2282
3.99k
    ds->apply_cm_arg      = apply_cm_arg;
2283
3.99k
    ds->early_cm          = dst_bpc < src_bpc || (dst_bpc == src_bpc && post_cm_num_comps < num_comps);
2284
3.99k
    ds->post_cm_num_comps = post_cm_num_comps;
2285
3.99k
    ds->do_skew_detection = params->do_skew_detection;
2286
2287
3.99k
    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
3.99k
    {
2303
3.99k
        liner_getbits_planar *gb_liner;
2304
2305
3.99k
        code = alloc_liner(dev->memory,
2306
3.99k
                           liner_getbits_planar,
2307
3.99k
                           getbits_planar_line,
2308
3.99k
                           getbits_planar_drop,
2309
3.99k
                           &gb_liner);
2310
3.99k
        if (code < 0)
2311
0
            goto cleanup;
2312
3.99k
        gb_liner->dev = dev;
2313
3.99k
        gb_liner->num_comps = num_comps;
2314
3.99k
        ds->liner = &gb_liner->base;
2315
3.99k
    }
2316
2317
0
    memcpy(&ds->params, gb_params, sizeof(*gb_params));
2318
3.99k
    ds->params.raster = span;
2319
3.99k
    ds->pre_cm[0] = gs_alloc_bytes(dev->memory,
2320
3.99k
                                   (size_t)span * downfactor * num_comps,
2321
3.99k
                                   "gx_downscaler(planar_data)");
2322
16.0k
    for (i = 1; i < num_comps; i++) {
2323
12.0k
        ds->pre_cm[i] = ds->pre_cm[i-1] + (size_t)span * downfactor;
2324
12.0k
    }
2325
2326
#ifdef WITH_CAL
2327
    if (ds->do_skew_detection) {
2328
        /* Do a skew detection pass */
2329
        int j;
2330
        int w = ds->dev->width;
2331
        int h = ds->dev->height;
2332
        cal_skew *skew;
2333
2334
        for (i = 0; i < num_comps; i++) {
2335
            ds->params.data[i] = ds->pre_cm[i];
2336
        }
2337
2338
        skew = cal_skew_init(ds->dev->memory->gs_lib_ctx->core->cal_ctx,
2339
                             ds->dev->memory,
2340
                             w, h);
2341
        if (skew == NULL)
2342
            code = gs_error_VMerror;
2343
        for (j = 0; code >= 0 && j < h; j++) {
2344
            gs_get_bits_params_t params2 = ds->params;
2345
            code = ds->liner->get_line(ds->liner, &params2, j);
2346
            /* Craply turn that into "greyscale" - this assumes 8 bit. */
2347
            if (num_comps > 1) {
2348
                int i, k;
2349
                byte *dst = ds->params.data[0];
2350
                for (i = 0; i < w; i++) {
2351
                    int v = 0;
2352
                    for (k = num_comps-1; k > 0; k--)
2353
                        v += ((unsigned char *)params2.data[k])[i];
2354
                    *dst++ = (v+(num_comps>>1))/num_comps;
2355
                 }
2356
            }
2357
            code = cal_skew_process(skew, ds->dev->memory, ds->params.data[0]);
2358
        }
2359
        if (code >= 0) {
2360
            ds->skew_angle = cal_skew_detect(skew, ds->dev->memory);
2361
            if (ds->skew_angle < -45 || ds->skew_angle > 45)
2362
                ds->skew_angle = 0;
2363
        }
2364
        cal_skew_fin(skew, ds->dev->memory);
2365
        if (code < 0)
2366
            goto cleanup;
2367
2368
        if (ds->skew_angle != 0) {
2369
            liner_skew *sk_liner;
2370
            unsigned int dw, dh;
2371
2372
            code = alloc_liner(dev->memory,
2373
                               liner_skew,
2374
                               planar_skew_line,
2375
                               planar_skew_drop,
2376
                               &sk_liner);
2377
            if (code < 0)
2378
                goto cleanup;
2379
            sk_liner->chain = ds->liner;
2380
            sk_liner->get_row = 0;
2381
            sk_liner->got_row = 0;
2382
            sk_liner->height = dev->height;
2383
            sk_liner->num_planes = num_comps;
2384
            ds->liner = &sk_liner->base;
2385
            for (i = 0; i < num_comps; i++)
2386
            {
2387
                sk_liner->deskewer[i] = cal_deskewer_init(
2388
                             ds->dev->memory->gs_lib_ctx->core->cal_ctx,
2389
                             ds->dev->memory,
2390
                             ds->dev->width, ds->dev->height,
2391
                             &dw,
2392
                             &dh,
2393
                             ds->skew_angle,
2394
                             1, /* Keep the page size constant */
2395
                             1.0, 1.0, 1.0, 1.0,
2396
                             bg0,
2397
                             1);
2398
                if (sk_liner->deskewer[i] == NULL) {
2399
                    emprintf(dev->memory, "Deskewer initialisation failed");
2400
                    code = gs_note_error(gs_error_VMerror);
2401
                    goto cleanup;
2402
                }
2403
                sk_liner->bander[i] = cal_deskewer_band_begin(sk_liner->deskewer[i],
2404
                                                              ds->dev->memory,
2405
                                                              0, 0);
2406
                if (sk_liner->bander[i] == NULL) {
2407
                    emprintf(dev->memory, "Deskewer initialisation(2) failed");
2408
                    code = gs_note_error(gs_error_VMerror);
2409
                    goto cleanup;
2410
                }
2411
            }
2412
        }
2413
    }
2414
#endif
2415
2416
3.99k
    code = check_trapping(dev->memory, params->trap_w, params->trap_h,
2417
3.99k
                          num_comps, params->trap_order);
2418
3.99k
    if (code < 0)
2419
0
        return code;
2420
2421
3.99k
    if (params->trap_w > 0 || params->trap_h > 0) {
2422
0
        liner_claptrap_planar *ct_liner;
2423
2424
0
        code = alloc_liner(dev->memory,
2425
0
                           liner_claptrap_planar,
2426
0
                           claptrap_planar_line,
2427
0
                           claptrap_planar_drop,
2428
0
                           &ct_liner);
2429
0
        if (code < 0)
2430
0
            goto cleanup;
2431
0
        ct_liner->chain     = ds->liner;
2432
0
        ct_liner->y         = 0;
2433
0
        ct_liner->height    = dev->height;
2434
0
        ct_liner->num_comps = ds->num_comps;
2435
0
        ct_liner->width     = dev->width;
2436
0
        ds->liner = &ct_liner->base;
2437
0
        ct_liner->claptrap = ClapTrap_Init(dev->memory,
2438
0
                                           dev->width,
2439
0
                                           dev->height,
2440
0
                                           num_comps,
2441
0
                                           params->trap_order,
2442
0
                                           params->trap_w,
2443
0
                                           params->trap_h,
2444
0
                                           get_planar_line_for_trap,
2445
0
                                           ct_liner);
2446
0
        if (ct_liner->claptrap == NULL) {
2447
0
            emprintf(dev->memory, "Trapping initialisation failed");
2448
0
            code = gs_note_error(gs_error_VMerror);
2449
0
            goto cleanup;
2450
0
        }
2451
0
    }
2452
2453
3.99k
    if (upfactor > 1) {
2454
0
        ds->scaled_data = gs_alloc_bytes(dev->memory,
2455
0
                                         (size_t)ds->scaled_span * upfactor * num_comps,
2456
0
                                         "gx_downscaler(scaled_data)");
2457
0
        if (ds->scaled_data == NULL) {
2458
0
            code = gs_note_error(gs_error_VMerror);
2459
0
            goto cleanup;
2460
0
        }
2461
0
    }
2462
2463
3.99k
    if ((src_bpc == 8) && (dst_bpc == 8) && (factor == 32)) {
2464
0
        core = &down_core8_3_2;
2465
3.99k
    } else if ((src_bpc == 8) && (dst_bpc == 8) && (factor == 34)) {
2466
0
        core = &down_core8_3_4;
2467
3.99k
    } else if (factor > 8) {
2468
0
        code = gs_note_error(gs_error_rangecheck);
2469
0
        goto cleanup;
2470
3.99k
    } else if (dst_bpc == 1) {
2471
0
        if (src_bpc == dst_bpc)
2472
0
            core = NULL;
2473
0
        else if (mfs > 1)
2474
0
            core = &down_core_mfs;
2475
0
        else if (factor == 4)
2476
0
            core = &down_core_4;
2477
0
        else if (factor == 3)
2478
0
            core = &down_core_3;
2479
0
        else if (factor == 2)
2480
0
            core = &down_core_2;
2481
0
        else if (factor == 1)
2482
0
            core = &down_core_1;
2483
0
        else
2484
0
            core = &down_core;
2485
3.99k
    } else if (factor == 1)
2486
3.99k
        core = NULL;
2487
0
    else if (src_bpc == 16)
2488
0
        core = &down_core16;
2489
0
    else if (factor == 4)
2490
0
        core = &down_core8_4;
2491
0
    else if (factor == 3)
2492
0
        core = &down_core8_3;
2493
0
    else if (factor == 2)
2494
0
        core = &down_core8_2;
2495
0
    else
2496
0
        core = &down_core8;
2497
3.99k
    ds->down_core = core;
2498
2499
3.99k
    if (mfs > 1) {
2500
0
        ds->mfs_data = (byte *)gs_alloc_bytes(dev->memory,
2501
0
                                              (size_t)(width+1) * num_comps,
2502
0
                                              "gx_downscaler(mfs)");
2503
0
        if (ds->mfs_data == NULL) {
2504
0
            code = gs_note_error(gs_error_VMerror);
2505
0
            goto cleanup;
2506
0
        }
2507
0
        memset(ds->mfs_data, 0, (size_t)num_comps * (width+1));
2508
0
    }
2509
3.99k
    if (dst_bpc == 1) {
2510
0
        ds->errors = (int *)gs_alloc_bytes(dev->memory,
2511
0
                                           (size_t)num_comps*(width+3)*sizeof(int),
2512
0
                                           "gx_downscaler(errors)");
2513
0
        if (ds->errors == NULL) {
2514
0
            code = gs_note_error(gs_error_VMerror);
2515
0
            goto cleanup;
2516
0
        }
2517
0
        memset(ds->errors, 0, (size_t)num_comps * (width+3) * sizeof(int));
2518
0
    }
2519
2520
3.99k
    return 0;
2521
2522
0
  cleanup:
2523
0
    gx_downscaler_fin(ds);
2524
0
    return code;
2525
3.99k
}
2526
2527
static int get_line_for_trap(void *arg, unsigned char *buf)
2528
0
{
2529
0
    liner_claptrap *ct = (liner_claptrap *)arg;
2530
2531
    /* Allow for devices (like psdcmyk) that make several passes through
2532
     * the image. This is a bit crap cos it assumes that we will pass
2533
     * through strictly from top to bottom (possibly repeatedly). */
2534
0
    if (ct->y == ct->height)
2535
0
        ct->y = 0;
2536
2537
0
    return ct->chain->get_line(ct->chain, buf, ct->y++);
2538
0
}
2539
2540
int gx_downscaler_init(gx_downscaler_t      *ds,
2541
                       gx_device            *dev,
2542
                       int                   src_bpc,
2543
                       int                   dst_bpc,
2544
                       int                   num_comps,
2545
                 const gx_downscaler_params *params,
2546
                       int                 (*adjust_width_proc)(int, int),
2547
                       int                   adjust_width)
2548
326
{
2549
326
    return gx_downscaler_init_cm(ds, dev, src_bpc, dst_bpc, num_comps,
2550
326
                                 params, adjust_width_proc, adjust_width,
2551
326
                                 NULL, NULL, 0);
2552
326
}
2553
2554
static gx_downscaler_ht_t bogus_ets_halftone;
2555
2556
int gx_downscaler_init_cm(gx_downscaler_t      *ds,
2557
                          gx_device            *dev,
2558
                          int                   src_bpc,
2559
                          int                   dst_bpc,
2560
                          int                   num_comps,
2561
                    const gx_downscaler_params *params,
2562
                          int                 (*adjust_width_proc)(int, int),
2563
                          int                   adjust_width,
2564
                          gx_downscale_cm_fn   *apply_cm,
2565
                          void                 *apply_cm_arg,
2566
                          int                   post_cm_num_comps)
2567
326
{
2568
326
    return gx_downscaler_init_cm_halftone(ds, dev, src_bpc, dst_bpc,
2569
326
                                          num_comps, params,
2570
326
                                          adjust_width_proc, adjust_width,
2571
326
                                          apply_cm, apply_cm_arg,
2572
326
                                          post_cm_num_comps,
2573
326
                                          params->ets ? &bogus_ets_halftone : NULL);
2574
326
}
2575
2576
static gx_downscale_core *
2577
select_8_to_8_core(int nc, int factor)
2578
0
{
2579
0
    if (factor == 1)
2580
0
        return NULL; /* No sense doing anything */
2581
0
    if (nc == 1)
2582
0
    {
2583
0
        if (factor == 4)
2584
0
            return &down_core8_4;
2585
0
        else if (factor == 3)
2586
0
            return &down_core8_3;
2587
0
        else if (factor == 2)
2588
0
            return &down_core8_2;
2589
0
        else
2590
0
            return &down_core8;
2591
0
    }
2592
0
    else if (nc == 3)
2593
0
        return &down_core24;
2594
0
    else if (nc == 4)
2595
0
        return &down_core32;
2596
2597
0
    return NULL;
2598
0
}
2599
2600
int
2601
gx_downscaler_init_cm_halftone(gx_downscaler_t      *ds,
2602
                               gx_device            *dev,
2603
                               int                   src_bpc,
2604
                               int                   dst_bpc,
2605
                               int                   num_comps,
2606
                         const gx_downscaler_params *params,
2607
                               int                 (*adjust_width_proc)(int, int),
2608
                               int                   adjust_width,
2609
                               gx_downscale_cm_fn   *apply_cm,
2610
                               void                 *apply_cm_arg,
2611
                               int                   post_cm_num_comps,
2612
                               gx_downscaler_ht_t   *ht)
2613
326
{
2614
326
    int                size;
2615
326
    int                post_size;
2616
326
    int                span;
2617
326
    int                width;
2618
326
    int                awidth;
2619
326
    int                pad_white;
2620
326
    int                code = 0;
2621
326
    gx_downscale_core *core;
2622
326
    int                upfactor;
2623
326
    int                downfactor;
2624
326
    int                nc;
2625
326
    int                factor = params->downscale_factor;
2626
326
    int                mfs = params->min_feature_size;
2627
2628
326
    size = gdev_mem_bytes_per_scan_line((gx_device *)dev);
2629
326
    post_size = bitmap_raster(dev->width * src_bpc * post_cm_num_comps);
2630
2631
326
    gx_downscaler_decode_factor(factor, &upfactor, &downfactor);
2632
2633
    /* width = scaled width */
2634
326
    width = (dev->width * upfactor)/downfactor;
2635
326
    awidth = width;
2636
326
    if (adjust_width_proc != NULL)
2637
0
        awidth = (*adjust_width_proc)(width, adjust_width);
2638
326
    pad_white = awidth - width;
2639
326
    if (pad_white < 0)
2640
0
        pad_white = 0;
2641
2642
    /* size = unscaled size. span = unscaled size + padding */
2643
326
    span = size + pad_white*downfactor*num_comps/upfactor + downfactor-1;
2644
326
    memset(ds, 0, sizeof(*ds));
2645
326
    ds->dev               = dev;
2646
326
    ds->width             = width;
2647
326
    ds->awidth            = awidth;
2648
326
    ds->span              = span;
2649
326
    ds->factor            = factor;
2650
326
    ds->num_planes        = 0;
2651
326
    ds->src_bpc           = src_bpc;
2652
326
    ds->apply_cm          = apply_cm;
2653
326
    ds->apply_cm_arg      = apply_cm_arg;
2654
326
    ds->early_cm          = dst_bpc < src_bpc;
2655
326
    ds->post_cm_num_comps = post_cm_num_comps;
2656
326
    ds->ht                = ht;
2657
326
    ds->dst_bpc           = dst_bpc;
2658
326
    ds->num_comps         = num_comps;
2659
326
    ds->do_skew_detection = params->do_skew_detection;
2660
2661
    /* The primary line source comes always from getbits. */
2662
326
    {
2663
326
        liner_getbits_chunky *gb_liner;
2664
2665
326
        code = alloc_liner(dev->memory,
2666
326
                           liner_getbits_chunky,
2667
326
                           getbits_chunky_line,
2668
326
                           getbits_chunky_drop,
2669
326
                           &gb_liner);
2670
326
        if (code < 0)
2671
0
            goto cleanup;
2672
326
        gb_liner->dev = dev;
2673
326
        ds->liner = &gb_liner->base;
2674
326
    }
2675
2676
#ifdef WITH_CAL
2677
    if (ds->do_skew_detection) {
2678
        /* Do a skew detection pass */
2679
        int j;
2680
        int w = ds->dev->width;
2681
        int h = ds->dev->height;
2682
        int n = ds->dev->color_info.num_components;
2683
        cal_skew *skew;
2684
        byte *buffer = gs_alloc_bytes(ds->dev->memory, w*n, "skew_row");
2685
        if (buffer == NULL)
2686
            return_error(gs_error_VMerror);
2687
        skew = cal_skew_init(ds->dev->memory->gs_lib_ctx->core->cal_ctx,
2688
                             ds->dev->memory,
2689
                             w, h);
2690
        if (skew == NULL)
2691
            code = gs_error_VMerror;
2692
        for (j = 0; code >= 0 && j < h; j++) {
2693
            code = ds->liner->get_line(ds->liner, buffer, j);
2694
            /* Craply turn that into "greyscale" */
2695
            if (n > 1) {
2696
                int i, k;
2697
                const byte *src = buffer;
2698
                byte *dst = buffer;
2699
                for (i = w; i > 0; i--) {
2700
                    int v = 0;
2701
                    for (k = n; k > 0; k--)
2702
                        v += *src++;
2703
                    *dst++ = (v+(n>>1))/n;
2704
                 }
2705
            }
2706
            code = cal_skew_process(skew, ds->dev->memory, buffer);
2707
        }
2708
        if (code >= 0)
2709
            ds->skew_angle = cal_skew_detect(skew, ds->dev->memory);
2710
        gs_free_object(ds->dev->memory, buffer, "skew_row");
2711
        cal_skew_fin(skew, ds->dev->memory);
2712
        if (code < 0)
2713
            goto cleanup;
2714
2715
        if (ds->skew_angle != 0) {
2716
            liner_skew *sk_liner;
2717
            unsigned int dw, dh;
2718
2719
            code = alloc_liner(dev->memory,
2720
                               liner_skew,
2721
                               skew_line,
2722
                               skew_drop,
2723
                               &sk_liner);
2724
            if (code < 0)
2725
                goto cleanup;
2726
            sk_liner->chain = ds->liner;
2727
            sk_liner->get_row = 0;
2728
            sk_liner->got_row = 0;
2729
            sk_liner->height = dev->height;
2730
            sk_liner->num_planes = 1;
2731
            ds->liner = &sk_liner->base;
2732
            sk_liner->deskewer[0] = cal_deskewer_init(
2733
                             ds->dev->memory->gs_lib_ctx->core->cal_ctx,
2734
                             ds->dev->memory,
2735
                             ds->dev->width, ds->dev->height,
2736
                             &dw,
2737
                             &dh,
2738
                             ds->skew_angle,
2739
                             1, /* Keep the page size constant */
2740
                             1.0, 1.0, 1.0, 1.0,
2741
                             (ds->num_comps <= 3 ? bg1 : bg0),
2742
                             ds->num_comps);
2743
            if (sk_liner->deskewer[0] == NULL) {
2744
                emprintf(dev->memory, "Deskewer initialisation failed");
2745
                code = gs_note_error(gs_error_VMerror);
2746
                goto cleanup;
2747
            }
2748
            sk_liner->bander[0] = cal_deskewer_band_begin(sk_liner->deskewer[0],
2749
                                                       ds->dev->memory,
2750
                                                       0, 0);
2751
            if (sk_liner->bander[0] == NULL) {
2752
                emprintf(dev->memory, "Deskewer initialisation(2) failed");
2753
                code = gs_note_error(gs_error_VMerror);
2754
                goto cleanup;
2755
            }
2756
        }
2757
    }
2758
#endif
2759
2760
0
    code = check_trapping(dev->memory, params->trap_w, params->trap_h,
2761
326
                          num_comps, params->trap_order);
2762
326
    if (code < 0)
2763
0
        return code;
2764
2765
326
    if (params->trap_w > 0 || params->trap_h > 0) {
2766
0
        liner_claptrap *ct_liner;
2767
2768
0
        code = alloc_liner(dev->memory,
2769
0
                           liner_claptrap,
2770
0
                           claptrap_line,
2771
0
                           claptrap_drop,
2772
0
                           &ct_liner);
2773
0
        if (code < 0)
2774
0
            goto cleanup;
2775
0
        ct_liner->chain  = ds->liner;
2776
0
        ct_liner->y      = 0;
2777
0
        ct_liner->height = dev->height;
2778
0
        ds->liner = &ct_liner->base;
2779
0
        ct_liner->claptrap = ClapTrap_Init(dev->memory,
2780
0
                                           width,
2781
0
                                           dev->height,
2782
0
                                           num_comps,
2783
0
                                           params->trap_order,
2784
0
                                           params->trap_w,
2785
0
                                           params->trap_h,
2786
0
                                           get_line_for_trap,
2787
0
                                           ct_liner);
2788
0
        if (ct_liner->claptrap == NULL) {
2789
0
            emprintf(dev->memory, "Trapping initialisation failed");
2790
0
            code = gs_note_error(gs_error_VMerror);
2791
0
            goto cleanup;
2792
0
        }
2793
0
    }
2794
2795
    /* Choose an appropriate core. Try to honour our early_cm
2796
     * choice, and fallback to late cm if we can't. */
2797
326
    core = NULL;
2798
326
    while (1)
2799
326
    {
2800
326
        nc = ds->early_cm ? post_cm_num_comps : num_comps;
2801
2802
326
        if (factor > 8) {
2803
0
            code = gs_note_error(gs_error_rangecheck);
2804
0
            goto cleanup;
2805
0
        }
2806
326
        else if ((src_bpc == 16) && (dst_bpc == 16) && (nc == 1))
2807
0
        {
2808
0
            core = &down_core16;
2809
0
        }
2810
326
        else if ((src_bpc == 8) && (dst_bpc == 1) && (nc == 4))
2811
0
        {
2812
0
            if (mfs > 1)
2813
0
                core = &down_core4_mfs;
2814
0
            else if (ht == &bogus_ets_halftone)
2815
0
            {
2816
0
                code = init_ets(ds, 4, select_8_to_8_core(nc, factor));
2817
0
                if (code)
2818
0
                    goto cleanup;
2819
0
                core = &down_core4_ets;
2820
0
            }
2821
0
            else if (ht != NULL)
2822
0
            {
2823
0
                code = init_ht(ds, 4, select_8_to_8_core(nc, factor));
2824
0
                if (code)
2825
0
                    goto cleanup;
2826
0
                core = &down_core4_ht;
2827
0
            }
2828
0
            else
2829
0
                core = &down_core4;
2830
0
        }
2831
326
        else if ((src_bpc == 8) && (dst_bpc == 1) && (nc == 1))
2832
0
        {
2833
0
            if (mfs > 1)
2834
0
                core = &down_core_mfs;
2835
0
            else if (ht == &bogus_ets_halftone)
2836
0
            {
2837
0
                code = init_ets(ds, 1, select_8_to_8_core(nc, factor));
2838
0
                if (code)
2839
0
                    goto cleanup;
2840
0
                core = &down_core_ets_1;
2841
0
            }
2842
0
            else if (factor == 4)
2843
0
                core = &down_core_4;
2844
0
            else if (factor == 3)
2845
0
                core = &down_core_3;
2846
0
            else if (factor == 2)
2847
0
                core = &down_core_2;
2848
0
            else if (factor == 1)
2849
0
                core = &down_core_1;
2850
0
            else
2851
0
                core = &down_core;
2852
0
        }
2853
326
        else if ((factor == 1) && (src_bpc == dst_bpc))
2854
326
            break;
2855
0
        else if (src_bpc == 8 && dst_bpc == 8)
2856
0
            core = select_8_to_8_core(nc, factor);
2857
2858
        /* If we found one, or we have nothing to fallback to, exit */
2859
0
        if (core || !ds->early_cm)
2860
0
            break;
2861
2862
        /* Fallback */
2863
0
        ds->early_cm = false;
2864
0
    }
2865
326
    if (factor == 1 && src_bpc == dst_bpc) {
2866
        /* core can permissibly be NULL */
2867
326
    } else if (core == NULL) {
2868
0
        code = gs_note_error(gs_error_rangecheck);
2869
0
        goto cleanup;
2870
0
    }
2871
326
    ds->down_core = core;
2872
2873
326
    if (apply_cm) {
2874
0
        ds->post_cm[0] = gs_alloc_bytes(dev->memory,
2875
0
                                        (size_t)post_size * downfactor,
2876
0
                                        "gx_downscaler(data)");
2877
0
        if (ds->post_cm[0] == NULL) {
2878
0
            code = gs_note_error(gs_error_VMerror);
2879
0
            goto cleanup;
2880
0
        }
2881
0
    }
2882
2883
326
    if (core != NULL || apply_cm) {
2884
0
        ds->pre_cm[0] = gs_alloc_bytes(dev->memory,
2885
0
                                       (size_t)span * downfactor,
2886
0
                                       "gx_downscaler(data)");
2887
0
        if (ds->pre_cm[0] == NULL) {
2888
0
            code = gs_note_error(gs_error_VMerror);
2889
0
            goto cleanup;
2890
0
        }
2891
0
    }
2892
326
    if (core != NULL) {
2893
0
        if (mfs > 1) {
2894
0
            ds->mfs_data = (byte *)gs_alloc_bytes(dev->memory,
2895
0
                                                  (size_t)(awidth+1)*nc,
2896
0
                                                  "gx_downscaler(mfs)");
2897
0
            if (ds->mfs_data == NULL) {
2898
0
                code = gs_note_error(gs_error_VMerror);
2899
0
                goto cleanup;
2900
0
            }
2901
0
            memset(ds->mfs_data, 0, (size_t)nc*(awidth+1));
2902
0
        }
2903
0
        if (dst_bpc == 1) {
2904
0
            ds->errors = (int *)gs_alloc_bytes(dev->memory,
2905
0
                                               (size_t)nc*(awidth+3)*sizeof(int),
2906
0
                                               "gx_downscaler(errors)");
2907
0
            if (ds->errors == NULL) {
2908
0
                code = gs_note_error(gs_error_VMerror);
2909
0
                goto cleanup;
2910
0
            }
2911
0
            memset(ds->errors, 0, (size_t)nc * (awidth+3) * sizeof(int));
2912
0
        }
2913
0
    }
2914
2915
326
    return 0;
2916
2917
0
  cleanup:
2918
0
    gx_downscaler_fin(ds);
2919
0
    return code;
2920
326
}
2921
2922
void gx_downscaler_fin(gx_downscaler_t *ds)
2923
4.32k
{
2924
4.32k
    if (ds->dev == NULL)
2925
0
        return;
2926
2927
4.32k
    gs_free_object(ds->dev->memory, ds->pre_cm[0],
2928
4.32k
                   "gx_downscaler(planar_data)");
2929
4.32k
    gs_free_object(ds->dev->memory, ds->post_cm[0],
2930
4.32k
                   "gx_downscaler(planar_data)");
2931
4.32k
    ds->pre_cm[0] = NULL;
2932
4.32k
    ds->post_cm[0] = NULL;
2933
4.32k
    ds->num_planes = 0;
2934
2935
4.32k
    gs_free_object(ds->dev->memory, ds->mfs_data, "gx_downscaler(mfs)");
2936
4.32k
    ds->mfs_data = NULL;
2937
4.32k
    gs_free_object(ds->dev->memory, ds->errors, "gx_downscaler(errors)");
2938
4.32k
    ds->errors = NULL;
2939
4.32k
    gs_free_object(ds->dev->memory, ds->scaled_data, "gx_downscaler(scaled_data)");
2940
4.32k
    ds->scaled_data = NULL;
2941
4.32k
    gs_free_object(ds->dev->memory, ds->htrow_alloc, "gx_downscaler(htrow)");
2942
4.32k
    ds->htrow = NULL;
2943
4.32k
    ds->htrow_alloc = NULL;
2944
2945
4.32k
    if (ds->liner)
2946
4.32k
        ds->liner->drop(ds->liner, ds->dev->memory);
2947
4.32k
    ds->liner = NULL;
2948
2949
4.32k
    if (ds->ets_config)
2950
0
        ets_destroy(ds->dev->memory, ds->ets_config);
2951
4.32k
    ds->ets_config = NULL;
2952
4.32k
}
2953
2954
/* Chunky case */
2955
int gx_downscaler_getbits(gx_downscaler_t *ds,
2956
                          byte            *out_data,
2957
                          int              row)
2958
639k
{
2959
639k
    int   code = 0;
2960
639k
    int   y, y_end;
2961
639k
    byte *data_ptr;
2962
639k
    int   upfactor, downfactor;
2963
2964
639k
    gx_downscaler_decode_factor(ds->factor, &upfactor, &downfactor);
2965
2966
    /* Check for the simple case */
2967
639k
    if (ds->down_core == NULL) {
2968
639k
        code = ds->liner->get_line(ds->liner,
2969
639k
                                   ds->apply_cm ? ds->pre_cm[0] : out_data,
2970
639k
                                   row);
2971
639k
        if (code < 0)
2972
0
            return code;
2973
639k
        if (ds->apply_cm) {
2974
0
            data_ptr = out_data;
2975
0
            return ds->apply_cm(ds->apply_cm_arg, &data_ptr, ds->pre_cm, ds->width, 1, 0);
2976
0
        }
2977
639k
        return 0;
2978
639k
    }
2979
2980
    /* Get factor rows worth of data */
2981
0
    y        = row * downfactor;
2982
0
    y_end    = y + downfactor;
2983
0
    data_ptr = ds->pre_cm[0];
2984
0
    do {
2985
0
        code = ds->liner->get_line(ds->liner, data_ptr, y);
2986
0
        if (code < 0)
2987
0
            return code;
2988
0
        data_ptr += ds->span;
2989
0
        y++;
2990
0
    } while (y < y_end);
2991
2992
0
    if (ds->apply_cm) {
2993
0
        if (ds->early_cm) {
2994
0
            code = ds->apply_cm(ds->apply_cm_arg, ds->post_cm, ds->pre_cm, ds->dev->width, 1, 0);
2995
0
            if (code < 0)
2996
0
                return code;
2997
0
            (ds->down_core)(ds, out_data, ds->post_cm[0], row, 0, ds->span);
2998
0
        } else {
2999
0
            data_ptr = out_data;
3000
0
            (ds->down_core)(ds, ds->post_cm[0], ds->pre_cm[0], row, 0, ds->span);
3001
0
            code = ds->apply_cm(ds->apply_cm_arg, &out_data, ds->post_cm, ds->width, 1, 0);
3002
0
            if (code < 0)
3003
0
                return code;
3004
0
        }
3005
0
    } else
3006
0
        (ds->down_core)(ds, out_data, ds->pre_cm[0], row, 0, ds->span);
3007
3008
0
    return code;
3009
0
}
3010
3011
/* Planar case */
3012
int gx_downscaler_get_bits_rectangle(gx_downscaler_t      *ds,
3013
                                     gs_get_bits_params_t *params,
3014
                                     int                   row)
3015
3.99k
{
3016
3.99k
    int                   code = 0;
3017
3.99k
    gs_int_rect           rect;
3018
3.99k
    int                   plane;
3019
3.99k
    int                   factor = ds->factor;
3020
3.99k
    gs_get_bits_params_t  params2;
3021
3.99k
    int                   upfactor, downfactor;
3022
3.99k
    int                   subrow;
3023
3.99k
    int                   copy = (ds->dev->width * ds->src_bpc + 7)>>3;
3024
3.99k
    int                   i, j, n;
3025
3.99k
    int                   num_planes_to_downscale;
3026
3027
3.99k
    n = ds->dev->width;
3028
3.99k
    if (ds->dev->color_info.depth > ds->dev->color_info.num_components*8+8)
3029
0
       n *= 2;
3030
3031
3.99k
    n = (n*ds->src_bpc+7)/8;
3032
3033
3.99k
    gx_downscaler_decode_factor(factor, &upfactor, &downfactor);
3034
3035
3.99k
    subrow = row % upfactor;
3036
3.99k
    if (subrow) {
3037
        /* Just copy a previous row from our stored buffer */
3038
0
        for (plane=0; plane < ds->num_planes; plane++)
3039
0
            params->data[plane] = ds->scaled_data + (upfactor * plane + subrow) * ds->scaled_span;
3040
0
        return 0;
3041
0
    }
3042
3043
3.99k
    rect.p.x = 0;
3044
3.99k
    rect.p.y = (row/upfactor) * downfactor;
3045
3.99k
    rect.q.x = ds->dev->width;
3046
3.99k
    rect.q.y = ((row/upfactor) + 1) * downfactor;
3047
3048
    /* Check for the simple case */
3049
3.99k
    if (ds->down_core == NULL) {
3050
3.99k
        gs_get_bits_params_t saved;
3051
3.99k
        if (ds->apply_cm) {
3052
            /* Always do the request giving our own workspace,
3053
             * and be prepared to accept a pointer */
3054
0
            saved = *params;
3055
0
            for (i = 0; i < ds->num_planes; i++)
3056
0
                params->data[i] = ds->pre_cm[i];
3057
0
            params->options |= GB_RETURN_POINTER;
3058
0
        }
3059
3.99k
        code = ds->liner->get_line(ds->liner, params, row);
3060
3.99k
        if (code < 0)
3061
0
            return code;
3062
3.99k
        if (ds->apply_cm) {
3063
0
            byte **buffer;
3064
0
            if (saved.options & GB_RETURN_COPY) {
3065
                /* They will accept a copy. Let's use the buffer they supplied */
3066
0
                params->options &= ~GB_RETURN_POINTER;
3067
0
                buffer = saved.data;
3068
0
            } else
3069
0
                buffer = ds->post_cm;
3070
0
            code = ds->apply_cm(ds->apply_cm_arg, buffer, params->data, ds->dev->width, rect.q.y - rect.p.y, params->raster);
3071
0
            for (i = 0; i < ds->post_cm_num_comps; i++)
3072
0
                params->data[i] = buffer[i];
3073
0
        }
3074
3.99k
        return code;
3075
3.99k
    }
3076
3077
    /* Copy the params, because get_bits_rectangle can helpfully overwrite
3078
     * them. */
3079
0
    memcpy(&params2, &ds->params, sizeof(params2));
3080
0
    for (i = 0; i < ds->num_planes; i++)
3081
0
         params2.data[i] = ds->pre_cm[i];
3082
3083
    /* Get downfactor rows worth of data - we always work a line at a
3084
     * time now. */
3085
0
    for (i = 0; i < downfactor; i++) {
3086
0
        rect.q.y = rect.p.y+1;
3087
0
        if (rect.q.y > ds->dev->height)
3088
0
            break;
3089
0
        memcpy(&params2, &ds->params, sizeof(params2));
3090
0
        for (j = 0; j < ds->num_planes; j++)
3091
0
            params2.data[j] = ds->pre_cm[j] + i * ds->span;
3092
0
        code = ds->liner->get_line(ds->liner, &params2, rect.p.y);
3093
0
        if (code < 0)
3094
0
            break;
3095
0
        for (j = 0; j < ds->num_planes; j++) {
3096
0
            byte *tgt = ds->pre_cm[j] + i * ds->span;
3097
0
            if (params2.data[j] != tgt)
3098
0
                memcpy(tgt, params2.data[j], n);
3099
0
        }
3100
0
        rect.p.y++;
3101
0
    }
3102
0
    if (i == 0)
3103
0
        return code;
3104
0
    if (code < 0)
3105
0
        return code;
3106
    /* If we still haven't got enough, we've hit the end of the page; just
3107
     * duplicate the last line we did get. */
3108
0
    for (; i < downfactor; i++)
3109
0
        for (j = 0; j < ds->num_planes; j++)
3110
0
            memcpy(ds->pre_cm[j] + i*ds->span, ds->pre_cm[j] + (i-1)*ds->span, copy);
3111
3112
    /* All the data is now in ds->pre_cm. Update params2.data so that this points to
3113
     * it. From here on in, we will keep params2.data pointing to whereever the
3114
     * latest processed version of the data is. */
3115
0
    for (j = 0; j < ds->num_planes; j++)
3116
0
        params2.data[j] = ds->pre_cm[j];
3117
3118
0
    num_planes_to_downscale = ds->num_planes;
3119
0
    if (ds->early_cm && ds->apply_cm) {
3120
0
        code = ds->apply_cm(ds->apply_cm_arg, ds->post_cm, params2.data, ds->dev->width, downfactor, ds->span);
3121
0
        if (code < 0)
3122
0
            return code;
3123
0
        for (j = 0; j < ds->post_cm_num_comps; j++)
3124
0
            params2.data[j] = ds->post_cm[j];
3125
0
        num_planes_to_downscale = ds->post_cm_num_comps;
3126
0
    }
3127
3128
0
    if (upfactor > 1) {
3129
        /* Downscale the block of lines into our output buffer */
3130
0
        for (plane=0; plane < num_planes_to_downscale; plane++) {
3131
0
            byte *scaled = ds->scaled_data + upfactor * plane * ds->scaled_span;
3132
0
            (ds->down_core)(ds, scaled, params2.data[plane], row, plane, params2.raster);
3133
0
            params2.data[plane] = scaled;
3134
0
        }
3135
0
    } else if (ds->down_core != NULL) {
3136
        /* Downscale direct into output buffer */
3137
0
        for (plane=0; plane < num_planes_to_downscale; plane++) {
3138
0
            (ds->down_core)(ds, params->data[plane], params2.data[plane], row, plane, params2.raster);
3139
0
            params2.data[plane] = params->data[plane];
3140
0
        }
3141
0
    } else {
3142
        /* Copy into output buffer */
3143
        /* No color management can be required here */
3144
0
        assert(!ds->early_cm || ds->apply_cm == NULL);
3145
0
        for (plane=0; plane < num_planes_to_downscale; plane++) {
3146
0
            memcpy(params->data[plane], params2.data[plane], params2.raster);
3147
0
            params2.data[plane] = params->data[plane];
3148
0
        }
3149
0
    }
3150
3151
0
    if (!ds->early_cm && ds->apply_cm) {
3152
0
        code = ds->apply_cm(ds->apply_cm_arg, params->data, params2.data, ds->width, 1, params->raster);
3153
0
        if (code < 0)
3154
0
            return code;
3155
0
        for (plane=0; plane < num_planes_to_downscale; plane++)
3156
0
            params2.data[plane] = params->data[plane];
3157
0
    }
3158
3159
0
    for (plane=0; plane < num_planes_to_downscale; plane++)
3160
0
        params->data[plane] = params2.data[plane];
3161
3162
0
    return code;
3163
0
}
3164
3165
typedef struct downscaler_process_page_arg_s
3166
{
3167
    gx_process_page_options_t *orig_options;
3168
    int upfactor;
3169
    int downfactor;
3170
    gx_downscaler_t ds;
3171
}
3172
downscaler_process_page_arg_t;
3173
3174
typedef struct downscaler_process_page_buffer_s
3175
{
3176
    gx_device *bdev;
3177
    void *orig_buffer;
3178
}
3179
downscaler_process_page_buffer_t;
3180
3181
static int downscaler_init_fn(void *arg_, gx_device *dev, gs_memory_t *memory, int w, int h, void **pbuffer)
3182
0
{
3183
0
    downscaler_process_page_arg_t *arg = (downscaler_process_page_arg_t *)arg_;
3184
0
    downscaler_process_page_buffer_t *buffer;
3185
0
    int code = 0;
3186
3187
0
    buffer = (downscaler_process_page_buffer_t *)gs_alloc_bytes(memory, sizeof(*buffer), "downscaler process_page buffer");
3188
0
    if (buffer == NULL)
3189
0
        return_error(gs_error_VMerror);
3190
0
    memset(buffer, 0, sizeof(*buffer));
3191
3192
0
    if (arg->upfactor > arg->downfactor) {
3193
0
        code = gx_default_create_buf_device(&buffer->bdev, dev,
3194
0
                          (h*arg->upfactor + arg->downfactor-1)/arg->downfactor,
3195
0
                          NULL, memory, NULL);
3196
0
        if (code < 0) {
3197
0
            gs_free_object(memory, buffer, "downscaler process_page buffer");
3198
0
            return code;
3199
0
        }
3200
0
    }
3201
3202
0
    if (arg->orig_options && arg->orig_options->init_buffer_fn) {
3203
0
        code = arg->orig_options->init_buffer_fn(arg->orig_options->arg, dev, memory,
3204
0
                                                 (w * arg->upfactor + arg->downfactor-1)/arg->downfactor,
3205
0
                                                 (h * arg->upfactor + arg->downfactor-1)/arg->downfactor,
3206
0
                                                 &buffer->orig_buffer);
3207
0
        if (code < 0) {
3208
0
            if (buffer->bdev)
3209
0
                dev_proc(dev, close_device)(dev);
3210
0
            gs_free_object(memory, buffer, "downscaler process_page buffer");
3211
0
            return code;
3212
0
        }
3213
0
    }
3214
3215
0
    *pbuffer = (void *)buffer;
3216
0
    return code;
3217
0
}
3218
3219
static int downscaler_process_fn(void *arg_, gx_device *dev, gx_device *bdev, const gs_int_rect *rect, void *buffer_)
3220
0
{
3221
0
    downscaler_process_page_arg_t *arg = (downscaler_process_page_arg_t *)arg_;
3222
0
    downscaler_process_page_buffer_t *buffer = (downscaler_process_page_buffer_t *)buffer_;
3223
0
    int code, raster_in, raster_out;
3224
0
    gs_get_bits_params_t params;
3225
0
    gs_int_rect in_rect, out_rect;
3226
0
    byte *in_ptr, *out_ptr;
3227
3228
0
    in_rect.p.x = 0;
3229
0
    in_rect.p.y = 0;
3230
0
    in_rect.q.x = rect->q.x - rect->p.x;
3231
0
    in_rect.q.y = rect->q.y - rect->p.y;
3232
0
    out_rect.p.x = 0;
3233
0
    out_rect.p.y = 0;
3234
0
    out_rect.q.x = (in_rect.q.x * arg->upfactor + arg->downfactor-1) / arg->downfactor;
3235
0
    out_rect.q.y = (in_rect.q.y * arg->upfactor + arg->downfactor-1) / arg->downfactor;
3236
3237
    /* Where do we get the data from? */
3238
0
    params.options = GB_COLORS_NATIVE | GB_ALPHA_NONE | GB_PACKING_CHUNKY | GB_RETURN_POINTER | GB_ALIGN_ANY | GB_OFFSET_0 | GB_RASTER_ANY;
3239
0
    code = dev_proc(bdev, get_bits_rectangle)(bdev, &in_rect, &params);
3240
0
    if (code < 0)
3241
0
        return code;
3242
0
    raster_in = params.raster;
3243
0
    in_ptr = params.data[0];
3244
3245
    /* Where do we write it to? */
3246
0
    if (buffer->bdev) {
3247
0
        code = dev_proc(bdev, get_bits_rectangle)(buffer->bdev, &out_rect, &params);
3248
0
        if (code < 0)
3249
0
            return code;
3250
0
        raster_out = params.raster;
3251
0
        out_ptr = params.data[0];
3252
0
    } else {
3253
0
        raster_out = raster_in;
3254
0
        out_ptr = params.data[0];
3255
0
    }
3256
3257
    /* Do the downscale */
3258
0
    if (arg->ds.down_core) {
3259
0
        int y;
3260
0
        for (y = rect->p.y; y < rect->q.y; y += arg->downfactor)
3261
0
        {
3262
0
            arg->ds.down_core(&arg->ds, out_ptr, in_ptr, y, 0, arg->ds.span);
3263
0
            in_ptr += arg->ds.span * arg->downfactor;
3264
0
            out_ptr += raster_out * arg->upfactor;
3265
0
        }
3266
0
    }
3267
3268
    /* Pass on to further processing */
3269
0
    if (arg->orig_options && arg->orig_options->process_fn) {
3270
0
        out_rect.p.y = rect->p.y*arg->upfactor/arg->downfactor;
3271
0
        out_rect.q.y += out_rect.p.y;
3272
0
        code = arg->orig_options->process_fn(arg->orig_options->arg, dev,
3273
0
                                             (buffer->bdev ? buffer->bdev : bdev),
3274
0
                                             &out_rect, buffer->orig_buffer);
3275
0
    }
3276
0
    return code;
3277
0
}
3278
3279
static void
3280
downscaler_free_fn(void *arg_, gx_device *dev, gs_memory_t *memory, void *buffer_)
3281
0
{
3282
0
    downscaler_process_page_arg_t *arg = (downscaler_process_page_arg_t *)arg_;
3283
0
    downscaler_process_page_buffer_t *buffer = (downscaler_process_page_buffer_t *)buffer_;
3284
3285
0
    arg->orig_options->free_buffer_fn(arg->orig_options->arg, dev, memory,
3286
0
                                      buffer->orig_buffer);
3287
0
    if (buffer->bdev)
3288
0
        dev_proc(dev, close_device)(dev);
3289
0
    gs_free_object(memory, buffer, "downscaler process_page buffer");
3290
0
}
3291
3292
static int
3293
downscaler_output_fn(void *arg_, gx_device *dev, void *buffer_)
3294
0
{
3295
0
    downscaler_process_page_arg_t *arg = (downscaler_process_page_arg_t *)arg_;
3296
0
    downscaler_process_page_buffer_t *buffer = (downscaler_process_page_buffer_t *)buffer_;
3297
3298
0
    return arg->orig_options->output_fn(arg->orig_options->arg, dev,
3299
0
                                        buffer->orig_buffer);
3300
0
}
3301
3302
/* No error diffusion with process_page as bands need to be handled
3303
 * separately. */
3304
int gx_downscaler_process_page(gx_device                 *dev,
3305
                               gx_process_page_options_t *options,
3306
                               int                        factor)
3307
0
{
3308
0
    downscaler_process_page_arg_t arg = { 0 };
3309
0
    gx_process_page_options_t my_options = { 0 };
3310
0
    int num_comps = dev->color_info.num_components;
3311
0
    int src_bpc = dev->color_info.comp_bits[0];
3312
0
    int scaled_w;
3313
0
    gx_downscale_core *core;
3314
3315
0
    arg.orig_options = options;
3316
0
    gx_downscaler_decode_factor(factor, &arg.upfactor, &arg.downfactor);
3317
0
    arg.ds.dev = dev;
3318
0
    arg.ds.width = (dev->width * arg.upfactor + arg.downfactor-1)/arg.downfactor;
3319
0
    arg.ds.awidth = arg.ds.width;
3320
0
    arg.ds.span = bitmap_raster(dev->width * num_comps * src_bpc);
3321
0
    scaled_w = (dev->width * arg.upfactor + arg.downfactor-1)/arg.downfactor;
3322
0
    arg.ds.factor = factor;
3323
0
    arg.ds.src_bpc = src_bpc;
3324
0
    arg.ds.scaled_span = bitmap_raster(scaled_w * num_comps * src_bpc);
3325
0
    arg.ds.num_planes = 0;
3326
3327
    /* Choose an appropriate core */
3328
0
    if (factor > 8)
3329
0
    {
3330
0
        return gs_note_error(gs_error_rangecheck);
3331
0
    }
3332
0
    else if ((src_bpc == 16) && (num_comps == 1))
3333
0
    {
3334
0
        core = &down_core16;
3335
0
    }
3336
0
    else if (factor == 1)
3337
0
        core = NULL;
3338
0
    else if ((src_bpc == 8) && (num_comps == 1))
3339
0
    {
3340
0
        if (factor == 4)
3341
0
            core = &down_core8_4;
3342
0
        else if (factor == 3)
3343
0
            core = &down_core8_3;
3344
0
        else if (factor == 2)
3345
0
            core = &down_core8_2;
3346
0
        else
3347
0
            core = &down_core8;
3348
0
    }
3349
0
    else if ((src_bpc == 8) && (num_comps == 3))
3350
0
        core = &down_core24;
3351
0
    else if ((src_bpc == 8) && (num_comps == 4))
3352
0
         core = &down_core32;
3353
0
    else {
3354
0
        return gs_note_error(gs_error_rangecheck);
3355
0
    }
3356
0
    arg.ds.down_core = core;
3357
3358
0
    my_options.init_buffer_fn = downscaler_init_fn;
3359
0
    my_options.process_fn = downscaler_process_fn;
3360
0
    my_options.output_fn = downscaler_output_fn;
3361
0
    my_options.free_buffer_fn = downscaler_free_fn;
3362
0
    my_options.arg = &arg;
3363
3364
0
    return dev_proc(dev, process_page)(dev, &my_options);
3365
0
}
3366
3367
int gx_downscaler_read_params(gs_param_list        *plist,
3368
                              gx_downscaler_params *params,
3369
                              int                   features)
3370
69.1k
{
3371
69.1k
    int code;
3372
69.1k
    int downscale, mfs, ets, deskew;
3373
69.1k
    int trap_w, trap_h;
3374
69.1k
    const char *param_name;
3375
69.1k
    gs_param_int_array trap_order;
3376
3377
69.1k
    trap_order.data = NULL;
3378
3379
69.1k
    switch (code = param_read_int(plist,
3380
69.1k
                                   (param_name = "DownScaleFactor"),
3381
69.1k
                                   &downscale)) {
3382
66.2k
        case 1:
3383
66.2k
            break;
3384
2.87k
        case 0:
3385
2.87k
            if (downscale >= 1) {
3386
2.87k
                params->downscale_factor = downscale;
3387
2.87k
                break;
3388
2.87k
            }
3389
0
            code = gs_error_rangecheck;
3390
0
        default:
3391
0
            param_signal_error(plist, param_name, code);
3392
0
            return code;
3393
69.1k
    }
3394
3395
69.1k
    switch (code = param_read_bool(plist,
3396
69.1k
                                   (param_name = "Deskew"),
3397
69.1k
                                   &deskew)) {
3398
66.2k
        case 1:
3399
66.2k
            break;
3400
2.87k
        case 0:
3401
2.87k
            if (deskew >= 0) {
3402
2.87k
                params->do_skew_detection = deskew;
3403
2.87k
                break;
3404
2.87k
            }
3405
0
            code = gs_error_rangecheck;
3406
0
        default:
3407
0
            param_signal_error(plist, param_name, code);
3408
0
            return code;
3409
69.1k
    }
3410
3411
69.1k
    if (features & GX_DOWNSCALER_PARAMS_MFS)
3412
2.30k
    {
3413
2.30k
        switch (code = param_read_int(plist, (param_name = "MinFeatureSize"), &mfs)) {
3414
2.07k
            case 1:
3415
2.07k
                break;
3416
227
            case 0:
3417
227
                if ((mfs >= 0) && (mfs <= 4)) {
3418
227
                    params->min_feature_size = mfs;
3419
227
                    break;
3420
227
                }
3421
0
                code = gs_error_rangecheck;
3422
0
            default:
3423
0
                param_signal_error(plist, param_name, code);
3424
0
                return code;
3425
2.30k
        }
3426
2.30k
    }
3427
3428
69.1k
    if (features & GX_DOWNSCALER_PARAMS_TRAP)
3429
41.3k
    {
3430
41.3k
        switch (code = param_read_int(plist,
3431
41.3k
                                      (param_name = "TrapX"),
3432
41.3k
                                      &trap_w)) {
3433
38.6k
            case 1:
3434
38.6k
                break;
3435
2.77k
            case 0:
3436
2.77k
                if (trap_w >= 0)
3437
2.77k
                {
3438
2.77k
                    params->trap_w = trap_w;
3439
2.77k
                    break;
3440
2.77k
                }
3441
0
                code = gs_error_rangecheck;
3442
0
            default:
3443
0
                param_signal_error(plist, param_name, code);
3444
0
                return code;
3445
41.3k
        }
3446
41.3k
        switch (code = param_read_int(plist,
3447
41.3k
                                      (param_name = "TrapY"),
3448
41.3k
                                      &trap_h)) {
3449
38.6k
            case 1:
3450
38.6k
                break;
3451
2.77k
            case 0:
3452
2.77k
                if (trap_h >= 0)
3453
2.77k
                {
3454
2.77k
                    params->trap_h = trap_h;
3455
2.77k
                    break;
3456
2.77k
                }
3457
0
                code = gs_error_rangecheck;
3458
0
            default:
3459
0
                param_signal_error(plist, param_name, code);
3460
0
                return code;
3461
41.3k
        }
3462
41.3k
        switch (code = param_read_int_array(plist, (param_name = "TrapOrder"), &trap_order)) {
3463
2.77k
            case 0:
3464
2.77k
                break;
3465
38.6k
            case 1:
3466
38.6k
                trap_order.data = 0;          /* mark as not filled */
3467
38.6k
                break;
3468
0
            default:
3469
0
                param_signal_error(plist, param_name, code);
3470
0
                return code;
3471
41.3k
        }
3472
3473
41.3k
        if (trap_order.data != NULL)
3474
2.77k
        {
3475
2.77k
            int i;
3476
2.77k
            int n = trap_order.size;
3477
3478
2.77k
            if (n > GS_CLIENT_COLOR_MAX_COMPONENTS)
3479
0
                n = GS_CLIENT_COLOR_MAX_COMPONENTS;
3480
3481
180k
            for (i = 0; i < n; i++)
3482
177k
            {
3483
177k
                params->trap_order[i] = trap_order.data[i];
3484
177k
            }
3485
2.77k
            for (; i < GS_CLIENT_COLOR_MAX_COMPONENTS; i++)
3486
0
            {
3487
0
                params->trap_order[i] = i;
3488
0
            }
3489
2.77k
        }
3490
38.6k
        else
3491
38.6k
        {
3492
            /* Set some sane defaults */
3493
38.6k
            int i;
3494
3495
38.6k
            params->trap_order[0] = 3; /* K */
3496
38.6k
            params->trap_order[1] = 1; /* M */
3497
38.6k
            params->trap_order[2] = 0; /* C */
3498
38.6k
            params->trap_order[3] = 2; /* Y */
3499
3500
2.35M
            for (i = 4; i < GS_CLIENT_COLOR_MAX_COMPONENTS; i++)
3501
2.31M
            {
3502
2.31M
                params->trap_order[i] = i;
3503
2.31M
            }
3504
38.6k
        }
3505
41.3k
    }
3506
69.1k
    if (features & GX_DOWNSCALER_PARAMS_ETS)
3507
0
    {
3508
0
        switch (code = param_read_int(plist,
3509
0
                                      (param_name = "DownScaleETS"),
3510
0
                                      &ets)) {
3511
0
            case 1:
3512
0
                break;
3513
0
            case 0:
3514
0
                if (ets >= 0)
3515
0
                {
3516
0
                    params->ets = ets;
3517
0
                    break;
3518
0
                }
3519
0
                code = gs_error_rangecheck;
3520
0
            default:
3521
0
                param_signal_error(plist, param_name, code);
3522
0
                return code;
3523
0
        }
3524
0
    }
3525
3526
69.1k
    return 0;
3527
69.1k
}
3528
3529
int gx_downscaler_write_params(gs_param_list        *plist,
3530
                               gx_downscaler_params *params,
3531
                               int                   features)
3532
234k
{
3533
234k
    int code;
3534
234k
    int ecode = 0;
3535
234k
    gs_param_int_array trap_order;
3536
3537
234k
    trap_order.data = params->trap_order;
3538
234k
    trap_order.size = GS_CLIENT_COLOR_MAX_COMPONENTS;
3539
234k
    trap_order.persistent = false;
3540
3541
234k
    if ((code = param_write_int(plist, "DownScaleFactor", &params->downscale_factor)) < 0)
3542
0
        ecode = code;
3543
234k
    if ((code = param_write_bool(plist, "Deskew", &params->do_skew_detection)) < 0)
3544
0
        ecode = code;
3545
234k
    if (features & GX_DOWNSCALER_PARAMS_MFS)
3546
8.82k
    {
3547
8.82k
        if ((code = param_write_int(plist, "MinFeatureSize", &params->min_feature_size)) < 0)
3548
0
            ecode = code;
3549
8.82k
    }
3550
234k
    if (features & GX_DOWNSCALER_PARAMS_TRAP)
3551
141k
    {
3552
141k
        if ((code = param_write_int(plist, "TrapX", &params->trap_w)) < 0)
3553
0
            ecode = code;
3554
141k
        if ((code = param_write_int(plist, "TrapY", &params->trap_h)) < 0)
3555
0
            ecode = code;
3556
141k
        if ((code = param_write_int_array(plist, "TrapOrder", &trap_order)) < 0)
3557
0
            ecode = code;
3558
141k
    }
3559
234k
    if (features & GX_DOWNSCALER_PARAMS_ETS)
3560
0
    {
3561
0
        if ((code = param_write_int(plist, "DownScaleETS", &params->ets)) < 0)
3562
0
            ecode = code;
3563
0
    }
3564
3565
234k
    return ecode;
3566
234k
}
3567
3568
/* ETS relies on some malloc wrappers */
3569
void *ets_malloc(void *malloc_arg, int size)
3570
0
{
3571
0
    return gs_alloc_bytes((gs_memory_t *)malloc_arg, size, "ets_malloc");
3572
0
}
3573
3574
void *ets_calloc(void *malloc_arg, int count, int size)
3575
0
{
3576
0
    void *p = ets_malloc(malloc_arg, (size_t)count * size);
3577
0
    if (p)
3578
0
        memset(p, 0, (size_t)count * size);
3579
0
    return p;
3580
0
}
3581
3582
void ets_free(void *malloc_arg, void *p)
3583
0
{
3584
0
    if (!p)
3585
0
        return;
3586
3587
0
    gs_free_object((gs_memory_t *)malloc_arg, p, "ets_malloc");
3588
0
}
3589
3590
int gx_downscaler_create_post_render_link(gx_device *dev, gsicc_link_t **link)
3591
0
{
3592
0
    cmm_dev_profile_t *profile_struct;
3593
0
    gsicc_rendering_param_t rendering_params;
3594
0
    int code = dev_proc(dev, get_profile)(dev, &profile_struct);
3595
0
    if (code < 0)
3596
0
        return_error(gs_error_undefined);
3597
3598
0
    *link = NULL;
3599
0
    if (profile_struct->postren_profile == NULL)
3600
0
        return 0;
3601
3602
0
    rendering_params.black_point_comp = gsBLACKPTCOMP_ON;
3603
0
    rendering_params.graphics_type_tag = GS_UNKNOWN_TAG;
3604
0
    rendering_params.override_icc = false;
3605
0
    rendering_params.preserve_black = gsBLACKPRESERVE_OFF;
3606
0
    rendering_params.rendering_intent = gsRELATIVECOLORIMETRIC;
3607
0
    rendering_params.cmm = gsCMM_DEFAULT;
3608
0
    *link = gsicc_alloc_link_dev(dev->memory,
3609
0
                                 profile_struct->device_profile[GS_DEFAULT_DEVICE_PROFILE],
3610
0
                                 profile_struct->postren_profile,
3611
0
                                 &rendering_params);
3612
0
    if (*link == NULL)
3613
0
        return_error(gs_error_VMerror);
3614
3615
    /* If it is identity, release it now and set link to NULL */
3616
0
    if ((*link)->is_identity) {
3617
0
        gsicc_free_link_dev(*link);
3618
0
        *link = NULL;
3619
0
    }
3620
0
    return 0;
3621
0
}
3622
3623
int gx_downscaler_create_icc_link(gx_device *dev, gsicc_link_t **link, cmm_profile_t *icc_profile)
3624
0
{
3625
0
    gsicc_rendering_param_t rendering_params;
3626
0
    cmm_dev_profile_t *profile_struct;
3627
0
    int code = dev_proc(dev, get_profile)(dev, &profile_struct);
3628
3629
0
    *link = NULL;
3630
3631
0
    if (code < 0)
3632
0
        return code;
3633
3634
0
    if (icc_profile == NULL)
3635
0
        return 0; /* Should be an error, maybe? */
3636
3637
0
    rendering_params.black_point_comp = gsBLACKPTCOMP_ON;
3638
0
    rendering_params.graphics_type_tag = GS_UNKNOWN_TAG;
3639
0
    rendering_params.override_icc = false;
3640
0
    rendering_params.preserve_black = gsBLACKPRESERVE_OFF;
3641
0
    rendering_params.rendering_intent = gsRELATIVECOLORIMETRIC;
3642
0
    rendering_params.cmm = gsCMM_DEFAULT;
3643
0
    *link = gsicc_alloc_link_dev(dev->memory,
3644
0
                                 profile_struct->device_profile[GS_DEFAULT_DEVICE_PROFILE],
3645
0
                                 icc_profile,
3646
0
                                 &rendering_params);
3647
0
    if (*link == NULL)
3648
0
        return_error(gs_error_VMerror);
3649
3650
    /* If it is identity, release it now and set link to NULL */
3651
0
    if ((*link)->is_identity) {
3652
0
        gsicc_free_link_dev(*link);
3653
0
        *link = NULL;
3654
0
    }
3655
0
    return 0;
3656
0
}