Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/psi/zht2.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
/* Level 2 sethalftone operator */
18
#include "memory_.h"
19
#include "ghost.h"
20
#include "oper.h"
21
#include "gsstruct.h"
22
#include "gxdevice.h"   /* for gzht.h */
23
#include "gzht.h"
24
#include "estack.h"
25
#include "ialloc.h"
26
#include "iddict.h"
27
#include "idparam.h"
28
#include "igstate.h"
29
#include "icolor.h"
30
#include "iht.h"
31
#include "store.h"
32
#include "iname.h"
33
#include "zht2.h"
34
#include "gxgstate.h"
35
#include "gen_ordered.h"
36
#include "gp.h"
37
38
/* Forward references */
39
static int dict_spot_params(const ref *, gs_spot_halftone *, ref *, ref *,
40
                            gs_memory_t *);
41
static int dict_spot_results(i_ctx_t *, ref *, const gs_spot_halftone *);
42
static int dict_threshold_params(const ref *, gs_threshold_halftone *,
43
                                  ref *);
44
static int dict_threshold2_params(const ref *, gs_threshold2_halftone *,
45
                                   ref *, gs_memory_t *);
46
47
/*
48
 * This routine translates a gs_separation_name value into a character string
49
 * pointer and a string length.
50
 */
51
int
52
gs_get_colorname_string(gs_gstate *pgs, gs_separation_name colorname_index,
53
                        unsigned char **ppstr, unsigned int *pname_size)
