Coverage Report

Created: 2025-01-28 06:27

/src/leptonica/src/pix2.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 pix2.c
29
 * <pre>
30
 *
31
 *    This file has these basic operations:
32
 *
33
 *      (1) Get and set: individual pixels, full image, rectangular region,
34
 *          pad pixels, border pixels, and color components for RGB
35
 *      (2) Add and remove border pixels
36
 *      (3) Endian byte swaps
37
 *      (4) Simple method for byte-processing images (instead of words)
38
 *
39
 *      Pixel poking
40
 *           l_int32     pixGetPixel()
41
 *           l_int32     pixSetPixel()
42
 *           l_int32     pixGetRGBPixel()
43
 *           l_int32     pixSetRGBPixel()
44
 *           l_int32     pixSetCmapPixel()
45
 *           l_int32     pixGetRandomPixel()
46
 *           l_int32     pixClearPixel()
47
 *           l_int32     pixFlipPixel()
48
 *           void        setPixelLow()
49
 *
50
 *      Find black or white value
51
 *           l_int32     pixGetBlackOrWhiteVal()
52
 *
53
 *      Full image clear/set/set-to-arbitrary-value
54
 *           l_int32     pixClearAll()
55
 *           l_int32     pixSetAll()
56
 *           l_int32     pixSetAllGray()
57
 *           l_int32     pixSetAllArbitrary()
58
 *           l_int32     pixSetBlackOrWhite()
59
 *           l_int32     pixSetComponentArbitrary()
60
 *
61
 *      Rectangular region clear/set/set-to-arbitrary-value/blend
62
 *           l_int32     pixClearInRect()
63
 *           l_int32     pixSetInRect()
64
 *           l_int32     pixSetInRectArbitrary()
65
 *           l_int32     pixBlendInRect()
66
 *
67
 *      Set pad bits
68
 *           l_int32     pixSetPadBits()
69
 *           l_int32     pixSetPadBitsBand()
70
 *
71
 *      Assign border pixels
72
 *           l_int32     pixSetOrClearBorder()
73
 *           l_int32     pixSetBorderVal()
74
 *           l_int32     pixSetBorderRingVal()
75
 *           l_int32     pixSetMirroredBorder()
76
 *           PIX        *pixCopyBorder()
77
 *
78
 *      Add and remove border
79
 *           PIX        *pixAddBorder()
80
 *           PIX        *pixAddBlackOrWhiteBorder()
81
 *           PIX        *pixAddBorderGeneral()
82
 *           PIX        *pixAddMultipleBlackWhiteBorders()
83
 *           PIX        *pixRemoveBorder()
84
 *           PIX        *pixRemoveBorderGeneral()
85
 *           PIX        *pixRemoveBorderToSize()
86
 *           PIX        *pixAddMirroredBorder()
87
 *           PIX        *pixAddRepeatedBorder()
88
 *           PIX        *pixAddMixedBorder()
89
 *           PIX        *pixAddContinuedBorder()
90
 *
91
 *      Helper functions using alpha
92
 *           l_int32     pixShiftAndTransferAlpha()
93
 *           PIX        *pixDisplayLayersRGBA()
94
 *
95
 *      Color sample setting and extraction
96
 *           PIX        *pixCreateRGBImage()
97
 *           PIX        *pixGetRGBComponent()
98
 *           l_int32     pixSetRGBComponent()
99
 *           PIX        *pixGetRGBComponentCmap()
100
 *           l_int32     pixCopyRGBComponent()
101
 *           l_int32     composeRGBPixel()
102
 *           l_int32     composeRGBAPixel()
103
 *           void        extractRGBValues()
104
 *           void        extractRGBAValues()
105
 *           l_int32     extractMinMaxComponent()
106
 *           l_int32     pixGetRGBLine()
107
 *
108
 *      Raster line pixel setter
109
 *           l_int32     setLineDataVal()
110
 *
111
 *      Conversion between big and little endians
112
 *           PIX        *pixEndianByteSwapNew()
113
 *           l_int32     pixEndianByteSwap()
114
 *           l_int32     lineEndianByteSwap()
115
 *           PIX        *pixEndianTwoByteSwapNew()
116
 *           l_int32     pixEndianTwoByteSwap()
117
 *
118
 *      Extract raster data as binary string
119
 *           l_int32     pixGetRasterData()
120
 *
121
 *      Test alpha component opaqueness
122
 *           l_int32     pixAlphaIsOpaque()
123
 *
124
 *      Infer resolution from image size
125
 *           l_int32     pixInferResolution()
126
 *
127
 *      Setup helpers for 8 bpp byte processing
128
 *           l_uint8   **pixSetupByteProcessing()
129
 *           l_int32     pixCleanupByteProcessing()
130
 *
131
 *      Setting parameters for antialias masking with alpha transforms
132
 *           void        l_setAlphaMaskBorder()
133
 * </pre>
134
 */
135
136
#ifdef HAVE_CONFIG_H
137
#include <config_auto.h>
138
#endif  /* HAVE_CONFIG_H */
139
140
#include <string.h>
141
#include "allheaders.h"
142
#include "pix_internal.h"
143
144
static const l_uint32 rmask32[] = {0x0,
145
    0x00000001, 0x00000003, 0x00000007, 0x0000000f,
146
    0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
147
    0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
148
    0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
149
    0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
150
    0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
151
    0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
152
    0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff};
153
154
    /* This is a global that determines the default 8 bpp alpha mask values
155
     * for rings at distance 1 and 2 from the border.  Declare extern
156
     * to use.  To change the values, use l_setAlphaMaskBorder(). */
157
LEPT_DLL l_float32  AlphaMaskBorderVals[2] = {0.0, 0.5};
158
159
160
#ifndef  NO_CONSOLE_IO
161
#define  DEBUG_SERIALIZE        0
162
#endif  /* ~NO_CONSOLE_IO */
163
164
165
/*-------------------------------------------------------------*
166
 *                         Pixel poking                        *
167
 *-------------------------------------------------------------*/
168
/*!
169
 * \brief   pixGetPixel()
170
 *
171
 * \param[in]    pix
172
 * \param[in]    x,y    pixel coords
173
 * \param[out]   pval   pixel value
174
 * \return  0 if OK; 1 or 2 on error
175
 *
176
 * <pre>
177
 * Notes:
178
 *      (1) This returns the value in the data array.  If the pix is
179
 *          colormapped, it returns the colormap index, not the rgb value.
180
 *      (2) Because of the function overhead and the parameter checking,
181
 *          this is much slower than using the GET_DATA_*() macros directly.
182
 *          Speed on a 1 Mpixel RGB image, using a 3 GHz machine:
183
 *            * pixGet/pixSet: ~25 Mpix/sec
184
 *            * GET_DATA/SET_DATA: ~350 MPix/sec
185
 *          If speed is important and you're doing random access into
186
 *          the pix, use pixGetLinePtrs() and the array access macros.
187
 *      (3) If the point is outside the image, this returns an error (2),
188
 *          with 0 in %pval.  To avoid spamming output, it fails silently.
189
 * </pre>
190
 */
191
l_ok
192
pixGetPixel(PIX       *pix,
193
            l_int32    x,
194
            l_int32    y,
195
            l_uint32  *pval)
196
158k
{
197
158k
l_int32    w, h, d, wpl, val;
198
158k
l_uint32  *line, *data;
199
200
158k
    if (!pval)
201
0
        return ERROR_INT("&val not defined", __func__, 1);
202
158k
    *pval = 0;
203
158k
    if (!pix)
204
0
        return ERROR_INT("pix not defined", __func__, 1);
205
206
158k
    pixGetDimensions(pix, &w, &h, &d);
207
158k
    if (x < 0 || x >= w || y < 0 || y >= h)
208
73
        return 2;
209
210
158k
    wpl = pixGetWpl(pix);
211
158k
    data = pixGetData(pix);
212
158k
    line = data + y * wpl;
213
158k
    switch (d)
214
158k
    {
215
683
    case 1:
216
683
        val = GET_DATA_BIT(line, x);
217
683
        break;
218
0
    case 2:
219
0
        val = GET_DATA_DIBIT(line, x);
220
0
        break;
221
0
    case 4:
222
0
        val = GET_DATA_QBIT(line, x);
223
0
        break;
224
153k
    case 8:
225
153k
        val = GET_DATA_BYTE(line, x);
226
153k
        break;
227
0
    case 16:
228
0
        val = GET_DATA_TWO_BYTES(line, x);
229
0
        break;
230
4.79k
    case 32:
231
4.79k
        val = line[x];
232
4.79k
        break;
233
0
    default:
234
0
        return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", __func__, 1);
235
158k
    }
236
237
158k
    *pval = val;
238
158k
    return 0;
239
158k
}
240
241
242
/*!
243
 * \brief   pixSetPixel()
244
 *
245
 * \param[in]    pix
246
 * \param[in]    x,y   pixel coords
247
 * \param[in]    val   value to be inserted
248
 * \return  0 if OK; 1 or 2 on error
249
 *
250
 * <pre>
251
 * Notes:
252
 *      (1) Warning: the input value is not checked for overflow with respect
253
 *          the the depth of %pix, and the sign bit (if any) is ignored.
254
 *          * For d == 1, %val > 0 sets the bit on.
255
 *          * For d == 2, 4, 8 and 16, %val is masked to the maximum allowable
256
 *            pixel value, and any (invalid) higher order bits are discarded.
257
 *      (2) See pixGetPixel() for information on performance.
258
 *      (3) If the point is outside the image, this returns an error (2),
259
 *          with 0 in %pval.  To avoid spamming output, it fails silently.
260
 * </pre>
261
 */
262
l_ok
263
pixSetPixel(PIX      *pix,
264
            l_int32   x,
265
            l_int32   y,
266
            l_uint32  val)
267
153k
{
268
153k
l_int32    w, h, d, wpl;
269
153k
l_uint32  *line, *data;
270
271
153k
    if (!pix)
272
0
        return ERROR_INT("pix not defined", __func__, 1);
273
153k
    pixGetDimensions(pix, &w, &h, &d);
274
153k
    if (x < 0 || x >= w || y < 0 || y >= h)
275
73
        return 2;
276
277
153k
    data = pixGetData(pix);
278
153k
    wpl = pixGetWpl(pix);
279
153k
    line = data + y * wpl;
280
153k
    switch (d)
281
153k
    {
282
226
    case 1:
283
226
        if (val)
284
226
            SET_DATA_BIT(line, x);
285
0
        else
286
0
            CLEAR_DATA_BIT(line, x);
287
226
        break;
288
0
    case 2:
289
0
        SET_DATA_DIBIT(line, x, val);
290
0
        break;
291
0
    case 4:
292
0
        SET_DATA_QBIT(line, x, val);
293
0
        break;
294
0
    case 8:
295
0
        SET_DATA_BYTE(line, x, val);
296
0
        break;
297
0
    case 16:
298
0
        SET_DATA_TWO_BYTES(line, x, val);
299
0
        break;
300
153k
    case 32:
301
153k
        line[x] = val;
302
153k
        break;
303
0
    default:
304
0
        return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", __func__, 1);
305
153k
    }
306
307
153k
    return 0;
308
153k
}
309
310
311
/*!
312
 * \brief   pixGetRGBPixel()
313
 *
314
 * \param[in]    pix    32 bpp rgb, not colormapped
315
 * \param[in]    x,y    pixel coords
316
 * \param[out]   prval  [optional] red component
317
 * \param[out]   pgval  [optional] green component
318
 * \param[out]   pbval  [optional] blue component
319
 * \return  0 if OK; 1 or 2 on error
320
 *
321
 * <pre>
322
 * Notes:
323
 *      (1) If the point is outside the image, this returns an error (2),
324
 *          with 0 in %pval.  To avoid spamming output, it fails silently.
325
 * </pre>
326
 */
327
l_ok
328
pixGetRGBPixel(PIX      *pix,
329
               l_int32   x,
330
               l_int32   y,
331
               l_int32  *prval,
332
               l_int32  *pgval,
333
               l_int32  *pbval)
334
0
{
335
0
l_int32    w, h, d, wpl;
336
0
l_uint32  *data, *ppixel;
337
338
0
    if (prval) *prval = 0;
339
0
    if (pgval) *pgval = 0;
340
0
    if (pbval) *pbval = 0;
341
0
    if (!prval && !pgval && !pbval)
342
0
        return ERROR_INT("no output requested", __func__, 1);
343
0
    if (!pix)
344
0
        return ERROR_INT("pix not defined", __func__, 1);
345
0
    pixGetDimensions(pix, &w, &h, &d);
346
0
    if (d != 32)
347
0
        return ERROR_INT("pix not 32 bpp", __func__, 1);
348
0
    if (x < 0 || x >= w || y < 0 || y >= h)
349
0
        return 2;
350
351
0
    wpl = pixGetWpl(pix);
352
0
    data = pixGetData(pix);
353
0
    ppixel = data + y * wpl + x;
354
0
    if (prval) *prval = GET_DATA_BYTE(ppixel, COLOR_RED);
355
0
    if (pgval) *pgval = GET_DATA_BYTE(ppixel, COLOR_GREEN);
356
0
    if (pbval) *pbval = GET_DATA_BYTE(ppixel, COLOR_BLUE);
357
0
    return 0;
358
0
}
359
360
361
/*!
362
 * \brief   pixSetRGBPixel()
363
 *
364
 * \param[in]    pix    32 bpp rgb
365
 * \param[in]    x,y    pixel coords
366
 * \param[in]    rval   red component
367
 * \param[in]    gval   green component
368
 * \param[in]    bval   blue component
369
 * \return  0 if OK; 1 or 2 on error
370
 *
371
 * <pre>
372
 * Notes:
373
 *      (1) If the point is outside the image, this returns an error (2),
374
 *          and to avoid spamming output, it fails silently.
375
 * </pre>
376
 */
377
l_ok
378
pixSetRGBPixel(PIX     *pix,
379
               l_int32  x,
380
               l_int32  y,
381
               l_int32  rval,
382
               l_int32  gval,
383
               l_int32  bval)
384
0
{
385
0
l_int32    w, h, d, wpl;
386
0
l_uint32   pixel;
387
0
l_uint32  *data, *line;
388
389
0
    if (!pix)
390
0
        return ERROR_INT("pix not defined", __func__, 1);
391
0
    pixGetDimensions(pix, &w, &h, &d);
392
0
    if (d != 32)
393
0
        return ERROR_INT("pix not 32 bpp", __func__, 1);
394
0
    if (x < 0 || x >= w || y < 0 || y >= h)
395
0
        return 2;
396
397
0
    wpl = pixGetWpl(pix);
398
0
    data = pixGetData(pix);
399
0
    line = data + y * wpl;
400
0
    composeRGBPixel(rval, gval, bval, &pixel);
401
0
    *(line + x) = pixel;
402
0
    return 0;
403
0
}
404
405
406
/*!
407
 * \brief   pixSetCmapPixel()
408
 *
409
 * \param[in]    pix    2, 4 or 8 bpp, colormapped
410
 * \param[in]    x,y    pixel coords
411
 * \param[in]    rval   red component
412
 * \param[in]    gval   green component
413
 * \param[in]    bval   blue component
414
 * \return  0 if OK; 1 or 2 on error
415
 *
416
 * <pre>
417
 * Notes:
418
 *      (1) If the point is outside the image, this returns an error (2),
419
 *          and to avoid spamming output, it fails silently.
420
 *      (2) - If the color already exists, use it.
421
 *          - If the color does not exist in the colormap, it is added
422
 *            if possible.
423
 *          - If there is not room in the colormap for the new color:
424
 *            * if d < 8, return 2 with a warning.
425
 *            * if d == 8, find and use the nearest color.
426
 *      (3) Note that this operation scales with the number of colors
427
 *          in the colormap, and therefore can be very expensive if an
428
 *          attempt is made to set many pixels.  (In that case, it should
429
 *          be implemented with a map:rgb-->index for efficiency.)
430
 *          This is best used with very small images.
431
 * </pre>
432
 */
433
l_ok
434
pixSetCmapPixel(PIX     *pix,
435
                l_int32  x,
436
                l_int32  y,
437
                l_int32  rval,
438
                l_int32  gval,
439
                l_int32  bval)
440
0
{
441
0
l_int32   w, h, d, index;
442
0
PIXCMAP  *cmap;
443
444
0
    if (!pix)
445
0
        return ERROR_INT("pix not defined", __func__, 1);
446
0
    if ((cmap = pixGetColormap(pix)) == NULL)
447
0
        return ERROR_INT("pix is not colormapped", __func__, 1);
448
0
    pixGetDimensions(pix, &w, &h, &d);
449
0
    if (d != 2 && d != 4 && d != 8)
450
0
        return ERROR_INT("pix depth not 2, 4 or 8", __func__, 1);
451
0
    if (x < 0 || x >= w || y < 0 || y >= h)
452
0
        return 2;
453
454
0
    if (d == 8) {  /* always add */
455
0
        pixcmapAddNearestColor(cmap, rval, gval, bval, &index);
456
0
    } else {  /* d < 8 */
457
0
        if (pixcmapAddNewColor(cmap, rval, gval, bval, &index) == 2)
458
0
            return ERROR_INT("colormap is full", __func__, 2);
459
0
    }
460
0
    pixSetPixel(pix, x, y, index);
461
0
    return 0;
462
0
}
463
464
465
/*!
466
 * \brief   pixGetRandomPixel()
467
 *
468
 * \param[in]    pix    any depth; can be colormapped
469
 * \param[out]   pval   [optional] pixel value
470
 * \param[out]   px     [optional] x coordinate chosen; can be null
471
 * \param[out]   py     [optional] y coordinate chosen; can be null
472
 * \return  0 if OK; 1 on error
473
 *
474
 * <pre>
475
 * Notes:
476
 *      (1) If the pix is colormapped, it returns the rgb value.
477
 * </pre>
478
 */
479
l_ok
480
pixGetRandomPixel(PIX       *pix,
481
                  l_uint32  *pval,
482
                  l_int32   *px,
483
                  l_int32   *py)
