Coverage Report

Created: 2025-06-13 06:49

/src/leptonica/src/rotateorth.c
Line
Count
Source (jump to first uncovered line)
1
/*====================================================================*
2
 -  Copyright (C) 2001 Leptonica.  All rights reserved.
3
 -
4
 -  Redistribution and use in source and binary forms, with or without
5
 -  modification, are permitted provided that the following conditions
6
 -  are met:
7
 -  1. Redistributions of source code must retain the above copyright
8
 -     notice, this list of conditions and the following disclaimer.
9
 -  2. Redistributions in binary form must reproduce the above
10
 -     copyright notice, this list of conditions and the following
11
 -     disclaimer in the documentation and/or other materials
12
 -     provided with the distribution.
13
 -
14
 -  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15
 -  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16
 -  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17
 -  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ANY
18
 -  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19
 -  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20
 -  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21
 -  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22
 -  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23
 -  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
 -  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
 *====================================================================*/
26
27
/*!
28
 * \file rotateorth.c
29
 * <pre>
30
 *
31
 *      Top-level rotation by multiples of 90 degrees
32
 *            PIX             *pixRotateOrth()
33
 *
34
 *      180-degree rotation
35
 *            PIX             *pixRotate180()
36
 *
37
 *      90-degree rotation (both directions)
38
 *            PIX             *pixRotate90()
39
 *
40
 *      Left-right flip
41
 *            PIX             *pixFlipLR()
42
 *
43
 *      Top-bottom flip
44
 *            PIX             *pixFlipTB()
45
 *
46
 *      Byte reverse tables
47
 *            static l_uint8  *makeReverseByteTab1()
48
 *            static l_uint8  *makeReverseByteTab2()
49
 *            static l_uint8  *makeReverseByteTab4()
50
 * </pre>
51
 */
52
53
#ifdef HAVE_CONFIG_H
54
#include <config_auto.h>
55
#endif  /* HAVE_CONFIG_H */
56
57
#include <string.h>
58
#include "allheaders.h"
59
60
static l_uint8 *makeReverseByteTab1(void);
61
static l_uint8 *makeReverseByteTab2(void);
62
static l_uint8 *makeReverseByteTab4(void);
63
64
/*------------------------------------------------------------------*
65
 *           Top-level rotation by multiples of 90 degrees          *
66
 *------------------------------------------------------------------*/
67
/*!
68
 * \brief   pixRotateOrth()
69
 *
70
 * \param[in]    pixs       all depths
71
 * \param[in]    quads      0-3; number of 90 degree cw rotations
72
 * \return  pixd, or NULL on error
73
 */
74
PIX *
75
pixRotateOrth(PIX     *pixs,
76
              l_int32  quads)
77
0
{
78
0
    if (!pixs)
79
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
80
0
    if (quads < 0 || quads > 3)
81
0
        return (PIX *)ERROR_PTR("quads not in {0,1,2,3}", __func__, NULL);
82
83
0
    if (quads == 0)
84
0
        return pixCopy(NULL, pixs);
85
0
    else if (quads == 1)
86
0
        return pixRotate90(pixs, 1);
87
0
    else if (quads == 2)
88
0
        return pixRotate180(NULL, pixs);
89
0
    else /* quads == 3 */
90
0
        return pixRotate90(pixs, -1);
91
0
}
92
93
94
/*------------------------------------------------------------------*
95
 *                          180 degree rotation                     *
96
 *------------------------------------------------------------------*/
97
/*!
98
 * \brief   pixRotate180()
99
 *
100
 * \param[in]    pixd    [optional]; can be null, equal to pixs,
101
 *                       or different from pixs
102
 * \param[in]    pixs    all depths
103
 * \return  pixd, or NULL on error
104
 *
105
 * <pre>
106
 * Notes:
107
 *      (1) This does a 180 rotation of the image about the center,
108
 *          which is equivalent to a left-right flip about a vertical
109
 *          line through the image center, followed by a top-bottom
110
 *          flip about a horizontal line through the image center.
111
 *      (2) There are 3 cases for input:
112
 *          (a) pixd == null (creates a new pixd)
113
 *          (b) pixd == pixs (in-place operation)
114
 *          (c) pixd != pixs (existing pixd)
115
 *      (3) For clarity, use these three patterns, respectively:
116
 *          (a) pixd = pixRotate180(NULL, pixs);
117
 *          (b) pixRotate180(pixs, pixs);
118
 *          (c) pixRotate180(pixd, pixs);
119
 * </pre>
120
 */
