Coverage Report

Created: 2025-06-10 06:56

/src/ghostpdl/base/gsht1.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* Extended halftone operators for Ghostscript library */
18
#include "memory_.h"
19
#include "string_.h"
20
#include "gx.h"
21
#include "gserrors.h"
22
#include "gsstruct.h"
23
#include "gsutil.h"   /* for gs_next_ids */
24
#include "gzstate.h"
25
#include "gxdevice.h"   /* for gzht.h */
26
#include "gzht.h"
27
28
29
/* Imports from gscolor.c */
30
void load_transfer_map(gs_gstate *, gx_transfer_map *, double);
31
32
/* Forward declarations */
33
static int process_spot(gx_ht_order *, gs_gstate *,
34
                         gs_spot_halftone *, gs_memory_t *);
35
static int process_threshold(gx_ht_order *, gs_gstate *,
36
                              gs_threshold_halftone *, gs_memory_t *);
37
static int process_threshold2(gx_ht_order *, gs_gstate *,
38
                               gs_threshold2_halftone *, gs_memory_t *);
39
static int process_client_order(gx_ht_order *, gs_gstate *,
40
                                 gs_client_order_halftone *, gs_memory_t *);
41
42
/* Structure types */
43
public_st_halftone_component();
44
public_st_ht_component_element();
45
46
/* GC procedures */
47
48
static
49
0
ENUM_PTRS_WITH(halftone_component_enum_ptrs, gs_halftone_component *hptr) return 0;
50
0
case 0:
51
0
switch (hptr->type)
52
0
{
53
0
    case ht_type_spot:
54
0
ENUM_RETURN((hptr->params.spot.transfer == 0 ?
55
0
             hptr->params.spot.transfer_closure.data :
56
0
             0));
57
0
    case ht_type_threshold:
58
0
ENUM_RETURN_CONST_STRING_PTR(gs_halftone_component,
59
0
                             params.threshold.thresholds);
60
0
    case ht_type_threshold2:
61
0
return ENUM_CONST_BYTESTRING(&hptr->params.threshold2.thresholds);
62
0
    case ht_type_client_order:
63
0
ENUM_RETURN(hptr->params.client_order.client_data);
64
0
    default:      /* not possible */
65
0
return 0;
66
0
}
67
0
case 1:
68
0
switch (hptr->type) {
69
0
    case ht_type_threshold:
70
0
        ENUM_RETURN((hptr->params.threshold.transfer == 0 ?
71
0
                     hptr->params.threshold.transfer_closure.data :
72
0
                     0));
73
0
    case ht_type_threshold2:
74
0
        ENUM_RETURN(hptr->params.threshold2.transfer_closure.data);
75
0
    case ht_type_client_order:
76
0
        ENUM_RETURN(hptr->params.client_order.transfer_closure.data);
77
0
    default:
78
0
        return 0;
79
0
}
80
0
ENUM_PTRS_END
81
0
static RELOC_PTRS_WITH(halftone_component_reloc_ptrs, gs_halftone_component *hptr)
82
0
{
83
0
    switch (hptr->type) {
84
0
        case ht_type_spot:
85
0
            if (hptr->params.spot.transfer == 0)
86
0
                RELOC_VAR(hptr->params.spot.transfer_closure.data);
87
0
            break;
88
0
        case ht_type_threshold:
89
0
            RELOC_CONST_STRING_VAR(hptr->params.threshold.thresholds);
90
0
            if (hptr->params.threshold.transfer == 0)
91
0
                RELOC_VAR(hptr->params.threshold.transfer_closure.data);
92
0
            break;
93
0
        case ht_type_threshold2:
94
0
            RELOC_CONST_BYTESTRING_VAR(hptr->params.threshold2.thresholds);
95
0
            RELOC_OBJ_VAR(hptr->params.threshold2.transfer_closure.data);
96
0
            break;
97
0
        case ht_type_client_order:
98
0
            RELOC_VAR(hptr->params.client_order.client_data);
99
0
            RELOC_VAR(hptr->params.client_order.transfer_closure.data);
100
0
            break;
101
0
        default:
102
0
            break;
103
0
    }
104
0
}
105
0
RELOC_PTRS_END
106
107
/* setcolorscreen */
108
int
109
gs_setcolorscreen(gs_gstate * pgs, gs_colorscreen_halftone * pht)
110
0
{
111
0
    gs_halftone ht;
112
113
0
    ht.type = ht_type_colorscreen;
114
0
    ht.params.colorscreen = *pht;
115
0
    return gs_sethalftone(pgs, &ht);
116
0
}
117
118
/* currentcolorscreen */
119
int
120
gs_currentcolorscreen(gs_gstate * pgs, gs_colorscreen_halftone * pht)
121
0
{
122
0
    int code;
123
124
0
    switch (pgs->halftone->type) {
125
0
        case ht_type_colorscreen:
126
0
            *pht = pgs->halftone->params.colorscreen;
127
0
            return 0;
128
0
        default:
129
0
            code = gs_currentscreen(pgs, &pht->screens.colored.gray);
130
0
            if (code < 0)
131
0
                return code;
132
0
            pht->screens.colored.red = pht->screens.colored.gray;
133
0
            pht->screens.colored.green = pht->screens.colored.gray;
134
0
            pht->screens.colored.blue = pht->screens.colored.gray;
135
0
            return 0;
136
0
    }
137
0
}
138
139
/* Set the halftone in the graphics state. */
140
int
141
gs_sethalftone(gs_gstate * pgs, gs_halftone * pht)
142
0
{
143
0
    gs_halftone ht;
144
145
0
    ht = *pht;
146
0
    ht.rc.memory = pgs->memory;
147
0
    return gs_sethalftone_allocated(pgs, &ht);
148
0
}
149
int
150
gs_sethalftone_allocated(gs_gstate * pgs, gs_halftone * pht)
151
0
{
152
0
    gx_device_halftone dev_ht;
153
0
    int code = gs_sethalftone_prepare(pgs, pht, &dev_ht);
154
155
0
    if (code < 0)
156
0
        return code;
157
0
    dev_ht.rc.memory = pht->rc.memory;
158
0
    if ((code = gx_ht_install(pgs, pht, &dev_ht)) < 0)
159
0
        gx_device_halftone_release(&dev_ht, pht->rc.memory);
160
0
    return code;
161
0
}
162
163
/* Prepare the halftone, but don't install it. */
164
int
165
gs_sethalftone_prepare(gs_gstate * pgs, gs_halftone * pht,
166
                       gx_device_halftone * pdht)