54
0
{
55
0
    ref nref;
56
57
0
    name_index_ref(pgs->memory, colorname_index, &nref);
58
0
    name_string_ref(pgs->memory, &nref, &nref);
59
0
    return obj_string_data(pgs->memory, &nref, (const unsigned char**) ppstr, pname_size);
60
0
}
61
62
/* Dummy spot function */
63
static float
64
spot1_dummy(double x, double y)
65
0
{
66
0
    return (x + y) / 2;
67
0
}
68
69
static int
70
ht_object_type_from_name(gs_ref_memory_t *mem, ref *pname, gs_HT_objtype_t *HTobjtype)
71
1
{
72
1
    ref sref;
73
74
1
    *HTobjtype = HT_OBJTYPE_DEFAULT;
75
1
    name_string_ref(mem, pname, &sref);
76
1
    if (r_size(&sref) <= 1)
77
0
        return_error(gs_error_undefined); /* PDF allows zero length strings, but it can't match */
78
79
1
    switch (sref.value.const_bytes[0]) {
80
0
  case 'D':
81
0
            if (r_size(&sref) == 7 && strncmp((const char *)sref.value.const_bytes, "Default", 7) == 0) {
82
0
                *HTobjtype = HT_OBJTYPE_DEFAULT;
83
0
    break;
84
0
            }
85
0
            return_error(gs_error_undefined);
86
0
  case 'V':
87
0
            if (r_size(&sref) == 6 && strncmp((const char *)sref.value.const_bytes, "Vector", 6) == 0) {
88
0
                *HTobjtype = HT_OBJTYPE_VECTOR;
89
0
    break;
90
0
            }
91
0
            return_error(gs_error_undefined);
92
0
  case 'I':
93
0
            if (r_size(&sref) == 5 && strncmp((const char *)sref.value.const_bytes, "Image", 5) == 0) {
94
0
                *HTobjtype = HT_OBJTYPE_IMAGE;
95
0
    break;
96
0
            }
97
0
            return_error(gs_error_undefined);
98
0
  case 'T':
99
0
            if (r_size(&sref) == 4 && strncmp((const char *)sref.value.const_bytes, "Text", 4) == 0) {
100
0
                *HTobjtype = HT_OBJTYPE_TEXT;
101
0
    break;
102
0
            }  /* falls through to default if no match */
103
1
        default:
104
1
            return_error(gs_error_undefined);
105
1
    }
106
0
    return 0;
107
1
}
108
109
/* <dict> <dict5> .sethalftone5 - */
110
static int sethalftone_finish(i_ctx_t *);
111
static int sethalftone_cleanup(i_ctx_t *);
112
static int
113
zsethalftone5(i_ctx_t *i_ctx_p)
114
0
{
115
0
    os_ptr op = osp;
116
0
    uint count;
117
0
    gs_halftone_component *phtc = 0;
118
0
    gs_halftone_component *pc;
119
0
    int code = 0;
120
0
    int j;
121
0
    bool have_default;
122
0
    gs_halftone *pht = 0;
123
0
    gx_device_halftone *pdht = 0;
124
0
    ref sprocs[GS_CLIENT_COLOR_MAX_COMPONENTS + 1];
125
0
    ref tprocs[GS_CLIENT_COLOR_MAX_COMPONENTS + 1];
126
0
    gs_memory_t *mem;
127
0
    uint edepth = ref_stack_count(&e_stack);
128
0
    int npop = 2;
129
0
    int dict_enum;
130
0
    ref rvalue[2];
131
0
    int cname, colorant_number;
132
0
    byte * pname;
133
0
    uint name_size;
134
0
    int halftonetype, type = 0;
135
0
    gs_HT_objtype_t objtype = HT_OBJTYPE_DEFAULT;
136
0
    ref *pdval;
137
0
    gs_gstate *pgs = igs;
138
0
    int space_index;
139
140
0
    if (ref_stack_count(&o_stack) < 2)
141
0
        return_error(gs_error_stackunderflow);
142
0
    check_type(*op, t_dictionary);
143
0
    check_type(*(op - 1), t_dictionary);
144
145
0
    dict_enum = dict_first(op);
146
0
    space_index = r_space_index(op - 1);
147
148
0
    mem = (gs_memory_t *) idmemory->spaces_indexed[space_index];
149
150
0
    check_type(*op, t_dictionary);
151
0
    check_dict_read(*op);
152
0
    check_type(op[-1], t_dictionary);
153
0
    check_dict_read(op[-1]);
154
155
    /*
156
     * We think that Type 2 and Type 4 halftones, like
157
     * screens set by setcolorscreen, adapt automatically to
158
     * the device color space, so we need to mark them
159
     * with a different internal halftone type.
160
     */
161
0
    code = dict_int_param(op - 1, "HalftoneType", 1, 100, 0, &type);
162
0
    if (code < 0)
163
0
          return code;
164
0
    halftonetype = (type == 2 || type == 4)
165
0
                        ? ht_type_multiple_colorscreen
166
0
                        : ht_type_multiple;
167
168
    /* Check if this dict has the optional ObjectType parameter */
169
0
    if (dict_find_string(op - 1, "ObjectType", &pdval) > 0 &&
170
0
        r_has_type(pdval, t_name)) {
171
0
        if ((code = ht_object_type_from_name(iimemory, pdval, &objtype)) < 0)
172
0
            return code;
173
0
    }
174
175
    /* Count how many components that we will actually use. */
176
177
0
    have_default = false;
178
0
    for (count = 0; ;) {
179
180
        /* Move to next element in the dictionary */
181
0
        if ((dict_enum = dict_next(op, dict_enum, rvalue)) == -1)
182
0
            break;
183
        /*
184
         * Verify that we have a valid component.  We may have a
185
         * /HalfToneType entry.
186
         */
187
0
        if (!r_has_type(&rvalue[0], t_name))
188
0
            continue;
189
0
        if (!r_has_type(&rvalue[1], t_dictionary))
190
0
            continue;
191
192
        /* Get the name of the component  verify that we will use it. */
193
0
        cname = name_index(mem, &rvalue[0]);
194
0
        code = gs_get_colorname_string(pgs, cname, &pname, &name_size);
195
0
        if (code < 0)
196
0
            break;
197
0
        colorant_number = gs_cname_to_colorant_number(pgs, pname, name_size,
198
0
                                                halftonetype);
199
0
        if (colorant_number < 0)
200
0
            continue;
201
0
        else if (colorant_number == GX_DEVICE_COLOR_MAX_COMPONENTS) {
202
            /* If here then we have the "Default" component */
203
0
            if (have_default)
204
0
                return_error(gs_error_rangecheck);
205
0
            have_default = true;
206
0
        }
207
208
0
        count++;
209
        /*
210
         * Check to see if we have already reached the legal number of
211
         * components.
212
         */
213
0
        if (count > GS_CLIENT_COLOR_MAX_COMPONENTS + 1) {
214
0
            code = gs_note_error(gs_error_rangecheck);
215
0
            break;
216
0
        }
217
0
    }
218
0
    if (count == 0 || (halftonetype == ht_type_multiple && ! have_default))
219
0
        code = gs_note_error(gs_error_rangecheck);
220
221
0
    if (code >= 0) {
222
0
        check_estack(5);   /* for sampling Type 1 screens */
223
0
        refset_null(sprocs, count);
224
0
        refset_null(tprocs, count);
225
0
        rc_alloc_struct_0(pht, gs_halftone, &st_halftone,
226
0
                          imemory, pht = 0, ".sethalftone5");
227
0
        phtc = gs_alloc_struct_array(mem, count, gs_halftone_component,
228
0
                                     &st_ht_component_element,
229
0
                                     ".sethalftone5");
230
0
        rc_alloc_struct_0(pdht, gx_device_halftone, &st_device_halftone,
231
0
                          imemory, pdht = 0, ".sethalftone5");
232
0
        if (pht == 0 || phtc == 0 || pdht == 0) {
233
0
            j = 0; /* Quiet the compiler:
234
                      gs_note_error isn't necessarily identity,
235
                      so j could be left ununitialized. */
236
0
            code = gs_note_error(gs_error_VMerror);
237
0
        }
238
0
    }
239
0
    if (code >= 0) {
240
0
        dict_enum = dict_first(op);
241
0
        for (j = 0, pc = phtc; ;) {
242
0
            int type;
243
244
            /* Move to next element in the dictionary */
245
0
            if ((dict_enum = dict_next(op, dict_enum, rvalue)) == -1)
246
0
                break;
247
            /*
248
             * Verify that we have a valid component.  We may have a
249
             * /HalfToneType entry.
250
             */
251
0
            if (!r_has_type(&rvalue[0], t_name))
252
0
                continue;
253
0
            if (!r_has_type(&rvalue[1], t_dictionary))
254
0
                continue;
255
256
            /* Get the name of the component */
257
0
            cname = name_index(mem, &rvalue[0]);
258
0
            code = gs_get_colorname_string(pgs, cname, &pname, &name_size);
259
0
            if (code < 0)
260
0
                break;
261
0
            colorant_number = gs_cname_to_colorant_number(pgs, pname, name_size,
262
0
                                                halftonetype);
263
0
            if (colorant_number < 0)
264
0
                continue;   /* Do not use this component */
265
0
            pc->cname = cname;
266
0
            pc->comp_number = colorant_number;
267
268
            /* Now process the component dictionary */
269
0
            check_dict_read(rvalue[1]);
270
0
            if (dict_int_param(&rvalue[1], "HalftoneType", 1, 7, 0, &type) < 0) {
271
0
                code = gs_note_error(gs_error_typecheck);
272
0
                break;
273
0
            }
274
0
            switch (type) {
275
0
                default:
276
0
                    code = gs_note_error(gs_error_rangecheck);
277
0
                    break;
278
0
                case 1:
279
0
                    code = dict_spot_params(&rvalue[1], &pc->params.spot,
280
0
                                                sprocs + j, tprocs + j, mem);
281
0
                    pc->params.spot.screen.spot_function = spot1_dummy;
282
0
                    pc->type = ht_type_spot;
283
0
                    break;
284
0
                case 3:
285
0
                    code = dict_threshold_params(&rvalue[1], &pc->params.threshold,
286
0
                                                        tprocs + j);
287
0
                    pc->type = ht_type_threshold;
288
0
                    break;
289
0
                case 7:
290
0
                    code = dict_threshold2_params(&rvalue[1], &pc->params.threshold2,
291
0
                                                        tprocs + j, imemory);
292
0
                    pc->type = ht_type_threshold2;
293
0
                    break;
294
0
            }
295
0
            if (code < 0)
296
0
                break;
297
0
            pc++;
298
0
            j++;
299
0
        }
300
0
    }
301
0
    if (code >= 0) {
302
0
        pht->type = halftonetype;
303
0
        pht->objtype = objtype;
304
0
        pht->params.multiple.components = phtc;
305
0
        pht->params.multiple.num_comp = j;
306
0
        pht->params.multiple.get_colorname_string = gs_get_colorname_string;
307
0
        code = gs_sethalftone_prepare(igs, pht, pdht);
308
0
    }
309
0
    if (code >= 0) {
310
        /*
311
         * Put the actual frequency and angle in the spot function component dictionaries.
312
         */
313
0
        dict_enum = dict_first(op);
314
0
        for (pc = phtc; ; ) {
315
            /* Move to next element in the dictionary */
316
0
            if ((dict_enum = dict_next(op, dict_enum, rvalue)) == -1)
317
0
                break;
318
319
            /* Verify that we have a valid component */
320
0
            if (!r_has_type(&rvalue[0], t_name))
321
0
                continue;
322
0
            if (!r_has_type(&rvalue[1], t_dictionary))
323
0
                continue;
324
325
            /* Get the name of the component and verify that we will use it. */
326
0
            cname = name_index(mem, &rvalue[0]);
327
0
            code = gs_get_colorname_string(pgs, cname, &pname, &name_size);
328
0
            if (code < 0)
329
0
                break;
330
0
            colorant_number = gs_cname_to_colorant_number(pgs, pname, name_size,
331
0
                                                halftonetype);
332
0
            if (colorant_number < 0)
333
0
                continue;
334
335
0
            if (pc->type == ht_type_spot) {
336
0
                code = dict_spot_results(i_ctx_p, &rvalue[1], &pc->params.spot);
337
0
                if (code < 0)
338
0
                    break;
339
0
            }
340
0
            pc++;
341
0
        }
342
0
    }
343
0
    if (code >= 0) {
344
        /*
345
         * Schedule the sampling of any Type 1 screens,
346
         * and any (Type 1 or Type 3) TransferFunctions.
347
         * Save the stack depths in case we have to back out.
348
         */
349
0
        uint odepth = ref_stack_count(&o_stack);
350
0
        ref odict, odict5;
351
352
0
        odict = op[-1];
353
0
        odict5 = *op;
354
0
        ref_stack_pop(&o_stack, 2);
355
0
        op = osp;
356
0
        esp += 5;
357
0
        make_mark_estack(esp - 4, es_other, sethalftone_cleanup);
358
0
        esp[-3] = odict;
359
0
        make_istruct(esp - 2, 0, pht);
360
0
        make_istruct(esp - 1, 0, pdht);
361
0
        make_op_estack(esp, sethalftone_finish);
362
0
        for (j = 0; j < count; j++) {
363
0
            gx_ht_order *porder = NULL;
364
365
0
            if (pdht->components == 0)
366
0
                porder = &pdht->order;
367
0
            else {
368
                /* Find the component in pdht that matches component j in
369
                   the pht; gs_sethalftone_prepare() may permute these. */
370
0
                int k;
371
0
                int comp_number = phtc[j].comp_number;
372
0
                for (k = 0; k < count; k++) {
373
0
                    if (pdht->components[k].comp_number == comp_number) {
374
0
                        porder = &pdht->components[k].corder;
375
0
                        break;
376
0
                    }
377
0
                }
378
0
            }
379
0
            switch (phtc[j].type) {
380
0
            case ht_type_spot:
381
0
                code = zscreen_enum_init(i_ctx_p, porder,
382
0
                                         &phtc[j].params.spot.screen,
383
0
                                         &sprocs[j], 0, 0, space_index);
384
0
                if (code < 0)
385
0
                    break;
386
                /* falls through */
387
0
            case ht_type_threshold:
388
0
            case ht_type_threshold2:
389
0
                if (!r_has_type(tprocs + j, t__invalid)) {
390
                    /* Schedule TransferFunction sampling. */
391
                    /****** check_xstack IS WRONG ******/
392
0
                    check_ostack(zcolor_remap_one_ostack);
393
0
                    check_estack(zcolor_remap_one_estack);
394
0
                    code = zcolor_remap_one(i_ctx_p, tprocs + j,
395
0
                                            porder->transfer, igs,
396
0
                                            zcolor_remap_one_finish);
397
0
                    op = osp;
398
0
                }
399
0
                break;
400
0
            default:  /* not possible here, but to keep */
401
                                /* the compilers happy.... */
402
0
                ;
403
0
            }
404
0
            if (code < 0) { /* Restore the stack. */
405
0
                ref_stack_pop_to(&o_stack, odepth);
406
0
                ref_stack_pop_to(&e_stack, edepth);
407
0
                op = osp;
408
0
                op[-1] = odict;
409
0
                *op = odict5;
410
0
                break;
411
0
            }
412
0
            npop = 0;
413
0
        }
414
0
    }
415
0
    if (code < 0) {
416
0
        gs_free_object(mem, pdht, ".sethalftone5");
417
0
        gs_free_object(mem, phtc, ".sethalftone5");
418
0
        gs_free_object(mem, pht, ".sethalftone5");
419
0
        return code;
420
0
    }
421
0
    pop(npop);
422
0
    return (ref_stack_count(&e_stack) > edepth ? o_push_estack : 0);
423
0
}
424
425
/* <dict> .genordered <string> */
426
/*         array will have: width height turn_on_sequence.x turn_on_sequence.y ...  */
427
/*         total array length is 2 + (2 * width * height)       */
428
static int
429
zgenordered(i_ctx_t *i_ctx_p)
430
12
{
431
12
    os_ptr op = osp;
432
12
    int i, code = 0;
433
12
    gs_memory_t *mem;
434
12
    int space_index;
435
12
    htsc_param_t params;
436
12
    int S;
437
12
    htsc_dig_grid_t final_mask;
438
12
    float tmp_float;
439
12
    gs_gstate *pgs = igs;
440
12
    gx_device *currdevice = pgs->device;
441
12
    output_format_type output_type = OUTPUT_PS;
442
12
    ref *out_type_name;
443
444
12
    if (ref_stack_count(&o_stack) < 1)
445
4
        return_error(gs_error_stackunderflow);
446
8
    check_type(*op, t_dictionary);
447
448
0
    space_index = r_space_index(op);   /* used to construct array that is returned */
449
0
    mem = (gs_memory_t *) idmemory->spaces_indexed[space_index];
450
451
0
    check_type(*op, t_dictionary);
452
0
    check_dict_read(*op);
453
454
0
    htsc_set_default_params(&params);
455
    /* Modify the default HResolution and VResolution to be the device HWResolution */
456
0
    params.horiz_dpi = currdevice->HWResolution[0];
457
0
    params.vert_dpi = currdevice->HWResolution[1];
458
0
    final_mask.memory = mem->non_gc_memory;
459
0
    final_mask.data = NULL;
460
461
0
    if ((code = dict_find_string(op, "OutputType", &out_type_name)) > 0) {
462
0
        ref namestr;
463
464
0
        if (!r_has_type(out_type_name, t_name))
465
0
            return gs_error_typecheck;
466
0
        name_string_ref(imemory, out_type_name, &namestr);
467
0
        if (r_size(&namestr) == 8 && !memcmp(namestr.value.bytes, "TOSArray", 8))
468
0
            output_type = OUTPUT_TOS;
469
0
        else if (r_size(&namestr) == 5 && !memcmp(namestr.value.bytes, "Type3", 5))
470
0
            output_type = OUTPUT_PS;
471
0
        else if (r_size(&namestr) == 12 && !memcmp(namestr.value.bytes, "ThreshString", 12))
472
0
            output_type = OUTPUT_RAW;
473
0
        else
474
0
            return gs_error_undefined;
475
0
    }
476
0
    if ((code = dict_int_param(op, "Angle", 0, 360, 0, &params.targ_scr_ang)) < 0)
477
0
        return gs_error_undefined;
478
0
    if ((code = dict_int_param(op, "Frequency", 1, 0x7fff, 75, &params.targ_lpi)) < 0)
479
0
        return gs_error_undefined;
480
0
    if ((code = dict_float_param(op, "HResolution", 300., &tmp_float)) < 0)
481
0
        return gs_error_undefined;
482
0
    if (code == 0)
483
0
        params.horiz_dpi = tmp_float;
484
0
    if ((code = dict_float_param(op, "VResolution", 300., &tmp_float)) < 0)
485
0
        return gs_error_undefined;
486
0
    if (code == 0)
487
0
        params.vert_dpi = tmp_float;
488
0
    if ((code = dict_int_param(op, "Levels", 1, 0x7fff, 256, &params.targ_quant)) < 0)
489
0
        return gs_error_undefined;
490
0
    if (code == 0)
491
0
        params.targ_quant_spec = true;
492
0
    if ((code = dict_int_param(op, "SuperCellSize", 1, 0x7fff, 1, &params.targ_size)) < 0)
493
0
        return gs_error_undefined;
494
0
    if (code == 0)
495
0
        params.targ_size_spec = true;
496
0
    if ((code = dict_int_param(op, "DotShape", 0, CUSTOM - 1, 0, (int *)(&params.spot_type))) < 0)
497
0
        return gs_error_undefined;
498
0
    if ((code = dict_bool_param(op, "Holladay", false, &params.holladay)) < 0)
499
0
        return gs_error_undefined;
500
501
0
    params.output_format = OUTPUT_TOS;    /* we want this format */
502
0
    code = htsc_gen_ordered(params, &S, &final_mask, mem);
503
504
#if FINAL_SCREEN_DUMP
505
    if (code >= 0) {
506
        code = htsc_save_screen(&final_mask, params.holladay, S, params, mem);
507
    }
508
#endif
509
510
0
    if (code < 0)
511
0
        goto done;
512
513
0
    switch (output_type) {
514
0
      case OUTPUT_TOS:
515
        /* Now return the mask info in an array [ width height turn_on.x turn_on.y ... ] */
516
0
        code = ialloc_ref_array((ref *)op, a_all, 2 + (2 * final_mask.width * final_mask.height), "gen_ordered");
517
0
        if (code < 0)
518
0
            goto done;
519
0
        make_int(&(op->value.refs[0]), final_mask.width);
520
0
        make_int(&(op->value.refs[1]), final_mask.height);
521
0
        for (i=0; i < 2 * final_mask.width * final_mask.height; i++)
522
0
            make_int(&(op->value.refs[i+2]), final_mask.data[i]);
523
0
        break;
524
0
      case OUTPUT_RAW:
525
0
      case OUTPUT_PS:
526
    /* Return a threshold array string first two bytes are width (high byte first),
527
     * next two bytes are height, followed by the threshold array (one byte per cell)
528
     * PostScript can easily form a Type 3 Halftone Thresholds string from this
529
     * using "getinterval".
530
     */
531
0
        {
532
            /* Make a threshold array from the turn_on_sequence */
533
0
            int level;
534
0
            int cur_pix = 0;
535
0
            int width = final_mask.width;
536
0
            int num_pix = width * final_mask.height;
537
0
            double delta_value = 1.0 / (double)(num_pix);
538
0
            double end_value, cur_value = 0.0;
539
0
            byte *thresh;
540
0
            ref rval, thresh_ref;
541
542
0
            code = gs_error_VMerror;  /* in case allocation of thresh fails */
543
0
            if (output_type == OUTPUT_RAW) {
544
0
                if ((thresh = ialloc_string(4 + num_pix, "gen_ordered"))  == 0)
545
0
                    goto done;
546
0
                *thresh++ = width >> 8;
547
0
                *thresh++ = width & 0xff;
548
0
                *thresh++ = final_mask.height >> 8;
549
0
                *thresh++ = final_mask.height & 0xff;
550
0
            } else if ((thresh = ialloc_string(num_pix, "gen_ordered"))  == 0)
551
0
                    goto done;
552
            /* The following is adapted from thresh_remap with the default linear map */
553
0
            for (level=0; level<256; level++) {
554
0
                end_value = (float)(1+level) / 255.;
555
0
                if (end_value > 255.0)
556
0
                    end_value = 255.0;   /* clamp in case of rounding errors */
557
0
                while (cur_value < (end_value - (delta_value * (1./256.))) ||
558
0
                       (cur_pix + 1) == (num_pix / 2) ) { /* force 50% gray level */
559
0
                    thresh[final_mask.data[2*cur_pix] + (width*final_mask.data[2*cur_pix+1])] = 255 - level;
560
0
                    cur_pix++;
561
0
                    if (cur_pix >= num_pix)
562
0
                        break;
563
0
                    cur_value += delta_value;
564
0
                }
565
0
                if (cur_pix >= num_pix)
566
0
                    break;
567
0
            }
568
            /* now fill any remaining cells */
569
0
            for (; cur_pix < num_pix; cur_pix++) {
570
0
                thresh[final_mask.data[2 * cur_pix] + (width*final_mask.data[2 * cur_pix + 1])] = 0;
571
0
            }
572
#if FINAL_SCREEN_DUMP
573
            {
574
                char file_name[FULL_FILE_NAME_LENGTH];
575
                gp_file *fid;
576
577
                snprintf(file_name, FULL_FILE_NAME_LENGTH, "Screen_%dx%d.raw", width, final_mask.height);
578
                fid = gp_fopen(mem, file_name, "wb");
579
                if (fid) {
580
                    gp_fwrite(thresh, sizeof(unsigned char), num_pix, fid);
581
                    gp_fclose(fid);
582
                }
583
            }
584
#endif
585
0
            if (output_type == OUTPUT_RAW) {
586
0
                make_string(&thresh_ref, a_all | icurrent_space, 4 + num_pix, thresh-4);
587
0
                *op = thresh_ref;
588
0
                code = 0;
589
0
            } else {
590
                /* output_type == OUTPUT_PS */
591
                /* Return a HalftoneType 3 dictionary */
592
0
                code = dict_create(4, op);
593
0
                if (code < 0)
594
0
                    goto done;
595
0
                make_string(&thresh_ref, a_all | icurrent_space, num_pix, thresh);
596
0
                if ((code = idict_put_string(op, "Thresholds", &thresh_ref)) < 0)
597
0
                    goto done;
598
0
                make_int(&rval, final_mask.width);
599
0
                if ((code = idict_put_string(op, "Width", &rval)) < 0)
600
0
                    goto done;
601
0
                make_int(&rval, final_mask.height);
602
0
                if ((code = idict_put_string(op, "Height", &rval)) < 0)
603
0
                    goto done;
604
0
                make_int(&rval, 3);
605
0
                if ((code = idict_put_string(op, "HalftoneType", &rval)) < 0)
606
0
                    goto done;
607
0
            }
608
0
        }
609
0
        break;
610
0
      default:
611
0
        return gs_error_undefined;
612
0
    }
613
614
0
done:
615
0
    if (final_mask.data != NULL)
616
0
        gs_free_object(mem->non_gc_memory, final_mask.data, ".genordered");
617
618
0
    return (code < 0 ? gs_error_undefined : 0);
619
0
}
620
621
/* Install the halftone after sampling. */
622
static int
623
sethalftone_finish(i_ctx_t *i_ctx_p)
624
0
{
625
0
    gx_device_halftone *pdht = r_ptr(esp, gx_device_halftone);
626
0
    int code;
627
628
0
    if (pdht->components)
629
0
        pdht->order = pdht->components[0].corder;
630
0
    code = gx_ht_install(igs, r_ptr(esp - 1, gs_halftone), pdht);
631
0
    if (code < 0) {
632
0
        esp -= 4;
633
0
        sethalftone_cleanup(i_ctx_p);
634
0
        return code;
635
0
    }
636
0
    istate->halftone = esp[-2];
637
0
    esp -= 4;
638
0
    sethalftone_cleanup(i_ctx_p);
639
0
    return o_pop_estack;
640
0
}
641
/* Clean up after installing the halftone. */
642
static int
643
sethalftone_cleanup(i_ctx_t *i_ctx_p)
644
0
{
645
0
    gx_device_halftone *pdht = r_ptr(&esp[4], gx_device_halftone);
646
0
    gs_halftone *pht = r_ptr(&esp[3], gs_halftone);
647
648
0
    gs_free_object(pdht->rc.memory, pdht,
649
0
                   "sethalftone_cleanup(device halftone)");
650
0
    gs_free_object(pht->rc.memory, pht,
651
0
                   "sethalftone_cleanup(halftone)");
652
    /* See bug #707007, explicitly freed structures on the stacks need to be made NULL */
653
0
    make_null(&esp[4]);
654
0
    make_null(&esp[3]);
655
0
    return 0;
656
0
}
657
658
static int
659
zsetobjtypeHT(i_ctx_t *i_ctx_p)   /* <name> .setobjtypeHT - */
660
                                        /* name is one of /Vector, /Image, or /Text */
