1 /*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 - This software is distributed in the hope that it will be
4 - useful, but with NO WARRANTY OF ANY KIND.
5 - No author or distributor accepts responsibility to anyone for the
6 - consequences of using this software, or for whether it serves any
7 - particular purpose or works at all, unless he or she says so in
8 - writing. Everyone is granted permission to copy, modify and
9 - redistribute this source code, for commercial or non-commercial
10 - purposes, with the following restrictions: (1) the origin of this
11 - source code must not be misrepresented; (2) modified versions must
12 - be plainly marked as such; and (3) this notice may not be removed
13 - or altered from any source or modified source distribution.
14 *====================================================================*/
15
16 /*
17 * pix2.c
18 *
19 * This file has these basic operations:
20 *
21 * (1) Get and set: individual pixels, full image, rectangular region,
22 * pad pixels, border pixels, and color components for RGB
23 * (2) Add and remove border pixels
24 * (3) Endian byte swaps
25 *
26 * Pixel poking
27 * l_int32 pixGetPixel()
28 * l_int32 pixSetPixel()
29 * l_int32 pixGetRGBPixel()
30 * l_int32 pixSetRGBPixel()
31 * l_int32 pixGetRandomPixel()
32 * l_int32 pixClearPixel()
33 * l_int32 pixFlipPixel()
34 * void setPixelLow()
35 *
36 * Full image clear/set/set-to-arbitrary-value
37 * l_int32 pixClearAll()
38 * l_int32 pixSetAll()
39 * l_int32 pixSetAllArbitrary()
40 * l_int32 pixSetBlackOrWhite()
41 *
42 * Rectangular region clear/set/set-to-arbitrary-value/blend
43 * l_int32 pixClearInRect()
44 * l_int32 pixSetInRect()
45 * l_int32 pixSetInRectArbitrary()
46 * l_int32 pixBlendInRect()
47 *
48 * Set pad bits
49 * l_int32 pixSetPadBits()
50 * l_int32 pixSetPadBitsBand()
51 *
52 * Assign border pixels
53 * l_int32 pixSetOrClearBorder()
54 * l_int32 pixSetBorderVal()
55 * l_int32 pixSetMirroredBorder()
56 * PIX *pixCopyBorder()
57 *
58 * Add and remove border
59 * PIX *pixAddBorder()
60 * PIX *pixAddBorderGeneral()
61 * PIX *pixRemoveBorder()
62 * PIX *pixRemoveBorderGeneral()
63 * PIX *pixAddMirroredBorder()
64 * PIX *pixAddRepeatedBorder()
65 * PIX *pixAddMixedBorder()
66 *
67 * Color sample setting and extraction
68 * PIX *pixCreateRGBImage()
69 * PIX *pixGetRGBComponent()
70 * l_int32 pixSetRGBComponent()
71 * PIX *pixGetRGBComponentCmap()
72 * l_int32 composeRGBPixel()
73 * void extractRGBValues()
74 * l_int32 pixGetRGBLine()
75 *
76 * Conversion between big and little endians
77 * PIX *pixEndianByteSwapNew()
78 * l_int32 pixEndianByteSwap()
79 * l_int32 lineEndianByteSwap()
80 * PIX *pixEndianTwoByteSwapNew()
81 * l_int32 pixEndianTwoByteSwap()
82 *
83 * *** indicates implicit assumption about RGB component ordering
84 */
85
86
87 #include <stdio.h>
88 #include <stdlib.h>
89 #include <string.h>
90 #include "allheaders.h"
91
92 static const l_uint32 rmask32[] = {0x0,
93 0x00000001, 0x00000003, 0x00000007, 0x0000000f,
94 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
95 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
96 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
97 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
98 0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
99 0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
100 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff};
101
102
103
104 /*-------------------------------------------------------------*
105 * Pixel poking *
106 *-------------------------------------------------------------*/
107 /*!
108 * pixGetPixel()
109 *
110 * Input: pix
111 * (x,y) pixel coords
112 * &val (<return> pixel value)
113 * Return: 0 if OK; 1 on error
114 *
115 * Notes:
116 * (1) This returns the value in the data array. If the pix is
117 * colormapped, it returns the colormap index, not the rgb value.
118 */
119 l_int32
pixGetPixel(PIX * pix,l_int32 x,l_int32 y,l_uint32 * pval)120 pixGetPixel(PIX *pix,
121 l_int32 x,
122 l_int32 y,
123 l_uint32 *pval)
124 {
125 l_int32 w, h, d, wpl, val;
126 l_uint32 *line, *data;
127
128 PROCNAME("pixGetPixel");
129
130 if (!pval)
131 return ERROR_INT("pval not defined", procName, 1);
132 *pval = 0;
133 if (!pix)
134 return ERROR_INT("pix not defined", procName, 1);
135
136 pixGetDimensions(pix, &w, &h, &d);
137 if (x < 0 || x >= w)
138 return ERROR_INT("x out of bounds", procName, 1);
139 if (y < 0 || y >= h)
140 return ERROR_INT("y out of bounds", procName, 1);
141
142 wpl = pixGetWpl(pix);
143 data = pixGetData(pix);
144 line = data + y * wpl;
145 switch (d)
146 {
147 case 1:
148 val = GET_DATA_BIT(line, x);
149 break;
150 case 2:
151 val = GET_DATA_DIBIT(line, x);
152 break;
153 case 4:
154 val = GET_DATA_QBIT(line, x);
155 break;
156 case 8:
157 val = GET_DATA_BYTE(line, x);
158 break;
159 case 16:
160 val = GET_DATA_TWO_BYTES(line, x);
161 break;
162 case 32:
163 val = line[x];
164 break;
165 default:
166 return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", procName, 1);
167 }
168
169 *pval = val;
170 return 0;
171 }
172
173
174 /*!
175 * pixSetPixel()
176 *
177 * Input: pix
178 * (x,y) pixel coords
179 * val (value to be inserted)
180 * Return: 0 if OK; 1 on error
181 *
182 * Note: the input value is not checked for overflow, and
183 * the sign bit (if any) is ignored.
184 */
185 l_int32
pixSetPixel(PIX * pix,l_int32 x,l_int32 y,l_uint32 val)186 pixSetPixel(PIX *pix,
187 l_int32 x,
188 l_int32 y,
189 l_uint32 val)
190 {
191 l_int32 w, h, d, wpl;
192 l_uint32 *line, *data;
193
194 PROCNAME("pixSetPixel");
195
196 if (!pix)
197 return ERROR_INT("pix not defined", procName, 1);
198
199 pixGetDimensions(pix, &w, &h, &d);
200 if (x < 0 || x >= w)
201 return ERROR_INT("x out of bounds", procName, 1);
202 if (y < 0 || y >= h)
203 return ERROR_INT("y out of bounds", procName, 1);
204
205 data = pixGetData(pix);
206 wpl = pixGetWpl(pix);
207 line = data + y * wpl;
208 switch (d)
209 {
210 case 1:
211 if (val)
212 SET_DATA_BIT(line, x);
213 else
214 CLEAR_DATA_BIT(line, x);
215 break;
216 case 2:
217 SET_DATA_DIBIT(line, x, val);
218 break;
219 case 4:
220 SET_DATA_QBIT(line, x, val);
221 break;
222 case 8:
223 SET_DATA_BYTE(line, x, val);
224 break;
225 case 16:
226 SET_DATA_TWO_BYTES(line, x, val);
227 break;
228 case 32:
229 line[x] = val;
230 break;
231 default:
232 return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", procName, 1);
233 }
234
235 return 0;
236 }
237
238
239 /*!
240 * pixGetRGBPixel()
241 *
242 * Input: pix (32 bpp rgb, not colormapped)
243 * (x,y) pixel coords
244 * &rval (<optional return> red component)
245 * &gval (<optional return> green component)
246 * &bval (<optional return> blue component)
247 * Return: 0 if OK; 1 on error
248 */
249 l_int32
pixGetRGBPixel(PIX * pix,l_int32 x,l_int32 y,l_int32 * prval,l_int32 * pgval,l_int32 * pbval)250 pixGetRGBPixel(PIX *pix,
251 l_int32 x,
252 l_int32 y,
253 l_int32 *prval,
254 l_int32 *pgval,
255 l_int32 *pbval)
256 {
257 l_int32 w, h, d, wpl;
258 l_uint32 *data, *ppixel;
259
260 PROCNAME("pixGetRGBPixel");
261
262 if (!pix)
263 return ERROR_INT("pix not defined", procName, 1);
264 pixGetDimensions(pix, &w, &h, &d);
265 if (d != 32)
266 return ERROR_INT("pix not 32 bpp", procName, 1);
267 if (x < 0 || x >= w)
268 return ERROR_INT("x out of bounds", procName, 1);
269 if (y < 0 || y >= h)
270 return ERROR_INT("y out of bounds", procName, 1);
271
272 wpl = pixGetWpl(pix);
273 data = pixGetData(pix);
274 ppixel = data + y * wpl + x;
275 if (prval) *prval = GET_DATA_BYTE(ppixel, COLOR_RED);
276 if (pgval) *pgval = GET_DATA_BYTE(ppixel, COLOR_GREEN);
277 if (pbval) *pbval = GET_DATA_BYTE(ppixel, COLOR_BLUE);
278 return 0;
279 }
280
281
282 /*!
283 * pixSetRGBPixel()
284 *
285 * Input: pix (32 bpp rgb)
286 * (x,y) pixel coords
287 * rval (red component)
288 * gval (green component)
289 * bval (blue component)
290 * Return: 0 if OK; 1 on error
291 */
292 l_int32
pixSetRGBPixel(PIX * pix,l_int32 x,l_int32 y,l_int32 rval,l_int32 gval,l_int32 bval)293 pixSetRGBPixel(PIX *pix,
294 l_int32 x,
295 l_int32 y,
296 l_int32 rval,
297 l_int32 gval,
298 l_int32 bval)
299 {
300 l_int32 w, h, d, wpl;
301 l_uint32 pixel;
302 l_uint32 *data, *line;
303
304 PROCNAME("pixSetRGBPixel");
305
306 if (!pix)
307 return ERROR_INT("pix not defined", procName, 1);
308 pixGetDimensions(pix, &w, &h, &d);
309 if (d != 32)
310 return ERROR_INT("pix not 32 bpp", procName, 1);
311 if (x < 0 || x >= w)
312 return ERROR_INT("x out of bounds", procName, 1);
313 if (y < 0 || y >= h)
314 return ERROR_INT("y out of bounds", procName, 1);
315
316 wpl = pixGetWpl(pix);
317 data = pixGetData(pix);
318 line = data + y * wpl;
319 composeRGBPixel(rval, gval, bval, &pixel);
320 *(line + x) = pixel;
321 return 0;
322 }
323
324
325 /*!
326 * pixGetRandomPixel()
327 *
328 * Input: pix (any depth; can be colormapped)
329 * &val (<return> pixel value)
330 * &x (<optional return> x coordinate chosen; can be null)
331 * &y (<optional return> y coordinate chosen; can be null)
332 * Return: 0 if OK; 1 on error
333 *
334 * Notes:
335 * (1) If the pix is colormapped, it returns the rgb value.
336 */
337 l_int32
pixGetRandomPixel(PIX * pix,l_uint32 * pval,l_int32 * px,l_int32 * py)338 pixGetRandomPixel(PIX *pix,
339 l_uint32 *pval,
340 l_int32 *px,
341 l_int32 *py)
342 {
343 l_int32 w, h, x, y, rval, gval, bval;
344 l_uint32 val;
345 PIXCMAP *cmap;
346
347 PROCNAME("pixGetRandomPixel");
348
349 if (!pval)
350 return ERROR_INT("pval not defined", procName, 1);
351 *pval = 0;
352 if (!pix)
353 return ERROR_INT("pix not defined", procName, 1);
354
355 pixGetDimensions(pix, &w, &h, NULL);
356 x = rand() % w;
357 y = rand() % h;
358 if (px) *px = x;
359 if (py) *py = y;
360 pixGetPixel(pix, x, y, &val);
361 if ((cmap = pixGetColormap(pix)) != NULL) {
362 pixcmapGetColor(cmap, val, &rval, &gval, &bval);
363 composeRGBPixel(rval, gval, bval, pval);
364 }
365 else
366 *pval = val;
367
368 return 0;
369 }
370
371
372 /*!
373 * pixClearPixel()
374 *
375 * Input: pix
376 * (x,y) pixel coords
377 * Return: 0 if OK; 1 on error.
378 */
379 l_int32
pixClearPixel(PIX * pix,l_int32 x,l_int32 y)380 pixClearPixel(PIX *pix,
381 l_int32 x,
382 l_int32 y)
383 {
384 l_int32 w, h, d, wpl;
385 l_uint32 *line, *data;
386
387 PROCNAME("pixClearPixel");
388
389 if (!pix)
390 return ERROR_INT("pix not defined", procName, 1);
391
392 pixGetDimensions(pix, &w, &h, &d);
393 if (x < 0 || x >= w)
394 return ERROR_INT("x out of bounds", procName, 1);
395 if (y < 0 || y >= h)
396 return ERROR_INT("y out of bounds", procName, 1);
397
398 wpl = pixGetWpl(pix);
399 data = pixGetData(pix);
400 line = data + y * wpl;
401 switch (d)
402 {
403 case 1:
404 CLEAR_DATA_BIT(line, x);
405 break;
406 case 2:
407 CLEAR_DATA_DIBIT(line, x);
408 break;
409 case 4:
410 CLEAR_DATA_QBIT(line, x);
411 break;
412 case 8:
413 SET_DATA_BYTE(line, x, 0);
414 break;
415 case 16:
416 SET_DATA_TWO_BYTES(line, x, 0);
417 break;
418 case 32:
419 line[x] = 0;
420 break;
421 default:
422 return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", procName, 1);
423 }
424
425 return 0;
426 }
427
428
429 /*!
430 * pixFlipPixel()
431 *
432 * Input: pix
433 * (x,y) pixel coords
434 * Return: 0 if OK; 1 on error
435 */
436 l_int32
pixFlipPixel(PIX * pix,l_int32 x,l_int32 y)437 pixFlipPixel(PIX *pix,
438 l_int32 x,
439 l_int32 y)
440 {
441 l_int32 w, h, d, wpl;
442 l_uint32 val;
443 l_uint32 *line, *data;
444
445 PROCNAME("pixFlipPixel");
446
447 if (!pix)
448 return ERROR_INT("pix not defined", procName, 1);
449
450 pixGetDimensions(pix, &w, &h, &d);
451 if (x < 0 || x >= w)
452 return ERROR_INT("x out of bounds", procName, 1);
453 if (y < 0 || y >= h)
454 return ERROR_INT("y out of bounds", procName, 1);
455
456 data = pixGetData(pix);
457 wpl = pixGetWpl(pix);
458 line = data + y * wpl;
459 switch (d)
460 {
461 case 1:
462 val = GET_DATA_BIT(line, x);
463 if (val)
464 CLEAR_DATA_BIT(line, x);
465 else
466 SET_DATA_BIT(line, x);
467 break;
468 case 2:
469 val = GET_DATA_DIBIT(line, x);
470 val ^= 0x3;
471 SET_DATA_DIBIT(line, x, val);
472 break;
473 case 4:
474 val = GET_DATA_QBIT(line, x);
475 val ^= 0xf;
476 SET_DATA_QBIT(line, x, val);
477 break;
478 case 8:
479 val = GET_DATA_BYTE(line, x);
480 val ^= 0xff;
481 SET_DATA_BYTE(line, x, val);
482 break;
483 case 16:
484 val = GET_DATA_TWO_BYTES(line, x);
485 val ^= 0xffff;
486 SET_DATA_TWO_BYTES(line, x, val);
487 break;
488 case 32:
489 val = line[x] ^ 0xffffffff;
490 line[x] = val;
491 break;
492 default:
493 return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", procName, 1);
494 }
495
496 return 0;
497 }
498
499
500 /*!
501 * setPixelLow()
502 *
503 * Input: line (ptr to beginning of line),
504 * x (pixel location in line)
505 * depth (bpp)
506 * val (to be inserted)
507 * Return: void
508 *
509 * Notes:
510 * (1) Caution: input variables are not checked!
511 */
512 void
setPixelLow(l_uint32 * line,l_int32 x,l_int32 depth,l_uint32 val)513 setPixelLow(l_uint32 *line,
514 l_int32 x,
515 l_int32 depth,
516 l_uint32 val)
517 {
518 switch (depth)
519 {
520 case 1:
521 if (val)
522 SET_DATA_BIT(line, x);
523 else
524 CLEAR_DATA_BIT(line, x);
525 break;
526 case 2:
527 SET_DATA_DIBIT(line, x, val);
528 break;
529 case 4:
530 SET_DATA_QBIT(line, x, val);
531 break;
532 case 8:
533 SET_DATA_BYTE(line, x, val);
534 break;
535 case 16:
536 SET_DATA_TWO_BYTES(line, x, val);
537 break;
538 case 32:
539 line[x] = val;
540 break;
541 default:
542 fprintf(stderr, "illegal depth in setPixelLow()\n");
543 }
544
545 return;
546 }
547
548
549 /*-------------------------------------------------------------*
550 * Full image clear/set/set-to-arbitrary-value/invert *
551 *-------------------------------------------------------------*/
552 /*!
553 * pixClearAll()
554 *
555 * Input: pix (all depths; use cmapped with caution)
556 * Return: 0 if OK, 1 on error
557 *
558 * Notes:
559 * (1) Clears all data to 0. For 1 bpp, this is white; for grayscale
560 * or color, this is black.
561 * (2) Caution: for colormapped pix, this sets the color to the first
562 * one in the colormap. Be sure that this is the intended color!
563 */
564 l_int32
pixClearAll(PIX * pix)565 pixClearAll(PIX *pix)
566 {
567 PROCNAME("pixClearAll");
568
569 if (!pix)
570 return ERROR_INT("pix not defined", procName, 1);
571
572 pixRasterop(pix, 0, 0, pixGetWidth(pix), pixGetHeight(pix),
573 PIX_CLR, NULL, 0, 0);
574 return 0;
575 }
576
577
578 /*!
579 * pixSetAll()
580 *
581 * Input: pix (all depths; use cmapped with caution)
582 * Return: 0 if OK, 1 on error
583 *
584 * Notes:
585 * (1) Sets all data to 1. For 1 bpp, this is black; for grayscale
586 * or color, this is white.
587 * (2) Caution: for colormapped pix, this sets the pixel value to the
588 * maximum value supported by the colormap: 2^d - 1. However, this
589 * color may not be defined, because the colormap may not be full.
590 */
591 l_int32
pixSetAll(PIX * pix)592 pixSetAll(PIX *pix)
593 {
594 l_int32 n;
595 PIXCMAP *cmap;
596
597 PROCNAME("pixSetAll");
598
599 if (!pix)
600 return ERROR_INT("pix not defined", procName, 1);
601 if ((cmap = pixGetColormap(pix)) != NULL) {
602 n = pixcmapGetCount(cmap);
603 if (n < cmap->nalloc) /* cmap is not full */
604 return ERROR_INT("cmap entry does not exist", procName, 1);
605 }
606
607 pixRasterop(pix, 0, 0, pixGetWidth(pix), pixGetHeight(pix),
608 PIX_SET, NULL, 0, 0);
609 return 0;
610 }
611
612
613 /*!
614 * pixSetAllArbitrary()
615 *
616 * Input: pix (all depths; use cmapped with caution)
617 * val (value to set all pixels)
618 * Return: 0 if OK; 1 on error
619 *
620 * Notes:
621 * (1) For colormapped pix, be sure the value is the intended
622 * one in the colormap.
623 * (2) Caution: for colormapped pix, this sets each pixel to the
624 * color at the index equal to val. Be sure that this index
625 * exists in the colormap and that it is the intended one!
626 */
627 l_int32
pixSetAllArbitrary(PIX * pix,l_uint32 val)628 pixSetAllArbitrary(PIX *pix,
629 l_uint32 val)
630 {
631 l_int32 n, i, j, w, h, d, wpl, npix;
632 l_uint32 maxval, wordval;
633 l_uint32 *data, *line;
634 PIXCMAP *cmap;
635
636 PROCNAME("pixSetAllArbitrary");
637
638 if (!pix)
639 return ERROR_INT("pix not defined", procName, 1);
640 if ((cmap = pixGetColormap(pix)) != NULL) {
641 n = pixcmapGetCount(cmap);
642 if (val < 0) {
643 L_WARNING("index not in colormap; using first color", procName);
644 val = 0;
645 }
646 else if (val >= n) {
647 L_WARNING("index not in colormap; using last color", procName);
648 val = n - 1;
649 }
650 }
651
652 pixGetDimensions(pix, &w, &h, &d);
653 if (d == 32)
654 maxval = 0xffffffff;
655 else
656 maxval = (1 << d) - 1;
657 if (val < 0) {
658 L_WARNING("invalid pixel value; set to 0", procName);
659 val = 0;
660 }
661 if (val > maxval) {
662 L_WARNING_INT("invalid pixel val; set to maxval = %d",
663 procName, maxval);
664 val = maxval;
665 }
666
667 /* Set up word to tile with */
668 wordval = 0;
669 npix = 32 / d; /* number of pixels per 32 bit word */
670 for (j = 0; j < npix; j++)
671 wordval |= (val << (j * d));
672
673 wpl = pixGetWpl(pix);
674 data = pixGetData(pix);
675 for (i = 0; i < h; i++) {
676 line = data + i * wpl;
677 for (j = 0; j < wpl; j++) {
678 *(line + j) = wordval;
679 }
680 }
681
682 return 0;
683 }
684
685
686 /*!
687 * pixSetBlackOrWhite()
688 *
689 * Input: pixs (all depths; cmap ok)
690 * incolor (L_BRING_IN_BLACK or L_BRING_IN_WHITE)
691 * Return: 0 if OK; 1 on error
692 *
693 * Notes:
694 * (1) Function for setting all pixels in an image to either black
695 * or white.
696 * (2) If pixs is colormapped, it adds black or white to the
697 * colormap if it's not there and there is room. If the colormap
698 * is full, it finds the closest color in intensity.
699 * This index is written to all pixels.
700 */
701 l_int32
pixSetBlackOrWhite(PIX * pixs,l_int32 incolor)702 pixSetBlackOrWhite(PIX *pixs,
703 l_int32 incolor)
704 {
705 l_int32 d, index;
706 PIXCMAP *cmap;
707
708 PROCNAME("pixSetBlackOrWhite");
709
710 if (!pixs)
711 return ERROR_INT("pix not defined", procName, 1);
712 if (incolor != L_BRING_IN_BLACK && incolor != L_BRING_IN_WHITE)
713 return ERROR_INT("invalid incolor", procName, 1);
714
715 cmap = pixGetColormap(pixs);
716 d = pixGetDepth(pixs);
717 if (!cmap) {
718 if ((d == 1 && incolor == L_BRING_IN_BLACK) ||
719 (d > 1 && incolor == L_BRING_IN_WHITE))
720 pixSetAll(pixs);
721 else
722 pixClearAll(pixs);
723 }
724 else { /* handle colormap */
725 if (incolor == L_BRING_IN_BLACK)
726 pixcmapAddBlackOrWhite(cmap, 0, &index);
727 else /* L_BRING_IN_WHITE */
728 pixcmapAddBlackOrWhite(cmap, 1, &index);
729 pixSetAllArbitrary(pixs, index);
730 }
731
732 return 0;
733 }
734
735
736 /*-------------------------------------------------------------*
737 * Rectangular region clear/set/set-to-arbitrary-value *
738 *-------------------------------------------------------------*/
739 /*!
740 * pixClearInRect()
741 *
742 * Input: pix (all depths; can be cmapped)
743 * box (in which all pixels will be cleared)
744 * Return: 0 if OK, 1 on error
745 *
746 * Notes:
747 * (1) Clears all data in rect to 0. For 1 bpp, this is white;
748 * for grayscale or color, this is black.
749 * (2) Caution: for colormapped pix, this sets the color to the first
750 * one in the colormap. Be sure that this is the intended color!
751 */
752 l_int32
pixClearInRect(PIX * pix,BOX * box)753 pixClearInRect(PIX *pix,
754 BOX *box)
755 {
756 l_int32 x, y, w, h;
757
758 PROCNAME("pixClearInRect");
759
760 if (!pix)
761 return ERROR_INT("pix not defined", procName, 1);
762 if (!box)
763 return ERROR_INT("box not defined", procName, 1);
764
765 boxGetGeometry(box, &x, &y, &w, &h);
766 pixRasterop(pix, x, y, w, h, PIX_CLR, NULL, 0, 0);
767 return 0;
768 }
769
770
771 /*!
772 * pixSetInRect()
773 *
774 * Input: pix (all depths, can be cmapped)
775 * box (in which all pixels will be set)
776 * Return: 0 if OK, 1 on error
777 *
778 * Notes:
779 * (1) Sets all data in rect to 1. For 1 bpp, this is black;
780 * for grayscale or color, this is white.
781 * (2) Caution: for colormapped pix, this sets the pixel value to the
782 * maximum value supported by the colormap: 2^d - 1. However, this
783 * color may not be defined, because the colormap may not be full.
784 */
785 l_int32
pixSetInRect(PIX * pix,BOX * box)786 pixSetInRect(PIX *pix,
787 BOX *box)
788 {
789 l_int32 n, x, y, w, h;
790 PIXCMAP *cmap;
791
792 PROCNAME("pixSetInRect");
793
794 if (!pix)
795 return ERROR_INT("pix not defined", procName, 1);
796 if (!box)
797 return ERROR_INT("box not defined", procName, 1);
798 if ((cmap = pixGetColormap(pix)) != NULL) {
799 n = pixcmapGetCount(cmap);
800 if (n < cmap->nalloc) /* cmap is not full */
801 return ERROR_INT("cmap entry does not exist", procName, 1);
802 }
803
804 boxGetGeometry(box, &x, &y, &w, &h);
805 pixRasterop(pix, x, y, w, h, PIX_SET, NULL, 0, 0);
806 return 0;
807 }
808
809
810 /*!
811 * pixSetInRectArbitrary()
812 *
813 * Input: pix (all depths; can be cmapped)
814 * box (in which all pixels will be set to val)
815 * val (value to set all pixels)
816 * Return: 0 if OK; 1 on error
817 *
818 * Notes:
819 * (1) For colormapped pix, be sure the value is the intended
820 * one in the colormap.
821 * (2) Caution: for colormapped pix, this sets each pixel in the
822 * rect to the color at the index equal to val. Be sure that
823 * this index exists in the colormap and that it is the intended one!
824 */
825 l_int32
pixSetInRectArbitrary(PIX * pix,BOX * box,l_uint32 val)826 pixSetInRectArbitrary(PIX *pix,
827 BOX *box,
828 l_uint32 val)
829 {
830 l_int32 n, x, y, xstart, xend, ystart, yend, bw, bh, w, h, d, wpl, maxval;
831 l_uint32 *data, *line;
832 BOX *boxc;
833 PIXCMAP *cmap;
834
835 PROCNAME("pixSetInRectArbitrary");
836
837 if (!pix)
838 return ERROR_INT("pix not defined", procName, 1);
839 if (!box)
840 return ERROR_INT("box not defined", procName, 1);
841 pixGetDimensions(pix, &w, &h, &d);
842 if (d != 1 && d != 2 && d != 4 && d !=8 && d != 16 && d != 32)
843 return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", procName, 1);
844 if ((cmap = pixGetColormap(pix)) != NULL) {
845 n = pixcmapGetCount(cmap);
846 if (val < 0) {
847 L_WARNING("index not in colormap; using first color", procName);
848 val = 0;
849 }
850 else if (val >= n) {
851 L_WARNING("index not in colormap; using last color", procName);
852 val = n - 1;
853 }
854 }
855
856 if (d == 32)
857 maxval = 0xffffffff;
858 else
859 maxval = (1 << d) - 1;
860 if (val < 0) {
861 L_WARNING("invalid pixel value; set to 0", procName);
862 val = 0;
863 }
864 if (val > maxval) {
865 L_WARNING_INT("invalid pixel val; set to maxval = %d",
866 procName, maxval);
867 val = maxval;
868 }
869
870 /* Handle the simple cases: the min and max values */
871 if (val == 0) {
872 pixClearInRect(pix, box);
873 return 0;
874 }
875 if (d == 1 ||
876 (d == 2 && val == 3) ||
877 (d == 4 && val == 0xf) ||
878 (d == 8 && val == 0xff) ||
879 (d == 16 && val == 0xffff) ||
880 (d == 32 && ((val ^ 0xffffff00) >> 8 == 0))) {
881 pixSetInRect(pix, box);
882 return 0;
883 }
884
885 /* Find the overlap of box with the input pix */
886 if ((boxc = boxClipToRectangle(box, w, h)) == NULL)
887 return ERROR_INT("no overlap of box with image", procName, 1);
888 boxGetGeometry(boxc, &xstart, &ystart, &bw, &bh);
889 xend = xstart + bw - 1;
890 yend = ystart + bh - 1;
891 boxDestroy(&boxc);
892
893 wpl = pixGetWpl(pix);
894 data = pixGetData(pix);
895 for (y = ystart; y <= yend; y++) {
896 line = data + y * wpl;
897 for (x = xstart; x <= xend; x++) {
898 switch(d)
899 {
900 case 2:
901 SET_DATA_DIBIT(line, x, val);
902 break;
903 case 4:
904 SET_DATA_QBIT(line, x, val);
905 break;
906 case 8:
907 SET_DATA_BYTE(line, x, val);
908 break;
909 case 16:
910 SET_DATA_TWO_BYTES(line, x, val);
911 break;
912 case 32:
913 line[x] = val;
914 break;
915 default:
916 return ERROR_INT("depth not 2|4|8|16|32 bpp", procName, 1);
917 }
918 }
919 }
920
921 return 0;
922 }
923
924
925 /*!
926 * pixBlendInRect()
927 *
928 * Input: pixs (32 bpp rgb)
929 * box (in which all pixels will be blended)
930 * val (blend value; 0xrrggbb00)
931 * fract (fraction of color to be blended with each pixel in pixs)
932 * Return: 0 if OK; 1 on error
933 *
934 * Notes:
935 * (1) This is an in-place function. It blends the input color @val
936 * with the pixels in pixs in the specified rectangle.
937 */
938 l_int32
pixBlendInRect(PIX * pixs,BOX * box,l_uint32 val,l_float32 fract)939 pixBlendInRect(PIX *pixs,
940 BOX *box,
941 l_uint32 val,
942 l_float32 fract)
943 {
944 l_int32 i, j, bx, by, bw, bh, w, h, wpls;
945 l_int32 prval, pgval, pbval, rval, gval, bval;
946 l_uint32 val32;
947 l_uint32 *datas, *lines;
948
949 PROCNAME("pixBlendInRect");
950
951 if (!pixs || pixGetDepth(pixs) != 32)
952 return ERROR_INT("pixs not defined or not 32 bpp", procName, 1);
953 if (!box)
954 return ERROR_INT("box not defined", procName, 1);
955
956 boxGetGeometry(box, &bx, &by, &bw, &bh);
957 pixGetDimensions(pixs, &w, &h, NULL);
958 datas = pixGetData(pixs);
959 wpls = pixGetWpl(pixs);
960 extractRGBValues(val, &rval, &gval, &bval);
961 for (i = 0; i < bh; i++) { /* scan over box */
962 if (by + i < 0 || by + i >= h) continue;
963 lines = datas + (by + i) * wpls;
964 for (j = 0; j < bw; j++) {
965 if (bx + j < 0 || bx + j >= w) continue;
966 val32 = *(lines + bx + j);
967 extractRGBValues(val32, &prval, &pgval, &pbval);
968 prval = (l_int32)((1. - fract) * prval + fract * rval);
969 pgval = (l_int32)((1. - fract) * pgval + fract * gval);
970 pbval = (l_int32)((1. - fract) * pbval + fract * bval);
971 composeRGBPixel(prval, pgval, pbval, &val32);
972 *(lines + bx + j) = val32;
973 }
974 }
975
976 return 0;
977 }
978
979
980 /*-------------------------------------------------------------*
981 * Set pad bits *
982 *-------------------------------------------------------------*/
983 /*!
984 * pixSetPadBits()
985 *
986 * Input: pix (1, 2, 4, 8, 16, 32 bpp)
987 * val (0 or 1)
988 * Return: 0 if OK; 1 on error
989 *
990 * Notes:
991 * (1) The pad bits are the bits that expand each scanline to a
992 * multiple of 32 bits. They are usually not used in
993 * image processing operations. When boundary conditions
994 * are important, as in seedfill, they must be set properly.
995 * (2) This sets the value of the pad bits (if any) in the last
996 * 32-bit word in each scanline.
997 * (3) For 32 bpp pix, there are no pad bits, so this is a no-op.
998 */
999 l_int32
pixSetPadBits(PIX * pix,l_int32 val)1000 pixSetPadBits(PIX *pix,
1001 l_int32 val)
1002 {
1003 l_int32 i, w, h, d, wpl, endbits, fullwords;
1004 l_uint32 mask;
1005 l_uint32 *data, *pword;
1006
1007 PROCNAME("pixSetPadBits");
1008
1009 if (!pix)
1010 return ERROR_INT("pix not defined", procName, 1);
1011
1012 pixGetDimensions(pix, &w, &h, &d);
1013 if (d == 32) /* no padding exists for 32 bpp */
1014 return 0;
1015
1016 data = pixGetData(pix);
1017 wpl = pixGetWpl(pix);
1018 endbits = 32 - ((w * d) % 32);
1019 if (endbits == 32) /* no partial word */
1020 return 0;
1021 fullwords = w * d / 32;
1022
1023 mask = rmask32[endbits];
1024 if (val == 0)
1025 mask = ~mask;
1026
1027 for (i = 0; i < h; i++) {
1028 pword = data + i * wpl + fullwords;
1029 if (val == 0) /* clear */
1030 *pword = *pword & mask;
1031 else /* set */
1032 *pword = *pword | mask;
1033 }
1034
1035 return 0;
1036 }
1037
1038
1039 /*!
1040 * pixSetPadBitsBand()
1041 *
1042 * Input: pix (1, 2, 4, 8, 16, 32 bpp)
1043 * by (starting y value of band)
1044 * bh (height of band)
1045 * val (0 or 1)
1046 * Return: 0 if OK; 1 on error
1047 *
1048 * Notes:
1049 * (1) The pad bits are the bits that expand each scanline to a
1050 * multiple of 32 bits. They are usually not used in
1051 * image processing operations. When boundary conditions
1052 * are important, as in seedfill, they must be set properly.
1053 * (2) This sets the value of the pad bits (if any) in the last
1054 * 32-bit word in each scanline, within the specified
1055 * band of raster lines.
1056 * (3) For 32 bpp pix, there are no pad bits, so this is a no-op.
1057 */
1058 l_int32
pixSetPadBitsBand(PIX * pix,l_int32 by,l_int32 bh,l_int32 val)1059 pixSetPadBitsBand(PIX *pix,
1060 l_int32 by,
1061 l_int32 bh,
1062 l_int32 val)
1063 {
1064 l_int32 i, w, h, d, wpl, endbits, fullwords;
1065 l_uint32 mask;
1066 l_uint32 *data, *pword;
1067
1068 PROCNAME("pixSetPadBitsBand");
1069
1070 if (!pix)
1071 return ERROR_INT("pix not defined", procName, 1);
1072
1073 pixGetDimensions(pix, &w, &h, &d);
1074 if (d == 32) /* no padding exists for 32 bpp */
1075 return 0;
1076
1077 if (by < 0)
1078 by = 0;
1079 if (by >= h)
1080 return ERROR_INT("start y not in image", procName, 1);
1081 if (by + bh > h)
1082 bh = h - by;
1083
1084 data = pixGetData(pix);
1085 wpl = pixGetWpl(pix);
1086 endbits = 32 - ((w * d) % 32);
1087 if (endbits == 32) /* no partial word */
1088 return 0;
1089 fullwords = w * d / 32;
1090
1091 mask = rmask32[endbits];
1092 if (val == 0)
1093 mask = ~mask;
1094
1095 for (i = by; i < by + bh; i++) {
1096 pword = data + i * wpl + fullwords;
1097 if (val == 0) /* clear */
1098 *pword = *pword & mask;
1099 else /* set */
1100 *pword = *pword | mask;
1101 }
1102
1103 return 0;
1104 }
1105
1106
1107 /*-------------------------------------------------------------*
1108 * Set border pixels *
1109 *-------------------------------------------------------------*/
1110 /*!
1111 * pixSetOrClearBorder()
1112 *
1113 * Input: pixs (all depths)
1114 * left, right, top, bot (amount to set or clear)
1115 * operation (PIX_SET or PIX_CLR)
1116 * Return: 0 if OK; 1 on error
1117 *
1118 * Notes:
1119 * (1) The border region is defined to be the region in the
1120 * image within a specific distance of each edge. Here, we
1121 * allow the pixels within a specified distance of each
1122 * edge to be set independently. This either sets or
1123 * clears all pixels in the border region.
1124 * (2) For binary images, use PIX_SET for black and PIX_CLR for white.
1125 * (3) For grayscale or color images, use PIX_SET for white
1126 * and PIX_CLR for black.
1127 */
1128 l_int32
pixSetOrClearBorder(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot,l_int32 op)1129 pixSetOrClearBorder(PIX *pixs,
1130 l_int32 left,
1131 l_int32 right,
1132 l_int32 top,
1133 l_int32 bot,
1134 l_int32 op)
1135 {
1136 l_int32 w, h;
1137
1138 PROCNAME("pixSetOrClearBorder");
1139
1140 if (!pixs)
1141 return ERROR_INT("pixs not defined", procName, 1);
1142 if (op != PIX_SET && op != PIX_CLR)
1143 return ERROR_INT("op must be PIX_SET or PIX_CLR", procName, 1);
1144
1145 pixGetDimensions(pixs, &w, &h, NULL);
1146 pixRasterop(pixs, 0, 0, left, h, op, NULL, 0, 0);
1147 pixRasterop(pixs, w - right, 0, right, h, op, NULL, 0, 0);
1148 pixRasterop(pixs, 0, 0, w, top, op, NULL, 0, 0);
1149 pixRasterop(pixs, 0, h - bot, w, bot, op, NULL, 0, 0);
1150
1151 return 0;
1152 }
1153
1154
1155 /*!
1156 * pixSetBorderVal()
1157 *
1158 * Input: pixs (8, 16 or 32 bpp)
1159 * left, right, top, bot (amount to set)
1160 * val (value to set at each border pixel)
1161 * Return: 0 if OK; 1 on error
1162 *
1163 * Notes:
1164 * (1) The border region is defined to be the region in the
1165 * image within a specific distance of each edge. Here, we
1166 * allow the pixels within a specified distance of each
1167 * edge to be set independently. This sets the pixels
1168 * in the border region to the given input value.
1169 * (2) For efficiency, use pixSetOrClearBorder() if
1170 * you're setting the border to either black or white.
1171 * (3) If d != 32, the input value should be masked off
1172 * to the appropriate number of least significant bits.
1173 * (4) The code is easily generalized for 2 or 4 bpp.
1174 */
1175 l_int32
pixSetBorderVal(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot,l_uint32 val)1176 pixSetBorderVal(PIX *pixs,
1177 l_int32 left,
1178 l_int32 right,
1179 l_int32 top,
1180 l_int32 bot,
1181 l_uint32 val)
1182 {
1183 l_int32 w, h, d, wpls, i, j, bstart, rstart;
1184 l_uint32 *datas, *lines;
1185
1186 PROCNAME("pixSetBorderVal");
1187
1188 if (!pixs)
1189 return ERROR_INT("pixs not defined", procName, 1);
1190 pixGetDimensions(pixs, &w, &h, &d);
1191 if (d != 8 && d != 16 && d != 32)
1192 return ERROR_INT("depth must be 8, 16 or 32 bpp", procName, 1);
1193
1194 datas = pixGetData(pixs);
1195 wpls = pixGetWpl(pixs);
1196 if (d == 8) {
1197 val &= 0xff;
1198 for (i = 0; i < top; i++) {
1199 lines = datas + i * wpls;
1200 for (j = 0; j < w; j++)
1201 SET_DATA_BYTE(lines, j, val);
1202 }
1203 rstart = w - right;
1204 bstart = h - bot;
1205 for (i = top; i < bstart; i++) {
1206 lines = datas + i * wpls;
1207 for (j = 0; j < left; j++)
1208 SET_DATA_BYTE(lines, j, val);
1209 for (j = rstart; j < w; j++)
1210 SET_DATA_BYTE(lines, j, val);
1211 }
1212 for (i = bstart; i < h; i++) {
1213 lines = datas + i * wpls;
1214 for (j = 0; j < w; j++)
1215 SET_DATA_BYTE(lines, j, val);
1216 }
1217 }
1218 else if (d == 16) {
1219 val &= 0xffff;
1220 for (i = 0; i < top; i++) {
1221 lines = datas + i * wpls;
1222 for (j = 0; j < w; j++)
1223 SET_DATA_TWO_BYTES(lines, j, val);
1224 }
1225 rstart = w - right;
1226 bstart = h - bot;
1227 for (i = top; i < bstart; i++) {
1228 lines = datas + i * wpls;
1229 for (j = 0; j < left; j++)
1230 SET_DATA_TWO_BYTES(lines, j, val);
1231 for (j = rstart; j < w; j++)
1232 SET_DATA_TWO_BYTES(lines, j, val);
1233 }
1234 for (i = bstart; i < h; i++) {
1235 lines = datas + i * wpls;
1236 for (j = 0; j < w; j++)
1237 SET_DATA_TWO_BYTES(lines, j, val);
1238 }
1239 }
1240 else { /* d == 32 */
1241 for (i = 0; i < top; i++) {
1242 lines = datas + i * wpls;
1243 for (j = 0; j < w; j++)
1244 *(lines + j) = val;
1245 }
1246 rstart = w - right;
1247 bstart = h - bot;
1248 for (i = top; i < bstart; i++) {
1249 lines = datas + i * wpls;
1250 for (j = 0; j < left; j++)
1251 *(lines + j) = val;
1252 for (j = rstart; j < w; j++)
1253 *(lines + j) = val;
1254 }
1255 for (i = bstart; i < h; i++) {
1256 lines = datas + i * wpls;
1257 for (j = 0; j < w; j++)
1258 *(lines + j) = val;
1259 }
1260 }
1261
1262 return 0;
1263 }
1264
1265
1266 /*!
1267 * pixSetMirroredBorder()
1268 *
1269 * Input: pixs (all depths; colormap ok)
1270 * left, right, top, bot (number of pixels to set)
1271 * Return: 0 if OK, 1 on error
1272 *
1273 * Notes:
1274 * (1) This applies what is effectively mirror boundary conditions
1275 * to a border region in the image. It is in-place.
1276 * (2) This is useful for setting pixels near the border to a
1277 * value representative of the near pixels to the interior.
1278 * (3) The general pixRasterop() is used for an in-place operation here
1279 * because there is no overlap between the src and dest rectangles.
1280 */
1281 l_int32
pixSetMirroredBorder(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot)1282 pixSetMirroredBorder(PIX *pixs,
1283 l_int32 left,
1284 l_int32 right,
1285 l_int32 top,
1286 l_int32 bot)
1287 {
1288 l_int32 i, j, w, h;
1289
1290 PROCNAME("pixSetMirroredBorder");
1291
1292 if (!pixs)
1293 return ERROR_INT("pixs not defined", procName, 1);
1294
1295 pixGetDimensions(pixs, &w, &h, NULL);
1296 for (j = 0; j < left; j++)
1297 pixRasterop(pixs, left - 1 - j, top, 1, h - top - bot, PIX_SRC,
1298 pixs, left + j, top);
1299 for (j = 0; j < right; j++)
1300 pixRasterop(pixs, w - right + j, top, 1, h - top - bot, PIX_SRC,
1301 pixs, w - right - 1 - j, top);
1302 for (i = 0; i < top; i++)
1303 pixRasterop(pixs, 0, top - 1 - i, w, 1, PIX_SRC,
1304 pixs, 0, top + i);
1305 for (i = 0; i < bot; i++)
1306 pixRasterop(pixs, 0, h - bot + i, w, 1, PIX_SRC,
1307 pixs, 0, h - bot - 1 - i);
1308
1309 return 0;
1310 }
1311
1312
1313 /*!
1314 * pixCopyBorder()
1315 *
1316 * Input: pixd (all depths; colormap ok; can be NULL)
1317 * pixs (same depth and size as pixd)
1318 * left, right, top, bot (number of pixels to copy)
1319 * Return: pixd, or null on error if pixd is not defined
1320 *
1321 * Notes:
1322 * (1) pixd can be null, but otherwise it must be the same size
1323 * and depth as pixs. Always returns pixd.
1324 * (1) This is useful in situations where by setting a few border
1325 * pixels we can avoid having to copy all pixels in pixs into
1326 * pixd as an initialization step for some operation.
1327 */
1328 PIX *
pixCopyBorder(PIX * pixd,PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot)1329 pixCopyBorder(PIX *pixd,
1330 PIX *pixs,
1331 l_int32 left,
1332 l_int32 right,
1333 l_int32 top,
1334 l_int32 bot)
1335 {
1336 l_int32 w, h;
1337
1338 PROCNAME("pixCopyBorder");
1339
1340 if (!pixs)
1341 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
1342
1343 if (pixd) {
1344 if (pixd == pixs) {
1345 L_WARNING("same: nothing to do", procName);
1346 return pixd;
1347 }
1348 else if (!pixSizesEqual(pixs, pixd))
1349 return (PIX *)ERROR_PTR("pixs and pixd sizes differ",
1350 procName, pixd);
1351 }
1352 else {
1353 if ((pixd = pixCreateTemplateNoInit(pixs)) == NULL)
1354 return (PIX *)ERROR_PTR("pixd not made", procName, pixd);
1355 }
1356
1357 pixGetDimensions(pixs, &w, &h, NULL);
1358 pixRasterop(pixd, 0, 0, left, h, PIX_SRC, pixs, 0, 0);
1359 pixRasterop(pixd, w - right, 0, right, h, PIX_SRC, pixs, w - right, 0);
1360 pixRasterop(pixd, 0, 0, w, top, PIX_SRC, pixs, 0, 0);
1361 pixRasterop(pixd, 0, h - bot, w, bot, PIX_SRC, pixs, 0, h - bot);
1362
1363 return pixd;
1364 }
1365
1366
1367
1368 /*-------------------------------------------------------------*
1369 * Add and remove border *
1370 *-------------------------------------------------------------*/
1371 /*!
1372 * pixAddBorder()
1373 *
1374 * Input: pixs (all depths; colormap ok)
1375 * npix (number of pixels to be added to each side)
1376 * val (value of added border pixels)
1377 * Return: pixd (with the input pixs centered), or null on error
1378 *
1379 * Notes:
1380 * (1) See pixAddBorderGeneral() for values of white & black pixels.
1381 */
1382 PIX *
pixAddBorder(PIX * pixs,l_int32 npix,l_uint32 val)1383 pixAddBorder(PIX *pixs,
1384 l_int32 npix,
1385 l_uint32 val)
1386 {
1387 PROCNAME("pixAddBorder");
1388
1389 if (!pixs)
1390 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1391 if (npix == 0)
1392 return pixClone(pixs);
1393 return pixAddBorderGeneral(pixs, npix, npix, npix, npix, val);
1394 }
1395
1396
1397 /*!
1398 * pixAddBorderGeneral()
1399 *
1400 * Input: pixs (all depths; colormap ok)
1401 * left, right, top, bot (number of pixels added)
1402 * val (value of added border pixels)
1403 * Return: pixd (with the input pixs inserted), or null on error
1404 *
1405 * Notes:
1406 * (1) For binary images:
1407 * white: val = 0
1408 * black: val = 1
1409 * (2) For grayscale images:
1410 * white: val = 2 ** d - 1
1411 * black: val = 0
1412 * (3) For rgb color images:
1413 * white: val = 0xffffff00
1414 * black: val = 0
1415 */
1416 PIX *
pixAddBorderGeneral(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot,l_uint32 val)1417 pixAddBorderGeneral(PIX *pixs,
1418 l_int32 left,
1419 l_int32 right,
1420 l_int32 top,
1421 l_int32 bot,
1422 l_uint32 val)
1423 {
1424 l_int32 ws, hs, wd, hd, d, op;
1425 PIX *pixd;
1426
1427 PROCNAME("pixAddBorderGeneral");
1428
1429 if (!pixs)
1430 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1431 if (left < 0 || right < 0 || top < 0 || bot < 0)
1432 return (PIX *)ERROR_PTR("negative border added!", procName, NULL);
1433
1434 pixGetDimensions(pixs, &ws, &hs, &d);
1435 wd = ws + left + right;
1436 hd = hs + top + bot;
1437 if ((pixd = pixCreateNoInit(wd, hd, d)) == NULL)
1438 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1439 pixCopyResolution(pixd, pixs);
1440 pixCopyColormap(pixd, pixs);
1441
1442 /* Set the new border pixels */
1443 op = UNDEF;
1444 if (val == 0)
1445 op = PIX_CLR;
1446 else if ((d == 1 && val == 1) || (d == 2 && val == 3) ||
1447 (d == 4 && val == 0xf) || (d == 8 && val == 0xff) ||
1448 (d == 32 && (val >> 8) == 0xffffff))
1449 op = PIX_SET;
1450 if (op == UNDEF)
1451 pixSetAllArbitrary(pixd, val); /* a little extra writing ! */
1452 else {
1453 pixRasterop(pixd, 0, 0, left, hd, op, NULL, 0, 0);
1454 pixRasterop(pixd, wd - right, 0, right, hd, op, NULL, 0, 0);
1455 pixRasterop(pixd, 0, 0, wd, top, op, NULL, 0, 0);
1456 pixRasterop(pixd, 0, hd - bot, wd, bot, op, NULL, 0, 0);
1457 }
1458
1459 /* Copy pixs into the interior */
1460 pixRasterop(pixd, left, top, ws, hs, PIX_SRC, pixs, 0, 0);
1461 return pixd;
1462 }
1463
1464
1465 /*!
1466 * pixRemoveBorder()
1467 *
1468 * Input: pixs (all depths; colormap ok)
1469 * npix (number to be removed from each of the 4 sides)
1470 * Return: pixd (with pixels removed around border), or null on error
1471 */
1472 PIX *
pixRemoveBorder(PIX * pixs,l_int32 npix)1473 pixRemoveBorder(PIX *pixs,
1474 l_int32 npix)
1475 {
1476 PROCNAME("pixRemoveBorder");
1477
1478 if (!pixs)
1479 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1480 if (npix == 0)
1481 return pixClone(pixs);
1482 return pixRemoveBorderGeneral(pixs, npix, npix, npix, npix);
1483 }
1484
1485
1486 /*!
1487 * pixRemoveBorderGeneral()
1488 *
1489 * Input: pixs (all depths; colormap ok)
1490 * left, right, top, bot (number of pixels added)
1491 * Return: pixd (with pixels removed around border), or null on error
1492 */
1493 PIX *
pixRemoveBorderGeneral(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot)1494 pixRemoveBorderGeneral(PIX *pixs,
1495 l_int32 left,
1496 l_int32 right,
1497 l_int32 top,
1498 l_int32 bot)
1499 {
1500 l_int32 ws, hs, wd, hd, d;
1501 PIX *pixd;
1502
1503 PROCNAME("pixRemoveBorderGeneral");
1504
1505 if (!pixs)
1506 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1507 if (left < 0 || right < 0 || top < 0 || bot < 0)
1508 return (PIX *)ERROR_PTR("negative border removed!", procName, NULL);
1509
1510 pixGetDimensions(pixs, &ws, &hs, &d);
1511 wd = ws - left - right;
1512 hd = hs - top - bot;
1513 if (wd <= 0)
1514 return (PIX *)ERROR_PTR("width must be > 0", procName, NULL);
1515 if (hd <= 0)
1516 return (PIX *)ERROR_PTR("height must be > 0", procName, NULL);
1517 if ((pixd = pixCreateNoInit(wd, hd, d)) == NULL)
1518 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1519 pixCopyResolution(pixd, pixs);
1520 pixCopyColormap(pixd, pixs);
1521
1522 pixRasterop(pixd, 0, 0, wd, hd, PIX_SRC, pixs, left, top);
1523 return pixd;
1524 }
1525
1526
1527 /*!
1528 * pixAddMirroredBorder()
1529 *
1530 * Input: pixs (all depths; colormap ok)
1531 * left, right, top, bot (number of pixels added)
1532 * Return: pixd, or null on error
1533 *
1534 * Notes:
1535 * (1) This applies what is effectively mirror boundary conditions.
1536 * For the added border pixels in pixd, the pixels in pixs
1537 * near the border are mirror-copied into the border region.
1538 * (2) This is useful for avoiding special operations near
1539 * boundaries when doing image processing operations
1540 * such as rank filters and convolution. In use, one first
1541 * adds mirrored pixels to each side of the image. The number
1542 * of pixels added on each side is half the filter dimension.
1543 * Then the image processing operations proceed over a
1544 * region equal to the size of the original image, and
1545 * write directly into a dest pix of the same size as pixs.
1546 * (3) The general pixRasterop() is used for an in-place operation here
1547 * because there is no overlap between the src and dest rectangles.
1548 */
1549 PIX *
pixAddMirroredBorder(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot)1550 pixAddMirroredBorder(PIX *pixs,
1551 l_int32 left,
1552 l_int32 right,
1553 l_int32 top,
1554 l_int32 bot)
1555 {
1556 l_int32 i, j, w, h;
1557 PIX *pixd;
1558
1559 PROCNAME("pixAddMirroredBorder");
1560
1561 if (!pixs)
1562 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1563 pixGetDimensions(pixs, &w, &h, NULL);
1564 if (left > w || right > w || top > h || bot > h)
1565 return (PIX *)ERROR_PTR("border too large", procName, NULL);
1566
1567 /* Set pixels on left, right, top and bottom, in that order */
1568 pixd = pixAddBorderGeneral(pixs, left, right, top, bot, 0);
1569 for (j = 0; j < left; j++)
1570 pixRasterop(pixd, left - 1 - j, top, 1, h, PIX_SRC,
1571 pixd, left + j, top);
1572 for (j = 0; j < right; j++)
1573 pixRasterop(pixd, left + w + j, top, 1, h, PIX_SRC,
1574 pixd, left + w - 1 - j, top);
1575 for (i = 0; i < top; i++)
1576 pixRasterop(pixd, 0, top - 1 - i, left + w + right, 1, PIX_SRC,
1577 pixd, 0, top + i);
1578 for (i = 0; i < bot; i++)
1579 pixRasterop(pixd, 0, top + h + i, left + w + right, 1, PIX_SRC,
1580 pixd, 0, top + h - 1 - i);
1581
1582 return pixd;
1583 }
1584
1585 /*!
1586 * pixAddRepeatedBorder()
1587 *
1588 * Input: pixs (all depths; colormap ok)
1589 * left, right, top, bot (number of pixels added)
1590 * Return: pixd, or null on error
1591 *
1592 * Notes:
1593 * (1) This applies a repeated border, as if the central part of
1594 * the image is tiled over the plane. So, for example, the
1595 * pixels in the left border come from the right side of the image.
1596 * (2) The general pixRasterop() is used for an in-place operation here
1597 * because there is no overlap between the src and dest rectangles.
1598 */
1599 PIX *
pixAddRepeatedBorder(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot)1600 pixAddRepeatedBorder(PIX *pixs,
1601 l_int32 left,
1602 l_int32 right,
1603 l_int32 top,
1604 l_int32 bot)
1605 {
1606 l_int32 w, h;
1607 PIX *pixd;
1608
1609 PROCNAME("pixAddRepeatedBorder");
1610
1611 if (!pixs)
1612 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1613 pixGetDimensions(pixs, &w, &h, NULL);
1614 if (left > w || right > w || top > h || bot > h)
1615 return (PIX *)ERROR_PTR("border too large", procName, NULL);
1616
1617 pixd = pixAddBorderGeneral(pixs, left, right, top, bot, 0);
1618
1619 /* Set pixels on left, right, top and bottom, in that order */
1620 pixRasterop(pixd, 0, top, left, h, PIX_SRC, pixd, w, top);
1621 pixRasterop(pixd, left + w, top, right, h, PIX_SRC, pixd, left, top);
1622 pixRasterop(pixd, 0, 0, left + w + right, top, PIX_SRC, pixd, 0, h);
1623 pixRasterop(pixd, 0, top + h, left + w + right, bot, PIX_SRC, pixd, 0, top);
1624
1625 return pixd;
1626 }
1627
1628
1629 /*!
1630 * pixAddMixedBorder()
1631 *
1632 * Input: pixs (all depths; colormap ok)
1633 * left, right, top, bot (number of pixels added)
1634 * Return: pixd, or null on error
1635 *
1636 * Notes:
1637 * (1) This applies mirrored boundary conditions horizontally
1638 * and repeated b.c. vertically.
1639 * (2) It is specifically used for avoiding special operations
1640 * near boundaries when convolving a hue-saturation histogram
1641 * with a given window size. The repeated b.c. are used
1642 * vertically for hue, and the mirrored b.c. are used
1643 * horizontally for saturation. The number of pixels added
1644 * on each side is approximately (but not quite) half the
1645 * filter dimension. The image processing operations can
1646 * then proceed over a region equal to the size of the original
1647 * image, and write directly into a dest pix of the same
1648 * size as pixs.
1649 * (3) The general pixRasterop() can be used for an in-place
1650 * operation here because there is no overlap between the
1651 * src and dest rectangles.
1652 */
1653 PIX *
pixAddMixedBorder(PIX * pixs,l_int32 left,l_int32 right,l_int32 top,l_int32 bot)1654 pixAddMixedBorder(PIX *pixs,
1655 l_int32 left,
1656 l_int32 right,
1657 l_int32 top,
1658 l_int32 bot)
1659 {
1660 l_int32 j, w, h;
1661 PIX *pixd;
1662
1663 PROCNAME("pixAddMixedBorder");
1664
1665 if (!pixs)
1666 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1667 pixGetDimensions(pixs, &w, &h, NULL);
1668 if (left > w || right > w || top > h || bot > h)
1669 return (PIX *)ERROR_PTR("border too large", procName, NULL);
1670
1671 /* Set mirrored pixels on left and right;
1672 * then set repeated pixels on top and bottom. */
1673 pixd = pixAddBorderGeneral(pixs, left, right, top, bot, 0);
1674 for (j = 0; j < left; j++)
1675 pixRasterop(pixd, left - 1 - j, top, 1, h, PIX_SRC,
1676 pixd, left + j, top);
1677 for (j = 0; j < right; j++)
1678 pixRasterop(pixd, left + w + j, top, 1, h, PIX_SRC,
1679 pixd, left + w - 1 - j, top);
1680 pixRasterop(pixd, 0, 0, left + w + right, top, PIX_SRC, pixd, 0, h);
1681 pixRasterop(pixd, 0, top + h, left + w + right, bot, PIX_SRC, pixd, 0, top);
1682
1683 return pixd;
1684 }
1685
1686
1687
1688 /*-------------------------------------------------------------*
1689 * Color sample setting and extraction *
1690 *-------------------------------------------------------------*/
1691 /*!
1692 * pixCreateRGBImage()
1693 *
1694 * Input: 8 bpp red pix
1695 * 8 bpp green pix
1696 * 8 bpp blue pix
1697 * Return: 32 bpp pix, interleaved with 4 samples/pixel,
1698 * or null on error
1699 *
1700 * Notes:
1701 * (1) the 4th byte, sometimes called the "alpha channel",
1702 * and which is often used for blending between different
1703 * images, is left with 0 value.
1704 * (2) see Note (4) in pix.h for details on storage of
1705 * 8-bit samples within each 32-bit word.
1706 * (3) This implementation, setting the r, g and b components
1707 * sequentially, is much faster than setting them in parallel
1708 * by constructing an RGB dest pixel and writing it to dest.
1709 * The reason is there are many more cache misses when reading
1710 * from 3 input images simultaneously.
1711 */
1712 PIX *
pixCreateRGBImage(PIX * pixr,PIX * pixg,PIX * pixb)1713 pixCreateRGBImage(PIX *pixr,
1714 PIX *pixg,
1715 PIX *pixb)
1716 {
1717 l_int32 wr, wg, wb, hr, hg, hb, dr, dg, db;
1718 PIX *pixd;
1719
1720 PROCNAME("pixCreateRGBImage");
1721
1722 if (!pixr)
1723 return (PIX *)ERROR_PTR("pixr not defined", procName, NULL);
1724 if (!pixg)
1725 return (PIX *)ERROR_PTR("pixg not defined", procName, NULL);
1726 if (!pixb)
1727 return (PIX *)ERROR_PTR("pixb not defined", procName, NULL);
1728 pixGetDimensions(pixr, &wr, &hr, &dr);
1729 pixGetDimensions(pixg, &wg, &hg, &dg);
1730 pixGetDimensions(pixb, &wb, &hb, &db);
1731 if (dr != 8 || dg != 8 || db != 8)
1732 return (PIX *)ERROR_PTR("input pix not all 8 bpp", procName, NULL);
1733 if (wr != wg || wr != wb)
1734 return (PIX *)ERROR_PTR("widths not the same", procName, NULL);
1735 if (hr != hg || hr != hb)
1736 return (PIX *)ERROR_PTR("heights not the same", procName, NULL);
1737
1738 if ((pixd = pixCreate(wr, hr, 32)) == NULL)
1739 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1740 pixCopyResolution(pixd, pixr);
1741 pixSetRGBComponent(pixd, pixr, COLOR_RED);
1742 pixSetRGBComponent(pixd, pixg, COLOR_GREEN);
1743 pixSetRGBComponent(pixd, pixb, COLOR_BLUE);
1744
1745 return pixd;
1746 }
1747
1748
1749 /*!
1750 * pixGetRGBComponent()
1751 *
1752 * Input: pixs (32 bpp)
1753 * color (one of {COLOR_RED, COLOR_GREEN, COLOR_BLUE,
1754 * L_ALPHA_CHANNEL})
1755 * Return: pixd, the selected 8 bpp component image of the
1756 * input 32 bpp image, or null on error
1757 *
1758 * Notes:
1759 * (1) The alpha channel (in the 4th byte of each RGB pixel)
1760 * is not used in leptonica.
1761 * (2) Three calls to this function generate the three 8 bpp component
1762 * images. This is much faster than generating the three
1763 * images in parallel, by extracting a src pixel and setting
1764 * the pixels of each component image from it. The reason is
1765 * there are many more cache misses when writing to three
1766 * output images simultaneously.
1767 */
1768 PIX *
pixGetRGBComponent(PIX * pixs,l_int32 color)1769 pixGetRGBComponent(PIX *pixs,
1770 l_int32 color)
1771 {
1772 l_uint8 srcbyte;
1773 l_uint32 *lines, *lined;
1774 l_uint32 *datas, *datad;
1775 l_int32 i, j, w, h;
1776 l_int32 wpls, wpld;
1777 PIX *pixd;
1778
1779 PROCNAME("pixGetRGBComponent");
1780
1781 if (!pixs)
1782 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1783 if (pixGetDepth(pixs) != 32)
1784 return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
1785 if (color != COLOR_RED && color != COLOR_GREEN &&
1786 color != COLOR_BLUE && color != L_ALPHA_CHANNEL)
1787 return (PIX *)ERROR_PTR("invalid color", procName, NULL);
1788
1789 pixGetDimensions(pixs, &w, &h, NULL);
1790 if ((pixd = pixCreate(w, h, 8)) == NULL)
1791 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1792 pixCopyResolution(pixd, pixs);
1793 wpls = pixGetWpl(pixs);
1794 wpld = pixGetWpl(pixd);
1795 datas = pixGetData(pixs);
1796 datad = pixGetData(pixd);
1797
1798 for (i = 0; i < h; i++) {
1799 lines = datas + i * wpls;
1800 lined = datad + i * wpld;
1801 for (j = 0; j < w; j++) {
1802 srcbyte = GET_DATA_BYTE(lines + j, color);
1803 SET_DATA_BYTE(lined, j, srcbyte);
1804 }
1805 }
1806
1807 return pixd;
1808 }
1809
1810
1811 /*!
1812 * pixSetRGBComponent()
1813 *
1814 * Input: pixd (32 bpp)
1815 * pixs (8 bpp)
1816 * color (one of {COLOR_RED, COLOR_GREEN, COLOR_BLUE,
1817 * L_ALPHA_CHANNEL})
1818 * Return: 0 if OK; 1 on error
1819 *
1820 * Notes:
1821 * (1) This places the 8 bpp pixel in pixs into the
1822 * specified color component (properly interleaved) in pixd.
1823 * (2) The alpha channel component is not used in leptonica.
1824 */
1825 l_int32
pixSetRGBComponent(PIX * pixd,PIX * pixs,l_int32 color)1826 pixSetRGBComponent(PIX *pixd,
1827 PIX *pixs,
1828 l_int32 color)
1829 {
1830 l_uint8 srcbyte;
1831 l_int32 i, j, w, h;
1832 l_int32 wpls, wpld;
1833 l_uint32 *lines, *lined;
1834 l_uint32 *datas, *datad;
1835
1836 PROCNAME("pixSetRGBComponent");
1837
1838 if (!pixd)
1839 return ERROR_INT("pixd not defined", procName, 1);
1840 if (!pixs)
1841 return ERROR_INT("pixs not defined", procName, 1);
1842
1843 if (pixGetDepth(pixd) != 32)
1844 return ERROR_INT("pixd not 32 bpp", procName, 1);
1845 if (pixGetDepth(pixs) != 8)
1846 return ERROR_INT("pixs not 8 bpp", procName, 1);
1847 if (color != COLOR_RED && color != COLOR_GREEN &&
1848 color != COLOR_BLUE && color != L_ALPHA_CHANNEL)
1849 return ERROR_INT("invalid color", procName, 1);
1850 pixGetDimensions(pixs, &w, &h, NULL);
1851 if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd))
1852 return ERROR_INT("sizes not commensurate", procName, 1);
1853
1854 datas = pixGetData(pixs);
1855 datad = pixGetData(pixd);
1856 wpls = pixGetWpl(pixs);
1857 wpld = pixGetWpl(pixd);
1858 for (i = 0; i < h; i++) {
1859 lines = datas + i * wpls;
1860 lined = datad + i * wpld;
1861 for (j = 0; j < w; j++) {
1862 srcbyte = GET_DATA_BYTE(lines, j);
1863 SET_DATA_BYTE(lined + j, color, srcbyte);
1864 }
1865 }
1866
1867 return 0;
1868 }
1869
1870
1871 /*!
1872 * pixGetRGBComponentCmap()
1873 *
1874 * Input: pixs (colormapped)
1875 * color (one of {COLOR_RED, COLOR_GREEN, COLOR_BLUE})
1876 * Return: pixd (the selected 8 bpp component image of the
1877 * input cmapped image), or null on error
1878 */
1879 PIX *
pixGetRGBComponentCmap(PIX * pixs,l_int32 color)1880 pixGetRGBComponentCmap(PIX *pixs,
1881 l_int32 color)
1882 {
1883 l_int32 i, j, w, h, val, index;
1884 l_int32 wplc, wpld;
1885 l_uint32 *linec, *lined;
1886 l_uint32 *datac, *datad;
1887 PIX *pixc, *pixd;
1888 PIXCMAP *cmap;
1889 RGBA_QUAD *cta;
1890
1891 PROCNAME("pixGetRGBComponentCmap");
1892
1893 if (!pixs)
1894 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1895 if ((cmap = pixGetColormap(pixs)) == NULL)
1896 return (PIX *)ERROR_PTR("pixs not cmapped", procName, NULL);
1897 if (color != COLOR_RED && color != COLOR_GREEN &&
1898 color != COLOR_BLUE)
1899 return (PIX *)ERROR_PTR("invalid color", procName, NULL);
1900
1901 /* If not 8 bpp, make a cmapped 8 bpp pix */
1902 if (pixGetDepth(pixs) == 8)
1903 pixc = pixClone(pixs);
1904 else
1905 pixc = pixConvertTo8(pixs, TRUE);
1906
1907 pixGetDimensions(pixs, &w, &h, NULL);
1908 if ((pixd = pixCreateNoInit(w, h, 8)) == NULL)
1909 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1910 pixCopyResolution(pixd, pixs);
1911 wplc = pixGetWpl(pixc);
1912 wpld = pixGetWpl(pixd);
1913 datac = pixGetData(pixc);
1914 datad = pixGetData(pixd);
1915 cta = (RGBA_QUAD *)cmap->array;
1916
1917 for (i = 0; i < h; i++) {
1918 linec = datac + i * wplc;
1919 lined = datad + i * wpld;
1920 if (color == COLOR_RED) {
1921 for (j = 0; j < w; j++) {
1922 index = GET_DATA_BYTE(linec, j);
1923 val = cta[index].red;
1924 SET_DATA_BYTE(lined, j, val);
1925 }
1926 }
1927 else if (color == COLOR_GREEN) {
1928 for (j = 0; j < w; j++) {
1929 index = GET_DATA_BYTE(linec, j);
1930 val = cta[index].green;
1931 SET_DATA_BYTE(lined, j, val);
1932 }
1933 }
1934 else if (color == COLOR_BLUE) {
1935 for (j = 0; j < w; j++) {
1936 index = GET_DATA_BYTE(linec, j);
1937 val = cta[index].green;
1938 SET_DATA_BYTE(lined, j, val);
1939 }
1940 }
1941 }
1942
1943 pixDestroy(&pixc);
1944 return pixd;
1945 }
1946
1947
1948 /*!
1949 * composeRGBPixel()
1950 *
1951 * Input: rval, gval, bval
1952 * &rgbpixel (<return> 32-bit pixel)
1953 * Return: 0 if OK; 1 on error
1954 *
1955 * Notes:
1956 * (1) A slower implementation uses macros:
1957 * SET_DATA_BYTE(ppixel, COLOR_RED, rval);
1958 * SET_DATA_BYTE(ppixel, COLOR_GREEN, gval);
1959 * SET_DATA_BYTE(ppixel, COLOR_BLUE, bval);
1960 */
1961 l_int32
composeRGBPixel(l_int32 rval,l_int32 gval,l_int32 bval,l_uint32 * ppixel)1962 composeRGBPixel(l_int32 rval,
1963 l_int32 gval,
1964 l_int32 bval,
1965 l_uint32 *ppixel)
1966 {
1967 PROCNAME("composeRGBPixel");
1968
1969 if (!ppixel)
1970 return ERROR_INT("&pixel not defined", procName, 1);
1971
1972 *ppixel = (rval << L_RED_SHIFT) | (gval << L_GREEN_SHIFT) |
1973 (bval << L_BLUE_SHIFT);
1974 return 0;
1975 }
1976
1977
1978 /*!
1979 * extractRGBValues()
1980 *
1981 * Input: pixel (32 bit)
1982 * &rval (<optional return> red component)
1983 * &gval (<optional return> green component)
1984 * &bval (<optional return> blue component)
1985 * Return: void
1986 *
1987 * Notes:
1988 * (1) A slower implementation uses macros:
1989 * *prval = GET_DATA_BYTE(&pixel, COLOR_RED);
1990 * *pgval = GET_DATA_BYTE(&pixel, COLOR_GREEN);
1991 * *pbval = GET_DATA_BYTE(&pixel, COLOR_BLUE);
1992 */
1993 void
extractRGBValues(l_uint32 pixel,l_int32 * prval,l_int32 * pgval,l_int32 * pbval)1994 extractRGBValues(l_uint32 pixel,
1995 l_int32 *prval,
1996 l_int32 *pgval,
1997 l_int32 *pbval)
1998 {
1999 if (prval) *prval = (pixel >> L_RED_SHIFT) & 0xff;
2000 if (pgval) *pgval = (pixel >> L_GREEN_SHIFT) & 0xff;
2001 if (pbval) *pbval = (pixel >> L_BLUE_SHIFT) & 0xff;
2002 return;
2003 }
2004
2005
2006 /*!
2007 * pixGetRGBLine()
2008 *
2009 * Input: pixs (32 bpp)
2010 * row
2011 * bufr (array of red samples; size w bytes)
2012 * bufg (array of green samples; size w bytes)
2013 * bufb (array of blue samples; size w bytes)
2014 * Return: 0 if OK; 1 on error
2015 *
2016 * Notes:
2017 * (1) This puts rgb components from the input line in pixs
2018 * into the given buffers.
2019 */
2020 l_int32
pixGetRGBLine(PIX * pixs,l_int32 row,l_uint8 * bufr,l_uint8 * bufg,l_uint8 * bufb)2021 pixGetRGBLine(PIX *pixs,
2022 l_int32 row,
2023 l_uint8 *bufr,
2024 l_uint8 *bufg,
2025 l_uint8 *bufb)
2026 {
2027 l_uint32 *lines;
2028 l_int32 j, w, h;
2029 l_int32 wpls;
2030
2031 PROCNAME("pixGetRGBLine");
2032
2033 if (!pixs)
2034 return ERROR_INT("pixs not defined", procName, 1);
2035 if (pixGetDepth(pixs) != 32)
2036 return ERROR_INT("pixs not 32 bpp", procName, 1);
2037 if (!bufr || !bufg || !bufb)
2038 return ERROR_INT("buffer not defined", procName, 1);
2039
2040 pixGetDimensions(pixs, &w, &h, NULL);
2041 if (row < 0 || row >= h)
2042 return ERROR_INT("row out of bounds", procName, 1);
2043 wpls = pixGetWpl(pixs);
2044 lines = pixGetData(pixs) + row * wpls;
2045
2046 for (j = 0; j < w; j++) {
2047 bufr[j] = GET_DATA_BYTE(lines + j, COLOR_RED);
2048 bufg[j] = GET_DATA_BYTE(lines + j, COLOR_GREEN);
2049 bufb[j] = GET_DATA_BYTE(lines + j, COLOR_BLUE);
2050 }
2051
2052 return 0;
2053 }
2054
2055
2056 /*-------------------------------------------------------------*
2057 * Pixel endian conversion *
2058 *-------------------------------------------------------------*/
2059 /*!
2060 * pixEndianByteSwapNew()
2061 *
2062 * Input: pixs
2063 * Return: pixd, or null on error
2064 *
2065 * Notes:
2066 * (1) This is used to convert the data in a pix to a
2067 * serialized byte buffer in raster order, and, for RGB,
2068 * in order RGBA. This requires flipping bytes within
2069 * each 32-bit word for little-endian platforms, because the
2070 * words have a MSB-to-the-left rule, whereas byte raster-order
2071 * requires the left-most byte in each word to be byte 0.
2072 * For big-endians, no swap is necessary, so this returns a clone.
2073 * (2) Unlike pixEndianByteSwap(), which swaps the bytes in-place,
2074 * this returns a new pix (or a clone). We provide this
2075 * because often when serialization is done, the source
2076 * pix needs to be restored to canonical little-endian order,
2077 * and this requires a second byte swap. In such a situation,
2078 * it is twice as fast to make a new pix in big-endian order,
2079 * use it, and destroy it.
2080 */
2081 PIX *
pixEndianByteSwapNew(PIX * pixs)2082 pixEndianByteSwapNew(PIX *pixs)
2083 {
2084 l_uint32 *datas, *datad;
2085 l_int32 i, j, h, wpl;
2086 l_uint32 word;
2087 PIX *pixd;
2088
2089 PROCNAME("pixEndianByteSwapNew");
2090
2091 #ifdef L_BIG_ENDIAN
2092
2093 return pixClone(pixs);
2094
2095 #else /* L_LITTLE_ENDIAN */
2096
2097 if (!pixs)
2098 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2099
2100 datas = pixGetData(pixs);
2101 wpl = pixGetWpl(pixs);
2102 h = pixGetHeight(pixs);
2103 pixd = pixCreateTemplate(pixs);
2104 datad = pixGetData(pixd);
2105 for (i = 0; i < h; i++) {
2106 for (j = 0; j < wpl; j++, datas++, datad++) {
2107 word = *datas;
2108 *datad = (word >> 24) |
2109 ((word >> 8) & 0x0000ff00) |
2110 ((word << 8) & 0x00ff0000) |
2111 (word << 24);
2112 }
2113 }
2114
2115 return pixd;
2116
2117 #endif /* L_BIG_ENDIAN */
2118
2119 }
2120
2121
2122 /*!
2123 * pixEndianByteSwap()
2124 *
2125 * Input: pixs
2126 * Return: 0 if OK, 1 on error
2127 *
2128 * Notes:
2129 * (1) This is used on little-endian platforms to swap
2130 * the bytes within a word; bytes 0 and 3 are swapped,
2131 * and bytes 1 and 2 are swapped.
2132 * (2) This is required for little-endians in situations
2133 * where we convert from a serialized byte order that is
2134 * in raster order, as one typically has in file formats,
2135 * to one with MSB-to-the-left in each 32-bit word, or v.v.
2136 * See pix.h for a description of the canonical format
2137 * (MSB-to-the left) that is used for both little-endian
2138 * and big-endian platforms. For big-endians, the
2139 * MSB-to-the-left word order has the bytes in raster
2140 * order when serialized, so no byte flipping is required.
2141 */
2142 l_int32
pixEndianByteSwap(PIX * pixs)2143 pixEndianByteSwap(PIX *pixs)
2144 {
2145 l_uint32 *data;
2146 l_int32 i, j, h, wpl;
2147 l_uint32 word;
2148
2149 PROCNAME("pixEndianByteSwap");
2150
2151 #ifdef L_BIG_ENDIAN
2152
2153 return 0;
2154
2155 #else /* L_LITTLE_ENDIAN */
2156
2157 if (!pixs)
2158 return ERROR_INT("pixs not defined", procName, 1);
2159
2160 data = pixGetData(pixs);
2161 wpl = pixGetWpl(pixs);
2162 h = pixGetHeight(pixs);
2163 for (i = 0; i < h; i++) {
2164 for (j = 0; j < wpl; j++, data++) {
2165 word = *data;
2166 *data = (word >> 24) |
2167 ((word >> 8) & 0x0000ff00) |
2168 ((word << 8) & 0x00ff0000) |
2169 (word << 24);
2170 }
2171 }
2172
2173 return 0;
2174
2175 #endif /* L_BIG_ENDIAN */
2176
2177 }
2178
2179
2180 /*!
2181 * lineEndianByteSwap()
2182 *
2183 * Input datad (dest byte array data, reordered on little-endians)
2184 * datas (a src line of pix data)
2185 * wpl (number of 32 bit words in the line)
2186 * Return: 0 if OK, 1 on error
2187 *
2188 * Notes:
2189 * (1) This is used on little-endian platforms to swap
2190 * the bytes within each word in the line of image data.
2191 * Bytes 0 <==> 3 and 1 <==> 2 are swapped in the dest
2192 * byte array data8d, relative to the pix data in datas.
2193 * (2) The bytes represent 8 bit pixel values. They are swapped
2194 * for little endians so that when the dest array (char *)datad
2195 * is addressed by bytes, the pixels are chosen sequentially
2196 * from left to right in the image.
2197 */
2198 l_int32
lineEndianByteSwap(l_uint32 * datad,l_uint32 * datas,l_int32 wpl)2199 lineEndianByteSwap(l_uint32 *datad,
2200 l_uint32 *datas,
2201 l_int32 wpl)
2202 {
2203 l_int32 j;
2204 l_uint32 word;
2205
2206 PROCNAME("lineEndianByteSwap");
2207
2208 if (!datad || !datas)
2209 return ERROR_INT("datad and datas not both defined", procName, 1);
2210
2211 #ifdef L_BIG_ENDIAN
2212
2213 memcpy((char *)datad, (char *)datas, 4 * wpl);
2214 return 0;
2215
2216 #else /* L_LITTLE_ENDIAN */
2217
2218 for (j = 0; j < wpl; j++, datas++, datad++) {
2219 word = *datas;
2220 *datad = (word >> 24) |
2221 ((word >> 8) & 0x0000ff00) |
2222 ((word << 8) & 0x00ff0000) |
2223 (word << 24);
2224 }
2225 return 0;
2226
2227 #endif /* L_BIG_ENDIAN */
2228
2229 }
2230
2231
2232 /*!
2233 * pixEndianTwoByteSwapNew()
2234 *
2235 * Input: pixs
2236 * Return: 0 if OK, 1 on error
2237 *
2238 * Notes:
2239 * (1) This is used on little-endian platforms to swap the
2240 * 2-byte entities within a 32-bit word.
2241 * (2) This is equivalent to a full byte swap, as performed
2242 * by pixEndianByteSwap(), followed by byte swaps in
2243 * each of the 16-bit entities separately.
2244 * (3) Unlike pixEndianTwoByteSwap(), which swaps the shorts in-place,
2245 * this returns a new pix (or a clone). We provide this
2246 * to avoid having to swap twice in situations where the input
2247 * pix must be restored to canonical little-endian order.
2248 */
2249 PIX *
pixEndianTwoByteSwapNew(PIX * pixs)2250 pixEndianTwoByteSwapNew(PIX *pixs)
2251 {
2252 l_uint32 *datas, *datad;
2253 l_int32 i, j, h, wpl;
2254 l_uint32 word;
2255 PIX *pixd;
2256
2257 PROCNAME("pixEndianTwoByteSwapNew");
2258
2259 #ifdef L_BIG_ENDIAN
2260
2261 return pixClone(pixs);
2262
2263 #else /* L_LITTLE_ENDIAN */
2264
2265 if (!pixs)
2266 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2267
2268 datas = pixGetData(pixs);
2269 wpl = pixGetWpl(pixs);
2270 h = pixGetHeight(pixs);
2271 pixd = pixCreateTemplate(pixs);
2272 datad = pixGetData(pixd);
2273 for (i = 0; i < h; i++) {
2274 for (j = 0; j < wpl; j++, datas++, datad++) {
2275 word = *datas;
2276 *datad = (word << 16) | (word >> 16);
2277 }
2278 }
2279
2280 return pixd;
2281
2282 #endif /* L_BIG_ENDIAN */
2283
2284 }
2285
2286
2287 /*!
2288 * pixEndianTwoByteSwap()
2289 *
2290 * Input: pixs
2291 * Return: 0 if OK, 1 on error
2292 *
2293 * Notes:
2294 * (1) This is used on little-endian platforms to swap the
2295 * 2-byte entities within a 32-bit word.
2296 * (2) This is equivalent to a full byte swap, as performed
2297 * by pixEndianByteSwap(), followed by byte swaps in
2298 * each of the 16-bit entities separately.
2299 */
2300 l_int32
pixEndianTwoByteSwap(PIX * pixs)2301 pixEndianTwoByteSwap(PIX *pixs)
2302 {
2303 l_uint32 *data;
2304 l_int32 i, j, h, wpl;
2305 l_uint32 word;
2306
2307 PROCNAME("pixEndianTwoByteSwap");
2308
2309 #ifdef L_BIG_ENDIAN
2310
2311 return 0;
2312
2313 #else /* L_LITTLE_ENDIAN */
2314
2315 if (!pixs)
2316 return ERROR_INT("pixs not defined", procName, 1);
2317
2318 data = pixGetData(pixs);
2319 wpl = pixGetWpl(pixs);
2320 h = pixGetHeight(pixs);
2321 for (i = 0; i < h; i++) {
2322 for (j = 0; j < wpl; j++, data++) {
2323 word = *data;
2324 *data = (word << 16) | (word >> 16);
2325 }
2326 }
2327
2328 return 0;
2329
2330 #endif /* L_BIG_ENDIAN */
2331
2332 }
2333
2334
2335