484
0
{
485
0
l_int32   w, h, x, y, rval, gval, bval;
486
0
l_uint32  val;
487
0
PIXCMAP  *cmap;
488
489
0
    if (pval) *pval = 0;
490
0
    if (px) *px = 0;
491
0
    if (py) *py = 0;
492
0
    if (!pval && !px && !py)
493
0
        return ERROR_INT("no output requested", __func__, 1);
494
0
    if (!pix)
495
0
        return ERROR_INT("pix not defined", __func__, 1);
496
497
0
    pixGetDimensions(pix, &w, &h, NULL);
498
0
    x = rand() % w;
499
0
    y = rand() % h;
500
0
    if (px) *px = x;
501
0
    if (py) *py = y;
502
0
    if (pval) {
503
0
        pixGetPixel(pix, x, y, &val);
504
0
        if ((cmap = pixGetColormap(pix)) != NULL) {
505
0
            pixcmapGetColor(cmap, val, &rval, &gval, &bval);
506
0
            composeRGBPixel(rval, gval, bval, pval);
507
0
        } else {
508
0
            *pval = val;
509
0
        }
510
0
    }
511
512
0
    return 0;
513
0
}
514
515
516
/*!
517
 * \brief   pixClearPixel()
518
 *
519
 * \param[in]    pix   any depth; warning if colormapped
520
 * \param[in]    x,y   pixel coords
521
 * \return  0 if OK; 1 or 2 on error.
522
 *
523
 * <pre>
524
 * Notes:
525
 *      (1) If the point is outside the image, this returns an error (2),
526
 *          with 0 in %pval.  To avoid spamming output, it fails silently.
527
 * </pre>
528
 */
529
l_ok
530
pixClearPixel(PIX     *pix,
531
              l_int32  x,
532
              l_int32  y)
533
0
{
534
0
l_int32    w, h, d, wpl;
535
0
l_uint32  *line, *data;
536
537
0
    if (!pix)
538
0
        return ERROR_INT("pix not defined", __func__, 1);
539
0
    if (pixGetColormap(pix))
540
0
        L_WARNING("cmapped: setting to 0 may not be intended\n", __func__);
541
0
    pixGetDimensions(pix, &w, &h, &d);
542
0
    if (x < 0 || x >= w || y < 0 || y >= h)
543
0
        return 2;
544
545
0
    wpl = pixGetWpl(pix);
546
0
    data = pixGetData(pix);
547
0
    line = data + y * wpl;
548
0
    switch (d)
549
0
    {
550
0
    case 1:
551
0
        CLEAR_DATA_BIT(line, x);
552
0
        break;
553
0
    case 2:
554
0
        CLEAR_DATA_DIBIT(line, x);
555
0
        break;
556
0
    case 4:
557
0
        CLEAR_DATA_QBIT(line, x);
558
0
        break;
559
0
    case 8:
560
0
        SET_DATA_BYTE(line, x, 0);
561
0
        break;
562
0
    case 16:
563
0
        SET_DATA_TWO_BYTES(line, x, 0);
564
0
        break;
565
0
    case 32:
566
0
        line[x] = 0;
567
0
        break;
568
0
    default:
569
0
        return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", __func__, 1);
570
0
    }
571
572
0
    return 0;
573
0
}
574
575
576
/*!
577
 * \brief   pixFlipPixel()
578
 *
579
 * \param[in]    pix   any depth, warning if colormapped
580
 * \param[in]    x,y   pixel coords
581
 * \return  0 if OK; 1 or 2 on error
582
 *
583
 * <pre>
584
 * Notes:
585
 *      (1) If the point is outside the image, this returns an error (2),
586
 *          with 0 in %pval.  To avoid spamming output, it fails silently.
587
 * </pre>
588
 */
589
l_ok
590
pixFlipPixel(PIX     *pix,
591
             l_int32  x,
592
             l_int32  y)
593
0
{
594
0
l_int32    w, h, d, wpl;
595
0
l_uint32   val;
596
0
l_uint32  *line, *data;
597
598
0
    if (!pix)
599
0
        return ERROR_INT("pix not defined", __func__, 1);
600
0
    if (pixGetColormap(pix))
601
0
        L_WARNING("cmapped: setting to 0 may not be intended\n", __func__);
602
0
    pixGetDimensions(pix, &w, &h, &d);
603
0
    if (x < 0 || x >= w || y < 0 || y >= h)
604
0
        return 2;
605
606
0
    data = pixGetData(pix);
607
0
    wpl = pixGetWpl(pix);
608
0
    line = data + y * wpl;
609
0
    switch (d)
610
0
    {
611
0
    case 1:
612
0
        val = GET_DATA_BIT(line, x);
613
0
        if (val)
614
0
            CLEAR_DATA_BIT(line, x);
615
0
        else
616
0
            SET_DATA_BIT(line, x);
617
0
        break;
618
0
    case 2:
619
0
        val = GET_DATA_DIBIT(line, x);
620
0
        val ^= 0x3;
621
0
        SET_DATA_DIBIT(line, x, val);
622
0
        break;
623
0
    case 4:
624
0
        val = GET_DATA_QBIT(line, x);
625
0
        val ^= 0xf;
626
0
        SET_DATA_QBIT(line, x, val);
627
0
        break;
628
0
    case 8:
629
0
        val = GET_DATA_BYTE(line, x);
630
0
        val ^= 0xff;
631
0
        SET_DATA_BYTE(line, x, val);
632
0
        break;
633
0
    case 16:
634
0
        val = GET_DATA_TWO_BYTES(line, x);
635
0
        val ^= 0xffff;
636
0
        SET_DATA_TWO_BYTES(line, x, val);
637
0
        break;
638
0
    case 32:
639
0
        val = line[x] ^ 0xffffffff;
640
0
        line[x] = val;
641
0
        break;
642
0
    default:
643
0
        return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", __func__, 1);
644
0
    }
645
646
0
    return 0;
647
0
}
648
649
650
/*!
651
 * \brief   setPixelLow()
652
 *
653
 * \param[in]    line    ptr to beginning of line,
654
 * \param[in]    x       pixel location in line
655
 * \param[in]    depth   bpp
656
 * \param[in]    val     to be inserted
657
 * \return  void
658
 *
659
 * <pre>
660
 * Notes:
661
 *      (1) Caution: input variables are not checked!
662
 * </pre>
663
 */
664
void
665
setPixelLow(l_uint32  *line,
666
            l_int32    x,
667
            l_int32    depth,
668
            l_uint32   val)
669
0
{
670
0
    switch (depth)
671
0
    {
672
0
    case 1:
673
0
        if (val)
674
0
            SET_DATA_BIT(line, x);
675
0
        else
676
0
            CLEAR_DATA_BIT(line, x);
677
0
        break;
678
0
    case 2:
679
0
        SET_DATA_DIBIT(line, x, val);
680
0
        break;
681
0
    case 4:
682
0
        SET_DATA_QBIT(line, x, val);
683
0
        break;
684
0
    case 8:
685
0
        SET_DATA_BYTE(line, x, val);
686
0
        break;
687
0
    case 16:
688
0
        SET_DATA_TWO_BYTES(line, x, val);
689
0
        break;
690
0
    case 32:
691
0
        line[x] = val;
692
0
        break;
693
0
    default:
694
0
        lept_stderr("illegal depth in setPixelLow()\n");
695
0
    }
696
0
}
697
698
699
/*-------------------------------------------------------------*
700
 *                     Find black or white value               *
701
 *-------------------------------------------------------------*/
702
/*!
703
 * \brief   pixGetBlackOrWhiteVal()
704
 *
705
 * \param[in]    pixs    all depths; cmap ok
706
 * \param[in]    op      L_GET_BLACK_VAL, L_GET_WHITE_VAL
707
 * \param[out]   pval    pixel value
708
 * \return  0 if OK; 1 on error
709
 *
710
 * <pre>
711
 * Notes:
712
 *      (1) Side effect.  For a colormapped image, if the requested
713
 *          color is not present and there is room to add it in the cmap,
714
 *          it is added and the new index is returned.  If there is no room,
715
 *          the index of the closest color in intensity is returned.
716
 * </pre>
717
 */
718
l_ok
719
pixGetBlackOrWhiteVal(PIX       *pixs,
720
                      l_int32    op,
721
                      l_uint32  *pval)
722
0
{
723
0
l_int32   d, index;
724
0
PIXCMAP  *cmap;
725
726
0
    if (!pval)
727
0
        return ERROR_INT("&val not defined", __func__, 1);
728
0
    *pval = 0;
729
0
    if (!pixs)
730
0
        return ERROR_INT("pixs not defined", __func__, 1);
731
0
    if (op != L_GET_BLACK_VAL && op != L_GET_WHITE_VAL)
732
0
        return ERROR_INT("invalid op", __func__, 1);
733
734
0
    cmap = pixGetColormap(pixs);
735
0
    d = pixGetDepth(pixs);
736
0
    if (!cmap) {
737
0
        if ((d == 1 && op == L_GET_WHITE_VAL) ||
738
0
            (d > 1 && op == L_GET_BLACK_VAL)) {  /* min val */
739
0
            *pval = 0;
740
0
        } else {  /* max val */
741
0
            *pval = (d == 32) ? 0xffffff00 : (1 << d) - 1;
742
0
        }
743
0
    } else {  /* handle colormap */
744
0
        if (op == L_GET_BLACK_VAL)
745
0
            pixcmapAddBlackOrWhite(cmap, 0, &index);
746
0
        else  /* L_GET_WHITE_VAL */
747
0
            pixcmapAddBlackOrWhite(cmap, 1, &index);
748
0
        *pval = index;
749
0
    }
750
751
0
    return 0;
752
0
}
753
754
755
/*-------------------------------------------------------------*
756
 *     Full image clear/set/set-to-arbitrary-value/invert      *
757
 *-------------------------------------------------------------*/
758
/*!
759
 * \brief   pixClearAll()
760
 *
761
 * \param[in]    pix    all depths; use cmapped with caution
762
 * \return  0 if OK, 1 on error
763
 *
764
 * <pre>
765
 * Notes:
766
 *      (1) Clears all data to 0.  For 1 bpp, this is white; for grayscale
767
 *          or color, this is black.
768
 *      (2) Caution: for colormapped pix, this sets the color to the first
769
 *          one in the colormap.  Be sure that this is the intended color!
770
 * </pre>
771
 */
772
l_ok
773
pixClearAll(PIX  *pix)
774
0
{
775
0
    if (!pix)
776
0
        return ERROR_INT("pix not defined", __func__, 1);
777
778
0
    memset(pix->data, 0, 4LL * pix->wpl * pix->h);
779
0
    return 0;
780
0
}
781
782
783
/*!
784
 * \brief   pixSetAll()
785
 *
786
 * \param[in]    pix     all depths; use cmapped with caution
787
 * \return  0 if OK, 1 on error
788
 *
789
 * <pre>
790
 * Notes:
791
 *      (1) Sets all data to 1.  For 1 bpp, this is black; for grayscale
792
 *          or color, this is white.
793
 *      (2) Caution: for colormapped pix, this sets the pixel value to the
794
 *          maximum value supported by the colormap: 2^d - 1.  However, this
795
 *          color may not be defined, because the colormap may not be full.
796
 * </pre>
797
 */
798
l_ok
799
pixSetAll(PIX  *pix)
800
113
{
801
113
l_int32   n;
802
113
PIXCMAP  *cmap;
803
804
113
    if (!pix)
805
0
        return ERROR_INT("pix not defined", __func__, 1);
806
113
    if ((cmap = pixGetColormap(pix)) != NULL) {
807
0
        n = pixcmapGetCount(cmap);
808
0
        if (n < cmap->nalloc)  /* cmap is not full */
809
0
            return ERROR_INT("cmap entry does not exist", __func__, 1);
810
0
    }
811
812
113
    memset(pix->data, 0xff, 4LL * pix->wpl * pix->h);
813
113
    return 0;
814
113
}
815
816
817
/*!
818
 * \brief   pixSetAllGray()
819
 *
820
 * \param[in]    pix       all depths, cmap ok
821
 * \param[in]    grayval   in range 0 ... 255
822
 * \return  0 if OK; 1 on error
823
 *
824
 * <pre>
825
 * Notes:
826
 *      (1) N.B.  For all images, %grayval == 0 represents black and
827
 *          %grayval == 255 represents white.
828
 *      (2) For depth < 8, we do our best to approximate the gray level.
829
 *          For 1 bpp images, any %grayval < 128 is black; >= 128 is white.
830
 *          For 32 bpp images, each r,g,b component is set to %grayval,
831
 *          and the alpha component is preserved.
832
 *      (3) If pix is colormapped, it adds the gray value, replicated in
833
 *          all components, to the colormap if it's not there and there
834
 *          is room.  If the colormap is full, it finds the closest color in
835
 *          L2 distance of components.  This index is written to all pixels.
836
 * </pre>
837
 */
838
l_ok
839
pixSetAllGray(PIX     *pix,
840
              l_int32  grayval)
841
0
{
842
0
l_int32   d, spp, index;
843
0
l_uint32  val32;
844
0
PIX      *alpha;
845
0
PIXCMAP  *cmap;
846
847
0
    if (!pix)
848
0
        return ERROR_INT("pix not defined", __func__, 1);
849
0
    if (grayval < 0) {
850
0
        L_WARNING("grayval < 0; setting to 0\n", __func__);
851
0
        grayval = 0;
852
0
    } else if (grayval > 255) {
853
0
        L_WARNING("grayval > 255; setting to 255\n", __func__);
854
0
        grayval = 255;
855
0
    }
856
857
        /* Handle the colormap case */
858
0
    cmap = pixGetColormap(pix);
859
0
    if (cmap) {
860
0
        pixcmapAddNearestColor(cmap, grayval, grayval, grayval, &index);
861
0
        pixSetAllArbitrary(pix, index);
862
0
        return 0;
863
0
    }
864
865
        /* Non-cmapped */
866
0
    d = pixGetDepth(pix);
867
0
    spp = pixGetSpp(pix);
868
0
    if (d == 1) {
869
0
        if (grayval < 128)  /* black */
870
0
            pixSetAll(pix);
871
0
        else
872
0
            pixClearAll(pix);  /* white */
873
0
    } else if (d < 8) {
874
0
        grayval >>= 8 - d;
875
0
        pixSetAllArbitrary(pix, grayval);
876
0
    } else if (d == 8) {
877
0
        pixSetAllArbitrary(pix, grayval);
878
0
    } else if (d == 16) {
879
0
        grayval |= (grayval << 8);
880
0
        pixSetAllArbitrary(pix, grayval);
881
0
    } else if (d == 32 && spp == 3) {
882
0
        composeRGBPixel(grayval, grayval, grayval, &val32);
883
0
        pixSetAllArbitrary(pix, val32);
884
0
    } else if (d == 32 && spp == 4) {
885
0
        alpha = pixGetRGBComponent(pix, L_ALPHA_CHANNEL);
886
0
        composeRGBPixel(grayval, grayval, grayval, &val32);
887
0
        pixSetAllArbitrary(pix, val32);
888
0
        pixSetRGBComponent(pix, alpha, L_ALPHA_CHANNEL);
889
0
        pixDestroy(&alpha);
890
0
    } else {
891
0
        L_ERROR("invalid depth: %d\n", __func__, d);
892
0
        return 1;
893
0
    }
894
895
0
    return 0;
896
0
}
897
898
899
/*!
900
 * \brief   pixSetAllArbitrary()
901
 *
902
 * \param[in]    pix    all depths; use cmapped with caution
903
 * \param[in]    val    value to set all pixels
904
 * \return  0 if OK; 1 on error
905
 *
906
 * <pre>
907
 * Notes:
908
 *      (1) Caution 1!  For colormapped pix, %val is used as an index
909
 *          into a colormap.  Be sure that index refers to the intended color.
910
 *          If the color is not in the colormap, you should first add it
911
 *          and then call this function.
912
 *      (2) Caution 2!  For 32 bpp pix, the interpretation of the LSB
913
 *          of %val depends on whether spp == 3 (RGB) or spp == 4 (RGBA).
914
 *          For RGB, the LSB is ignored in image transformations.
915
 *          For RGBA, the LSB is interpreted as the alpha (transparency)
916
 *          component; full transparency has alpha == 0x0, whereas
917
 *          full opacity has alpha = 0xff.  An RGBA image with full
918
 *          opacity behaves like an RGB image.
919
 *      (3) As an example of (2), suppose you want to initialize a 32 bpp
920
 *          pix with partial opacity, say 0xee337788.  If the pix is 3 spp,
921
 *          the 0x88 alpha component will be ignored and may be changed
922
 *          in subsequent processing.  However, if the pix is 4 spp, the
923
 *          alpha component will be retained and used. The function
924
 *          pixCreate(w, h, 32) makes an RGB image by default, and
925
 *          pixSetSpp(pix, 4) can be used to promote an RGB image to RGBA.
926
 * </pre>
927
 */
928
l_ok
929
pixSetAllArbitrary(PIX      *pix,
930
                   l_uint32  val)
931
0
{
932
0
l_int32    n, i, j, w, h, d, wpl, npix;
933
0
l_uint32   maxval, wordval;
934
0
l_uint32  *data, *line;
935
0
PIXCMAP   *cmap;
936
937
0
    if (!pix)
938
0
        return ERROR_INT("pix not defined", __func__, 1);
939
940
        /* If colormapped, make sure that val is less than the size
941
         * of the cmap array. */
942
0
    if ((cmap = pixGetColormap(pix)) != NULL) {
943
0
        n = pixcmapGetCount(cmap);
944
0
        if (val >= n) {
945
0
            L_WARNING("index not in colormap; using last color\n", __func__);
946
0
            val = n - 1;
947
0
        }
948
0
    }
949
950
        /* Make sure val isn't too large for the pixel depth.
951
         * If it is too large, set the pixel color to white.  */
952
0
    pixGetDimensions(pix, &w, &h, &d);
953
0
    if (d < 32) {
954
0
        maxval = (1 << d) - 1;
955
0
        if (val > maxval) {
956
0
            L_WARNING("val = %d too large for depth; using maxval = %d\n",
957
0
                      __func__, val, maxval);
958
0
            val = maxval;
959
0
        }
960
0
    }
961
962
        /* Set up word to tile with */
963
0
    wordval = 0;
964
0
    npix = 32 / d;    /* number of pixels per 32 bit word */
965
0
    for (j = 0; j < npix; j++)
966
0
        wordval |= (val << (j * d));
967
0
    wpl = pixGetWpl(pix);
968
0
    data = pixGetData(pix);
969
0
    for (i = 0; i < h; i++) {
970
0
        line = data + i * wpl;
971
0
        for (j = 0; j < wpl; j++) {
972
0
            *(line + j) = wordval;
973
0
        }
974
0
    }
975
0
    return 0;
976
0
}
977
978
979
/*!
980
 * \brief   pixSetBlackOrWhite()
981
 *
982
 * \param[in]    pixs    all depths; cmap ok
983
 * \param[in]    op      L_SET_BLACK, L_SET_WHITE
984
 * \return  0 if OK; 1 on error
985
 *
986
 * <pre>
987
 * Notes:
988
 *      (1) Function for setting all pixels in an image to either black
989
 *          or white.
990
 *      (2) If pixs is colormapped, it adds black or white to the
991
 *          colormap if it's not there and there is room.  If the colormap
992
 *          is full, it finds the closest color in intensity.
993
 *          This index is written to all pixels.
994
 * </pre>
995
 */