661
11
{
662
11
    os_ptr op = osp;
663
11
    int code = 0;
664
11
    gs_HT_objtype_t HTobjtype = HT_OBJTYPE_DEFAULT;
665
666
11
    if (ref_stack_count(&o_stack) < 1)
667
3
        return_error(gs_error_stackunderflow);
668
8
    check_type(*op, t_name);
669
670
1
    if ((code = ht_object_type_from_name(iimemory, op, &HTobjtype)) < 0)
671
1
        return code;
672
673
    /* If we made it this far, HTobjtype is valid */
674
0
    code = gx_gstate_dev_ht_copy_to_objtype(i_ctx_p->pgs, HTobjtype);
675
0
    if (code < 0)
676
0
        return code;
677
678
0
    pop(1);
679
0
    return 0;
680
0
}
681
682
/* ------ Initialization procedure ------ */
683
684
const op_def zht2_l2_op_defs[] =
685
{
686
    op_def_begin_level2(),
687
    {"2.sethalftone5", zsethalftone5},
688
    {"1.genordered", zgenordered},
689
    {"1.setobjtypeHT", zsetobjtypeHT},
690
                /* Internal operators */
691
    {"0%sethalftone_finish", sethalftone_finish},
692
    op_def_end(0)
693
};
694
695
/* ------ Internal routines ------ */
696
697
/* Extract frequency, angle, spot function, and accurate screens flag */
698
/* from a dictionary. */
699
static int
700
dict_spot_params(const ref * pdict, gs_spot_halftone * psp,
701
                 ref * psproc, ref * ptproc, gs_memory_t *mem)