121
PIX *
122
pixRotate180(PIX  *pixd,
123
             PIX  *pixs)
124
0
{
125
0
l_int32  d;
126
127
0
    if (!pixs)
128
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
129
0
    d = pixGetDepth(pixs);
130
0
    if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
131
0
        return (PIX *)ERROR_PTR("pixs not in {1,2,4,8,16,32} bpp",
132
0
                                __func__, NULL);
133
134
        /* Prepare pixd for in-place operation */
135
0
    if ((pixd = pixCopy(pixd, pixs)) == NULL)
136
0
        return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
137
138
0
    pixFlipLR(pixd, pixd);
139
0
    pixFlipTB(pixd, pixd);
140
0
    return pixd;
141
0
}
142
143
144
/*------------------------------------------------------------------*
145
 *                           90 degree rotation                     *
146
 *------------------------------------------------------------------*/
147
/*!
148
 * \brief   pixRotate90()
149
 *
150
 * \param[in]    pixs         all depths
151
 * \param[in]    direction    clockwise = 1, counterclockwise = -1
152
 * \return  pixd, or NULL on error
153
 *
154
 * <pre>
155
 * Notes:
156
 *      (1) This does a 90 degree rotation of the image about the center,
157
 *          either cw or ccw, returning a new pix.
158
 *      (2) The direction must be either 1 (cw) or -1 (ccw).
159
 * </pre>
160
 */
161
PIX *
162
pixRotate90(PIX     *pixs,
163
            l_int32  direction)