996
l_ok
997
pixSetBlackOrWhite(PIX     *pixs,
998
                   l_int32  op)
999
0
{
1000
0
l_int32   d, index;
1001
0
PIXCMAP  *cmap;
1002
1003
0
    if (!pixs)
1004
0
        return ERROR_INT("pix not defined", __func__, 1);
1005
0
    if (op != L_SET_BLACK && op != L_SET_WHITE)
1006
0
        return ERROR_INT("invalid op", __func__, 1);
1007
1008
0
    cmap = pixGetColormap(pixs);
1009
0
    d = pixGetDepth(pixs);
1010
0
    if (!cmap) {
1011
0
        if ((d == 1 && op == L_SET_BLACK) || (d > 1 && op == L_SET_WHITE))
1012
0
            pixSetAll(pixs);
1013
0
        else
1014
0
            pixClearAll(pixs);
1015
0
    } else {  /* handle colormap */
1016
0
        if (op == L_SET_BLACK)
1017
0
            pixcmapAddBlackOrWhite(cmap, 0, &index);
1018
0
        else  /* L_SET_WHITE */
1019
0
            pixcmapAddBlackOrWhite(cmap, 1, &index);
1020
0
        pixSetAllArbitrary(pixs, index);
1021
0
    }
1022
1023
0
    return 0;
1024
0
}
1025
1026
1027
/*!
1028
 * \brief   pixSetComponentArbitrary()
1029
 *
1030
 * \param[in]    pix    32 bpp
1031
 * \param[in]    comp   COLOR_RED, COLOR_GREEN, COLOR_BLUE, L_ALPHA_CHANNEL
1032
 * \param[in]    val    value to set this component
1033
 * \return  0 if OK; 1 on error
1034
 *
1035
 * <pre>
1036
 * Notes:
1037
 *      (1) For example, this can be used to set the alpha component to opaque:
1038
 *              pixSetComponentArbitrary(pix, L_ALPHA_CHANNEL, 255)
1039
 * </pre>
1040
 */
1041
l_ok
1042
pixSetComponentArbitrary(PIX     *pix,
1043
                         l_int32  comp,
1044
                         l_int32  val)
1045
0
{
1046
0
l_int32    i, nwords;
1047
0
l_uint32   mask1, mask2;
1048
0
l_uint32  *data;
1049
1050
0
    if (!pix || pixGetDepth(pix) != 32)
1051
0
        return ERROR_INT("pix not defined or not 32 bpp", __func__, 1);
1052
0
    if (comp != COLOR_RED && comp != COLOR_GREEN && comp != COLOR_BLUE &&
1053
0
        comp != L_ALPHA_CHANNEL)
1054
0
        return ERROR_INT("invalid component", __func__, 1);
1055
0
    if (val < 0 || val > 255)
1056
0
        return ERROR_INT("val not in [0 ... 255]", __func__, 1);
1057
1058
0
    mask1 = ~(255 << (8 * (3 - comp)));
1059
0
    mask2 = val << (8 * (3 - comp));
1060
0
    nwords = pixGetHeight(pix) * pixGetWpl(pix);
1061
0
    data = pixGetData(pix);
1062
0
    for (i = 0; i < nwords; i++) {
1063
0
        data[i] &= mask1;  /* clear out the component */
1064
0
        data[i] |= mask2;  /* insert the new component value */
1065
0
    }
1066
1067
0
    return 0;
1068
0
}
1069
1070
1071
/*-------------------------------------------------------------*
1072
 *     Rectangular region clear/set/set-to-arbitrary-value     *
1073
 *-------------------------------------------------------------*/
1074
/*!
1075
 * \brief   pixClearInRect()
1076
 *
1077
 * \param[in]    pix   all depths; can be cmapped
1078
 * \param[in]    box   in which all pixels will be cleared
1079
 * \return  0 if OK, 1 on error
1080
 *
1081
 * <pre>
1082
 * Notes:
1083
 *      (1) Clears all data in rect to 0.  For 1 bpp, this is white;
1084
 *          for grayscale or color, this is black.
1085
 *      (2) Caution: for colormapped pix, this sets the color to the first
1086
 *          one in the colormap.  Be sure that this is the intended color!
1087
 * </pre>
1088
 */
1089
l_ok
1090
pixClearInRect(PIX  *pix,
1091
               BOX  *box)
1092
0
{
1093
0
l_int32  x, y, w, h;
1094
1095
0
    if (!pix)
1096
0
        return ERROR_INT("pix not defined", __func__, 1);
1097
0
    if (!box)
1098
0
        return ERROR_INT("box not defined", __func__, 1);
1099
1100
0
    boxGetGeometry(box, &x, &y, &w, &h);
1101
0
    pixRasterop(pix, x, y, w, h, PIX_CLR, NULL, 0, 0);
1102
0
    return 0;
1103
0
}
1104
1105
1106
/*!
1107
 * \brief   pixSetInRect()
1108
 *
1109
 * \param[in]    pix   all depths, can be cmapped
1110
 * \param[in]    box   in which all pixels will be set
1111
 * \return  0 if OK, 1 on error
1112
 *
1113
 * <pre>
1114
 * Notes:
1115
 *      (1) Sets all data in rect to 1.  For 1 bpp, this is black;
1116
 *          for grayscale or color, this is white.
1117
 *      (2) Caution: for colormapped pix, this sets the pixel value to the
1118
 *          maximum value supported by the colormap: 2^d - 1.  However, this
1119
 *          color may not be defined, because the colormap may not be full.
1120
 * </pre>
1121
 */
1122
l_ok
1123
pixSetInRect(PIX  *pix,
1124
             BOX  *box)
1125
0
{
1126
0
l_int32   n, x, y, w, h;
1127
0
PIXCMAP  *cmap;
1128
1129
0
    if (!pix)
1130
0
        return ERROR_INT("pix not defined", __func__, 1);
1131
0
    if (!box)
1132
0
        return ERROR_INT("box not defined", __func__, 1);
1133
0
    if ((cmap = pixGetColormap(pix)) != NULL) {
1134
0
        n = pixcmapGetCount(cmap);
1135
0
        if (n < cmap->nalloc)  /* cmap is not full */
1136
0
            return ERROR_INT("cmap entry does not exist", __func__, 1);
1137
0
    }
1138
1139
0
    boxGetGeometry(box, &x, &y, &w, &h);
1140
0
    pixRasterop(pix, x, y, w, h, PIX_SET, NULL, 0, 0);
1141
0
    return 0;
1142
0
}
1143
1144
1145
/*!
1146
 * \brief   pixSetInRectArbitrary()
1147
 *
1148
 * \param[in]    pix   all depths; can be cmapped
1149
 * \param[in]    box   in which all pixels will be set to val
1150
 * \param[in]    val   value to set all pixels
1151
 * \return  0 if OK; 1 on error
1152
 *
1153
 * <pre>
1154
 * Notes:
1155
 *      (1) For colormapped pix, be sure the value is the intended
1156
 *          one in the colormap.
1157
 *      (2) Caution: for colormapped pix, this sets each pixel in the
1158
 *          rect to the color at the index equal to val.  Be sure that
1159
 *          this index exists in the colormap and that it is the intended one!
1160
 * </pre>
1161
 */
1162
l_ok
1163
pixSetInRectArbitrary(PIX      *pix,
1164
                      BOX      *box,
1165
                      l_uint32  val)
1166
0
{
1167
0
l_int32    n, x, y, xstart, xend, ystart, yend, bw, bh, w, h, d, wpl;
1168
0
l_uint32   maxval;
1169
0
l_uint32  *data, *line;
1170
0
BOX       *boxc;
1171
0
PIXCMAP   *cmap;
1172
1173
0
    if (!pix)
1174
0
        return ERROR_INT("pix not defined", __func__, 1);
1175
0
    if (!box)
1176
0
        return ERROR_INT("box not defined", __func__, 1);
1177
0
    pixGetDimensions(pix, &w, &h, &d);
1178
0
    if (d != 1 && d != 2 && d != 4 && d !=8 && d != 16 && d != 32)
1179
0
        return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", __func__, 1);
1180
0
    if ((cmap = pixGetColormap(pix)) != NULL) {
1181
0
        n = pixcmapGetCount(cmap);
1182
0
        if (val >= n) {
1183
0
            L_WARNING("index not in colormap; using last color\n", __func__);
1184
0
            val = n - 1;
1185
0
        }
1186
0
    }
1187
1188
0
    maxval = (d == 32) ? 0xffffff00 : (1 << d) - 1;
1189
0
    if (val > maxval) val = maxval;
1190
1191
        /* Handle the simple cases: the min and max values */
1192
0
    if (val == 0) {
1193
0
        pixClearInRect(pix, box);
1194
0
        return 0;
1195
0
    }
1196
0
    if (d == 1 ||
1197
0
        (d == 2 && val == 3) ||
1198
0
        (d == 4 && val == 0xf) ||
1199
0
        (d == 8 && val == 0xff) ||
1200
0
        (d == 16 && val == 0xffff) ||
1201
0
        (d == 32 && ((val ^ 0xffffff00) >> 8 == 0))) {
1202
0
        pixSetInRect(pix, box);
1203
0
        return 0;
1204
0
    }
1205
1206
        /* Find the overlap of box with the input pix */
1207
0
    if ((boxc = boxClipToRectangle(box, w, h)) == NULL)
1208
0
        return ERROR_INT("no overlap of box with image", __func__, 1);
1209
0
    boxGetGeometry(boxc, &xstart, &ystart, &bw, &bh);
1210
0
    xend = xstart + bw - 1;
1211
0
    yend = ystart + bh - 1;
1212
0
    boxDestroy(&boxc);
1213
1214
0
    wpl = pixGetWpl(pix);
1215
0
    data = pixGetData(pix);
1216
0
    for (y = ystart; y <= yend; y++) {
1217
0
        line = data + y * wpl;
1218
0
        for (x = xstart; x <= xend; x++) {
1219
0
            switch(d)
1220
0
            {
1221
0
            case 2:
1222
0
                SET_DATA_DIBIT(line, x, val);
1223
0
                break;
1224
0
            case 4:
1225
0
                SET_DATA_QBIT(line, x, val);
1226
0
                break;
1227
0
            case 8:
1228
0
                SET_DATA_BYTE(line, x, val);
1229
0
                break;
1230
0
            case 16:
1231
0
                SET_DATA_TWO_BYTES(line, x, val);
1232
0
                break;
1233
0
            case 32:
1234
0
                line[x] = val;
1235
0
                break;
1236
0
            default:
1237
0
                return ERROR_INT("depth not 2|4|8|16|32 bpp", __func__, 1);
1238
0
            }
1239
0
        }
1240
0
    }
1241
1242
0
    return 0;
1243
0
}
1244
1245
1246
/*!
1247
 * \brief   pixBlendInRect()
1248
 *
1249
 * \param[in]    pixs   32 bpp rgb
1250
 * \param[in]    box    [optional] in which all pixels will be blended
1251
 * \param[in]    val    blend value; 0xrrggbb00
1252
 * \param[in]    fract  fraction of color to be blended with each pixel in pixs
1253
 * \return  0 if OK; 1 on error
1254
 *
1255
 * <pre>
1256
 * Notes:
1257
 *      (1) This is an in-place function.  It blends the input color %val
1258
 *          with the pixels in pixs in the specified rectangle.
1259
 *          If no rectangle is specified, it blends over the entire image.
1260
 * </pre>
1261
 */
1262
l_ok
1263
pixBlendInRect(PIX       *pixs,
1264
               BOX       *box,
1265
               l_uint32   val,
1266
               l_float32  fract)
1267
0
{
1268
0
l_int32    i, j, bx, by, bw, bh, w, h, wpls;
1269
0
l_int32    prval, pgval, pbval, rval, gval, bval;
1270
0
l_uint32   val32;
1271
0
l_uint32  *datas, *lines;
1272
1273
0
    if (!pixs || pixGetDepth(pixs) != 32)
1274
0
        return ERROR_INT("pixs not defined or not 32 bpp", __func__, 1);
1275
1276
0
    extractRGBValues(val, &rval, &gval, &bval);
1277
0
    pixGetDimensions(pixs, &w, &h, NULL);
1278
0
    datas = pixGetData(pixs);
1279
0
    wpls = pixGetWpl(pixs);
1280
0
    if (!box) {
1281
0
        for (i = 0; i < h; i++) {   /* scan over box */
1282
0
            lines = datas +  i * wpls;
1283
0
            for (j = 0; j < w; j++) {
1284
0
                val32 = *(lines + j);
1285
0
                extractRGBValues(val32, &prval, &pgval, &pbval);
1286
0
                prval = (l_int32)((1. - fract) * prval + fract * rval);
1287
0
                pgval = (l_int32)((1. - fract) * pgval + fract * gval);
1288
0
                pbval = (l_int32)((1. - fract) * pbval + fract * bval);
1289
0
                composeRGBPixel(prval, pgval, pbval, &val32);
1290
0
                *(lines + j) = val32;
1291
0
            }
1292
0
        }
1293
0
        return 0;
1294
0
    }
1295
1296
0
    boxGetGeometry(box, &bx, &by, &bw, &bh);
1297
0
    for (i = 0; i < bh; i++) {   /* scan over box */
1298
0
        if (by + i < 0 || by + i >= h) continue;
1299
0
        lines = datas + (by + i) * wpls;
1300
0
        for (j = 0; j < bw; j++) {
1301
0
            if (bx + j < 0 || bx + j >= w) continue;
1302
0
            val32 = *(lines + bx + j);
1303
0
            extractRGBValues(val32, &prval, &pgval, &pbval);
1304
0
            prval = (l_int32)((1. - fract) * prval + fract * rval);
1305
0
            pgval = (l_int32)((1. - fract) * pgval + fract * gval);
1306
0
            pbval = (l_int32)((1. - fract) * pbval + fract * bval);
1307
0
            composeRGBPixel(prval, pgval, pbval, &val32);
1308
0
            *(lines + bx + j) = val32;
1309
0
        }
1310
0
    }
1311
0
    return 0;
1312
0
}
1313
1314
1315
/*-------------------------------------------------------------*
1316
 *                         Set pad bits                        *
1317
 *-------------------------------------------------------------*/
1318
/*!
1319
 * \brief   pixSetPadBits()
1320
 *
1321
 * \param[in]    pix   1, 2, 4, 8, 16, 32 bpp
1322
 * \param[in]    val   0 or 1
1323
 * \return  0 if OK; 1 on error
1324
 *
1325
 * <pre>
1326
 * Notes:
1327
 *      (1) The pad bits are the bits that expand each scanline to a
1328
 *          multiple of 32 bits.  They are usually not used in
1329
 *          image processing operations.  When boundary conditions
1330
 *          are important, as in seedfill, they must be set properly.
1331
 *      (2) This sets the value of the pad bits (if any) in the last
1332
 *          32-bit word in each scanline.
1333
 *      (3) For 32 bpp pix, there are no pad bits, so this is a no-op.
1334
 *      (4) For 24 bpp pix (which are not generally supported in leptonica),
1335
 *          this operation would affect image components because the pixels
1336
 *          are not aligned with 32-bit word boundaries.
1337
 *      (5) When writing formatted output, such as tiff, png or jpeg,
1338
 *          the pad bits have no effect on the raster image that is
1339
 *          generated by reading back from the file.  However, in some
1340
 *          cases, the compressed file itself will depend on the pad
1341
 *          bits.  This is seen, for example, in Windows with 2 and 4 bpp
1342
 *          tiff-compressed images that have pad bits on each scanline.
1343
 *          It is sometimes convenient to use a golden file with a
1344
 *          byte-by-byte check to verify invariance.  Consequently,
1345
 *          and because setting the pad bits is cheap, the pad bits are
1346
 *          set to 0 before writing these compressed files.
1347
 * </pre>
1348
 */
1349
l_ok
1350
pixSetPadBits(PIX     *pix,
1351
              l_int32  val)
1352
1.66k
{
1353
1.66k
l_int32    i, w, h, d, wpl, endbits, fullwords;
1354
1.66k
l_uint32   mask;
1355
1.66k
l_uint32  *data, *pword;
1356
1357
1.66k
    if (!pix)
1358
0
        return ERROR_INT("pix not defined", __func__, 1);
1359
1360
1.66k
    pixGetDimensions(pix, &w, &h, &d);
1361
1.66k
    if (d == 32)  /* no padding exists for 32 bpp */
1362
453
        return 0;
1363
1.21k
    if (d == 24) {  /* pixels not aligned with 32-bit words */
1364
2
        L_INFO("pix is 24 bpp\n", __func__);
1365
2
        return 1;
1366
2
    }
1367
1368
1.21k
    data = pixGetData(pix);
1369
1.21k
    wpl = pixGetWpl(pix);
1370
1.21k
    endbits = 32 - (((l_int64)w * d) % 32);
1371
1.21k
    if (endbits == 32)  /* no partial word */
1372
393
        return 0;
1373
817
    fullwords = (1LL * w * d) / 32;
1374
817
    mask = rmask32[endbits];
1375
817
    if (val == 0)
1376
817
        mask = ~mask;
1377
1378
217k
    for (i = 0; i < h; i++) {
1379
216k
        pword = data + i * wpl + fullwords;
1380
216k
        if (val == 0) /* clear */
1381
216k
            *pword = *pword & mask;
1382
0
        else  /* set */
1383
0
            *pword = *pword | mask;
1384
216k
    }
1385
1386
817
    return 0;
1387
1.21k
}
1388
1389
1390
/*!
1391
 * \brief   pixSetPadBitsBand()
1392
 *
1393
 * \param[in]    pix   1, 2, 4, 8, 16, 32 bpp
1394
 * \param[in]    by    starting y value of band
1395
 * \param[in]    bh    height of band
1396
 * \param[in]    val   0 or 1
1397
 * \return  0 if OK; 1 on error
1398
 *
1399
 * <pre>
1400
 * Notes:
1401
 *      (1) The pad bits are the bits that expand each scanline to a
1402
 *          multiple of 32 bits.  They are usually not used in
1403
 *          image processing operations.  When boundary conditions
1404
 *          are important, as in seedfill, they must be set properly.
1405
 *      (2) This sets the value of the pad bits (if any) in the last
1406
 *          32-bit word in each scanline, within the specified
1407
 *          band of raster lines.
1408
 *      (3) For 32 bpp pix, there are no pad bits, so this is a no-op.
1409
 *          For 24 bpp pix, this function would change image components.
1410
 * </pre>
1411
 */