702
0
{
703
0
    int code;
704
705
0
    check_dict_read(*pdict);
706
0
    if ((code = dict_float_param(pdict, "Frequency", 0.0,
707
0
                                 &psp->screen.frequency)) != 0 ||
708
0
        (code = dict_float_param(pdict, "Angle", 0.0,
709
0
                                 &psp->screen.angle)) != 0 ||
710
0
      (code = dict_proc_param(pdict, "SpotFunction", psproc, false)) != 0 ||
711
0
        (code = dict_bool_param(pdict, "AccurateScreens",
712
0
                                gs_currentaccuratescreens(mem),
713
0
                                &psp->accurate_screens)) < 0 ||
714
0
      (code = dict_proc_param(pdict, "TransferFunction", ptproc, false)) < 0
715
0
        )
716
0
        return (code < 0 ? code : gs_error_undefined);
717
0
    psp->transfer = (code > 0 ? (gs_mapping_proc) 0 : gs_mapped_transfer);
718
0
    psp->transfer_closure.proc = 0;
719
0
    psp->transfer_closure.data = 0;
720
0
    return 0;
721
0
}
722
723
/* Set actual frequency and angle in a dictionary. */
724
static int
725
dict_real_result(i_ctx_t *i_ctx_p, ref * pdict, const char *kstr, double val)
726
0
{
727
0
    int code = 0;
728
0
    ref *ignore;
729
730
0
    if (dict_find_string(pdict, kstr, &ignore) > 0) {
731
0
        ref rval;
732
733
0
        check_dict_write(*pdict);
734
0
        make_real(&rval, val);
735
0
        code = idict_put_string(pdict, kstr, &rval);
736
0
    }
737
0
    return code;
738
0
}
739
static int
740
dict_spot_results(i_ctx_t *i_ctx_p, ref * pdict, const gs_spot_halftone * psp)
741
0
{
742
0
    int code;
743
744
0
    code = dict_real_result(i_ctx_p, pdict, "ActualFrequency",
745
0
                            psp->screen.actual_frequency);
746
0
    if (code < 0)
747
0
        return code;
748
0
    return dict_real_result(i_ctx_p, pdict, "ActualAngle",
749
0
                            psp->screen.actual_angle);
750
0
}
751
752
/* Extract Width, Height, and TransferFunction from a dictionary. */
753
static int
754
dict_threshold_common_params(const ref * pdict,
755
                             gs_threshold_halftone_common * ptp,
756
                             ref **pptstring, ref *ptproc)