167
55.7k
{
168
55.7k
    gs_memory_t *mem = pht->rc.memory;
169
55.7k
    gx_ht_order_component *pocs = 0;
170
55.7k
    int code = 0;
171
172
55.7k
    if (pht->objtype >= HT_OBJTYPE_COUNT)
173
0
        return_error(gs_error_limitcheck);
174
55.7k
    switch (pht->type) {
175
55.7k
        case ht_type_colorscreen:
176
55.7k
            {
177
55.7k
                gs_screen_halftone *phc =
178
55.7k
                    pht->params.colorscreen.screens.indexed;
179
55.7k
                static const int cindex[4] = {3, 0, 1, 2};
180
55.7k
                static const char * color_names[4] = {"Gray", "Red", "Green", "Blue"};
181
55.7k
                int i;
182
183
55.7k
                pocs = gs_alloc_struct_array(mem, 4,
184
55.7k
                                             gx_ht_order_component,
185
55.7k
                                             &st_ht_order_component_element,
186
55.7k
                                             "gs_sethalftone");
187
55.7k
                if (pocs == 0)
188
0
                    return_error(gs_error_VMerror);
189
278k
                for (i = 0; i < 4; i++) {
190
222k
                    gs_screen_enum senum;
191
222k
                    int ci = cindex[i];
192
222k
                    gx_ht_order_component *poc = &pocs[i];
193
194
222k
                    code = gx_ht_process_screen_memory(&senum, pgs, &phc[ci],
195
222k
                                        gs_currentaccuratescreens(mem), mem);
196
222k
                    if (code < 0)
197
0
                        break;
198
222k
                    poc->corder = senum.order;
199
222k
                    poc->comp_number = gs_color_name_component_number(pgs->device,
200
222k
                                color_names[i], strlen(color_names[i]), pht->type);
201
222k
                    poc->cname = 0;  /* name index values are not known (or needed) */
202
222k
                    if (i == 0)  /* Gray = Default */
203
55.7k
                        pdht->order = poc->corder; /* Save default value */
204
222k
                }
205
55.7k
                if (code < 0)
206
0
                    break;
207
55.7k
                pdht->components = pocs;
208
55.7k
                pdht->num_comp = 4;
209
55.7k
            }
210
0
            break;
211
0
        case ht_type_spot:
212
0
            code = process_spot(&pdht->order, pgs, &pht->params.spot, mem);
213
0
            if (code < 0)
214
0
                return code;
215
0
            pdht->components = 0;
216
0
            break;
217
0
        case ht_type_threshold:
218
0
            code = process_threshold(&pdht->order, pgs,
219
0
                                     &pht->params.threshold, mem);
220
0
            if (code < 0)
221
0
                return code;
222
0
            pdht->components = 0;
223
0
            break;
224
0
        case ht_type_threshold2:
225
0
            code = process_threshold2(&pdht->order, pgs,
226
0
                                      &pht->params.threshold2, mem);
227
0
            if (code < 0)
228
0
                return code;
229
0
            pdht->components = 0;
230
0
            break;
231
0
        case ht_type_client_order:
232
0
            code = process_client_order(&pdht->order, pgs,
233
0
                                        &pht->params.client_order, mem);
234
0
            if (code < 0)
235
0
                return code;
236
0
            pdht->components = 0;
237
0
            break;
238
0
        case ht_type_multiple:
239
0
        case ht_type_multiple_colorscreen:
240
0
            {
241
0
                uint count = pht->params.multiple.num_comp;
242
0
                bool have_Default = false;
243
0
                uint i;
244
0
                gs_halftone_component *phc = pht->params.multiple.components;
245
0
                gx_ht_order_component *poc_next;
246
247
0
                pocs = gs_alloc_struct_array(mem, count,
248
0
                                             gx_ht_order_component,
249
0
                                             &st_ht_order_component_element,
250
0
                                             "gs_sethalftone");
251
0
                if (pocs == 0)
252
0
                    return_error(gs_error_VMerror);
253
0
                poc_next = pocs + 1;
254
0
                for (i = 0; i < count; i++, phc++) {
255
0
                    gx_ht_order_component *poc;
256
257
0
                    if (gs_debug['h']) {
258
0
                         int i;
259
0
                         byte* pname;
260
0
                         uint name_size;
261
262
0
                         pht->params.multiple.get_colorname_string(pgs, phc->cname, &pname, &name_size);
263
0
                         dmprintf(mem, "Colorant: ");
264
0
                         for (i = 0; i < name_size; i++)
265
0
                             dmprintf1(mem, "%c", pname[i]);
266
0
                         dmprintf(mem, "\n");
267
0
                    }
268
0
                    if (phc->comp_number == GX_DEVICE_COLOR_MAX_COMPONENTS) {
269
0
                        if (have_Default) {
270
                            /* Duplicate Default */
271
0
                            code = gs_note_error(gs_error_rangecheck);
272
0
                            break;
273
0
                        }
274
0
                        poc = pocs;
275
0
                        have_Default = true;
276
0
                    } else if (i == count - 1 && !have_Default) {
277
                        /* No Default */
278
0
                        code = gs_note_error(gs_error_rangecheck);
279
0
                        break;
280
0
                    } else
281
0
                        poc = poc_next++;
282
283
0
                    poc->comp_number = phc->comp_number;
284
0
                    poc->cname = phc->cname;
285
0
                    switch (phc->type) {
286
0
                        case ht_type_spot:
287
0
                            code = process_spot(&poc->corder, pgs,
288
0
                                                &phc->params.spot, mem);
289
0
                            break;
290
0
                        case ht_type_threshold:
291
0
                            code = process_threshold(&poc->corder, pgs,
292
0
                                                &phc->params.threshold, mem);
293
0
                            break;
294
0
                        case ht_type_threshold2:
295
0
                            code = process_threshold2(&poc->corder, pgs,
296
0
                                                &phc->params.threshold2, mem);
297
0
                            break;
298
0
                        case ht_type_client_order:
299
0
                            code = process_client_order(&poc->corder, pgs,
300
0
                                            &phc->params.client_order, mem);
301
0
                            break;
302
0
                        default:
303
0
                            code = gs_note_error(gs_error_rangecheck);
304
0
                            break;
305
0
                    }
306
0
                    if (code < 0)
307
0
                        break;
308
0
                }
309
0
                if (code < 0)
310
0
                    break;
311
0
                pdht->order = pocs[0].corder; /* Default */
312
0
                if (count == 1) {
313
                    /* We have only a Default; */
314
                    /* we don't need components. */
315
0
                    gs_free_object(mem, pocs, "gs_sethalftone");
316
0
                    pdht->components = 0;
317
0
                    pdht->num_comp = 0;
318
0
                } else {
319
0
                    pdht->components = pocs;
320
0
                    pdht->num_comp = count;
321
0
                }
322
0
            }
323
0
            break;
324
0
        default:
325
0
            return_error(gs_error_rangecheck);
326
55.7k
    }
327
55.7k
    if (code < 0)
328
0
        gs_free_object(mem, pocs, "gs_sethalftone");
329
55.7k
    return code;
330
55.7k
}
331
332
/* ------ Internal routines ------ */
333
334
/* Process a transfer function override, if any. */
335
static int
336
process_transfer(gx_ht_order * porder, gs_gstate * pgs,
337
                 gs_mapping_proc proc, gs_mapping_closure_t * pmc,
338
                 gs_memory_t * mem)
