comparison mupdf-source/thirdparty/leptonica/src/pix2.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
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 {
197 l_int32 w, h, d, wpl, val;
198 l_uint32 *line, *data;
199
200 if (!pval)
201 return ERROR_INT("&val not defined", __func__, 1);
202 *pval = 0;
203 if (!pix)
204 return ERROR_INT("pix not defined", __func__, 1);
205
206 pixGetDimensions(pix, &w, &h, &d);
207 if (x < 0 || x >= w || y < 0 || y >= h)
208 return 2;
209
210 wpl = pixGetWpl(pix);
211 data = pixGetData(pix);
212 line = data + y * wpl;
213 switch (d)
214 {
215 case 1:
216 val = GET_DATA_BIT(line, x);
217 break;
218 case 2:
219 val = GET_DATA_DIBIT(line, x);
220 break;
221 case 4:
222 val = GET_DATA_QBIT(line, x);
223 break;
224 case 8:
225 val = GET_DATA_BYTE(line, x);
226 break;
227 case 16:
228 val = GET_DATA_TWO_BYTES(line, x);
229 break;
230 case 32:
231 val = line[x];
232 break;
233 default:
234 return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", __func__, 1);
235 }
236
237 *pval = val;
238 return 0;
239 }
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 {
268 l_int32 w, h, d, wpl;
269 l_uint32 *line, *data;
270
271 if (!pix)
272 return ERROR_INT("pix not defined", __func__, 1);
273 pixGetDimensions(pix, &w, &h, &d);
274 if (x < 0 || x >= w || y < 0 || y >= h)
275 return 2;
276
277 data = pixGetData(pix);
278 wpl = pixGetWpl(pix);
279 line = data + y * wpl;
280 switch (d)
281 {
282 case 1:
283 if (val)
284 SET_DATA_BIT(line, x);
285 else
286 CLEAR_DATA_BIT(line, x);
287 break;
288 case 2:
289 SET_DATA_DIBIT(line, x, val);
290 break;
291 case 4:
292 SET_DATA_QBIT(line, x, val);
293 break;
294 case 8:
295 SET_DATA_BYTE(line, x, val);
296 break;
297 case 16:
298 SET_DATA_TWO_BYTES(line, x, val);
299 break;
300 case 32:
301 line[x] = val;
302 break;
303 default:
304 return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", __func__, 1);
305 }
306
307 return 0;
308 }
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 {
335 l_int32 w, h, d, wpl;
336 l_uint32 *data, *ppixel;
337
338 if (prval) *prval = 0;
339 if (pgval) *pgval = 0;
340 if (pbval) *pbval = 0;
341 if (!prval && !pgval && !pbval)
342 return ERROR_INT("no output requested", __func__, 1);
343 if (!pix)
344 return ERROR_INT("pix not defined", __func__, 1);
345 pixGetDimensions(pix, &w, &h, &d);
346 if (d != 32)
347 return ERROR_INT("pix not 32 bpp", __func__, 1);
348 if (x < 0 || x >= w || y < 0 || y >= h)
349 return 2;
350
351 wpl = pixGetWpl(pix);
352 data = pixGetData(pix);
353 ppixel = data + y * wpl + x;
354 if (prval) *prval = GET_DATA_BYTE(ppixel, COLOR_RED);
355 if (pgval) *pgval = GET_DATA_BYTE(ppixel, COLOR_GREEN);
356 if (pbval) *pbval = GET_DATA_BYTE(ppixel, COLOR_BLUE);
357 return 0;
358 }
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 {
385 l_int32 w, h, d, wpl;
386 l_uint32 pixel;
387 l_uint32 *data, *line;
388
389 if (!pix)
390 return ERROR_INT("pix not defined", __func__, 1);
391 pixGetDimensions(pix, &w, &h, &d);
392 if (d != 32)
393 return ERROR_INT("pix not 32 bpp", __func__, 1);
394 if (x < 0 || x >= w || y < 0 || y >= h)
395 return 2;
396
397 wpl = pixGetWpl(pix);
398 data = pixGetData(pix);
399 line = data + y * wpl;
400 composeRGBPixel(rval, gval, bval, &pixel);
401 *(line + x) = pixel;
402 return 0;
403 }
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 {
441 l_int32 w, h, d, index;
442 PIXCMAP *cmap;
443
444 if (!pix)
445 return ERROR_INT("pix not defined", __func__, 1);
446 if ((cmap = pixGetColormap(pix)) == NULL)
447 return ERROR_INT("pix is not colormapped", __func__, 1);
448 pixGetDimensions(pix, &w, &h, &d);
449 if (d != 2 && d != 4 && d != 8)
450 return ERROR_INT("pix depth not 2, 4 or 8", __func__, 1);
451 if (x < 0 || x >= w || y < 0 || y >= h)
452 return 2;
453
454 if (d == 8) { /* always add */
455 pixcmapAddNearestColor(cmap, rval, gval, bval, &index);
456 } else { /* d < 8 */
457 if (pixcmapAddNewColor(cmap, rval, gval, bval, &index) == 2)
458 return ERROR_INT("colormap is full", __func__, 2);
459 }
460 pixSetPixel(pix, x, y, index);
461 return 0;
462 }
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 {
485 l_int32 w, h, x, y, rval, gval, bval;
486 l_uint32 val;
487 PIXCMAP *cmap;
488
489 if (pval) *pval = 0;
490 if (px) *px = 0;
491 if (py) *py = 0;
492 if (!pval && !px && !py)
493 return ERROR_INT("no output requested", __func__, 1);
494 if (!pix)
495 return ERROR_INT("pix not defined", __func__, 1);
496
497 pixGetDimensions(pix, &w, &h, NULL);
498 x = rand() % w;
499 y = rand() % h;
500 if (px) *px = x;
501 if (py) *py = y;
502 if (pval) {
503 pixGetPixel(pix, x, y, &val);
504 if ((cmap = pixGetColormap(pix)) != NULL) {
505 pixcmapGetColor(cmap, val, &rval, &gval, &bval);
506 composeRGBPixel(rval, gval, bval, pval);
507 } else {
508 *pval = val;
509 }
510 }
511
512 return 0;
513 }
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 {
534 l_int32 w, h, d, wpl;
535 l_uint32 *line, *data;
536
537 if (!pix)
538 return ERROR_INT("pix not defined", __func__, 1);
539 if (pixGetColormap(pix))
540 L_WARNING("cmapped: setting to 0 may not be intended\n", __func__);
541 pixGetDimensions(pix, &w, &h, &d);
542 if (x < 0 || x >= w || y < 0 || y >= h)
543 return 2;
544
545 wpl = pixGetWpl(pix);
546 data = pixGetData(pix);
547 line = data + y * wpl;
548 switch (d)
549 {
550 case 1:
551 CLEAR_DATA_BIT(line, x);
552 break;
553 case 2:
554 CLEAR_DATA_DIBIT(line, x);
555 break;
556 case 4:
557 CLEAR_DATA_QBIT(line, x);
558 break;
559 case 8:
560 SET_DATA_BYTE(line, x, 0);
561 break;
562 case 16:
563 SET_DATA_TWO_BYTES(line, x, 0);
564 break;
565 case 32:
566 line[x] = 0;
567 break;
568 default:
569 return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", __func__, 1);
570 }
571
572 return 0;
573 }
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 {
594 l_int32 w, h, d, wpl;
595 l_uint32 val;
596 l_uint32 *line, *data;
597
598 if (!pix)
599 return ERROR_INT("pix not defined", __func__, 1);
600 if (pixGetColormap(pix))
601 L_WARNING("cmapped: setting to 0 may not be intended\n", __func__);
602 pixGetDimensions(pix, &w, &h, &d);
603 if (x < 0 || x >= w || y < 0 || y >= h)
604 return 2;
605
606 data = pixGetData(pix);
607 wpl = pixGetWpl(pix);
608 line = data + y * wpl;
609 switch (d)
610 {
611 case 1:
612 val = GET_DATA_BIT(line, x);
613 if (val)
614 CLEAR_DATA_BIT(line, x);
615 else
616 SET_DATA_BIT(line, x);
617 break;
618 case 2:
619 val = GET_DATA_DIBIT(line, x);
620 val ^= 0x3;
621 SET_DATA_DIBIT(line, x, val);
622 break;
623 case 4:
624 val = GET_DATA_QBIT(line, x);
625 val ^= 0xf;
626 SET_DATA_QBIT(line, x, val);
627 break;
628 case 8:
629 val = GET_DATA_BYTE(line, x);
630 val ^= 0xff;
631 SET_DATA_BYTE(line, x, val);
632 break;
633 case 16:
634 val = GET_DATA_TWO_BYTES(line, x);
635 val ^= 0xffff;
636 SET_DATA_TWO_BYTES(line, x, val);
637 break;
638 case 32:
639 val = line[x] ^ 0xffffffff;
640 line[x] = val;
641 break;
642 default:
643 return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", __func__, 1);
644 }
645
646 return 0;
647 }
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 {
670 switch (depth)
671 {
672 case 1:
673 if (val)
674 SET_DATA_BIT(line, x);
675 else
676 CLEAR_DATA_BIT(line, x);
677 break;
678 case 2:
679 SET_DATA_DIBIT(line, x, val);
680 break;
681 case 4:
682 SET_DATA_QBIT(line, x, val);
683 break;
684 case 8:
685 SET_DATA_BYTE(line, x, val);
686 break;
687 case 16:
688 SET_DATA_TWO_BYTES(line, x, val);
689 break;
690 case 32:
691 line[x] = val;
692 break;
693 default:
694 lept_stderr("illegal depth in setPixelLow()\n");
695 }
696 }
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 {
723 l_int32 d, index;
724 PIXCMAP *cmap;
725
726 if (!pval)
727 return ERROR_INT("&val not defined", __func__, 1);
728 *pval = 0;
729 if (!pixs)
730 return ERROR_INT("pixs not defined", __func__, 1);
731 if (op != L_GET_BLACK_VAL && op != L_GET_WHITE_VAL)
732 return ERROR_INT("invalid op", __func__, 1);
733
734 cmap = pixGetColormap(pixs);
735 d = pixGetDepth(pixs);
736 if (!cmap) {
737 if ((d == 1 && op == L_GET_WHITE_VAL) ||
738 (d > 1 && op == L_GET_BLACK_VAL)) { /* min val */
739 *pval = 0;
740 } else { /* max val */
741 *pval = (d == 32) ? 0xffffff00 : (1 << d) - 1;
742 }
743 } else { /* handle colormap */
744 if (op == L_GET_BLACK_VAL)
745 pixcmapAddBlackOrWhite(cmap, 0, &index);
746 else /* L_GET_WHITE_VAL */
747 pixcmapAddBlackOrWhite(cmap, 1, &index);
748 *pval = index;
749 }
750
751 return 0;
752 }
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 {
775 if (!pix)
776 return ERROR_INT("pix not defined", __func__, 1);
777
778 memset(pix->data, 0, 4LL * pix->wpl * pix->h);
779 return 0;
780 }
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 {
801 l_int32 n;
802 PIXCMAP *cmap;
803
804 if (!pix)
805 return ERROR_INT("pix not defined", __func__, 1);
806 if ((cmap = pixGetColormap(pix)) != NULL) {
807 n = pixcmapGetCount(cmap);
808 if (n < cmap->nalloc) /* cmap is not full */
809 return ERROR_INT("cmap entry does not exist", __func__, 1);
810 }
811
812 memset(pix->data, 0xff, 4LL * pix->wpl * pix->h);
813 return 0;
814 }
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 {
842 l_int32 d, spp, index;
843 l_uint32 val32;
844 PIX *alpha;
845 PIXCMAP *cmap;
846
847 if (!pix)
848 return ERROR_INT("pix not defined", __func__, 1);
849 if (grayval < 0) {
850 L_WARNING("grayval < 0; setting to 0\n", __func__);
851 grayval = 0;
852 } else if (grayval > 255) {
853 L_WARNING("grayval > 255; setting to 255\n", __func__);
854 grayval = 255;
855 }
856
857 /* Handle the colormap case */
858 cmap = pixGetColormap(pix);
859 if (cmap) {
860 pixcmapAddNearestColor(cmap, grayval, grayval, grayval, &index);
861 pixSetAllArbitrary(pix, index);
862 return 0;
863 }
864
865 /* Non-cmapped */
866 d = pixGetDepth(pix);
867 spp = pixGetSpp(pix);
868 if (d == 1) {
869 if (grayval < 128) /* black */
870 pixSetAll(pix);
871 else
872 pixClearAll(pix); /* white */
873 } else if (d < 8) {
874 grayval >>= 8 - d;
875 pixSetAllArbitrary(pix, grayval);
876 } else if (d == 8) {
877 pixSetAllArbitrary(pix, grayval);
878 } else if (d == 16) {
879 grayval |= (grayval << 8);
880 pixSetAllArbitrary(pix, grayval);
881 } else if (d == 32 && spp == 3) {
882 composeRGBPixel(grayval, grayval, grayval, &val32);
883 pixSetAllArbitrary(pix, val32);
884 } else if (d == 32 && spp == 4) {
885 alpha = pixGetRGBComponent(pix, L_ALPHA_CHANNEL);
886 composeRGBPixel(grayval, grayval, grayval, &val32);
887 pixSetAllArbitrary(pix, val32);
888 pixSetRGBComponent(pix, alpha, L_ALPHA_CHANNEL);
889 pixDestroy(&alpha);
890 } else {
891 L_ERROR("invalid depth: %d\n", __func__, d);
892 return 1;
893 }
894
895 return 0;
896 }
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 {
932 l_int32 n, i, j, w, h, d, wpl, npix;
933 l_uint32 maxval, wordval;
934 l_uint32 *data, *line;
935 PIXCMAP *cmap;
936
937 if (!pix)
938 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 if ((cmap = pixGetColormap(pix)) != NULL) {
943 n = pixcmapGetCount(cmap);
944 if (val >= n) {
945 L_WARNING("index not in colormap; using last color\n", __func__);
946 val = n - 1;
947 }
948 }
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 pixGetDimensions(pix, &w, &h, &d);
953 if (d < 32) {
954 maxval = (1 << d) - 1;
955 if (val > maxval) {
956 L_WARNING("val = %d too large for depth; using maxval = %d\n",
957 __func__, val, maxval);
958 val = maxval;
959 }
960 }
961
962 /* Set up word to tile with */
963 wordval = 0;
964 npix = 32 / d; /* number of pixels per 32 bit word */
965 for (j = 0; j < npix; j++)
966 wordval |= (val << (j * d));
967 wpl = pixGetWpl(pix);
968 data = pixGetData(pix);
969 for (i = 0; i < h; i++) {
970 line = data + i * wpl;
971 for (j = 0; j < wpl; j++) {
972 *(line + j) = wordval;
973 }
974 }
975 return 0;
976 }
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 {
1000 l_int32 d, index;
1001 PIXCMAP *cmap;
1002
1003 if (!pixs)
1004 return ERROR_INT("pix not defined", __func__, 1);
1005 if (op != L_SET_BLACK && op != L_SET_WHITE)
1006 return ERROR_INT("invalid op", __func__, 1);
1007
1008 cmap = pixGetColormap(pixs);
1009 d = pixGetDepth(pixs);
1010 if (!cmap) {
1011 if ((d == 1 && op == L_SET_BLACK) || (d > 1 && op == L_SET_WHITE))
1012 pixSetAll(pixs);
1013 else
1014 pixClearAll(pixs);
1015 } else { /* handle colormap */
1016 if (op == L_SET_BLACK)
1017 pixcmapAddBlackOrWhite(cmap, 0, &index);
1018 else /* L_SET_WHITE */
1019 pixcmapAddBlackOrWhite(cmap, 1, &index);
1020 pixSetAllArbitrary(pixs, index);
1021 }
1022
1023 return 0;
1024 }
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 {
1046 l_int32 i, nwords;
1047 l_uint32 mask1, mask2;
1048 l_uint32 *data;
1049
1050 if (!pix || pixGetDepth(pix) != 32)
1051 return ERROR_INT("pix not defined or not 32 bpp", __func__, 1);
1052 if (comp != COLOR_RED && comp != COLOR_GREEN && comp != COLOR_BLUE &&
1053 comp != L_ALPHA_CHANNEL)
1054 return ERROR_INT("invalid component", __func__, 1);
1055 if (val < 0 || val > 255)
1056 return ERROR_INT("val not in [0 ... 255]", __func__, 1);
1057
1058 mask1 = ~(255 << (8 * (3 - comp)));
1059 mask2 = val << (8 * (3 - comp));
1060 nwords = pixGetHeight(pix) * pixGetWpl(pix);
1061 data = pixGetData(pix);
1062 for (i = 0; i < nwords; i++) {
1063 data[i] &= mask1; /* clear out the component */
1064 data[i] |= mask2; /* insert the new component value */
1065 }
1066
1067 return 0;
1068 }
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 {
1093 l_int32 x, y, w, h;
1094
1095 if (!pix)
1096 return ERROR_INT("pix not defined", __func__, 1);
1097 if (!box)
1098 return ERROR_INT("box not defined", __func__, 1);
1099
1100 boxGetGeometry(box, &x, &y, &w, &h);
1101 pixRasterop(pix, x, y, w, h, PIX_CLR, NULL, 0, 0);
1102 return 0;
1103 }
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 {
1126 l_int32 n, x, y, w, h;
1127 PIXCMAP *cmap;
1128
1129 if (!pix)
1130 return ERROR_INT("pix not defined", __func__, 1);
1131 if (!box)
1132 return ERROR_INT("box not defined", __func__, 1);
1133 if ((cmap = pixGetColormap(pix)) != NULL) {
1134 n = pixcmapGetCount(cmap);
1135 if (n < cmap->nalloc) /* cmap is not full */
1136 return ERROR_INT("cmap entry does not exist", __func__, 1);
1137 }
1138
1139 boxGetGeometry(box, &x, &y, &w, &h);
1140 pixRasterop(pix, x, y, w, h, PIX_SET, NULL, 0, 0);
1141 return 0;
1142 }
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 {
1167 l_int32 n, x, y, xstart, xend, ystart, yend, bw, bh, w, h, d, wpl;
1168 l_uint32 maxval;
1169 l_uint32 *data, *line;
1170 BOX *boxc;
1171 PIXCMAP *cmap;
1172
1173 if (!pix)
1174 return ERROR_INT("pix not defined", __func__, 1);
1175 if (!box)
1176 return ERROR_INT("box not defined", __func__, 1);
1177 pixGetDimensions(pix, &w, &h, &d);
1178 if (d != 1 && d != 2 && d != 4 && d !=8 && d != 16 && d != 32)
1179 return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", __func__, 1);
1180 if ((cmap = pixGetColormap(pix)) != NULL) {
1181 n = pixcmapGetCount(cmap);
1182 if (val >= n) {
1183 L_WARNING("index not in colormap; using last color\n", __func__);
1184 val = n - 1;
1185 }
1186 }
1187
1188 maxval = (d == 32) ? 0xffffff00 : (1 << d) - 1;
1189 if (val > maxval) val = maxval;
1190
1191 /* Handle the simple cases: the min and max values */
1192 if (val == 0) {
1193 pixClearInRect(pix, box);
1194 return 0;
1195 }
1196 if (d == 1 ||
1197 (d == 2 && val == 3) ||
1198 (d == 4 && val == 0xf) ||
1199 (d == 8 && val == 0xff) ||
1200 (d == 16 && val == 0xffff) ||
1201 (d == 32 && ((val ^ 0xffffff00) >> 8 == 0))) {
1202 pixSetInRect(pix, box);
1203 return 0;
1204 }
1205
1206 /* Find the overlap of box with the input pix */
1207 if ((boxc = boxClipToRectangle(box, w, h)) == NULL)
1208 return ERROR_INT("no overlap of box with image", __func__, 1);
1209 boxGetGeometry(boxc, &xstart, &ystart, &bw, &bh);
1210 xend = xstart + bw - 1;
1211 yend = ystart + bh - 1;
1212 boxDestroy(&boxc);
1213
1214 wpl = pixGetWpl(pix);
1215 data = pixGetData(pix);
1216 for (y = ystart; y <= yend; y++) {
1217 line = data + y * wpl;
1218 for (x = xstart; x <= xend; x++) {
1219 switch(d)
1220 {
1221 case 2:
1222 SET_DATA_DIBIT(line, x, val);
1223 break;
1224 case 4:
1225 SET_DATA_QBIT(line, x, val);
1226 break;
1227 case 8:
1228 SET_DATA_BYTE(line, x, val);
1229 break;
1230 case 16:
1231 SET_DATA_TWO_BYTES(line, x, val);
1232 break;
1233 case 32:
1234 line[x] = val;
1235 break;
1236 default:
1237 return ERROR_INT("depth not 2|4|8|16|32 bpp", __func__, 1);
1238 }
1239 }
1240 }
1241
1242 return 0;
1243 }
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 {
1268 l_int32 i, j, bx, by, bw, bh, w, h, wpls;
1269 l_int32 prval, pgval, pbval, rval, gval, bval;
1270 l_uint32 val32;
1271 l_uint32 *datas, *lines;
1272
1273 if (!pixs || pixGetDepth(pixs) != 32)
1274 return ERROR_INT("pixs not defined or not 32 bpp", __func__, 1);
1275
1276 extractRGBValues(val, &rval, &gval, &bval);
1277 pixGetDimensions(pixs, &w, &h, NULL);
1278 datas = pixGetData(pixs);
1279 wpls = pixGetWpl(pixs);
1280 if (!box) {
1281 for (i = 0; i < h; i++) { /* scan over box */
1282 lines = datas + i * wpls;
1283 for (j = 0; j < w; j++) {
1284 val32 = *(lines + j);
1285 extractRGBValues(val32, &prval, &pgval, &pbval);
1286 prval = (l_int32)((1. - fract) * prval + fract * rval);
1287 pgval = (l_int32)((1. - fract) * pgval + fract * gval);
1288 pbval = (l_int32)((1. - fract) * pbval + fract * bval);
1289 composeRGBPixel(prval, pgval, pbval, &val32);
1290 *(lines + j) = val32;
1291 }
1292 }
1293 return 0;
1294 }
1295
1296 boxGetGeometry(box, &bx, &by, &bw, &bh);
1297 for (i = 0; i < bh; i++) { /* scan over box */
1298 if (by + i < 0 || by + i >= h) continue;
1299 lines = datas + (by + i) * wpls;
1300 for (j = 0; j < bw; j++) {
1301 if (bx + j < 0 || bx + j >= w) continue;
1302 val32 = *(lines + bx + j);
1303 extractRGBValues(val32, &prval, &pgval, &pbval);
1304 prval = (l_int32)((1. - fract) * prval + fract * rval);
1305 pgval = (l_int32)((1. - fract) * pgval + fract * gval);
1306 pbval = (l_int32)((1. - fract) * pbval + fract * bval);
1307 composeRGBPixel(prval, pgval, pbval, &val32);
1308 *(lines + bx + j) = val32;
1309 }
1310 }
1311 return 0;
1312 }
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 {
1353 l_int32 i, w, h, d, wpl, endbits, fullwords;
1354 l_uint32 mask;
1355 l_uint32 *data, *pword;
1356
1357 if (!pix)
1358 return ERROR_INT("pix not defined", __func__, 1);
1359
1360 pixGetDimensions(pix, &w, &h, &d);
1361 if (d == 32) /* no padding exists for 32 bpp */
1362 return 0;
1363 if (d == 24) { /* pixels not aligned with 32-bit words */
1364 L_INFO("pix is 24 bpp\n", __func__);
1365 return 1;
1366 }
1367
1368 data = pixGetData(pix);
1369 wpl = pixGetWpl(pix);
1370 endbits = 32 - (((l_int64)w * d) % 32);
1371 if (endbits == 32) /* no partial word */
1372 return 0;
1373 fullwords = (1LL * w * d) / 32;
1374 mask = rmask32[endbits];
1375 if (val == 0)
1376 mask = ~mask;
1377
1378 for (i = 0; i < h; i++) {
1379 pword = data + i * wpl + fullwords;
1380 if (val == 0) /* clear */
1381 *pword = *pword & mask;
1382 else /* set */
1383 *pword = *pword | mask;
1384 }
1385
1386 return 0;
1387 }
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 {
1418 l_int32 i, w, h, d, wpl, endbits, fullwords;
1419 l_uint32 mask;
1420 l_uint32 *data, *pword;
1421
1422 if (!pix)
1423 return ERROR_INT("pix not defined", __func__, 1);
1424
1425 pixGetDimensions(pix, &w, &h, &d);
1426 if (d == 32) /* no padding exists for 32 bpp */
1427 return 0;
1428 if (d == 24) { /* pixels not aligned with 32-bit words */
1429 L_INFO("pix is 24 bpp\n", __func__);
1430 return 1;
1431 }
1432
1433 if (by < 0)
1434 by = 0;
1435 if (by >= h)
1436 return ERROR_INT("start y not in image", __func__, 1);
1437 if (by + bh > h)
1438 bh = h - by;
1439
1440 data = pixGetData(pix);
1441 wpl = pixGetWpl(pix);
1442 endbits = 32 - (((l_int64)w * d) % 32);
1443 if (endbits == 32) /* no partial word */
1444 return 0;
1445 fullwords = (l_int64)w * d / 32;
1446
1447 mask = rmask32[endbits];
1448 if (val == 0)
1449 mask = ~mask;
1450
1451 for (i = by; i < by + bh; i++) {
1452 pword = data + i * wpl + fullwords;
1453 if (val == 0) /* clear */
1454 *pword = *pword & mask;
1455 else /* set */
1456 *pword = *pword | mask;
1457 }
1458
1459 return 0;
1460 }
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 {
1494 l_int32 w, h;
1495
1496 if (!pixs)
1497 return ERROR_INT("pixs not defined", __func__, 1);
1498 if (op != PIX_SET && op != PIX_CLR)
1499 return ERROR_INT("op must be PIX_SET or PIX_CLR", __func__, 1);
1500
1501 pixGetDimensions(pixs, &w, &h, NULL);
1502 pixRasterop(pixs, 0, 0, left, h, op, NULL, 0, 0);
1503 pixRasterop(pixs, w - right, 0, right, h, op, NULL, 0, 0);
1504 pixRasterop(pixs, 0, 0, w, top, op, NULL, 0, 0);
1505 pixRasterop(pixs, 0, h - bot, w, bot, op, NULL, 0, 0);
1506
1507 return 0;
1508 }
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 {
1541 l_int32 w, h, d, wpls, i, j, bstart, rstart;
1542 l_uint32 *datas, *lines;
1543
1544 if (!pixs)
1545 return ERROR_INT("pixs not defined", __func__, 1);
1546 pixGetDimensions(pixs, &w, &h, &d);
1547 if (d != 8 && d != 16 && d != 32)
1548 return ERROR_INT("depth must be 8, 16 or 32 bpp", __func__, 1);
1549
1550 datas = pixGetData(pixs);
1551 wpls = pixGetWpl(pixs);
1552 if (d == 8) {
1553 val &= 0xff;
1554 for (i = 0; i < top; i++) {
1555 lines = datas + i * wpls;
1556 for (j = 0; j < w; j++)
1557 SET_DATA_BYTE(lines, j, val);
1558 }
1559 rstart = w - right;
1560 bstart = h - bot;
1561 for (i = top; i < bstart; i++) {
1562 lines = datas + i * wpls;
1563 for (j = 0; j < left; j++)
1564 SET_DATA_BYTE(lines, j, val);
1565 for (j = rstart; j < w; j++)
1566 SET_DATA_BYTE(lines, j, val);
1567 }
1568 for (i = bstart; i < h; i++) {
1569 lines = datas + i * wpls;
1570 for (j = 0; j < w; j++)
1571 SET_DATA_BYTE(lines, j, val);
1572 }
1573 } else if (d == 16) {
1574 val &= 0xffff;
1575 for (i = 0; i < top; i++) {
1576 lines = datas + i * wpls;
1577 for (j = 0; j < w; j++)
1578 SET_DATA_TWO_BYTES(lines, j, val);
1579 }
1580 rstart = w - right;
1581 bstart = h - bot;
1582 for (i = top; i < bstart; i++) {
1583 lines = datas + i * wpls;
1584 for (j = 0; j < left; j++)
1585 SET_DATA_TWO_BYTES(lines, j, val);
1586 for (j = rstart; j < w; j++)
1587 SET_DATA_TWO_BYTES(lines, j, val);
1588 }
1589 for (i = bstart; i < h; i++) {
1590 lines = datas + i * wpls;
1591 for (j = 0; j < w; j++)
1592 SET_DATA_TWO_BYTES(lines, j, val);
1593 }
1594 } else { /* d == 32 */
1595 for (i = 0; i < top; i++) {
1596 lines = datas + i * wpls;
1597 for (j = 0; j < w; j++)
1598 *(lines + j) = val;
1599 }
1600 rstart = w - right;
1601 bstart = h - bot;
1602 for (i = top; i < bstart; i++) {
1603 lines = datas + i * wpls;
1604 for (j = 0; j < left; j++)
1605 *(lines + j) = val;
1606 for (j = rstart; j < w; j++)
1607 *(lines + j) = val;
1608 }
1609 for (i = bstart; i < h; i++) {
1610 lines = datas + i * wpls;
1611 for (j = 0; j < w; j++)
1612 *(lines + j) = val;
1613 }
1614 }
1615
1616 return 0;
1617 }
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 {
1640 l_int32 w, h, d, i, j, xend, yend;
1641
1642 if (!pixs)
1643 return ERROR_INT("pixs not defined", __func__, 1);
1644 if (dist < 1)
1645 return ERROR_INT("dist must be > 0", __func__, 1);
1646 pixGetDimensions(pixs, &w, &h, &d);
1647 if (w < 2 * dist + 1 || h < 2 * dist + 1)
1648 return ERROR_INT("ring doesn't exist", __func__, 1);
1649 if (d < 32 && (val >= (1 << d)))
1650 return ERROR_INT("invalid pixel value", __func__, 1);
1651
1652 xend = w - dist;
1653 yend = h - dist;
1654 for (j = dist - 1; j <= xend; j++)
1655 pixSetPixel(pixs, j, dist - 1, val);
1656 for (j = dist - 1; j <= xend; j++)
1657 pixSetPixel(pixs, j, yend, val);
1658 for (i = dist - 1; i <= yend; i++)
1659 pixSetPixel(pixs, dist - 1, i, val);
1660 for (i = dist - 1; i <= yend; i++)
1661 pixSetPixel(pixs, xend, i, val);
1662
1663 return 0;
1664 }
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 {
1691 l_int32 i, j, w, h;
1692
1693 if (!pixs)
1694 return ERROR_INT("pixs not defined", __func__, 1);
1695
1696 pixGetDimensions(pixs, &w, &h, NULL);
1697 for (j = 0; j < left; j++)
1698 pixRasterop(pixs, left - 1 - j, top, 1, h - top - bot, PIX_SRC,
1699 pixs, left + j, top);
1700 for (j = 0; j < right; j++)
1701 pixRasterop(pixs, w - right + j, top, 1, h - top - bot, PIX_SRC,
1702 pixs, w - right - 1 - j, top);
1703 for (i = 0; i < top; i++)
1704 pixRasterop(pixs, 0, top - 1 - i, w, 1, PIX_SRC,
1705 pixs, 0, top + i);
1706 for (i = 0; i < bot; i++)
1707 pixRasterop(pixs, 0, h - bot + i, w, 1, PIX_SRC,
1708 pixs, 0, h - bot - 1 - i);
1709
1710 return 0;
1711 }
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 {
1741 l_int32 w, h;
1742
1743 if (!pixs)
1744 return (PIX *)ERROR_PTR("pixs not defined", __func__, pixd);
1745
1746 if (pixd) {
1747 if (pixd == pixs) {
1748 L_WARNING("same: nothing to do\n", __func__);
1749 return pixd;
1750 } else if (!pixSizesEqual(pixs, pixd)) {
1751 return (PIX *)ERROR_PTR("pixs and pixd sizes differ",
1752 __func__, pixd);
1753 }
1754 } else {
1755 if ((pixd = pixCreateTemplate(pixs)) == NULL)
1756 return (PIX *)ERROR_PTR("pixd not made", __func__, pixd);
1757 }
1758
1759 pixGetDimensions(pixs, &w, &h, NULL);
1760 pixRasterop(pixd, 0, 0, left, h, PIX_SRC, pixs, 0, 0);
1761 pixRasterop(pixd, w - right, 0, right, h, PIX_SRC, pixs, w - right, 0);
1762 pixRasterop(pixd, 0, 0, w, top, PIX_SRC, pixs, 0, 0);
1763 pixRasterop(pixd, 0, h - bot, w, bot, PIX_SRC, pixs, 0, h - bot);
1764 return pixd;
1765 }
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 {
1790 if (!pixs)
1791 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1792 if (npix == 0)
1793 return pixClone(pixs);
1794 return pixAddBorderGeneral(pixs, npix, npix, npix, npix, val);
1795 }
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 {
1831 l_uint32 val;
1832
1833 if (!pixs)
1834 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1835 if (op != L_GET_BLACK_VAL && op != L_GET_WHITE_VAL)
1836 return (PIX *)ERROR_PTR("invalid op", __func__, NULL);
1837
1838 pixGetBlackOrWhiteVal(pixs, op, &val);
1839 return pixAddBorderGeneral(pixs, left, right, top, bot, val);
1840 }
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 {
1883 l_int32 ws, hs, wd, hd, d, op;
1884 l_uint32 maxval;
1885 PIX *pixd;
1886
1887 if (!pixs)
1888 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1889 if (left < 0 || right < 0 || top < 0 || bot < 0)
1890 return (PIX *)ERROR_PTR("negative border added!", __func__, NULL);
1891
1892 pixGetDimensions(pixs, &ws, &hs, &d);
1893 wd = ws + left + right;
1894 hd = hs + top + bot;
1895 if ((pixd = pixCreate(wd, hd, d)) == NULL)
1896 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1897 pixCopyResolution(pixd, pixs);
1898 pixCopyColormap(pixd, pixs);
1899
1900 /* Set the new border pixels */
1901 maxval = (d == 32) ? 0xffffff00 : (1 << d) - 1;
1902 op = UNDEF;
1903 if (val == 0)
1904 op = PIX_CLR;
1905 else if (val >= maxval)
1906 op = PIX_SET;
1907 if (op == UNDEF) {
1908 pixSetAllArbitrary(pixd, val);
1909 } else { /* just set or clear the border pixels */
1910 pixRasterop(pixd, 0, 0, left, hd, op, NULL, 0, 0);
1911 pixRasterop(pixd, wd - right, 0, right, hd, op, NULL, 0, 0);
1912 pixRasterop(pixd, 0, 0, wd, top, op, NULL, 0, 0);
1913 pixRasterop(pixd, 0, hd - bot, wd, bot, op, NULL, 0, 0);
1914 }
1915
1916 /* Copy pixs into the interior */
1917 pixRasterop(pixd, left, top, ws, hs, PIX_SRC, pixs, 0, 0);
1918 return pixd;
1919 }
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 {
1953 l_int32 i, color;
1954 l_int32 w[6];
1955 PIX *pix1, *pixd;
1956
1957 if (!pixs)
1958 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1959
1960 w[0] = nblack1;
1961 w[1] = nwhite1;
1962 w[2] = nblack2;
1963 w[3] = nwhite2;
1964 w[4] = nblack3;
1965 w[5] = nwhite3;
1966 pixd = pixClone(pixs);
1967 for (i = 0; i < 6; i++) {
1968 if (w[i] > 500)
1969 L_WARNING("w = %d > 500; skipping\n", __func__, w[i]);
1970 if (w[i] > 0 && w[i] <= 500) {
1971 color = (i % 2 == 0) ? L_GET_BLACK_VAL : L_GET_WHITE_VAL;
1972 pix1 = pixAddBlackOrWhiteBorder(pixd, w[i], w[i], w[i], w[i],
1973 color);
1974 pixDestroy(&pixd);
1975 pixd = pix1;
1976 }
1977 }
1978
1979 return pixd;
1980 }
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 {
1994 if (!pixs)
1995 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1996 if (npix == 0)
1997 return pixClone(pixs);
1998 return pixRemoveBorderGeneral(pixs, npix, npix, npix, npix);
1999 }
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 {
2016 l_int32 ws, hs, wd, hd, d;
2017 PIX *pixd;
2018
2019 if (!pixs)
2020 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2021 if (left < 0 || right < 0 || top < 0 || bot < 0)
2022 return (PIX *)ERROR_PTR("negative border removed!", __func__, NULL);
2023
2024 pixGetDimensions(pixs, &ws, &hs, &d);
2025 wd = ws - left - right;
2026 hd = hs - top - bot;
2027 if (wd <= 0)
2028 return (PIX *)ERROR_PTR("width must be > 0", __func__, NULL);
2029 if (hd <= 0)
2030 return (PIX *)ERROR_PTR("height must be > 0", __func__, NULL);
2031 if ((pixd = pixCreate(wd, hd, d)) == NULL)
2032 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
2033 pixCopyResolution(pixd, pixs);
2034 pixCopySpp(pixd, pixs);
2035 pixCopyColormap(pixd, pixs);
2036
2037 pixRasterop(pixd, 0, 0, wd, hd, PIX_SRC, pixs, left, top);
2038 if (pixGetDepth(pixs) == 32 && pixGetSpp(pixs) == 4)
2039 pixShiftAndTransferAlpha(pixd, pixs, -left, -top);
2040 return pixd;
2041 }
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 {
2065 l_int32 w, h, top, bot, left, right, delta;
2066
2067 if (!pixs)
2068 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2069
2070 pixGetDimensions(pixs, &w, &h, NULL);
2071 if ((wd <= 0 || wd >= w) && (hd <= 0 || hd >= h))
2072 return pixClone(pixs);
2073
2074 left = right = (w - wd) / 2;
2075 delta = w - 2 * left - wd;
2076 right += delta;
2077 top = bot = (h - hd) / 2;
2078 delta = h - hd - 2 * top;
2079 bot += delta;
2080 if (wd <= 0 || wd > w)
2081 left = right = 0;
2082 else if (hd <= 0 || hd > h)
2083 top = bot = 0;
2084
2085 return pixRemoveBorderGeneral(pixs, left, right, top, bot);
2086 }
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 {
2120 l_int32 i, j, w, h;
2121 PIX *pixd;
2122
2123 if (!pixs)
2124 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2125 pixGetDimensions(pixs, &w, &h, NULL);
2126 if (left > w || right > w || top > h || bot > h)
2127 return (PIX *)ERROR_PTR("border too large", __func__, NULL);
2128
2129 /* Set pixels on left, right, top and bottom, in that order */
2130 pixd = pixAddBorderGeneral(pixs, left, right, top, bot, 0);
2131 for (j = 0; j < left; j++)
2132 pixRasterop(pixd, left - 1 - j, top, 1, h, PIX_SRC,
2133 pixd, left + j, top);
2134 for (j = 0; j < right; j++)
2135 pixRasterop(pixd, left + w + j, top, 1, h, PIX_SRC,
2136 pixd, left + w - 1 - j, top);
2137 for (i = 0; i < top; i++)
2138 pixRasterop(pixd, 0, top - 1 - i, left + w + right, 1, PIX_SRC,
2139 pixd, 0, top + i);
2140 for (i = 0; i < bot; i++)
2141 pixRasterop(pixd, 0, top + h + i, left + w + right, 1, PIX_SRC,
2142 pixd, 0, top + h - 1 - i);
2143
2144 return pixd;
2145 }
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 {
2171 l_int32 w, h;
2172 PIX *pixd;
2173
2174 if (!pixs)
2175 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2176 pixGetDimensions(pixs, &w, &h, NULL);
2177 if (left > w || right > w || top > h || bot > h)
2178 return (PIX *)ERROR_PTR("border too large", __func__, NULL);
2179
2180 pixd = pixAddBorderGeneral(pixs, left, right, top, bot, 0);
2181
2182 /* Set pixels on left, right, top and bottom, in that order */
2183 pixRasterop(pixd, 0, top, left, h, PIX_SRC, pixd, w, top);
2184 pixRasterop(pixd, left + w, top, right, h, PIX_SRC, pixd, left, top);
2185 pixRasterop(pixd, 0, 0, left + w + right, top, PIX_SRC, pixd, 0, h);
2186 pixRasterop(pixd, 0, top + h, left + w + right, bot, PIX_SRC, pixd, 0, top);
2187
2188 return pixd;
2189 }
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 {
2225 l_int32 j, w, h;
2226 PIX *pixd;
2227
2228 if (!pixs)
2229 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2230 pixGetDimensions(pixs, &w, &h, NULL);
2231 if (left > w || right > w || top > h || bot > h)
2232 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 pixd = pixAddBorderGeneral(pixs, left, right, top, bot, 0);
2237 for (j = 0; j < left; j++)
2238 pixRasterop(pixd, left - 1 - j, top, 1, h, PIX_SRC,
2239 pixd, left + j, top);
2240 for (j = 0; j < right; j++)
2241 pixRasterop(pixd, left + w + j, top, 1, h, PIX_SRC,
2242 pixd, left + w - 1 - j, top);
2243 pixRasterop(pixd, 0, 0, left + w + right, top, PIX_SRC, pixd, 0, h);
2244 pixRasterop(pixd, 0, top + h, left + w + right, bot, PIX_SRC, pixd, 0, top);
2245
2246 return pixd;
2247 }
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 {
2270 l_int32 i, j, w, h;
2271 PIX *pixd;
2272
2273 if (!pixs)
2274 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2275
2276 pixd = pixAddBorderGeneral(pixs, left, right, top, bot, 0);
2277 pixGetDimensions(pixs, &w, &h, NULL);
2278 for (j = 0; j < left; j++)
2279 pixRasterop(pixd, j, top, 1, h, PIX_SRC, pixd, left, top);
2280 for (j = 0; j < right; j++)
2281 pixRasterop(pixd, left + w + j, top, 1, h,
2282 PIX_SRC, pixd, left + w - 1, top);
2283 for (i = 0; i < top; i++)
2284 pixRasterop(pixd, 0, i, left + w + right, 1, PIX_SRC, pixd, 0, top);
2285 for (i = 0; i < bot; i++)
2286 pixRasterop(pixd, 0, top + h + i, left + w + right, 1,
2287 PIX_SRC, pixd, 0, top + h - 1);
2288
2289 return pixd;
2290 }
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 {
2310 l_int32 w, h;
2311 PIX *pix1, *pix2;
2312
2313 if (!pixs || !pixd)
2314 return ERROR_INT("pixs and pixd not both defined", __func__, 1);
2315 if (pixGetDepth(pixs) != 32 || pixGetSpp(pixs) != 4)
2316 return ERROR_INT("pixs not 32 bpp and 4 spp", __func__, 1);
2317 if (pixGetDepth(pixd) != 32)
2318 return ERROR_INT("pixd not 32 bpp", __func__, 1);
2319
2320 if (shiftx == 0 && shifty == 0) {
2321 pixCopyRGBComponent(pixd, pixs, L_ALPHA_CHANNEL);
2322 return 0;
2323 }
2324
2325 pix1 = pixGetRGBComponent(pixs, L_ALPHA_CHANNEL);
2326 pixGetDimensions(pixd, &w, &h, NULL);
2327 pix2 = pixCreate(w, h, 8);
2328 pixRasterop(pix2, 0, 0, w, h, PIX_SRC, pix1, -shiftx, -shifty);
2329 pixSetRGBComponent(pixd, pix2, L_ALPHA_CHANNEL);
2330 pixDestroy(&pix1);
2331 pixDestroy(&pix2);
2332 return 0;
2333 }
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 {
2358 l_int32 w, width;
2359 l_float32 scalefact;
2360 PIX *pix1, *pix2, *pixd;
2361 PIXA *pixa;
2362 PIXCMAP *cmap;
2363
2364 if (!pixs)
2365 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2366 cmap = pixGetColormap(pixs);
2367 if (!cmap && !(pixGetDepth(pixs) == 32 && pixGetSpp(pixs) == 4))
2368 return (PIX *)ERROR_PTR("pixs not cmap and not 32 bpp rgba",
2369 __func__, NULL);
2370 if ((w = pixGetWidth(pixs)) == 0)
2371 return (PIX *)ERROR_PTR("pixs width 0 !!", __func__, NULL);
2372
2373 if (cmap)
2374 pix1 = pixRemoveColormap(pixs, REMOVE_CMAP_WITH_ALPHA);
2375 else
2376 pix1 = pixCopy(NULL, pixs);
2377
2378 /* Scale if necessary so the output width is not larger than maxw */
2379 scalefact = (maxw == 0) ? 1.0f : L_MIN(1.0f, (l_float32)(maxw) / w);
2380 width = (l_int32)(scalefact * w);
2381
2382 pixa = pixaCreate(3);
2383 pixSetSpp(pix1, 3);
2384 pixaAddPix(pixa, pix1, L_INSERT); /* show the rgb values */
2385 pix1 = pixGetRGBComponent(pixs, L_ALPHA_CHANNEL);
2386 pix2 = pixConvertTo32(pix1);
2387 pixaAddPix(pixa, pix2, L_INSERT); /* show the alpha channel */
2388 pixDestroy(&pix1);
2389 pix1 = pixAlphaBlendUniform(pixs, (val & 0xffffff00));
2390 pixaAddPix(pixa, pix1, L_INSERT); /* with %val color bg showing */
2391 pixd = pixaDisplayTiledInRows(pixa, 32, width, scalefact, 0, 25, 2);
2392 pixaDestroy(&pixa);
2393 return pixd;
2394 }
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 {
2428 l_int32 wr, wg, wb, hr, hg, hb, dr, dg, db;
2429 PIX *pixd;
2430
2431 if (!pixr)
2432 return (PIX *)ERROR_PTR("pixr not defined", __func__, NULL);
2433 if (!pixg)
2434 return (PIX *)ERROR_PTR("pixg not defined", __func__, NULL);
2435 if (!pixb)
2436 return (PIX *)ERROR_PTR("pixb not defined", __func__, NULL);
2437 pixGetDimensions(pixr, &wr, &hr, &dr);
2438 pixGetDimensions(pixg, &wg, &hg, &dg);
2439 pixGetDimensions(pixb, &wb, &hb, &db);
2440 if (dr != 8 || dg != 8 || db != 8)
2441 return (PIX *)ERROR_PTR("input pix not all 8 bpp", __func__, NULL);
2442 if (wr != wg || wr != wb)
2443 return (PIX *)ERROR_PTR("widths not the same", __func__, NULL);
2444 if (hr != hg || hr != hb)
2445 return (PIX *)ERROR_PTR("heights not the same", __func__, NULL);
2446
2447 if ((pixd = pixCreate(wr, hr, 32)) == NULL)
2448 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
2449 pixCopyResolution(pixd, pixr);
2450 pixSetRGBComponent(pixd, pixr, COLOR_RED);
2451 pixSetRGBComponent(pixd, pixg, COLOR_GREEN);
2452 pixSetRGBComponent(pixd, pixb, COLOR_BLUE);
2453
2454 return pixd;
2455 }
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 {
2481 l_int32 i, j, w, h, wpls, wpld, val;
2482 l_uint32 *lines, *lined;
2483 l_uint32 *datas, *datad;
2484 PIX *pixd;
2485
2486 if (!pixs)
2487 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2488 if (pixGetColormap(pixs))
2489 return pixGetRGBComponentCmap(pixs, comp);
2490 if (pixGetDepth(pixs) != 32)
2491 return (PIX *)ERROR_PTR("pixs not 32 bpp", __func__, NULL);
2492 if (comp != COLOR_RED && comp != COLOR_GREEN &&
2493 comp != COLOR_BLUE && comp != L_ALPHA_CHANNEL)
2494 return (PIX *)ERROR_PTR("invalid comp", __func__, NULL);
2495
2496 pixGetDimensions(pixs, &w, &h, NULL);
2497 if ((pixd = pixCreate(w, h, 8)) == NULL)
2498 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
2499 pixCopyResolution(pixd, pixs);
2500 wpls = pixGetWpl(pixs);
2501 wpld = pixGetWpl(pixd);
2502 datas = pixGetData(pixs);
2503 datad = pixGetData(pixd);
2504 for (i = 0; i < h; i++) {
2505 lines = datas + i * wpls;
2506 lined = datad + i * wpld;
2507 for (j = 0; j < w; j++) {
2508 val = GET_DATA_BYTE(lines + j, comp);
2509 SET_DATA_BYTE(lined, j, val);
2510 }
2511 }
2512
2513 return pixd;
2514 }
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 {
2539 l_uint8 srcbyte;
2540 l_int32 i, j, w, h, ws, hs, wd, hd;
2541 l_int32 wpls, wpld;
2542 l_uint32 *lines, *lined;
2543 l_uint32 *datas, *datad;
2544
2545 if (!pixd)
2546 return ERROR_INT("pixd not defined", __func__, 1);
2547 if (!pixs)
2548 return ERROR_INT("pixs not defined", __func__, 1);
2549 if (pixGetDepth(pixd) != 32)
2550 return ERROR_INT("pixd not 32 bpp", __func__, 1);
2551 if (pixGetDepth(pixs) != 8)
2552 return ERROR_INT("pixs not 8 bpp", __func__, 1);
2553 if (comp != COLOR_RED && comp != COLOR_GREEN &&
2554 comp != COLOR_BLUE && comp != L_ALPHA_CHANNEL)
2555 return ERROR_INT("invalid comp", __func__, 1);
2556 pixGetDimensions(pixs, &ws, &hs, NULL);
2557 pixGetDimensions(pixd, &wd, &hd, NULL);
2558 if (ws != wd || hs != hd)
2559 L_WARNING("images sizes not equal\n", __func__);
2560 w = L_MIN(ws, wd);
2561 h = L_MIN(hs, hd);
2562 if (comp == L_ALPHA_CHANNEL)
2563 pixSetSpp(pixd, 4);
2564 datas = pixGetData(pixs);
2565 datad = pixGetData(pixd);
2566 wpls = pixGetWpl(pixs);
2567 wpld = pixGetWpl(pixd);
2568 for (i = 0; i < h; i++) {
2569 lines = datas + i * wpls;
2570 lined = datad + i * wpld;
2571 for (j = 0; j < w; j++) {
2572 srcbyte = GET_DATA_BYTE(lines, j);
2573 SET_DATA_BYTE(lined + j, comp, srcbyte);
2574 }
2575 }
2576
2577 return 0;
2578 }
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 {
2598 l_int32 i, j, w, h, val, index, valid;
2599 l_int32 wplc, wpld;
2600 l_uint32 *linec, *lined;
2601 l_uint32 *datac, *datad;
2602 PIX *pixc, *pixd;
2603 PIXCMAP *cmap;
2604 RGBA_QUAD *cta;
2605
2606 if (!pixs)
2607 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2608 if ((cmap = pixGetColormap(pixs)) == NULL)
2609 return (PIX *)ERROR_PTR("pixs not cmapped", __func__, NULL);
2610 if (comp == L_ALPHA_CHANNEL)
2611 return (PIX *)ERROR_PTR("alpha in cmaps not supported", __func__, NULL);
2612 if (comp != COLOR_RED && comp != COLOR_GREEN && comp != COLOR_BLUE)
2613 return (PIX *)ERROR_PTR("invalid comp", __func__, NULL);
2614
2615 /* If not 8 bpp, make a cmapped 8 bpp pix */
2616 if (pixGetDepth(pixs) == 8)
2617 pixc = pixClone(pixs);
2618 else
2619 pixc = pixConvertTo8(pixs, TRUE);
2620 pixcmapIsValid(cmap, pixc, &valid);
2621 if (!valid) {
2622 pixDestroy(&pixc);
2623 return (PIX *)ERROR_PTR("invalid colormap", __func__, NULL);
2624 }
2625
2626 pixGetDimensions(pixs, &w, &h, NULL);
2627 if ((pixd = pixCreate(w, h, 8)) == NULL) {
2628 pixDestroy(&pixc);
2629 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
2630 }
2631 pixCopyResolution(pixd, pixs);
2632 wplc = pixGetWpl(pixc);
2633 wpld = pixGetWpl(pixd);
2634 datac = pixGetData(pixc);
2635 datad = pixGetData(pixd);
2636 cta = (RGBA_QUAD *)cmap->array;
2637
2638 for (i = 0; i < h; i++) {
2639 linec = datac + i * wplc;
2640 lined = datad + i * wpld;
2641 if (comp == COLOR_RED) {
2642 for (j = 0; j < w; j++) {
2643 index = GET_DATA_BYTE(linec, j);
2644 val = cta[index].red;
2645 SET_DATA_BYTE(lined, j, val);
2646 }
2647 } else if (comp == COLOR_GREEN) {
2648 for (j = 0; j < w; j++) {
2649 index = GET_DATA_BYTE(linec, j);
2650 val = cta[index].green;
2651 SET_DATA_BYTE(lined, j, val);
2652 }
2653 } else if (comp == COLOR_BLUE) {
2654 for (j = 0; j < w; j++) {
2655 index = GET_DATA_BYTE(linec, j);
2656 val = cta[index].blue;
2657 SET_DATA_BYTE(lined, j, val);
2658 }
2659 }
2660 }
2661
2662 pixDestroy(&pixc);
2663 return pixd;
2664 }
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 {
2687 l_int32 i, j, w, h, ws, hs, wd, hd, val;
2688 l_int32 wpls, wpld;
2689 l_uint32 *lines, *lined;
2690 l_uint32 *datas, *datad;
2691
2692 if (!pixd && pixGetDepth(pixd) != 32)
2693 return ERROR_INT("pixd not defined or not 32 bpp", __func__, 1);
2694 if (!pixs && pixGetDepth(pixs) != 32)
2695 return ERROR_INT("pixs not defined or not 32 bpp", __func__, 1);
2696 if (comp != COLOR_RED && comp != COLOR_GREEN &&
2697 comp != COLOR_BLUE && comp != L_ALPHA_CHANNEL)
2698 return ERROR_INT("invalid component", __func__, 1);
2699 pixGetDimensions(pixs, &ws, &hs, NULL);
2700 pixGetDimensions(pixd, &wd, &hd, NULL);
2701 if (ws != wd || hs != hd)
2702 L_WARNING("images sizes not equal\n", __func__);
2703 w = L_MIN(ws, wd);
2704 h = L_MIN(hs, hd);
2705 if (comp == L_ALPHA_CHANNEL)
2706 pixSetSpp(pixd, 4);
2707 wpls = pixGetWpl(pixs);
2708 wpld = pixGetWpl(pixd);
2709 datas = pixGetData(pixs);
2710 datad = pixGetData(pixd);
2711 for (i = 0; i < h; i++) {
2712 lines = datas + i * wpls;
2713 lined = datad + i * wpld;
2714 for (j = 0; j < w; j++) {
2715 val = GET_DATA_BYTE(lines + j, comp);
2716 SET_DATA_BYTE(lined + j, comp, val);
2717 }
2718 }
2719 return 0;
2720 }
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 {
2747 if (!ppixel)
2748 return ERROR_INT("&pixel not defined", __func__, 1);
2749
2750 *ppixel = ((l_uint32)rval << L_RED_SHIFT) |
2751 ((l_uint32)gval << L_GREEN_SHIFT) |
2752 ((l_uint32)bval << L_BLUE_SHIFT);
2753 return 0;
2754 }
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 {
2778 if (!ppixel)
2779 return ERROR_INT("&pixel not defined", __func__, 1);
2780
2781 *ppixel = ((l_uint32)rval << L_RED_SHIFT) |
2782 ((l_uint32)gval << L_GREEN_SHIFT) |
2783 ((l_uint32)bval << L_BLUE_SHIFT) |
2784 aval;
2785 return 0;
2786 }
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 {
2812 if (prval) *prval = (pixel >> L_RED_SHIFT) & 0xff;
2813 if (pgval) *pgval = (pixel >> L_GREEN_SHIFT) & 0xff;
2814 if (pbval) *pbval = (pixel >> L_BLUE_SHIFT) & 0xff;
2815 }
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 {
2835 if (prval) *prval = (pixel >> L_RED_SHIFT) & 0xff;
2836 if (pgval) *pgval = (pixel >> L_GREEN_SHIFT) & 0xff;
2837 if (pbval) *pbval = (pixel >> L_BLUE_SHIFT) & 0xff;
2838 if (paval) *paval = (pixel >> L_ALPHA_SHIFT) & 0xff;
2839 }
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 {
2853 l_int32 rval, gval, bval, val;
2854
2855 extractRGBValues(pixel, &rval, &gval, &bval);
2856 if (type == L_CHOOSE_MIN) {
2857 val = L_MIN(rval, gval);
2858 val = L_MIN(val, bval);
2859 } else { /* type == L_CHOOSE_MAX */
2860 val = L_MAX(rval, gval);
2861 val = L_MAX(val, bval);
2862 }
2863 return val;
2864 }
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 {
2890 l_uint32 *lines;
2891 l_int32 j, w, h;
2892 l_int32 wpls;
2893
2894 if (!pixs)
2895 return ERROR_INT("pixs not defined", __func__, 1);
2896 if (pixGetDepth(pixs) != 32)
2897 return ERROR_INT("pixs not 32 bpp", __func__, 1);
2898 if (!bufr || !bufg || !bufb)
2899 return ERROR_INT("buffer not defined", __func__, 1);
2900
2901 pixGetDimensions(pixs, &w, &h, NULL);
2902 if (row < 0 || row >= h)
2903 return ERROR_INT("row out of bounds", __func__, 1);
2904 wpls = pixGetWpl(pixs);
2905 lines = pixGetData(pixs) + row * wpls;
2906
2907 for (j = 0; j < w; j++) {
2908 bufr[j] = GET_DATA_BYTE(lines + j, COLOR_RED);
2909 bufg[j] = GET_DATA_BYTE(lines + j, COLOR_GREEN);
2910 bufb[j] = GET_DATA_BYTE(lines + j, COLOR_BLUE);
2911 }
2912
2913 return 0;
2914 }
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 {
2942 if (!line)
2943 return ERROR_INT("line not defined", __func__, 1);
2944 if (j < 0)
2945 return ERROR_INT("j must be >= 0", __func__, 1);
2946 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
2947 return ERROR_INT("invalid d", __func__, 1);
2948
2949 if (d == 1)
2950 SET_DATA_BIT_VAL(line, j, val);
2951 else if (d == 2)
2952 SET_DATA_DIBIT(line, j, val);
2953 else if (d == 4)
2954 SET_DATA_QBIT(line, j, val);
2955 else if (d == 8)
2956 SET_DATA_BYTE(line, j, val);
2957 else if (d == 16)
2958 SET_DATA_TWO_BYTES(line, j, val);
2959 else /* d == 32 */
2960 *(line + j) = val;
2961 return 0;
2962 }
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 {
2995 l_uint32 *datas, *datad;
2996 l_int32 i, j, h, wpl;
2997 l_uint32 word;
2998 PIX *pixd;
2999
3000 #ifdef L_BIG_ENDIAN
3001
3002 return pixClone(pixs);
3003
3004 #else /* L_LITTLE_ENDIAN */
3005
3006 if (!pixs)
3007 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
3008
3009 datas = pixGetData(pixs);
3010 wpl = pixGetWpl(pixs);
3011 h = pixGetHeight(pixs);
3012 if ((pixd = pixCreateTemplate(pixs)) == NULL)
3013 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
3014 datad = pixGetData(pixd);
3015 for (i = 0; i < h; i++) {
3016 for (j = 0; j < wpl; j++, datas++, datad++) {
3017 word = *datas;
3018 *datad = (word >> 24) |
3019 ((word >> 8) & 0x0000ff00) |
3020 ((word << 8) & 0x00ff0000) |
3021 (word << 24);
3022 }
3023 }
3024
3025 return pixd;
3026
3027 #endif /* L_BIG_ENDIAN */
3028
3029 }
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 {
3057 l_uint32 *data;
3058 l_int32 i, j, h, wpl;
3059 l_uint32 word;
3060
3061 #ifdef L_BIG_ENDIAN
3062
3063 return 0;
3064
3065 #else /* L_LITTLE_ENDIAN */
3066
3067 if (!pixs)
3068 return ERROR_INT("pixs not defined", __func__, 1);
3069
3070 data = pixGetData(pixs);
3071 wpl = pixGetWpl(pixs);
3072 h = pixGetHeight(pixs);
3073 for (i = 0; i < h; i++) {
3074 for (j = 0; j < wpl; j++, data++) {
3075 word = *data;
3076 *data = (word >> 24) |
3077 ((word >> 8) & 0x0000ff00) |
3078 ((word << 8) & 0x00ff0000) |
3079 (word << 24);
3080 }
3081 }
3082
3083 return 0;
3084
3085 #endif /* L_BIG_ENDIAN */
3086
3087 }
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 {
3115 l_int32 j;
3116 l_uint32 word;
3117
3118 if (!datad || !datas)
3119 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 for (j = 0; j < wpl; j++, datas++, datad++) {
3129 word = *datas;
3130 *datad = (word >> 24) |
3131 ((word >> 8) & 0x0000ff00) |
3132 ((word << 8) & 0x00ff0000) |
3133 (word << 24);
3134 }
3135 return 0;
3136
3137 #endif /* L_BIG_ENDIAN */
3138
3139 }
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 {
3164 l_uint32 *datas, *datad;
3165 l_int32 i, j, h, wpl;
3166 l_uint32 word;
3167 PIX *pixd;
3168
3169 #ifdef L_BIG_ENDIAN
3170
3171 return pixClone(pixs);
3172
3173 #else /* L_LITTLE_ENDIAN */
3174
3175 if (!pixs)
3176 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
3177
3178 datas = pixGetData(pixs);
3179 wpl = pixGetWpl(pixs);
3180 h = pixGetHeight(pixs);
3181 if ((pixd = pixCreateTemplate(pixs)) == NULL)
3182 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
3183 datad = pixGetData(pixd);
3184 for (i = 0; i < h; i++) {
3185 for (j = 0; j < wpl; j++, datas++, datad++) {
3186 word = *datas;
3187 *datad = (word << 16) | (word >> 16);
3188 }
3189 }
3190
3191 return pixd;
3192
3193 #endif /* L_BIG_ENDIAN */
3194
3195 }
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 {
3216 l_uint32 *data;
3217 l_int32 i, j, h, wpl;
3218 l_uint32 word;
3219
3220 #ifdef L_BIG_ENDIAN
3221
3222 return 0;
3223
3224 #else /* L_LITTLE_ENDIAN */
3225
3226 if (!pixs)
3227 return ERROR_INT("pixs not defined", __func__, 1);
3228
3229 data = pixGetData(pixs);
3230 wpl = pixGetWpl(pixs);
3231 h = pixGetHeight(pixs);
3232 for (i = 0; i < h; i++) {
3233 for (j = 0; j < wpl; j++, data++) {
3234 word = *data;
3235 *data = (word << 16) | (word >> 16);
3236 }
3237 }
3238
3239 return 0;
3240
3241 #endif /* L_BIG_ENDIAN */
3242
3243 }
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 {
3270 l_int32 w, h, d, wpl, i, j, rval, gval, bval;
3271 l_int32 databpl; /* bytes for each raster line in returned data */
3272 l_uint8 *line, *data; /* packed data in returned array */
3273 l_uint32 *rline, *rdata; /* data in pix raster */
3274
3275 if (pdata) *pdata = NULL;
3276 if (pnbytes) *pnbytes = 0;
3277 if (!pdata || !pnbytes)
3278 return ERROR_INT("&data and &nbytes not both defined", __func__, 1);
3279 if (!pixs)
3280 return ERROR_INT("pixs not defined", __func__, 1);
3281 pixGetDimensions(pixs, &w, &h, &d);
3282 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
3283 return ERROR_INT("depth not in {1,2,4,8,16,32}", __func__, 1);
3284
3285 pixSetPadBits(pixs, 0);
3286 rdata = pixGetData(pixs);
3287 wpl = pixGetWpl(pixs);
3288 if (d == 1)
3289 databpl = (w + 7) / 8;
3290 else if (d == 2)
3291 databpl = (w + 3) / 4;
3292 else if (d == 4)
3293 databpl = (w + 1) / 2;
3294 else if (d == 8 || d == 16)
3295 databpl = w * (d / 8);
3296 else /* d == 32 bpp rgb */
3297 databpl = 3 * w;
3298 if ((data = (l_uint8 *)LEPT_CALLOC((size_t)databpl * h, sizeof(l_uint8)))
3299 == NULL)
3300 return ERROR_INT("data not allocated", __func__, 1);
3301 *pdata = data;
3302 *pnbytes = (size_t)databpl * h;
3303
3304 for (i = 0; i < h; i++) {
3305 rline = rdata + i * wpl;
3306 line = data + i * databpl;
3307 if (d <= 8) {
3308 for (j = 0; j < databpl; j++)
3309 line[j] = GET_DATA_BYTE(rline, j);
3310 } else if (d == 16) {
3311 for (j = 0; j < w; j++)
3312 line[2 * j] = GET_DATA_TWO_BYTES(rline, j);
3313 } else { /* d == 32 bpp rgb */
3314 for (j = 0; j < w; j++) {
3315 extractRGBValues(rline[j], &rval, &gval, &bval);
3316 *(line + 3 * j) = rval;
3317 *(line + 3 * j + 1) = gval;
3318 *(line + 3 * j + 2) = bval;
3319 }
3320 }
3321 }
3322
3323 return 0;
3324 }
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 {
3352 l_int32 w, h, maxdim, res;
3353
3354 if (!pres)
3355 return ERROR_INT("&res not defined", __func__, 1);
3356 *pres = 300;
3357 if (!pix)
3358 return ERROR_INT("pix not defined", __func__, 1);
3359 if (longside <= 0.0)
3360 return ERROR_INT("longside not > 0", __func__, 1);
3361
3362 pixGetDimensions(pix, &w, &h, NULL);
3363 maxdim = L_MAX(w, h);
3364 res = (l_int32)(maxdim / longside + 0.5);
3365 res = L_MAX(res, 1); /* don't let it be 0 */
3366 if (res < 10)
3367 L_WARNING("low inferred resolution: %d ppi\n", __func__, res);
3368 if (res > 10000)
3369 L_WARNING("high inferred resolution: %d ppi\n", __func__, res);
3370 *pres = res;
3371 return 0;
3372 }
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 {
3395 l_int32 w, h, wpl, i, j, alpha;
3396 l_uint32 *data, *line;
3397
3398 if (!popaque)
3399 return ERROR_INT("&opaque not defined", __func__, 1);
3400 *popaque = FALSE;
3401 if (!pix)
3402 return ERROR_INT("&pix not defined", __func__, 1);
3403 if (pixGetDepth(pix) != 32)
3404 return ERROR_INT("&pix not 32 bpp", __func__, 1);
3405 if (pixGetSpp(pix) != 4)
3406 return ERROR_INT("&pix not 4 spp", __func__, 1);
3407
3408 data = pixGetData(pix);
3409 wpl = pixGetWpl(pix);
3410 pixGetDimensions(pix, &w, &h, NULL);
3411 for (i = 0; i < h; i++) {
3412 line = data + i * wpl;
3413 for (j = 0; j < w; j++) {
3414 alpha = GET_DATA_BYTE(line + j, L_ALPHA_CHANNEL);
3415 if (alpha ^ 0xff) /* not opaque */
3416 return 0;
3417 }
3418 }
3419
3420 *popaque = TRUE;
3421 return 0;
3422 }
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 {
3459 l_int32 w, h;
3460
3461 if (pw) *pw = 0;
3462 if (ph) *ph = 0;
3463 if (!pix || pixGetDepth(pix) != 8)
3464 return (l_uint8 **)ERROR_PTR("pix not defined or not 8 bpp",
3465 __func__, NULL);
3466 pixGetDimensions(pix, &w, &h, NULL);
3467 if (pw) *pw = w;
3468 if (ph) *ph = h;
3469 if (pixGetColormap(pix))
3470 return (l_uint8 **)ERROR_PTR("pix has colormap", __func__, NULL);
3471
3472 pixEndianByteSwap(pix);
3473 return (l_uint8 **)pixGetLinePtrs(pix, NULL);
3474 }
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 {
3494 if (!pix)
3495 return ERROR_INT("pix not defined", __func__, 1);
3496 if (!lineptrs)
3497 return ERROR_INT("lineptrs not defined", __func__, 1);
3498
3499 pixEndianByteSwap(pix);
3500 LEPT_FREE(lineptrs);
3501 return 0;
3502 }
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 {
3534 val1 = L_MAX(0.0f, L_MIN(1.0f, val1));
3535 val2 = L_MAX(0.0f, L_MIN(1.0f, val2));
3536 AlphaMaskBorderVals[0] = val1;
3537 AlphaMaskBorderVals[1] = val2;
3538 }