1412
l_ok
1413
pixSetPadBitsBand(PIX     *pix,
1414
                  l_int32  by,
1415
                  l_int32  bh,
1416
                  l_int32  val)
1417
0
{
1418
0
l_int32    i, w, h, d, wpl, endbits, fullwords;
1419
0
l_uint32   mask;
1420
0
l_uint32  *data, *pword;
1421
1422
0
    if (!pix)
1423
0
        return ERROR_INT("pix not defined", __func__, 1);
1424
1425
0
    pixGetDimensions(pix, &w, &h, &d);
1426
0
    if (d == 32)  /* no padding exists for 32 bpp */
1427
0
        return 0;
1428
0
    if (d == 24) {  /* pixels not aligned with 32-bit words */
1429
0
        L_INFO("pix is 24 bpp\n", __func__);
1430
0
        return 1;
1431
0
    }
1432
1433
0
    if (by < 0)
1434
0
        by = 0;
1435
0
    if (by >= h)
1436
0
        return ERROR_INT("start y not in image", __func__, 1);
1437
0
    if (by + bh > h)
1438
0
        bh = h - by;
1439
1440
0
    data = pixGetData(pix);
1441
0
    wpl = pixGetWpl(pix);
1442
0
    endbits = 32 - (((l_int64)w * d) % 32);
1443
0
    if (endbits == 32)  /* no partial word */
1444
0
        return 0;
1445
0
    fullwords = (l_int64)w * d / 32;
1446
1447
0
    mask = rmask32[endbits];
1448
0
    if (val == 0)
1449
0
        mask = ~mask;
1450
1451
0
    for (i = by; i < by + bh; i++) {
1452
0
        pword = data + i * wpl + fullwords;
1453
0
        if (val == 0) /* clear */
1454
0
            *pword = *pword & mask;
1455
0
        else  /* set */
1456
0
            *pword = *pword | mask;
1457
0
    }
1458
1459
0
    return 0;
1460
0
}
1461
1462
1463
/*-------------------------------------------------------------*
1464
 *                       Set border pixels                     *
1465
 *-------------------------------------------------------------*/
1466
/*!
1467
 * \brief   pixSetOrClearBorder()
1468
 *
1469
 * \param[in]    pixs                     all depths
1470
 * \param[in]    left, right, top, bot    border region amount to set or clear: these distances are from outside
1471
 * \param[in]    op                       operation PIX_SET or PIX_CLR
1472
 * \return  0 if OK; 1 on error
1473
 *
1474
 * <pre>
1475
 * Notes:
1476
 *      (1) The border region is defined to be the region in the
1477
 *          image within a specific distance of each edge.  Here, we
1478
 *          allow the pixels within a specified distance of each
1479
 *          edge to be set independently.  This either sets or
1480
 *          clears all pixels in the border region.
1481
 *      (2) For binary images, use PIX_SET for black and PIX_CLR for white.
1482
 *      (3) For grayscale or color images, use PIX_SET for white
1483
 *          and PIX_CLR for black.
1484
 * </pre>
1485
 */
1486
l_ok
1487
pixSetOrClearBorder(PIX     *pixs,
1488
                    l_int32  left,
1489
                    l_int32  right,
1490
                    l_int32  top,
1491
                    l_int32  bot,
1492
                    l_int32  op)
1493
0
{
1494
0
l_int32  w, h;
1495
1496
0
    if (!pixs)
1497
0
        return ERROR_INT("pixs not defined", __func__, 1);
1498
0
    if (op != PIX_SET && op != PIX_CLR)
1499
0
        return ERROR_INT("op must be PIX_SET or PIX_CLR", __func__, 1);
1500
1501
0
    pixGetDimensions(pixs, &w, &h, NULL);
1502
0
    pixRasterop(pixs, 0, 0, left, h, op, NULL, 0, 0);
1503
0
    pixRasterop(pixs, w - right, 0, right, h, op, NULL, 0, 0);
1504
0
    pixRasterop(pixs, 0, 0, w, top, op, NULL, 0, 0);
1505
0
    pixRasterop(pixs, 0, h - bot, w, bot, op, NULL, 0, 0);
1506
1507
0
    return 0;
1508
0
}
1509
1510
1511
/*!
1512
 * \brief   pixSetBorderVal()
1513
 *
1514
 * \param[in]    pixs                   8, 16 or 32 bpp
1515
 * \param[in]    left, right, top, bot  border region amount to set: these distances are from outside
1516
 * \param[in]    val                    value to set at each border pixel
1517
 * \return  0 if OK; 1 on error
1518
 *
1519
 * <pre>
1520
 * Notes:
1521
 *      (1) The border region is defined to be the region in the
1522
 *          image within a specific distance of each edge.  Here, we
1523
 *          allow the pixels within a specified distance of each
1524
 *          edge to be set independently.  This sets the pixels
1525
 *          in the border region to the given input value.
1526
 *      (2) For efficiency, use pixSetOrClearBorder() if
1527
 *          you're setting the border to either black or white.
1528
 *      (3) If d != 32, the input value should be masked off
1529
 *          to the appropriate number of least significant bits.
1530
 *      (4) The code is easily generalized for 2 or 4 bpp.
1531
 * </pre>
1532
 */
1533
l_ok
1534
pixSetBorderVal(PIX      *pixs,
1535
                l_int32   left,
1536
                l_int32   right,
1537
                l_int32   top,
1538
                l_int32   bot,
1539
                l_uint32  val)
1540
0
{
1541
0
l_int32    w, h, d, wpls, i, j, bstart, rstart;
1542
0
l_uint32  *datas, *lines;
1543
1544
0
    if (!pixs)
1545
0
        return ERROR_INT("pixs not defined", __func__, 1);
1546
0
    pixGetDimensions(pixs, &w, &h, &d);
1547
0
    if (d != 8 && d != 16 && d != 32)
1548
0
        return ERROR_INT("depth must be 8, 16 or 32 bpp", __func__, 1);
1549
1550
0
    datas = pixGetData(pixs);
1551
0
    wpls = pixGetWpl(pixs);
1552
0
    if (d == 8) {
1553
0
        val &= 0xff;
1554
0
        for (i = 0; i < top; i++) {
1555
0
            lines = datas + i * wpls;
1556
0
            for (j = 0; j < w; j++)
1557
0
                SET_DATA_BYTE(lines, j, val);
1558
0
        }
1559
0
        rstart = w - right;
1560
0
        bstart = h - bot;
1561
0
        for (i = top; i < bstart; i++) {
1562
0
            lines = datas + i * wpls;
1563
0
            for (j = 0; j < left; j++)
1564
0
                SET_DATA_BYTE(lines, j, val);
1565
0
            for (j = rstart; j < w; j++)
1566
0
                SET_DATA_BYTE(lines, j, val);
1567
0
        }
1568
0
        for (i = bstart; i < h; i++) {
1569
0
            lines = datas + i * wpls;
1570
0
            for (j = 0; j < w; j++)
1571
0
                SET_DATA_BYTE(lines, j, val);
1572
0
        }
1573
0
    } else if (d == 16) {
1574
0
        val &= 0xffff;
1575
0
        for (i = 0; i < top; i++) {
1576
0
            lines = datas + i * wpls;
1577
0
            for (j = 0; j < w; j++)
1578
0
                SET_DATA_TWO_BYTES(lines, j, val);
1579
0
        }
1580
0
        rstart = w - right;
1581
0
        bstart = h - bot;
1582
0
        for (i = top; i < bstart; i++) {
1583
0
            lines = datas + i * wpls;
1584
0
            for (j = 0; j < left; j++)
1585
0
                SET_DATA_TWO_BYTES(lines, j, val);
1586
0
            for (j = rstart; j < w; j++)
1587
0
                SET_DATA_TWO_BYTES(lines, j, val);
1588
0
        }
1589
0
        for (i = bstart; i < h; i++) {
1590
0
            lines = datas + i * wpls;
1591
0
            for (j = 0; j < w; j++)
1592
0
                SET_DATA_TWO_BYTES(lines, j, val);
1593
0
        }
1594
0
    } else {   /* d == 32 */
1595
0
        for (i = 0; i < top; i++) {
1596
0
            lines = datas + i * wpls;
1597
0
            for (j = 0; j < w; j++)
1598
0
                *(lines + j) = val;
1599
0
        }
1600
0
        rstart = w - right;
1601
0
        bstart = h - bot;
1602
0
        for (i = top; i < bstart; i++) {
1603
0
            lines = datas + i * wpls;
1604
0
            for (j = 0; j < left; j++)
1605
0
                *(lines + j) = val;
1606
0
            for (j = rstart; j < w; j++)
1607
0
                *(lines + j) = val;
1608
0
        }
1609
0
        for (i = bstart; i < h; i++) {
1610
0
            lines = datas + i * wpls;
1611
0
            for (j = 0; j < w; j++)
1612
0
                *(lines + j) = val;
1613
0
        }
1614
0
    }
1615
1616
0
    return 0;
1617
0
}
1618
1619
1620
/*!
1621
 * \brief   pixSetBorderRingVal()
1622
 *
1623
 * \param[in]    pixs    any depth; cmap OK
1624
 * \param[in]    dist    distance from outside; must be > 0; first ring is 1
1625
 * \param[in]    val     value to set at each border pixel
1626
 * \return  0 if OK; 1 on error
1627
 *
1628
 * <pre>
1629
 * Notes:
1630
 *      (1) The rings are single-pixel-wide rectangular sets of
1631
 *          pixels at a given distance from the edge of the pix.
1632
 *          This sets all pixels in a given ring to a value.
1633
 * </pre>
1634
 */
1635
l_ok
1636
pixSetBorderRingVal(PIX      *pixs,
1637
                    l_int32   dist,
1638
                    l_uint32  val)
1639
0
{
1640
0
l_int32  w, h, d, i, j, xend, yend;
1641
1642
0
    if (!pixs)
1643
0
        return ERROR_INT("pixs not defined", __func__, 1);
1644
0
    if (dist < 1)
1645
0
        return ERROR_INT("dist must be > 0", __func__, 1);
1646
0
    pixGetDimensions(pixs, &w, &h, &d);
1647
0
    if (w < 2 * dist + 1 || h < 2 * dist + 1)
1648
0
        return ERROR_INT("ring doesn't exist", __func__, 1);
1649
0
    if (d < 32 && (val >= (1 << d)))
1650
0
        return ERROR_INT("invalid pixel value", __func__, 1);
1651
1652
0
    xend = w - dist;
1653
0
    yend = h - dist;
1654
0
    for (j = dist - 1; j <= xend; j++)
1655
0
        pixSetPixel(pixs, j, dist - 1, val);
1656
0
    for (j = dist - 1; j <= xend; j++)
1657
0
        pixSetPixel(pixs, j, yend, val);
1658
0
    for (i = dist - 1; i <= yend; i++)
1659
0
        pixSetPixel(pixs, dist - 1, i, val);
1660
0
    for (i = dist - 1; i <= yend; i++)
1661
0
        pixSetPixel(pixs, xend, i, val);
1662
1663
0
    return 0;
1664
0
}
1665
1666
1667
/*!
1668
 * \brief   pixSetMirroredBorder()
1669
 *
1670
 * \param[in]    pixs                   all depths; colormap ok
1671
 * \param[in]    left, right, top, bot  number of pixels to set
1672
 * \return  0 if OK, 1 on error
1673
 *
1674
 * <pre>
1675
 * Notes:
1676
 *      (1) This applies what is effectively mirror boundary conditions
1677
 *          to a border region in the image.  It is in-place.
1678
 *      (2) This is useful for setting pixels near the border to a
1679
 *          value representative of the near pixels to the interior.
1680
 *      (3) The general pixRasterop() is used for an in-place operation here
1681
 *          because there is no overlap between the src and dest rectangles.
1682
 * </pre>
1683
 */
1684
l_ok
1685
pixSetMirroredBorder(PIX     *pixs,
1686
                     l_int32  left,
1687
                     l_int32  right,
1688
                     l_int32  top,
1689
                     l_int32  bot)
1690
0
{
1691
0
l_int32  i, j, w, h;
1692
1693
0
    if (!pixs)
1694
0
        return ERROR_INT("pixs not defined", __func__, 1);
1695
1696
0
    pixGetDimensions(pixs, &w, &h, NULL);
1697
0
    for (j = 0; j < left; j++)
1698
0
        pixRasterop(pixs, left - 1 - j, top, 1, h - top - bot, PIX_SRC,
1699
0
                    pixs, left + j, top);
1700
0
    for (j = 0; j < right; j++)
1701
0
        pixRasterop(pixs, w - right + j, top, 1, h - top - bot, PIX_SRC,
1702
0
                    pixs, w - right - 1 - j, top);
1703
0
    for (i = 0; i < top; i++)
1704
0
        pixRasterop(pixs, 0, top - 1 - i, w, 1, PIX_SRC,
1705
0
                    pixs, 0, top + i);
1706
0
    for (i = 0; i < bot; i++)
1707
0
        pixRasterop(pixs, 0, h - bot + i, w, 1, PIX_SRC,
1708
0
                    pixs, 0, h - bot - 1 - i);
1709
1710
0
    return 0;
1711
0
}
1712
1713
1714
/*!
1715
 * \brief   pixCopyBorder()
1716
 *
1717
 * \param[in]    pixd                   all depths; colormap ok; can be NULL
1718
 * \param[in]    pixs                   same depth and size as pixd
1719
 * \param[in]    left, right, top, bot  number of pixels to copy
1720
 * \return  pixd, or NULL on error if pixd is not defined
1721
 *
1722
 * <pre>
1723
 * Notes:
1724
 *      (1) pixd can be null, but otherwise it must be the same size
1725
 *          and depth as pixs.  Always returns pixd.
1726
 *      (2) This is useful in situations where by setting a few border
1727
 *          pixels we can avoid having to copy all pixels in pixs into
1728
 *          pixd as an initialization step for some operation.
1729
 *          Nevertheless, for safety, if making a new pixd, all the
1730
 *          non-border pixels are initialized to 0.
1731
 * </pre>
1732
 */
1733
PIX *
1734
pixCopyBorder(PIX     *pixd,
1735
              PIX     *pixs,
1736
              l_int32  left,
1737
              l_int32  right,
1738
              l_int32  top,
1739
              l_int32  bot)
1740
0
{
1741
0
l_int32  w, h;
1742
1743
0
    if (!pixs)
1744
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd);
1745
1746
0
    if (pixd) {
1747
0
        if (pixd == pixs) {
1748
0
            L_WARNING("same: nothing to do\n", __func__);
1749
0
            return pixd;
1750
0
        } else if (!pixSizesEqual(pixs, pixd)) {
1751
0
            return (PIX *)ERROR_PTR("pixs and pixd sizes differ",
1752
0
                                    __func__, pixd);
1753
0
        }
1754
0
    } else {
1755
0
        if ((pixd = pixCreateTemplate(pixs)) == NULL)
1756
0
            return (PIX *)ERROR_PTR("pixd not made", __func__, pixd);
1757
0
    }
1758
1759
0
    pixGetDimensions(pixs, &w, &h, NULL);
1760
0
    pixRasterop(pixd, 0, 0, left, h, PIX_SRC, pixs, 0, 0);
1761
0
    pixRasterop(pixd, w - right, 0, right, h, PIX_SRC, pixs, w - right, 0);
1762
0
    pixRasterop(pixd, 0, 0, w, top, PIX_SRC, pixs, 0, 0);
1763
0
    pixRasterop(pixd, 0, h - bot, w, bot, PIX_SRC, pixs, 0, h - bot);
1764
0
    return pixd;
1765
0
}
1766
1767
1768
1769
/*-------------------------------------------------------------*
1770
 *                     Add and remove border                   *
1771
 *-------------------------------------------------------------*/
1772
/*!
1773
 * \brief   pixAddBorder()
1774
 *
1775
 * \param[in]    pixs   all depths; colormap ok
1776
 * \param[in]    npix   number of pixels to be added to each side
1777
 * \param[in]    val    value of added border pixels
1778
 * \return  pixd with the added exterior pixels, or NULL on error
1779
 *
1780
 * <pre>
1781
 * Notes:
1782
 *      (1) See pixGetBlackOrWhiteVal() for values of black and white pixels.
1783
 * </pre>
1784
 */
1785
PIX *
1786
pixAddBorder(PIX      *pixs,
1787
             l_int32   npix,
1788
             l_uint32  val)
1789
0
{
1790
0
    if (!pixs)
1791
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1792
0
    if (npix == 0)
1793
0
        return pixClone(pixs);
1794
0
    return pixAddBorderGeneral(pixs, npix, npix, npix, npix, val);
1795
0
}
1796
1797
1798
/*!
1799
 * \brief   pixAddBlackOrWhiteBorder()
1800
 *
1801
 * \param[in]    pixs all depths; colormap ok
1802
 * \param[in]    left, right, top, bot  number of pixels added
1803
 * \param[in]    op L_GET_BLACK_VAL, L_GET_WHITE_VAL
1804
 * \return  pixd with the added exterior pixels, or NULL on error
1805
 *
1806
 * <pre>
1807
 * Notes:
1808
 *      (1) See pixGetBlackOrWhiteVal() for possible side effect (adding
1809
 *          a color to a colormap).
1810
 *      (2) The only complication is that pixs may have a colormap.
1811
 *          There are two ways to add the black or white border:
1812
 *          (a) As done here (simplest, most efficient)
1813
 *          (b) l_int32 ws, hs, d;
1814
 *              pixGetDimensions(pixs, &ws, &hs, &d);
1815
 *              Pix *pixd = pixCreate(ws + left + right, hs + top + bot, d);
1816
 *              PixColormap *cmap = pixGetColormap(pixs);
1817
 *              if (cmap != NULL)
1818
 *                  pixSetColormap(pixd, pixcmapCopy(cmap));
1819
 *              pixSetBlackOrWhite(pixd, L_SET_WHITE);  // uses cmap
1820
 *              pixRasterop(pixd, left, top, ws, hs, PIX_SET, pixs, 0, 0);
1821
 * </pre>
1822
 */
1823
PIX *
1824
pixAddBlackOrWhiteBorder(PIX     *pixs,
1825
                         l_int32  left,
1826
                         l_int32  right,
1827
                         l_int32  top,
1828
                         l_int32  bot,
1829
                         l_int32  op)
