Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/base/gsflip.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
/* Routines for "flipping" image data */
18
#include "gx.h"
19
#include "gserrors.h"   /* for rangecheck in sample macros */
20
#include "gsbitops.h"
21
#include "gsbittab.h"
22
#include "gsflip.h"
23
24
#define ARCH_HAS_BYTE_REGS 1
25
26
/* Transpose a block of bits between registers. */
27
#define TRANSPOSE(r,s,mask,shift)\
28
0
  r ^= (temp = ((s >> shift) ^ r) & mask);\
29
0
  s ^= temp << shift
30
31
/* Define the size of byte temporaries.  On Intel CPUs, this should be */
32
/* byte, but on all other CPUs, it should be uint. */
33
#if ARCH_HAS_BYTE_REGS
34
typedef byte byte_var;
35
#else
36
typedef uint byte_var;
37
#endif
38
39
#define VTAB(v80,v40,v20,v10,v8,v4,v2,v1)\
40
0
  bit_table_8(0,v80,v40,v20,v10,v8,v4,v2,v1)
41
42
/* Convert 3Mx1 to 3x1. */
43
static int
44
flip3x1(byte * buffer, const byte ** planes, int offset, int nbytes)
45
0
{
46
0
    byte *out = buffer;
47
0
    const byte *in1 = planes[0] + offset;
48
0
    const byte *in2 = planes[1] + offset;
49
0
    const byte *in3 = planes[2] + offset;
50
0
    int n = nbytes;
51
0
    static const bits32 tab3x1[256] = {
52
0
        VTAB(0x800000, 0x100000, 0x20000, 0x4000, 0x800, 0x100, 0x20, 4)
53
0
    };
54
55
0
    for (; n > 0; out += 3, ++in1, ++in2, ++in3, --n) {
56
0
        bits32 b24 = tab3x1[*in1] | (tab3x1[*in2] >> 1) | (tab3x1[*in3] >> 2);
57
58
0
        out[0] = (byte) (b24 >> 16);
59
0
        out[1] = (byte) (b24 >> 8);
60
0
        out[2] = (byte) b24;
61
0
    }
62
0
    return 0;
63
0
}
64
65
/* Convert 3Mx2 to 3x2. */
66
static int
67
flip3x2(byte * buffer, const byte ** planes, int offset, int nbytes)
68
0
{
69
0
    byte *out = buffer;
70
0
    const byte *in1 = planes[0] + offset;
71
0
    const byte *in2 = planes[1] + offset;
72
0
    const byte *in3 = planes[2] + offset;
73
0
    int n = nbytes;
74
0
    static const bits32 tab3x2[256] = {
75
0
        VTAB(0x800000, 0x400000, 0x20000, 0x10000, 0x800, 0x400, 0x20, 0x10)
76
0
    };
77
78
0
    for (; n > 0; out += 3, ++in1, ++in2, ++in3, --n) {
79
0
        bits32 b24 = tab3x2[*in1] | (tab3x2[*in2] >> 2) | (tab3x2[*in3] >> 4);
80
81
0
        out[0] = (byte) (b24 >> 16);
82
0
        out[1] = (byte) (b24 >> 8);
83
0
        out[2] = (byte) b24;
84
0
    }
85
0
    return 0;
86
0
}
87
88
/* Convert 3Mx4 to 3x4. */
89
static int
90
flip3x4(byte * buffer, const byte ** planes, int offset, int nbytes)
91
0
{
92
0
    byte *out = buffer;
93
0
    const byte *in1 = planes[0] + offset;
94
0
    const byte *in2 = planes[1] + offset;
95
0
    const byte *in3 = planes[2] + offset;
96
0
    int n = nbytes;
97
98
0
    for (; n > 0; out += 3, ++in1, ++in2, ++in3, --n) {
99
0
        byte_var b1 = *in1, b2 = *in2, b3 = *in3;
100
101
0
        out[0] = (b1 & 0xf0) | (b2 >> 4);
102
0
        out[1] = (b3 & 0xf0) | (b1 & 0xf);
103
0
        out[2] = (byte) (b2 << 4) | (b3 & 0xf);
104
0
    }
105
0
    return 0;
106
0
}
107
108
/* Convert 3Mx8 to 3x8. */
109
static int
110
flip3x8(byte * buffer, const byte ** planes, int offset, int nbytes)
111
15.3k
{
112
15.3k
    byte *out = buffer;
113
15.3k
    const byte *in1 = planes[0] + offset;
114
15.3k
    const byte *in2 = planes[1] + offset;
115
15.3k
    const byte *in3 = planes[2] + offset;
116
15.3k
    int n = nbytes;
117
118
887k
    for (; n > 0; out += 3, ++in1, ++in2, ++in3, --n) {
119
872k
        out[0] = *in1;
120
872k
        out[1] = *in2;
121
872k
        out[2] = *in3;
122
872k
    }
123
15.3k
    return 0;
124
15.3k
}
125
126
/* Convert 3Mx12 to 3x12. */
127
static int
128
flip3x12(byte * buffer, const byte ** planes, int offset, int nbytes)
129
0
{
130
0
    byte *out = buffer;
131
0
    const byte *pa = planes[0] + offset;
132
0
    const byte *pb = planes[1] + offset;
133
0
    const byte *pc = planes[2] + offset;
134
0
    int n = nbytes;
135
136
    /*
137
     * We assume that the input is an integral number of pixels, and
138
     * round up n to a multiple of 3.
139
     */
140
0
    for (; n > 0; out += 9, pa += 3, pb += 3, pc += 3, n -= 3) {
141
0
        byte_var a1 = pa[1], b0 = pb[0], b1 = pb[1], b2 = pb[2], c1 = pc[1];
142
143
0
        out[0] = pa[0];
144
0
        out[1] = (a1 & 0xf0) | (b0 >> 4);
145
0
        out[2] = (byte) ((b0 << 4) | (b1 >> 4));
146
0
        out[3] = pc[0];
147
0
        out[4] = (c1 & 0xf0) | (a1 & 0xf);
148
0
        out[5] = pa[2];
149
0
        out[6] = (byte) ((b1 << 4) | (b2 >> 4));
150
0
        out[7] = (byte) ((b2 << 4) | (c1 & 0xf));
151
0
        out[8] = pc[2];
152
0
    }
153
0
    return 0;
154
0
}
155
156
/* Convert 3Mx16 to 3x16. */
157
static int
158
flip3x16(byte * buffer, const byte ** planes, int offset, int nbytes)
159
0
{
160
0
    byte *out = buffer;
161
0
    const byte *pa = planes[0] + offset;
162
0
    const byte *pb = planes[1] + offset;
163
0
    const byte *pc = planes[2] + offset;
164
0
    int n = nbytes;
165
166
0
    for (; n > 0; out += 6, pa += 2, pb += 2, pc += 2, n -= 2) {
167
0
        out[0] = pa[0];
168
0
        out[1] = pa[1];
169
0
        out[2] = pb[0];
170
0
        out[3] = pb[1];
171
0
        out[4] = pc[0];
172
0
        out[5] = pc[1];
173
0
    }
174
0
    return 0;
175
0
}
176
177
/* Convert 4Mx1 to 4x1. */
178
static int
179
flip4x1(byte * buffer, const byte ** planes, int offset, int nbytes)
180
0
{
181
0
    byte *out = buffer;
182
0
    const byte *in1 = planes[0] + offset;
183
0
    const byte *in2 = planes[1] + offset;
184
0
    const byte *in3 = planes[2] + offset;
185
0
    const byte *in4 = planes[3] + offset;
186
0
    int n = nbytes;
187
188
0
    for (; n > 0; out += 4, ++in1, ++in2, ++in3, ++in4, --n) {
189
0
        byte_var b1 = *in1, b2 = *in2, b3 = *in3, b4 = *in4;
190
0
        byte_var temp;
191
192
        /* Transpose blocks of 1 */
193
0
        TRANSPOSE(b1, b2, 0x55, 1);
194
0
        TRANSPOSE(b3, b4, 0x55, 1);
195
        /* Transpose blocks of 2 */
196
0
        TRANSPOSE(b1, b3, 0x33, 2);
197
0
        TRANSPOSE(b2, b4, 0x33, 2);
198
        /* There's probably a faster way to do this.... */
199
0
        out[0] = (b1 & 0xf0) | (b2 >> 4);
200
0
        out[1] = (b3 & 0xf0) | (b4 >> 4);
201
0
        out[2] = (byte) ((b1 << 4) | (b2 & 0xf));
202
0
        out[3] = (byte) ((b3 << 4) | (b4 & 0xf));
203
0
    }
204
0
    return 0;
205
0
}
206
207
/* Convert 4Mx2 to 4x2. */
208
static int
209
flip4x2(byte * buffer, const byte ** planes, int offset, int nbytes)
210
0
{
211
0
    byte *out = buffer;
212
0
    const byte *in1 = planes[0] + offset;
213
0
    const byte *in2 = planes[1] + offset;
214
0
    const byte *in3 = planes[2] + offset;
215
0
    const byte *in4 = planes[3] + offset;
216
0
    int n = nbytes;
217
218
0
    for (; n > 0; out += 4, ++in1, ++in2, ++in3, ++in4, --n) {
219
0
        byte_var b1 = *in1, b2 = *in2, b3 = *in3, b4 = *in4;
220
0
        byte_var temp;
221
222
        /* Transpose blocks of 4x2 */
223
0
        TRANSPOSE(b1, b3, 0x0f, 4);
224
0
        TRANSPOSE(b2, b4, 0x0f, 4);
225
        /* Transpose blocks of 2x1 */
226
0
        TRANSPOSE(b1, b2, 0x33, 2);
227
0
        TRANSPOSE(b3, b4, 0x33, 2);
228
0
        out[0] = b1;
229
0
        out[1] = b2;
230
0
        out[2] = b3;
231
0
        out[3] = b4;
232
0
    }
233
0
    return 0;
234
0
}
235
236
/* Convert 4Mx4 to 4x4. */
237
static int
238
flip4x4(byte * buffer, const byte ** planes, int offset, int nbytes)
239
0
{
240
0
    byte *out = buffer;
241
0
    const byte *in1 = planes[0] + offset;
242
0
    const byte *in2 = planes[1] + offset;
243
0
    const byte *in3 = planes[2] + offset;
244
0
    const byte *in4 = planes[3] + offset;
245
0
    int n = nbytes;
246
247
0
    for (; n > 0; out += 4, ++in1, ++in2, ++in3, ++in4, --n) {
248
0
        byte_var b1 = *in1, b2 = *in2, b3 = *in3, b4 = *in4;
249
250
0
        out[0] = (b1 & 0xf0) | (b2 >> 4);
251
0
        out[1] = (b3 & 0xf0) | (b4 >> 4);
252
0
        out[2] = (byte) ((b1 << 4) | (b2 & 0xf));
253
0
        out[3] = (byte) ((b3 << 4) | (b4 & 0xf));
254
0
    }
255
0
    return 0;
256
0
}
257
258
/* Convert 4Mx8 to 4x8. */
259
static int
260
flip4x8(byte * buffer, const byte ** planes, int offset, int nbytes)
261
0
{
262
0
    byte *out = buffer;
263
0
    const byte *in1 = planes[0] + offset;
264
0
    const byte *in2 = planes[1] + offset;
265
0
    const byte *in3 = planes[2] + offset;
266
0
    const byte *in4 = planes[3] + offset;
267
0
    int n = nbytes;
268
269
0
    for (; n > 0; out += 4, ++in1, ++in2, ++in3, ++in4, --n) {
270
0
        out[0] = *in1;
271
0
        out[1] = *in2;
272
0
        out[2] = *in3;
273
0
        out[3] = *in4;
274
0
    }
275
0
    return 0;
276
0
}
277
278
/* Convert 4Mx12 to 4x12. */
279
static int
280
flip4x12(byte * buffer, const byte ** planes, int offset, int nbytes)
281
0
{
282
0
    byte *out = buffer;
283
0
    const byte *pa = planes[0] + offset;
284
0
    const byte *pb = planes[1] + offset;
285
0
    const byte *pc = planes[2] + offset;
286
0
    const byte *pd = planes[3] + offset;
287
0
    int n = nbytes;
288
289
    /*
290
     * We assume that the input is an integral number of pixels, and
291
     * round up n to a multiple of 3.
292
     */
293
0
    for (; n > 0; out += 12, pa += 3, pb += 3, pc += 3, pd += 3, n -= 3) {
294
0
        byte_var a1 = pa[1], b1 = pb[1], c1 = pc[1], d1 = pd[1];
295
296
0
        {
297
0
            byte_var v0;
298
299
0
            out[0] = pa[0];
300
0
            v0 = pb[0];
301
0
            out[1] = (a1 & 0xf0) | (v0 >> 4);
302
0
            out[2] = (byte) ((v0 << 4) | (b1 >> 4));
303
0
            out[3] = pc[0];
304
0
            v0 = pd[0];
305
0
            out[4] = (c1 & 0xf0) | (v0 >> 4);
306
0
            out[5] = (byte) ((v0 << 4) | (d1 >> 4));
307
0
        }
308
0
        {
309
0
            byte_var v2;
310
311
0
            v2 = pa[2];
312
0
            out[6] = (byte) ((a1 << 4) | (v2 >> 4));
313
0
            out[7] = (byte) ((v2 << 4) | (b1 & 0xf));
314
0
            out[8] = pb[2];
315
0
            v2 = pc[2];
316
0
            out[9] = (byte) ((c1 << 4) | (v2 >> 4));
317
0
            out[10] = (byte) ((v2 << 4) | (d1 & 0xf));
318
0
            out[11] = pd[2];
319
0
        }
320
0
    }
321
0
    return 0;
322
0
}
323
324
/* Convert 4Mx16 to 4x16. */
325
static int
326
flip4x16(byte * buffer, const byte ** planes, int offset, int nbytes)
327
0
{
328
0
    byte *out = buffer;
329
0
    const byte *pa = planes[0] + offset;
330
0
    const byte *pb = planes[1] + offset;
331
0
    const byte *pc = planes[2] + offset;
332
0
    const byte *pd = planes[3] + offset;
333
0
    int n = nbytes;
334
335
0
    for (; n > 0; out += 8, pa += 2, pb += 2, pc += 2, pd += 2, n -= 2) {
336
0
        out[0] = pa[0];
337
0
        out[1] = pa[1];
338
0
        out[2] = pb[0];
339
0
        out[3] = pb[1];
340
0
        out[4] = pc[0];
341
0
        out[5] = pc[1];
342
0
        out[6] = pd[0];
343
0
        out[7] = pd[1];
344
0
    }
345
0
    return 0;
346
0
}
347
348
/* Convert NMx{1,2,4,8} to Nx{1,2,4,8}. */
349
static int
350
flipNx1to8(byte * buffer, const byte ** planes, int offset, int nbytes,
351
           int num_planes, int bits_per_sample)