164
0
{
165
0
l_int32    wd, hd, d, wpls, wpld;
166
0
l_int32    i, j, k, m, iend, nswords;
167
0
l_uint32   val, word;
168
0
l_uint32  *lines, *datas, *lined, *datad;
169
0
PIX       *pixd;
170
171
0
    if (!pixs)
172
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
173
0
    pixGetDimensions(pixs, &hd, &wd, &d);  /* note: reversed */
174
0
    if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
175
0
        return (PIX *)ERROR_PTR("pixs not in {1,2,4,8,16,32} bpp",
176
0
                                __func__, NULL);
177
0
    if (direction != 1 && direction != -1)
178
0
        return (PIX *)ERROR_PTR("invalid direction", __func__, NULL);
179
180
0
    if ((pixd = pixCreate(wd, hd, d)) == NULL)
181
0
        return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
182
0
    pixCopyColormap(pixd, pixs);
183
0
    pixCopyResolution(pixd, pixs);
184
0
    pixCopyInputFormat(pixd, pixs);
185
0
    pixCopySpp(pixd, pixs);
186
187
0
    datas = pixGetData(pixs);
188
0
    wpls = pixGetWpl(pixs);
189
0
    datad = pixGetData(pixd);
190
0
    wpld = pixGetWpl(pixd);
191
192
0
    if (direction == 1) {  /* clockwise */
193
0
        switch (d)
194
0
        {
195
0
            case 32:
196
0
                for (i = 0; i < hd; i++) {
197
0
                    lined = datad + i * wpld;
198
0
                    lines = datas + (wd - 1) * wpls;
199
0
                    for (j = 0; j < wd; j++) {
200
0
                        lined[j] = lines[i];
201
0
                        lines -= wpls;
202
0
                    }
203
0
                }
204
0
                break;
205
0
            case 16:
206
0
                for (i = 0; i < hd; i++) {
207
0
                    lined = datad + i * wpld;
208
0
                    lines = datas + (wd - 1) * wpls;
209
0
                    for (j = 0; j < wd; j++) {
210
0
                        if ((val = GET_DATA_TWO_BYTES(lines, i)))
211
0
                            SET_DATA_TWO_BYTES(lined, j, val);
212
0
                        lines -= wpls;
213
0
                    }
214
0
                }
215
0
                break;
216
0
            case 8:
217
0
                for (i = 0; i < hd; i++) {
218
0
                    lined = datad + i * wpld;
219
0
                    lines = datas + (wd - 1) * wpls;
220
0
                    for (j = 0; j < wd; j++) {
221
0
                        if ((val = GET_DATA_BYTE(lines, i)))
222
0
                            SET_DATA_BYTE(lined, j, val);
223
0
                        lines -= wpls;
224
0
                    }
225
0
                }
226
0
                break;
227
0
            case 4:
228
0
                for (i = 0; i < hd; i++) {
229
0
                    lined = datad + i * wpld;
230
0
                    lines = datas + (wd - 1) * wpls;
231
0
                    for (j = 0; j < wd; j++) {
232
0
                        if ((val = GET_DATA_QBIT(lines, i)))
233
0
                            SET_DATA_QBIT(lined, j, val);
234
0
                        lines -= wpls;
235
0
                    }
236
0
                }
237
0
                break;
238
0
            case 2:
239
0
                for (i = 0; i < hd; i++) {
240
0
                    lined = datad + i * wpld;
241
0
                    lines = datas + (wd - 1) * wpls;
242
0
                    for (j = 0; j < wd; j++) {
243
0
                        if ((val = GET_DATA_DIBIT(lines, i)))
244
0
                            SET_DATA_DIBIT(lined, j, val);
245
0
                        lines -= wpls;
246
0
                    }
247
0
                }
248
0
                break;
249
0
            case 1:
250
0
                nswords = hd / 32;
251
0
                for (j = 0; j < wd; j++) {
252
0
                    lined = datad;
253
0
                    lines = datas + (wd - 1 - j) * wpls;
254
0
                    for (k = 0; k < nswords; k++) {
255
0
                        word = lines[k];
256
0
                        if (!word) {
257
0
                            lined += 32 * wpld;
258
0
                            continue;
259
0
                        } else {
260
0
                            iend = 32 * (k + 1);
261
0
                            for (m = 0, i = 32 * k; i < iend; i++, m++) {
262
0
                                if ((word << m) & 0x80000000)
263
0
                                    SET_DATA_BIT(lined, j);
264
0
                                lined += wpld;
265
0
                            }
266
0
                        }
267
0
                    }
268
0
                    for (i = 32 * nswords; i < hd; i++) {
269
0
                        if (GET_DATA_BIT(lines, i))
270
0
                            SET_DATA_BIT(lined, j);
271
0
                        lined += wpld;
272
0
                    }
273
0
                }
274
0
                break;
275
0
            default:
276
0
                pixDestroy(&pixd);
277
0
                L_ERROR("illegal depth: %d\n", __func__, d);
278
0
                break;
279
0
        }
280
0
    } else  {     /* direction counter-clockwise */
281
0
        switch (d)
282
0
        {
283
0
            case 32:
284
0
                for (i = 0; i < hd; i++) {
285
0
                    lined = datad + i * wpld;
286
0
                    lines = datas;
287
0
                    for (j = 0; j < wd; j++) {
288
0
                        lined[j] = lines[hd - 1 - i];
289
0
                        lines += wpls;
290
0
                    }
291
0
                }
292
0
                break;
293
0
            case 16:
294
0
                for (i = 0; i < hd; i++) {
295
0
                    lined = datad + i * wpld;
296
0
                    lines = datas;
297
0
                    for (j = 0; j < wd; j++) {
298
0
                        if ((val = GET_DATA_TWO_BYTES(lines, hd - 1 - i)))
299
0
                            SET_DATA_TWO_BYTES(lined, j, val);
300
0
                        lines += wpls;
301
0
                    }
302
0
                }
303
0
                break;
304
0
            case 8:
305
0
                for (i = 0; i < hd; i++) {
306
0
                    lined = datad + i * wpld;
307
0
                    lines = datas;
308
0
                    for (j = 0; j < wd; j++) {
309
0
                        if ((val = GET_DATA_BYTE(lines, hd - 1 - i)))
310
0
                            SET_DATA_BYTE(lined, j, val);
311
0
                        lines += wpls;
312
0
                    }
313
0
                }
314
0
                break;
315
0
            case 4:
316
0
                for (i = 0; i < hd; i++) {
317
0
                    lined = datad + i * wpld;
318
0
                    lines = datas;
319
0
                    for (j = 0; j < wd; j++) {
320
0
                        if ((val = GET_DATA_QBIT(lines, hd - 1 - i)))
321
0
                            SET_DATA_QBIT(lined, j, val);
322
0
                        lines += wpls;
323
0
                    }
324
0
                }
325
0
                break;
326
0
            case 2:
327
0
                for (i = 0; i < hd; i++) {
328
0
                    lined = datad + i * wpld;
329
0
                    lines = datas;
330
0
                    for (j = 0; j < wd; j++) {
331
0
                        if ((val = GET_DATA_DIBIT(lines, hd - 1 - i)))
332
0
                            SET_DATA_DIBIT(lined, j, val);
333
0
                        lines += wpls;
334
0
                    }
335
0
                }
336
0
                break;
337
0
            case 1:
338
0
                nswords = hd / 32;
339
0
                for (j = 0; j < wd; j++) {
340
0
                    lined = datad + (hd - 1) * wpld;
341
0
                    lines = datas + (wd - 1 - j) * wpls;
342
0
                    for (k = 0; k < nswords; k++) {
343
0
                        word = lines[k];
344
0
                        if (!word) {
345
0
                            lined -= 32 * wpld;
346
0
                            continue;
347
0
                        } else {
348
0
                            iend = 32 * (k + 1);
349
0
                            for (m = 0, i = 32 * k; i < iend; i++, m++) {
350
0
                                if ((word << m) & 0x80000000)
351
0
                                    SET_DATA_BIT(lined, wd - 1 - j);
352
0
                                lined -= wpld;
353
0
                            }
354
0
                        }
355
0
                    }
356
0
                    for (i = 32 * nswords; i < hd; i++) {
357
0
                        if (GET_DATA_BIT(lines, i))
358
0
                            SET_DATA_BIT(lined, wd - 1 - j);
359
0
                        lined -= wpld;
360
0
                    }
361
0
                }
362
0
                break;
363
0
            default:
364
0
                pixDestroy(&pixd);
365
0
                L_ERROR("illegal depth: %d\n", __func__, d);
366
0
                break;
367
0
        }
368
0
    }
369
370
0
    return pixd;
371
0
}
372
373
374
/*------------------------------------------------------------------*
375
 *                            Left-right flip                       *
376
 *------------------------------------------------------------------*/
