Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/base/gsflip.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2021 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
/* 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
0
{
112
0
    byte *out = buffer;
113
0
    const byte *in1 = planes[0] + offset;
114
0
    const byte *in2 = planes[1] + offset;
115
0
    const byte *in3 = planes[2] + offset;
116
0
    int n = nbytes;
117
118
0
    for (; n > 0; out += 3, ++in1, ++in2, ++in3, --n) {
119
0
        out[0] = *in1;
120
0
        out[1] = *in2;
121
0
        out[2] = *in3;
122
0
    }
123
0
    return 0;
124
0
}
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 4Mx1 to 4x1. */
157
static int
158
flip4x1(byte * buffer, const byte ** planes, int offset, int nbytes)
159
0
{
160
0
    byte *out = buffer;
161
0
    const byte *in1 = planes[0] + offset;
162
0
    const byte *in2 = planes[1] + offset;
163
0
    const byte *in3 = planes[2] + offset;
164
0
    const byte *in4 = planes[3] + offset;
165
0
    int n = nbytes;
166
167
0
    for (; n > 0; out += 4, ++in1, ++in2, ++in3, ++in4, --n) {
168
0
        byte_var b1 = *in1, b2 = *in2, b3 = *in3, b4 = *in4;
169
0
        byte_var temp;
170
171
        /* Transpose blocks of 1 */
172
0
        TRANSPOSE(b1, b2, 0x55, 1);
173
0
        TRANSPOSE(b3, b4, 0x55, 1);
174
        /* Transpose blocks of 2 */
175
0
        TRANSPOSE(b1, b3, 0x33, 2);
176
0
        TRANSPOSE(b2, b4, 0x33, 2);
177
        /* There's probably a faster way to do this.... */
178
0
        out[0] = (b1 & 0xf0) | (b2 >> 4);
179
0
        out[1] = (b3 & 0xf0) | (b4 >> 4);
180
0
        out[2] = (byte) ((b1 << 4) | (b2 & 0xf));
181
0
        out[3] = (byte) ((b3 << 4) | (b4 & 0xf));
182
0
    }
183
0
    return 0;
184
0
}
185
186
/* Convert 4Mx2 to 4x2. */
187
static int
188
flip4x2(byte * buffer, const byte ** planes, int offset, int nbytes)
189
0
{
190
0
    byte *out = buffer;
191
0
    const byte *in1 = planes[0] + offset;
192
0
    const byte *in2 = planes[1] + offset;
193
0
    const byte *in3 = planes[2] + offset;
194
0
    const byte *in4 = planes[3] + offset;
195
0
    int n = nbytes;
196
197
0
    for (; n > 0; out += 4, ++in1, ++in2, ++in3, ++in4, --n) {
198
0
        byte_var b1 = *in1, b2 = *in2, b3 = *in3, b4 = *in4;
199
0
        byte_var temp;
200
201
        /* Transpose blocks of 4x2 */
202
0
        TRANSPOSE(b1, b3, 0x0f, 4);
203
0
        TRANSPOSE(b2, b4, 0x0f, 4);
204
        /* Transpose blocks of 2x1 */
205
0
        TRANSPOSE(b1, b2, 0x33, 2);
206
0
        TRANSPOSE(b3, b4, 0x33, 2);
207
0
        out[0] = b1;
208
0
        out[1] = b2;
209
0
        out[2] = b3;
210
0
        out[3] = b4;
211
0
    }
212
0
    return 0;
213
0
}
214
215
/* Convert 4Mx4 to 4x4. */
216
static int
217
flip4x4(byte * buffer, const byte ** planes, int offset, int nbytes)
218
0
{
219
0
    byte *out = buffer;
220
0
    const byte *in1 = planes[0] + offset;
221
0
    const byte *in2 = planes[1] + offset;
222
0
    const byte *in3 = planes[2] + offset;
223
0
    const byte *in4 = planes[3] + offset;
224
0
    int n = nbytes;
225
226
0
    for (; n > 0; out += 4, ++in1, ++in2, ++in3, ++in4, --n) {
227
0
        byte_var b1 = *in1, b2 = *in2, b3 = *in3, b4 = *in4;
228
229
0
        out[0] = (b1 & 0xf0) | (b2 >> 4);
230
0
        out[1] = (b3 & 0xf0) | (b4 >> 4);
231
0
        out[2] = (byte) ((b1 << 4) | (b2 & 0xf));
232
0
        out[3] = (byte) ((b3 << 4) | (b4 & 0xf));
233
0
    }
234
0
    return 0;
235
0
}
236
237
/* Convert 4Mx8 to 4x8. */
238
static int
239
flip4x8(byte * buffer, const byte ** planes, int offset, int nbytes)
240
0
{
241
0
    byte *out = buffer;
242
0
    const byte *in1 = planes[0] + offset;
243
0
    const byte *in2 = planes[1] + offset;
244
0
    const byte *in3 = planes[2] + offset;
245
0
    const byte *in4 = planes[3] + offset;
246
0
    int n = nbytes;
247
248
0
    for (; n > 0; out += 4, ++in1, ++in2, ++in3, ++in4, --n) {
249
0
        out[0] = *in1;
250
0
        out[1] = *in2;
251
0
        out[2] = *in3;
252
0
        out[3] = *in4;
253
0
    }
254
0
    return 0;
255
0
}
256
257
/* Convert 4Mx12 to 4x12. */
258
static int
259
flip4x12(byte * buffer, const byte ** planes, int offset, int nbytes)
260
0
{
261
0
    byte *out = buffer;
262
0
    const byte *pa = planes[0] + offset;
263
0
    const byte *pb = planes[1] + offset;
264
0
    const byte *pc = planes[2] + offset;
265
0
    const byte *pd = planes[3] + offset;
266
0
    int n = nbytes;
267
268
    /*
269
     * We assume that the input is an integral number of pixels, and
270
     * round up n to a multiple of 3.
271
     */
272
0
    for (; n > 0; out += 12, pa += 3, pb += 3, pc += 3, pd += 3, n -= 3) {
273
0
        byte_var a1 = pa[1], b1 = pb[1], c1 = pc[1], d1 = pd[1];
274
275
0
        {
276
0
            byte_var v0;
277
278
0
            out[0] = pa[0];
279
0
            v0 = pb[0];
280
0
            out[1] = (a1 & 0xf0) | (v0 >> 4);
281
0
            out[2] = (byte) ((v0 << 4) | (b1 >> 4));
282
0
            out[3] = pc[0];
283
0
            v0 = pd[0];
284
0
            out[4] = (c1 & 0xf0) | (v0 >> 4);
285
0
            out[5] = (byte) ((v0 << 4) | (d1 >> 4));
286
0
        }
287
0
        {
288
0
            byte_var v2;
289
290
0
            v2 = pa[2];
291
0
            out[6] = (byte) ((a1 << 4) | (v2 >> 4));
292
0
            out[7] = (byte) ((v2 << 4) | (b1 & 0xf));
293
0
            out[8] = pb[2];
294
0
            v2 = pc[2];
295
0
            out[9] = (byte) ((c1 << 4) | (v2 >> 4));
296
0
            out[10] = (byte) ((v2 << 4) | (d1 & 0xf));
297
0
            out[11] = pd[2];
298
0
        }
299
0
    }
300
0
    return 0;
301
0
}
302
303
/* Convert NMx{1,2,4,8} to Nx{1,2,4,8}. */
304
static int
305
flipNx1to8(byte * buffer, const byte ** planes, int offset, int nbytes,
306
           int num_planes, int bits_per_sample)