352
0
{
353
    /* This is only needed for DeviceN colors, so it can be slow. */
354
0
    uint mask = (1 << bits_per_sample) - 1;
355
0
    int bi, pi;
356
0
    byte *dptr = buffer;
357
0
    int dbit = 0;
358
0
    byte dbbyte = 0;
359
360
0
    for (bi = 0; bi < nbytes * 8; bi += bits_per_sample) {
361
0
        for (pi = 0; pi < num_planes; ++pi) {
362
0
            const byte *sptr = planes[pi] + offset + (bi >> 3);
363
0
            uint value = (*sptr >> (8 - (bi & 7) - bits_per_sample)) & mask;
364
365
0
            if (sample_store_next8(value, &dptr, &dbit, bits_per_sample, &dbbyte) < 0)
366
0
                return_error(gs_error_rangecheck);
367
0
        }
368
0
    }
369
0
    sample_store_flush(dptr, dbit, dbbyte);
370
0
    return 0;
371
0
}
372
373
/* Convert NMx12 to Nx12. */
374
static int
375
flipNx12(byte * buffer, const byte ** planes, int offset, int nbytes,
376
         int num_planes, int ignore_bits_per_sample)
377
0
{
378
    /* This is only needed for DeviceN colors, so it can be slow. */
379
0
    int bi, pi;
380
0
    byte *dptr = buffer;
381
0
    int dbit = 0;
382
0
    byte dbbyte = 0;
383
384
0
    for (bi = 0; bi < nbytes * 8; bi += 12) {
385
0
        for (pi = 0; pi < num_planes; ++pi) {
386
0
            const byte *sptr = planes[pi] + offset + (bi >> 3);
387
0
            uint value =
388
0
                (bi & 4 ? ((*sptr & 0xf) << 8) | sptr[1] :
389
0
                 (*sptr << 4) | (sptr[1] >> 4));
390
391
0
            sample_store_next_12(value, &dptr, &dbit, &dbbyte);
392
0
        }
393
0
    }
394
0
    sample_store_flush(dptr, dbit, dbbyte);
395
0
    return 0;
396
0
}
397
398
/* Convert NMx16 to Nx16. */
399
static int
400
flipNx16(byte * buffer, const byte ** planes, int offset, int nbytes,
401
         int num_planes, int ignore_bits_per_sample)
