Leptonica 1.68
C Image Processing Library
|
00001 /*====================================================================* 00002 - Copyright (C) 2001 Leptonica. All rights reserved. 00003 - This software is distributed in the hope that it will be 00004 - useful, but with NO WARRANTY OF ANY KIND. 00005 - No author or distributor accepts responsibility to anyone for the 00006 - consequences of using this software, or for whether it serves any 00007 - particular purpose or works at all, unless he or she says so in 00008 - writing. Everyone is granted permission to copy, modify and 00009 - redistribute this source code, for commercial or non-commercial 00010 - purposes, with the following restrictions: (1) the origin of this 00011 - source code must not be misrepresented; (2) modified versions must 00012 - be plainly marked as such; and (3) this notice may not be removed 00013 - or altered from any source or modified source distribution. 00014 *====================================================================*/ 00015 00016 /* 00017 * pix2.c 00018 * 00019 * This file has these basic operations: 00020 * 00021 * (1) Get and set: individual pixels, full image, rectangular region, 00022 * pad pixels, border pixels, and color components for RGB 00023 * (2) Add and remove border pixels 00024 * (3) Endian byte swaps 00025 * (4) Simple method for byte-processing images (instead of words) 00026 * 00027 * Pixel poking 00028 * l_int32 pixGetPixel() 00029 * l_int32 pixSetPixel() 00030 * l_int32 pixGetRGBPixel() 00031 * l_int32 pixSetRGBPixel() 00032 * l_int32 pixGetRandomPixel() 00033 * l_int32 pixClearPixel() 00034 * l_int32 pixFlipPixel() 00035 * void setPixelLow() 00036 * 00037 * Full image clear/set/set-to-arbitrary-value 00038 * l_int32 pixClearAll() 00039 * l_int32 pixSetAll() 00040 * l_int32 pixSetAllArbitrary() 00041 * l_int32 pixSetBlackOrWhite() 00042 * 00043 * Rectangular region clear/set/set-to-arbitrary-value/blend 00044 * l_int32 pixClearInRect() 00045 * l_int32 pixSetInRect() 00046 * l_int32 pixSetInRectArbitrary() 00047 * l_int32 pixBlendInRect() 00048 * 00049 * Set pad bits 00050 * l_int32 pixSetPadBits() 00051 * l_int32 pixSetPadBitsBand() 00052 * 00053 * Assign border pixels 00054 * l_int32 pixSetOrClearBorder() 00055 * l_int32 pixSetBorderVal() 00056 * l_int32 pixSetBorderRingVal() 00057 * l_int32 pixSetMirroredBorder() 00058 * PIX *pixCopyBorder() 00059 * 00060 * Add and remove border 00061 * PIX *pixAddBorder() 00062 * PIX *pixAddBlackBorder() 00063 * PIX *pixAddBorderGeneral() 00064 * PIX *pixRemoveBorder() 00065 * PIX *pixRemoveBorderGeneral() 00066 * PIX *pixAddMirroredBorder() 00067 * PIX *pixAddRepeatedBorder() 00068 * PIX *pixAddMixedBorder() 00069 * 00070 * Color sample setting and extraction 00071 * PIX *pixCreateRGBImage() 00072 * PIX *pixGetRGBComponent() 00073 * l_int32 pixSetRGBComponent() 00074 * PIX *pixGetRGBComponentCmap() 00075 * l_int32 composeRGBPixel() 00076 * void extractRGBValues() 00077 * l_int32 extractMinMaxComponent() 00078 * l_int32 pixGetRGBLine() 00079 * 00080 * Conversion between big and little endians 00081 * PIX *pixEndianByteSwapNew() 00082 * l_int32 pixEndianByteSwap() 00083 * l_int32 lineEndianByteSwap() 00084 * PIX *pixEndianTwoByteSwapNew() 00085 * l_int32 pixEndianTwoByteSwap() 00086 * 00087 * Extract raster data as binary string 00088 * l_int32 pixGetRasterData() 00089 * 00090 * Setup helpers for 8 bpp byte processing 00091 * l_uint8 **pixSetupByteProcessing() 00092 * l_int32 pixCleanupByteProcessing() 00093 * 00094 * Setting parameters for antialias masking with alpha transforms 00095 * void l_setAlphaMaskBorder() 00096 * 00097 * *** indicates implicit assumption about RGB component ordering 00098 */ 00099 00100 00101 #include <string.h> 00102 #include "allheaders.h" 00103 00104 static const l_uint32 rmask32[] = {0x0, 00105 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 00106 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 00107 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 00108 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff, 00109 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff, 00110 0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff, 00111 0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff, 00112 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff}; 00113 00114 /* This is a global that determines the default 8 bpp alpha mask values 00115 * for rings at distance 1 and 2 from the border. Declare extern 00116 * to use. To change the values, use l_setAlphaMaskBorder(). */ 00117 LEPT_DLL l_float32 AlphaMaskBorderVals[2] = {0.0, 0.5}; 00118 00119 00120 #ifndef NO_CONSOLE_IO 00121 #define DEBUG_SERIALIZE 0 00122 #endif /* ~NO_CONSOLE_IO */ 00123 00124 00125 /*-------------------------------------------------------------* 00126 * Pixel poking * 00127 *-------------------------------------------------------------*/ 00128 /*! 00129 * pixGetPixel() 00130 * 00131 * Input: pix 00132 * (x,y) pixel coords 00133 * &val (<return> pixel value) 00134 * Return: 0 if OK; 1 on error 00135 * 00136 * Notes: 00137 * (1) This returns the value in the data array. If the pix is 00138 * colormapped, it returns the colormap index, not the rgb value. 00139 * (2) Because of the function overhead and the parameter checking, 00140 * this is much slower than using the GET_DATA_*() macros directly. 00141 * Speed on a 1 Mpixel RGB image, using a 3 GHz machine: 00142 * * pixGet/pixSet: ~25 Mpix/sec 00143 * * GET_DATA/SET_DATA: ~350 MPix/sec 00144 * If speed is important and you're doing random access into 00145 * the pix, use pixGetLinePtrs() and the array access macros. 00146 */ 00147 l_int32 00148 pixGetPixel(PIX *pix, 00149 l_int32 x, 00150 l_int32 y, 00151 l_uint32 *pval) 00152 { 00153 l_int32 w, h, d, wpl, val; 00154 l_uint32 *line, *data; 00155 00156 PROCNAME("pixGetPixel"); 00157 00158 if (!pval) 00159 return ERROR_INT("pval not defined", procName, 1); 00160 *pval = 0; 00161 if (!pix) 00162 return ERROR_INT("pix not defined", procName, 1); 00163 00164 pixGetDimensions(pix, &w, &h, &d); 00165 if (x < 0 || x >= w) 00166 return ERROR_INT("x out of bounds", procName, 1); 00167 if (y < 0 || y >= h) 00168 return ERROR_INT("y out of bounds", procName, 1); 00169 00170 wpl = pixGetWpl(pix); 00171 data = pixGetData(pix); 00172 line = data + y * wpl; 00173 switch (d) 00174 { 00175 case 1: 00176 val = GET_DATA_BIT(line, x); 00177 break; 00178 case 2: 00179 val = GET_DATA_DIBIT(line, x); 00180 break; 00181 case 4: 00182 val = GET_DATA_QBIT(line, x); 00183 break; 00184 case 8: 00185 val = GET_DATA_BYTE(line, x); 00186 break; 00187 case 16: 00188 val = GET_DATA_TWO_BYTES(line, x); 00189 break; 00190 case 32: 00191 val = line[x]; 00192 break; 00193 default: 00194 return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", procName, 1); 00195 } 00196 00197 *pval = val; 00198 return 0; 00199 } 00200 00201 00202 /*! 00203 * pixSetPixel() 00204 * 00205 * Input: pix 00206 * (x,y) pixel coords 00207 * val (value to be inserted) 00208 * Return: 0 if OK; 1 on error 00209 * 00210 * Notes: 00211 * (1) Warning: the input value is not checked for overflow with respect 00212 * the the depth of @pix, and the sign bit (if any) is ignored. 00213 * * For d == 1, @val > 0 sets the bit on. 00214 * * For d == 2, 4, 8 and 16, @val is masked to the maximum allowable 00215 * pixel value, and any (invalid) higher order bits are discarded. 00216 * (2) See pixGetPixel() for information on performance. 00217 */ 00218 l_int32 00219 pixSetPixel(PIX *pix, 00220 l_int32 x, 00221 l_int32 y, 00222 l_uint32 val) 00223 { 00224 l_int32 w, h, d, wpl; 00225 l_uint32 *line, *data; 00226 00227 PROCNAME("pixSetPixel"); 00228 00229 if (!pix) 00230 return ERROR_INT("pix not defined", procName, 1); 00231 00232 pixGetDimensions(pix, &w, &h, &d); 00233 if (x < 0 || x >= w) 00234 return ERROR_INT("x out of bounds", procName, 1); 00235 if (y < 0 || y >= h) 00236 return ERROR_INT("y out of bounds", procName, 1); 00237 00238 data = pixGetData(pix); 00239 wpl = pixGetWpl(pix); 00240 line = data + y * wpl; 00241 switch (d) 00242 { 00243 case 1: 00244 if (val) 00245 SET_DATA_BIT(line, x); 00246 else 00247 CLEAR_DATA_BIT(line, x); 00248 break; 00249 case 2: 00250 SET_DATA_DIBIT(line, x, val); 00251 break; 00252 case 4: 00253 SET_DATA_QBIT(line, x, val); 00254 break; 00255 case 8: 00256 SET_DATA_BYTE(line, x, val); 00257 break; 00258 case 16: 00259 SET_DATA_TWO_BYTES(line, x, val); 00260 break; 00261 case 32: 00262 line[x] = val; 00263 break; 00264 default: 00265 return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", procName, 1); 00266 } 00267 00268 return 0; 00269 } 00270 00271 00272 /*! 00273 * pixGetRGBPixel() 00274 * 00275 * Input: pix (32 bpp rgb, not colormapped) 00276 * (x,y) pixel coords 00277 * &rval (<optional return> red component) 00278 * &gval (<optional return> green component) 00279 * &bval (<optional return> blue component) 00280 * Return: 0 if OK; 1 on error 00281 */ 00282 l_int32 00283 pixGetRGBPixel(PIX *pix, 00284 l_int32 x, 00285 l_int32 y, 00286 l_int32 *prval, 00287 l_int32 *pgval, 00288 l_int32 *pbval) 00289 { 00290 l_int32 w, h, d, wpl; 00291 l_uint32 *data, *ppixel; 00292 00293 PROCNAME("pixGetRGBPixel"); 00294 00295 if (!pix) 00296 return ERROR_INT("pix not defined", procName, 1); 00297 pixGetDimensions(pix, &w, &h, &d); 00298 if (d != 32) 00299 return ERROR_INT("pix not 32 bpp", procName, 1); 00300 if (x < 0 || x >= w) 00301 return ERROR_INT("x out of bounds", procName, 1); 00302 if (y < 0 || y >= h) 00303 return ERROR_INT("y out of bounds", procName, 1); 00304 00305 wpl = pixGetWpl(pix); 00306 data = pixGetData(pix); 00307 ppixel = data + y * wpl + x; 00308 if (prval) *prval = GET_DATA_BYTE(ppixel, COLOR_RED); 00309 if (pgval) *pgval = GET_DATA_BYTE(ppixel, COLOR_GREEN); 00310 if (pbval) *pbval = GET_DATA_BYTE(ppixel, COLOR_BLUE); 00311 return 0; 00312 } 00313 00314 00315 /*! 00316 * pixSetRGBPixel() 00317 * 00318 * Input: pix (32 bpp rgb) 00319 * (x,y) pixel coords 00320 * rval (red component) 00321 * gval (green component) 00322 * bval (blue component) 00323 * Return: 0 if OK; 1 on error 00324 */ 00325 l_int32 00326 pixSetRGBPixel(PIX *pix, 00327 l_int32 x, 00328 l_int32 y, 00329 l_int32 rval, 00330 l_int32 gval, 00331 l_int32 bval) 00332 { 00333 l_int32 w, h, d, wpl; 00334 l_uint32 pixel; 00335 l_uint32 *data, *line; 00336 00337 PROCNAME("pixSetRGBPixel"); 00338 00339 if (!pix) 00340 return ERROR_INT("pix not defined", procName, 1); 00341 pixGetDimensions(pix, &w, &h, &d); 00342 if (d != 32) 00343 return ERROR_INT("pix not 32 bpp", procName, 1); 00344 if (x < 0 || x >= w) 00345 return ERROR_INT("x out of bounds", procName, 1); 00346 if (y < 0 || y >= h) 00347 return ERROR_INT("y out of bounds", procName, 1); 00348 00349 wpl = pixGetWpl(pix); 00350 data = pixGetData(pix); 00351 line = data + y * wpl; 00352 composeRGBPixel(rval, gval, bval, &pixel); 00353 *(line + x) = pixel; 00354 return 0; 00355 } 00356 00357 00358 /*! 00359 * pixGetRandomPixel() 00360 * 00361 * Input: pix (any depth; can be colormapped) 00362 * &val (<return> pixel value) 00363 * &x (<optional return> x coordinate chosen; can be null) 00364 * &y (<optional return> y coordinate chosen; can be null) 00365 * Return: 0 if OK; 1 on error 00366 * 00367 * Notes: 00368 * (1) If the pix is colormapped, it returns the rgb value. 00369 */ 00370 l_int32 00371 pixGetRandomPixel(PIX *pix, 00372 l_uint32 *pval, 00373 l_int32 *px, 00374 l_int32 *py) 00375 { 00376 l_int32 w, h, x, y, rval, gval, bval; 00377 l_uint32 val; 00378 PIXCMAP *cmap; 00379 00380 PROCNAME("pixGetRandomPixel"); 00381 00382 if (!pval) 00383 return ERROR_INT("pval not defined", procName, 1); 00384 *pval = 0; 00385 if (!pix) 00386 return ERROR_INT("pix not defined", procName, 1); 00387 00388 pixGetDimensions(pix, &w, &h, NULL); 00389 x = rand() % w; 00390 y = rand() % h; 00391 if (px) *px = x; 00392 if (py) *py = y; 00393 pixGetPixel(pix, x, y, &val); 00394 if ((cmap = pixGetColormap(pix)) != NULL) { 00395 pixcmapGetColor(cmap, val, &rval, &gval, &bval); 00396 composeRGBPixel(rval, gval, bval, pval); 00397 } 00398 else 00399 *pval = val; 00400 00401 return 0; 00402 } 00403 00404 00405 /*! 00406 * pixClearPixel() 00407 * 00408 * Input: pix 00409 * (x,y) pixel coords 00410 * Return: 0 if OK; 1 on error. 00411 */ 00412 l_int32 00413 pixClearPixel(PIX *pix, 00414 l_int32 x, 00415 l_int32 y) 00416 { 00417 l_int32 w, h, d, wpl; 00418 l_uint32 *line, *data; 00419 00420 PROCNAME("pixClearPixel"); 00421 00422 if (!pix) 00423 return ERROR_INT("pix not defined", procName, 1); 00424 00425 pixGetDimensions(pix, &w, &h, &d); 00426 if (x < 0 || x >= w) 00427 return ERROR_INT("x out of bounds", procName, 1); 00428 if (y < 0 || y >= h) 00429 return ERROR_INT("y out of bounds", procName, 1); 00430 00431 wpl = pixGetWpl(pix); 00432 data = pixGetData(pix); 00433 line = data + y * wpl; 00434 switch (d) 00435 { 00436 case 1: 00437 CLEAR_DATA_BIT(line, x); 00438 break; 00439 case 2: 00440 CLEAR_DATA_DIBIT(line, x); 00441 break; 00442 case 4: 00443 CLEAR_DATA_QBIT(line, x); 00444 break; 00445 case 8: 00446 SET_DATA_BYTE(line, x, 0); 00447 break; 00448 case 16: 00449 SET_DATA_TWO_BYTES(line, x, 0); 00450 break; 00451 case 32: 00452 line[x] = 0; 00453 break; 00454 default: 00455 return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", procName, 1); 00456 } 00457 00458 return 0; 00459 } 00460 00461 00462 /*! 00463 * pixFlipPixel() 00464 * 00465 * Input: pix 00466 * (x,y) pixel coords 00467 * Return: 0 if OK; 1 on error 00468 */ 00469 l_int32 00470 pixFlipPixel(PIX *pix, 00471 l_int32 x, 00472 l_int32 y) 00473 { 00474 l_int32 w, h, d, wpl; 00475 l_uint32 val; 00476 l_uint32 *line, *data; 00477 00478 PROCNAME("pixFlipPixel"); 00479 00480 if (!pix) 00481 return ERROR_INT("pix not defined", procName, 1); 00482 00483 pixGetDimensions(pix, &w, &h, &d); 00484 if (x < 0 || x >= w) 00485 return ERROR_INT("x out of bounds", procName, 1); 00486 if (y < 0 || y >= h) 00487 return ERROR_INT("y out of bounds", procName, 1); 00488 00489 data = pixGetData(pix); 00490 wpl = pixGetWpl(pix); 00491 line = data + y * wpl; 00492 switch (d) 00493 { 00494 case 1: 00495 val = GET_DATA_BIT(line, x); 00496 if (val) 00497 CLEAR_DATA_BIT(line, x); 00498 else 00499 SET_DATA_BIT(line, x); 00500 break; 00501 case 2: 00502 val = GET_DATA_DIBIT(line, x); 00503 val ^= 0x3; 00504 SET_DATA_DIBIT(line, x, val); 00505 break; 00506 case 4: 00507 val = GET_DATA_QBIT(line, x); 00508 val ^= 0xf; 00509 SET_DATA_QBIT(line, x, val); 00510 break; 00511 case 8: 00512 val = GET_DATA_BYTE(line, x); 00513 val ^= 0xff; 00514 SET_DATA_BYTE(line, x, val); 00515 break; 00516 case 16: 00517 val = GET_DATA_TWO_BYTES(line, x); 00518 val ^= 0xffff; 00519 SET_DATA_TWO_BYTES(line, x, val); 00520 break; 00521 case 32: 00522 val = line[x] ^ 0xffffffff; 00523 line[x] = val; 00524 break; 00525 default: 00526 return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", procName, 1); 00527 } 00528 00529 return 0; 00530 } 00531 00532 00533 /*! 00534 * setPixelLow() 00535 * 00536 * Input: line (ptr to beginning of line), 00537 * x (pixel location in line) 00538 * depth (bpp) 00539 * val (to be inserted) 00540 * Return: void 00541 * 00542 * Notes: 00543 * (1) Caution: input variables are not checked! 00544 */ 00545 void 00546 setPixelLow(l_uint32 *line, 00547 l_int32 x, 00548 l_int32 depth, 00549 l_uint32 val) 00550 { 00551 switch (depth) 00552 { 00553 case 1: 00554 if (val) 00555 SET_DATA_BIT(line, x); 00556 else 00557 CLEAR_DATA_BIT(line, x); 00558 break; 00559 case 2: 00560 SET_DATA_DIBIT(line, x, val); 00561 break; 00562 case 4: 00563 SET_DATA_QBIT(line, x, val); 00564 break; 00565 case 8: 00566 SET_DATA_BYTE(line, x, val); 00567 break; 00568 case 16: 00569 SET_DATA_TWO_BYTES(line, x, val); 00570 break; 00571 case 32: 00572 line[x] = val; 00573 break; 00574 default: 00575 fprintf(stderr, "illegal depth in setPixelLow()\n"); 00576 } 00577 00578 return; 00579 } 00580 00581 00582 /*-------------------------------------------------------------* 00583 * Full image clear/set/set-to-arbitrary-value/invert * 00584 *-------------------------------------------------------------*/ 00585 /*! 00586 * pixClearAll() 00587 * 00588 * Input: pix (all depths; use cmapped with caution) 00589 * Return: 0 if OK, 1 on error 00590 * 00591 * Notes: 00592 * (1) Clears all data to 0. For 1 bpp, this is white; for grayscale 00593 * or color, this is black. 00594 * (2) Caution: for colormapped pix, this sets the color to the first 00595 * one in the colormap. Be sure that this is the intended color! 00596 */ 00597 l_int32 00598 pixClearAll(PIX *pix) 00599 { 00600 PROCNAME("pixClearAll"); 00601 00602 if (!pix) 00603 return ERROR_INT("pix not defined", procName, 1); 00604 00605 pixRasterop(pix, 0, 0, pixGetWidth(pix), pixGetHeight(pix), 00606 PIX_CLR, NULL, 0, 0); 00607 return 0; 00608 } 00609 00610 00611 /*! 00612 * pixSetAll() 00613 * 00614 * Input: pix (all depths; use cmapped with caution) 00615 * Return: 0 if OK, 1 on error 00616 * 00617 * Notes: 00618 * (1) Sets all data to 1. For 1 bpp, this is black; for grayscale 00619 * or color, this is white. 00620 * (2) Caution: for colormapped pix, this sets the pixel value to the 00621 * maximum value supported by the colormap: 2^d - 1. However, this 00622 * color may not be defined, because the colormap may not be full. 00623 */ 00624 l_int32 00625 pixSetAll(PIX *pix) 00626 { 00627 l_int32 n; 00628 PIXCMAP *cmap; 00629 00630 PROCNAME("pixSetAll"); 00631 00632 if (!pix) 00633 return ERROR_INT("pix not defined", procName, 1); 00634 if ((cmap = pixGetColormap(pix)) != NULL) { 00635 n = pixcmapGetCount(cmap); 00636 if (n < cmap->nalloc) /* cmap is not full */ 00637 return ERROR_INT("cmap entry does not exist", procName, 1); 00638 } 00639 00640 pixRasterop(pix, 0, 0, pixGetWidth(pix), pixGetHeight(pix), 00641 PIX_SET, NULL, 0, 0); 00642 return 0; 00643 } 00644 00645 00646 /*! 00647 * pixSetAllArbitrary() 00648 * 00649 * Input: pix (all depths; use cmapped with caution) 00650 * val (value to set all pixels) 00651 * Return: 0 if OK; 1 on error 00652 * 00653 * Notes: 00654 * (1) For colormapped pix, be sure the value is the intended 00655 * one in the colormap. 00656 * (2) Caution: for colormapped pix, this sets each pixel to the 00657 * color at the index equal to val. Be sure that this index 00658 * exists in the colormap and that it is the intended one! 00659 */ 00660 l_int32 00661 pixSetAllArbitrary(PIX *pix, 00662 l_uint32 val) 00663 { 00664 l_int32 n, i, j, w, h, d, wpl, npix; 00665 l_uint32 maxval, wordval; 00666 l_uint32 *data, *line; 00667 PIXCMAP *cmap; 00668 00669 PROCNAME("pixSetAllArbitrary"); 00670 00671 if (!pix) 00672 return ERROR_INT("pix not defined", procName, 1); 00673 if ((cmap = pixGetColormap(pix)) != NULL) { 00674 n = pixcmapGetCount(cmap); 00675 if (val < 0) { 00676 L_WARNING("index not in colormap; using first color", procName); 00677 val = 0; 00678 } 00679 else if (val >= n) { 00680 L_WARNING("index not in colormap; using last color", procName); 00681 val = n - 1; 00682 } 00683 } 00684 00685 pixGetDimensions(pix, &w, &h, &d); 00686 if (d == 32) 00687 maxval = 0xffffffff; 00688 else 00689 maxval = (1 << d) - 1; 00690 if (val < 0) { 00691 L_WARNING("invalid pixel value; set to 0", procName); 00692 val = 0; 00693 } 00694 if (val > maxval) { 00695 L_WARNING_INT("invalid pixel val; set to maxval = %d", 00696 procName, maxval); 00697 val = maxval; 00698 } 00699 00700 /* Set up word to tile with */ 00701 wordval = 0; 00702 npix = 32 / d; /* number of pixels per 32 bit word */ 00703 for (j = 0; j < npix; j++) 00704 wordval |= (val << (j * d)); 00705 00706 wpl = pixGetWpl(pix); 00707 data = pixGetData(pix); 00708 for (i = 0; i < h; i++) { 00709 line = data + i * wpl; 00710 for (j = 0; j < wpl; j++) { 00711 *(line + j) = wordval; 00712 } 00713 } 00714 00715 return 0; 00716 } 00717 00718 00719 /*! 00720 * pixSetBlackOrWhite() 00721 * 00722 * Input: pixs (all depths; cmap ok) 00723 * op (L_SET_BLACK, L_SET_WHITE) 00724 * Return: 0 if OK; 1 on error 00725 * 00726 * Notes: 00727 * (1) Function for setting all pixels in an image to either black 00728 * or white. 00729 * (2) If pixs is colormapped, it adds black or white to the 00730 * colormap if it's not there and there is room. If the colormap 00731 * is full, it finds the closest color in intensity. 00732 * This index is written to all pixels. 00733 */ 00734 l_int32 00735 pixSetBlackOrWhite(PIX *pixs, 00736 l_int32 op) 00737 { 00738 l_int32 d, index; 00739 PIXCMAP *cmap; 00740 00741 PROCNAME("pixSetBlackOrWhite"); 00742 00743 if (!pixs) 00744 return ERROR_INT("pix not defined", procName, 1); 00745 if (op != L_SET_BLACK && op != L_SET_WHITE) 00746 return ERROR_INT("invalid op", procName, 1); 00747 00748 cmap = pixGetColormap(pixs); 00749 d = pixGetDepth(pixs); 00750 if (!cmap) { 00751 if ((d == 1 && op == L_SET_BLACK) || 00752 (d > 1 && op == L_SET_WHITE)) 00753 pixSetAll(pixs); 00754 else 00755 pixClearAll(pixs); 00756 } 00757 else { /* handle colormap */ 00758 if (op == L_SET_BLACK) 00759 pixcmapAddBlackOrWhite(cmap, 0, &index); 00760 else /* L_SET_WHITE */ 00761 pixcmapAddBlackOrWhite(cmap, 1, &index); 00762 pixSetAllArbitrary(pixs, index); 00763 } 00764 00765 return 0; 00766 } 00767 00768 00769 /*-------------------------------------------------------------* 00770 * Rectangular region clear/set/set-to-arbitrary-value * 00771 *-------------------------------------------------------------*/ 00772 /*! 00773 * pixClearInRect() 00774 * 00775 * Input: pix (all depths; can be cmapped) 00776 * box (in which all pixels will be cleared) 00777 * Return: 0 if OK, 1 on error 00778 * 00779 * Notes: 00780 * (1) Clears all data in rect to 0. For 1 bpp, this is white; 00781 * for grayscale or color, this is black. 00782 * (2) Caution: for colormapped pix, this sets the color to the first 00783 * one in the colormap. Be sure that this is the intended color! 00784 */ 00785 l_int32 00786 pixClearInRect(PIX *pix, 00787 BOX *box) 00788 { 00789 l_int32 x, y, w, h; 00790 00791 PROCNAME("pixClearInRect"); 00792 00793 if (!pix) 00794 return ERROR_INT("pix not defined", procName, 1); 00795 if (!box) 00796 return ERROR_INT("box not defined", procName, 1); 00797 00798 boxGetGeometry(box, &x, &y, &w, &h); 00799 pixRasterop(pix, x, y, w, h, PIX_CLR, NULL, 0, 0); 00800 return 0; 00801 } 00802 00803 00804 /*! 00805 * pixSetInRect() 00806 * 00807 * Input: pix (all depths, can be cmapped) 00808 * box (in which all pixels will be set) 00809 * Return: 0 if OK, 1 on error 00810 * 00811 * Notes: 00812 * (1) Sets all data in rect to 1. For 1 bpp, this is black; 00813 * for grayscale or color, this is white. 00814 * (2) Caution: for colormapped pix, this sets the pixel value to the 00815 * maximum value supported by the colormap: 2^d - 1. However, this 00816 * color may not be defined, because the colormap may not be full. 00817 */ 00818 l_int32 00819 pixSetInRect(PIX *pix, 00820 BOX *box) 00821 { 00822 l_int32 n, x, y, w, h; 00823 PIXCMAP *cmap; 00824 00825 PROCNAME("pixSetInRect"); 00826 00827 if (!pix) 00828 return ERROR_INT("pix not defined", procName, 1); 00829 if (!box) 00830 return ERROR_INT("box not defined", procName, 1); 00831 if ((cmap = pixGetColormap(pix)) != NULL) { 00832 n = pixcmapGetCount(cmap); 00833 if (n < cmap->nalloc) /* cmap is not full */ 00834 return ERROR_INT("cmap entry does not exist", procName, 1); 00835 } 00836 00837 boxGetGeometry(box, &x, &y, &w, &h); 00838 pixRasterop(pix, x, y, w, h, PIX_SET, NULL, 0, 0); 00839 return 0; 00840 } 00841 00842 00843 /*! 00844 * pixSetInRectArbitrary() 00845 * 00846 * Input: pix (all depths; can be cmapped) 00847 * box (in which all pixels will be set to val) 00848 * val (value to set all pixels) 00849 * Return: 0 if OK; 1 on error 00850 * 00851 * Notes: 00852 * (1) For colormapped pix, be sure the value is the intended 00853 * one in the colormap. 00854 * (2) Caution: for colormapped pix, this sets each pixel in the 00855 * rect to the color at the index equal to val. Be sure that 00856 * this index exists in the colormap and that it is the intended one! 00857 */ 00858 l_int32 00859 pixSetInRectArbitrary(PIX *pix, 00860 BOX *box, 00861 l_uint32 val) 00862 { 00863 l_int32 n, x, y, xstart, xend, ystart, yend, bw, bh, w, h, d, wpl, maxval; 00864 l_uint32 *data, *line; 00865 BOX *boxc; 00866 PIXCMAP *cmap; 00867 00868 PROCNAME("pixSetInRectArbitrary"); 00869 00870 if (!pix) 00871 return ERROR_INT("pix not defined", procName, 1); 00872 if (!box) 00873 return ERROR_INT("box not defined", procName, 1); 00874 pixGetDimensions(pix, &w, &h, &d); 00875 if (d != 1 && d != 2 && d != 4 && d !=8 && d != 16 && d != 32) 00876 return ERROR_INT("depth must be in {1,2,4,8,16,32} bpp", procName, 1); 00877 if ((cmap = pixGetColormap(pix)) != NULL) { 00878 n = pixcmapGetCount(cmap); 00879 if (val < 0) { 00880 L_WARNING("index not in colormap; using first color", procName); 00881 val = 0; 00882 } 00883 else if (val >= n) { 00884 L_WARNING("index not in colormap; using last color", procName); 00885 val = n - 1; 00886 } 00887 } 00888 00889 if (d == 32) 00890 maxval = 0xffffffff; 00891 else 00892 maxval = (1 << d) - 1; 00893 if (val < 0) { 00894 L_WARNING("invalid pixel value; set to 0", procName); 00895 val = 0; 00896 } 00897 if (val > maxval) { 00898 L_WARNING_INT("invalid pixel val; set to maxval = %d", 00899 procName, maxval); 00900 val = maxval; 00901 } 00902 00903 /* Handle the simple cases: the min and max values */ 00904 if (val == 0) { 00905 pixClearInRect(pix, box); 00906 return 0; 00907 } 00908 if (d == 1 || 00909 (d == 2 && val == 3) || 00910 (d == 4 && val == 0xf) || 00911 (d == 8 && val == 0xff) || 00912 (d == 16 && val == 0xffff) || 00913 (d == 32 && ((val ^ 0xffffff00) >> 8 == 0))) { 00914 pixSetInRect(pix, box); 00915 return 0; 00916 } 00917 00918 /* Find the overlap of box with the input pix */ 00919 if ((boxc = boxClipToRectangle(box, w, h)) == NULL) 00920 return ERROR_INT("no overlap of box with image", procName, 1); 00921 boxGetGeometry(boxc, &xstart, &ystart, &bw, &bh); 00922 xend = xstart + bw - 1; 00923 yend = ystart + bh - 1; 00924 boxDestroy(&boxc); 00925 00926 wpl = pixGetWpl(pix); 00927 data = pixGetData(pix); 00928 for (y = ystart; y <= yend; y++) { 00929 line = data + y * wpl; 00930 for (x = xstart; x <= xend; x++) { 00931 switch(d) 00932 { 00933 case 2: 00934 SET_DATA_DIBIT(line, x, val); 00935 break; 00936 case 4: 00937 SET_DATA_QBIT(line, x, val); 00938 break; 00939 case 8: 00940 SET_DATA_BYTE(line, x, val); 00941 break; 00942 case 16: 00943 SET_DATA_TWO_BYTES(line, x, val); 00944 break; 00945 case 32: 00946 line[x] = val; 00947 break; 00948 default: 00949 return ERROR_INT("depth not 2|4|8|16|32 bpp", procName, 1); 00950 } 00951 } 00952 } 00953 00954 return 0; 00955 } 00956 00957 00958 /*! 00959 * pixBlendInRect() 00960 * 00961 * Input: pixs (32 bpp rgb) 00962 * box (in which all pixels will be blended) 00963 * val (blend value; 0xrrggbb00) 00964 * fract (fraction of color to be blended with each pixel in pixs) 00965 * Return: 0 if OK; 1 on error 00966 * 00967 * Notes: 00968 * (1) This is an in-place function. It blends the input color @val 00969 * with the pixels in pixs in the specified rectangle. 00970 */ 00971 l_int32 00972 pixBlendInRect(PIX *pixs, 00973 BOX *box, 00974 l_uint32 val, 00975 l_float32 fract) 00976 { 00977 l_int32 i, j, bx, by, bw, bh, w, h, wpls; 00978 l_int32 prval, pgval, pbval, rval, gval, bval; 00979 l_uint32 val32; 00980 l_uint32 *datas, *lines; 00981 00982 PROCNAME("pixBlendInRect"); 00983 00984 if (!pixs || pixGetDepth(pixs) != 32) 00985 return ERROR_INT("pixs not defined or not 32 bpp", procName, 1); 00986 if (!box) 00987 return ERROR_INT("box not defined", procName, 1); 00988 00989 boxGetGeometry(box, &bx, &by, &bw, &bh); 00990 pixGetDimensions(pixs, &w, &h, NULL); 00991 datas = pixGetData(pixs); 00992 wpls = pixGetWpl(pixs); 00993 extractRGBValues(val, &rval, &gval, &bval); 00994 for (i = 0; i < bh; i++) { /* scan over box */ 00995 if (by + i < 0 || by + i >= h) continue; 00996 lines = datas + (by + i) * wpls; 00997 for (j = 0; j < bw; j++) { 00998 if (bx + j < 0 || bx + j >= w) continue; 00999 val32 = *(lines + bx + j); 01000 extractRGBValues(val32, &prval, &pgval, &pbval); 01001 prval = (l_int32)((1. - fract) * prval + fract * rval); 01002 pgval = (l_int32)((1. - fract) * pgval + fract * gval); 01003 pbval = (l_int32)((1. - fract) * pbval + fract * bval); 01004 composeRGBPixel(prval, pgval, pbval, &val32); 01005 *(lines + bx + j) = val32; 01006 } 01007 } 01008 01009 return 0; 01010 } 01011 01012 01013 /*-------------------------------------------------------------* 01014 * Set pad bits * 01015 *-------------------------------------------------------------*/ 01016 /*! 01017 * pixSetPadBits() 01018 * 01019 * Input: pix (1, 2, 4, 8, 16, 32 bpp) 01020 * val (0 or 1) 01021 * Return: 0 if OK; 1 on error 01022 * 01023 * Notes: 01024 * (1) The pad bits are the bits that expand each scanline to a 01025 * multiple of 32 bits. They are usually not used in 01026 * image processing operations. When boundary conditions 01027 * are important, as in seedfill, they must be set properly. 01028 * (2) This sets the value of the pad bits (if any) in the last 01029 * 32-bit word in each scanline. 01030 * (3) For 32 bpp pix, there are no pad bits, so this is a no-op. 01031 */ 01032 l_int32 01033 pixSetPadBits(PIX *pix, 01034 l_int32 val) 01035 { 01036 l_int32 i, w, h, d, wpl, endbits, fullwords; 01037 l_uint32 mask; 01038 l_uint32 *data, *pword; 01039 01040 PROCNAME("pixSetPadBits"); 01041 01042 if (!pix) 01043 return ERROR_INT("pix not defined", procName, 1); 01044 01045 pixGetDimensions(pix, &w, &h, &d); 01046 if (d == 32) /* no padding exists for 32 bpp */ 01047 return 0; 01048 01049 data = pixGetData(pix); 01050 wpl = pixGetWpl(pix); 01051 endbits = 32 - ((w * d) % 32); 01052 if (endbits == 32) /* no partial word */ 01053 return 0; 01054 fullwords = w * d / 32; 01055 01056 mask = rmask32[endbits]; 01057 if (val == 0) 01058 mask = ~mask; 01059 01060 for (i = 0; i < h; i++) { 01061 pword = data + i * wpl + fullwords; 01062 if (val == 0) /* clear */ 01063 *pword = *pword & mask; 01064 else /* set */ 01065 *pword = *pword | mask; 01066 } 01067 01068 return 0; 01069 } 01070 01071 01072 /*! 01073 * pixSetPadBitsBand() 01074 * 01075 * Input: pix (1, 2, 4, 8, 16, 32 bpp) 01076 * by (starting y value of band) 01077 * bh (height of band) 01078 * val (0 or 1) 01079 * Return: 0 if OK; 1 on error 01080 * 01081 * Notes: 01082 * (1) The pad bits are the bits that expand each scanline to a 01083 * multiple of 32 bits. They are usually not used in 01084 * image processing operations. When boundary conditions 01085 * are important, as in seedfill, they must be set properly. 01086 * (2) This sets the value of the pad bits (if any) in the last 01087 * 32-bit word in each scanline, within the specified 01088 * band of raster lines. 01089 * (3) For 32 bpp pix, there are no pad bits, so this is a no-op. 01090 */ 01091 l_int32 01092 pixSetPadBitsBand(PIX *pix, 01093 l_int32 by, 01094 l_int32 bh, 01095 l_int32 val) 01096 { 01097 l_int32 i, w, h, d, wpl, endbits, fullwords; 01098 l_uint32 mask; 01099 l_uint32 *data, *pword; 01100 01101 PROCNAME("pixSetPadBitsBand"); 01102 01103 if (!pix) 01104 return ERROR_INT("pix not defined", procName, 1); 01105 01106 pixGetDimensions(pix, &w, &h, &d); 01107 if (d == 32) /* no padding exists for 32 bpp */ 01108 return 0; 01109 01110 if (by < 0) 01111 by = 0; 01112 if (by >= h) 01113 return ERROR_INT("start y not in image", procName, 1); 01114 if (by + bh > h) 01115 bh = h - by; 01116 01117 data = pixGetData(pix); 01118 wpl = pixGetWpl(pix); 01119 endbits = 32 - ((w * d) % 32); 01120 if (endbits == 32) /* no partial word */ 01121 return 0; 01122 fullwords = w * d / 32; 01123 01124 mask = rmask32[endbits]; 01125 if (val == 0) 01126 mask = ~mask; 01127 01128 for (i = by; i < by + bh; i++) { 01129 pword = data + i * wpl + fullwords; 01130 if (val == 0) /* clear */ 01131 *pword = *pword & mask; 01132 else /* set */ 01133 *pword = *pword | mask; 01134 } 01135 01136 return 0; 01137 } 01138 01139 01140 /*-------------------------------------------------------------* 01141 * Set border pixels * 01142 *-------------------------------------------------------------*/ 01143 /*! 01144 * pixSetOrClearBorder() 01145 * 01146 * Input: pixs (all depths) 01147 * left, right, top, bot (amount to set or clear) 01148 * operation (PIX_SET or PIX_CLR) 01149 * Return: 0 if OK; 1 on error 01150 * 01151 * Notes: 01152 * (1) The border region is defined to be the region in the 01153 * image within a specific distance of each edge. Here, we 01154 * allow the pixels within a specified distance of each 01155 * edge to be set independently. This either sets or 01156 * clears all pixels in the border region. 01157 * (2) For binary images, use PIX_SET for black and PIX_CLR for white. 01158 * (3) For grayscale or color images, use PIX_SET for white 01159 * and PIX_CLR for black. 01160 */ 01161 l_int32 01162 pixSetOrClearBorder(PIX *pixs, 01163 l_int32 left, 01164 l_int32 right, 01165 l_int32 top, 01166 l_int32 bot, 01167 l_int32 op) 01168 { 01169 l_int32 w, h; 01170 01171 PROCNAME("pixSetOrClearBorder"); 01172 01173 if (!pixs) 01174 return ERROR_INT("pixs not defined", procName, 1); 01175 if (op != PIX_SET && op != PIX_CLR) 01176 return ERROR_INT("op must be PIX_SET or PIX_CLR", procName, 1); 01177 01178 pixGetDimensions(pixs, &w, &h, NULL); 01179 pixRasterop(pixs, 0, 0, left, h, op, NULL, 0, 0); 01180 pixRasterop(pixs, w - right, 0, right, h, op, NULL, 0, 0); 01181 pixRasterop(pixs, 0, 0, w, top, op, NULL, 0, 0); 01182 pixRasterop(pixs, 0, h - bot, w, bot, op, NULL, 0, 0); 01183 01184 return 0; 01185 } 01186 01187 01188 /*! 01189 * pixSetBorderVal() 01190 * 01191 * Input: pixs (8, 16 or 32 bpp) 01192 * left, right, top, bot (amount to set) 01193 * val (value to set at each border pixel) 01194 * Return: 0 if OK; 1 on error 01195 * 01196 * Notes: 01197 * (1) The border region is defined to be the region in the 01198 * image within a specific distance of each edge. Here, we 01199 * allow the pixels within a specified distance of each 01200 * edge to be set independently. This sets the pixels 01201 * in the border region to the given input value. 01202 * (2) For efficiency, use pixSetOrClearBorder() if 01203 * you're setting the border to either black or white. 01204 * (3) If d != 32, the input value should be masked off 01205 * to the appropriate number of least significant bits. 01206 * (4) The code is easily generalized for 2 or 4 bpp. 01207 */ 01208 l_int32 01209 pixSetBorderVal(PIX *pixs, 01210 l_int32 left, 01211 l_int32 right, 01212 l_int32 top, 01213 l_int32 bot, 01214 l_uint32 val) 01215 { 01216 l_int32 w, h, d, wpls, i, j, bstart, rstart; 01217 l_uint32 *datas, *lines; 01218 01219 PROCNAME("pixSetBorderVal"); 01220 01221 if (!pixs) 01222 return ERROR_INT("pixs not defined", procName, 1); 01223 pixGetDimensions(pixs, &w, &h, &d); 01224 if (d != 8 && d != 16 && d != 32) 01225 return ERROR_INT("depth must be 8, 16 or 32 bpp", procName, 1); 01226 01227 datas = pixGetData(pixs); 01228 wpls = pixGetWpl(pixs); 01229 if (d == 8) { 01230 val &= 0xff; 01231 for (i = 0; i < top; i++) { 01232 lines = datas + i * wpls; 01233 for (j = 0; j < w; j++) 01234 SET_DATA_BYTE(lines, j, val); 01235 } 01236 rstart = w - right; 01237 bstart = h - bot; 01238 for (i = top; i < bstart; i++) { 01239 lines = datas + i * wpls; 01240 for (j = 0; j < left; j++) 01241 SET_DATA_BYTE(lines, j, val); 01242 for (j = rstart; j < w; j++) 01243 SET_DATA_BYTE(lines, j, val); 01244 } 01245 for (i = bstart; i < h; i++) { 01246 lines = datas + i * wpls; 01247 for (j = 0; j < w; j++) 01248 SET_DATA_BYTE(lines, j, val); 01249 } 01250 } 01251 else if (d == 16) { 01252 val &= 0xffff; 01253 for (i = 0; i < top; i++) { 01254 lines = datas + i * wpls; 01255 for (j = 0; j < w; j++) 01256 SET_DATA_TWO_BYTES(lines, j, val); 01257 } 01258 rstart = w - right; 01259 bstart = h - bot; 01260 for (i = top; i < bstart; i++) { 01261 lines = datas + i * wpls; 01262 for (j = 0; j < left; j++) 01263 SET_DATA_TWO_BYTES(lines, j, val); 01264 for (j = rstart; j < w; j++) 01265 SET_DATA_TWO_BYTES(lines, j, val); 01266 } 01267 for (i = bstart; i < h; i++) { 01268 lines = datas + i * wpls; 01269 for (j = 0; j < w; j++) 01270 SET_DATA_TWO_BYTES(lines, j, val); 01271 } 01272 } 01273 else { /* d == 32 */ 01274 for (i = 0; i < top; i++) { 01275 lines = datas + i * wpls; 01276 for (j = 0; j < w; j++) 01277 *(lines + j) = val; 01278 } 01279 rstart = w - right; 01280 bstart = h - bot; 01281 for (i = top; i < bstart; i++) { 01282 lines = datas + i * wpls; 01283 for (j = 0; j < left; j++) 01284 *(lines + j) = val; 01285 for (j = rstart; j < w; j++) 01286 *(lines + j) = val; 01287 } 01288 for (i = bstart; i < h; i++) { 01289 lines = datas + i * wpls; 01290 for (j = 0; j < w; j++) 01291 *(lines + j) = val; 01292 } 01293 } 01294 01295 return 0; 01296 } 01297 01298 01299 /*! 01300 * pixSetBorderRingVal() 01301 * 01302 * Input: pixs (any depth; cmap OK) 01303 * dist (distance from outside; must be > 0; first ring is 1) 01304 * val (value to set at each border pixel) 01305 * Return: 0 if OK; 1 on error 01306 * 01307 * Notes: 01308 * (1) The rings are single-pixel-wide rectangular sets of 01309 * pixels at a given distance from the edge of the pix. 01310 * This sets all pixels in a given ring to a value. 01311 */ 01312 l_int32 01313 pixSetBorderRingVal(PIX *pixs, 01314 l_int32 dist, 01315 l_uint32 val) 01316 { 01317 l_int32 w, h, d, i, j, xend, yend; 01318 01319 PROCNAME("pixSetBorderRingVal"); 01320 01321 if (!pixs) 01322 return ERROR_INT("pixs not defined", procName, 1); 01323 if (dist < 1) 01324 return ERROR_INT("dist must be > 0", procName, 1); 01325 pixGetDimensions(pixs, &w, &h, &d); 01326 if (w < 2 * dist + 1 || h < 2 * dist + 1) 01327 return ERROR_INT("ring doesn't exist", procName, 1); 01328 if (d < 32 && (val >= (1 << d))) 01329 return ERROR_INT("invalid pixel value", procName, 1); 01330 01331 xend = w - dist; 01332 yend = h - dist; 01333 for (j = dist - 1; j <= xend; j++) 01334 pixSetPixel(pixs, j, dist - 1, val); 01335 for (j = dist - 1; j <= xend; j++) 01336 pixSetPixel(pixs, j, yend, val); 01337 for (i = dist - 1; i <= yend; i++) 01338 pixSetPixel(pixs, dist - 1, i, val); 01339 for (i = dist - 1; i <= yend; i++) 01340 pixSetPixel(pixs, xend, i, val); 01341 01342 return 0; 01343 } 01344 01345 01346 /*! 01347 * pixSetMirroredBorder() 01348 * 01349 * Input: pixs (all depths; colormap ok) 01350 * left, right, top, bot (number of pixels to set) 01351 * Return: 0 if OK, 1 on error 01352 * 01353 * Notes: 01354 * (1) This applies what is effectively mirror boundary conditions 01355 * to a border region in the image. It is in-place. 01356 * (2) This is useful for setting pixels near the border to a 01357 * value representative of the near pixels to the interior. 01358 * (3) The general pixRasterop() is used for an in-place operation here 01359 * because there is no overlap between the src and dest rectangles. 01360 */ 01361 l_int32 01362 pixSetMirroredBorder(PIX *pixs, 01363 l_int32 left, 01364 l_int32 right, 01365 l_int32 top, 01366 l_int32 bot) 01367 { 01368 l_int32 i, j, w, h; 01369 01370 PROCNAME("pixSetMirroredBorder"); 01371 01372 if (!pixs) 01373 return ERROR_INT("pixs not defined", procName, 1); 01374 01375 pixGetDimensions(pixs, &w, &h, NULL); 01376 for (j = 0; j < left; j++) 01377 pixRasterop(pixs, left - 1 - j, top, 1, h - top - bot, PIX_SRC, 01378 pixs, left + j, top); 01379 for (j = 0; j < right; j++) 01380 pixRasterop(pixs, w - right + j, top, 1, h - top - bot, PIX_SRC, 01381 pixs, w - right - 1 - j, top); 01382 for (i = 0; i < top; i++) 01383 pixRasterop(pixs, 0, top - 1 - i, w, 1, PIX_SRC, 01384 pixs, 0, top + i); 01385 for (i = 0; i < bot; i++) 01386 pixRasterop(pixs, 0, h - bot + i, w, 1, PIX_SRC, 01387 pixs, 0, h - bot - 1 - i); 01388 01389 return 0; 01390 } 01391 01392 01393 /*! 01394 * pixCopyBorder() 01395 * 01396 * Input: pixd (all depths; colormap ok; can be NULL) 01397 * pixs (same depth and size as pixd) 01398 * left, right, top, bot (number of pixels to copy) 01399 * Return: pixd, or null on error if pixd is not defined 01400 * 01401 * Notes: 01402 * (1) pixd can be null, but otherwise it must be the same size 01403 * and depth as pixs. Always returns pixd. 01404 * (1) This is useful in situations where by setting a few border 01405 * pixels we can avoid having to copy all pixels in pixs into 01406 * pixd as an initialization step for some operation. 01407 */ 01408 PIX * 01409 pixCopyBorder(PIX *pixd, 01410 PIX *pixs, 01411 l_int32 left, 01412 l_int32 right, 01413 l_int32 top, 01414 l_int32 bot) 01415 { 01416 l_int32 w, h; 01417 01418 PROCNAME("pixCopyBorder"); 01419 01420 if (!pixs) 01421 return (PIX *)ERROR_PTR("pixs not defined", procName, pixd); 01422 01423 if (pixd) { 01424 if (pixd == pixs) { 01425 L_WARNING("same: nothing to do", procName); 01426 return pixd; 01427 } 01428 else if (!pixSizesEqual(pixs, pixd)) 01429 return (PIX *)ERROR_PTR("pixs and pixd sizes differ", 01430 procName, pixd); 01431 } 01432 else { 01433 if ((pixd = pixCreateTemplateNoInit(pixs)) == NULL) 01434 return (PIX *)ERROR_PTR("pixd not made", procName, pixd); 01435 } 01436 01437 pixGetDimensions(pixs, &w, &h, NULL); 01438 pixRasterop(pixd, 0, 0, left, h, PIX_SRC, pixs, 0, 0); 01439 pixRasterop(pixd, w - right, 0, right, h, PIX_SRC, pixs, w - right, 0); 01440 pixRasterop(pixd, 0, 0, w, top, PIX_SRC, pixs, 0, 0); 01441 pixRasterop(pixd, 0, h - bot, w, bot, PIX_SRC, pixs, 0, h - bot); 01442 01443 return pixd; 01444 } 01445 01446 01447 01448 /*-------------------------------------------------------------* 01449 * Add and remove border * 01450 *-------------------------------------------------------------*/ 01451 /*! 01452 * pixAddBorder() 01453 * 01454 * Input: pixs (all depths; colormap ok) 01455 * npix (number of pixels to be added to each side) 01456 * val (value of added border pixels) 01457 * Return: pixd (with the added exterior pixels), or null on error 01458 * 01459 * Notes: 01460 * (1) See pixAddBorderGeneral() for values of white & black pixels. 01461 */ 01462 PIX * 01463 pixAddBorder(PIX *pixs, 01464 l_int32 npix, 01465 l_uint32 val) 01466 { 01467 PROCNAME("pixAddBorder"); 01468 01469 if (!pixs) 01470 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01471 if (npix == 0) 01472 return pixClone(pixs); 01473 return pixAddBorderGeneral(pixs, npix, npix, npix, npix, val); 01474 } 01475 01476 01477 /*! 01478 * pixAddBlackBorder() 01479 * 01480 * Input: pixs (all depths; colormap ok) 01481 * npix (number of pixels to be added to each side) 01482 * Return: pixd (with the added exterior pixels), or null on error 01483 */ 01484 PIX * 01485 pixAddBlackBorder(PIX *pixs, 01486 l_int32 npix) 01487 { 01488 l_int32 d, val; 01489 PIXCMAP *cmap; 01490 01491 PROCNAME("pixAddBlackBorder"); 01492 01493 if (!pixs) 01494 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01495 if (npix == 0) 01496 return pixClone(pixs); 01497 01498 if ((cmap = pixGetColormap(pixs)) != NULL) 01499 pixcmapGetRankIntensity(cmap, 0.0, &val); 01500 else { 01501 d = pixGetDepth(pixs); 01502 val = (d == 1) ? 1 : 0; 01503 } 01504 return pixAddBorderGeneral(pixs, npix, npix, npix, npix, val); 01505 } 01506 01507 01508 /*! 01509 * pixAddBorderGeneral() 01510 * 01511 * Input: pixs (all depths; colormap ok) 01512 * left, right, top, bot (number of pixels added) 01513 * val (value of added border pixels) 01514 * Return: pixd (with the added exterior pixels), or null on error 01515 * 01516 * Notes: 01517 * (1) For binary images: 01518 * white: val = 0 01519 * black: val = 1 01520 * For grayscale images: 01521 * white: val = 2 ** d - 1 01522 * black: val = 0 01523 * For rgb color images: 01524 * white: val = 0xffffff00 01525 * black: val = 0 01526 * For colormapped images, use 'index' found this way: 01527 * white: pixcmapGetRankIntensity(cmap, 1.0, &index); 01528 * black: pixcmapGetRankIntensity(cmap, 0.0, &index); 01529 */ 01530 PIX * 01531 pixAddBorderGeneral(PIX *pixs, 01532 l_int32 left, 01533 l_int32 right, 01534 l_int32 top, 01535 l_int32 bot, 01536 l_uint32 val) 01537 { 01538 l_int32 ws, hs, wd, hd, d, op; 01539 PIX *pixd; 01540 01541 PROCNAME("pixAddBorderGeneral"); 01542 01543 if (!pixs) 01544 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01545 if (left < 0 || right < 0 || top < 0 || bot < 0) 01546 return (PIX *)ERROR_PTR("negative border added!", procName, NULL); 01547 01548 pixGetDimensions(pixs, &ws, &hs, &d); 01549 wd = ws + left + right; 01550 hd = hs + top + bot; 01551 if ((pixd = pixCreateNoInit(wd, hd, d)) == NULL) 01552 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01553 pixCopyResolution(pixd, pixs); 01554 pixCopyColormap(pixd, pixs); 01555 01556 /* Set the new border pixels */ 01557 op = UNDEF; 01558 if (val == 0) 01559 op = PIX_CLR; 01560 else if ((d == 1 && val == 1) || (d == 2 && val == 3) || 01561 (d == 4 && val == 0xf) || (d == 8 && val == 0xff) || 01562 (d == 16 && val == 0xffff) || (d == 32 && (val >> 8) == 0xffffff)) 01563 op = PIX_SET; 01564 if (op == UNDEF) 01565 pixSetAllArbitrary(pixd, val); /* a little extra writing ! */ 01566 else { 01567 pixRasterop(pixd, 0, 0, left, hd, op, NULL, 0, 0); 01568 pixRasterop(pixd, wd - right, 0, right, hd, op, NULL, 0, 0); 01569 pixRasterop(pixd, 0, 0, wd, top, op, NULL, 0, 0); 01570 pixRasterop(pixd, 0, hd - bot, wd, bot, op, NULL, 0, 0); 01571 } 01572 01573 /* Copy pixs into the interior */ 01574 pixRasterop(pixd, left, top, ws, hs, PIX_SRC, pixs, 0, 0); 01575 return pixd; 01576 } 01577 01578 01579 /*! 01580 * pixRemoveBorder() 01581 * 01582 * Input: pixs (all depths; colormap ok) 01583 * npix (number to be removed from each of the 4 sides) 01584 * Return: pixd (with pixels removed around border), or null on error 01585 */ 01586 PIX * 01587 pixRemoveBorder(PIX *pixs, 01588 l_int32 npix) 01589 { 01590 PROCNAME("pixRemoveBorder"); 01591 01592 if (!pixs) 01593 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01594 if (npix == 0) 01595 return pixClone(pixs); 01596 return pixRemoveBorderGeneral(pixs, npix, npix, npix, npix); 01597 } 01598 01599 01600 /*! 01601 * pixRemoveBorderGeneral() 01602 * 01603 * Input: pixs (all depths; colormap ok) 01604 * left, right, top, bot (number of pixels added) 01605 * Return: pixd (with pixels removed around border), or null on error 01606 */ 01607 PIX * 01608 pixRemoveBorderGeneral(PIX *pixs, 01609 l_int32 left, 01610 l_int32 right, 01611 l_int32 top, 01612 l_int32 bot) 01613 { 01614 l_int32 ws, hs, wd, hd, d; 01615 PIX *pixd; 01616 01617 PROCNAME("pixRemoveBorderGeneral"); 01618 01619 if (!pixs) 01620 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01621 if (left < 0 || right < 0 || top < 0 || bot < 0) 01622 return (PIX *)ERROR_PTR("negative border removed!", procName, NULL); 01623 01624 pixGetDimensions(pixs, &ws, &hs, &d); 01625 wd = ws - left - right; 01626 hd = hs - top - bot; 01627 if (wd <= 0) 01628 return (PIX *)ERROR_PTR("width must be > 0", procName, NULL); 01629 if (hd <= 0) 01630 return (PIX *)ERROR_PTR("height must be > 0", procName, NULL); 01631 if ((pixd = pixCreateNoInit(wd, hd, d)) == NULL) 01632 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01633 pixCopyResolution(pixd, pixs); 01634 pixCopyColormap(pixd, pixs); 01635 01636 pixRasterop(pixd, 0, 0, wd, hd, PIX_SRC, pixs, left, top); 01637 return pixd; 01638 } 01639 01640 01641 /*! 01642 * pixAddMirroredBorder() 01643 * 01644 * Input: pixs (all depths; colormap ok) 01645 * left, right, top, bot (number of pixels added) 01646 * Return: pixd, or null on error 01647 * 01648 * Notes: 01649 * (1) This applies what is effectively mirror boundary conditions. 01650 * For the added border pixels in pixd, the pixels in pixs 01651 * near the border are mirror-copied into the border region. 01652 * (2) This is useful for avoiding special operations near 01653 * boundaries when doing image processing operations 01654 * such as rank filters and convolution. In use, one first 01655 * adds mirrored pixels to each side of the image. The number 01656 * of pixels added on each side is half the filter dimension. 01657 * Then the image processing operations proceed over a 01658 * region equal to the size of the original image, and 01659 * write directly into a dest pix of the same size as pixs. 01660 * (3) The general pixRasterop() is used for an in-place operation here 01661 * because there is no overlap between the src and dest rectangles. 01662 */ 01663 PIX * 01664 pixAddMirroredBorder(PIX *pixs, 01665 l_int32 left, 01666 l_int32 right, 01667 l_int32 top, 01668 l_int32 bot) 01669 { 01670 l_int32 i, j, w, h; 01671 PIX *pixd; 01672 01673 PROCNAME("pixAddMirroredBorder"); 01674 01675 if (!pixs) 01676 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01677 pixGetDimensions(pixs, &w, &h, NULL); 01678 if (left > w || right > w || top > h || bot > h) 01679 return (PIX *)ERROR_PTR("border too large", procName, NULL); 01680 01681 /* Set pixels on left, right, top and bottom, in that order */ 01682 pixd = pixAddBorderGeneral(pixs, left, right, top, bot, 0); 01683 for (j = 0; j < left; j++) 01684 pixRasterop(pixd, left - 1 - j, top, 1, h, PIX_SRC, 01685 pixd, left + j, top); 01686 for (j = 0; j < right; j++) 01687 pixRasterop(pixd, left + w + j, top, 1, h, PIX_SRC, 01688 pixd, left + w - 1 - j, top); 01689 for (i = 0; i < top; i++) 01690 pixRasterop(pixd, 0, top - 1 - i, left + w + right, 1, PIX_SRC, 01691 pixd, 0, top + i); 01692 for (i = 0; i < bot; i++) 01693 pixRasterop(pixd, 0, top + h + i, left + w + right, 1, PIX_SRC, 01694 pixd, 0, top + h - 1 - i); 01695 01696 return pixd; 01697 } 01698 01699 /*! 01700 * pixAddRepeatedBorder() 01701 * 01702 * Input: pixs (all depths; colormap ok) 01703 * left, right, top, bot (number of pixels added) 01704 * Return: pixd, or null on error 01705 * 01706 * Notes: 01707 * (1) This applies a repeated border, as if the central part of 01708 * the image is tiled over the plane. So, for example, the 01709 * pixels in the left border come from the right side of the image. 01710 * (2) The general pixRasterop() is used for an in-place operation here 01711 * because there is no overlap between the src and dest rectangles. 01712 */ 01713 PIX * 01714 pixAddRepeatedBorder(PIX *pixs, 01715 l_int32 left, 01716 l_int32 right, 01717 l_int32 top, 01718 l_int32 bot) 01719 { 01720 l_int32 w, h; 01721 PIX *pixd; 01722 01723 PROCNAME("pixAddRepeatedBorder"); 01724 01725 if (!pixs) 01726 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01727 pixGetDimensions(pixs, &w, &h, NULL); 01728 if (left > w || right > w || top > h || bot > h) 01729 return (PIX *)ERROR_PTR("border too large", procName, NULL); 01730 01731 pixd = pixAddBorderGeneral(pixs, left, right, top, bot, 0); 01732 01733 /* Set pixels on left, right, top and bottom, in that order */ 01734 pixRasterop(pixd, 0, top, left, h, PIX_SRC, pixd, w, top); 01735 pixRasterop(pixd, left + w, top, right, h, PIX_SRC, pixd, left, top); 01736 pixRasterop(pixd, 0, 0, left + w + right, top, PIX_SRC, pixd, 0, h); 01737 pixRasterop(pixd, 0, top + h, left + w + right, bot, PIX_SRC, pixd, 0, top); 01738 01739 return pixd; 01740 } 01741 01742 01743 /*! 01744 * pixAddMixedBorder() 01745 * 01746 * Input: pixs (all depths; colormap ok) 01747 * left, right, top, bot (number of pixels added) 01748 * Return: pixd, or null on error 01749 * 01750 * Notes: 01751 * (1) This applies mirrored boundary conditions horizontally 01752 * and repeated b.c. vertically. 01753 * (2) It is specifically used for avoiding special operations 01754 * near boundaries when convolving a hue-saturation histogram 01755 * with a given window size. The repeated b.c. are used 01756 * vertically for hue, and the mirrored b.c. are used 01757 * horizontally for saturation. The number of pixels added 01758 * on each side is approximately (but not quite) half the 01759 * filter dimension. The image processing operations can 01760 * then proceed over a region equal to the size of the original 01761 * image, and write directly into a dest pix of the same 01762 * size as pixs. 01763 * (3) The general pixRasterop() can be used for an in-place 01764 * operation here because there is no overlap between the 01765 * src and dest rectangles. 01766 */ 01767 PIX * 01768 pixAddMixedBorder(PIX *pixs, 01769 l_int32 left, 01770 l_int32 right, 01771 l_int32 top, 01772 l_int32 bot) 01773 { 01774 l_int32 j, w, h; 01775 PIX *pixd; 01776 01777 PROCNAME("pixAddMixedBorder"); 01778 01779 if (!pixs) 01780 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01781 pixGetDimensions(pixs, &w, &h, NULL); 01782 if (left > w || right > w || top > h || bot > h) 01783 return (PIX *)ERROR_PTR("border too large", procName, NULL); 01784 01785 /* Set mirrored pixels on left and right; 01786 * then set repeated pixels on top and bottom. */ 01787 pixd = pixAddBorderGeneral(pixs, left, right, top, bot, 0); 01788 for (j = 0; j < left; j++) 01789 pixRasterop(pixd, left - 1 - j, top, 1, h, PIX_SRC, 01790 pixd, left + j, top); 01791 for (j = 0; j < right; j++) 01792 pixRasterop(pixd, left + w + j, top, 1, h, PIX_SRC, 01793 pixd, left + w - 1 - j, top); 01794 pixRasterop(pixd, 0, 0, left + w + right, top, PIX_SRC, pixd, 0, h); 01795 pixRasterop(pixd, 0, top + h, left + w + right, bot, PIX_SRC, pixd, 0, top); 01796 01797 return pixd; 01798 } 01799 01800 01801 01802 /*-------------------------------------------------------------* 01803 * Color sample setting and extraction * 01804 *-------------------------------------------------------------*/ 01805 /*! 01806 * pixCreateRGBImage() 01807 * 01808 * Input: 8 bpp red pix 01809 * 8 bpp green pix 01810 * 8 bpp blue pix 01811 * Return: 32 bpp pix, interleaved with 4 samples/pixel, 01812 * or null on error 01813 * 01814 * Notes: 01815 * (1) the 4th byte, sometimes called the "alpha channel", 01816 * and which is often used for blending between different 01817 * images, is left with 0 value. 01818 * (2) see Note (4) in pix.h for details on storage of 01819 * 8-bit samples within each 32-bit word. 01820 * (3) This implementation, setting the r, g and b components 01821 * sequentially, is much faster than setting them in parallel 01822 * by constructing an RGB dest pixel and writing it to dest. 01823 * The reason is there are many more cache misses when reading 01824 * from 3 input images simultaneously. 01825 */ 01826 PIX * 01827 pixCreateRGBImage(PIX *pixr, 01828 PIX *pixg, 01829 PIX *pixb) 01830 { 01831 l_int32 wr, wg, wb, hr, hg, hb, dr, dg, db; 01832 PIX *pixd; 01833 01834 PROCNAME("pixCreateRGBImage"); 01835 01836 if (!pixr) 01837 return (PIX *)ERROR_PTR("pixr not defined", procName, NULL); 01838 if (!pixg) 01839 return (PIX *)ERROR_PTR("pixg not defined", procName, NULL); 01840 if (!pixb) 01841 return (PIX *)ERROR_PTR("pixb not defined", procName, NULL); 01842 pixGetDimensions(pixr, &wr, &hr, &dr); 01843 pixGetDimensions(pixg, &wg, &hg, &dg); 01844 pixGetDimensions(pixb, &wb, &hb, &db); 01845 if (dr != 8 || dg != 8 || db != 8) 01846 return (PIX *)ERROR_PTR("input pix not all 8 bpp", procName, NULL); 01847 if (wr != wg || wr != wb) 01848 return (PIX *)ERROR_PTR("widths not the same", procName, NULL); 01849 if (hr != hg || hr != hb) 01850 return (PIX *)ERROR_PTR("heights not the same", procName, NULL); 01851 01852 if ((pixd = pixCreate(wr, hr, 32)) == NULL) 01853 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01854 pixCopyResolution(pixd, pixr); 01855 pixSetRGBComponent(pixd, pixr, COLOR_RED); 01856 pixSetRGBComponent(pixd, pixg, COLOR_GREEN); 01857 pixSetRGBComponent(pixd, pixb, COLOR_BLUE); 01858 01859 return pixd; 01860 } 01861 01862 01863 /*! 01864 * pixGetRGBComponent() 01865 * 01866 * Input: pixs (32 bpp) 01867 * color (one of {COLOR_RED, COLOR_GREEN, COLOR_BLUE, 01868 * L_ALPHA_CHANNEL}) 01869 * Return: pixd, the selected 8 bpp component image of the 01870 * input 32 bpp image, or null on error 01871 * 01872 * Notes: 01873 * (1) The alpha channel (in the 4th byte of each RGB pixel) 01874 * is mostly ignored in leptonica. 01875 * (2) Three calls to this function generate the three 8 bpp component 01876 * images. This is much faster than generating the three 01877 * images in parallel, by extracting a src pixel and setting 01878 * the pixels of each component image from it. The reason is 01879 * there are many more cache misses when writing to three 01880 * output images simultaneously. 01881 */ 01882 PIX * 01883 pixGetRGBComponent(PIX *pixs, 01884 l_int32 color) 01885 { 01886 l_uint8 srcbyte; 01887 l_uint32 *lines, *lined; 01888 l_uint32 *datas, *datad; 01889 l_int32 i, j, w, h; 01890 l_int32 wpls, wpld; 01891 PIX *pixd; 01892 01893 PROCNAME("pixGetRGBComponent"); 01894 01895 if (!pixs) 01896 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 01897 if (pixGetDepth(pixs) != 32) 01898 return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL); 01899 if (color != COLOR_RED && color != COLOR_GREEN && 01900 color != COLOR_BLUE && color != L_ALPHA_CHANNEL) 01901 return (PIX *)ERROR_PTR("invalid color", procName, NULL); 01902 01903 pixGetDimensions(pixs, &w, &h, NULL); 01904 if ((pixd = pixCreate(w, h, 8)) == NULL) 01905 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 01906 pixCopyResolution(pixd, pixs); 01907 wpls = pixGetWpl(pixs); 01908 wpld = pixGetWpl(pixd); 01909 datas = pixGetData(pixs); 01910 datad = pixGetData(pixd); 01911 01912 for (i = 0; i < h; i++) { 01913 lines = datas + i * wpls; 01914 lined = datad + i * wpld; 01915 for (j = 0; j < w; j++) { 01916 srcbyte = GET_DATA_BYTE(lines + j, color); 01917 SET_DATA_BYTE(lined, j, srcbyte); 01918 } 01919 } 01920 01921 return pixd; 01922 } 01923 01924 01925 /*! 01926 * pixSetRGBComponent() 01927 * 01928 * Input: pixd (32 bpp) 01929 * pixs (8 bpp) 01930 * color (one of {COLOR_RED, COLOR_GREEN, COLOR_BLUE, 01931 * L_ALPHA_CHANNEL}) 01932 * Return: 0 if OK; 1 on error 01933 * 01934 * Notes: 01935 * (1) This places the 8 bpp pixel in pixs into the 01936 * specified color component (properly interleaved) in pixd. 01937 * (2) The alpha channel component mostly ignored in leptonica. 01938 */ 01939 l_int32 01940 pixSetRGBComponent(PIX *pixd, 01941 PIX *pixs, 01942 l_int32 color) 01943 { 01944 l_uint8 srcbyte; 01945 l_int32 i, j, w, h; 01946 l_int32 wpls, wpld; 01947 l_uint32 *lines, *lined; 01948 l_uint32 *datas, *datad; 01949 01950 PROCNAME("pixSetRGBComponent"); 01951 01952 if (!pixd) 01953 return ERROR_INT("pixd not defined", procName, 1); 01954 if (!pixs) 01955 return ERROR_INT("pixs not defined", procName, 1); 01956 01957 if (pixGetDepth(pixd) != 32) 01958 return ERROR_INT("pixd not 32 bpp", procName, 1); 01959 if (pixGetDepth(pixs) != 8) 01960 return ERROR_INT("pixs not 8 bpp", procName, 1); 01961 if (color != COLOR_RED && color != COLOR_GREEN && 01962 color != COLOR_BLUE && color != L_ALPHA_CHANNEL) 01963 return ERROR_INT("invalid color", procName, 1); 01964 pixGetDimensions(pixs, &w, &h, NULL); 01965 if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd)) 01966 return ERROR_INT("sizes not commensurate", procName, 1); 01967 01968 datas = pixGetData(pixs); 01969 datad = pixGetData(pixd); 01970 wpls = pixGetWpl(pixs); 01971 wpld = pixGetWpl(pixd); 01972 for (i = 0; i < h; i++) { 01973 lines = datas + i * wpls; 01974 lined = datad + i * wpld; 01975 for (j = 0; j < w; j++) { 01976 srcbyte = GET_DATA_BYTE(lines, j); 01977 SET_DATA_BYTE(lined + j, color, srcbyte); 01978 } 01979 } 01980 01981 return 0; 01982 } 01983 01984 01985 /*! 01986 * pixGetRGBComponentCmap() 01987 * 01988 * Input: pixs (colormapped) 01989 * color (one of {COLOR_RED, COLOR_GREEN, COLOR_BLUE}) 01990 * Return: pixd (the selected 8 bpp component image of the 01991 * input cmapped image), or null on error 01992 */ 01993 PIX * 01994 pixGetRGBComponentCmap(PIX *pixs, 01995 l_int32 color) 01996 { 01997 l_int32 i, j, w, h, val, index; 01998 l_int32 wplc, wpld; 01999 l_uint32 *linec, *lined; 02000 l_uint32 *datac, *datad; 02001 PIX *pixc, *pixd; 02002 PIXCMAP *cmap; 02003 RGBA_QUAD *cta; 02004 02005 PROCNAME("pixGetRGBComponentCmap"); 02006 02007 if (!pixs) 02008 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02009 if ((cmap = pixGetColormap(pixs)) == NULL) 02010 return (PIX *)ERROR_PTR("pixs not cmapped", procName, NULL); 02011 if (color != COLOR_RED && color != COLOR_GREEN && 02012 color != COLOR_BLUE) 02013 return (PIX *)ERROR_PTR("invalid color", procName, NULL); 02014 02015 /* If not 8 bpp, make a cmapped 8 bpp pix */ 02016 if (pixGetDepth(pixs) == 8) 02017 pixc = pixClone(pixs); 02018 else 02019 pixc = pixConvertTo8(pixs, TRUE); 02020 02021 pixGetDimensions(pixs, &w, &h, NULL); 02022 if ((pixd = pixCreateNoInit(w, h, 8)) == NULL) 02023 return (PIX *)ERROR_PTR("pixd not made", procName, NULL); 02024 pixCopyResolution(pixd, pixs); 02025 wplc = pixGetWpl(pixc); 02026 wpld = pixGetWpl(pixd); 02027 datac = pixGetData(pixc); 02028 datad = pixGetData(pixd); 02029 cta = (RGBA_QUAD *)cmap->array; 02030 02031 for (i = 0; i < h; i++) { 02032 linec = datac + i * wplc; 02033 lined = datad + i * wpld; 02034 if (color == COLOR_RED) { 02035 for (j = 0; j < w; j++) { 02036 index = GET_DATA_BYTE(linec, j); 02037 val = cta[index].red; 02038 SET_DATA_BYTE(lined, j, val); 02039 } 02040 } 02041 else if (color == COLOR_GREEN) { 02042 for (j = 0; j < w; j++) { 02043 index = GET_DATA_BYTE(linec, j); 02044 val = cta[index].green; 02045 SET_DATA_BYTE(lined, j, val); 02046 } 02047 } 02048 else if (color == COLOR_BLUE) { 02049 for (j = 0; j < w; j++) { 02050 index = GET_DATA_BYTE(linec, j); 02051 val = cta[index].green; 02052 SET_DATA_BYTE(lined, j, val); 02053 } 02054 } 02055 } 02056 02057 pixDestroy(&pixc); 02058 return pixd; 02059 } 02060 02061 02062 /*! 02063 * composeRGBPixel() 02064 * 02065 * Input: rval, gval, bval 02066 * &rgbpixel (<return> 32-bit pixel) 02067 * Return: 0 if OK; 1 on error 02068 * 02069 * Notes: 02070 * (1) A slower implementation uses macros: 02071 * SET_DATA_BYTE(ppixel, COLOR_RED, rval); 02072 * SET_DATA_BYTE(ppixel, COLOR_GREEN, gval); 02073 * SET_DATA_BYTE(ppixel, COLOR_BLUE, bval); 02074 */ 02075 l_int32 02076 composeRGBPixel(l_int32 rval, 02077 l_int32 gval, 02078 l_int32 bval, 02079 l_uint32 *ppixel) 02080 { 02081 PROCNAME("composeRGBPixel"); 02082 02083 if (!ppixel) 02084 return ERROR_INT("&pixel not defined", procName, 1); 02085 02086 *ppixel = (rval << L_RED_SHIFT) | (gval << L_GREEN_SHIFT) | 02087 (bval << L_BLUE_SHIFT); 02088 return 0; 02089 } 02090 02091 02092 /*! 02093 * extractRGBValues() 02094 * 02095 * Input: pixel (32 bit) 02096 * &rval (<optional return> red component) 02097 * &gval (<optional return> green component) 02098 * &bval (<optional return> blue component) 02099 * Return: void 02100 * 02101 * Notes: 02102 * (1) A slower implementation uses macros: 02103 * *prval = GET_DATA_BYTE(&pixel, COLOR_RED); 02104 * *pgval = GET_DATA_BYTE(&pixel, COLOR_GREEN); 02105 * *pbval = GET_DATA_BYTE(&pixel, COLOR_BLUE); 02106 */ 02107 void 02108 extractRGBValues(l_uint32 pixel, 02109 l_int32 *prval, 02110 l_int32 *pgval, 02111 l_int32 *pbval) 02112 { 02113 if (prval) *prval = (pixel >> L_RED_SHIFT) & 0xff; 02114 if (pgval) *pgval = (pixel >> L_GREEN_SHIFT) & 0xff; 02115 if (pbval) *pbval = (pixel >> L_BLUE_SHIFT) & 0xff; 02116 return; 02117 } 02118 02119 02120 /*! 02121 * extractMinMaxComponent() 02122 * 02123 * Input: pixel (32 bpp RGB) 02124 * type (L_CHOOSE_MIN or L_CHOOSE_MAX) 02125 * Return: componet (in range [0 ... 255], or null on error 02126 */ 02127 l_int32 02128 extractMinMaxComponent(l_uint32 pixel, 02129 l_int32 type) 02130 { 02131 l_int32 rval, gval, bval, val; 02132 02133 extractRGBValues(pixel, &rval, &gval, &bval); 02134 if (type == L_CHOOSE_MIN) { 02135 val = L_MIN(rval, gval); 02136 val = L_MIN(val, bval); 02137 } 02138 else { /* type == L_CHOOSE_MAX */ 02139 val = L_MAX(rval, gval); 02140 val = L_MAX(val, bval); 02141 } 02142 return val; 02143 } 02144 02145 02146 /*! 02147 * pixGetRGBLine() 02148 * 02149 * Input: pixs (32 bpp) 02150 * row 02151 * bufr (array of red samples; size w bytes) 02152 * bufg (array of green samples; size w bytes) 02153 * bufb (array of blue samples; size w bytes) 02154 * Return: 0 if OK; 1 on error 02155 * 02156 * Notes: 02157 * (1) This puts rgb components from the input line in pixs 02158 * into the given buffers. 02159 */ 02160 l_int32 02161 pixGetRGBLine(PIX *pixs, 02162 l_int32 row, 02163 l_uint8 *bufr, 02164 l_uint8 *bufg, 02165 l_uint8 *bufb) 02166 { 02167 l_uint32 *lines; 02168 l_int32 j, w, h; 02169 l_int32 wpls; 02170 02171 PROCNAME("pixGetRGBLine"); 02172 02173 if (!pixs) 02174 return ERROR_INT("pixs not defined", procName, 1); 02175 if (pixGetDepth(pixs) != 32) 02176 return ERROR_INT("pixs not 32 bpp", procName, 1); 02177 if (!bufr || !bufg || !bufb) 02178 return ERROR_INT("buffer not defined", procName, 1); 02179 02180 pixGetDimensions(pixs, &w, &h, NULL); 02181 if (row < 0 || row >= h) 02182 return ERROR_INT("row out of bounds", procName, 1); 02183 wpls = pixGetWpl(pixs); 02184 lines = pixGetData(pixs) + row * wpls; 02185 02186 for (j = 0; j < w; j++) { 02187 bufr[j] = GET_DATA_BYTE(lines + j, COLOR_RED); 02188 bufg[j] = GET_DATA_BYTE(lines + j, COLOR_GREEN); 02189 bufb[j] = GET_DATA_BYTE(lines + j, COLOR_BLUE); 02190 } 02191 02192 return 0; 02193 } 02194 02195 02196 /*-------------------------------------------------------------* 02197 * Pixel endian conversion * 02198 *-------------------------------------------------------------*/ 02199 /*! 02200 * pixEndianByteSwapNew() 02201 * 02202 * Input: pixs 02203 * Return: pixd, or null on error 02204 * 02205 * Notes: 02206 * (1) This is used to convert the data in a pix to a 02207 * serialized byte buffer in raster order, and, for RGB, 02208 * in order RGBA. This requires flipping bytes within 02209 * each 32-bit word for little-endian platforms, because the 02210 * words have a MSB-to-the-left rule, whereas byte raster-order 02211 * requires the left-most byte in each word to be byte 0. 02212 * For big-endians, no swap is necessary, so this returns a clone. 02213 * (2) Unlike pixEndianByteSwap(), which swaps the bytes in-place, 02214 * this returns a new pix (or a clone). We provide this 02215 * because often when serialization is done, the source 02216 * pix needs to be restored to canonical little-endian order, 02217 * and this requires a second byte swap. In such a situation, 02218 * it is twice as fast to make a new pix in big-endian order, 02219 * use it, and destroy it. 02220 */ 02221 PIX * 02222 pixEndianByteSwapNew(PIX *pixs) 02223 { 02224 l_uint32 *datas, *datad; 02225 l_int32 i, j, h, wpl; 02226 l_uint32 word; 02227 PIX *pixd; 02228 02229 PROCNAME("pixEndianByteSwapNew"); 02230 02231 #ifdef L_BIG_ENDIAN 02232 02233 return pixClone(pixs); 02234 02235 #else /* L_LITTLE_ENDIAN */ 02236 02237 if (!pixs) 02238 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02239 02240 datas = pixGetData(pixs); 02241 wpl = pixGetWpl(pixs); 02242 h = pixGetHeight(pixs); 02243 pixd = pixCreateTemplate(pixs); 02244 datad = pixGetData(pixd); 02245 for (i = 0; i < h; i++) { 02246 for (j = 0; j < wpl; j++, datas++, datad++) { 02247 word = *datas; 02248 *datad = (word >> 24) | 02249 ((word >> 8) & 0x0000ff00) | 02250 ((word << 8) & 0x00ff0000) | 02251 (word << 24); 02252 } 02253 } 02254 02255 return pixd; 02256 02257 #endif /* L_BIG_ENDIAN */ 02258 02259 } 02260 02261 02262 /*! 02263 * pixEndianByteSwap() 02264 * 02265 * Input: pixs 02266 * Return: 0 if OK, 1 on error 02267 * 02268 * Notes: 02269 * (1) This is used on little-endian platforms to swap 02270 * the bytes within a word; bytes 0 and 3 are swapped, 02271 * and bytes 1 and 2 are swapped. 02272 * (2) This is required for little-endians in situations 02273 * where we convert from a serialized byte order that is 02274 * in raster order, as one typically has in file formats, 02275 * to one with MSB-to-the-left in each 32-bit word, or v.v. 02276 * See pix.h for a description of the canonical format 02277 * (MSB-to-the left) that is used for both little-endian 02278 * and big-endian platforms. For big-endians, the 02279 * MSB-to-the-left word order has the bytes in raster 02280 * order when serialized, so no byte flipping is required. 02281 */ 02282 l_int32 02283 pixEndianByteSwap(PIX *pixs) 02284 { 02285 l_uint32 *data; 02286 l_int32 i, j, h, wpl; 02287 l_uint32 word; 02288 02289 PROCNAME("pixEndianByteSwap"); 02290 02291 #ifdef L_BIG_ENDIAN 02292 02293 return 0; 02294 02295 #else /* L_LITTLE_ENDIAN */ 02296 02297 if (!pixs) 02298 return ERROR_INT("pixs not defined", procName, 1); 02299 02300 data = pixGetData(pixs); 02301 wpl = pixGetWpl(pixs); 02302 h = pixGetHeight(pixs); 02303 for (i = 0; i < h; i++) { 02304 for (j = 0; j < wpl; j++, data++) { 02305 word = *data; 02306 *data = (word >> 24) | 02307 ((word >> 8) & 0x0000ff00) | 02308 ((word << 8) & 0x00ff0000) | 02309 (word << 24); 02310 } 02311 } 02312 02313 return 0; 02314 02315 #endif /* L_BIG_ENDIAN */ 02316 02317 } 02318 02319 02320 /*! 02321 * lineEndianByteSwap() 02322 * 02323 * Input datad (dest byte array data, reordered on little-endians) 02324 * datas (a src line of pix data) 02325 * wpl (number of 32 bit words in the line) 02326 * Return: 0 if OK, 1 on error 02327 * 02328 * Notes: 02329 * (1) This is used on little-endian platforms to swap 02330 * the bytes within each word in the line of image data. 02331 * Bytes 0 <==> 3 and 1 <==> 2 are swapped in the dest 02332 * byte array data8d, relative to the pix data in datas. 02333 * (2) The bytes represent 8 bit pixel values. They are swapped 02334 * for little endians so that when the dest array (char *)datad 02335 * is addressed by bytes, the pixels are chosen sequentially 02336 * from left to right in the image. 02337 */ 02338 l_int32 02339 lineEndianByteSwap(l_uint32 *datad, 02340 l_uint32 *datas, 02341 l_int32 wpl) 02342 { 02343 l_int32 j; 02344 l_uint32 word; 02345 02346 PROCNAME("lineEndianByteSwap"); 02347 02348 if (!datad || !datas) 02349 return ERROR_INT("datad and datas not both defined", procName, 1); 02350 02351 #ifdef L_BIG_ENDIAN 02352 02353 memcpy((char *)datad, (char *)datas, 4 * wpl); 02354 return 0; 02355 02356 #else /* L_LITTLE_ENDIAN */ 02357 02358 for (j = 0; j < wpl; j++, datas++, datad++) { 02359 word = *datas; 02360 *datad = (word >> 24) | 02361 ((word >> 8) & 0x0000ff00) | 02362 ((word << 8) & 0x00ff0000) | 02363 (word << 24); 02364 } 02365 return 0; 02366 02367 #endif /* L_BIG_ENDIAN */ 02368 02369 } 02370 02371 02372 /*! 02373 * pixEndianTwoByteSwapNew() 02374 * 02375 * Input: pixs 02376 * Return: 0 if OK, 1 on error 02377 * 02378 * Notes: 02379 * (1) This is used on little-endian platforms to swap the 02380 * 2-byte entities within a 32-bit word. 02381 * (2) This is equivalent to a full byte swap, as performed 02382 * by pixEndianByteSwap(), followed by byte swaps in 02383 * each of the 16-bit entities separately. 02384 * (3) Unlike pixEndianTwoByteSwap(), which swaps the shorts in-place, 02385 * this returns a new pix (or a clone). We provide this 02386 * to avoid having to swap twice in situations where the input 02387 * pix must be restored to canonical little-endian order. 02388 */ 02389 PIX * 02390 pixEndianTwoByteSwapNew(PIX *pixs) 02391 { 02392 l_uint32 *datas, *datad; 02393 l_int32 i, j, h, wpl; 02394 l_uint32 word; 02395 PIX *pixd; 02396 02397 PROCNAME("pixEndianTwoByteSwapNew"); 02398 02399 #ifdef L_BIG_ENDIAN 02400 02401 return pixClone(pixs); 02402 02403 #else /* L_LITTLE_ENDIAN */ 02404 02405 if (!pixs) 02406 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); 02407 02408 datas = pixGetData(pixs); 02409 wpl = pixGetWpl(pixs); 02410 h = pixGetHeight(pixs); 02411 pixd = pixCreateTemplate(pixs); 02412 datad = pixGetData(pixd); 02413 for (i = 0; i < h; i++) { 02414 for (j = 0; j < wpl; j++, datas++, datad++) { 02415 word = *datas; 02416 *datad = (word << 16) | (word >> 16); 02417 } 02418 } 02419 02420 return pixd; 02421 02422 #endif /* L_BIG_ENDIAN */ 02423 02424 } 02425 02426 02427 /*! 02428 * pixEndianTwoByteSwap() 02429 * 02430 * Input: pixs 02431 * Return: 0 if OK, 1 on error 02432 * 02433 * Notes: 02434 * (1) This is used on little-endian platforms to swap the 02435 * 2-byte entities within a 32-bit word. 02436 * (2) This is equivalent to a full byte swap, as performed 02437 * by pixEndianByteSwap(), followed by byte swaps in 02438 * each of the 16-bit entities separately. 02439 */ 02440 l_int32 02441 pixEndianTwoByteSwap(PIX *pixs) 02442 { 02443 l_uint32 *data; 02444 l_int32 i, j, h, wpl; 02445 l_uint32 word; 02446 02447 PROCNAME("pixEndianTwoByteSwap"); 02448 02449 #ifdef L_BIG_ENDIAN 02450 02451 return 0; 02452 02453 #else /* L_LITTLE_ENDIAN */ 02454 02455 if (!pixs) 02456 return ERROR_INT("pixs not defined", procName, 1); 02457 02458 data = pixGetData(pixs); 02459 wpl = pixGetWpl(pixs); 02460 h = pixGetHeight(pixs); 02461 for (i = 0; i < h; i++) { 02462 for (j = 0; j < wpl; j++, data++) { 02463 word = *data; 02464 *data = (word << 16) | (word >> 16); 02465 } 02466 } 02467 02468 return 0; 02469 02470 #endif /* L_BIG_ENDIAN */ 02471 02472 } 02473 02474 02475 /*-------------------------------------------------------------* 02476 * Extract raster data as binary string * 02477 *-------------------------------------------------------------*/ 02478 /*! 02479 * pixGetRasterData() 02480 * 02481 * Input: pixs (1, 8, 32 bpp) 02482 * &data (<return> raster data in memory) 02483 * &nbytes (<return> number of bytes in data string) 02484 * Return: 0 if OK, 1 on error 02485 * 02486 * Notes: 02487 * (1) This returns the raster data as a byte string, padded to the 02488 * byte. For 1 bpp, the first pixel is the MSbit in the first byte. 02489 * For rgb, the bytes are in (rgb) order. This is the format 02490 * required for flate encoding of pixels in a PostScript file. 02491 */ 02492 l_int32 02493 pixGetRasterData(PIX *pixs, 02494 l_uint8 **pdata, 02495 size_t *pnbytes) 02496 { 02497 l_int32 w, h, d, wpl, i, j, rval, gval, bval; 02498 l_int32 databpl; /* bytes for each raster line in returned data */ 02499 l_uint8 *line, *data; /* packed data in returned array */ 02500 l_uint32 *rline, *rdata; /* data in pix raster */ 02501 02502 PROCNAME("pixGetRasterData"); 02503 02504 if (!pdata || !pnbytes) 02505 return ERROR_INT("&data and &nbytes not both defined", procName, 1); 02506 *pdata = NULL; 02507 *pnbytes = 0; 02508 if (!pixs) 02509 return ERROR_INT("pixs not defined", procName, 1); 02510 pixGetDimensions(pixs, &w, &h, &d); 02511 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32) 02512 return ERROR_INT("depth not in {1,2,4,8,16,32}", procName, 1); 02513 rdata = pixGetData(pixs); 02514 wpl = pixGetWpl(pixs); 02515 if (d == 1) 02516 databpl = (w + 7) / 8; 02517 else if (d == 2) 02518 databpl = (w + 3) / 4; 02519 else if (d == 4) 02520 databpl = (w + 1) / 2; 02521 else if (d == 8 || d == 16) 02522 databpl = w * (d / 8); 02523 else /* d == 32 bpp rgb */ 02524 databpl = 3 * w; 02525 if ((data = (l_uint8 *)CALLOC(databpl * h, sizeof(l_uint8))) == NULL) 02526 return ERROR_INT("data not allocated", procName, 1); 02527 *pdata = data; 02528 *pnbytes = databpl * h; 02529 02530 for (i = 0; i < h; i++) { 02531 rline = rdata + i * wpl; 02532 line = data + i * databpl; 02533 if (d <= 8) { 02534 for (j = 0; j < databpl; j++) 02535 line[j] = GET_DATA_BYTE(rline, j); 02536 } 02537 else if (d == 16) { 02538 for (j = 0; j < w; j++) 02539 line[2 * j] = GET_DATA_TWO_BYTES(rline, j); 02540 } 02541 else { /* d == 32 bpp rgb */ 02542 for (j = 0; j < w; j++) { 02543 extractRGBValues(rline[j], &rval, &gval, &bval); 02544 *(line + 3 * j) = rval; 02545 *(line + 3 * j + 1) = gval; 02546 *(line + 3 * j + 2) = bval; 02547 } 02548 } 02549 } 02550 02551 return 0; 02552 } 02553 02554 02555 /*-------------------------------------------------------------* 02556 * Setup helpers for 8 bpp byte processing * 02557 *-------------------------------------------------------------*/ 02558 /*! 02559 * pixSetupByteProcessing() 02560 * 02561 * Input: pix (8 bpp, no colormap) 02562 * &w (<optional return> width) 02563 * &h (<optional return> height) 02564 * Return: line ptr array, or null on error 02565 * 02566 * Notes: 02567 * (1) This is a simple helper for processing 8 bpp images with 02568 * direct byte access. It can swap byte order within each word. 02569 * (2) After processing, you must call pixCleanupByteProcessing(), 02570 * which frees the lineptr array and restores byte order. 02571 * (3) Usage: 02572 * l_uint8 **lineptrs = pixSetupByteProcessing(pix, &w, &h); 02573 * for (i = 0; i < h; i++) { 02574 * l_uint8 *line = lineptrs[i]; 02575 * for (j = 0; j < w; j++) { 02576 * val = line[j]; 02577 * ... 02578 * } 02579 * } 02580 * pixCleanupByteProcessing(pix, lineptrs); 02581 */ 02582 l_uint8 ** 02583 pixSetupByteProcessing(PIX *pix, 02584 l_int32 *pw, 02585 l_int32 *ph) 02586 { 02587 l_int32 w, h; 02588 02589 PROCNAME("pixSetupByteProcessing"); 02590 02591 if (pw) *pw = 0; 02592 if (ph) *ph = 0; 02593 if (!pix || pixGetDepth(pix) != 8) 02594 return (l_uint8 **)ERROR_PTR("pix not defined or not 8 bpp", 02595 procName, NULL); 02596 if (pixGetColormap(pix)) 02597 return (l_uint8 **)ERROR_PTR("pix has colormap", procName, NULL); 02598 02599 pixGetDimensions(pix, &w, &h, NULL); 02600 if (pw) *pw = w; 02601 if (ph) *ph = h; 02602 pixEndianByteSwap(pix); 02603 return (l_uint8 **)pixGetLinePtrs(pix, NULL); 02604 } 02605 02606 02607 /*! 02608 * pixCleanupByteProcessing() 02609 * 02610 * Input: pix (8 bpp, no colormap) 02611 * lineptrs (ptrs to the beginning of each raster line of data) 02612 * Return: 0 if OK, 1 on error 02613 * 02614 * Notes: 02615 * (1) This must be called after processing that was initiated 02616 * by pixSetupByteProcessing() has finished. 02617 */ 02618 l_int32 02619 pixCleanupByteProcessing(PIX *pix, 02620 l_uint8 **lineptrs) 02621 { 02622 PROCNAME("pixCleanupByteProcessing"); 02623 02624 if (!pix) 02625 return ERROR_INT("pix not defined", procName, 1); 02626 if (!lineptrs) 02627 return ERROR_INT("lineptrs not defined", procName, 1); 02628 02629 pixEndianByteSwap(pix); 02630 FREE(lineptrs); 02631 return 0; 02632 } 02633 02634 02635 /*------------------------------------------------------------------------* 02636 * Setting parameters for antialias masking with alpha transforms * 02637 *------------------------------------------------------------------------*/ 02638 /*! 02639 * l_setAlphaMaskBorder() 02640 * 02641 * Input: val1, val2 (in [0.0 ... 1.0]) 02642 * Return: void 02643 * 02644 * Notes: 02645 * (1) This sets the opacity values used to generate the two outer 02646 * boundary rings in the alpha mask associated with geometric 02647 * transforms such as pixRotateWithAlpha(). 02648 * (2) The default values are val1 = 0.0 (completely transparent 02649 * in the outermost ring) and val2 = 0.5 (half transparent 02650 * in the second ring). When the image is blended, this 02651 * completely removes the outer ring (shrinking the image by 02652 * 2 in each direction), and alpha-blends with 0.5 the second ring. 02653 * (3) The actual mask values are found by multiplying these 02654 * normalized opacity values by 255. 02655 */ 02656 void 02657 l_setAlphaMaskBorder(l_float32 val1, 02658 l_float32 val2) 02659 { 02660 val1 = L_MAX(0.0, L_MIN(1.0, val1)); 02661 val2 = L_MAX(0.0, L_MIN(1.0, val2)); 02662 AlphaMaskBorderVals[0] = val1; 02663 AlphaMaskBorderVals[1] = val2; 02664 } 02665 02666