307
0
{
308
    /* This is only needed for DeviceN colors, so it can be slow. */
309
0
    uint mask = (1 << bits_per_sample) - 1;
310
0
    int bi, pi;
311
0
    byte *dptr = buffer;
312
0
    int dbit = 0;
313
0
    byte dbbyte = 0;
314
315
0
    for (bi = 0; bi < nbytes * 8; bi += bits_per_sample) {
316
0
        for (pi = 0; pi < num_planes; ++pi) {
317
0
            const byte *sptr = planes[pi] + offset + (bi >> 3);
318
0
            uint value = (*sptr >> (8 - (bi & 7) - bits_per_sample)) & mask;
319
320
0
            if (sample_store_next8(value, &dptr, &dbit, bits_per_sample, &dbbyte) < 0)
321
0
                return_error(gs_error_rangecheck);
322
0
        }
323
0
    }
324
0
    sample_store_flush(dptr, dbit, dbbyte);
325
0
    return 0;
326
0
}
327
328
/* Convert NMx12 to Nx12. */
329
static int
330
flipNx12(byte * buffer, const byte ** planes, int offset, int nbytes,
331
         int num_planes, int ignore_bits_per_sample)
332
0
{
333
    /* This is only needed for DeviceN colors, so it can be slow. */
334
0
    int bi, pi;
335
0
    byte *dptr = buffer;
336
0
    int dbit = 0;
337
0
    byte dbbyte = 0;
338
339
0
    for (bi = 0; bi < nbytes * 8; bi += 12) {
340
0
        for (pi = 0; pi < num_planes; ++pi) {
341
0
            const byte *sptr = planes[pi] + offset + (bi >> 3);
342
0
            uint value =
343
0
                (bi & 4 ? ((*sptr & 0xf) << 8) | sptr[1] :
344
0
                 (*sptr << 4) | (sptr[1] >> 4));
345
346
0
            sample_store_next_12(value, &dptr, &dbit, &dbbyte);
347
0
        }
348
0
    }
349
0
    sample_store_flush(dptr, dbit, dbbyte);
350
0
    return 0;
351
0
}
352
353
/* Flip data given number of planes and bits per pixel. */
354
typedef int (*image_flip_proc) (byte *, const byte **, int, int);
355
static int
356
flip_fail(byte * buffer, const byte ** planes, int offset, int nbytes)
357
0
{
358
0
    return -1;
359
0
}
360
static const image_flip_proc image_flip3_procs[13] = {
361
    flip_fail, flip3x1, flip3x2, flip_fail, flip3x4,
362
    flip_fail, flip_fail, flip_fail, flip3x8,
363
    flip_fail, flip_fail, flip_fail, flip3x12
364
};
365
static const image_flip_proc image_flip4_procs[13] = {
366
    flip_fail, flip4x1, flip4x2, flip_fail, flip4x4,
367
    flip_fail, flip_fail, flip_fail, flip4x8,
368
    flip_fail, flip_fail, flip_fail, flip4x12
369
};
370
typedef int (*image_flipN_proc) (byte *, const byte **, int, int, int, int);
371
static int
372
flipN_fail(byte * buffer, const byte ** planes, int offset, int nbytes,
373
           int num_planes, int bits_per_sample)