377
/*!
378
 * \brief   pixFlipLR()
379
 *
380
 * \param[in]    pixd    [optional]; can be null, equal to pixs,
381
 *                       or different from pixs
382
 * \param[in]    pixs    all depths
383
 * \return  pixd, or NULL on error
384
 *
385
 * <pre>
386
 * Notes:
387
 *      (1) This does a left-right flip of the image, which is
388
 *          equivalent to a rotation out of the plane about a
389
 *          vertical line through the image center.
390
 *      (2) There are 3 cases for input:
391
 *          (a) pixd == null (creates a new pixd)
392
 *          (b) pixd == pixs (in-place operation)
393
 *          (c) pixd != pixs (existing pixd)
394
 *      (3) For clarity, use these three patterns, respectively:
395
 *          (a) pixd = pixFlipLR(NULL, pixs);
396
 *          (b) pixFlipLR(pixs, pixs);
397
 *          (c) pixFlipLR(pixd, pixs);
398
 *      (4) If an existing pixd is not the same size as pixs, the
399
 *          image data will be reallocated.
400
 *      (5) The pixel access routines allow a trivial implementation.
401
 *          However, for d < 8, it is more efficient to right-justify
402
 *          each line to a 32-bit boundary and then extract bytes and
403
 *          do pixel reversing.   In those cases, as in the 180 degree
404
 *          rotation, we right-shift the data (if necessary) to
405
 *          right-justify on the 32 bit boundary, and then read the
406
 *          bytes off each raster line in reverse order, reversing
407
 *          the pixels in each byte using a table.  These functions
408
 *          for 1, 2 and 4 bpp were tested against the "trivial"
409
 *          version (shown here for 4 bpp):
410
 *              for (i = 0; i < h; i++) {
411
 *                  line = data + i * wpl;
412
 *                  memcpy(buffer, line, bpl);
413
 *                    for (j = 0; j < w; j++) {
414
 *                      val = GET_DATA_QBIT(buffer, w - 1 - j);
415
 *                        SET_DATA_QBIT(line, j, val);
416
 *                  }
417
 *              }
418
 * </pre>
419
 */