339
0
{
340
0
    gx_transfer_map *pmap;
341
342
0
    if (proc == 0 && pmc->proc == 0)
343
0
        return 0;
344
    /*
345
     * The transfer funtion is referenced by the order, so start the
346
     * reference count at 1.
347
     */
348
0
    rc_alloc_struct_1(pmap, gx_transfer_map, &st_transfer_map, mem,
349
0
                      return_error(gs_error_VMerror),
350
0
                      "process_transfer");
351
0
    pmap->proc = proc;    /* 0 => use closure */
352
0
    pmap->closure = *pmc;
353
0
    pmap->id = gs_next_ids(mem, 1);
354
0
    memset(pmap->values, 0x00, 256 * sizeof(frac));
355
0
    porder->transfer = pmap;
356
0
    if (proc == gs_mapped_transfer)
357
0
        return 0; /* nothing to load, the source is uninitialzed */
358
0
    load_transfer_map(pgs, pmap, 0.0);
359
0
    return 0;
360
0
}
361
362
/* Process a spot plane. */
363
static int
364
process_spot(gx_ht_order * porder, gs_gstate * pgs,
365
             gs_spot_halftone * phsp, gs_memory_t * mem)
366
0
{
367
0
    gs_screen_enum senum;
368
369
0
    int code = gx_ht_process_screen_memory(&senum, pgs, &phsp->screen,
370
0
                                           phsp->accurate_screens, mem);
371
372
0
    if (code < 0)
373
0
        return code;
374
0
    *porder = senum.order;
375
0
    return process_transfer(porder, pgs, phsp->transfer,
376
0
                            &phsp->transfer_closure, mem);
377
0
}
378
379
/* Construct the halftone order from a threshold array. */
380
void
381
gx_ht_complete_threshold_order(gx_ht_order * porder)
382
0
{
383
0
    int num_levels = porder->num_levels;
384
0
    uint *levels = porder->levels;
385
0
    uint size = porder->num_bits;
386
0
    gx_ht_bit *bits = porder->bit_data;
387
0
    uint i, j;
388
389
    /* The caller has set bits[i] = max(1, thresholds[i]). */
390
0
    gx_sort_ht_order(bits, size);
391
    /* We want to set levels[j] to the lowest value of i */
392
    /* such that bits[i].mask > j. */
393
0
    for (i = 0, j = 0; i < size; i++) {
394
0
        if (bits[i].mask != j) {
395
0
            if_debug3('h', "[h]levels[%u..%u] = %u\n",
396
0
                      j, (uint) bits[i].mask, i);
397
0
            while (j < bits[i].mask)
398
0
                levels[j++] = i;
399
0
        }
400
0
    }
401
0
    while (j < num_levels)
402
0
        levels[j++] = size;
403
0
    gx_ht_construct_bits(porder);
404
0
}
405
int
406
gx_ht_construct_threshold_order(gx_ht_order * porder, const byte * thresholds)
407
0
{
408
0
    return porder->procs->construct_order(porder, thresholds);
409
0
}
410
411
/* Process a threshold plane. */
412
static int
413
process_threshold(gx_ht_order * porder, gs_gstate * pgs,
414
                  gs_threshold_halftone * phtp, gs_memory_t * mem)