1830
0
{
1831
0
l_uint32  val;
1832
1833
0
    if (!pixs)
1834
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1835
0
    if (op != L_GET_BLACK_VAL && op != L_GET_WHITE_VAL)
1836
0
        return (PIX *)ERROR_PTR("invalid op", __func__, NULL);
1837
1838
0
    pixGetBlackOrWhiteVal(pixs, op, &val);
1839
0
    return pixAddBorderGeneral(pixs, left, right, top, bot, val);
1840
0
}
1841
1842
1843
/*!
1844
 * \brief   pixAddBorderGeneral()
1845
 *
1846
 * \param[in]    pixs                   all depths; colormap ok
1847
 * \param[in]    left, right, top, bot  number of pixels added
1848
 * \param[in]    val                    value of added border pixels
1849
 * \return  pixd with the added exterior pixels, or NULL on error
1850
 *
1851
 * <pre>
1852
 * Notes:
1853
 *      (1) For binary images:
1854
 *             white:  val = 0
1855
 *             black:  val = 1
1856
 *          For grayscale images:
1857
 *             white:  val = 2 ** d - 1
1858
 *             black:  val = 0
1859
 *          For rgb color images:
1860
 *             white:  val = 0xffffff00
1861
 *             black:  val = 0
1862
 *          For colormapped images, set val to the appropriate colormap index.
1863
 *      (2) If the added border is either black or white, you can use
1864
 *             pixAddBlackOrWhiteBorder()
1865
 *          The black and white values for all images can be found with
1866
 *             pixGetBlackOrWhiteVal()
1867
 *          which, if pixs is cmapped, may add an entry to the colormap.
1868
 *          Alternatively, if pixs has a colormap, you can find the index
1869
 *          of the pixel whose intensity is closest to white or black:
1870
 *             white: pixcmapGetRankIntensity(cmap, 1.0, &index);
1871
 *             black: pixcmapGetRankIntensity(cmap, 0.0, &index);
1872
 *          and use that for val.
1873
 * </pre>
1874
 */
1875
PIX *
1876
pixAddBorderGeneral(PIX      *pixs,
1877
                    l_int32   left,
1878
                    l_int32   right,
1879
                    l_int32   top,
1880
                    l_int32   bot,
1881
                    l_uint32  val)
1882
0
{
1883
0
l_int32   ws, hs, wd, hd, d, op;
1884
0
l_uint32  maxval;
1885
0
PIX      *pixd;
1886
1887
0
    if (!pixs)
1888
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1889
0
    if (left < 0 || right < 0 || top < 0 || bot < 0)
1890
0
        return (PIX *)ERROR_PTR("negative border added!", __func__, NULL);
1891
1892
0
    pixGetDimensions(pixs, &ws, &hs, &d);
1893
0
    wd = ws + left + right;
1894
0
    hd = hs + top + bot;
1895
0
    if ((pixd = pixCreate(wd, hd, d)) == NULL)
1896
0
        return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1897
0
    pixCopyResolution(pixd, pixs);
1898
0
    pixCopyColormap(pixd, pixs);
1899
1900
        /* Set the new border pixels */
1901
0
    maxval = (d == 32) ? 0xffffff00 : (1 << d) - 1;
1902
0
    op = UNDEF;
1903
0
    if (val == 0)
1904
0
        op = PIX_CLR;
1905
0
    else if (val >= maxval)
1906
0
        op = PIX_SET;
1907
0
    if (op == UNDEF) {
1908
0
        pixSetAllArbitrary(pixd, val);
1909
0
    } else {  /* just set or clear the border pixels */
1910
0
        pixRasterop(pixd, 0, 0, left, hd, op, NULL, 0, 0);
1911
0
        pixRasterop(pixd, wd - right, 0, right, hd, op, NULL, 0, 0);
1912
0
        pixRasterop(pixd, 0, 0, wd, top, op, NULL, 0, 0);
1913
0
        pixRasterop(pixd, 0, hd - bot, wd, bot, op, NULL, 0, 0);
1914
0
    }
1915
1916
        /* Copy pixs into the interior */
1917
0
    pixRasterop(pixd, left, top, ws, hs, PIX_SRC, pixs, 0, 0);
1918
0
    return pixd;
1919
0
}
1920
1921
1922
/*!
1923
 * \brief   pixAddMultipleBlackWhiteBorders()
1924
 *
1925
 * \param[in]    pixs       all depths; colormap ok
1926
 * \param[in]    nblack1    width of first black border
1927
 * \param[in]    nwhite1    width of first white border
1928
 * \param[in]    nblack2    width of second black border
1929
 * \param[in]    nwhite2    width of second white border
1930
 * \param[in]    nblack3    width of third black border
1931
 * \param[in]    nwhite3    width of third white border
1932
 * \return  pixd with the added borders, or NULL on error
1933
 *
1934
 * <pre>
1935
 * Notes:
1936
 *      (1) This is a convenience function for adding up to 3 black and
1937
 *          3 white borders, alternating black and white.
1938
 *      (2) Each of the 6 args gives the width of the next border, starting
1939
 *          with a black border.  Any of the args can be 0, skipping
1940
 *          the addition of that border.
1941
 *      (3) Maximum allowed border width is 500 for any border.
1942
 * </pre>
1943
 */
1944
PIX *
1945
pixAddMultipleBlackWhiteBorders(PIX      *pixs,
1946
                                l_int32   nblack1,
1947
                                l_int32   nwhite1,
1948
                                l_int32   nblack2,
1949
                                l_int32   nwhite2,
1950
                                l_int32   nblack3,
1951
                                l_int32   nwhite3)
1952
0
{
1953
0
l_int32  i, color;
1954
0
l_int32  w[6];
1955
0
PIX     *pix1, *pixd;
1956
1957
0
    if (!pixs)
1958
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1959
1960
0
    w[0] = nblack1;
1961
0
    w[1] = nwhite1;
1962
0
    w[2] = nblack2;
1963
0
    w[3] = nwhite2;
1964
0
    w[4] = nblack3;
1965
0
    w[5] = nwhite3;
1966
0
    pixd = pixClone(pixs);
1967
0
    for (i = 0; i < 6; i++) {
1968
0
        if (w[i] > 500)
1969
0
            L_WARNING("w = %d > 500; skipping\n", __func__, w[i]);
1970
0
        if (w[i] > 0 && w[i] <= 500) {
1971
0
            color = (i % 2 == 0) ? L_GET_BLACK_VAL : L_GET_WHITE_VAL;
1972
0
            pix1 = pixAddBlackOrWhiteBorder(pixd, w[i], w[i], w[i], w[i],
1973
0
                                            color);
1974
0
            pixDestroy(&pixd);
1975
0
            pixd = pix1;
1976
0
        }
1977
0
    }
1978
1979
0
    return pixd;
1980
0
}
1981
1982
1983
/*!
1984
 * \brief   pixRemoveBorder()
1985
 *
1986
 * \param[in]    pixs   all depths; colormap ok
1987
 * \param[in]    npix   number to be removed from each of the 4 sides
1988
 * \return  pixd with pixels removed around border, or NULL on error
1989
 */
1990
PIX *
1991
pixRemoveBorder(PIX     *pixs,
1992
                l_int32  npix)
1993
0
{
1994
0
    if (!pixs)
1995
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1996
0
    if (npix == 0)
1997
0
        return pixClone(pixs);
1998
0
    return pixRemoveBorderGeneral(pixs, npix, npix, npix, npix);
1999
0
}
2000
2001
2002
/*!
2003
 * \brief   pixRemoveBorderGeneral()
2004
 *
2005
 * \param[in]    pixs                   all depths; colormap ok
2006
 * \param[in]    left, right, top, bot  number of pixels removed
2007
 * \return  pixd with pixels removed around border, or NULL on error
2008
 */
2009
PIX *
2010
pixRemoveBorderGeneral(PIX     *pixs,
2011
                       l_int32  left,
2012
                       l_int32  right,
2013
                       l_int32  top,
2014
                       l_int32  bot)
2015
0
{
2016
0
l_int32  ws, hs, wd, hd, d;
2017
0
PIX     *pixd;
2018
2019
0
    if (!pixs)
2020
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2021
0
    if (left < 0 || right < 0 || top < 0 || bot < 0)
2022
0
        return (PIX *)ERROR_PTR("negative border removed!", __func__, NULL);
2023
2024
0
    pixGetDimensions(pixs, &ws, &hs, &d);
2025
0
    wd = ws - left - right;
2026
0
    hd = hs - top - bot;
2027
0
    if (wd <= 0)
2028
0
        return (PIX *)ERROR_PTR("width must be > 0", __func__, NULL);
2029
0
    if (hd <= 0)
2030
0
        return (PIX *)ERROR_PTR("height must be > 0", __func__, NULL);
2031
0
    if ((pixd = pixCreate(wd, hd, d)) == NULL)
2032
0
        return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
2033
0
    pixCopyResolution(pixd, pixs);
2034
0
    pixCopySpp(pixd, pixs);
2035
0
    pixCopyColormap(pixd, pixs);
2036
2037
0
    pixRasterop(pixd, 0, 0, wd, hd, PIX_SRC, pixs, left, top);
2038
0
    if (pixGetDepth(pixs) == 32 && pixGetSpp(pixs) == 4)
2039
0
        pixShiftAndTransferAlpha(pixd, pixs, -left, -top);
2040
0
    return pixd;
2041
0
}
2042
2043
2044
/*!
2045
 * \brief   pixRemoveBorderToSize()
2046
 *
2047
 * \param[in]    pixs   all depths; colormap ok
2048
 * \param[in]    wd     target width; use 0 if only removing from height
2049
 * \param[in]    hd     target height; use 0 if only removing from width
2050
 * \return  pixd with pixels removed around border, or NULL on error
2051
 *
2052
 * <pre>
2053
 * Notes:
2054
 *      (1) Removes pixels as evenly as possible from the sides of the
2055
 *          image, leaving the central part.
2056
 *      (2) Returns clone if no pixels requested removed, or the target
2057
 *          sizes are larger than the image.
2058
 * </pre>
2059
 */
2060
PIX *
2061
pixRemoveBorderToSize(PIX     *pixs,
2062
                      l_int32  wd,
2063
                      l_int32  hd)
2064
0
{
2065
0
l_int32  w, h, top, bot, left, right, delta;
2066
2067
0
    if (!pixs)
2068
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2069
2070
0
    pixGetDimensions(pixs, &w, &h, NULL);
2071
0
    if ((wd <= 0 || wd >= w) && (hd <= 0 || hd >= h))
2072
0
        return pixClone(pixs);
2073
2074
0
    left = right = (w - wd) / 2;
2075
0
    delta = w - 2 * left - wd;
2076
0
    right += delta;
2077
0
    top = bot = (h - hd) / 2;
2078
0
    delta = h - hd - 2 * top;
2079
0
    bot += delta;
2080
0
    if (wd <= 0 || wd > w)
2081
0
        left = right = 0;
2082
0
    else if (hd <= 0 || hd > h)
2083
0
        top = bot = 0;
2084
2085
0
    return pixRemoveBorderGeneral(pixs, left, right, top, bot);
2086
0
}
2087
2088
2089
/*!
2090
 * \brief   pixAddMirroredBorder()
2091
 *
2092
 * \param[in]    pixs                   all depths; colormap ok
2093
 * \param[in]    left, right, top, bot  number of pixels added
2094
 * \return  pixd, or NULL on error
2095
 *
2096
 * <pre>
2097
 * Notes:
2098
 *      (1) This applies what is effectively mirror boundary conditions.
2099
 *          For the added border pixels in pixd, the pixels in pixs
2100
 *          near the border are mirror-copied into the border region.
2101
 *      (2) This is useful for avoiding special operations near
2102
 *          boundaries when doing image processing operations
2103
 *          such as rank filters and convolution.  In use, one first
2104
 *          adds mirrored pixels to each side of the image.  The number
2105
 *          of pixels added on each side is half the filter dimension.
2106
 *          Then the image processing operations proceed over a
2107
 *          region equal to the size of the original image, and
2108
 *          write directly into a dest pix of the same size as pixs.
2109
 *      (3) The general pixRasterop() is used for an in-place operation here
2110
 *          because there is no overlap between the src and dest rectangles.
2111
 * </pre>
2112
 */
2113
PIX  *
2114
pixAddMirroredBorder(PIX      *pixs,
2115
                      l_int32  left,
2116
                      l_int32  right,
2117
                      l_int32  top,
2118
                      l_int32  bot)
2119
0
{
2120
0
l_int32  i, j, w, h;
2121
0
PIX     *pixd;
2122
2123
0
    if (!pixs)
2124
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2125
0
    pixGetDimensions(pixs, &w, &h, NULL);
2126
0
    if (left > w || right > w || top > h || bot > h)
2127
0
        return (PIX *)ERROR_PTR("border too large", __func__, NULL);
2128
2129
        /* Set pixels on left, right, top and bottom, in that order */
2130
0
    pixd = pixAddBorderGeneral(pixs, left, right, top, bot, 0);
2131
0
    for (j = 0; j < left; j++)
2132
0
        pixRasterop(pixd, left - 1 - j, top, 1, h, PIX_SRC,
2133
0
                    pixd, left + j, top);
2134
0
    for (j = 0; j < right; j++)
2135
0
        pixRasterop(pixd, left + w + j, top, 1, h, PIX_SRC,
2136
0
                    pixd, left + w - 1 - j, top);
2137
0
    for (i = 0; i < top; i++)
2138
0
        pixRasterop(pixd, 0, top - 1 - i, left + w + right, 1, PIX_SRC,
2139
0
                    pixd, 0, top + i);
2140
0
    for (i = 0; i < bot; i++)
2141
0
        pixRasterop(pixd, 0, top + h + i, left + w + right, 1, PIX_SRC,
2142
0
                    pixd, 0, top + h - 1 - i);
2143
2144
0
    return pixd;
2145
0
}
2146
2147
2148
/*!
2149
 * \brief   pixAddRepeatedBorder()
2150
 *
2151
 * \param[in]    pixs                   all depths; colormap ok
2152
 * \param[in]    left, right, top, bot  number of pixels added
2153
 * \return  pixd, or NULL on error
2154
 *
2155
 * <pre>
2156
 * Notes:
2157
 *      (1) This applies a repeated border, as if the central part of
2158
 *          the image is tiled over the plane.  So, for example, the
2159
 *          pixels in the left border come from the right side of the image.
2160
 *      (2) The general pixRasterop() is used for an in-place operation here
2161
 *          because there is no overlap between the src and dest rectangles.
2162
 * </pre>
2163
 */
2164
PIX  *
2165
pixAddRepeatedBorder(PIX      *pixs,
2166
                     l_int32  left,
2167
                     l_int32  right,
2168
                     l_int32  top,
2169
                     l_int32  bot)
2170
0
{
2171
0
l_int32  w, h;
2172
0
PIX     *pixd;
2173
2174
0
    if (!pixs)
2175
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2176
0
    pixGetDimensions(pixs, &w, &h, NULL);
2177
0
    if (left > w || right > w || top > h || bot > h)
2178
0
        return (PIX *)ERROR_PTR("border too large", __func__, NULL);
2179
2180
0
    pixd = pixAddBorderGeneral(pixs, left, right, top, bot, 0);
2181
2182
        /* Set pixels on left, right, top and bottom, in that order */
2183
0
    pixRasterop(pixd, 0, top, left, h, PIX_SRC, pixd, w, top);
2184
0
    pixRasterop(pixd, left + w, top, right, h, PIX_SRC, pixd, left, top);
2185
0
    pixRasterop(pixd, 0, 0, left + w + right, top, PIX_SRC, pixd, 0, h);
2186
0
    pixRasterop(pixd, 0, top + h, left + w + right, bot, PIX_SRC, pixd, 0, top);
2187
2188
0
    return pixd;
2189
0
}
2190
2191
2192
/*!
2193
 * \brief   pixAddMixedBorder()
2194
 *
2195
 * \param[in]    pixs                   all depths; colormap ok
2196
 * \param[in]    left, right, top, bot  number of pixels added
2197
 * \return  pixd, or NULL on error
2198
 *
2199
 * <pre>
2200
 * Notes:
2201
 *      (1) This applies mirrored boundary conditions (b.c.) horizontally
2202
 *          and repeated b.c. vertically.
2203
 *      (2) It is specifically used for avoiding special operations
2204
 *          near boundaries when convolving a hue-saturation histogram
2205
 *          with a given window size.  The repeated b.c. are used
2206
 *          vertically for hue, and the mirrored b.c. are used
2207
 *          horizontally for saturation.  The number of pixels added
2208
 *          on each side is approximately (but not quite) half the
2209
 *          filter dimension.  The image processing operations can
2210
 *          then proceed over a region equal to the size of the original
2211
 *          image, and write directly into a dest pix of the same
2212
 *          size as pixs.
2213
 *      (3) The general pixRasterop() can be used for an in-place
2214
 *          operation here because there is no overlap between the
2215
 *          src and dest rectangles.
2216
 * </pre>
2217
 */
2218
PIX  *
2219
pixAddMixedBorder(PIX      *pixs,
2220
                  l_int32  left,
2221
                  l_int32  right,
2222
                  l_int32  top,
2223
                  l_int32  bot)
2224
0
{
2225
0
l_int32  j, w, h;
2226
0
PIX     *pixd;
2227
2228
0
    if (!pixs)
2229
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2230
0
    pixGetDimensions(pixs, &w, &h, NULL);
2231
0
    if (left > w || right > w || top > h || bot > h)
2232
0
        return (PIX *)ERROR_PTR("border too large", __func__, NULL);
2233
2234
        /* Set mirrored pixels on left and right;
2235
         * then set repeated pixels on top and bottom. */
2236
0
    pixd = pixAddBorderGeneral(pixs, left, right, top, bot, 0);
2237
0
    for (j = 0; j < left; j++)
2238
0
        pixRasterop(pixd, left - 1 - j, top, 1, h, PIX_SRC,
2239
0
                    pixd, left + j, top);
2240
0
    for (j = 0; j < right; j++)
2241
0
        pixRasterop(pixd, left + w + j, top, 1, h, PIX_SRC,
2242
0
                    pixd, left + w - 1 - j, top);
2243
0
    pixRasterop(pixd, 0, 0, left + w + right, top, PIX_SRC, pixd, 0, h);
2244
0
    pixRasterop(pixd, 0, top + h, left + w + right, bot, PIX_SRC, pixd, 0, top);
2245
2246
0
    return pixd;
2247
0
}
2248
2249
2250
/*!
2251
 * \brief   pixAddContinuedBorder()
2252
 *
2253
 * \param[in]    pixs                   all depths; colormap ok
2254
 * \param[in]    left, right, top, bot  pixels on each side to be added
2255
 * \return  pixd, or NULL on error
2256
 *
2257
 * <pre>
2258
 * Notes:
2259
 *      (1) This adds pixels on each side whose values are equal to
2260
 *          the value on the closest boundary pixel.
2261
 * </pre>
2262
 */
