Leptonica 1.68
C Image Processing Library

colormap.c

Go to the documentation of this file.
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 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines