Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/base/gxhtbit.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
/* Halftone bit updating for imaging library */
18
#include "memory_.h"
19
#include "gx.h"
20
#include "gserrors.h"
21
#include "gsbitops.h"
22
#include "gscdefs.h"
23
#include "gxbitmap.h"
24
#include "gxhttile.h"
25
#include "gxtmap.h"
26
#include "gxdht.h"
27
#include "gxdhtres.h"
28
#include "gp.h"
29
30
#define DUMP_TOS 0
31
32
extern_gx_device_halftone_list();
33
34
/*
35
 * Construct a standard-representation order from a threshold array.
36
 */
37
static int
38
construct_ht_order_default(gx_ht_order *porder, const byte *thresholds)
39
0
{
40
0
    gx_ht_bit *bits = (gx_ht_bit *)porder->bit_data;
41
0
    uint i;
42
43
0
    for (i = 0; i < porder->num_bits; i++)
44
0
        bits[i].mask = max(1, thresholds[i]);
45
0
    gx_ht_complete_threshold_order(porder);
46
0
    return 0;
47
0
}
48
49
/*
50
 * Construct a short-representation order from a threshold array.
51
 * Uses porder->width, num_levels, num_bits, levels, bit_data;
52
 * sets porder->levels[], bit_data[].
53
 */
54
static int
55
construct_ht_order_short(gx_ht_order *porder, const byte *thresholds)
56
0
{
57
0
    uint size = porder->num_bits;
58
0
    uint i;
59
0
    ushort *bits = (ushort *)porder->bit_data;
60
0
    uint *levels = porder->levels;
61
0
    uint num_levels = porder->num_levels;
62
63
0
    memset(levels, 0, num_levels * sizeof(*levels));
64
    /* Count the number of threshold elements with each value. */
65
0
    for (i = 0; i < size; i++) {
66
0
        uint value = max(1, thresholds[i]);
67
68
0
        if (value + 1 < num_levels)
69
0
            levels[value + 1]++;
70
0
    }
71
0
    for (i = 2; i < num_levels; ++i)
72
0
        levels[i] += levels[i - 1];
73
    /* Now construct the actual order. */
74
0
    {
75
0
        uint width = porder->width;
76
0
        uint padding = bitmap_raster(width) * 8 - width;
77
78
0
        for (i = 0; i < size; i++) {
79
0
            uint value = max(1, thresholds[i]);
80
81
0
            bits[levels[value]++] = i + (i / width * padding);
82
0
        }
83
0
    }
84
85
    /* Check whether this is a predefined halftone. */
86
0
    {
87
0
        const gx_dht_proc *phtrp = gx_device_halftone_list;
88
89
0
        for (; *phtrp; ++phtrp) {
90
0
            const gx_device_halftone_resource_t *const *pphtr = (*phtrp)();
91
0
            const gx_device_halftone_resource_t *phtr;
92
93
0
            while ((phtr = *pphtr++) != 0) {
94
0
                if (phtr->Width == porder->width &&
95
0
                    phtr->Height == porder->height &&
96
0
                    phtr->elt_size == sizeof(ushort) &&
97
0
                    !memcmp(phtr->levels, levels, num_levels * sizeof(*levels)) &&
98
0
                    !memcmp(phtr->bit_data, porder->bit_data,
99
0
                            (size_t)size * phtr->elt_size)
100
0
                    ) {
101
                    /*
102
                     * This is a predefined halftone.  Free the levels and
103
                     * bit_data arrays, replacing them with the built-in ones.
104
                     */
105
0
                    if (porder->data_memory) {
106
0
                        gs_free_object(porder->data_memory, porder->bit_data,
107
0
                                       "construct_ht_order_short(bit_data)");
108
0
                        gs_free_object(porder->data_memory, porder->levels,
109
0
                                       "construct_ht_order_short(levels)");
110
0
                    }
111
0
                    porder->data_memory = 0;
112
0
                    porder->levels = (uint *)phtr->levels; /* actually const */
113
0
                    porder->bit_data = (void *)phtr->bit_data; /* actually const */
114
0
                    goto out;
115
0
                }
116
0
            }
117
0
        }
118
0
    }
119
#if DUMP_TOS
120
/* Lets look at the bit data which is the TOS level by level if I understand what the above
121
   code is supposed to be doing */
122
    {
123
        char file_name[50];
124
        gp_file *fid;
125
126
        snprintf(file_name, 50, "TOS_porder_%dx%d.raw", porder->width, porder->height);
127
        fid = gp_fopen(porder->data_memory, file_name, "wb");
128
        if (fid) {
129
            gp_fwrite(porder->bit_data, sizeof(unsigned short), size, fid);
130
            gp_fclose(fid);
131
        }
132
    }
133
#endif
134
135
0
 out:
136
0
    return 0;
137
0
}
138
139
/*
140
 * Construct a uint-representation order from a threshold array.
141
 * Uses porder->width, num_levels, num_bits, levels, bit_data;
142
 * sets porder->levels[], bit_data[].
143
 */