2263
PIX *
2264
pixAddContinuedBorder(PIX     *pixs,
2265
                      l_int32  left,
2266
                      l_int32  right,
2267
                      l_int32  top,
2268
                      l_int32  bot)
2269
0
{
2270
0
l_int32  i, j, w, h;
2271
0
PIX     *pixd;
2272
2273
0
    if (!pixs)
2274
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2275
2276
0
    pixd = pixAddBorderGeneral(pixs, left, right, top, bot, 0);
2277
0
    pixGetDimensions(pixs, &w, &h, NULL);
2278
0
    for (j = 0; j < left; j++)
2279
0
        pixRasterop(pixd, j, top, 1, h, PIX_SRC, pixd, left, top);
2280
0
    for (j = 0; j < right; j++)
2281
0
        pixRasterop(pixd, left + w + j, top, 1, h,
2282
0
                    PIX_SRC, pixd, left + w - 1, top);
2283
0
    for (i = 0; i < top; i++)
2284
0
        pixRasterop(pixd, 0, i, left + w + right, 1, PIX_SRC, pixd, 0, top);
2285
0
    for (i = 0; i < bot; i++)
2286
0
        pixRasterop(pixd, 0, top + h + i, left + w + right, 1,
2287
0
                    PIX_SRC, pixd, 0, top + h - 1);
2288
2289
0
    return pixd;
2290
0
}
2291
2292
2293
/*-------------------------------------------------------------------*
2294
 *                     Helper functions using alpha                  *
2295
 *-------------------------------------------------------------------*/
2296
/*!
2297
 * \brief   pixShiftAndTransferAlpha()
2298
 *
2299
 * \param[in]    pixd            32 bpp
2300
 * \param[in]    pixs            32 bpp
2301
 * \param[in]    shiftx, shifty
2302
 * \return  0 if OK; 1 on error
2303
 */
2304
l_ok
2305
pixShiftAndTransferAlpha(PIX       *pixd,
2306
                         PIX       *pixs,
2307
                         l_float32  shiftx,
2308
                         l_float32  shifty)
2309
0
{
2310
0
l_int32  w, h;
2311
0
PIX     *pix1, *pix2;
2312
2313
0
    if (!pixs || !pixd)
2314
0
        return ERROR_INT("pixs and pixd not both defined", __func__, 1);
2315
0
    if (pixGetDepth(pixs) != 32 || pixGetSpp(pixs) != 4)
2316
0
        return ERROR_INT("pixs not 32 bpp and 4 spp", __func__, 1);
2317
0
    if (pixGetDepth(pixd) != 32)
2318
0
        return ERROR_INT("pixd not 32 bpp", __func__, 1);
2319
2320
0
    if (shiftx == 0 && shifty == 0) {
2321
0
        pixCopyRGBComponent(pixd, pixs, L_ALPHA_CHANNEL);
2322
0
        return 0;
2323
0
    }
2324
2325
0
    pix1 = pixGetRGBComponent(pixs, L_ALPHA_CHANNEL);
2326
0
    pixGetDimensions(pixd, &w, &h, NULL);
2327
0
    pix2 = pixCreate(w, h, 8);
2328
0
    pixRasterop(pix2, 0, 0, w, h, PIX_SRC, pix1, -shiftx, -shifty);
2329
0
    pixSetRGBComponent(pixd, pix2, L_ALPHA_CHANNEL);
2330
0
    pixDestroy(&pix1);
2331
0
    pixDestroy(&pix2);
2332
0
    return 0;
2333
0
}
2334
2335
2336
/*!
2337
 * \brief   pixDisplayLayersRGBA()
2338
 *
2339
 * \param[in]    pixs   cmap or 32 bpp rgba
2340
 * \param[in]    val    32 bit unsigned color to use as background
2341
 * \param[in]    maxw   max output image width; 0 for no scaling
2342
 * \return  pixd showing various image views, or NULL on error
2343
 *
2344
 * <pre>
2345
 * Notes:
2346
 *      (1) Use %val == 0xffffff00 for white background.
2347
 *      (2) Three views are given:
2348
 *           ~ the image with a fully opaque alpha
2349
 *           ~ the alpha layer
2350
 *           ~ the image as it would appear with a white background.
2351
 * </pre>
2352
 */
2353
PIX *
2354
pixDisplayLayersRGBA(PIX      *pixs,
2355
                     l_uint32  val,
2356
                     l_int32   maxw)
2357
0
{
2358
0
l_int32    w, width;
2359
0
l_float32  scalefact;
2360
0
PIX       *pix1, *pix2, *pixd;
2361
0
PIXA      *pixa;
2362
0
PIXCMAP   *cmap;
2363
2364
0
    if (!pixs)
2365
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2366
0
    cmap = pixGetColormap(pixs);
2367
0
    if (!cmap && !(pixGetDepth(pixs) == 32 && pixGetSpp(pixs) == 4))
2368
0
        return (PIX *)ERROR_PTR("pixs not cmap and not 32 bpp rgba",
2369
0
                                __func__, NULL);
2370
0
    if ((w = pixGetWidth(pixs)) == 0)
2371
0
        return (PIX *)ERROR_PTR("pixs width 0 !!", __func__, NULL);
2372
2373
0
    if (cmap)
2374
0
        pix1 = pixRemoveColormap(pixs, REMOVE_CMAP_WITH_ALPHA);
2375
0
    else
2376
0
        pix1 = pixCopy(NULL, pixs);
2377
2378
        /* Scale if necessary so the output width is not larger than maxw */
2379
0
    scalefact = (maxw == 0) ? 1.0f : L_MIN(1.0f, (l_float32)(maxw) / w);
2380
0
    width = (l_int32)(scalefact * w);
2381
2382
0
    pixa = pixaCreate(3);
2383
0
    pixSetSpp(pix1, 3);
2384
0
    pixaAddPix(pixa, pix1, L_INSERT);  /* show the rgb values */
2385
0
    pix1 = pixGetRGBComponent(pixs, L_ALPHA_CHANNEL);
2386
0
    pix2 = pixConvertTo32(pix1);
2387
0
    pixaAddPix(pixa, pix2, L_INSERT);  /* show the alpha channel */
2388
0
    pixDestroy(&pix1);
2389
0
    pix1 = pixAlphaBlendUniform(pixs, (val & 0xffffff00));
2390
0
    pixaAddPix(pixa, pix1, L_INSERT);  /* with %val color bg showing */
2391
0
    pixd = pixaDisplayTiledInRows(pixa, 32, width, scalefact, 0, 25, 2);
2392
0
    pixaDestroy(&pixa);
2393
0
    return pixd;
2394
0
}
2395
2396
2397
/*-------------------------------------------------------------*
2398
 *                Color sample setting and extraction          *
2399
 *-------------------------------------------------------------*/
2400
/*!
2401
 * \brief   pixCreateRGBImage()
2402
 *
2403
 * \param[in]   pixr   8 bpp red pix
2404
 * \param[in]   pixg   8 bpp green pix
2405
 * \param[in]   pixb   8 bpp blue pix
2406
 * \return  32 bpp pix, interleaved with 4 samples/pixel,
2407
 *              or NULL on error
2408
 *
2409
 * <pre>
2410
 * Notes:
2411
 *      (1) the 4th byte, sometimes called the "alpha channel",
2412
 *          and which is often used for blending between different
2413
 *          images, is left with 0 value (fully opaque).
2414
 *      (2) see Note (4) in pix.h for details on storage of
2415
 *          8-bit samples within each 32-bit word.
2416
 *      (3) This implementation, setting the r, g and b components
2417
 *          sequentially, is much faster than setting them in parallel
2418
 *          by constructing an RGB dest pixel and writing it to dest.
2419
 *          The reason is there are many more cache misses when reading
2420
 *          from 3 input images simultaneously.
2421
 * </pre>
2422
 */
2423
PIX *
2424
pixCreateRGBImage(PIX  *pixr,
2425
                  PIX  *pixg,
2426
                  PIX  *pixb)
2427
0
{
2428
0
l_int32  wr, wg, wb, hr, hg, hb, dr, dg, db;
2429
0
PIX     *pixd;
2430
2431
0
    if (!pixr)
2432
0
        return (PIX *)ERROR_PTR("pixr not defined", __func__, NULL);
2433
0
    if (!pixg)
2434
0
        return (PIX *)ERROR_PTR("pixg not defined", __func__, NULL);
2435
0
    if (!pixb)
2436
0
        return (PIX *)ERROR_PTR("pixb not defined", __func__, NULL);
2437
0
    pixGetDimensions(pixr, &wr, &hr, &dr);
2438
0
    pixGetDimensions(pixg, &wg, &hg, &dg);
2439
0
    pixGetDimensions(pixb, &wb, &hb, &db);
2440
0
    if (dr != 8 || dg != 8 || db != 8)
2441
0
        return (PIX *)ERROR_PTR("input pix not all 8 bpp", __func__, NULL);
2442
0
    if (wr != wg || wr != wb)
2443
0
        return (PIX *)ERROR_PTR("widths not the same", __func__, NULL);
2444
0
    if (hr != hg || hr != hb)
2445
0
        return (PIX *)ERROR_PTR("heights not the same", __func__, NULL);
2446
2447
0
    if ((pixd = pixCreate(wr, hr, 32)) == NULL)
2448
0
        return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
2449
0
    pixCopyResolution(pixd, pixr);
2450
0
    pixSetRGBComponent(pixd, pixr, COLOR_RED);
2451
0
    pixSetRGBComponent(pixd, pixg, COLOR_GREEN);
2452
0
    pixSetRGBComponent(pixd, pixb, COLOR_BLUE);
2453
2454
0
    return pixd;
2455
0
}
2456
2457
2458
/*!
2459
 * \brief   pixGetRGBComponent()
2460
 *
2461
 * \param[in]   pixs   32 bpp, or colormapped
2462
 * \param[in]   comp   one of {COLOR_RED, COLOR_GREEN, COLOR_BLUE,
2463
 *                     L_ALPHA_CHANNEL}
2464
 * \return  pixd the selected 8 bpp component image of the
2465
 *                    input 32 bpp image or NULL on error
2466
 *
2467
 * <pre>
2468
 * Notes:
2469
 *      (1) Three calls to this function generate the r, g and b 8 bpp
2470
 *          component images.  This is much faster than generating the
2471
 *          three images in parallel, by extracting a src pixel and setting
2472
 *          the pixels of each component image from it.  The reason is
2473
 *          there are many more cache misses when writing to three
2474
 *          output images simultaneously.
2475
 * </pre>
2476
 */
2477
PIX *
2478
pixGetRGBComponent(PIX     *pixs,
2479
                   l_int32  comp)
2480
0
{
2481
0
l_int32    i, j, w, h, wpls, wpld, val;
2482
0
l_uint32  *lines, *lined;
2483
0
l_uint32  *datas, *datad;
2484
0
PIX       *pixd;
2485
2486
0
    if (!pixs)
2487
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2488
0
    if (pixGetColormap(pixs))
2489
0
        return pixGetRGBComponentCmap(pixs, comp);
2490
0
    if (pixGetDepth(pixs) != 32)
2491
0
        return (PIX *)ERROR_PTR("pixs not 32 bpp", __func__, NULL);
2492
0
    if (comp != COLOR_RED && comp != COLOR_GREEN &&
2493
0
        comp != COLOR_BLUE && comp != L_ALPHA_CHANNEL)
2494
0
        return (PIX *)ERROR_PTR("invalid comp", __func__, NULL);
2495
2496
0
    pixGetDimensions(pixs, &w, &h, NULL);
2497
0
    if ((pixd = pixCreate(w, h, 8)) == NULL)
2498
0
        return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
2499
0
    pixCopyResolution(pixd, pixs);
2500
0
    wpls = pixGetWpl(pixs);
2501
0
    wpld = pixGetWpl(pixd);
2502
0
    datas = pixGetData(pixs);
2503
0
    datad = pixGetData(pixd);
2504
0
    for (i = 0; i < h; i++) {
2505
0
        lines = datas + i * wpls;
2506
0
        lined = datad + i * wpld;
2507
0
        for (j = 0; j < w; j++) {
2508
0
            val = GET_DATA_BYTE(lines + j, comp);
2509
0
            SET_DATA_BYTE(lined, j, val);
2510
0
        }
2511
0
    }
2512
2513
0
    return pixd;
2514
0
}
2515
2516
2517
/*!
2518
 * \brief   pixSetRGBComponent()
2519
 *
2520
 * \param[in]   pixd   32 bpp
2521
 * \param[in]   pixs   8 bpp
2522
 * \param[in]   comp   one of the set: {COLOR_RED, COLOR_GREEN,
2523
 *                                      COLOR_BLUE, L_ALPHA_CHANNEL}
2524
 * \return  0 if OK; 1 on error
2525
 *
2526
 * <pre>
2527
 * Notes:
2528
 *      (1) This places the 8 bpp pixel in pixs into the
2529
 *          specified component (properly interleaved) in pixd,
2530
 *      (2) The two images are registered to the UL corner; the sizes
2531
 *          need not be the same, but a warning is issued if they differ.
2532
 * </pre>
2533
 */
2534
l_ok
2535
pixSetRGBComponent(PIX     *pixd,
2536
                   PIX     *pixs,
2537
                   l_int32  comp)
2538
0
{
2539
0
l_uint8    srcbyte;
2540
0
l_int32    i, j, w, h, ws, hs, wd, hd;
2541
0
l_int32    wpls, wpld;
2542
0
l_uint32  *lines, *lined;
2543
0
l_uint32  *datas, *datad;
2544
2545
0
    if (!pixd)
2546
0
        return ERROR_INT("pixd not defined", __func__, 1);
2547
0
    if (!pixs)
2548
0
        return ERROR_INT("pixs not defined", __func__, 1);
2549
0
    if (pixGetDepth(pixd) != 32)
2550
0
        return ERROR_INT("pixd not 32 bpp", __func__, 1);
2551
0
    if (pixGetDepth(pixs) != 8)
2552
0
        return ERROR_INT("pixs not 8 bpp", __func__, 1);
2553
0
    if (comp != COLOR_RED && comp != COLOR_GREEN &&
2554
0
        comp != COLOR_BLUE && comp != L_ALPHA_CHANNEL)
2555
0
        return ERROR_INT("invalid comp", __func__, 1);
2556
0
    pixGetDimensions(pixs, &ws, &hs, NULL);
2557
0
    pixGetDimensions(pixd, &wd, &hd, NULL);
2558
0
    if (ws != wd || hs != hd)
2559
0
        L_WARNING("images sizes not equal\n", __func__);
2560
0
    w = L_MIN(ws, wd);
2561
0
    h = L_MIN(hs, hd);
2562
0
    if (comp == L_ALPHA_CHANNEL)
2563
0
        pixSetSpp(pixd, 4);
2564
0
    datas = pixGetData(pixs);
2565
0
    datad = pixGetData(pixd);
2566
0
    wpls = pixGetWpl(pixs);
2567
0
    wpld = pixGetWpl(pixd);
2568
0
    for (i = 0; i < h; i++) {
2569
0
        lines = datas + i * wpls;
2570
0
        lined = datad + i * wpld;
2571
0
        for (j = 0; j < w; j++) {
2572
0
            srcbyte = GET_DATA_BYTE(lines, j);
2573
0
            SET_DATA_BYTE(lined + j, comp, srcbyte);
2574
0
        }
2575
0
    }
2576
2577
0
    return 0;
2578
0
}
2579
2580
2581
/*!
2582
 * \brief   pixGetRGBComponentCmap()
2583
 *
2584
 * \param[in]   pixs   colormapped
2585
 * \param[in]   comp   one of the set: {COLOR_RED, COLOR_GREEN, COLOR_BLUE}
2586
 * \return  pixd  the selected 8 bpp component image of the
2587
 *                     input cmapped image, or NULL on error
2588
 *
2589
 * <pre>
2590
 * Notes:
2591
 *      (1) In leptonica, we do not support alpha in colormaps.
2592
 * </pre>
2593
 */
2594
PIX *
2595
pixGetRGBComponentCmap(PIX     *pixs,
2596
                       l_int32  comp)
2597
0
{
2598
0
l_int32     i, j, w, h, val, index, valid;
2599
0
l_int32     wplc, wpld;
2600
0
l_uint32   *linec, *lined;
2601
0
l_uint32   *datac, *datad;
2602
0
PIX        *pixc, *pixd;
2603
0
PIXCMAP    *cmap;
2604
0
RGBA_QUAD  *cta;
2605
2606
0
    if (!pixs)
2607
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2608
0
    if ((cmap = pixGetColormap(pixs)) == NULL)
2609
0
        return (PIX *)ERROR_PTR("pixs not cmapped", __func__, NULL);
2610
0
    if (comp == L_ALPHA_CHANNEL)
2611
0
        return (PIX *)ERROR_PTR("alpha in cmaps not supported", __func__, NULL);
2612
0
    if (comp != COLOR_RED && comp != COLOR_GREEN && comp != COLOR_BLUE)
2613
0
        return (PIX *)ERROR_PTR("invalid comp", __func__, NULL);
2614
2615
        /* If not 8 bpp, make a cmapped 8 bpp pix */
2616
0
    if (pixGetDepth(pixs) == 8)
2617
0
        pixc = pixClone(pixs);
2618
0
    else
2619
0
        pixc = pixConvertTo8(pixs, TRUE);
2620
0
    pixcmapIsValid(cmap, pixc, &valid);
2621
0
    if (!valid) {
2622
0
        pixDestroy(&pixc);
2623
0
        return (PIX *)ERROR_PTR("invalid colormap", __func__, NULL);
2624
0
    }
2625
2626
0
    pixGetDimensions(pixs, &w, &h, NULL);
2627
0
    if ((pixd = pixCreate(w, h, 8)) == NULL) {
2628
0
        pixDestroy(&pixc);
2629
0
        return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
2630
0
    }
2631
0
    pixCopyResolution(pixd, pixs);
2632
0
    wplc = pixGetWpl(pixc);
2633
0
    wpld = pixGetWpl(pixd);
2634
0
    datac = pixGetData(pixc);
2635
0
    datad = pixGetData(pixd);
2636
0
    cta = (RGBA_QUAD *)cmap->array;
2637
2638
0
    for (i = 0; i < h; i++) {
2639
0
        linec = datac + i * wplc;
2640
0
        lined = datad + i * wpld;
2641
0
        if (comp == COLOR_RED) {
2642
0
            for (j = 0; j < w; j++) {
2643
0
                index = GET_DATA_BYTE(linec, j);
2644
0
                val = cta[index].red;
2645
0
                SET_DATA_BYTE(lined, j, val);
2646
0
            }
2647
0
        } else if (comp == COLOR_GREEN) {
2648
0
            for (j = 0; j < w; j++) {
2649
0
                index = GET_DATA_BYTE(linec, j);
2650
0
                val = cta[index].green;
2651
0
                SET_DATA_BYTE(lined, j, val);
2652
0
            }
2653
0
        } else if (comp == COLOR_BLUE) {
2654
0
            for (j = 0; j < w; j++) {
2655
0
                index = GET_DATA_BYTE(linec, j);
2656
0
                val = cta[index].blue;
2657
0
                SET_DATA_BYTE(lined, j, val);
2658
0
            }
2659
0
        }
2660
0
    }
2661
2662
0
    pixDestroy(&pixc);
2663
0
    return pixd;
2664
0
}
2665
2666
2667
/*!
2668
 * \brief   pixCopyRGBComponent()
2669
 *
2670
 * \param[in]   pixd   32 bpp
2671
 * \param[in]   pixs   32 bpp
2672
 * \param[in]   comp   one of the set: {COLOR_RED, COLOR_GREEN,
2673
 *                                      COLOR_BLUE, L_ALPHA_CHANNEL}
2674
 * \return  0 if OK; 1 on error
2675
 *
2676
 * <pre>
2677
 * Notes:
2678
 *      (1) The two images are registered to the UL corner.  The sizes
2679
 *          are usually the same, and a warning is issued if they differ.
2680
 * </pre>
2681
 */