420
PIX *
421
pixFlipLR(PIX  *pixd,
422
          PIX  *pixs)
423
0
{
424
0
l_uint8   *tab;
425
0
l_int32    w, h, d, wpl;
426
0
l_int32    extra, shift, databpl, bpl, i, j;
427
0
l_uint32   val;
428
0
l_uint32  *line, *data, *buffer;
429
430
0
    if (!pixs)
431
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
432
0
    pixGetDimensions(pixs, &w, &h, &d);
433
0
    if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
434
0
        return (PIX *)ERROR_PTR("pixs not in {1,2,4,8,16,32} bpp",
435
0
                                __func__, NULL);
436
437
        /* Prepare pixd for in-place operation */
438
0
    if ((pixd = pixCopy(pixd, pixs)) == NULL)
439
0
        return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
440
441
0
    data = pixGetData(pixd);
442
0
    wpl = pixGetWpl(pixd);
443
0
    switch (d)
444
0
    {
445
0
    case 1:
446
0
        tab = makeReverseByteTab1();
447
0
        break;
448
0
    case 2:
449
0
        tab = makeReverseByteTab2();
450
0
        break;
451
0
    case 4:
452
0
        tab = makeReverseByteTab4();
453
0
        break;
454
0
    default:
455
0
        tab = NULL;
456
0
        break;
457
0
    }
458
459
        /* Possibly inplace assigning return val, so on failure return pixd */
460
0
    if ((buffer = (l_uint32 *)LEPT_CALLOC(wpl, sizeof(l_uint32))) == NULL) {
461
0
        if (tab) LEPT_FREE(tab);
462
0
        return (PIX *)ERROR_PTR("buffer not made", __func__, pixd);
463
0
    }
464
465
0
    bpl = 4 * wpl;
466
0
    switch (d)
467
0
    {
468
0
        case 32:
469
0
            for (i = 0; i < h; i++) {
470
0
                line = data + i * wpl;
471
0
                memcpy(buffer, line, bpl);
472
0
                for (j = 0; j < w; j++)
473
0
                    line[j] = buffer[w - 1 - j];
474
0
            }
475
0
            break;
476
0
        case 16:
477
0
            for (i = 0; i < h; i++) {
478
0
                line = data + i * wpl;
479
0
                memcpy(buffer, line, bpl);
480
0
                for (j = 0; j < w; j++) {
481
0
                    val = GET_DATA_TWO_BYTES(buffer, w - 1 - j);
482
0
                    SET_DATA_TWO_BYTES(line, j, val);
483
0
                }
484
0
            }
485
0
            break;
486
0
        case 8:
487
0
            for (i = 0; i < h; i++) {
488
0
                line = data + i * wpl;
489
0
                memcpy(buffer, line, bpl);
490
0
                for (j = 0; j < w; j++) {
491
0
                    val = GET_DATA_BYTE(buffer, w - 1 - j);
492
0
                    SET_DATA_BYTE(line, j, val);
493
0
                }
494
0
            }
495
0
            break;
496
0
        case 4:
497
0
            extra = (w * d) & 31;
498
0
            if (extra)
499
0
                shift = 8 - extra / 4;
500
0
            else
501
0
                shift = 0;
502
0
            if (shift)
503
0
                rasteropHipLow(data, h, d, wpl, 0, h, shift);
504
505
0
            databpl = (w + 1) / 2;
506
0
            for (i = 0; i < h; i++) {
507
0
                line = data + i * wpl;
508
0
                memcpy(buffer, line, bpl);
509
0
                for (j = 0; j < databpl; j++) {
510
0
                    val = GET_DATA_BYTE(buffer, bpl - 1 - j);
511
0
                    SET_DATA_BYTE(line, j, tab[val]);
512
0
                }
513
0
            }
514
0
            break;
515
0
        case 2:
516
0
            extra = (w * d) & 31;
517
0
            if (extra)
518
0
                shift = 16 - extra / 2;
519
0
            else
520
0
                shift = 0;
521
0
            if (shift)
522
0
                rasteropHipLow(data, h, d, wpl, 0, h, shift);
523
524
0
            databpl = (w + 3) / 4;
525
0
            for (i = 0; i < h; i++) {
526
0
                line = data + i * wpl;
527
0
                memcpy(buffer, line, bpl);
528
0
                for (j = 0; j < databpl; j++) {
529
0
                    val = GET_DATA_BYTE(buffer, bpl - 1 - j);
530
0
                    SET_DATA_BYTE(line, j, tab[val]);
531
0
                }
532
0
            }
533
0
            break;
534
0
        case 1:
535
0
            extra = (w * d) & 31;
536
0
            if (extra)
537
0
                shift = 32 - extra;
538
0
            else
539
0
                shift = 0;
540
0
            if (shift)
541
0
                rasteropHipLow(data, h, d, wpl, 0, h, shift);
542
543
0
            databpl = (w + 7) / 8;
544
0
            for (i = 0; i < h; i++) {
545
0
                line = data + i * wpl;
546
0
                memcpy(buffer, line, bpl);
547
0
                for (j = 0; j < databpl; j++) {
548
0
                    val = GET_DATA_BYTE(buffer, bpl - 1 - j);
549
0
                    SET_DATA_BYTE(line, j, tab[val]);
550
0
                }
551
0
            }
552
0
            break;
553
0
        default:
554
0
            pixDestroy(&pixd);
555
0
            L_ERROR("illegal depth: %d\n", __func__, d);
556
0
            break;
557
0
    }
558
559
0
    LEPT_FREE(buffer);
560
0
    if (tab) LEPT_FREE(tab);
561
0
    return pixd;
562
0
}
563
564
565
/*------------------------------------------------------------------*
566
 *                            Top-bottom flip                       *
567
 *------------------------------------------------------------------*/
