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