2682
l_ok
2683
pixCopyRGBComponent(PIX     *pixd,
2684
                    PIX     *pixs,
2685
                    l_int32  comp)
2686
0
{
2687
0
l_int32    i, j, w, h, ws, hs, wd, hd, val;
2688
0
l_int32    wpls, wpld;
2689
0
l_uint32  *lines, *lined;
2690
0
l_uint32  *datas, *datad;
2691
2692
0
    if (!pixd && pixGetDepth(pixd) != 32)
2693
0
        return ERROR_INT("pixd not defined or not 32 bpp", __func__, 1);
2694
0
    if (!pixs && pixGetDepth(pixs) != 32)
2695
0
        return ERROR_INT("pixs not defined or not 32 bpp", __func__, 1);
2696
0
    if (comp != COLOR_RED && comp != COLOR_GREEN &&
2697
0
        comp != COLOR_BLUE && comp != L_ALPHA_CHANNEL)
2698
0
        return ERROR_INT("invalid component", __func__, 1);
2699
0
    pixGetDimensions(pixs, &ws, &hs, NULL);
2700
0
    pixGetDimensions(pixd, &wd, &hd, NULL);
2701
0
    if (ws != wd || hs != hd)
2702
0
        L_WARNING("images sizes not equal\n", __func__);
2703
0
    w = L_MIN(ws, wd);
2704
0
    h = L_MIN(hs, hd);
2705
0
    if (comp == L_ALPHA_CHANNEL)
2706
0
        pixSetSpp(pixd, 4);
2707
0
    wpls = pixGetWpl(pixs);
2708
0
    wpld = pixGetWpl(pixd);
2709
0
    datas = pixGetData(pixs);
2710
0
    datad = pixGetData(pixd);
2711
0
    for (i = 0; i < h; i++) {
2712
0
        lines = datas + i * wpls;
2713
0
        lined = datad + i * wpld;
2714
0
        for (j = 0; j < w; j++) {
2715
0
            val = GET_DATA_BYTE(lines + j, comp);
2716
0
            SET_DATA_BYTE(lined + j, comp, val);
2717
0
        }
2718
0
    }
2719
0
    return 0;
2720
0
}
2721
2722
2723
/*!
2724
 * \brief   composeRGBPixel()
2725
 *
2726
 * \param[in]    rval, gval, bval
2727
 * \param[out]   ppixel             32-bit pixel
2728
 * \return  0 if OK; 1 on error
2729
 *
2730
 * <pre>
2731
 * Notes:
2732
 *      (1) All channels are 8 bits: the input values must be between
2733
 *          0 and 255.  For speed, this is not enforced by masking
2734
 *          with 0xff before shifting.
2735
 *      (2) A slower implementation uses macros:
2736
 *            SET_DATA_BYTE(ppixel, COLOR_RED, rval);
2737
 *            SET_DATA_BYTE(ppixel, COLOR_GREEN, gval);
2738
 *            SET_DATA_BYTE(ppixel, COLOR_BLUE, bval);
2739
 * </pre>
2740
 */
2741
l_ok
2742
composeRGBPixel(l_int32    rval,
2743
                l_int32    gval,
2744
                l_int32    bval,
2745
                l_uint32  *ppixel)
2746
3.29k
{
2747
3.29k
    if (!ppixel)
2748
0
        return ERROR_INT("&pixel not defined", __func__, 1);
2749
2750
3.29k
    *ppixel = ((l_uint32)rval << L_RED_SHIFT) |
2751
3.29k
              ((l_uint32)gval << L_GREEN_SHIFT) |
2752
3.29k
              ((l_uint32)bval << L_BLUE_SHIFT);
2753
3.29k
    return 0;
2754
3.29k
}
2755
2756
2757
/*!
2758
 * \brief   composeRGBAPixel()
2759
 *
2760
 * \param[in]    rval, gval, bval, aval
2761
 * \param[out]   ppixel                  32-bit pixel
2762
 * \return  0 if OK; 1 on error
2763
 *
2764
 * <pre>
2765
 * Notes:
2766
 *      (1) All channels are 8 bits: the input values must be between
2767
 *          0 and 255.  For speed, this is not enforced by masking
2768
 *          with 0xff before shifting.
2769
 * </pre>
2770
 */
2771
l_ok
2772
composeRGBAPixel(l_int32    rval,
2773
                 l_int32    gval,
2774
                 l_int32    bval,
2775
                 l_int32    aval,
2776
                 l_uint32  *ppixel)
2777
0
{
2778
0
    if (!ppixel)
2779
0
        return ERROR_INT("&pixel not defined", __func__, 1);
2780
2781
0
    *ppixel = ((l_uint32)rval << L_RED_SHIFT) |
2782
0
              ((l_uint32)gval << L_GREEN_SHIFT) |
2783
0
              ((l_uint32)bval << L_BLUE_SHIFT) |
2784
0
              aval;
2785
0
    return 0;
2786
0
}
2787
2788
2789
/*!
2790
 * \brief   extractRGBValues()
2791
 *
2792
 * \param[in]    pixel   32 bit
2793
 * \param[out]   prval   [optional] red component
2794
 * \param[out]   pgval   [optional] green component
2795
 * \param[out]   pbval   [optional] blue component
2796
 * \return  void
2797
 *
2798
 * <pre>
2799
 * Notes:
2800
 *      (1) A slower implementation uses macros:
2801
 *             *prval = GET_DATA_BYTE(&pixel, COLOR_RED);
2802
 *             *pgval = GET_DATA_BYTE(&pixel, COLOR_GREEN);
2803
 *             *pbval = GET_DATA_BYTE(&pixel, COLOR_BLUE);
2804
 * </pre>
2805
 */
2806
void
2807
extractRGBValues(l_uint32  pixel,
2808
                 l_int32  *prval,
2809
                 l_int32  *pgval,
2810
                 l_int32  *pbval)
2811
0
{
2812
0
    if (prval) *prval = (pixel >> L_RED_SHIFT) & 0xff;
2813
0
    if (pgval) *pgval = (pixel >> L_GREEN_SHIFT) & 0xff;
2814
0
    if (pbval) *pbval = (pixel >> L_BLUE_SHIFT) & 0xff;
2815
0
}
2816
2817
2818
/*!
2819
 * \brief   extractRGBAValues()
2820
 *
2821
 * \param[in]    pixel   32 bit
2822
 * \param[out]   prval   [optional] red component
2823
 * \param[out]   pgval   [optional] green component
2824
 * \param[out]   pbval   [optional] blue component
2825
 * \param[out]   paval   [optional] alpha component
2826
 * \return  void
2827
 */
2828
void
2829
extractRGBAValues(l_uint32  pixel,
2830
                  l_int32  *prval,
2831
                  l_int32  *pgval,
2832
                  l_int32  *pbval,
2833
                  l_int32  *paval)
2834
0
{
2835
0
    if (prval) *prval = (pixel >> L_RED_SHIFT) & 0xff;
2836
0
    if (pgval) *pgval = (pixel >> L_GREEN_SHIFT) & 0xff;
2837
0
    if (pbval) *pbval = (pixel >> L_BLUE_SHIFT) & 0xff;
2838
0
    if (paval) *paval = (pixel >> L_ALPHA_SHIFT) & 0xff;
2839
0
}
2840
2841
2842
/*!
2843
 * \brief   extractMinMaxComponent()
2844
 *
2845
 * \param[in]   pixel   32 bpp RGB
2846
 * \param[in]   type    L_CHOOSE_MIN or L_CHOOSE_MAX
2847
 * \return  component in range [0 ... 255], or NULL on error
2848
 */
2849
l_int32
2850
extractMinMaxComponent(l_uint32  pixel,
2851
                       l_int32   type)
2852
0
{
2853
0
l_int32  rval, gval, bval, val;
2854
2855
0
    extractRGBValues(pixel, &rval, &gval, &bval);
2856
0
    if (type == L_CHOOSE_MIN) {
2857
0
        val = L_MIN(rval, gval);
2858
0
        val = L_MIN(val, bval);
2859
0
    } else {  /* type == L_CHOOSE_MAX */
2860
0
        val = L_MAX(rval, gval);
2861
0
        val = L_MAX(val, bval);
2862
0
    }
2863
0
    return val;
2864
0
}
2865
2866
2867
/*!
2868
 * \brief   pixGetRGBLine()
2869
 *
2870
 * \param[in]   pixs   32 bpp
2871
 * \param[in]   row
2872
 * \param[in]   bufr   array of red samples; size w bytes
2873
 * \param[in]   bufg   array of green samples; size w bytes
2874
 * \param[in]   bufb   array of blue samples; size w bytes
2875
 * \return  0 if OK; 1 on error
2876
 *
2877
 * <pre>
2878
 * Notes:
2879
 *      (1) This puts rgb components from the input line in pixs
2880
 *          into the given buffers.
2881
 * </pre>
2882
 */
2883
l_ok
2884
pixGetRGBLine(PIX      *pixs,
2885
              l_int32   row,
2886
              l_uint8  *bufr,
2887
              l_uint8  *bufg,
2888
              l_uint8  *bufb)
2889
0
{
2890
0
l_uint32  *lines;
2891
0
l_int32    j, w, h;
2892
0
l_int32    wpls;
2893
2894
0
    if (!pixs)
2895
0
        return ERROR_INT("pixs not defined", __func__, 1);
2896
0
    if (pixGetDepth(pixs) != 32)
2897
0
        return ERROR_INT("pixs not 32 bpp", __func__, 1);
2898
0
    if (!bufr || !bufg || !bufb)
2899
0
        return ERROR_INT("buffer not defined", __func__, 1);
2900
2901
0
    pixGetDimensions(pixs, &w, &h, NULL);
2902
0
    if (row < 0 || row >= h)
2903
0
        return ERROR_INT("row out of bounds", __func__, 1);
2904
0
    wpls = pixGetWpl(pixs);
2905
0
    lines = pixGetData(pixs) + row * wpls;
2906
2907
0
    for (j = 0; j < w; j++) {
2908
0
        bufr[j] = GET_DATA_BYTE(lines + j, COLOR_RED);
2909
0
        bufg[j] = GET_DATA_BYTE(lines + j, COLOR_GREEN);
2910
0
        bufb[j] = GET_DATA_BYTE(lines + j, COLOR_BLUE);
2911
0
    }
2912
2913
0
    return 0;
2914
0
}
2915
2916
2917
/*-------------------------------------------------------------*
2918
 *                   Raster line pixel setter                  *
2919
 *-------------------------------------------------------------*/
2920
/*!
2921
 * \brief   setLineDataVal()
2922
 *
2923
 * \param[in]    line    ptr to first word in raster line data
2924
 * \param[in]    j       index of pixels into the raster line
2925
 * \param[in]    d       depth of the pixel
2926
 * \param[in]    val     pixel value to be set
2927
 * \return  0 if OK, 1 on error
2928
 *
2929
 * <pre>
2930
 * Notes:
2931
 *      (1) This is a convenience function to set a pixel value in a
2932
 *          raster line where the depth of the image can have different
2933
 *          values (1, 2, 4, 8, 16 or 32).
2934
 * </pre>
2935
 */
2936
l_ok
2937
setLineDataVal(l_uint32  *line,
2938
               l_int32    j,
2939
               l_int32    d,
2940
               l_uint32   val)
2941
0
{
2942
0
    if (!line)
2943
0
        return ERROR_INT("line not defined", __func__, 1);
2944
0
    if (j < 0)
2945
0
        return ERROR_INT("j must be >= 0", __func__, 1);
2946
0
    if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
2947
0
        return ERROR_INT("invalid d", __func__, 1);
2948
2949
0
    if (d == 1)
2950
0
        SET_DATA_BIT_VAL(line, j, val);
2951
0
    else if (d == 2)
2952
0
        SET_DATA_DIBIT(line, j, val);
2953
0
    else if (d == 4)
2954
0
        SET_DATA_QBIT(line, j, val);
2955
0
    else if (d == 8)
2956
0
        SET_DATA_BYTE(line, j, val);
2957
0
    else if (d == 16)
2958
0
        SET_DATA_TWO_BYTES(line, j, val);
2959
0
    else  /* d == 32 */
2960
0
        *(line + j) = val;
2961
0
    return 0;
2962
0
}
2963
2964
2965
/*-------------------------------------------------------------*
2966
 *                    Pixel endian conversion                  *
2967
 *-------------------------------------------------------------*/
2968
/*!
2969
 * \brief   pixEndianByteSwapNew()
2970
 *
2971
 * \param[in]    pixs
2972
 * \return  pixd, or NULL on error
2973
 *
2974
 * <pre>
2975
 * Notes:
2976
 *      (1) This is used to convert the data in a pix to a
2977
 *          serialized byte buffer in raster order, and, for RGB,
2978
 *          in order RGBA.  This requires flipping bytes within
2979
 *          each 32-bit word for little-endian platforms, because the
2980
 *          words have a MSB-to-the-left rule, whereas byte raster-order
2981
 *          requires the left-most byte in each word to be byte 0.
2982
 *          For big-endians, no swap is necessary, so this returns a clone.
2983
 *      (2) Unlike pixEndianByteSwap(), which swaps the bytes in-place,
2984
 *          this returns a new pix (or a clone).  We provide this
2985
 *          because often when serialization is done, the source
2986
 *          pix needs to be restored to canonical little-endian order,
2987
 *          and this requires a second byte swap.  In such a situation,
2988
 *          it is twice as fast to make a new pix in big-endian order,
2989
 *          use it, and destroy it.
2990
 * </pre>
2991
 */
2992
PIX *
2993
pixEndianByteSwapNew(PIX  *pixs)
2994
0
{
2995
0
l_uint32  *datas, *datad;
2996
0
l_int32    i, j, h, wpl;
2997
0
l_uint32   word;
2998
0
PIX       *pixd;
2999
3000
#ifdef L_BIG_ENDIAN
3001
3002
    return pixClone(pixs);
3003
3004
#else   /* L_LITTLE_ENDIAN */
3005
3006
0
    if (!pixs)
3007
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
3008
3009
0
    datas = pixGetData(pixs);
3010
0
    wpl = pixGetWpl(pixs);
3011
0
    h = pixGetHeight(pixs);
3012
0
    if ((pixd = pixCreateTemplate(pixs)) == NULL)
3013
0
        return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
3014
0
    datad = pixGetData(pixd);
3015
0
    for (i = 0; i < h; i++) {
3016
0
        for (j = 0; j < wpl; j++, datas++, datad++) {
3017
0
            word = *datas;
3018
0
            *datad = (word >> 24) |
3019
0
                    ((word >> 8) & 0x0000ff00) |
3020
0
                    ((word << 8) & 0x00ff0000) |
3021
0
                    (word << 24);
3022
0
        }
3023
0
    }
3024
3025
0
    return pixd;
3026
3027
0
#endif   /* L_BIG_ENDIAN */
3028
3029
0
}
3030
3031
3032
/*!
3033
 * \brief   pixEndianByteSwap()
3034
 *
3035
 * \param[in]   pixs
3036
 * \return  0 if OK, 1 on error
3037
 *
3038
 * <pre>
3039
 * Notes:
3040
 *      (1) This is used on little-endian platforms to swap
3041
 *          the bytes within a word; bytes 0 and 3 are swapped,
3042
 *          and bytes 1 and 2 are swapped.
3043
 *      (2) This is required for little-endians in situations
3044
 *          where we convert from a serialized byte order that is
3045
 *          in raster order, as one typically has in file formats,
3046
 *          to one with MSB-to-the-left in each 32-bit word, or v.v.
3047
 *          See pix.h for a description of the canonical format
3048
 *          (MSB-to-the left) that is used for both little-endian
3049
 *          and big-endian platforms.   For big-endians, the
3050
 *          MSB-to-the-left word order has the bytes in raster
3051
 *          order when serialized, so no byte flipping is required.
3052
 * </pre>
3053
 */
3054
l_ok
3055
pixEndianByteSwap(PIX  *pixs)
3056
0
{
3057
0
l_uint32  *data;
3058
0
l_int32    i, j, h, wpl;
3059
0
l_uint32   word;
3060
3061
#ifdef L_BIG_ENDIAN
3062
3063
    return 0;
3064
3065
#else   /* L_LITTLE_ENDIAN */
3066
3067
0
    if (!pixs)
3068
0
        return ERROR_INT("pixs not defined", __func__, 1);
3069
3070
0
    data = pixGetData(pixs);
3071
0
    wpl = pixGetWpl(pixs);
3072
0
    h = pixGetHeight(pixs);
3073
0
    for (i = 0; i < h; i++) {
3074
0
        for (j = 0; j < wpl; j++, data++) {
3075
0
            word = *data;
3076
0
            *data = (word >> 24) |
3077
0
                    ((word >> 8) & 0x0000ff00) |
3078
0
                    ((word << 8) & 0x00ff0000) |
3079
0
                    (word << 24);
3080
0
        }
3081
0
    }
3082
3083
0
    return 0;
3084
3085
0
#endif   /* L_BIG_ENDIAN */
3086
3087
0
}
3088
3089
3090
/*!
3091
 * \brief   lineEndianByteSwap()
3092
 *
3093
 * \param[in]  datad   dest byte array data, reordered on little-endians
3094
 * \param[in]  datas   a src line of pix data)
3095
 * \param[in]  wpl     number of 32 bit words in the line
3096
 * \return  0 if OK, 1 on error
3097
 *
3098
 * <pre>
3099
 * Notes:
3100
 *      (1) This is used on little-endian platforms to swap
3101
 *          the bytes within each word in the line of image data.
3102
 *          Bytes 0 <==> 3 and 1 <==> 2 are swapped in the dest
3103
 *          byte array data8d, relative to the pix data in datas.
3104
 *      (2) The bytes represent 8 bit pixel values.  They are swapped
3105
 *          for little endians so that when the dest array datad
3106
 *          is addressed by bytes, the pixels are chosen sequentially
3107
 *          from left to right in the image.
3108
 * </pre>
3109
 */