757
0
{
758
0
    int code;
759
760
0
    check_dict_read(*pdict);
761
0
    if ((code = dict_int_param(pdict, "Width", 1, 0x7fff, -1,
762
0
                               &ptp->width)) < 0 ||
763
0
        (code = dict_int_param(pdict, "Height", 1, 0x7fff, -1,
764
0
                               &ptp->height)) < 0 ||
765
0
        (code = dict_find_string(pdict, "Thresholds", pptstring)) <= 0 ||
766
0
      (code = dict_proc_param(pdict, "TransferFunction", ptproc, false)) < 0
767
0
        )
768
0
        return (code < 0 ? code : gs_error_undefined);
769
0
    ptp->transfer_closure.proc = 0;
770
0
    ptp->transfer_closure.data = 0;
771
0
    return code;
772
0
}
773
774
/* Extract threshold common parameters + Thresholds. */
775
static int
776
dict_threshold_params(const ref * pdict, gs_threshold_halftone * ptp,
777
                      ref * ptproc)
778
0
{
779
0
    ref *tstring;
780
0
    int code =
781
0
        dict_threshold_common_params(pdict,
782
0
                                     (gs_threshold_halftone_common *)ptp,
783
0
                                     &tstring, ptproc);
784
785
0
    if (code < 0)
786
0
        return code;
787
0
    check_read_type_only(*tstring, t_string);
788
0
    if (r_size(tstring) != (long)ptp->width * ptp->height)
789
0
        return_error(gs_error_rangecheck);
790
0
    ptp->thresholds.data = tstring->value.const_bytes;
791
0
    ptp->thresholds.size = r_size(tstring);
792
0
    ptp->transfer = (code > 0 ? (gs_mapping_proc) 0 : gs_mapped_transfer);
793
0
    return 0;
794
0
}
795
796
/* Extract threshold common parameters + Thresholds, Width2, Height2, */
797
/* BitsPerSample. */
798
static int
799
dict_threshold2_params(const ref * pdict, gs_threshold2_halftone * ptp,
800
                       ref * ptproc, gs_memory_t *mem)