374
0
{
375
0
    return -1;
376
0
}
377
static const image_flipN_proc image_flipN_procs[13] = {
378
    flipN_fail, flipNx1to8, flipNx1to8, flipN_fail, flipNx1to8,
379
    flipN_fail, flipN_fail, flipN_fail, flipNx1to8,
380
    flipN_fail, flipN_fail, flipN_fail, flipNx12
381
};
382
383
/* Here is the public interface to all of the above. */
384
int
385
image_flip_planes(byte * buffer, const byte ** planes, int offset, int nbytes,
386
                  int num_planes, int bits_per_sample)
387
0
{
388
0
    if (bits_per_sample < 1 || bits_per_sample > 12)
389
0
        return -1;
390
0
    switch (num_planes) {
391
392
0
    case 3:
393
0
        return image_flip3_procs[bits_per_sample]
394
0
            (buffer, planes, offset, nbytes);
395
0
    case 4:
396
0
        return image_flip4_procs[bits_per_sample]
397
0
            (buffer, planes, offset, nbytes);
398
0
    default:
399
0
        if (num_planes < 0)
400
0
            return -1;
401
0
        return image_flipN_procs[bits_per_sample]
402
0
            (buffer, planes, offset, nbytes, num_planes, bits_per_sample);
403
0
    }
404
0
}