402
0
{
403
    /* This is only needed for DeviceN colors, so it can be slow. */
404
0
    int bi, pi;
405
0
    byte *dptr = buffer;
406
407
0
    for (bi = 0; bi < nbytes; bi += 2) {
408
0
        for (pi = 0; pi < num_planes; ++pi) {
409
0
            const byte *sptr = planes[pi] + offset + bi;
410
0
            dptr[0] = sptr[0];
411
0
            dptr[1] = sptr[1];
412
0
            dptr += 2;
413
0
        }
414
0
    }
415
0
    return 0;
416
0
}
417
418
/* Flip data given number of planes and bits per pixel. */
419
typedef int (*image_flip_proc) (byte *, const byte **, int, int);
420
static int
421
flip_fail(byte * buffer, const byte ** planes, int offset, int nbytes)
422
0
{
423
0
    return -1;
424
0
}
425
static const image_flip_proc image_flip3_procs[17] = {
426
    flip_fail, flip3x1, flip3x2, flip_fail, flip3x4,
427
    flip_fail, flip_fail, flip_fail, flip3x8,
428
    flip_fail, flip_fail, flip_fail, flip3x12,
429
    flip_fail, flip_fail, flip_fail, flip3x16
430
};
431
static const image_flip_proc image_flip4_procs[17] = {
432
    flip_fail, flip4x1, flip4x2, flip_fail, flip4x4,
433
    flip_fail, flip_fail, flip_fail, flip4x8,
434
    flip_fail, flip_fail, flip_fail, flip4x12,
435
    flip_fail, flip_fail, flip_fail, flip4x16
436
};
437
typedef int (*image_flipN_proc) (byte *, const byte **, int, int, int, int);
438
static int
439
flipN_fail(byte * buffer, const byte ** planes, int offset, int nbytes,
440
           int num_planes, int bits_per_sample)
