Leptonica 1.68
C Image Processing Library
|
00001 /*====================================================================* 00002 - Copyright (C) 2001 Leptonica. All rights reserved. 00003 - This software is distributed in the hope that it will be 00004 - useful, but with NO WARRANTY OF ANY KIND. 00005 - No author or distributor accepts responsibility to anyone for the 00006 - consequences of using this software, or for whether it serves any 00007 - particular purpose or works at all, unless he or she says so in 00008 - writing. Everyone is granted permission to copy, modify and 00009 - redistribute this source code, for commercial or non-commercial 00010 - purposes, with the following restrictions: (1) the origin of this 00011 - source code must not be misrepresented; (2) modified versions must 00012 - be plainly marked as such; and (3) this notice may not be removed 00013 - or altered from any source or modified source distribution. 00014 *====================================================================*/ 00015 00016 /* 00017 * colormap.c 00018 * 00019 * Colormap creation, copy, destruction, addition 00020 * PIXCMAP *pixcmapCreate() 00021 * PIXCMAP *pixcmapCreateRandom() 00022 * PIXCMAP *pixcmapCreateLinear() 00023 * PIXCMAP *pixcmapCopy() 00024 * void pixcmapDestroy() 00025 * l_int32 pixcmapAddColor() 00026 * l_int32 pixcmapAddNewColor() 00027 * l_int32 pixcmapAddNearestColor() 00028 * l_int32 pixcmapUsableColor() 00029 * l_int32 pixcmapAddBlackOrWhite() 00030 * l_int32 pixcmapSetBlackAndWhite() 00031 * l_int32 pixcmapGetCount() 00032 * l_int32 pixcmapGetDepth() 00033 * l_int32 pixcmapGetMinDepth() 00034 * l_int32 pixcmapGetFreeCount() 00035 * l_int32 pixcmapClear() 00036 * 00037 * Colormap random access and test 00038 * l_int32 pixcmapGetColor() 00039 * l_int32 pixcmapGetColor32() 00040 * l_int32 pixcmapResetColor() 00041 * l_int32 pixcmapGetIndex() 00042 * l_int32 pixcmapHasColor() 00043 * l_int32 pixcmapCountGrayColors() 00044 * l_int32 pixcmapGetRankIntensity() 00045 * l_int32 pixcmapGetNearestIndex() 00046 * l_int32 pixcmapGetNearestGrayIndex() 00047 * l_int32 pixcmapGetComponentRange() 00048 * l_int32 pixcmapGetExtremeValue() 00049 * 00050 * Colormap conversion 00051 * PIXCMAP *pixcmapGrayToColor() 00052 * PIXCMAP *pixcmapColorToGray() 00053 * 00054 * Colormap I/O 00055 * l_int32 pixcmapReadStream() 00056 * l_int32 pixcmapWriteStream() 00057 * 00058 * Extract colormap arrays and serialization 00059 * l_int32 pixcmapToArrays() 00060 * l_int32 pixcmapToRGBTable() 00061 * l_int32 pixcmapSerializeToMemory() 00062 * PIXCMAP *pixcmapDeserializeFromMemory() 00063 * char *pixcmapConvertToHex() 00064 * 00065 * Colormap transforms 00066 * l_int32 pixcmapGammaTRC() 00067 * l_int32 pixcmapContrastTRC() 00068 * l_int32 pixcmapShiftIntensity() 00069 */ 00070 00071 #include <string.h> 00072 #include "allheaders.h" 00073 00074 00075 /*-------------------------------------------------------------* 00076 * Colormap creation and addition * 00077 *-------------------------------------------------------------*/ 00078 /*! 00079 * pixcmapCreate() 00080 * 00081 * Input: depth (bpp, of pix) 00082 * Return: cmap, or null on error 00083 */ 00084 PIXCMAP * 00085 pixcmapCreate(l_int32 depth) 00086 { 00087 RGBA_QUAD *cta; 00088 PIXCMAP *cmap; 00089 00090 PROCNAME("pixcmapCreate"); 00091 00092 if (depth != 1 && depth != 2 && depth !=4 && depth != 8) 00093 return (PIXCMAP *)ERROR_PTR("depth not in {1,2,4,8}", procName, NULL); 00094 00095 if ((cmap = (PIXCMAP *)CALLOC(1, sizeof(PIXCMAP))) == NULL) 00096 return (PIXCMAP *)ERROR_PTR("cmap not made", procName, NULL); 00097 cmap->depth = depth; 00098 cmap->nalloc = 1 << depth; 00099 if ((cta = (RGBA_QUAD *)CALLOC(cmap->nalloc, sizeof(RGBA_QUAD))) == NULL) 00100 return (PIXCMAP *)ERROR_PTR("cta not made", procName, NULL); 00101 cmap->array = cta; 00102 cmap->n = 0; 00103 00104 return cmap; 00105 } 00106 00107 00108 /*! 00109 * pixcmapCreateRandom() 00110 * 00111 * Input: depth (bpp, of pix; 2, 4 or 8) 00112 * hasblack (1 if the first color is black; 0 if no black) 00113 * haswhite (1 if the last color is white; 0 if no white) 00114 * Return: cmap, or null on error 00115 * 00116 * Notes: 00117 * (1) This sets up a colormap with random colors, 00118 * where the first color is optionally black, the last color 00119 * is optionally white, and the remaining colors are 00120 * chosen randomly. 00121 * (2) The number of randomly chosen colors is: 00122 * 2^(depth) - haswhite - hasblack 00123 * (3) Because rand() is seeded, it might disrupt otherwise 00124 * deterministic results if also used elsewhere in a program. 00125 * (4) rand() is not threadsafe, and will generate garbage if run 00126 * on multiple threads at once -- though garbage is generally 00127 * what you want from a random number generator! 00128 * (5) Modern rand()s have equal randomness in low and high order 00129 * bits, but older ones don't. Here, we're just using rand() 00130 * to choose colors for output. 00131 */ 00132 PIXCMAP * 00133 pixcmapCreateRandom(l_int32 depth, 00134 l_int32 hasblack, 00135 l_int32 haswhite) 00136 { 00137 l_int32 ncolors, i; 00138 l_int32 red[256], green[256], blue[256]; 00139 PIXCMAP *cmap; 00140 00141 PROCNAME("pixcmapCreateRandom"); 00142 00143 if (depth != 2 && depth != 4 && depth != 8) 00144 return (PIXCMAP *)ERROR_PTR("depth not in {2, 4, 8}", procName, NULL); 00145 if (hasblack != 0) hasblack = 1; 00146 if (haswhite != 0) haswhite = 1; 00147 00148 cmap = pixcmapCreate(depth); 00149 ncolors = 1 << depth; 00150 if (hasblack) /* first color is optionally black */ 00151 pixcmapAddColor(cmap, 0, 0, 0); 00152 for (i = hasblack; i < ncolors - haswhite; i++) { 00153 red[i] = (l_uint32)rand() & 0xff; 00154 green[i] = (l_uint32)rand() & 0xff; 00155 blue[i] = (l_uint32)rand() & 0xff; 00156 pixcmapAddColor(cmap, red[i], green[i], blue[i]); 00157 } 00158 if (haswhite) /* last color is optionally white */ 00159 pixcmapAddColor(cmap, 255, 255, 255); 00160 00161 return cmap; 00162 } 00163 00164 00165 /*! 00166 * pixcmapCreateLinear() 00167 * 00168 * Input: d (depth of pix for this colormap; 1, 2, 4 or 8) 00169 * nlevels (valid in range [2, 2^d]) 00170 * Return: cmap, or null on error 00171 * 00172 * Notes: 00173 * (1) Colormap has equally spaced gray color values 00174 * from black (0, 0, 0) to white (255, 255, 255). 00175 */ 00176 PIXCMAP * 00177 pixcmapCreateLinear(l_int32 d, 00178 l_int32 nlevels) 00179 { 00180 l_int32 maxlevels, i, val; 00181 PIXCMAP *cmap; 00182 00183 PROCNAME("pixcmapCreateLinear"); 00184 00185 if (d != 1 && d != 2 && d !=4 && d != 8) 00186 return (PIXCMAP *)ERROR_PTR("d not in {1, 2, 4, 8}", procName, NULL); 00187 maxlevels = 1 << d; 00188 if (nlevels < 2 || nlevels > maxlevels) 00189 return (PIXCMAP *)ERROR_PTR("invalid nlevels", procName, NULL); 00190 00191 cmap = pixcmapCreate(d); 00192 for (i = 0; i < nlevels; i++) { 00193 val = (255 * i) / (nlevels - 1); 00194 pixcmapAddColor(cmap, val, val, val); 00195 } 00196 return cmap; 00197 } 00198 00199 00200 /*! 00201 * pixcmapCopy() 00202 * 00203 * Input: cmaps 00204 * Return: cmapd, or null on error 00205 */ 00206 PIXCMAP * 00207 pixcmapCopy(PIXCMAP *cmaps) 00208 { 00209 l_int32 nbytes; 00210 PIXCMAP *cmapd; 00211 00212 PROCNAME("pixcmapCopy"); 00213 00214 if (!cmaps) 00215 return (PIXCMAP *)ERROR_PTR("cmaps not defined", procName, NULL); 00216 00217 if ((cmapd = (PIXCMAP *)CALLOC(1, sizeof(PIXCMAP))) == NULL) 00218 return (PIXCMAP *)ERROR_PTR("cmapd not made", procName, NULL); 00219 nbytes = cmaps->nalloc * sizeof(RGBA_QUAD); 00220 if ((cmapd->array = (void *)CALLOC(1, nbytes)) == NULL) 00221 return (PIXCMAP *)ERROR_PTR("cmap array not made", procName, NULL); 00222 memcpy(cmapd->array, cmaps->array, nbytes); 00223 cmapd->n = cmaps->n; 00224 cmapd->nalloc = cmaps->nalloc; 00225 cmapd->depth = cmaps->depth; 00226 00227 return cmapd; 00228 } 00229 00230 00231 /*! 00232 * pixcmapDestroy() 00233 * 00234 * Input: &cmap (<set to null>) 00235 * Return: void 00236 */ 00237 void 00238 pixcmapDestroy(PIXCMAP **pcmap) 00239 { 00240 PIXCMAP *cmap; 00241 00242 PROCNAME("pixcmapDestroy"); 00243 00244 if (pcmap == NULL) { 00245 L_WARNING("ptr address is null!", procName); 00246 return; 00247 } 00248 00249 if ((cmap = *pcmap) == NULL) 00250 return; 00251 00252 FREE(cmap->array); 00253 FREE(cmap); 00254 *pcmap = NULL; 00255 00256 return; 00257 } 00258 00259 00260 /*! 00261 * pixcmapAddColor() 00262 * 00263 * Input: cmap 00264 * rval, gval, bval (colormap entry to be added; each number 00265 * is in range [0, ... 255]) 00266 * Return: 0 if OK, 1 on error 00267 * 00268 * Note: always adds the color if there is room. 00269 */ 00270 l_int32 00271 pixcmapAddColor(PIXCMAP *cmap, 00272 l_int32 rval, 00273 l_int32 gval, 00274 l_int32 bval) 00275 { 00276 RGBA_QUAD *cta; 00277 00278 PROCNAME("pixcmapAddColor"); 00279 00280 if (!cmap) 00281 return ERROR_INT("cmap not defined", procName, 1); 00282 if (cmap->n >= cmap->nalloc) 00283 return ERROR_INT("no free color entries", procName, 1); 00284 00285 cta = (RGBA_QUAD *)cmap->array; 00286 cta[cmap->n].red = rval; 00287 cta[cmap->n].green = gval; 00288 cta[cmap->n].blue = bval; 00289 cmap->n++; 00290 00291 return 0; 00292 } 00293 00294 00295 /*! 00296 * pixcmapAddNewColor() 00297 * 00298 * Input: cmap 00299 * rval, gval, bval (colormap entry to be added; each number 00300 * is in range [0, ... 255]) 00301 * &index (<return> index of color) 00302 * Return: 0 if OK, 1 on error; 2 if unable to add color 00303 * 00304 * Notes: 00305 * (1) This only adds color if not already there. 00306 * (2) This returns the index of the new (or existing) color. 00307 * (3) Returns 2 with a warning if unable to add this color; 00308 * the caller should check the return value. 00309 */ 00310 l_int32 00311 pixcmapAddNewColor(PIXCMAP *cmap, 00312 l_int32 rval, 00313 l_int32 gval, 00314 l_int32 bval, 00315 l_int32 *pindex) 00316 { 00317 PROCNAME("pixcmapAddNewColor"); 00318 00319 if (!pindex) 00320 return ERROR_INT("&index not defined", procName, 1); 00321 *pindex = 0; 00322 if (!cmap) 00323 return ERROR_INT("cmap not defined", procName, 1); 00324 00325 /* Check if the color is already present. */ 00326 if (!pixcmapGetIndex(cmap, rval, gval, bval, pindex)) /* found */ 00327 return 0; 00328 00329 /* We need to add the color. Is there room? */ 00330 if (cmap->n >= cmap->nalloc) { 00331 L_WARNING("no free color entries", procName); 00332 return 2; 00333 } 00334 00335 /* There's room. Add it. */ 00336 pixcmapAddColor(cmap, rval, gval, bval); 00337 *pindex = pixcmapGetCount(cmap) - 1; 00338 return 0; 00339 } 00340 00341 00342 /*! 00343 * pixcmapAddNearestColor() 00344 * 00345 * Input: cmap 00346 * rval, gval, bval (colormap entry to be added; each number 00347 * is in range [0, ... 255]) 00348 * &index (<return> index of color) 00349 * Return: 0 if OK, 1 on error 00350 * 00351 * Notes: 00352 * (1) This only adds color if not already there. 00353 * (2) If it's not in the colormap and there is no room to add 00354 * another color, this returns the index of the nearest color. 00355 */ 00356 l_int32 00357 pixcmapAddNearestColor(PIXCMAP *cmap, 00358 l_int32 rval, 00359 l_int32 gval, 00360 l_int32 bval, 00361 l_int32 *pindex) 00362 { 00363 PROCNAME("pixcmapAddNearestColor"); 00364 00365 if (!pindex) 00366 return ERROR_INT("&index not defined", procName, 1); 00367 *pindex = 0; 00368 if (!cmap) 00369 return ERROR_INT("cmap not defined", procName, 1); 00370 00371 /* Check if the color is already present. */ 00372 if (!pixcmapGetIndex(cmap, rval, gval, bval, pindex)) /* found */ 00373 return 0; 00374 00375 /* We need to add the color. Is there room? */ 00376 if (cmap->n < cmap->nalloc) { 00377 pixcmapAddColor(cmap, rval, gval, bval); 00378 *pindex = pixcmapGetCount(cmap) - 1; 00379 return 0; 00380 } 00381 00382 /* There's no room. Return the index of the nearest color */ 00383 pixcmapGetNearestIndex(cmap, rval, gval, bval, pindex); 00384 return 0; 00385 } 00386 00387 00388 /*! 00389 * pixcmapUsableColor() 00390 * 00391 * Input: cmap 00392 * rval, gval, bval (colormap entry to be added; each number 00393 * is in range [0, ... 255]) 00394 * usable (<return> 1 if usable; 0 if not) 00395 * Return: 0 if OK, 1 on error 00396 * 00397 * Notes: 00398 * (1) This checks if the color already exists or if there is 00399 * room to add it. It makes no change in the colormap. 00400 */ 00401 l_int32 00402 pixcmapUsableColor(PIXCMAP *cmap, 00403 l_int32 rval, 00404 l_int32 gval, 00405 l_int32 bval, 00406 l_int32 *pusable) 00407 { 00408 l_int32 index; 00409 00410 PROCNAME("pixcmapUsableColor"); 00411 00412 if (!pusable) 00413 return ERROR_INT("&usable not defined", procName, 1); 00414 *pusable = 0; 00415 if (!cmap) 00416 return ERROR_INT("cmap not defined", procName, 1); 00417 00418 /* Is there room to add it? */ 00419 if (cmap->n < cmap->nalloc) { 00420 *pusable = 1; 00421 return 0; 00422 } 00423 00424 /* No room; check if the color is already present. */ 00425 if (!pixcmapGetIndex(cmap, rval, gval, bval, &index)) /* found */ 00426 *pusable = 1; 00427 return 0; 00428 } 00429 00430 00431 /*! 00432 * pixcmapAddBlackOrWhite() 00433 * 00434 * Input: cmap 00435 * color (0 for black, 1 for white) 00436 * &index (<optional return> index of color; can be null) 00437 * Return: 0 if OK, 1 on error 00438 * 00439 * Notes: 00440 * (1) This only adds color if not already there. 00441 * (2) This sets index to the requested color. 00442 * (3) If there is no room in the colormap, returns the index 00443 * of the closest color. 00444 */ 00445 l_int32 00446 pixcmapAddBlackOrWhite(PIXCMAP *cmap, 00447 l_int32 color, 00448 l_int32 *pindex) 00449 { 00450 l_int32 index; 00451 00452 PROCNAME("pixcmapAddBlackOrWhite"); 00453 00454 if (pindex) *pindex = 0; 00455 if (!cmap) 00456 return ERROR_INT("cmap not defined", procName, 1); 00457 00458 if (color == 0) { /* black */ 00459 if (pixcmapGetFreeCount(cmap) > 0) 00460 pixcmapAddNewColor(cmap, 0, 0, 0, &index); 00461 else 00462 pixcmapGetRankIntensity(cmap, 0.0, &index); 00463 } 00464 else { /* white */ 00465 if (pixcmapGetFreeCount(cmap) > 0) 00466 pixcmapAddNewColor(cmap, 255, 255, 255, &index); 00467 else 00468 pixcmapGetRankIntensity(cmap, 1.0, &index); 00469 } 00470 00471 if (pindex) 00472 *pindex = index; 00473 return 0; 00474 } 00475 00476 00477 /*! 00478 * pixcmapSetBlackAndWhite() 00479 * 00480 * Input: cmap 00481 * setblack (0 for no operation; 1 to set darkest color to black) 00482 * setwhite (0 for no operation; 1 to set lightest color to white) 00483 * Return: 0 if OK, 1 on error 00484 */ 00485 l_int32 00486 pixcmapSetBlackAndWhite(PIXCMAP *cmap, 00487 l_int32 setblack, 00488 l_int32 setwhite) 00489 { 00490 l_int32 index; 00491 00492 PROCNAME("pixcmapSetBlackAndWhite"); 00493 00494 if (!cmap) 00495 return ERROR_INT("cmap not defined", procName, 1); 00496 00497 if (setblack) { 00498 pixcmapGetRankIntensity(cmap, 0.0, &index); 00499 pixcmapResetColor(cmap, index, 0, 0, 0); 00500 } 00501 if (setwhite) { 00502 pixcmapGetRankIntensity(cmap, 1.0, &index); 00503 pixcmapResetColor(cmap, index, 255, 255, 255); 00504 } 00505 00506 return 0; 00507 } 00508 00509 00510 /*! 00511 * pixcmapGetCount() 00512 * 00513 * Input: cmap 00514 * Return: count, or 0 on error 00515 */ 00516 l_int32 00517 pixcmapGetCount(PIXCMAP *cmap) 00518 { 00519 PROCNAME("pixcmapGetCount"); 00520 00521 if (!cmap) 00522 return ERROR_INT("cmap not defined", procName, 0); 00523 00524 return cmap->n; 00525 } 00526 00527 00528 /*! 00529 * pixcmapGetFreeCount() 00530 * 00531 * Input: cmap 00532 * Return: free entries, or 0 on error 00533 */ 00534 l_int32 00535 pixcmapGetFreeCount(PIXCMAP *cmap) 00536 { 00537 PROCNAME("pixcmapGetFreeCount"); 00538 00539 if (!cmap) 00540 return ERROR_INT("cmap not defined", procName, 0); 00541 00542 return (cmap->nalloc - cmap->n); 00543 } 00544 00545 00546 /*! 00547 * pixcmapGetDepth() 00548 * 00549 * Input: cmap 00550 * Return: depth, or 0 on error 00551 */ 00552 l_int32 00553 pixcmapGetDepth(PIXCMAP *cmap) 00554 { 00555 PROCNAME("pixcmapGetDepth"); 00556 00557 if (!cmap) 00558 return ERROR_INT("cmap not defined", procName, 0); 00559 00560 return cmap->depth; 00561 } 00562 00563 00564 /*! 00565 * pixcmapGetMinDepth() 00566 * 00567 * Input: cmap 00568 * &mindepth (<return> minimum depth to support the colormap) 00569 * Return: 0 if OK, 1 on error 00570 * 00571 * Notes: 00572 * (1) On error, &mindepth is returned as 0. 00573 */ 00574 l_int32 00575 pixcmapGetMinDepth(PIXCMAP *cmap, 00576 l_int32 *pmindepth) 00577 { 00578 l_int32 ncolors; 00579 00580 PROCNAME("pixcmapGetMinDepth"); 00581 00582 if (!pmindepth) 00583 return ERROR_INT("&mindepth not defined", procName, 1); 00584 *pmindepth = 0; 00585 if (!cmap) 00586 return ERROR_INT("cmap not defined", procName, 1); 00587 00588 ncolors = pixcmapGetCount(cmap); 00589 if (ncolors <= 4) 00590 *pmindepth = 2; 00591 else if (ncolors <= 16) 00592 *pmindepth = 4; 00593 else /* ncolors > 16 */ 00594 *pmindepth = 8; 00595 00596 return 0; 00597 } 00598 00599 00600 /*! 00601 * pixcmapClear() 00602 * 00603 * Input: cmap 00604 * Return: 0 if OK, 1 on error 00605 * 00606 * Note: this removes the colors by setting the count to 0. 00607 */ 00608 l_int32 00609 pixcmapClear(PIXCMAP *cmap) 00610 { 00611 PROCNAME("pixcmapClear"); 00612 00613 if (!cmap) 00614 return ERROR_INT("cmap not defined", procName, 1); 00615 cmap->n = 0; 00616 return 0; 00617 } 00618 00619 00620 /*-------------------------------------------------------------* 00621 * Colormap random access * 00622 *-------------------------------------------------------------*/ 00623 /*! 00624 * pixcmapGetColor() 00625 * 00626 * Input: cmap 00627 * index 00628 * &rval, &gval, &bval (<return> each color value in l_int32) 00629 * Return: 0 if OK, 1 if not accessable (caller should check) 00630 */ 00631 l_int32 00632 pixcmapGetColor(PIXCMAP *cmap, 00633 l_int32 index, 00634 l_int32 *prval, 00635 l_int32 *pgval, 00636 l_int32 *pbval) 00637 { 00638 RGBA_QUAD *cta; 00639 00640 PROCNAME("pixcmapGetColor"); 00641 00642 if (!prval || !pgval || !pbval) 00643 return ERROR_INT("&rval, &gval, &bval not all defined", procName, 1); 00644 *prval = *pgval = *pbval = 0; 00645 if (!cmap) 00646 return ERROR_INT("cmap not defined", procName, 1); 00647 if (index < 0 || index >= cmap->n) 00648 return ERROR_INT("index out of bounds", procName, 1); 00649 00650 cta = (RGBA_QUAD *)cmap->array; 00651 *prval = cta[index].red; 00652 *pgval = cta[index].green; 00653 *pbval = cta[index].blue; 00654 00655 return 0; 00656 } 00657 00658 00659 /*! 00660 * pixcmapGetColor32() 00661 * 00662 * Input: cmap 00663 * index 00664 * &val32 (<return> 32-bit rgba color value) 00665 * Return: 0 if OK, 1 if not accessable (caller should check) 00666 * 00667 * Notes: 00668 * (1) The returned alpha channel value is zero, because it is 00669 * not used in leptonica colormaps. 00670 */ 00671 l_int32 00672 pixcmapGetColor32(PIXCMAP *cmap, 00673 l_int32 index, 00674 l_uint32 *pval32) 00675 { 00676 l_int32 rval, gval, bval; 00677 00678 PROCNAME("pixcmapGetColor32"); 00679 00680 if (!pval32) 00681 return ERROR_INT("&val32 not defined", procName, 1); 00682 *pval32 = 0; 00683 00684 if (pixcmapGetColor(cmap, index, &rval, &gval, &bval) != 0) 00685 return ERROR_INT("rgb values not found", procName, 1); 00686 composeRGBPixel(rval, gval, bval, pval32); 00687 return 0; 00688 } 00689 00690 00691 /*! 00692 * pixcmapResetColor() 00693 * 00694 * Input: cmap 00695 * index 00696 * rval, gval, bval (colormap entry to be reset; each number 00697 * is in range [0, ... 255]) 00698 * Return: 0 if OK, 1 if not accessable (caller should check) 00699 * 00700 * Notes: 00701 * (1) This resets sets the color of an entry that has already 00702 * been set and included in the count of colors. 00703 */ 00704 l_int32 00705 pixcmapResetColor(PIXCMAP *cmap, 00706 l_int32 index, 00707 l_int32 rval, 00708 l_int32 gval, 00709 l_int32 bval) 00710 { 00711 RGBA_QUAD *cta; 00712 00713 PROCNAME("pixcmapResetColor"); 00714 00715 if (!cmap) 00716 return ERROR_INT("cmap not defined", procName, 1); 00717 if (index < 0 || index >= cmap->n) 00718 return ERROR_INT("index out of bounds", procName, 1); 00719 00720 cta = (RGBA_QUAD *)cmap->array; 00721 cta[index].red = rval; 00722 cta[index].green = gval; 00723 cta[index].blue = bval; 00724 00725 return 0; 00726 } 00727 00728 00729 /*! 00730 * pixcmapGetIndex() 00731 * 00732 * Input: cmap 00733 * rval, gval, bval (colormap colors to search for; each number 00734 * is in range [0, ... 255]) 00735 * &index (<return>) 00736 * Return: 0 if found, 1 if not found (caller must check) 00737 */ 00738 l_int32 00739 pixcmapGetIndex(PIXCMAP *cmap, 00740 l_int32 rval, 00741 l_int32 gval, 00742 l_int32 bval, 00743 l_int32 *pindex) 00744 { 00745 l_int32 n, i; 00746 RGBA_QUAD *cta; 00747 00748 PROCNAME("pixcmapGetIndex"); 00749 00750 if (!pindex) 00751 return ERROR_INT("&index not defined", procName, 1); 00752 *pindex = 0; 00753 if (!cmap) 00754 return ERROR_INT("cmap not defined", procName, 1); 00755 n = pixcmapGetCount(cmap); 00756 00757 cta = (RGBA_QUAD *)cmap->array; 00758 for (i = 0; i < n; i++) { 00759 if (rval == cta[i].red && gval == cta[i].green && bval == cta[i].blue) { 00760 *pindex = i; 00761 return 0; 00762 } 00763 } 00764 00765 return 1; 00766 } 00767 00768 00769 /*! 00770 * pixcmapHasColor() 00771 * 00772 * Input: cmap 00773 * &color (<return> TRUE if cmap has color; FALSE otherwise) 00774 * Return: 0 if OK, 1 on error 00775 */ 00776 l_int32 00777 pixcmapHasColor(PIXCMAP *cmap, 00778 l_int32 *pcolor) 00779 { 00780 l_int32 n, i; 00781 l_int32 *rmap, *gmap, *bmap; 00782 00783 PROCNAME("pixcmapHasColor"); 00784 00785 if (!pcolor) 00786 return ERROR_INT("&color not defined", procName, 1); 00787 *pcolor = FALSE; 00788 if (!cmap) 00789 return ERROR_INT("cmap not defined", procName, 1); 00790 00791 if (pixcmapToArrays(cmap, &rmap, &gmap, &bmap)) 00792 return ERROR_INT("colormap arrays not made", procName, 1); 00793 n = pixcmapGetCount(cmap); 00794 for (i = 0; i < n; i++) { 00795 if ((rmap[i] != gmap[i]) || (rmap[i] != bmap[i])) { 00796 *pcolor = TRUE; 00797 break; 00798 } 00799 } 00800 00801 FREE(rmap); 00802 FREE(gmap); 00803 FREE(bmap); 00804 return 0; 00805 } 00806 00807 00808 /*! 00809 * pixcmapCountGrayColors() 00810 * 00811 * Input: cmap 00812 * &ngray (<return> number of gray colors) 00813 * Return: 0 if OK, 1 on error 00814 * 00815 * Notes: 00816 * (1) This counts the unique gray colors, including black and white. 00817 */ 00818 l_int32 00819 pixcmapCountGrayColors(PIXCMAP *cmap, 00820 l_int32 *pngray) 00821 { 00822 l_int32 n, i, rval, gval, bval, count; 00823 l_int32 *array; 00824 00825 PROCNAME("pixcmapCountGrayColors"); 00826 00827 if (!pngray) 00828 return ERROR_INT("&ngray not defined", procName, 1); 00829 *pngray = 0; 00830 if (!cmap) 00831 return ERROR_INT("cmap not defined", procName, 1); 00832 00833 array = (l_int32 *)CALLOC(256, sizeof(l_int32)); 00834 n = pixcmapGetCount(cmap); 00835 count = 0; 00836 for (i = 0; i < n; i++) { 00837 pixcmapGetColor(cmap, i, &rval, &gval, &bval); 00838 if ((rval == gval) && (rval == bval) && (array[rval] == 0)) { 00839 array[rval] = 1; 00840 count++; 00841 } 00842 } 00843 00844 FREE(array); 00845 *pngray = count; 00846 return 0; 00847 } 00848 00849 00850 /*! 00851 * pixcmapGetRankIntensity() 00852 * 00853 * Input: cmap 00854 * rankval (0.0 for darkest, 1.0 for lightest color) 00855 * &index (<return> the index into the colormap that 00856 * corresponds to the rank intensity color) 00857 * Return: 0 if OK, 1 on error 00858 */ 00859 l_int32 00860 pixcmapGetRankIntensity(PIXCMAP *cmap, 00861 l_float32 rankval, 00862 l_int32 *pindex) 00863 { 00864 l_int32 n, i, rval, gval, bval, rankindex; 00865 NUMA *na, *nasort; 00866 00867 PROCNAME("pixcmapGetRankIntensity"); 00868 00869 if (!pindex) 00870 return ERROR_INT("&index not defined", procName, 1); 00871 *pindex = 0; 00872 if (!cmap) 00873 return ERROR_INT("cmap not defined", procName, 1); 00874 if (rankval < 0.0 || rankval > 1.0) 00875 return ERROR_INT("rankval not in [0.0 ... 1.0]", procName, 1); 00876 00877 n = pixcmapGetCount(cmap); 00878 na = numaCreate(n); 00879 for (i = 0; i < n; i++) { 00880 pixcmapGetColor(cmap, i, &rval, &gval, &bval); 00881 numaAddNumber(na, rval + gval + bval); 00882 } 00883 nasort = numaGetSortIndex(na, L_SORT_INCREASING); 00884 rankindex = (l_int32)(rankval * (n - 1) + 0.5); 00885 numaGetIValue(nasort, rankindex, pindex); 00886 00887 numaDestroy(&na); 00888 numaDestroy(&nasort); 00889 return 0; 00890 } 00891 00892 00893 /*! 00894 * pixcmapGetNearestIndex() 00895 * 00896 * Input: cmap 00897 * rval, gval, bval (colormap colors to search for; each number 00898 * is in range [0, ... 255]) 00899 * &index (<return> the index of the nearest color) 00900 * Return: 0 if OK, 1 on error (caller must check) 00901 * 00902 * Notes: 00903 * (1) Returns the index of the exact color if possible, otherwise the 00904 * index of the color closest to the target color. 00905 * (2) Nearest color is that which is the least sum-of-squares distance 00906 * from the target color. 00907 */ 00908 l_int32 00909 pixcmapGetNearestIndex(PIXCMAP *cmap, 00910 l_int32 rval, 00911 l_int32 gval, 00912 l_int32 bval, 00913 l_int32 *pindex) 00914 { 00915 l_int32 i, n, delta, dist, mindist; 00916 RGBA_QUAD *cta; 00917 00918 PROCNAME("pixcmapGetNearestIndex"); 00919 00920 if (!pindex) 00921 return ERROR_INT("&index not defined", procName, 1); 00922 *pindex = UNDEF; 00923 if (!cmap) 00924 return ERROR_INT("cmap not defined", procName, 1); 00925 00926 if ((cta = (RGBA_QUAD *)cmap->array) == NULL) 00927 return ERROR_INT("cta not defined(!)", procName, 1); 00928 n = pixcmapGetCount(cmap); 00929 00930 mindist = 3 * 255 * 255 + 1; 00931 for (i = 0; i < n; i++) { 00932 delta = cta[i].red - rval; 00933 dist = delta * delta; 00934 delta = cta[i].green - gval; 00935 dist += delta * delta; 00936 delta = cta[i].blue - bval; 00937 dist += delta * delta; 00938 if (dist < mindist) { 00939 *pindex = i; 00940 if (dist == 0) 00941 break; 00942 mindist = dist; 00943 } 00944 } 00945 00946 return 0; 00947 } 00948 00949 00950 /*! 00951 * pixcmapGetNearestGrayIndex() 00952 * 00953 * Input: cmap 00954 * val (gray value to search for; in range [0, ... 255]) 00955 * &index (<return> the index of the nearest color) 00956 * Return: 0 if OK, 1 on error (caller must check) 00957 * 00958 * Notes: 00959 * (1) This should be used on gray colormaps. It uses only the 00960 * green value of the colormap. 00961 * (2) Returns the index of the exact color if possible, otherwise the 00962 * index of the color closest to the target color. 00963 */ 00964 l_int32 00965 pixcmapGetNearestGrayIndex(PIXCMAP *cmap, 00966 l_int32 val, 00967 l_int32 *pindex) 00968 { 00969 l_int32 i, n, dist, mindist; 00970 RGBA_QUAD *cta; 00971 00972 PROCNAME("pixcmapGetNearestGrayIndex"); 00973 00974 if (!pindex) 00975 return ERROR_INT("&index not defined", procName, 1); 00976 *pindex = 0; 00977 if (!cmap) 00978 return ERROR_INT("cmap not defined", procName, 1); 00979 if (val < 0 || val > 255) 00980 return ERROR_INT("val not in [0 ... 255]", procName, 1); 00981 00982 if ((cta = (RGBA_QUAD *)cmap->array) == NULL) 00983 return ERROR_INT("cta not defined(!)", procName, 1); 00984 n = pixcmapGetCount(cmap); 00985 00986 mindist = 256; 00987 for (i = 0; i < n; i++) { 00988 dist = cta[i].green - val; 00989 dist = L_ABS(dist); 00990 if (dist < mindist) { 00991 *pindex = i; 00992 if (dist == 0) 00993 break; 00994 mindist = dist; 00995 } 00996 } 00997 00998 return 0; 00999 } 01000 01001 01002 /*! 01003 * pixcmapGetComponentRange() 01004 * 01005 * Input: cmap 01006 * color (L_SELECT_RED, L_SELECT_GREEN or L_SELECT_BLUE) 01007 * &minval (<optional return> minimum value of component) 01008 * &maxval (<optional return> minimum value of component) 01009 * Return: 0 if OK, 1 on error 01010 * 01011 * Notes: 01012 * (1) Returns for selected components the extreme value 01013 * (either min or max) of the color component that is 01014 * found in the colormap. 01015 */ 01016 l_int32 01017 pixcmapGetComponentRange(PIXCMAP *cmap, 01018 l_int32 color, 01019 l_int32 *pminval, 01020 l_int32 *pmaxval) 01021 { 01022 PROCNAME("pixcmapGetComponentRange"); 01023 01024 if (pminval) *pminval = 0; 01025 if (pmaxval) *pmaxval = 0; 01026 if (!pminval && !pmaxval) 01027 return ERROR_INT("no result requested", procName, 1); 01028 01029 if (color == L_SELECT_RED) { 01030 pixcmapGetExtremeValue(cmap, L_SELECT_MIN, pminval, NULL, NULL); 01031 pixcmapGetExtremeValue(cmap, L_SELECT_MAX, pmaxval, NULL, NULL); 01032 } 01033 else if (color == L_SELECT_GREEN) { 01034 pixcmapGetExtremeValue(cmap, L_SELECT_MIN, NULL, pminval, NULL); 01035 pixcmapGetExtremeValue(cmap, L_SELECT_MAX, NULL, pmaxval, NULL); 01036 } 01037 else if (color == L_SELECT_BLUE) { 01038 pixcmapGetExtremeValue(cmap, L_SELECT_MIN, NULL, NULL, pminval); 01039 pixcmapGetExtremeValue(cmap, L_SELECT_MAX, NULL, NULL, pmaxval); 01040 } 01041 else 01042 return ERROR_INT("invalid color", procName, 1); 01043 01044 return 0; 01045 } 01046 01047 01048 /*! 01049 * pixcmapGetExtremeValue() 01050 * 01051 * Input: cmap 01052 * type (L_SELECT_MIN or L_SELECT_MAX) 01053 * &rval (<optional return> red component) 01054 * &gval (<optional return> green component) 01055 * &bval (<optional return> blue component) 01056 * Return: 0 if OK, 1 on error 01057 * 01058 * Notes: 01059 * (1) Returns for selected components the extreme value 01060 * (either min or max) of the color component that is 01061 * found in the colormap. 01062 */ 01063 l_int32 01064 pixcmapGetExtremeValue(PIXCMAP *cmap, 01065 l_int32 type, 01066 l_int32 *prval, 01067 l_int32 *pgval, 01068 l_int32 *pbval) 01069 { 01070 l_int32 i, n, rval, gval, bval, extrval, extgval, extbval; 01071 01072 PROCNAME("pixcmapGetExtremeValue"); 01073 01074 if (!prval && !pgval && !pbval) 01075 return ERROR_INT("no result requested for return", procName, 1); 01076 if (prval) *prval = 0; 01077 if (pgval) *pgval = 0; 01078 if (pbval) *pbval = 0; 01079 if (!cmap) 01080 return ERROR_INT("cmap not defined", procName, 1); 01081 if (type != L_SELECT_MIN && type != L_SELECT_MAX) 01082 return ERROR_INT("invalid type", procName, 1); 01083 01084 if (type == L_SELECT_MIN) { 01085 extrval = 100000; 01086 extgval = 100000; 01087 extbval = 100000; 01088 } 01089 else { 01090 extrval = 0; 01091 extgval = 0; 01092 extbval = 0; 01093 } 01094 01095 n = pixcmapGetCount(cmap); 01096 for (i = 0; i < n; i++) { 01097 pixcmapGetColor(cmap, i, &rval, &gval, &bval); 01098 if ((type == L_SELECT_MIN && rval < extrval) || 01099 (type == L_SELECT_MAX && rval > extrval)) 01100 extrval = rval; 01101 if ((type == L_SELECT_MIN && gval < extgval) || 01102 (type == L_SELECT_MAX && gval > extgval)) 01103 extgval = gval; 01104 if ((type == L_SELECT_MIN && bval < extbval) || 01105 (type == L_SELECT_MAX && bval > extbval)) 01106 extbval = bval; 01107 } 01108 if (prval) *prval = extrval; 01109 if (pgval) *pgval = extgval; 01110 if (pbval) *pbval = extbval; 01111 return 0; 01112 } 01113 01114 01115 /*-------------------------------------------------------------* 01116 * Colormap conversion * 01117 *-------------------------------------------------------------*/ 01118 /*! 01119 * pixcmapGrayToColor() 01120 * 01121 * Input: color 01122 * Return: cmap, or null on error 01123 * 01124 * Notes: 01125 * (1) This creates a colormap that maps from gray to 01126 * a specific color. In the mapping, each component 01127 * is faded to white, depending on the gray value. 01128 * (2) In use, this is simply attached to a grayscale pix 01129 * to give it the input color. 01130 */ 01131 PIXCMAP * 01132 pixcmapGrayToColor(l_uint32 color) 01133 { 01134 l_int32 i, rval, gval, bval; 01135 PIXCMAP *cmap; 01136 01137 extractRGBValues(color, &rval, &gval, &bval); 01138 cmap = pixcmapCreate(8); 01139 for (i = 0; i < 256; i++) { 01140 pixcmapAddColor(cmap, rval + (i * (255 - rval)) / 255, 01141 gval + (i * (255 - gval)) / 255, 01142 bval + (i * (255 - bval)) / 255); 01143 } 01144 01145 return cmap; 01146 } 01147 01148 01149 /*! 01150 * pixcmapColorToGray() 01151 * 01152 * Input: cmap 01153 * rwt, gwt, bwt (non-negative; these should add to 1.0) 01154 * Return: cmap (gray), or null on error 01155 * 01156 * Notes: 01157 * (1) This creates a gray colormap from an arbitrary colormap. 01158 * (2) In use, attach the output gray colormap to the pix 01159 * (or a copy of it) that provided the input colormap. 01160 */ 01161 PIXCMAP * 01162 pixcmapColorToGray(PIXCMAP *cmaps, 01163 l_float32 rwt, 01164 l_float32 gwt, 01165 l_float32 bwt) 01166 { 01167 l_int32 i, n, rval, gval, bval, val; 01168 l_float32 sum; 01169 PIXCMAP *cmapd; 01170 01171 PROCNAME("pixcmapColorToGray"); 01172 01173 if (!cmaps) 01174 return (PIXCMAP *)ERROR_PTR("cmaps not defined", procName, NULL); 01175 if (rwt < 0.0 || gwt < 0.0 || bwt < 0.0) 01176 return (PIXCMAP *)ERROR_PTR("weights not all >= 0.0", procName, NULL); 01177 01178 /* Make sure the sum of weights is 1.0; otherwise, you can get 01179 * overflow in the gray value. */ 01180 sum = rwt + gwt + bwt; 01181 if (sum == 0.0) { 01182 L_WARNING("all weights zero; setting equal to 1/3", procName); 01183 rwt = gwt = bwt = 0.33333; 01184 sum = 1.0; 01185 } 01186 if (L_ABS(sum - 1.0) > 0.0001) { /* maintain ratios with sum == 1.0 */ 01187 L_WARNING("weights don't sum to 1; maintaining ratios", procName); 01188 rwt = rwt / sum; 01189 gwt = gwt / sum; 01190 bwt = bwt / sum; 01191 } 01192 01193 cmapd = pixcmapCopy(cmaps); 01194 n = pixcmapGetCount(cmapd); 01195 for (i = 0; i < n; i++) { 01196 pixcmapGetColor(cmapd, i, &rval, &gval, &bval); 01197 val = (l_int32)(rwt * rval + gwt * gval + bwt * bval + 0.5); 01198 pixcmapResetColor(cmapd, i, val, val, val); 01199 } 01200 01201 return cmapd; 01202 } 01203 01204 01205 /*-------------------------------------------------------------* 01206 * Colormap I/O * 01207 *-------------------------------------------------------------*/ 01208 /*! 01209 * pixcmapReadStream() 01210 * 01211 * Input: stream 01212 * Return: cmap, or null on error 01213 */ 01214 PIXCMAP * 01215 pixcmapReadStream(FILE *fp) 01216 { 01217 l_int32 rval, gval, bval, ignore; 01218 l_int32 i, index, ret, depth, ncolors; 01219 PIXCMAP *cmap; 01220 01221 PROCNAME("pixcmapReadStream"); 01222 01223 if (!fp) 01224 return (PIXCMAP *)ERROR_PTR("stream not defined", procName, NULL); 01225 01226 ret = fscanf(fp, "\nPixcmap: depth = %d bpp; %d colors\n", 01227 &depth, &ncolors); 01228 if (ret != 2 || 01229 (depth != 1 && depth != 2 && depth != 4 && depth != 8) || 01230 (ncolors < 2 || ncolors > 256)) 01231 return (PIXCMAP *)ERROR_PTR("invalid cmap size", procName, NULL); 01232 ignore = fscanf(fp, "Color R-val G-val B-val\n"); 01233 ignore = fscanf(fp, "--------------------------------\n"); 01234 01235 if ((cmap = pixcmapCreate(depth)) == NULL) 01236 return (PIXCMAP *)ERROR_PTR("cmap not made", procName, NULL); 01237 for (i = 0; i < ncolors; i++) { 01238 if (fscanf(fp, "%3d %3d %3d %3d\n", 01239 &index, &rval, &gval, &bval) != 4) 01240 return (PIXCMAP *)ERROR_PTR("invalid entry", procName, NULL); 01241 pixcmapAddColor(cmap, rval, gval, bval); 01242 } 01243 01244 return cmap; 01245 } 01246 01247 01248 /*! 01249 * pixcmapWriteStream() 01250 * 01251 * Input: stream, cmap 01252 * Return: 0 if OK, 1 on error 01253 */ 01254 l_int32 01255 pixcmapWriteStream(FILE *fp, 01256 PIXCMAP *cmap) 01257 { 01258 l_int32 *rmap, *gmap, *bmap; 01259 l_int32 i; 01260 01261 PROCNAME("pixcmapWriteStream"); 01262 01263 if (!fp) 01264 return ERROR_INT("stream not defined", procName, 1); 01265 if (!cmap) 01266 return ERROR_INT("cmap not defined", procName, 1); 01267 01268 if (pixcmapToArrays(cmap, &rmap, &gmap, &bmap)) 01269 return ERROR_INT("colormap arrays not made", procName, 1); 01270 01271 fprintf(fp, "\nPixcmap: depth = %d bpp; %d colors\n", cmap->depth, cmap->n); 01272 fprintf(fp, "Color R-val G-val B-val\n"); 01273 fprintf(fp, "--------------------------------\n"); 01274 for (i = 0; i < cmap->n; i++) 01275 fprintf(fp, "%3d %3d %3d %3d\n", 01276 i, rmap[i], gmap[i], bmap[i]); 01277 fprintf(fp, "\n"); 01278 01279 FREE(rmap); 01280 FREE(gmap); 01281 FREE(bmap); 01282 return 0; 01283 } 01284 01285 01286 /*----------------------------------------------------------------------* 01287 * Extract colormap arrays and serialization * 01288 *----------------------------------------------------------------------*/ 01289 /*! 01290 * pixcmapToArrays() 01291 * 01292 * Input: colormap 01293 * &rmap, &gmap, &bmap (<return> colormap arrays) 01294 * Return: 0 if OK; 1 on error 01295 */ 01296 l_int32 01297 pixcmapToArrays(PIXCMAP *cmap, 01298 l_int32 **prmap, 01299 l_int32 **pgmap, 01300 l_int32 **pbmap) 01301 { 01302 l_int32 *rmap, *gmap, *bmap; 01303 l_int32 i, ncolors; 01304 RGBA_QUAD *cta; 01305 01306 PROCNAME("pixcmapToArrays"); 01307 01308 if (!prmap || !pgmap || !pbmap) 01309 return ERROR_INT("&rmap, &gmap, &bmap not all defined", procName, 1); 01310 *prmap = *pgmap = *pbmap = NULL; 01311 if (!cmap) 01312 return ERROR_INT("cmap not defined", procName, 1); 01313 01314 ncolors = pixcmapGetCount(cmap); 01315 if (((rmap = (l_int32 *)CALLOC(ncolors, sizeof(l_int32))) == NULL) || 01316 ((gmap = (l_int32 *)CALLOC(ncolors, sizeof(l_int32))) == NULL) || 01317 ((bmap = (l_int32 *)CALLOC(ncolors, sizeof(l_int32))) == NULL)) 01318 return ERROR_INT("calloc fail for *map", procName, 1); 01319 *prmap = rmap; 01320 *pgmap = gmap; 01321 *pbmap = bmap; 01322 01323 cta = (RGBA_QUAD *)cmap->array; 01324 for (i = 0; i < ncolors; i++) { 01325 rmap[i] = cta[i].red; 01326 gmap[i] = cta[i].green; 01327 bmap[i] = cta[i].blue; 01328 } 01329 01330 return 0; 01331 } 01332 01333 01334 /*! 01335 * pixcmapToRGBTable() 01336 * 01337 * Input: colormap 01338 * &tab (<return> table of rgba values for the colormap) 01339 * &ncolors (<optional return> size of table) 01340 * Return: 0 if OK; 1 on error 01341 */ 01342 l_int32 01343 pixcmapToRGBTable(PIXCMAP *cmap, 01344 l_uint32 **ptab, 01345 l_int32 *pncolors) 01346 { 01347 l_int32 i, ncolors, rval, gval, bval; 01348 l_uint32 *tab; 01349 01350 PROCNAME("pixcmapToRGBTable"); 01351 01352 if (!ptab) 01353 return ERROR_INT("&tab not defined", procName, 1); 01354 *ptab = NULL; 01355 if (!cmap) 01356 return ERROR_INT("cmap not defined", procName, 1); 01357 01358 ncolors = pixcmapGetCount(cmap); 01359 if (pncolors) 01360 *pncolors = ncolors; 01361 if ((tab = (l_uint32 *)CALLOC(ncolors, sizeof(l_uint32))) == NULL) 01362 return ERROR_INT("tab not made", procName, 1); 01363 *ptab = tab; 01364 01365 for (i = 0; i < ncolors; i++) { 01366 pixcmapGetColor(cmap, i, &rval, &gval, &bval); 01367 composeRGBPixel(rval, gval, bval, &tab[i]); 01368 } 01369 01370 /* for (i = 0; i < ncolors; i++) 01371 fprintf(stderr, "Color[%d] = %x\n", i, tab[i]); */ 01372 01373 return 0; 01374 } 01375 01376 01377 /*! 01378 * pixcmapSerializeToMemory() 01379 * 01380 * Input: colormap 01381 * cpc (components/color: 3 for rgb, 4 for rgba) 01382 * &ncolors (<return> number of colors in table) 01383 * &data (<return> binary string, 3 or 4 bytes per color) 01384 * &nbytes (<return> size of data) 01385 * Return: 0 if OK; 1 on error 01386 * 01387 * Notes: 01388 * (1) If @cpc == 4, we leave room for the alpha channel 01389 * value in each color entry, but it is set to 0. 01390 */ 01391 l_int32 01392 pixcmapSerializeToMemory(PIXCMAP *cmap, 01393 l_int32 cpc, 01394 l_int32 *pncolors, 01395 l_uint8 **pdata, 01396 l_int32 *pnbytes) 01397 { 01398 l_int32 i, ncolors, rval, gval, bval; 01399 l_uint8 *data; 01400 01401 PROCNAME("pixcmapSerializeToMemory"); 01402 01403 if (!pdata) 01404 return ERROR_INT("&data not defined", procName, 1); 01405 *pdata = NULL; 01406 if (!pncolors || !pnbytes) 01407 return ERROR_INT("&ncolors and &nbytes not defined", procName, 1); 01408 *pncolors = *pnbytes = 0; 01409 if (!cmap) 01410 return ERROR_INT("cmap not defined", procName, 1); 01411 if (cpc != 3 && cpc != 4) 01412 return ERROR_INT("cpc not 3 or 4", procName, 1); 01413 01414 ncolors = pixcmapGetCount(cmap); 01415 *pncolors = ncolors; 01416 *pnbytes = cpc * ncolors; 01417 if ((data = (l_uint8 *)CALLOC(cpc * ncolors, sizeof(l_uint8))) == NULL) 01418 return ERROR_INT("data not made", procName, 1); 01419 *pdata = data; 01420 01421 for (i = 0; i < ncolors; i++) { 01422 pixcmapGetColor(cmap, i, &rval, &gval, &bval); 01423 data[cpc * i] = rval; 01424 data[cpc * i + 1] = gval; 01425 data[cpc * i + 2] = bval; 01426 } 01427 return 0; 01428 } 01429 01430 01431 /*! 01432 * pixcmapDeserializeFromMemory() 01433 * 01434 * Input: data (binary string, 3 or 4 bytes per color) 01435 * ncolors 01436 * nbytes (size of returned data) 01437 * Return: cmap, or null on error 01438 */ 01439 PIXCMAP * 01440 pixcmapDeserializeFromMemory(l_uint8 *data, 01441 l_int32 ncolors, 01442 l_int32 nbytes) 01443 { 01444 l_int32 i, cpc, d, rval, gval, bval; 01445 PIXCMAP *cmap; 01446 01447 PROCNAME("pixcmapDeserializeFromMemory"); 01448 01449 if (!data) 01450 return (PIXCMAP *)ERROR_PTR("data not defined", procName, NULL); 01451 if (nbytes == 0 || ncolors == 0) 01452 return (PIXCMAP *)ERROR_PTR("no entries", procName, NULL); 01453 if (ncolors > 256) 01454 return (PIXCMAP *)ERROR_PTR("ncolors > 256", procName, NULL); 01455 if (nbytes == 3 * ncolors) 01456 cpc = 3; 01457 else if (nbytes == 4 * ncolors) 01458 cpc = 4; 01459 else /* there must be either 3 or 4 bytes for each color */ 01460 return (PIXCMAP *)ERROR_PTR("invalid table size", procName, NULL); 01461 01462 if (ncolors > 16) 01463 d = 8; 01464 else if (ncolors > 4) 01465 d = 4; 01466 else if (ncolors > 2) 01467 d = 2; 01468 else 01469 d = 1; 01470 cmap = pixcmapCreate(d); 01471 for (i = 0; i < ncolors; i++) { 01472 rval = data[cpc * i]; 01473 gval = data[cpc * i + 1]; 01474 bval = data[cpc * i + 2]; 01475 pixcmapAddColor(cmap, rval, gval, bval); 01476 } 01477 01478 return cmap; 01479 } 01480 01481 01482 /*! 01483 * pixcmapConvertToHex() 01484 * 01485 * Input: data (binary serialized data) 01486 * nbytes (size of data) 01487 * ncolors (in colormap) 01488 * Return: hexdata (bracketed, space-separated ascii hex string), 01489 * or null on error. 01490 * 01491 * Notes: 01492 * (1) If rgb, there are 3 colors/component; if rgba, there are 4. 01493 * (2) Output is in form: 01494 * < r0g0b0 r1g1b1 ... rngnbn > 01495 * where r0, g0, b0, ... are each 2 bytes of hex ascii 01496 * (3) This is used in pdf files to express the colormap as an 01497 * array in ascii (human-readable) format. 01498 */ 01499 char * 01500 pixcmapConvertToHex(l_uint8 *data, 01501 l_int32 nbytes, 01502 l_int32 ncolors) 01503 { 01504 l_int32 i, j, hexbytes; 01505 l_int32 cpc; /* colors per component */ 01506 char *hexdata = NULL; 01507 char buf[4]; 01508 01509 PROCNAME("pixcmapConvertToHex"); 01510 01511 if (!data) 01512 return (char *)ERROR_PTR("data not defined", procName, NULL); 01513 if (ncolors < 1) 01514 return (char *)ERROR_PTR("no colors", procName, NULL); 01515 01516 cpc = nbytes / ncolors; 01517 if (cpc != 3 && cpc != 4) 01518 return (char *)ERROR_PTR("cpc not 3 or 4", procName, NULL); 01519 01520 hexbytes = 2 + (2 * cpc + 1) * ncolors + 2; 01521 hexdata = (char *)CALLOC(hexbytes, sizeof(char)); 01522 hexdata[0] = '<'; 01523 hexdata[1] = ' '; 01524 01525 for (i = 0; i < ncolors; i++) { 01526 j = 2 + (2 * cpc + 1) * i; 01527 snprintf(buf, sizeof(buf), "%02x", data[cpc * i]); 01528 hexdata[j] = buf[0]; 01529 hexdata[j + 1] = buf[1]; 01530 snprintf(buf, sizeof(buf), "%02x", data[cpc * i + 1]); 01531 hexdata[j + 2] = buf[0]; 01532 hexdata[j + 3] = buf[1]; 01533 snprintf(buf, sizeof(buf), "%02x", data[cpc * i + 2]); 01534 hexdata[j + 4] = buf[0]; 01535 hexdata[j + 5] = buf[1]; 01536 hexdata[j + 6] = ' '; 01537 } 01538 hexdata[j + 7] = '>'; 01539 hexdata[j + 8] = '\0'; 01540 return hexdata; 01541 } 01542 01543 01544 /*-------------------------------------------------------------* 01545 * Colormap transforms * 01546 *-------------------------------------------------------------*/ 01547 /*! 01548 * pixcmapGammaTRC() 01549 * 01550 * Input: colormap 01551 * gamma (gamma correction; must be > 0.0) 01552 * minval (input value that gives 0 for output; can be < 0) 01553 * maxval (input value that gives 255 for output; can be > 255) 01554 * Return: 0 if OK; 1 on error 01555 * 01556 * Notes: 01557 * - in-place transform 01558 * - see pixGammaTRC() and numaGammaTRC() in enhance.c for 01559 * description and use of transform 01560 */ 01561 l_int32 01562 pixcmapGammaTRC(PIXCMAP *cmap, 01563 l_float32 gamma, 01564 l_int32 minval, 01565 l_int32 maxval) 01566 { 01567 l_int32 rval, gval, bval, trval, tgval, tbval, i, ncolors; 01568 NUMA *nag; 01569 01570 PROCNAME("pixcmapGammaTRC"); 01571 01572 if (!cmap) 01573 return ERROR_INT("cmap not defined", procName, 1); 01574 if (gamma <= 0.0) { 01575 L_WARNING("gamma must be > 0.0; setting to 1.0", procName); 01576 gamma = 1.0; 01577 } 01578 if (minval >= maxval) 01579 return ERROR_INT("minval not < maxval", procName, 1); 01580 01581 if (gamma == 1.0 && minval == 0 && maxval == 255) /* no-op */ 01582 return 0; 01583 01584 if ((nag = numaGammaTRC(gamma, minval, maxval)) == NULL) 01585 return ERROR_INT("nag not made", procName, 1); 01586 01587 ncolors = pixcmapGetCount(cmap); 01588 for (i = 0; i < ncolors; i++) { 01589 pixcmapGetColor(cmap, i, &rval, &gval, &bval); 01590 numaGetIValue(nag, rval, &trval); 01591 numaGetIValue(nag, gval, &tgval); 01592 numaGetIValue(nag, bval, &tbval); 01593 pixcmapResetColor(cmap, i, trval, tgval, tbval); 01594 } 01595 01596 numaDestroy(&nag); 01597 return 0; 01598 } 01599 01600 01601 /*! 01602 * pixcmapContrastTRC() 01603 * 01604 * Input: colormap 01605 * factor (generally between 0.0 (no enhancement) 01606 * and 1.0, but can be larger than 1.0) 01607 * Return: 0 if OK; 1 on error 01608 * 01609 * Notes: 01610 * - in-place transform 01611 * - see pixContrastTRC() and numaContrastTRC() in enhance.c for 01612 * description and use of transform 01613 */ 01614 l_int32 01615 pixcmapContrastTRC(PIXCMAP *cmap, 01616 l_float32 factor) 01617 { 01618 l_int32 i, ncolors, rval, gval, bval, trval, tgval, tbval; 01619 NUMA *nac; 01620 01621 PROCNAME("pixcmapContrastTRC"); 01622 01623 if (!cmap) 01624 return ERROR_INT("cmap not defined", procName, 1); 01625 if (factor < 0.0) { 01626 L_WARNING("factor must be >= 0.0; setting to 0.0", procName); 01627 factor = 0.0; 01628 } 01629 01630 if ((nac = numaContrastTRC(factor)) == NULL) 01631 return ERROR_INT("nac not made", procName, 1); 01632 01633 ncolors = pixcmapGetCount(cmap); 01634 for (i = 0; i < ncolors; i++) { 01635 pixcmapGetColor(cmap, i, &rval, &gval, &bval); 01636 numaGetIValue(nac, rval, &trval); 01637 numaGetIValue(nac, gval, &tgval); 01638 numaGetIValue(nac, bval, &tbval); 01639 pixcmapResetColor(cmap, i, trval, tgval, tbval); 01640 } 01641 01642 numaDestroy(&nac); 01643 return 0; 01644 } 01645 01646 01647 /*! 01648 * pixcmapShiftIntensity() 01649 * 01650 * Input: colormap 01651 * fraction (between -1.0 and +1.0) 01652 * Return: 0 if OK; 1 on error 01653 * 01654 * Notes: 01655 * - in-place transform 01656 * - This does a proportional shift of the intensity for each color. 01657 * - If fraction < 0.0, it moves all colors towards (0,0,0). 01658 * This darkens the image. 01659 * - If fraction > 0.0, it moves all colors towards (255,255,255) 01660 * This fades the image. 01661 * - The equivalent transform can be accomplished with pixcmapGammaTRC(), 01662 * but it is considerably more difficult (see numaGammaTRC()). 01663 */ 01664 l_int32 01665 pixcmapShiftIntensity(PIXCMAP *cmap, 01666 l_float32 fraction) 01667 { 01668 l_int32 i, ncolors, rval, gval, bval; 01669 01670 PROCNAME("pixcmapShiftIntensity"); 01671 01672 if (!cmap) 01673 return ERROR_INT("cmap not defined", procName, 1); 01674 if (fraction < -1.0 || fraction > 1.0) 01675 return ERROR_INT("fraction not in [-1.0, 1.0]", procName, 1); 01676 01677 ncolors = pixcmapGetCount(cmap); 01678 for (i = 0; i < ncolors; i++) { 01679 pixcmapGetColor(cmap, i, &rval, &gval, &bval); 01680 if (fraction < 0.0) 01681 pixcmapResetColor(cmap, i, 01682 (l_int32)((1.0 + fraction) * rval), 01683 (l_int32)((1.0 + fraction) * gval), 01684 (l_int32)((1.0 + fraction) * bval)); 01685 else 01686 pixcmapResetColor(cmap, i, 01687 rval + (l_int32)(fraction * (255 - rval)), 01688 gval + (l_int32)(fraction * (255 - gval)), 01689 bval + (l_int32)(fraction * (255 - bval))); 01690 } 01691 01692 return 0; 01693 } 01694