144
static int
145
construct_ht_order_uint(gx_ht_order *porder, const byte *thresholds)
146
0
{
147
0
    uint size = porder->num_bits;
148
0
    uint i;
149
0
    uint *bits = (uint *)porder->bit_data;
150
0
    uint *levels = porder->levels;
151
0
    uint num_levels = porder->num_levels;
152
153
0
    memset(levels, 0, num_levels * sizeof(*levels));
154
155
    /* Count the number of threshold elements with each value. */
156
0
    for (i = 0; i < size; i++) {
157
0
        uint value = max(1, thresholds[i]);
158
159
0
        if (value + 1 < num_levels)
160
0
            levels[value + 1]++;
161
0
    }
162
0
    for (i = 2; i < num_levels; ++i)
163
0
        levels[i] += levels[i - 1];
164
    /* Now construct the actual order. */
165
0
    {
166
0
        uint width = porder->width;
167
0
        uint padding = bitmap_raster(width) * 8 - width;
168
169
0
        for (i = 0; i < size; i++) {
170
0
            uint value = max(1, thresholds[i]);
171
172
0
            bits[levels[value]++] = i + (i / width * padding);
173
0
        }
174
0
    }
175
176
    /* Check whether this is a predefined halftone. */
177
0
    {
178
0
        const gx_dht_proc *phtrp = gx_device_halftone_list;
179
180
0
        for (; *phtrp; ++phtrp) {
181
0
            const gx_device_halftone_resource_t *const *pphtr = (*phtrp)();
182
0
            const gx_device_halftone_resource_t *phtr;
183
184
0
            while ((phtr = *pphtr++) != 0) {
185
0
                if (phtr->Width == porder->width &&
186
0
                    phtr->Height == porder->height &&
187
0
                    phtr->elt_size == sizeof(uint) &&
188
0
                    !memcmp(phtr->levels, levels, num_levels * sizeof(*levels)) &&
189
0
                    !memcmp(phtr->bit_data, porder->bit_data,
190
0
                        (size_t)size * phtr->elt_size)
191
0
                    ) {
192
                    /*
193
                     * This is a predefined halftone.  Free the levels and
194
                     * bit_data arrays, replacing them with the built-in ones.
195
                     */
196
0
                    if (porder->data_memory) {
197
0
                        gs_free_object(porder->data_memory, porder->bit_data,
198
0
                            "construct_ht_order_uint(bit_data)");
199
0
                        gs_free_object(porder->data_memory, porder->levels,
200
0
                            "construct_ht_order_uint(levels)");
201
0
                    }
202
0
                    porder->data_memory = 0;
203
0
                    porder->levels = (uint *)phtr->levels; /* actually const */
204
0
                    porder->bit_data = (void *)phtr->bit_data; /* actually const */
205
0
                    goto out;
206
0
                }
207
0
            }
208
0
        }
209
0
    }
210
0
out:
211
0
    return 0;
212
0
}
213
214
/* Return the bit coordinate using the standard representation. */
215
static int
216
ht_bit_index_default(const gx_ht_order *porder, uint index, gs_int_point *ppt)
217
5.19M
{
218
5.19M
    const gx_ht_bit *phtb = &((const gx_ht_bit *)porder->bit_data)[index];
219
5.19M
    uint offset = phtb->offset;
220
5.19M
    int bit = 0;
221
222
18.8M
    while (!(((const byte *)&phtb->mask)[bit >> 3] & (0x80 >> (bit & 7))))
223
13.6M
        ++bit;
224
5.19M
    ppt->x = (offset % porder->raster * 8) + bit;
225
5.19M
    ppt->y = offset / porder->raster;
226
5.19M
    return 0;
227
5.19M
}
228
229
/* Return the bit coordinate using the short representation. */
230
static int
231
ht_bit_index_short(const gx_ht_order *porder, uint index, gs_int_point *ppt)
232
0
{
233
0
    uint bit_index = ((const ushort *)porder->bit_data)[index];
234
0
    uint bit_raster = porder->raster * 8;
235
236
0
    ppt->x = bit_index % bit_raster;
237
0
    ppt->y = bit_index / bit_raster;
238
0
    return 0;
239
0
}
240
241
/* Return the bit coordinate using the uint representation. */
242
static int
243
ht_bit_index_uint(const gx_ht_order *porder, uint index, gs_int_point *ppt)
244
0
{
245
0
    uint bit_index = ((const uint *)porder->bit_data)[index];
246
0
    uint bit_raster = porder->raster * 8;
247
248
0
    ppt->x = bit_index % bit_raster;
249
0
    ppt->y = bit_index / bit_raster;
250
0
    return 0;
251
0
}
252
253
/* Update a halftone tile using the default order representation. */
254
static int
255
render_ht_default(gx_ht_tile *pbt, int level, const gx_ht_order *porder)
256
2.38M
{
257
2.38M
    int old_level = pbt->level;
258
2.38M
    register const gx_ht_bit *p =
259
2.38M
        (const gx_ht_bit *)porder->bit_data + old_level;
260
2.38M
    register byte *data = pbt->tiles.data;
261
262
    /*
263
     * Invert bits between the two levels.  Note that we can use the same
264
     * loop to turn bits either on or off, using xor.  The Borland compiler
265
     * generates truly dreadful code if we don't use a temporary, and it
266
     * doesn't hurt better compilers, so we always use one.
267
     */
268
2.38M
#define INVERT_DATA(i)\
269
264M
     BEGIN\
270
264M
       ht_mask_t *dp = (ht_mask_t *)&data[p[i].offset];\
271
264M
       *dp ^= p[i].mask;\
272
264M
     END
273
#ifdef DEBUG
274
#  define INVERT(i)\
275
     BEGIN\
276
       if_debug3('H', "[H]invert level=%d offset=%u mask=0x%x\n",\
277
                 (int)(p + i - (const gx_ht_bit *)porder->bit_data),\
278
                 p[i].offset, p[i].mask);\
279
       INVERT_DATA(i);\
280
     END
281
#else
282
264M
#  define INVERT(i) INVERT_DATA(i)
283
2.38M
#endif
284
65.2M
  sw:switch (level - old_level) {
285
62.8M
        default:
286
62.8M
            if (level > old_level) {
287
62.8M
                INVERT(0); INVERT(1); INVERT(2); INVERT(3);
288
62.8M
                p += 4; old_level += 4;
289
62.8M
            } else {
290
0
                INVERT(-1); INVERT(-2); INVERT(-3); INVERT(-4);
291
0
                p -= 4; old_level -= 4;
292
0
            }
293
62.8M
            goto sw;
294
534k
        case 7: INVERT(6);
295
1.13M
        case 6: INVERT(5);
296
1.67M
        case 5: INVERT(4);
297
2.26M
        case 4: INVERT(3);
298
2.31M
        case 3: INVERT(2);
299
2.35M
        case 2: INVERT(1);
300
2.38M
        case 1: INVERT(0);
301
2.38M
        case 0: break;    /* Shouldn't happen! */
302
0
        case -7: INVERT(-7);
303
0
        case -6: INVERT(-6);
304
0
        case -5: INVERT(-5);
305
0
        case -4: INVERT(-4);
306
0
        case -3: INVERT(-3);
307
0
        case -2: INVERT(-2);
308
0
        case -1: INVERT(-1);
309
65.2M
    }
310
2.38M
#undef INVERT_DATA
311
2.38M
#undef INVERT
312
2.38M
    return 0;
313
65.2M
}
314
315
/* Update a halftone tile using the short representation. */
316
static int
317
render_ht_short(gx_ht_tile *pbt, int level, const gx_ht_order *porder)
318
0
{
319
0
    int old_level = pbt->level;
320
0
    register const ushort *p = (const ushort *)porder->bit_data + old_level;
321
0
    register byte *data = pbt->tiles.data;
322
323
    /* Invert bits between the two levels. */
324
0
#define INVERT_DATA(i)\
325
0
     BEGIN\
326
0
       uint bit_index = p[i];\
327
0
       byte *dp = &data[bit_index >> 3];\
328
0
       *dp ^= 0x80 >> (bit_index & 7);\
329
0
     END
330
#ifdef DEBUG
331
#  define INVERT(i)\
332
     BEGIN\
333
       if_debug3('H', "[H]invert level=%d offset=%u mask=0x%x\n",\
334
                 (int)(p + i - (const ushort *)porder->bit_data),\
335
                 p[i] >> 3, 0x80 >> (p[i] & 7));\
336
       INVERT_DATA(i);\
337
     END
338
#else
339
0
#  define INVERT(i) INVERT_DATA(i)
340
0
#endif
341
0
  sw:switch (level - old_level) {
342
0
        default:
343
0
            if (level > old_level) {
344
0
                INVERT(0); INVERT(1); INVERT(2); INVERT(3);
345
0
                p += 4; old_level += 4;
346
0
            } else {
347
0
                INVERT(-1); INVERT(-2); INVERT(-3); INVERT(-4);
348
0
                p -= 4; old_level -= 4;
349
0
            }
350
0
            goto sw;
351
0
        case 7: INVERT(6);
352
0
        case 6: INVERT(5);
353
0
        case 5: INVERT(4);
354
0
        case 4: INVERT(3);
355
0
        case 3: INVERT(2);
356
0
        case 2: INVERT(1);
357
0
        case 1: INVERT(0);
358
0
        case 0: break;   /* Shouldn't happen! */
359
0
        case -7: INVERT(-7);
360
0
        case -6: INVERT(-6);
361
0
        case -5: INVERT(-5);
362
0
        case -4: INVERT(-4);
363
0
        case -3: INVERT(-3);
364
0
        case -2: INVERT(-2);
365
0
        case -1: INVERT(-1);
366
0
    }
367
0
#undef INVERT_DATA
368
0
#undef INVERT
369
0
    return 0;
370
0
}
371
372
/* Update a halftone tile using the uint representation. */
373
static int
374
render_ht_uint(gx_ht_tile *pbt, int level, const gx_ht_order *porder)
375
0
{
376
0
    int old_level = pbt->level;
377
0
    register const uint *p = (const uint *)porder->bit_data + old_level;
378
0
    register byte *data = pbt->tiles.data;
379
380
    /* Invert bits between the two levels. */
381
0
#define INVERT_DATA(i)\
382
0
     BEGIN\
383
0
       uint bit_index = p[i];\
384
0
       byte *dp = &data[bit_index >> 3];\
385
0
       *dp ^= 0x80 >> (bit_index & 7);\
386
0
     END
387
#ifdef DEBUG
388
#  define INVERT(i)\
389
     BEGIN\
390
       if_debug3('H', "[H]invert level=%d offset=%u mask=0x%x\n",\
391
                 (int)(p + i - (const uint *)porder->bit_data),\
392
                 p[i] >> 3, 0x80 >> (p[i] & 7));\
393
       INVERT_DATA(i);\
394
     END
395
#else
396
0
#  define INVERT(i) INVERT_DATA(i)
397
0
#endif
398
0
sw:switch (level - old_level) {
399
0
default:
400
0
    if (level > old_level) {
401
0
        INVERT(0); INVERT(1); INVERT(2); INVERT(3);
402
0
        p += 4; old_level += 4;
403
0
    }
404
0
    else {
405
0
        INVERT(-1); INVERT(-2); INVERT(-3); INVERT(-4);
406
0
        p -= 4; old_level -= 4;
407
0
    }
408
0
    goto sw;
409
0
case 7: INVERT(6);
410
0
case 6: INVERT(5);
411
0
case 5: INVERT(4);
412
0
case 4: INVERT(3);
413
0
case 3: INVERT(2);
414
0
case 2: INVERT(1);
415
0
case 1: INVERT(0);
416
0
case 0: break;   /* Shouldn't happen! */
417
0
case -7: INVERT(-7);
418
0
case -6: INVERT(-6);
419
0
case -5: INVERT(-5);
420
0
case -4: INVERT(-4);
421
0
case -3: INVERT(-3);
422
0
case -2: INVERT(-2);
423
0
case -1: INVERT(-1);
424
0
}
425
0
#undef INVERT_DATA
426
0
#undef INVERT
427
0
return 0;
428
0
}
429
430
/* Define the procedure vectors for the order data implementations. */
431
const gx_ht_order_procs_t ht_order_procs_table[3] = {
432
    { sizeof(gx_ht_bit), construct_ht_order_default, ht_bit_index_default,
433
      render_ht_default },
434
    { sizeof(ushort), construct_ht_order_short, ht_bit_index_short,
435
      render_ht_short },
436
    { sizeof(uint), construct_ht_order_uint, ht_bit_index_uint,
437
      render_ht_uint }
438
};