801
0
{
802
0
    ref *tstring;
803
0
    int code =
804
0
        dict_threshold_common_params(pdict,
805
0
                                     (gs_threshold_halftone_common *)ptp,
806
0
                                     &tstring, ptproc);
807
0
    int bps;
808
0
    uint size;
809
0
    int cw2, ch2;
810
811
0
    ptp->transfer = (code > 0 ? (gs_mapping_proc) 0 : gs_mapped_transfer);
812
813
0
    if (code < 0 ||
814
0
        (code = cw2 = dict_int_param(pdict, "Width2", 0, 0x7fff, 0,
815
0
                                     &ptp->width2)) < 0 ||
816
0
        (code = ch2 = dict_int_param(pdict, "Height2", 0, 0x7fff, 0,
817
0
                                     &ptp->height2)) < 0 ||
818
0
        (code = dict_int_param(pdict, "BitsPerSample", 8, 16, -1, &bps)) < 0
819
0
        )
820
0
        return code;
821
0
    if ((bps != 8 && bps != 16) || cw2 != ch2 ||
822
0
        (!cw2 && (ptp->width2 == 0 || ptp->height2 == 0))
823
0
        )
824
0
        return_error(gs_error_rangecheck);
825
0
    ptp->bytes_per_sample = bps / 8;
826
0
    switch (r_type(tstring)) {
827
0
    case t_string:
828
0
        size = r_size(tstring);
829
0
        gs_bytestring_from_string(&ptp->thresholds, tstring->value.const_bytes,
830
0
                                  size);
831
0
        break;
832
0
    case t_astruct:
833
0
        if (gs_object_type(mem, tstring->value.pstruct) != &st_bytes)
834
0
            return_error(gs_error_typecheck);
835
0
        size = gs_object_size(mem, tstring->value.pstruct);
836
0
        gs_bytestring_from_bytes(&ptp->thresholds, r_ptr(tstring, byte),
837
0
                                 0, size);
838
0
        break;
839
0
    default:
840
0
        return_error(gs_error_typecheck);
841
0
    }
842
0
    check_read(*tstring);
843
0
    if (size != (ptp->width * ptp->height + ptp->width2 * ptp->height2) *
844
0
        ptp->bytes_per_sample)
845
0
        return_error(gs_error_rangecheck);
846
0
    return 0;
847
0
}