568
/*!
569
 * \brief   pixFlipTB()
570
 *
571
 * \param[in]    pixd   [optional]; can be null, equal to pixs,
572
 *                      or different from pixs
573
 * \param[in]    pixs   all depths
574
 * \return  pixd, or NULL on error
575
 *
576
 * <pre>
577
 * Notes:
578
 *      (1) This does a top-bottom flip of the image, which is
579
 *          equivalent to a rotation out of the plane about a
580
 *          horizontal line through the image center.
581
 *      (2) There are 3 cases for input:
582
 *          (a) pixd == null (creates a new pixd)
583
 *          (b) pixd == pixs (in-place operation)
584
 *          (c) pixd != pixs (existing pixd)
585
 *      (3) For clarity, use these three patterns, respectively:
586
 *          (a) pixd = pixFlipTB(NULL, pixs);
587
 *          (b) pixFlipTB(pixs, pixs);
588
 *          (c) pixFlipTB(pixd, pixs);
589
 *      (4) If an existing pixd is not the same size as pixs, the
590
 *          image data will be reallocated.
591
 *      (5) This is simple and fast.  We use the memcpy function
592
 *          to do all the work on aligned data, regardless of pixel
593
 *          depth.
594
 * </pre>
595
 */
596
PIX *
597
pixFlipTB(PIX  *pixd,
598
          PIX  *pixs)
