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