3110
l_int32
3111
lineEndianByteSwap(l_uint32  *datad,
3112
                   l_uint32  *datas,
3113
                   l_int32    wpl)
3114
0
{
3115
0
l_int32   j;
3116
0
l_uint32  word;
3117
3118
0
    if (!datad || !datas)
3119
0
        return ERROR_INT("datad and datas not both defined", __func__, 1);
3120
3121
#ifdef L_BIG_ENDIAN
3122
3123
    memcpy(datad, datas, 4 * wpl);
3124
    return 0;
3125
3126
#else   /* L_LITTLE_ENDIAN */
3127
3128
0
    for (j = 0; j < wpl; j++, datas++, datad++) {
3129
0
        word = *datas;
3130
0
        *datad = (word >> 24) |
3131
0
                 ((word >> 8) & 0x0000ff00) |
3132
0
                 ((word << 8) & 0x00ff0000) |
3133
0
                 (word << 24);
3134
0
    }
3135
0
    return 0;
3136
3137
0
#endif   /* L_BIG_ENDIAN */
3138
3139
0
}
3140
3141
3142
/*!
3143
 * \brief   pixEndianTwoByteSwapNew()
3144
 *
3145
 * \param[in]    pixs
3146
 * \return  0 if OK, 1 on error
3147
 *
3148
 * <pre>
3149
 * Notes:
3150
 *      (1) This is used on little-endian platforms to swap the
3151
 *          2-byte entities within a 32-bit word.
3152
 *      (2) This is equivalent to a full byte swap, as performed
3153
 *          by pixEndianByteSwap(), followed by byte swaps in
3154
 *          each of the 16-bit entities separately.
3155
 *      (3) Unlike pixEndianTwoByteSwap(), which swaps the shorts in-place,
3156
 *          this returns a new pix (or a clone).  We provide this
3157
 *          to avoid having to swap twice in situations where the input
3158
 *          pix must be restored to canonical little-endian order.
3159
 * </pre>
3160
 */
3161
PIX *
3162
pixEndianTwoByteSwapNew(PIX  *pixs)
3163
0
{
3164
0
l_uint32  *datas, *datad;
3165
0
l_int32    i, j, h, wpl;
3166
0
l_uint32   word;
3167
0
PIX       *pixd;
3168
3169
#ifdef L_BIG_ENDIAN
3170
3171
    return pixClone(pixs);
3172
3173
#else   /* L_LITTLE_ENDIAN */
3174
3175
0
    if (!pixs)
3176
0
        return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
3177
3178
0
    datas = pixGetData(pixs);
3179
0
    wpl = pixGetWpl(pixs);
3180
0
    h = pixGetHeight(pixs);
3181
0
    if ((pixd = pixCreateTemplate(pixs)) == NULL)
3182
0
        return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
3183
0
    datad = pixGetData(pixd);
3184
0
    for (i = 0; i < h; i++) {
3185
0
        for (j = 0; j < wpl; j++, datas++, datad++) {
3186
0
            word = *datas;
3187
0
            *datad = (word << 16) | (word >> 16);
3188
0
        }
3189
0
    }
3190
3191
0
    return pixd;
3192
3193
0
#endif   /* L_BIG_ENDIAN */
3194
3195
0
}
3196
3197
3198
/*!
3199
 * \brief   pixEndianTwoByteSwap()
3200
 *
3201
 * \param[in]    pixs
3202
 * \return  0 if OK, 1 on error
3203
 *
3204
 * <pre>
3205
 * Notes:
3206
 *      (1) This is used on little-endian platforms to swap the
3207
 *          2-byte entities within a 32-bit word.
3208
 *      (2) This is equivalent to a full byte swap, as performed
3209
 *          by pixEndianByteSwap(), followed by byte swaps in
3210
 *          each of the 16-bit entities separately.
3211
 * </pre>
3212
 */
3213
l_ok
3214
pixEndianTwoByteSwap(PIX  *pixs)
3215
0
{
3216
0
l_uint32  *data;
3217
0
l_int32    i, j, h, wpl;
3218
0
l_uint32   word;
3219
3220
#ifdef L_BIG_ENDIAN
3221
3222
    return 0;
3223
3224
#else   /* L_LITTLE_ENDIAN */
3225
3226
0
    if (!pixs)
3227
0
        return ERROR_INT("pixs not defined", __func__, 1);
3228
3229
0
    data = pixGetData(pixs);
3230
0
    wpl = pixGetWpl(pixs);
3231
0
    h = pixGetHeight(pixs);
3232
0
    for (i = 0; i < h; i++) {
3233
0
        for (j = 0; j < wpl; j++, data++) {
3234
0
            word = *data;
3235
0
            *data = (word << 16) | (word >> 16);
3236
0
        }
3237
0
    }
3238
3239
0
    return 0;
3240
3241
0
#endif   /* L_BIG_ENDIAN */
3242
3243
0
}
3244
3245
3246
/*-------------------------------------------------------------*
3247
 *             Extract raster data as binary string            *
3248
 *-------------------------------------------------------------*/
3249
/*!
3250
 * \brief   pixGetRasterData()
3251
 *
3252
 * \param[in]    pixs     1, 8, 32 bpp
3253
 * \param[out]   pdata    raster data in memory
3254
 * \param[out]   pnbytes  number of bytes in data string
3255
 * \return  0 if OK, 1 on error
3256
 *
3257
 * <pre>
3258
 * Notes:
3259
 *      (1) This returns the raster data as a byte string, padded to the
3260
 *          byte.  For 1 bpp, the first pixel is the MSbit in the first byte.
3261
 *          For rgb, the bytes are in (rgb) order.  This is the format
3262
 *          required for flate encoding of pixels in a PostScript file.
3263
 * </pre>
3264
 */
3265
l_ok
3266
pixGetRasterData(PIX       *pixs,
3267
                 l_uint8  **pdata,
3268
                 size_t    *pnbytes)
3269
0
{
3270
0
l_int32    w, h, d, wpl, i, j, rval, gval, bval;
3271
0
l_int32    databpl;  /* bytes for each raster line in returned data */
3272
0
l_uint8   *line, *data;  /* packed data in returned array */
3273
0
l_uint32  *rline, *rdata;  /* data in pix raster */
3274
3275
0
    if (pdata) *pdata = NULL;
3276
0
    if (pnbytes) *pnbytes = 0;
3277
0
    if (!pdata || !pnbytes)
3278
0
        return ERROR_INT("&data and &nbytes not both defined", __func__, 1);
3279
0
    if (!pixs)
3280
0
        return ERROR_INT("pixs not defined", __func__, 1);
3281
0
    pixGetDimensions(pixs, &w, &h, &d);
3282
0
    if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
3283
0
        return ERROR_INT("depth not in {1,2,4,8,16,32}", __func__, 1);
3284
3285
0
    pixSetPadBits(pixs, 0);
3286
0
    rdata = pixGetData(pixs);
3287
0
    wpl = pixGetWpl(pixs);
3288
0
    if (d == 1)
3289
0
        databpl = (w + 7) / 8;
3290
0
    else if (d == 2)
3291
0
        databpl = (w + 3) / 4;
3292
0
    else if (d == 4)
3293
0
        databpl = (w + 1) / 2;
3294
0
    else if (d == 8 || d == 16)
3295
0
        databpl = w * (d / 8);
3296
0
    else  /* d == 32 bpp rgb */
3297
0
        databpl = 3 * w;
3298
0
    if ((data = (l_uint8 *)LEPT_CALLOC((size_t)databpl * h, sizeof(l_uint8)))
3299
0
            == NULL)
3300
0
        return ERROR_INT("data not allocated", __func__, 1);
3301
0
    *pdata = data;
3302
0
    *pnbytes = (size_t)databpl * h;
3303
3304
0
    for (i = 0; i < h; i++) {
3305
0
         rline = rdata + i * wpl;
3306
0
         line = data + i * databpl;
3307
0
         if (d <= 8) {
3308
0
             for (j = 0; j < databpl; j++)
3309
0
                  line[j] = GET_DATA_BYTE(rline, j);
3310
0
         } else if (d == 16) {
3311
0
             for (j = 0; j < w; j++)
3312
0
                  line[2 * j] = GET_DATA_TWO_BYTES(rline, j);
3313
0
         } else {  /* d == 32 bpp rgb */
3314
0
             for (j = 0; j < w; j++) {
3315
0
                  extractRGBValues(rline[j], &rval, &gval, &bval);
3316
0
                  *(line + 3 * j) = rval;
3317
0
                  *(line + 3 * j + 1) = gval;
3318
0
                  *(line + 3 * j + 2) = bval;
3319
0
             }
3320
0
         }
3321
0
    }
3322
3323
0
    return 0;
3324
0
}
3325
3326
3327
/*-------------------------------------------------------------*
3328
 *                Infer resolution from image size             *
3329
 *-------------------------------------------------------------*/
3330
/*!
3331
 * \brief   pixInferResolution()
3332
 *
3333
 * \param[in]    pix
3334
 * \param[in]    longside    assumed max dimension, in inches
3335
 * \param[out]   pres        resolution (ppi)
3336
 * \return  0 if OK, 1 on error
3337
 *
3338
 * <pre>
3339
 * Notes:
3340
 *      (1) This finds the resolution, assuming that the longest side
3341
 *          of the image is %longside.  On error, returns 300 ppi.
3342
 *      (2) This is useful for computing resolution for generating pdfs,
3343
 *          when the images are scanned from pages of known size.
3344
 *          There, %longside is typically about 11.0.
3345
 * </pre>
3346
 */
3347
l_ok
3348
pixInferResolution(PIX       *pix,
3349
                   l_float32  longside,
3350
                   l_int32   *pres)
3351
0
{
3352
0
l_int32  w, h, maxdim, res;
3353
3354
0
    if (!pres)
3355
0
        return ERROR_INT("&res not defined", __func__, 1);
3356
0
    *pres = 300;
3357
0
    if (!pix)
3358
0
        return ERROR_INT("pix not defined", __func__, 1);
3359
0
    if (longside <= 0.0)
3360
0
        return ERROR_INT("longside not > 0", __func__, 1);
3361
3362
0
    pixGetDimensions(pix, &w, &h, NULL);
3363
0
    maxdim = L_MAX(w, h);
3364
0
    res = (l_int32)(maxdim / longside + 0.5);
3365
0
    res = L_MAX(res, 1);  /* don't let it be 0 */
3366
0
    if (res < 10)
3367
0
        L_WARNING("low inferred resolution: %d ppi\n", __func__, res);
3368
0
    if (res > 10000)
3369
0
        L_WARNING("high inferred resolution: %d ppi\n", __func__, res);
3370
0
    *pres = res;
3371
0
    return 0;
3372
0
}
3373
3374
3375
/*-------------------------------------------------------------*
3376
 *                 Test alpha component opaqueness             *
3377
 *-------------------------------------------------------------*/
3378
/*!
3379
 * \brief   pixAlphaIsOpaque()
3380
 *
3381
 * \param[in]    pix       32 bpp, spp == 4
3382
 * \param[out]   popaque   1 if spp == 4 and all alpha component
3383
 *                         values are 255 (opaque); 0 otherwise
3384
 * \return  0 if OK, 1 on error
3385
 *
3386
 * <pre>
3387
 * Notes:
3388
 *      1) On error, opaque is returned as 0 (FALSE).
3389
 * </pre>
3390
 */
3391
l_ok
3392
pixAlphaIsOpaque(PIX      *pix,
3393
                 l_int32  *popaque)
3394
0
{
3395
0
l_int32    w, h, wpl, i, j, alpha;
3396
0
l_uint32  *data, *line;
3397
3398
0
    if (!popaque)
3399
0
        return ERROR_INT("&opaque not defined", __func__, 1);
3400
0
    *popaque = FALSE;
3401
0
    if (!pix)
3402
0
        return ERROR_INT("&pix not defined", __func__, 1);
3403
0
    if (pixGetDepth(pix) != 32)
3404
0
        return ERROR_INT("&pix not 32 bpp", __func__, 1);
3405
0
    if (pixGetSpp(pix) != 4)
3406
0
        return ERROR_INT("&pix not 4 spp", __func__, 1);
3407
3408
0
    data = pixGetData(pix);
3409
0
    wpl = pixGetWpl(pix);
3410
0
    pixGetDimensions(pix, &w, &h, NULL);
3411
0
    for (i = 0; i < h; i++) {
3412
0
        line = data + i * wpl;
3413
0
        for (j = 0; j < w; j++) {
3414
0
            alpha = GET_DATA_BYTE(line + j, L_ALPHA_CHANNEL);
3415
0
            if (alpha ^ 0xff)  /* not opaque */
3416
0
                return 0;
3417
0
        }
3418
0
    }
3419
3420
0
    *popaque = TRUE;
3421
0
    return 0;
3422
0
}
3423
3424
3425
/*-------------------------------------------------------------*
3426
 *             Setup helpers for 8 bpp byte processing         *
3427
 *-------------------------------------------------------------*/
3428
/*!
3429
 * \brief   pixSetupByteProcessing()
3430
 *
3431
 * \param[in]    pix   8 bpp, no colormap
3432
 * \param[out]   pw    [optional] width
3433
 * \param[out]   ph    [optional] height
3434
 * \return  line ptr array, or NULL on error
3435
 *
3436
 * <pre>
3437
 * Notes:
3438
 *      (1) This is a simple helper for processing 8 bpp images with
3439
 *          direct byte access.  It can swap byte order within each word.
3440
 *      (2) After processing, you must call pixCleanupByteProcessing(),
3441
 *          which frees the lineptr array and restores byte order.
3442
 *      (3) Usage:
3443
 *              l_uint8 **lineptrs = pixSetupByteProcessing(pix, &w, &h);
3444
 *              for (i = 0; i < h; i++) {
3445
 *                  l_uint8 *line = lineptrs[i];
3446
 *                  for (j = 0; j < w; j++) {
3447
 *                      val = line[j];
3448
 *                      ...
3449
 *                  }
3450
 *              }
3451
 *              pixCleanupByteProcessing(pix, lineptrs);
3452
 * </pre>
3453
 */
3454
l_uint8 **
3455
pixSetupByteProcessing(PIX      *pix,
3456
                       l_int32  *pw,
3457
                       l_int32  *ph)
3458
0
{
3459
0
l_int32  w, h;
3460
3461
0
    if (pw) *pw = 0;
3462
0
    if (ph) *ph = 0;
3463
0
    if (!pix || pixGetDepth(pix) != 8)
3464
0
        return (l_uint8 **)ERROR_PTR("pix not defined or not 8 bpp",
3465
0
                                     __func__, NULL);
3466
0
    pixGetDimensions(pix, &w, &h, NULL);
3467
0
    if (pw) *pw = w;
3468
0
    if (ph) *ph = h;
3469
0
    if (pixGetColormap(pix))
3470
0
        return (l_uint8 **)ERROR_PTR("pix has colormap", __func__, NULL);
3471
3472
0
    pixEndianByteSwap(pix);
3473
0
    return (l_uint8 **)pixGetLinePtrs(pix, NULL);
3474
0
}
3475
3476
3477
/*!
3478
 * \brief   pixCleanupByteProcessing()
3479
 *
3480
 * \param[in]   pix        8 bpp, no colormap
3481
 * \param[in]   lineptrs   ptrs to the beginning of each raster line of data
3482
 * \return  0 if OK, 1 on error
3483
 *
3484
 * <pre>
3485
 * Notes:
3486
 *      (1) This must be called after processing that was initiated
3487
 *          by pixSetupByteProcessing() has finished.
3488
 * </pre>
3489
 */
3490
l_ok
3491
pixCleanupByteProcessing(PIX      *pix,
3492
                         l_uint8 **lineptrs)
3493
0
{
3494
0
    if (!pix)
3495
0
        return ERROR_INT("pix not defined", __func__, 1);
3496
0
    if (!lineptrs)
3497
0
        return ERROR_INT("lineptrs not defined", __func__, 1);
3498
3499
0
    pixEndianByteSwap(pix);
3500
0
    LEPT_FREE(lineptrs);
3501
0
    return 0;
3502
0
}
3503
3504
3505
/*------------------------------------------------------------------------*
3506
 *      Setting parameters for antialias masking with alpha transforms    *
3507
 *------------------------------------------------------------------------*/
3508
/*!
3509
 * \brief   l_setAlphaMaskBorder()
3510
 *
3511
 * \param[in]    val1, val2     in [0.0 ... 1.0]
3512
 * \return  void
3513
 *
3514
 * <pre>
3515
 * Notes:
3516
 *      (1) This sets the opacity values used to generate the two outer
3517
 *          boundary rings in the alpha mask associated with geometric
3518
 *          transforms such as pixRotateWithAlpha().
3519
 *      (2) The default values are val1 = 0.0 (completely transparent
3520
 *          in the outermost ring) and val2 = 0.5 (half transparent
3521
 *          in the second ring).  When the image is blended, this
3522
 *          completely removes the outer ring (shrinking the image by
3523
 *          2 in each direction), and alpha-blends with 0.5 the second ring.
3524
 *          Using val1 = 0.25 and val2 = 0.75 gives a slightly more
3525
 *          blurred border, with no perceptual difference at screen resolution.
3526
 *      (3) The actual mask values are found by multiplying these
3527
 *          normalized opacity values by 255.
3528
 * </pre>
3529
 */
3530
void
3531
l_setAlphaMaskBorder(l_float32  val1,
3532
                     l_float32  val2)
3533
0
{
3534
0
    val1 = L_MAX(0.0f, L_MIN(1.0f, val1));
3535
0
    val2 = L_MAX(0.0f, L_MIN(1.0f, val2));
3536
0
    AlphaMaskBorderVals[0] = val1;
3537
0
    AlphaMaskBorderVals[1] = val2;
3538
0
}