599
0
{
600
0
l_int32    h, d, wpl, i, k, h2, bpl;
601
0
l_uint32  *linet, *lineb;
602
0
l_uint32  *data, *buffer;
603
604
0
    if (!pixs)
605
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
606
0
    pixGetDimensions(pixs, NULL, &h, &d);
607
0
    if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
608
0
        return (PIX *)ERROR_PTR("pixs not in {1,2,4,8,16,32} bpp",
609
0
                                __func__, NULL);
610
611
        /* Prepare pixd for in-place operation */
612
0
    if ((pixd = pixCopy(pixd, pixs)) == NULL)
613
0
        return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
614
615
0
    data = pixGetData(pixd);
616
0
    wpl = pixGetWpl(pixd);
617
0
    if ((buffer = (l_uint32 *)LEPT_CALLOC(wpl, sizeof(l_uint32))) == NULL)
618
0
        return (PIX *)ERROR_PTR("buffer not made", __func__, pixd);
619
620
0
    h2 = h / 2;
621
0
    bpl = 4 * wpl;
622
0
    for (i = 0, k = h - 1; i < h2; i++, k--) {
623
0
        linet = data + i * wpl;
624
0
        lineb = data + k * wpl;
625
0
        memcpy(buffer, linet, bpl);
626
0
        memcpy(linet, lineb, bpl);
627
0
        memcpy(lineb, buffer, bpl);
628
0
    }
629
630
0
    LEPT_FREE(buffer);
631
0
    return pixd;
632
0
}
633
634
635
/*------------------------------------------------------------------*
636
 *                      Static byte reverse tables                  *
637
 *------------------------------------------------------------------*/
638
/*!
639
 * \brief   makeReverseByteTab1()
640
 *
641
 *  Notes:
642
 *      (1) This generates an 8 bit lookup table for reversing
643
 *          the order of eight 1-bit pixels.
644
 */
645
static l_uint8 *
646
makeReverseByteTab1(void)
647
0
{
648
0
l_int32   i;
649
0
l_uint8  *tab;
650
651
0
    tab = (l_uint8 *)LEPT_CALLOC(256, sizeof(l_uint8));
652
0
    for (i = 0; i < 256; i++)
653
0
        tab[i] = ((0x80 & i) >> 7) |
654
0
                 ((0x40 & i) >> 5) |
655
0
                 ((0x20 & i) >> 3) |
656
0
                 ((0x10 & i) >> 1) |
657
0
                 ((0x08 & i) << 1) |
658
0
                 ((0x04 & i) << 3) |
659
0
                 ((0x02 & i) << 5) |
660
0
                 ((0x01 & i) << 7);
661
0
    return tab;
662
0
}
663
664
665
/*!
666
 * \brief   makeReverseByteTab2()
667
 *
668
 *  Notes:
669
 *      (1) This generates an 8 bit lookup table for reversing
670
 *          the order of four 2-bit pixels.
671
 */
672
static l_uint8 *
673
makeReverseByteTab2(void)
674
0
{
675
0
l_int32   i;
676
0
l_uint8  *tab;
677
678
0
    tab = (l_uint8 *)LEPT_CALLOC(256, sizeof(l_uint8));
679
0
    for (i = 0; i < 256; i++)
680
0
        tab[i] = ((0xc0 & i) >> 6) |
681
0
                 ((0x30 & i) >> 2) |
682
0
                 ((0x0c & i) << 2) |
683
0
                 ((0x03 & i) << 6);
684
0
    return tab;
685
0
}
686
687
688
/*!
689
 * \brief   makeReverseByteTab4()
690
 *
691
 *  Notes:
692
 *      (1) This generates an 8 bit lookup table for reversing
693
 *          the order of two 4-bit pixels.
694
 */
695
static l_uint8 *
696
makeReverseByteTab4(void)
697
0
{
698
0
l_int32   i;
699
0
l_uint8  *tab;
700
701
0
    tab = (l_uint8 *)LEPT_CALLOC(256, sizeof(l_uint8));
702
0
    for (i = 0; i < 256; i++)
703
0
        tab[i] = ((0xf0 & i) >> 4) | ((0x0f & i) << 4);
704
0
    return tab;
705
0
}