415
0
{
416
0
    int code;
417
418
0
    porder->params.M = phtp->width, porder->params.N = 0;
419
0
    porder->params.R = 1;
420
0
    porder->params.M1 = phtp->height, porder->params.N1 = 0;
421
0
    porder->params.R1 = 1;
422
0
    code = gx_ht_alloc_threshold_order(porder, phtp->width, phtp->height,
423
0
                                       256, mem);
424
0
    if (code < 0)
425
0
        return code;
426
0
    gx_ht_construct_threshold_order(porder, phtp->thresholds.data);
427
0
    return process_transfer(porder, pgs, phtp->transfer,
428
0
                            &phtp->transfer_closure, mem);
429
0
}
430
431
/* Process an extended threshold plane. */
432
static int
433
process_threshold2(gx_ht_order * porder, gs_gstate * pgs,
434
                   gs_threshold2_halftone * phtp, gs_memory_t * mem)
435
0
{
436
0
    int code;
437
    /*
438
     * There are potentially 64K different levels for this plane, but this
439
     * is more than we're willing to handle.  Try to reduce the number of
440
     * levels by dropping leading or trailing zero bits from the thresholds;
441
     * as a last resort, drop (possibly significant) trailing bits.
442
     */
443
0
#define LOG2_MAX_HT_LEVELS 14
444
0
#define MAX_HT_LEVELS (1 << LOG2_MAX_HT_LEVELS)
445
0
    int bps = phtp->bytes_per_sample;
446
0
    const byte *data = phtp->thresholds.data;
447
0
    const int w1 = phtp->width, h1 = phtp->height, size1 = w1 * h1;
448
0
    const int w2 = phtp->width2, h2 = phtp->height2, size2 = w2 * h2;
449
0
    const uint size = size1 + size2;
450
0
    const int d = (h2 == 0 ? h1 : igcd(h1, h2));
451
0
    const int sod = size / d;
452
0
    uint num_levels;
453
0
    uint i;
454
0
    int rshift = 0;
455
0
    int shift;
456
457
0
    {
458
0
        uint mask = 0, max_thr = 0;
459
460
0
        for (i = 0; i < size; ++i) {
461
0
            uint thr =
462
0
                (bps == 1 ? data[i] : (data[i * 2] << 8) + data[i * 2 + 1]);
463
464
0
            mask |= thr;
465
0
            max_thr = max(max_thr, thr);
466
0
        }
467
0
        if (mask == 0)
468
0
            mask = 1, max_thr = 1;
469
0
        while (!(mask & 1) || max_thr > MAX_HT_LEVELS)
470
0
            mask >>= 1, max_thr >>= 1, rshift++;
471
0
        num_levels = max_thr + 1;
472
0
    }
473
    /*
474
     * Set nominal values for the params, and don't bother to call
475
     * gx_compute_cell_values -- the values are only needed for spot
476
     * halftones.
477
     */
478
0
    porder->params.M = sod, porder->params.N = d;
479
0
    porder->params.R = 1;
480
0
    porder->params.M1 = d, porder->params.N1 = sod;
481
0
    porder->params.R1 = 1;
482
    /*
483
     * Determine the shift between strips.  We don't know a closed formula
484
     * for this, so we do it by enumeration.
485
     */
486
0
    shift = 0;
487
0
    {
488
0
        int x = 0, y = 0;
489
490
0
        do {
491
0
            if (y < h1)
492
0
                x += w1, y += h2;
493
0
            else
494
0
                x += w2, y -= h1;
495
0
        } while (y > d);
496
0
        if (y)
497
0
            shift = x;
498
0
    }
499
0
    code = gx_ht_alloc_ht_order(porder, sod, d, num_levels, size, shift,
500
0
                                &ht_order_procs_default, mem);
501
0
    if (code < 0)
502
0
        return code;
503
0
    {
504
0
        gx_ht_bit *bits = (gx_ht_bit *)porder->bit_data;
505
0
        int row, di;
506
507
0
        if_debug7m('h', mem, "[h]rect1=(%d,%d), rect2=(%d,%d), strip=(%d,%d), shift=%d\n",
508
0
                   w1, h1, w2, h2, sod, d, shift);
509
0
        for (row = 0, di = 0; row < d; ++row) {
510
            /* Iterate over destination rows. */
511
0
            int dx, sy = row; /* sy = row mod d */
512
0
            int w;
513
514
0
            for (dx = 0; dx < sod; dx += w) {
515
                /* Iterate within a destination row, over source rows. */
516
0
                int si, j;
517
518
0
                if (sy < h1) {
519
                    /* Copy a row from rect1. */
520
0
                    si = sy * w1;
521
0
                    w = w1;
522
0
                    sy += h2;
523
0
                } else {
524
                    /* Copy a row from rect2. */
525
0
                    si = size1 + (sy - h1) * w2;
526
0
                    w = w2;
527
0
                    sy -= h1;
528
0
                }
529
0
                for (j = 0; j < w; ++j, ++si, ++di) {
530
0
                    uint thr =
531
0
                        (bps == 1 ? data[si] :
532
0
                         (data[si * 2] << 8) + data[si * 2 + 1])
533
0
                                       >> rshift;
534
535
0
                    if_debug3('H', "[H]sy=%d, si=%d, di=%d\n", sy, si, di);
536
0
                    bits[di].mask = max(thr, 1);
537
0
                }
538
0
            }
539
0
        }
540
0
    }
541
0
    gx_ht_complete_threshold_order(porder);
542
0
    return process_transfer(porder, pgs, phtp->transfer, &phtp->transfer_closure, mem);
543
0
#undef LOG2_MAX_HT_LEVELS
544
0
#undef MAX_HT_LEVELS
545
0
}
546
547
/* Process a client-order plane. */
548
static int
549
process_client_order(gx_ht_order * porder, gs_gstate * pgs,
550
                     gs_client_order_halftone * phcop, gs_memory_t * mem)
551
0
{
552
0
    int code = (*phcop->procs->create_order) (porder, pgs, phcop, mem);
553
554
0
    if (code < 0)
555
0
        return code;
556
0
    return process_transfer(porder, pgs, NULL,
557
0
                            &phcop->transfer_closure, mem);
558
0
}