441
0
{
442
0
    return -1;
443
0
}
444
static const image_flipN_proc image_flipN_procs[17] = {
445
    flipN_fail, flipNx1to8, flipNx1to8, flipN_fail, flipNx1to8,
446
    flipN_fail, flipN_fail, flipN_fail, flipNx1to8,
447
    flipN_fail, flipN_fail, flipN_fail, flipNx12,
448
    flipN_fail, flipN_fail, flipN_fail, flipNx16
449
};
450
451
/* Here is the public interface to all of the above. */
452
int
453
image_flip_planes(byte * buffer, const byte ** planes, int offset, int nbytes,
454
                  int num_planes, int bits_per_sample)
455
15.3k
{
456
15.3k
    if (bits_per_sample < 1 || bits_per_sample > 16)
457
0
        return -1;
458
15.3k
    switch (num_planes) {
459
460
15.3k
    case 3:
461
15.3k
        return image_flip3_procs[bits_per_sample]
462
15.3k
            (buffer, planes, offset, nbytes);
463
0
    case 4:
464
0
        return image_flip4_procs[bits_per_sample]
465
0
            (buffer, planes, offset, nbytes);
466
0
    default:
467
0
        if (num_planes < 0)
468
0
            return -1;
469
0
        return image_flipN_procs[bits_per_sample]
470
0
            (buffer, planes, offset, nbytes, num_planes, bits_per_sample);
471
15.3k
    }
472
15.3k
}