Leptonica 1.68
C Image Processing Library

pixconv.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  *  pixconv.c
00018  *
00019  *      These functions convert between images of different types
00020  *      without scaling.
00021  *
00022  *      Conversion from 8 bpp grayscale to 1, 2, 4 and 8 bpp
00023  *           PIX        *pixThreshold8()
00024  *
00025  *      Conversion from colormap to full color or grayscale
00026  *           PIX        *pixRemoveColormap()
00027  *
00028  *      Add colormap losslessly (8 to 8)
00029  *           l_int32     pixAddGrayColormap8()
00030  *           PIX        *pixAddMinimalGrayColormap8()
00031  *
00032  *      Conversion from RGB color to grayscale
00033  *           PIX        *pixConvertRGBToLuminance()
00034  *           PIX        *pixConvertRGBToGray()
00035  *           PIX        *pixConvertRGBToGrayFast()
00036  *           PIX        *pixConvertRGBToGrayMinMax()
00037  *
00038  *      Conversion from grayscale to colormap
00039  *           PIX        *pixConvertGrayToColormap()  -- 2, 4, 8 bpp
00040  *           PIX        *pixConvertGrayToColormap8()  -- 8 bpp only
00041  *
00042  *      Colorizing conversion from grayscale to color
00043  *           PIX        *pixColorizeGray()  -- 8 bpp or cmapped
00044  *
00045  *      Conversion from RGB color to colormap
00046  *           PIX        *pixConvertRGBToColormap()
00047  *
00048  *      Quantization for relatively small number of colors in source
00049  *           l_int32     pixQuantizeIfFewColors()
00050  *
00051  *      Conversion from 16 bpp to 8 bpp
00052  *           PIX        *pixConvert16To8()
00053  *
00054  *      Conversion from grayscale to false color
00055  *           PIX        *pixConvertGrayToFalseColor()
00056  *
00057  *      Unpacking conversion from 1 bpp to 2, 4, 8, 16 and 32 bpp
00058  *           PIX        *pixUnpackBinary()
00059  *           PIX        *pixConvert1To16()
00060  *           PIX        *pixConvert1To32()
00061  *
00062  *      Unpacking conversion from 1 bpp to 2 bpp
00063  *           PIX        *pixConvert1To2Cmap()
00064  *           PIX        *pixConvert1To2()
00065  *
00066  *      Unpacking conversion from 1 bpp to 4 bpp
00067  *           PIX        *pixConvert1To4Cmap()
00068  *           PIX        *pixConvert1To4()
00069  *
00070  *      Unpacking conversion from 1, 2 and 4 bpp to 8 bpp
00071  *           PIX        *pixConvert1To8()
00072  *           PIX        *pixConvert2To8()
00073  *           PIX        *pixConvert4To8()
00074  *
00075  *      Unpacking conversion from 8 bpp to 16 bpp
00076  *           PIX        *pixConvert8To16()
00077  *
00078  *      Top-level conversion to 1 bpp
00079  *           PIX        *pixConvertTo1()
00080  *           PIX        *pixConvertTo1BySampling()
00081  *
00082  *      Top-level conversion to 8 bpp
00083  *           PIX        *pixConvertTo8()
00084  *           PIX        *pixConvertTo8BySampling()
00085  *
00086  *      Top-level conversion to 16 bpp
00087  *           PIX        *pixConvertTo16()
00088  *
00089  *      Top-level conversion to 32 bpp (RGB)
00090  *           PIX        *pixConvertTo32()   ***
00091  *           PIX        *pixConvertTo32BySampling()   ***
00092  *           PIX        *pixConvert8To32()  ***
00093  *
00094  *      Top-level conversion to 8 or 32 bpp, without colormap
00095  *           PIX        *pixConvertTo8Or32
00096  *
00097  *      Conversion between 24 bpp and 32 bpp rgb
00098  *           PIX        *pixConvert24To32()
00099  *           PIX        *pixConvert32To24()
00100  *
00101  *      Lossless depth conversion (unpacking)
00102  *           PIX        *pixConvertLossless()
00103  *
00104  *      Conversion for printing in PostScript
00105  *           PIX        *pixConvertForPSWrap()
00106  *
00107  *      Scaling conversion to subpixel RGB
00108  *           PIX        *pixConvertToSubpixelRGB()
00109  *           PIX        *pixConvertGrayToSubpixelRGB()
00110  *           PIX        *pixConvertColorToSubpixelRGB()
00111  *
00112  *      *** indicates implicit assumption about RGB component ordering
00113  */
00114 
00115 #include <string.h>
00116 #include <math.h>
00117 #include "allheaders.h"
00118 
00119 #ifndef  NO_CONSOLE_IO
00120 #define DEBUG_CONVERT_TO_COLORMAP  0
00121 #define DEBUG_UNROLLING 0
00122 #endif   /* ~NO_CONSOLE_IO */
00123 
00124 
00125 /*-------------------------------------------------------------*
00126  *     Conversion from 8 bpp grayscale to 1, 2 4 and 8 bpp     *
00127  *-------------------------------------------------------------*/
00128 /*!
00129  *  pixThreshold8()
00130  *
00131  *      Input:  pix (8 bpp grayscale)
00132  *              d (destination depth: 1, 2, 4 or 8)
00133  *              nlevels (number of levels to be used for colormap)
00134  *              cmapflag (1 if makes colormap; 0 otherwise)
00135  *      Return: pixd (thresholded with standard dest thresholds),
00136  *              or null on error
00137  *
00138  *  Notes:
00139  *      (1) This uses, by default, equally spaced "target" values
00140  *          that depend on the number of levels, with thresholds
00141  *          halfway between.  For N levels, with separation (N-1)/255,
00142  *          there are N-1 fixed thresholds.
00143  *      (2) For 1 bpp destination, the number of levels can only be 2
00144  *          and if a cmap is made, black is (0,0,0) and white
00145  *          is (255,255,255), which is opposite to the convention
00146  *          without a colormap.
00147  *      (3) For 1, 2 and 4 bpp, the nlevels arg is used if a colormap
00148  *          is made; otherwise, we take the most significant bits
00149  *          from the src that will fit in the dest.
00150  *      (4) For 8 bpp, the input pixs is quantized to nlevels.  The
00151  *          dest quantized with that mapping, either through a colormap
00152  *          table or directly with 8 bit values.
00153  *      (5) Typically you should not use make a colormap for 1 bpp dest.
00154  *      (6) This is not dithering.  Each pixel is treated independently.
00155  */
00156 PIX *
00157 pixThreshold8(PIX     *pixs,
00158               l_int32  d,
00159               l_int32  nlevels,
00160               l_int32  cmapflag)
00161 {
00162 PIX       *pixd;
00163 PIXCMAP   *cmap;
00164 
00165     PROCNAME("pixThreshold8");
00166 
00167     if (!pixs)
00168         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00169     if (pixGetDepth(pixs) != 8)
00170         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
00171     if (cmapflag && nlevels < 2)
00172         return (PIX *)ERROR_PTR("nlevels must be at least 2", procName, NULL);
00173 
00174     switch (d) {
00175     case 1:
00176         pixd = pixThresholdToBinary(pixs, 128);
00177         if (cmapflag) {
00178             cmap = pixcmapCreateLinear(1, 2);
00179             pixSetColormap(pixd, cmap);
00180         }
00181         break;
00182     case 2:
00183         pixd = pixThresholdTo2bpp(pixs, nlevels, cmapflag);
00184         break;
00185     case 4:
00186         pixd = pixThresholdTo4bpp(pixs, nlevels, cmapflag);
00187         break;
00188     case 8:
00189         pixd = pixThresholdOn8bpp(pixs, nlevels, cmapflag);
00190         break;
00191     default:
00192         return (PIX *)ERROR_PTR("d must be in {1,2,4,8}", procName, NULL);
00193     }
00194 
00195     if (!pixd)
00196         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00197     return pixd;
00198 }
00199 
00200 
00201 /*-------------------------------------------------------------*
00202  *               Conversion from colormapped pix               *
00203  *-------------------------------------------------------------*/
00204 /*!
00205  *  pixRemoveColormap()
00206  *
00207  *      Input:  pixs (see restrictions below)
00208  *              type (REMOVE_CMAP_TO_BINARY,
00209  *                    REMOVE_CMAP_TO_GRAYSCALE,
00210  *                    REMOVE_CMAP_TO_FULL_COLOR,
00211  *                    REMOVE_CMAP_BASED_ON_SRC)
00212  *      Return: new pix, or null on error
00213  *
00214  *  Notes:
00215  *      (1) If there is no colormap, a clone is returned.
00216  *      (2) Otherwise, the input pixs is restricted to 1, 2, 4 or 8 bpp.
00217  *      (3) Use REMOVE_CMAP_TO_BINARY only on 1 bpp pix.
00218  *      (4) For grayscale conversion from RGB, use a weighted average
00219  *          of RGB values, and always return an 8 bpp pix, regardless
00220  *          of whether the input pixs depth is 2, 4 or 8 bpp.
00221  */
00222 PIX *
00223 pixRemoveColormap(PIX     *pixs,
00224                   l_int32  type)
00225 {
00226 l_int32    sval, rval, gval, bval;
00227 l_int32    i, j, k, w, h, d, wpls, wpld, ncolors, count;
00228 l_int32    colorfound;
00229 l_int32   *rmap, *gmap, *bmap, *graymap;
00230 l_uint32  *datas, *lines, *datad, *lined, *lut;
00231 l_uint32   sword, dword;
00232 PIXCMAP   *cmap;
00233 PIX       *pixd;
00234 
00235     PROCNAME("pixRemoveColormap");
00236 
00237     if (!pixs)
00238         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00239     if ((cmap = pixGetColormap(pixs)) == NULL)
00240         return pixClone(pixs);
00241 
00242     if (type != REMOVE_CMAP_TO_BINARY &&
00243         type != REMOVE_CMAP_TO_GRAYSCALE &&
00244         type != REMOVE_CMAP_TO_FULL_COLOR &&
00245         type != REMOVE_CMAP_BASED_ON_SRC) {
00246         L_WARNING("Invalid type; converting based on src", procName);
00247         type = REMOVE_CMAP_BASED_ON_SRC;
00248     }
00249 
00250     pixGetDimensions(pixs, &w, &h, &d);
00251     if (d != 1 && d != 2 && d != 4 && d != 8)
00252         return (PIX *)ERROR_PTR("pixs must be {1,2,4,8} bpp", procName, NULL);
00253 
00254     if (pixcmapToArrays(cmap, &rmap, &gmap, &bmap))
00255         return (PIX *)ERROR_PTR("colormap arrays not made", procName, NULL);
00256 
00257     if (d != 1 && type == REMOVE_CMAP_TO_BINARY) {
00258         L_WARNING("not 1 bpp; can't remove cmap to binary", procName);
00259         type = REMOVE_CMAP_BASED_ON_SRC;
00260     }
00261 
00262     if (type == REMOVE_CMAP_BASED_ON_SRC) {
00263             /* select output type depending on colormap */
00264         pixcmapHasColor(cmap, &colorfound);
00265         if (!colorfound) {
00266             if (d == 1)
00267                 type = REMOVE_CMAP_TO_BINARY;
00268             else
00269                 type = REMOVE_CMAP_TO_GRAYSCALE;
00270         }
00271         else
00272             type = REMOVE_CMAP_TO_FULL_COLOR;
00273     }
00274 
00275     ncolors = pixcmapGetCount(cmap);
00276     datas = pixGetData(pixs);
00277     wpls = pixGetWpl(pixs);
00278     if (type == REMOVE_CMAP_TO_BINARY) {
00279         if ((pixd = pixCopy(NULL, pixs)) == NULL)
00280             return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00281         pixcmapGetColor(cmap, 0, &rval, &gval, &bval);
00282         if (rval == 0)  /* photometrically inverted from standard */
00283             pixInvert(pixd, pixd);
00284         pixDestroyColormap(pixd);
00285     }
00286     else if (type == REMOVE_CMAP_TO_GRAYSCALE) {
00287         if ((pixd = pixCreate(w, h, 8)) == NULL)
00288             return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00289         pixCopyResolution(pixd, pixs);
00290         datad = pixGetData(pixd);
00291         wpld = pixGetWpl(pixd);
00292         if ((graymap = (l_int32 *)CALLOC(ncolors, sizeof(l_int32))) == NULL)
00293             return (PIX *)ERROR_PTR("calloc fail for graymap", procName, NULL);
00294         for (i = 0; i < pixcmapGetCount(cmap); i++) {
00295             graymap[i] = (rmap[i] + 2 * gmap[i] + bmap[i]) / 4;
00296         }
00297         for (i = 0; i < h; i++) {
00298             lines = datas + i * wpls;
00299             lined = datad + i * wpld;
00300             switch (d)   /* depth test above; no default permitted */
00301             {
00302                 case 8:
00303                         /* Unrolled 4x */
00304                     for (j = 0, count = 0; j + 3 < w; j += 4, count++) {
00305                         sword = lines[count];
00306                         dword = (graymap[(sword >> 24) & 0xff] << 24) |
00307                             (graymap[(sword >> 16) & 0xff] << 16) |
00308                             (graymap[(sword >> 8) & 0xff] << 8) |
00309                             graymap[sword & 0xff];
00310                         lined[count] = dword;
00311                     }
00312                         /* Cleanup partial word */
00313                     for (; j < w; j++) {
00314                         sval = GET_DATA_BYTE(lines, j);
00315                         gval = graymap[sval];
00316                         SET_DATA_BYTE(lined, j, gval);
00317                     }
00318 #if DEBUG_UNROLLING
00319 #define CHECK_VALUE(a, b, c) if (GET_DATA_BYTE(a, b) != c) { \
00320     fprintf(stderr, "Error: mismatch at %d, %d vs %d\n", \
00321             j, GET_DATA_BYTE(a, b), c); }
00322                     for (j = 0; j < w; j++) {
00323                         sval = GET_DATA_BYTE(lines, j);
00324                         gval = graymap[sval];
00325                         CHECK_VALUE(lined, j, gval);
00326                     }
00327 #endif
00328                     break;
00329                 case 4:
00330                         /* Unrolled 8x */
00331                     for (j = 0, count = 0; j + 7 < w; j += 8, count++) {
00332                         sword = lines[count];
00333                         dword = (graymap[(sword >> 28) & 0xf] << 24) |
00334                             (graymap[(sword >> 24) & 0xf] << 16) |
00335                             (graymap[(sword >> 20) & 0xf] << 8) |
00336                             graymap[(sword >> 16) & 0xf];
00337                         lined[2 * count] = dword;
00338                         dword = (graymap[(sword >> 12) & 0xf] << 24) |
00339                             (graymap[(sword >> 8) & 0xf] << 16) |
00340                             (graymap[(sword >> 4) & 0xf] << 8) |
00341                             graymap[sword & 0xf];
00342                         lined[2 * count + 1] = dword;
00343                     }
00344                         /* Cleanup partial word */
00345                     for (; j < w; j++) {
00346                         sval = GET_DATA_QBIT(lines, j);
00347                         gval = graymap[sval];
00348                         SET_DATA_BYTE(lined, j, gval);
00349                     }
00350 #if DEBUG_UNROLLING
00351                     for (j = 0; j < w; j++) {
00352                         sval = GET_DATA_QBIT(lines, j);
00353                         gval = graymap[sval];
00354                         CHECK_VALUE(lined, j, gval);
00355                     }
00356 #endif
00357                     break;
00358                 case 2:
00359                         /* Unrolled 16x */
00360                     for (j = 0, count = 0; j + 15 < w; j += 16, count++) {
00361                         sword = lines[count];
00362                         dword = (graymap[(sword >> 30) & 0x3] << 24) |
00363                             (graymap[(sword >> 28) & 0x3] << 16) |
00364                             (graymap[(sword >> 26) & 0x3] << 8) |
00365                             graymap[(sword >> 24) & 0x3];
00366                         lined[4 * count] = dword;
00367                         dword = (graymap[(sword >> 22) & 0x3] << 24) |
00368                             (graymap[(sword >> 20) & 0x3] << 16) |
00369                             (graymap[(sword >> 18) & 0x3] << 8) |
00370                             graymap[(sword >> 16) & 0x3];
00371                         lined[4 * count + 1] = dword;
00372                         dword = (graymap[(sword >> 14) & 0x3] << 24) |
00373                             (graymap[(sword >> 12) & 0x3] << 16) |
00374                             (graymap[(sword >> 10) & 0x3] << 8) |
00375                             graymap[(sword >> 8) & 0x3];
00376                         lined[4 * count + 2] = dword;
00377                         dword = (graymap[(sword >> 6) & 0x3] << 24) |
00378                             (graymap[(sword >> 4) & 0x3] << 16) |
00379                             (graymap[(sword >> 2) & 0x3] << 8) |
00380                             graymap[sword & 0x3];
00381                         lined[4 * count + 3] = dword;
00382                     }
00383                         /* Cleanup partial word */
00384                     for (; j < w; j++) {
00385                         sval = GET_DATA_DIBIT(lines, j);
00386                         gval = graymap[sval];
00387                         SET_DATA_BYTE(lined, j, gval);
00388                     }
00389 #if DEBUG_UNROLLING
00390                     for (j = 0; j < w; j++) {
00391                         sval = GET_DATA_DIBIT(lines, j);
00392                         gval = graymap[sval];
00393                         CHECK_VALUE(lined, j, gval);
00394                     }
00395 #endif
00396                     break;
00397                 case 1:
00398                         /* Unrolled 8x */
00399                     for (j = 0, count = 0; j + 31 < w; j += 32, count++) {
00400                         sword = lines[count];
00401                         for (k = 0; k < 4; k++) {
00402                                 /* The top byte is always the relevant one */
00403                             dword = (graymap[(sword >> 31) & 0x1] << 24) |
00404                                 (graymap[(sword >> 30) & 0x1] << 16) |
00405                                 (graymap[(sword >> 29) & 0x1] << 8) |
00406                                 graymap[(sword >> 28) & 0x1];
00407                             lined[8 * count + 2 * k] = dword;
00408                             dword = (graymap[(sword >> 27) & 0x1] << 24) |
00409                                 (graymap[(sword >> 26) & 0x1] << 16) |
00410                                 (graymap[(sword >> 25) & 0x1] << 8) |
00411                                 graymap[(sword >> 24) & 0x1];
00412                             lined[8 * count + 2 * k + 1] = dword;
00413                             sword <<= 8;  /* Move up the next byte */
00414                         }
00415                     }
00416                         /* Cleanup partial word */
00417                     for (; j < w; j++) {
00418                         sval = GET_DATA_BIT(lines, j);
00419                         gval = graymap[sval];
00420                         SET_DATA_BYTE(lined, j, gval);
00421                     }
00422 #if DEBUG_UNROLLING
00423                     for (j = 0; j < w; j++) {
00424                         sval = GET_DATA_BIT(lines, j);
00425                         gval = graymap[sval];
00426                         CHECK_VALUE(lined, j, gval);
00427                     }
00428 #undef CHECK_VALUE
00429 #endif
00430                     break;
00431                 default:
00432                     return NULL;
00433             }
00434         }
00435         if (graymap)
00436             FREE(graymap);
00437     }
00438     else {  /* type == REMOVE_CMAP_TO_FULL_COLOR */
00439         if ((pixd = pixCreate(w, h, 32)) == NULL)
00440             return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00441         pixCopyResolution(pixd, pixs);
00442         datad = pixGetData(pixd);
00443         wpld = pixGetWpl(pixd);
00444         if ((lut = (l_uint32 *)CALLOC(ncolors, sizeof(l_uint32))) == NULL)
00445             return (PIX *)ERROR_PTR("calloc fail for lut", procName, NULL);
00446         for (i = 0; i < ncolors; i++)
00447             composeRGBPixel(rmap[i], gmap[i], bmap[i], lut + i);
00448 
00449         for (i = 0; i < h; i++) {
00450             lines = datas + i * wpls;
00451             lined = datad + i * wpld;
00452             for (j = 0; j < w; j++) {
00453                 if (d == 8)
00454                     sval = GET_DATA_BYTE(lines, j);
00455                 else if (d == 4)
00456                     sval = GET_DATA_QBIT(lines, j);
00457                 else if (d == 2)
00458                     sval = GET_DATA_DIBIT(lines, j);
00459                 else if (d == 1)
00460                     sval = GET_DATA_BIT(lines, j);
00461                 else
00462                     return NULL;
00463                 if (sval >= ncolors)
00464                     L_WARNING("pixel value out of bounds", procName);
00465                 else
00466                     lined[j] = lut[sval];
00467             }
00468         }
00469         FREE(lut);
00470     }
00471 
00472     FREE(rmap);
00473     FREE(gmap);
00474     FREE(bmap);
00475     return pixd;
00476 }
00477 
00478 
00479 /*-------------------------------------------------------------*
00480  *              Add colormap losslessly (8 to 8)               *
00481  *-------------------------------------------------------------*/
00482 /*!
00483  *  pixAddGrayColormap8()
00484  *
00485  *      Input:  pixs (8 bpp)
00486  *      Return: 0 if OK, 1 on error
00487  *
00488  *  Notes:
00489  *      (1) If pixs has a colormap, this is a no-op.
00490  */
00491 l_int32
00492 pixAddGrayColormap8(PIX  *pixs)
00493 {
00494 PIXCMAP  *cmap;
00495 
00496     PROCNAME("pixAddGrayColormap8");
00497 
00498     if (!pixs || pixGetDepth(pixs) != 8)
00499         return ERROR_INT("pixs not defined or not 8 bpp", procName, 1);
00500     if (pixGetColormap(pixs))
00501         return 0;
00502 
00503     cmap = pixcmapCreateLinear(8, 256);
00504     pixSetColormap(pixs, cmap);
00505     return 0;
00506 }
00507 
00508 
00509 /*!
00510  *  pixAddMinimalGrayColormap8()
00511  *
00512  *      Input:  pixs (8 bpp)
00513  *      Return: 0 if OK, 1 on error
00514  *
00515  *  Notes:
00516  *      (1) This generates a colormapped version of the input image
00517  *          that has the same number of colormap entries as the
00518  *          input image has unique gray levels.
00519  */
00520 PIX *
00521 pixAddMinimalGrayColormap8(PIX  *pixs)
00522 {
00523 l_int32    ncolors, w, h, i, j, wplt, wpld, index, val;
00524 l_int32   *inta, *revmap;
00525 l_uint32  *datat, *datad, *linet, *lined;
00526 PIX       *pixt, *pixd;
00527 PIXCMAP   *cmap;
00528 
00529     PROCNAME("pixAddMinimalGrayColormap8");
00530 
00531     if (!pixs || pixGetDepth(pixs) != 8)
00532         return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
00533 
00534         /* Eliminate the easy cases */
00535     pixNumColors(pixs, 1, &ncolors);
00536     cmap = pixGetColormap(pixs);
00537     if (cmap) {
00538         if (pixcmapGetCount(cmap) == ncolors)  /* irreducible */
00539             return pixCopy(NULL, pixs);
00540         else
00541             pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
00542     }
00543     else {
00544         if (ncolors == 256) {
00545             pixt = pixCopy(NULL, pixs);
00546             pixAddGrayColormap8(pixt);
00547             return pixt;
00548         }
00549         pixt = pixClone(pixs);
00550     }
00551 
00552         /* Find the gray levels and make a reverse map */
00553     pixGetDimensions(pixt, &w, &h, NULL);
00554     datat = pixGetData(pixt);
00555     wplt = pixGetWpl(pixt);
00556     inta = (l_int32 *)CALLOC(256, sizeof(l_int32));
00557     for (i = 0; i < h; i++) {
00558         linet = datat + i * wplt;
00559         for (j = 0; j < w; j++) {
00560             val = GET_DATA_BYTE(linet, j);
00561             inta[val] = 1;
00562         }
00563     }
00564     cmap = pixcmapCreate(8);
00565     revmap = (l_int32 *)CALLOC(256, sizeof(l_int32));
00566     for (i = 0, index = 0; i < 256; i++) {
00567         if (inta[i]) {
00568             pixcmapAddColor(cmap, i, i, i);
00569             revmap[i] = index++;
00570         }
00571     }
00572 
00573         /* Set all pixels in pixd to the colormap index */
00574     pixd = pixCreateTemplate(pixt);
00575     pixSetColormap(pixd, cmap);
00576     pixCopyResolution(pixd, pixs);
00577     datad = pixGetData(pixd);
00578     wpld = pixGetWpl(pixd);
00579     for (i = 0; i < h; i++) {
00580         linet = datat + i * wplt;
00581         lined = datad + i * wpld;
00582         for (j = 0; j < w; j++) {
00583             val = GET_DATA_BYTE(linet, j);
00584             SET_DATA_BYTE(lined, j, revmap[val]);
00585         }
00586     }
00587     
00588     pixDestroy(&pixt);
00589     FREE(inta);
00590     FREE(revmap);
00591     return pixd;
00592 }
00593 
00594 
00595 /*-------------------------------------------------------------*
00596  *            Conversion from RGB color to grayscale           *
00597  *-------------------------------------------------------------*/
00598 /*!
00599  *  pixConvertRGBToLuminance()
00600  *
00601  *      Input:  pix (32 bpp RGB)
00602  *      Return: 8 bpp pix, or null on error
00603  *
00604  *  Notes:
00605  *      (1) Use a standard luminance conversion.
00606  */
00607 PIX *
00608 pixConvertRGBToLuminance(PIX *pixs)
00609 {
00610   return pixConvertRGBToGray(pixs, 0.0, 0.0, 0.0);
00611 }
00612 
00613 
00614 /*!
00615  *  pixConvertRGBToGray()
00616  *
00617  *      Input:  pix (32 bpp RGB)
00618  *              rwt, gwt, bwt  (non-negative; these should add to 1.0,
00619  *                              or use 0.0 for default)
00620  *      Return: 8 bpp pix, or null on error
00621  *
00622  *  Notes:
00623  *      (1) Use a weighted average of the RGB values.
00624  */
00625 PIX *
00626 pixConvertRGBToGray(PIX       *pixs,
00627                     l_float32  rwt,
00628                     l_float32  gwt,
00629                     l_float32  bwt)
00630 {
00631 l_int32    i, j, w, h, wpls, wpld, val;
00632 l_uint32   word;
00633 l_uint32  *datas, *lines, *datad, *lined;
00634 l_float32  sum;
00635 PIX       *pixd;
00636 
00637     PROCNAME("pixConvertRGBToGray");
00638 
00639     if (!pixs)
00640         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00641     if (pixGetDepth(pixs) != 32)
00642         return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
00643     if (rwt < 0.0 || gwt < 0.0 || bwt < 0.0)
00644         return (PIX *)ERROR_PTR("weights not all >= 0.0", procName, NULL);
00645 
00646         /* Make sure the sum of weights is 1.0; otherwise, you can get
00647          * overflow in the gray value. */
00648     if (rwt == 0.0 && gwt == 0.0 && bwt == 0.0) {
00649         rwt = L_RED_WEIGHT;
00650         gwt = L_GREEN_WEIGHT;
00651         bwt = L_BLUE_WEIGHT;
00652     }
00653     sum = rwt + gwt + bwt;
00654     if (L_ABS(sum - 1.0) > 0.0001) {  /* maintain ratios with sum == 1.0 */
00655         L_WARNING("weights don't sum to 1; maintaining ratios", procName);
00656         rwt = rwt / sum;
00657         gwt = gwt / sum;
00658         bwt = bwt / sum;
00659     }
00660 
00661     pixGetDimensions(pixs, &w, &h, NULL);
00662     datas = pixGetData(pixs);
00663     wpls = pixGetWpl(pixs);
00664     if ((pixd = pixCreate(w, h, 8)) == NULL)
00665         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00666     pixCopyResolution(pixd, pixs);
00667     datad = pixGetData(pixd);
00668     wpld = pixGetWpl(pixd);
00669 
00670     for (i = 0, lines = datas, lined = datad; i < h; i++) {
00671         for (j = 0; j < w; j++) {
00672             word = *(lines + j);
00673             val = (l_int32)(rwt * ((word >> L_RED_SHIFT) & 0xff) +
00674                             gwt * ((word >> L_GREEN_SHIFT) & 0xff) +
00675                             bwt * ((word >> L_BLUE_SHIFT) & 0xff) + 0.5);
00676             SET_DATA_BYTE(lined, j, val);
00677         }
00678         lines += wpls;
00679         lined += wpld;
00680     }
00681 
00682     return pixd;
00683 }
00684 
00685 
00686 /*!
00687  *  pixConvertRGBToGrayFast()
00688  *
00689  *      Input:  pix (32 bpp RGB)
00690  *      Return: 8 bpp pix, or null on error
00691  *
00692  *  Notes:
00693  *      (1) This function should be used if speed of conversion
00694  *          is paramount, and the green channel can be used as
00695  *          a fair representative of the RGB intensity.  It is
00696  *          several times faster than pixConvertRGBToGray().
00697  *      (2) To combine RGB to gray conversion with subsampling,
00698  *          use pixScaleRGBToGrayFast() instead.
00699  */
00700 PIX *
00701 pixConvertRGBToGrayFast(PIX  *pixs)
00702 {
00703 l_int32    i, j, w, h, wpls, wpld, val;
00704 l_uint32  *datas, *lines, *datad, *lined;
00705 PIX       *pixd;
00706 
00707     PROCNAME("pixConvertRGBToGrayFast");
00708 
00709     if (!pixs)
00710         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00711     if (pixGetDepth(pixs) != 32)
00712         return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
00713 
00714     pixGetDimensions(pixs, &w, &h, NULL);
00715     datas = pixGetData(pixs);
00716     wpls = pixGetWpl(pixs);
00717     if ((pixd = pixCreate(w, h, 8)) == NULL)
00718         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00719     pixCopyResolution(pixd, pixs);
00720     datad = pixGetData(pixd);
00721     wpld = pixGetWpl(pixd);
00722     
00723     for (i = 0; i < h; i++) {
00724         lines = datas + i * wpls;
00725         lined = datad + i * wpld;
00726         for (j = 0; j < w; j++, lines++) {
00727             val = ((*lines) >> L_GREEN_SHIFT) & 0xff;
00728             SET_DATA_BYTE(lined, j, val);
00729         }
00730     }
00731 
00732     return pixd;
00733 }
00734 
00735 
00736 /*!
00737  *  pixConvertRGBToGrayMinMax()
00738  *
00739  *      Input:  pix (32 bpp RGB)
00740  *              type (L_CHOOSE_MIN or L_CHOOSE_MAX)
00741  *      Return: 8 bpp pix, or null on error
00742  *
00743  *  Notes:
00744  *      (1) @type chooses among the 3 color components for each pixel
00745  *      (2) This is useful when looking for the maximum deviation
00746  *          of a component from either 0 or 255.  For finding the
00747  *          deviation of a single component, it is more sensitive
00748  *          than using a weighted average.
00749  */
00750 PIX *
00751 pixConvertRGBToGrayMinMax(PIX     *pixs,
00752                           l_int32  type)
00753 {
00754 l_int32    i, j, w, h, wpls, wpld, rval, gval, bval, val;
00755 l_uint32  *datas, *lines, *datad, *lined;
00756 PIX       *pixd;
00757 
00758     PROCNAME("pixConvertRGBToGrayMinMax");
00759 
00760     if (!pixs)
00761         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00762     if (pixGetDepth(pixs) != 32)
00763         return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
00764     if (type != L_CHOOSE_MIN && type != L_CHOOSE_MAX)
00765         return (PIX *)ERROR_PTR("invalid type", procName, NULL);
00766 
00767     pixGetDimensions(pixs, &w, &h, NULL);
00768     datas = pixGetData(pixs);
00769     wpls = pixGetWpl(pixs);
00770     if ((pixd = pixCreate(w, h, 8)) == NULL)
00771         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00772     pixCopyResolution(pixd, pixs);
00773     datad = pixGetData(pixd);
00774     wpld = pixGetWpl(pixd);
00775 
00776     for (i = 0; i < h; i++) {
00777         lines = datas + i * wpls;
00778         lined = datad + i * wpld;
00779         for (j = 0; j < w; j++) {
00780             extractRGBValues(lines[j], &rval, &gval, &bval);
00781             if (type == L_CHOOSE_MIN) {
00782                 val = L_MIN(rval, gval);
00783                 val = L_MIN(val, bval);
00784             }
00785             else {  /* type == L_CHOOSE_MAX */
00786                 val = L_MAX(rval, gval);
00787                 val = L_MAX(val, bval);
00788             }
00789             SET_DATA_BYTE(lined, j, val);
00790         }
00791     }
00792 
00793     return pixd;
00794 }
00795 
00796 
00797 
00798 /*---------------------------------------------------------------------------*
00799  *                  Conversion from grayscale to colormap                    *
00800  *---------------------------------------------------------------------------*/
00801 /*!
00802  *  pixConvertGrayToColormap()
00803  *
00804  *      Input:  pixs (2, 4 or 8 bpp grayscale)
00805  *      Return: pixd (2, 4 or 8 bpp with colormap), or null on error
00806  *
00807  *  Notes:
00808  *      (1) This is a simple interface for adding a colormap to a
00809  *          2, 4 or 8 bpp grayscale image without causing any
00810  *          quantization.  There is some similarity to operations
00811  *          in grayquant.c, such as pixThresholdOn8bpp(), where
00812  *          the emphasis is on quantization with an arbitrary number
00813  *          of levels, and a colormap is an option.
00814  *      (2) Returns a copy if pixs already has a colormap.
00815  *      (3) For 8 bpp src, this is a lossless transformation.
00816  *      (4) For 2 and 4 bpp src, this generates a colormap that
00817  *          assumes full coverage of the gray space, with equally spaced
00818  *          levels: 4 levels for d = 2 and 16 levels for d = 4.
00819  *      (5) In all cases, the depth of the dest is the same as the src. 
00820  */
00821 PIX *
00822 pixConvertGrayToColormap(PIX  *pixs)
00823 {
00824 l_int32    d;
00825 PIX       *pixd;
00826 PIXCMAP   *cmap;
00827 
00828     PROCNAME("pixConvertGrayToColormap");
00829 
00830     if (!pixs)
00831         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00832     d = pixGetDepth(pixs);
00833     if (d != 2 && d != 4 && d != 8)
00834         return (PIX *)ERROR_PTR("pixs not 2, 4 or 8 bpp", procName, NULL);
00835 
00836     if (pixGetColormap(pixs)) {
00837         L_WARNING("pixs already has a colormap", procName);
00838         return pixCopy(NULL, pixs);
00839     }
00840 
00841     if (d == 8)  /* lossless conversion */
00842         return pixConvertGrayToColormap8(pixs, 2);
00843 
00844         /* Build a cmap with equally spaced target values over the
00845          * full 8 bpp range. */
00846     pixd = pixCopy(NULL, pixs);
00847     cmap = pixcmapCreateLinear(d, 1 << d);
00848     pixSetColormap(pixd, cmap);
00849     return pixd;
00850 }
00851         
00852 
00853 /*!
00854  *  pixConvertGrayToColormap8()
00855  *
00856  *      Input:  pixs (8 bpp grayscale)
00857  *              mindepth (of pixd; valid values are 2, 4 and 8)
00858  *      Return: pixd (2, 4 or 8 bpp with colormap), or null on error
00859  *
00860  *  Notes:
00861  *      (1) Returns a copy if pixs already has a colormap.
00862  *      (2) This is a lossless transformation; there is no quantization.
00863  *          We compute the number of different gray values in pixs,
00864  *          and construct a colormap that has exactly these values.
00865  *      (3) 'mindepth' is the minimum depth of pixd.  If mindepth == 8,
00866  *          pixd will always be 8 bpp.  Let the number of different
00867  *          gray values in pixs be ngray.  If mindepth == 4, we attempt
00868  *          to save pixd as a 4 bpp image, but if ngray > 16,
00869  *          pixd must be 8 bpp.  Likewise, if mindepth == 2,
00870  *          the depth of pixd will be 2 if ngray <= 4 and 4 if ngray > 4
00871  *          but <= 16.
00872  */
00873 PIX *
00874 pixConvertGrayToColormap8(PIX     *pixs,
00875                           l_int32  mindepth)
00876 {
00877 l_int32    ncolors, w, h, depth, i, j, wpls, wpld;
00878 l_int32    index, num, val, newval;
00879 l_int32    array[256];
00880 l_uint32  *lines, *lined, *datas, *datad;
00881 NUMA      *na;
00882 PIX       *pixd;
00883 PIXCMAP   *cmap;
00884 
00885     PROCNAME("pixConvertGrayToColormap8");
00886 
00887     if (!pixs)
00888         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00889     if (pixGetDepth(pixs) != 8)        
00890         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
00891     if (mindepth != 2 && mindepth != 4 && mindepth != 8) {
00892         L_WARNING("invalid value of mindepth; setting to 8", procName);
00893         mindepth = 8;
00894     }
00895 
00896     if (pixGetColormap(pixs)) {
00897         L_WARNING("pixs already has a colormap", procName);
00898         return pixCopy(NULL, pixs);
00899     }
00900 
00901     na = pixGetGrayHistogram(pixs, 1);
00902     numaGetCountRelativeToZero(na, L_GREATER_THAN_ZERO, &ncolors);
00903     if (mindepth == 8 || ncolors > 16)
00904         depth = 8;
00905     else if (mindepth == 4 || ncolors > 4)
00906         depth = 4;
00907     else
00908         depth = 2;
00909 
00910     pixGetDimensions(pixs, &w, &h, NULL);
00911     pixd = pixCreate(w, h, depth);
00912     cmap = pixcmapCreate(depth);
00913     pixSetColormap(pixd, cmap);
00914     pixCopyResolution(pixd, pixs);
00915 
00916     index = 0;
00917     for (i = 0; i < 256; i++) {
00918         numaGetIValue(na, i, &num);
00919         if (num > 0) {
00920             pixcmapAddColor(cmap, i, i, i);
00921             array[i] = index;
00922             index++;
00923         }
00924     }
00925 
00926     datas = pixGetData(pixs);
00927     wpls = pixGetWpl(pixs);
00928     datad = pixGetData(pixd);
00929     wpld = pixGetWpl(pixd);
00930     for (i = 0; i < h; i++) {
00931         lines = datas + i * wpls;
00932         lined = datad + i * wpld;
00933         for (j = 0; j < w; j++) {
00934             val = GET_DATA_BYTE(lines, j);
00935             newval = array[val];
00936             if (depth == 2)
00937                 SET_DATA_DIBIT(lined, j, newval);
00938             else if (depth == 4)
00939                 SET_DATA_QBIT(lined, j, newval);
00940             else  /* depth == 8 */
00941                 SET_DATA_BYTE(lined, j, newval);
00942         }
00943     }
00944 
00945     numaDestroy(&na);
00946     return pixd;
00947 }
00948 
00949 
00950 /*---------------------------------------------------------------------------*
00951  *                Colorizing conversion from grayscale to color              *
00952  *---------------------------------------------------------------------------*/
00953 /*!
00954  *  pixColorizeGray()
00955  *
00956  *      Input:  pixs (8 bpp gray; 2, 4 or 8 bpp colormapped)
00957  *              color (32 bit rgba pixel)
00958  *              cmapflag (1 for result to have colormap; 0 for RGB)
00959  *      Return: pixd (8 bpp colormapped or 32 bpp rgb), or null on error
00960  *
00961  *  Notes:
00962  *      (1) This applies the specific color to the grayscale image.
00963  *      (2) If pixs already has a colormap, it is removed to gray
00964  *          before colorizing.
00965  */
00966 PIX *
00967 pixColorizeGray(PIX      *pixs,
00968                 l_uint32  color,
00969                 l_int32   cmapflag)
00970 {
00971 l_int32    i, j, w, h, wplt, wpld, val8;
00972 l_uint32  *datad, *datat, *lined, *linet, *tab;
00973 PIX       *pixt, *pixd;
00974 PIXCMAP   *cmap;
00975 
00976     PROCNAME("pixColorizeGray");
00977 
00978     if (!pixs)
00979         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00980     if (pixGetDepth(pixs) != 8 && !pixGetColormap(pixs))        
00981         return (PIX *)ERROR_PTR("pixs not 8 bpp or cmapped", procName, NULL);
00982 
00983     if (pixGetColormap(pixs))
00984         pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
00985     else
00986         pixt = pixClone(pixs);
00987 
00988     cmap = pixcmapGrayToColor(color);
00989     if (cmapflag) {
00990         pixd = pixCopy(NULL, pixt);
00991         pixSetColormap(pixd, cmap);
00992         pixDestroy(&pixt);
00993         return pixd;
00994     }
00995     
00996         /* Make an RGB pix */
00997     pixcmapToRGBTable(cmap, &tab, NULL);
00998     pixGetDimensions(pixt, &w, &h, NULL);
00999     pixd = pixCreate(w, h, 32);
01000     pixCopyResolution(pixd, pixs);
01001     datad = pixGetData(pixd);
01002     wpld = pixGetWpl(pixd);
01003     datat = pixGetData(pixt);
01004     wplt = pixGetWpl(pixt);
01005     for (i = 0; i < h; i++) {
01006         lined = datad + i * wpld;
01007         linet = datat + i * wplt;
01008         for (j = 0; j < w; j++) {
01009             val8 = GET_DATA_BYTE(linet, j);
01010             lined[j] = tab[val8];
01011         }
01012     }
01013 
01014     pixDestroy(&pixt);
01015     pixcmapDestroy(&cmap);
01016     FREE(tab);
01017     return pixd;
01018 }
01019 
01020 
01021 /*---------------------------------------------------------------------------*
01022  *                    Conversion from RGB color to colormap                  *
01023  *---------------------------------------------------------------------------*/
01024 /*!
01025  *  pixConvertRGBToColormap()
01026  *
01027  *      Input:  pixs (32 bpp rgb)
01028  *              ditherflag (1 to dither, 0 otherwise)
01029  *      Return: pixd (2, 4 or 8 bpp with colormap), or null on error
01030  *
01031  *  Notes:
01032  *      (1) This function has two relatively simple modes of color
01033  *          quantization:
01034  *            (a) If the image is made orthographically and has not more
01035  *                than 256 'colors' at the level 4 octcube leaves,
01036  *                it is quantized nearly exactly.  The ditherflag
01037  *                is ignored.
01038  *            (b) Most natural images have more than 256 different colors;
01039  *                in that case we use adaptive octree quantization,
01040  *                with dithering if requested.
01041  *      (2) If there are not more than 256 occupied level 4 octcubes,
01042  *          the color in the colormap that represents all pixels in
01043  *          one of those octcubes is given by the first pixel that
01044  *          falls into that octcube.
01045  *      (3) If there are more than 256 colors, we use adaptive octree
01046  *          color quantization.
01047  *      (4) Dithering gives better visual results on images where
01048  *          there is a color wash (a slow variation of color), but it
01049  *          is about twice as slow and results in significantly larger
01050  *          files when losslessly compressed (e.g., into png).
01051  */     
01052 PIX *
01053 pixConvertRGBToColormap(PIX     *pixs,
01054                         l_int32  ditherflag)
01055 {
01056 l_int32  ncolors;
01057 NUMA    *na;
01058 PIX     *pixd;
01059 
01060     PROCNAME("pixConvertRGBToColormap");
01061 
01062     if (!pixs)
01063         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01064     if (pixGetDepth(pixs) != 32)        
01065         return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
01066 
01067         /* Get the histogram and count the number of occupied level 4
01068          * leaf octcubes.  We don't yet know if this is the number of
01069          * actual colors, but if it's not, all pixels falling into
01070          * the same leaf octcube will be assigned to the color of the
01071          * first pixel that lands there. */
01072     na = pixOctcubeHistogram(pixs, 4, &ncolors);
01073 
01074         /* If there are too many occupied leaf octcubes to be
01075          * represented directly in a colormap, fall back to octree
01076          * quantization, optionally with dithering. */
01077     if (ncolors > 256) {
01078         numaDestroy(&na);
01079         if (ditherflag)
01080             L_INFO("More than 256 colors; using octree quant with dithering",
01081                    procName);
01082         else
01083             L_INFO("More than 256 colors; using octree quant; no dithering",
01084                    procName);
01085         return pixOctreeColorQuant(pixs, 240, ditherflag);
01086     }
01087 
01088         /* There are not more than 256 occupied leaf octcubes.
01089          * Quantize to those octcubes. */
01090     pixd = pixFewColorsOctcubeQuant2(pixs, 4, na, ncolors, NULL);
01091     numaDestroy(&na);
01092     return pixd;
01093 }
01094 
01095 
01096 /*---------------------------------------------------------------------------*
01097  *        Quantization for relatively small number of colors in source       *
01098  *---------------------------------------------------------------------------*/
01099 /*!
01100  *  pixQuantizeIfFewColors()
01101  *     
01102  *      Input:  pixs (8 bpp gray or 32 bpp rgb)
01103  *              maxcolors (max number of colors allowed to be returned
01104  *                         from pixColorsForQuantization(); use 0 for default)
01105  *              mingraycolors (min number of gray levels that a grayscale
01106  *                             image is quantized to; use 0 for default)
01107  *              octlevel (for octcube quantization: 3 or 4)
01108  *              &pixd (2, 4 or 8 bpp quantized; null if too many colors)
01109  *      Return: 0 if OK, 1 on error or if pixs can't be quantized into
01110  *              a small number of colors.
01111  *
01112  *  Notes:
01113  *      (1) This is a wrapper that tests if the pix can be quantized
01114  *          with good quality using a small number of colors.  If so,
01115  *          it does the quantization, defining a colormap and using
01116  *          pixels whose value is an index into the colormap.
01117  *      (2) If the image has color, it is quantized with 8 bpp pixels.
01118  *          If the image is essentially grayscale, the pixels are
01119  *          either 4 or 8 bpp, depending on the size of the required
01120  *          colormap.
01121  *      (3) @octlevel = 3 works well for most images.  However, for best
01122  *          quality, at a cost of more colors in the colormap, use
01123  *          @octlevel = 4.
01124  *      (4) If the image already has a colormap, it returns a clone.
01125  */
01126 l_int32
01127 pixQuantizeIfFewColors(PIX     *pixs,
01128                        l_int32  maxcolors,
01129                        l_int32  mingraycolors,
01130                        l_int32  octlevel,
01131                        PIX    **ppixd)
01132 {
01133 l_int32  d, ncolors, iscolor, graycolors;
01134 PIX     *pixg, *pixd;
01135 
01136     PROCNAME("pixQuantizeIfFewColors");
01137 
01138     if (!ppixd)
01139         return ERROR_INT("&pixd not defined", procName, 1);
01140     *ppixd = NULL;
01141     if (!pixs)
01142         return ERROR_INT("pixs not defined", procName, 1);
01143     d = pixGetDepth(pixs);
01144     if (d != 8 && d != 32)
01145         return ERROR_INT("pixs not defined", procName, 1);
01146     if (pixGetColormap(pixs) != NULL) {
01147         *ppixd = pixClone(pixs);
01148         return 0;
01149     }
01150     if (maxcolors <= 0)
01151         maxcolors = 15;  /* default */
01152     if (maxcolors > 50)
01153         L_WARNING("maxcolors > 50; very large!", procName);
01154     if (mingraycolors <= 0)
01155         mingraycolors = 10;  /* default */
01156     if (mingraycolors > 30)
01157         L_WARNING("mingraycolors > 30; very large!", procName);
01158     if (octlevel != 3 && octlevel != 4) {
01159         L_WARNING("invalid octlevel; setting to 3", procName);
01160         octlevel = 3;
01161     }
01162 
01163         /* Test the number of colors.  For color, the octcube leaves
01164          * are at level 4. */
01165     pixColorsForQuantization(pixs, 0, &ncolors, &iscolor, 0);
01166     if (ncolors > maxcolors)
01167         return ERROR_INT("too many colors", procName, 1);
01168 
01169         /* Quantize!
01170          *  (1) For color:
01171          *      If octlevel == 4, try to quantize to an octree where
01172          *      the octcube leaves are at level 4. If that fails,
01173          *      back off to level 3.
01174          *      If octlevel == 3, quantize to level 3 directly.
01175          *      For level 3, the quality is usually good enough and there
01176          *      is negligible chance of getting more than 256 colors.
01177          *  (2) For grayscale, multiply ncolors by 1.5 for extra quality,
01178          *      but use at least mingraycolors and not more than 256. */
01179     if (iscolor) {
01180         pixd = pixFewColorsOctcubeQuant1(pixs, octlevel);
01181         if (!pixd) {  /* backoff */
01182             pixd = pixFewColorsOctcubeQuant1(pixs, octlevel - 1);
01183             if (octlevel == 3)  /* shouldn't happen */
01184                 L_WARNING("quantized at level 2; low quality", procName);
01185         }
01186     }
01187     else  { /* image is really grayscale */
01188         if (d == 32)
01189             pixg = pixConvertRGBToLuminance(pixs);
01190         else
01191             pixg = pixClone(pixs);
01192         graycolors = L_MAX(mingraycolors, (l_int32)(1.5 * ncolors));
01193         graycolors = L_MIN(graycolors, 256);
01194         if (graycolors < 16)
01195             pixd = pixThresholdTo4bpp(pixg, graycolors, 1);
01196         else
01197             pixd = pixThresholdOn8bpp(pixg, graycolors, 1);
01198         pixDestroy(&pixg);
01199     }
01200     *ppixd = pixd;
01201 
01202     if (!pixd)
01203         return ERROR_INT("pixd not made", procName, 1);
01204     else
01205         return 0;
01206 }
01207 
01208 
01209 
01210 /*---------------------------------------------------------------------------*
01211  *                    Conversion from 16 bpp to 8 bpp                        *
01212  *---------------------------------------------------------------------------*/
01213 /*!
01214  *  pixConvert16To8()
01215  *     
01216  *      Input:  pixs (16 bpp)
01217  *              whichbyte (1 for MSB, 0 for LSB)
01218  *      Return: pixd (8 bpp), or null on error
01219  *
01220  *  Notes:
01221  *      (1) For each dest pixel, use either the MSB or LSB of each src pixel.
01222  */
01223 PIX *
01224 pixConvert16To8(PIX     *pixs,
01225                 l_int32  whichbyte)
01226 {
01227 l_uint16   dsword;
01228 l_int32    w, h, wpls, wpld, i, j;
01229 l_uint32   sword;
01230 l_uint32  *datas, *datad, *lines, *lined;
01231 PIX       *pixd;
01232 
01233     PROCNAME("pixConvert16To8");
01234 
01235     if (!pixs)
01236         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01237     if (pixGetDepth(pixs) != 16)
01238         return (PIX *)ERROR_PTR("pixs not 16 bpp", procName, NULL);
01239 
01240     pixGetDimensions(pixs, &w, &h, NULL);
01241     if ((pixd = pixCreate(w, h, 8)) == NULL)
01242         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01243     pixCopyResolution(pixd, pixs);
01244     wpls = pixGetWpl(pixs);
01245     datas = pixGetData(pixs);
01246     wpld = pixGetWpl(pixd);
01247     datad = pixGetData(pixd);
01248 
01249         /* Convert 2 pixels at a time */
01250     for (i = 0; i < h; i++) {
01251         lines = datas + i * wpls;
01252         lined = datad + i * wpld;
01253         if (whichbyte == 0) {  /* LSB */
01254             for (j = 0; j < wpls; j++) {
01255                 sword = *(lines + j);
01256                 dsword = ((sword >> 8) & 0xff00) | (sword & 0xff);
01257                 SET_DATA_TWO_BYTES(lined, j, dsword);
01258             }
01259         }
01260         else {  /* MSB */
01261             for (j = 0; j < wpls; j++) {
01262                 sword = *(lines + j);
01263                 dsword = ((sword >> 16) & 0xff00) | ((sword >> 8) & 0xff);
01264                 SET_DATA_TWO_BYTES(lined, j, dsword);
01265             }
01266         }
01267     }
01268 
01269     return pixd;
01270 }
01271     
01272 
01273 
01274 /*---------------------------------------------------------------------------*
01275  *                Conversion from grayscale to false color
01276  *---------------------------------------------------------------------------*/
01277 /*!
01278  *  pixConvertGrayToFalseColor()
01279  *
01280  *      Input:  pixs (8 or 16 bpp grayscale)
01281  *              gamma factor (0.0 or 1.0 for default; > 1.0 for brighter;
01282  *                            2.0 is quite nice)
01283  *      Return: pixd (8 bpp with colormap), or null on error
01284  *
01285  *  Notes:
01286  *      (1) For 8 bpp input, this simply adds a colormap to the input image.
01287  *      (2) For 16 bpp input, it first converts to 8 bpp and then
01288  *          adds the colormap.
01289  *      (3) The colormap is modeled after the Matlab "jet" configuration.
01290  */     
01291 PIX *
01292 pixConvertGrayToFalseColor(PIX       *pixs,
01293                            l_float32  gamma)
01294 {
01295 l_int32    d, i, rval, bval, gval;
01296 l_int32   *curve;
01297 l_float32  invgamma, x;
01298 PIX       *pixd;
01299 PIXCMAP   *cmap;
01300 
01301     PROCNAME("pixConvertGrayToFalseColor");
01302 
01303     if (!pixs)
01304         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01305     d = pixGetDepth(pixs);
01306     if (d != 8 && d != 16)        
01307         return (PIX *)ERROR_PTR("pixs not 8 or 16 bpp", procName, NULL);
01308 
01309     if (d == 16)
01310         pixd = pixConvert16To8(pixs, 1);
01311     else {  /* d == 8 */
01312         if (pixGetColormap(pixs))
01313             pixd = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
01314         else
01315             pixd = pixCopy(NULL, pixs);
01316     }
01317     if (!pixd)
01318         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01319     if ((cmap = pixcmapCreate(8)) == NULL)
01320         return (PIX *)ERROR_PTR("cmap not made", procName, NULL);
01321     pixSetColormap(pixd, cmap);
01322     pixCopyResolution(pixd, pixs);
01323 
01324         /* Generate curve for transition part of color map */
01325     if ((curve = (l_int32 *)CALLOC(64, sizeof(l_int32)))== NULL)
01326         return (PIX *)ERROR_PTR("curve not made", procName, NULL);
01327     if (gamma == 0.0) gamma = 1.0;
01328     invgamma = 1. / gamma;
01329     for (i = 0; i < 64; i++) {
01330         x = (l_float32)i / 64.;
01331         curve[i] = (l_int32)(255. * powf(x, invgamma) + 0.5);
01332     }
01333 
01334     for (i = 0; i < 256; i++) {
01335         if (i < 32) {
01336             rval = 0;
01337             gval = 0;
01338             bval = curve[i + 32];
01339         }
01340         else if (i < 96) {   /* 32 - 95 */
01341             rval = 0;
01342             gval = curve[i - 32];
01343             bval = 255;
01344         }
01345         else if (i < 160) {  /* 96 - 159 */
01346             rval = curve[i - 96];
01347             gval = 255;
01348             bval = curve[159 - i];
01349         }
01350         else if (i < 224) {  /* 160 - 223 */
01351             rval = 255;
01352             gval = curve[223 - i];
01353             bval = 0;
01354         }
01355         else {  /* 224 - 255 */
01356             rval = curve[287 - i];
01357             gval = 0;
01358             bval = 0;
01359         }
01360         pixcmapAddColor(cmap, rval, gval, bval);
01361     }
01362 
01363     FREE(curve);
01364     return pixd;
01365 }
01366 
01367 
01368 /*---------------------------------------------------------------------------*
01369  *         Unpacking conversion from 1 bpp to 2, 4, 8, 16 and 32 bpp         *
01370  *---------------------------------------------------------------------------*/
01371 /*!
01372  *  pixUnpackBinary()
01373  *
01374  *      Input:  pixs (1 bpp)
01375  *              depth (of destination: 2, 4, 8, 16 or 32 bpp)
01376  *              invert (0:  binary 0 --> grayscale 0
01377  *                          binary 1 --> grayscale 0xff...
01378  *                      1:  binary 0 --> grayscale 0xff...
01379  *                          binary 1 --> grayscale 0)
01380  *      Return: pixd (2, 4, 8, 16 or 32 bpp), or null on error
01381  *
01382  *  Notes:
01383  *      (1) This function calls special cases of pixConvert1To*(),
01384  *          for 2, 4, 8, 16 and 32 bpp destinations.
01385  */     
01386 PIX *
01387 pixUnpackBinary(PIX     *pixs,
01388                 l_int32  depth,
01389                 l_int32  invert)
01390 {
01391 PIX  *pixd;
01392 
01393     PROCNAME("pixUnpackBinary");
01394 
01395     if (!pixs)
01396         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01397     if (pixGetDepth(pixs) != 1)
01398         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
01399     if (depth != 2 && depth != 4 && depth != 8 && depth != 16 && depth != 32)
01400         return (PIX *)ERROR_PTR("depth not 2, 4, 8, 16 or 32 bpp",
01401                                 procName, NULL);
01402 
01403     if (depth == 2) {
01404         if (invert == 0)
01405             pixd = pixConvert1To2(NULL, pixs, 0, 3);
01406         else  /* invert bits */
01407             pixd = pixConvert1To2(NULL, pixs, 3, 0);
01408     }
01409     else if (depth == 4) {
01410         if (invert == 0)
01411             pixd = pixConvert1To4(NULL, pixs, 0, 15);
01412         else  /* invert bits */
01413             pixd = pixConvert1To4(NULL, pixs, 15, 0);
01414     }
01415     else if (depth == 8) {
01416         if (invert == 0)
01417             pixd = pixConvert1To8(NULL, pixs, 0, 255);
01418         else  /* invert bits */
01419             pixd = pixConvert1To8(NULL, pixs, 255, 0);
01420     }
01421     else if (depth == 16) {
01422         if (invert == 0)
01423             pixd = pixConvert1To16(NULL, pixs, 0, 0xffff);
01424         else  /* invert bits */
01425             pixd = pixConvert1To16(NULL, pixs, 0xffff, 0);
01426     }
01427     else {
01428         if (invert == 0)
01429             pixd = pixConvert1To32(NULL, pixs, 0, 0xffffffff);
01430         else  /* invert bits */
01431             pixd = pixConvert1To32(NULL, pixs, 0xffffffff, 0);
01432     }
01433 
01434     return pixd;
01435 }
01436 
01437 
01438 /*!
01439  *  pixConvert1To16()
01440  *
01441  *      Input:  pixd (<optional> 16 bpp, can be null)
01442  *              pixs (1 bpp)
01443  *              val0 (16 bit value to be used for 0s in pixs)
01444  *              val1 (16 bit value to be used for 1s in pixs)
01445  *      Return: pixd (16 bpp)
01446  *
01447  *  Notes:
01448  *      (1) If pixd is null, a new pix is made.
01449  *      (2) If pixd is not null, it must be of equal width and height
01450  *          as pixs.  It is always returned.
01451  */     
01452 PIX *
01453 pixConvert1To16(PIX      *pixd,
01454                 PIX      *pixs,
01455                 l_uint16  val0,
01456                 l_uint16  val1)
01457 {
01458 l_int32    w, h, i, j, dibit, ndibits, wpls, wpld;
01459 l_uint16   val[2];
01460 l_uint32   index;
01461 l_uint32  *tab, *datas, *datad, *lines, *lined;
01462 
01463     PROCNAME("pixConvert1To16");
01464 
01465     if (!pixs)
01466         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01467     if (pixGetDepth(pixs) != 1)
01468         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
01469 
01470     w = pixGetWidth(pixs);
01471     h = pixGetHeight(pixs);
01472     if (pixd) {
01473         if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd))
01474             return (PIX *)ERROR_PTR("pix sizes unequal", procName, pixd);
01475         if (pixGetDepth(pixd) != 16)
01476             return (PIX *)ERROR_PTR("pixd not 16 bpp", procName, pixd);
01477     }
01478     else {
01479         if ((pixd = pixCreate(w, h, 16)) == NULL)
01480             return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01481     }
01482     pixCopyResolution(pixd, pixs);
01483 
01484         /* Use a table to convert 2 src bits at a time */
01485     if ((tab = (l_uint32 *)CALLOC(4, sizeof(l_uint32))) == NULL) 
01486         return (PIX *)ERROR_PTR("tab not made", procName, NULL);
01487     val[0] = val0;
01488     val[1] = val1;
01489     for (index = 0; index < 4; index++) {
01490         tab[index] = (val[(index >> 1) & 1] << 16) | val[index & 1];
01491     }
01492 
01493     datas = pixGetData(pixs);
01494     wpls = pixGetWpl(pixs);
01495     datad = pixGetData(pixd);
01496     wpld = pixGetWpl(pixd);
01497     ndibits = (w + 1) / 2;
01498     for (i = 0; i < h; i++) {
01499         lines = datas + i * wpls;
01500         lined = datad + i * wpld;
01501         for (j = 0; j < ndibits; j++) {
01502             dibit = GET_DATA_DIBIT(lines, j);
01503             lined[j] = tab[dibit];
01504         }
01505     }
01506 
01507     FREE(tab);
01508     return pixd;
01509 }
01510  
01511 
01512 /*!
01513  *  pixConvert1To32()
01514  *
01515  *      Input:  pixd (<optional> 32 bpp, can be null)
01516  *              pixs (1 bpp)
01517  *              val0 (32 bit value to be used for 0s in pixs)
01518  *              val1 (32 bit value to be used for 1s in pixs)
01519  *      Return: pixd (32 bpp)
01520  *
01521  *  Notes:
01522  *      (1) If pixd is null, a new pix is made.
01523  *      (2) If pixd is not null, it must be of equal width and height
01524  *          as pixs.  It is always returned.
01525  */     
01526 PIX *
01527 pixConvert1To32(PIX      *pixd,
01528                 PIX      *pixs,
01529                 l_uint32  val0,
01530                 l_uint32  val1)
01531 {
01532 l_int32    w, h, i, j, wpls, wpld, bit;
01533 l_uint32   val[2];
01534 l_uint32  *datas, *datad, *lines, *lined;
01535 
01536     PROCNAME("pixConvert1To32");
01537 
01538     if (!pixs)
01539         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01540     if (pixGetDepth(pixs) != 1)
01541         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
01542 
01543     pixGetDimensions(pixs, &w, &h, NULL);
01544     if (pixd) {
01545         if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd))
01546             return (PIX *)ERROR_PTR("pix sizes unequal", procName, pixd);
01547         if (pixGetDepth(pixd) != 32)
01548             return (PIX *)ERROR_PTR("pixd not 32 bpp", procName, pixd);
01549     }
01550     else {
01551         if ((pixd = pixCreate(w, h, 32)) == NULL)
01552             return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01553     }
01554     pixCopyResolution(pixd, pixs);
01555 
01556     val[0] = val0;
01557     val[1] = val1;
01558     datas = pixGetData(pixs);
01559     wpls = pixGetWpl(pixs);
01560     datad = pixGetData(pixd);
01561     wpld = pixGetWpl(pixd);
01562     for (i = 0; i < h; i++) {
01563         lines = datas + i * wpls;
01564         lined = datad + i * wpld;
01565         for (j = 0; j <w; j++) {
01566             bit = GET_DATA_BIT(lines, j);
01567             lined[j] = val[bit];
01568         }
01569     }
01570 
01571     return pixd;
01572 }
01573  
01574 
01575 /*---------------------------------------------------------------------------*
01576  *                    Conversion from 1 bpp to 2 bpp                         *
01577  *---------------------------------------------------------------------------*/
01578 /*!
01579  *  pixConvert1To2Cmap()
01580  *
01581  *      Input:  pixs (1 bpp)
01582  *      Return: pixd (2 bpp, cmapped)
01583  *
01584  *  Notes:
01585  *      (1) Input 0 is mapped to (255, 255, 255); 1 is mapped to (0, 0, 0)
01586  */     
01587 PIX *
01588 pixConvert1To2Cmap(PIX  *pixs)
01589 {
01590 PIX      *pixd;
01591 PIXCMAP  *cmap;
01592 
01593     PROCNAME("pixConvert1To2Cmap");
01594 
01595     if (!pixs)
01596         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01597     if (pixGetDepth(pixs) != 1)
01598         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
01599 
01600     if ((pixd = pixConvert1To2(NULL, pixs, 0, 1)) == NULL)
01601         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01602     cmap = pixcmapCreate(2);
01603     pixcmapAddColor(cmap, 255, 255, 255);
01604     pixcmapAddColor(cmap, 0, 0, 0);
01605     pixSetColormap(pixd, cmap);
01606 
01607     return pixd;
01608 }
01609 
01610 
01611 /*!
01612  *  pixConvert1To2()
01613  *
01614  *      Input:  pixd (<optional> 2 bpp, can be null)
01615  *              pixs (1 bpp)
01616  *              val0 (2 bit value to be used for 0s in pixs)
01617  *              val1 (2 bit value to be used for 1s in pixs)
01618  *      Return: pixd (2 bpp)
01619  *
01620  *  Notes:
01621  *      (1) If pixd is null, a new pix is made.
01622  *      (2) If pixd is not null, it must be of equal width and height
01623  *          as pixs.  It is always returned.
01624  *      (3) A simple unpacking might use val0 = 0 and val1 = 3.
01625  *      (4) If you want a colormapped pixd, use pixConvert1To2Cmap().
01626  */     
01627 PIX *
01628 pixConvert1To2(PIX     *pixd,
01629                PIX     *pixs,
01630                l_int32  val0,
01631                l_int32  val1)
01632 {
01633 l_int32    w, h, i, j, byteval, nbytes, wpls, wpld;
01634 l_uint8    val[2];
01635 l_uint32   index;
01636 l_uint16  *tab;
01637 l_uint32  *datas, *datad, *lines, *lined;
01638 
01639     PROCNAME("pixConvert1To2");
01640 
01641     if (!pixs)
01642         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
01643     if (pixGetDepth(pixs) != 1)
01644         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
01645 
01646     pixGetDimensions(pixs, &w, &h, NULL);
01647     if (pixd) {
01648         if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd))
01649             return (PIX *)ERROR_PTR("pix sizes unequal", procName, pixd);
01650         if (pixGetDepth(pixd) != 2)
01651             return (PIX *)ERROR_PTR("pixd not 2 bpp", procName, pixd);
01652     }
01653     else {
01654         if ((pixd = pixCreate(w, h, 2)) == NULL)
01655             return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01656     }
01657     pixCopyResolution(pixd, pixs);
01658 
01659         /* Use a table to convert 8 src bits to 16 dest bits */
01660     if ((tab = (l_uint16 *)CALLOC(256, sizeof(l_uint16))) == NULL) 
01661         return (PIX *)ERROR_PTR("tab not made", procName, NULL);
01662     val[0] = val0;
01663     val[1] = val1;
01664     for (index = 0; index < 256; index++) {
01665         tab[index] = (val[(index >> 7) & 1] << 14) |
01666                      (val[(index >> 6) & 1] << 12) |
01667                      (val[(index >> 5) & 1] << 10) |
01668                      (val[(index >> 4) & 1] << 8) |
01669                      (val[(index >> 3) & 1] << 6) |
01670                      (val[(index >> 2) & 1] << 4) |
01671                      (val[(index >> 1) & 1] << 2) | val[index & 1];
01672     }
01673 
01674     datas = pixGetData(pixs);
01675     wpls = pixGetWpl(pixs);
01676     datad = pixGetData(pixd);
01677     wpld = pixGetWpl(pixd);
01678     nbytes = (w + 7) / 8;
01679     for (i = 0; i < h; i++) {
01680         lines = datas + i * wpls;
01681         lined = datad + i * wpld;
01682         for (j = 0; j < nbytes; j++) {
01683             byteval = GET_DATA_BYTE(lines, j);
01684             SET_DATA_TWO_BYTES(lined, j, tab[byteval]);
01685         }
01686     }
01687 
01688     FREE(tab);
01689     return pixd;
01690 }
01691 
01692 
01693 /*---------------------------------------------------------------------------*
01694  *                    Conversion from 1 bpp to 4 bpp                         *
01695  *---------------------------------------------------------------------------*/
01696 /*!
01697  *  pixConvert1To4Cmap()
01698  *
01699  *      Input:  pixs (1 bpp)
01700  *      Return: pixd (4 bpp, cmapped)
01701  *
01702  *  Notes:
01703  *      (1) Input 0 is mapped to (255, 255, 255); 1 is mapped to (0, 0, 0)
01704  */     
01705 PIX *
01706 pixConvert1To4Cmap(PIX  *pixs)
01707 {
01708 PIX      *pixd;
01709 PIXCMAP  *cmap;
01710 
01711     PROCNAME("pixConvert1To4Cmap");
01712 
01713     if (!pixs)
01714         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01715     if (pixGetDepth(pixs) != 1)
01716         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
01717 
01718     if ((pixd = pixConvert1To4(NULL, pixs, 0, 1)) == NULL)
01719         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01720     cmap = pixcmapCreate(4);
01721     pixcmapAddColor(cmap, 255, 255, 255);
01722     pixcmapAddColor(cmap, 0, 0, 0);
01723     pixSetColormap(pixd, cmap);
01724 
01725     return pixd;
01726 }
01727 
01728 
01729 /*!
01730  *  pixConvert1To4()
01731  *
01732  *      Input:  pixd (<optional> 4 bpp, can be null)
01733  *              pixs (1 bpp)
01734  *              val0 (4 bit value to be used for 0s in pixs)
01735  *              val1 (4 bit value to be used for 1s in pixs)
01736  *      Return: pixd (4 bpp)
01737  *
01738  *  Notes:
01739  *      (1) If pixd is null, a new pix is made.
01740  *      (2) If pixd is not null, it must be of equal width and height
01741  *          as pixs.  It is always returned.
01742  *      (3) A simple unpacking might use val0 = 0 and val1 = 15, or v.v.
01743  *      (4) If you want a colormapped pixd, use pixConvert1To4Cmap().
01744  */     
01745 PIX *
01746 pixConvert1To4(PIX     *pixd,
01747                PIX     *pixs,
01748                l_int32  val0,
01749                l_int32  val1)
01750 {
01751 l_int32    w, h, i, j, byteval, nbytes, wpls, wpld;
01752 l_uint8    val[2];
01753 l_uint32   index;
01754 l_uint32  *tab, *datas, *datad, *lines, *lined;
01755 
01756     PROCNAME("pixConvert1To4");
01757 
01758     if (!pixs)
01759         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
01760     if (pixGetDepth(pixs) != 1)
01761         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
01762 
01763     pixGetDimensions(pixs, &w, &h, NULL);
01764     if (pixd) {
01765         if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd))
01766             return (PIX *)ERROR_PTR("pix sizes unequal", procName, pixd);
01767         if (pixGetDepth(pixd) != 4)
01768             return (PIX *)ERROR_PTR("pixd not 4 bpp", procName, pixd);
01769     }
01770     else {
01771         if ((pixd = pixCreate(w, h, 4)) == NULL)
01772             return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01773     }
01774     pixCopyResolution(pixd, pixs);
01775 
01776         /* Use a table to convert 8 src bits to 32 bit dest word */
01777     if ((tab = (l_uint32 *)CALLOC(256, sizeof(l_uint32))) == NULL) 
01778         return (PIX *)ERROR_PTR("tab not made", procName, NULL);
01779     val[0] = val0;
01780     val[1] = val1;
01781     for (index = 0; index < 256; index++) {
01782         tab[index] = (val[(index >> 7) & 1] << 28) |
01783                      (val[(index >> 6) & 1] << 24) |
01784                      (val[(index >> 5) & 1] << 20) |
01785                      (val[(index >> 4) & 1] << 16) |
01786                      (val[(index >> 3) & 1] << 12) |
01787                      (val[(index >> 2) & 1] << 8) |
01788                      (val[(index >> 1) & 1] << 4) | val[index & 1];
01789     }
01790 
01791     datas = pixGetData(pixs);
01792     wpls = pixGetWpl(pixs);
01793     datad = pixGetData(pixd);
01794     wpld = pixGetWpl(pixd);
01795     nbytes = (w + 7) / 8;
01796     for (i = 0; i < h; i++) {
01797         lines = datas + i * wpls;
01798         lined = datad + i * wpld;
01799         for (j = 0; j < nbytes; j++) {
01800             byteval = GET_DATA_BYTE(lines, j);
01801             lined[j] = tab[byteval];
01802         }
01803     }
01804 
01805     FREE(tab);
01806     return pixd;
01807 }
01808 
01809 
01810 /*---------------------------------------------------------------------------*
01811  *               Conversion from 1, 2 and 4 bpp to 8 bpp                     *
01812  *---------------------------------------------------------------------------*/
01813 /*!
01814  *  pixConvert1To8()
01815  *
01816  *      Input:  pixd (<optional> 8 bpp, can be null)
01817  *              pixs (1 bpp)
01818  *              val0 (8 bit value to be used for 0s in pixs)
01819  *              val1 (8 bit value to be used for 1s in pixs)
01820  *      Return: pixd (8 bpp)
01821  *
01822  *  Notes:
01823  *      (1) If pixd is null, a new pix is made.
01824  *      (2) If pixd is not null, it must be of equal width and height
01825  *          as pixs.  It is always returned.
01826  *      (3) A simple unpacking might use val0 = 0 and val1 = 255, or v.v.
01827  *      (4) In a typical application where one wants to use a colormap
01828  *          with the dest, you can use val0 = 0, val1 = 1 to make a
01829  *          non-cmapped 8 bpp pix, and then make a colormap and set 0
01830  *          and 1 to the desired colors.  Here is an example:
01831  *             pixd = pixConvert1To8(NULL, pixs, 0, 1);
01832  *             cmap = pixCreate(8);
01833  *             pixcmapAddColor(cmap, 255, 255, 255);
01834  *             pixcmapAddColor(cmap, 0, 0, 0);
01835  *             pixSetColormap(pixd, cmap);
01836  */     
01837 PIX *
01838 pixConvert1To8(PIX     *pixd,
01839                PIX     *pixs,
01840                l_uint8  val0,
01841                l_uint8  val1)
01842 {
01843 l_int32    w, h, i, j, qbit, nqbits, wpls, wpld;
01844 l_uint8    val[2];
01845 l_uint32   index;
01846 l_uint32  *tab, *datas, *datad, *lines, *lined;
01847 
01848     PROCNAME("pixConvert1To8");
01849 
01850     if (!pixs)
01851         return (PIX *)ERROR_PTR("pixs not defined", procName, pixd);
01852     if (pixGetDepth(pixs) != 1)
01853         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, pixd);
01854 
01855     pixGetDimensions(pixs, &w, &h, NULL);
01856     if (pixd) {
01857         if (w != pixGetWidth(pixd) || h != pixGetHeight(pixd))
01858             return (PIX *)ERROR_PTR("pix sizes unequal", procName, pixd);
01859         if (pixGetDepth(pixd) != 8)
01860             return (PIX *)ERROR_PTR("pixd not 8 bpp", procName, pixd);
01861     }
01862     else {
01863         if ((pixd = pixCreate(w, h, 8)) == NULL)
01864             return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01865     }
01866     pixCopyResolution(pixd, pixs);
01867 
01868         /* Use a table to convert 4 src bits at a time */
01869     if ((tab = (l_uint32 *)CALLOC(16, sizeof(l_uint32))) == NULL) 
01870         return (PIX *)ERROR_PTR("tab not made", procName, NULL);
01871     val[0] = val0;
01872     val[1] = val1;
01873     for (index = 0; index < 16; index++) {
01874         tab[index] = (val[(index >> 3) & 1] << 24) |
01875                      (val[(index >> 2) & 1] << 16) |
01876                      (val[(index >> 1) & 1] << 8) | val[index & 1];
01877     }
01878 
01879     datas = pixGetData(pixs);
01880     wpls = pixGetWpl(pixs);
01881     datad = pixGetData(pixd);
01882     wpld = pixGetWpl(pixd);
01883     nqbits = (w + 3) / 4;
01884     for (i = 0; i < h; i++) {
01885         lines = datas + i * wpls;
01886         lined = datad + i * wpld;
01887         for (j = 0; j < nqbits; j++) {
01888             qbit = GET_DATA_QBIT(lines, j);
01889             lined[j] = tab[qbit];
01890         }
01891     }
01892 
01893     FREE(tab);
01894     return pixd;
01895 }
01896  
01897 
01898 /*!
01899  *  pixConvert2To8()
01900  *
01901  *      Input:  pixs (2 bpp)
01902  *              val0 (8 bit value to be used for 00 in pixs)
01903  *              val1 (8 bit value to be used for 01 in pixs)
01904  *              val2 (8 bit value to be used for 10 in pixs)
01905  *              val3 (8 bit value to be used for 11 in pixs)
01906  *              cmapflag (TRUE if pixd is to have a colormap; FALSE otherwise)
01907  *      Return: pixd (8 bpp), or null on error
01908  *
01909  *  Notes:
01910  *      - A simple unpacking might use val0 = 0,
01911  *        val1 = 85 (0x55), val2 = 170 (0xaa), val3 = 255.
01912  *      - If cmapflag is TRUE:
01913  *          - The 8 bpp image is made with a colormap.
01914  *          - If pixs has a colormap, the input values are ignored and
01915  *            the 8 bpp image is made using the colormap
01916  *          - If pixs does not have a colormap, the input values are
01917  *            used to build the colormap.
01918  *      - If cmapflag is FALSE:
01919  *          - The 8 bpp image is made without a colormap.
01920  *          - If pixs has a colormap, the input values are ignored,
01921  *            the colormap is removed, and the values stored in the 8 bpp
01922  *            image are from the colormap.
01923  *          - If pixs does not have a colormap, the input values are
01924  *            used to populate the 8 bpp image.
01925  */     
01926 PIX *
01927 pixConvert2To8(PIX     *pixs,
01928                l_uint8  val0,
01929                l_uint8  val1,
01930                l_uint8  val2,
01931                l_uint8  val3,
01932                l_int32  cmapflag)
01933 {
01934 l_int32    w, h, i, j, nbytes, wpls, wpld, dibit, ncolor;
01935 l_int32    rval, gval, bval, byte;
01936 l_uint8    val[4];
01937 l_uint32   index;
01938 l_uint32  *tab, *datas, *datad, *lines, *lined;
01939 PIX       *pixd;
01940 PIXCMAP   *cmaps, *cmapd;
01941 
01942     PROCNAME("pixConvert2To8");
01943 
01944     if (!pixs)
01945         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01946     if (pixGetDepth(pixs) != 2)
01947         return (PIX *)ERROR_PTR("pixs not 2 bpp", procName, NULL);
01948 
01949     cmaps = pixGetColormap(pixs);
01950     if (cmaps && cmapflag == FALSE)
01951         return pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
01952 
01953     pixGetDimensions(pixs, &w, &h, NULL);
01954     if ((pixd = pixCreate(w, h, 8)) == NULL)
01955         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01956     pixCopyResolution(pixd, pixs);
01957     datas = pixGetData(pixs);
01958     wpls = pixGetWpl(pixs);
01959     datad = pixGetData(pixd);
01960     wpld = pixGetWpl(pixd);
01961 
01962     if (cmapflag == TRUE) {  /* pixd will have a colormap */
01963         cmapd = pixcmapCreate(8);  /* 8 bpp standard cmap */
01964         if (cmaps) {  /* use the existing colormap from pixs */
01965             ncolor = pixcmapGetCount(cmaps);
01966             for (i = 0; i < ncolor; i++) {
01967                 pixcmapGetColor(cmaps, i, &rval, &gval, &bval);
01968                 pixcmapAddColor(cmapd, rval, gval, bval);
01969             }
01970         }
01971         else {  /* make a colormap from the input values */
01972             pixcmapAddColor(cmapd, val0, val0, val0);
01973             pixcmapAddColor(cmapd, val1, val1, val1);
01974             pixcmapAddColor(cmapd, val2, val2, val2);
01975             pixcmapAddColor(cmapd, val3, val3, val3);
01976         }
01977         pixSetColormap(pixd, cmapd);
01978         for (i = 0; i < h; i++) {
01979             lines = datas + i * wpls;
01980             lined = datad + i * wpld;
01981             for (j = 0; j < w; j++) {
01982                 dibit = GET_DATA_DIBIT(lines, j);
01983                 SET_DATA_BYTE(lined, j, dibit);
01984             }
01985         }
01986         return pixd;
01987     }
01988 
01989         /* Last case: no colormap in either pixs or pixd.
01990          * Use input values and build a table to convert 1 src byte
01991          * (4 src pixels) at a time */
01992     if ((tab = (l_uint32 *)CALLOC(256, sizeof(l_uint32))) == NULL) 
01993         return (PIX *)ERROR_PTR("tab not made", procName, NULL);
01994     val[0] = val0;
01995     val[1] = val1;
01996     val[2] = val2;
01997     val[3] = val3;
01998     for (index = 0; index < 256; index++) {
01999         tab[index] = (val[(index >> 6) & 3] << 24) |
02000                      (val[(index >> 4) & 3] << 16) |
02001                      (val[(index >> 2) & 3] << 8) | val[index & 3];
02002     }
02003 
02004     nbytes = (w + 3) / 4;
02005     for (i = 0; i < h; i++) {
02006         lines = datas + i * wpls;
02007         lined = datad + i * wpld;
02008         for (j = 0; j < nbytes; j++) {
02009             byte = GET_DATA_BYTE(lines, j);
02010             lined[j] = tab[byte];
02011         }
02012     }
02013 
02014     FREE(tab);
02015     return pixd;
02016 }
02017  
02018 
02019 /*!
02020  *  pixConvert4To8()
02021  *
02022  *      Input:  pixs (4 bpp)
02023  *              cmapflag (TRUE if pixd is to have a colormap; FALSE otherwise)
02024  *      Return: pixd (8 bpp), or null on error
02025  *
02026  *  Notes:
02027  *      - If cmapflag is TRUE:
02028  *          - pixd is made with a colormap.
02029  *          - If pixs has a colormap, it is copied and the colormap
02030  *            index values are placed in pixd.
02031  *          - If pixs does not have a colormap, a colormap with linear
02032  *            trc is built and the pixel values in pixs are placed in
02033  *            pixd as colormap index values.
02034  *      - If cmapflag is FALSE:
02035  *          - pixd is made without a colormap.
02036  *          - If pixs has a colormap, it is removed and the values stored
02037  *            in pixd are from the colormap (converted to gray).
02038  *          - If pixs does not have a colormap, the pixel values in pixs
02039  *            are used, with shift replication, to populate pixd.
02040  */     
02041 PIX *
02042 pixConvert4To8(PIX     *pixs,
02043                l_int32  cmapflag)
02044 {
02045 l_int32    w, h, i, j, wpls, wpld, ncolor;
02046 l_int32    rval, gval, bval, byte, qbit;
02047 l_uint32  *datas, *datad, *lines, *lined;
02048 PIX       *pixd;
02049 PIXCMAP   *cmaps, *cmapd;
02050 
02051     PROCNAME("pixConvert4To8");
02052 
02053     if (!pixs)
02054         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02055     if (pixGetDepth(pixs) != 4)
02056         return (PIX *)ERROR_PTR("pixs not 4 bpp", procName, NULL);
02057 
02058     cmaps = pixGetColormap(pixs);
02059     if (cmaps && cmapflag == FALSE)
02060         return pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
02061 
02062     pixGetDimensions(pixs, &w, &h, NULL);
02063     if ((pixd = pixCreate(w, h, 8)) == NULL)
02064         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
02065     pixCopyResolution(pixd, pixs);
02066     datas = pixGetData(pixs);
02067     wpls = pixGetWpl(pixs);
02068     datad = pixGetData(pixd);
02069     wpld = pixGetWpl(pixd);
02070 
02071     if (cmapflag == TRUE) {  /* pixd will have a colormap */
02072         cmapd = pixcmapCreate(8);
02073         if (cmaps) {  /* use the existing colormap from pixs */
02074             ncolor = pixcmapGetCount(cmaps);
02075             for (i = 0; i < ncolor; i++) {
02076                 pixcmapGetColor(cmaps, i, &rval, &gval, &bval);
02077                 pixcmapAddColor(cmapd, rval, gval, bval);
02078             }
02079         }
02080         else {  /* make a colormap with a linear trc */
02081             for (i = 0; i < 16; i++) 
02082                 pixcmapAddColor(cmapd, 17 * i, 17 * i, 17 * i);
02083         }
02084         pixSetColormap(pixd, cmapd);
02085         for (i = 0; i < h; i++) {
02086             lines = datas + i * wpls;
02087             lined = datad + i * wpld;
02088             for (j = 0; j < w; j++) {
02089                 qbit = GET_DATA_QBIT(lines, j);
02090                 SET_DATA_BYTE(lined, j, qbit);
02091             }
02092         }
02093         return pixd;
02094     }
02095 
02096         /* Last case: no colormap in either pixs or pixd.
02097          * Replicate the qbit value into 8 bits. */
02098     for (i = 0; i < h; i++) {
02099         lines = datas + i * wpls;
02100         lined = datad + i * wpld;
02101         for (j = 0; j < w; j++) {
02102             qbit = GET_DATA_QBIT(lines, j);
02103             byte = (qbit << 4) | qbit;
02104             SET_DATA_BYTE(lined, j, byte);
02105         }
02106     }
02107     return pixd;
02108 }
02109 
02110 
02111 
02112 /*---------------------------------------------------------------------------*
02113  *               Unpacking conversion from 8 bpp to 16 bpp                   *
02114  *---------------------------------------------------------------------------*/
02115 /*!
02116  *  pixConvert8To16()
02117  *
02118  *      Input:  pixs (8 bpp; colormap removed to gray)
02119  *              leftshift (number of bits: 0 is no shift;
02120  *                         8 replicates in MSB and LSB of dest)
02121  *      Return: pixd (16 bpp), or null on error
02122  *
02123  *  Notes:
02124  *      (1) For left shift of 8, the 8 bit value is replicated in both
02125  *          the MSB and the LSB of the pixels in pixd.  That way, we get
02126  *          proportional mapping, with a correct map from 8 bpp white
02127  *          (0xff) to 16 bpp white (0xffff).
02128  */
02129 PIX *
02130 pixConvert8To16(PIX     *pixs,
02131                 l_int32  leftshift)
02132 {
02133 l_int32    i, j, w, h, d, wplt, wpld, val;
02134 l_uint32  *datat, *datad, *linet, *lined;
02135 PIX       *pixt, *pixd;
02136 
02137     PROCNAME("pixConvert8To16");
02138 
02139     if (!pixs)
02140         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02141     pixGetDimensions(pixs, &w, &h, &d);
02142     if (d != 8)
02143         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
02144     if (leftshift < 0 || leftshift > 8)
02145         return (PIX *)ERROR_PTR("leftshift not in [0 ... 8]", procName, NULL);
02146 
02147     if (pixGetColormap(pixs) != NULL)
02148         pixt = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
02149     else
02150         pixt = pixClone(pixs);
02151 
02152     pixd = pixCreate(w, h, 16);
02153     datat = pixGetData(pixt);
02154     datad = pixGetData(pixd);
02155     wplt = pixGetWpl(pixt);
02156     wpld = pixGetWpl(pixd);
02157     for (i = 0; i < h; i++) {
02158         linet = datat + i * wplt;
02159         lined = datad + i * wpld;
02160         for (j = 0; j < w; j++) {
02161             val = GET_DATA_BYTE(linet, j);
02162             if (leftshift == 8)
02163                 val = val | (val << leftshift);
02164             else
02165                 val <<= leftshift;
02166             SET_DATA_TWO_BYTES(lined, j, val);
02167         }
02168     }
02169 
02170     pixDestroy(&pixt);
02171     return pixd;
02172 }
02173 
02174 
02175 
02176 /*---------------------------------------------------------------------------*
02177  *                     Top-level conversion to 1 bpp                         *
02178  *---------------------------------------------------------------------------*/
02179 /*!
02180  *  pixConvertTo1()
02181  *
02182  *      Input:  pixs (1, 2, 4, 8, 16 or 32 bpp)
02183  *              threshold (for final binarization, relative to 8 bpp)
02184  *      Return: pixd (1 bpp), or null on error
02185  *
02186  *  Notes:
02187  *      (1) This is a top-level function, with simple default values
02188  *          used in pixConvertTo8() if unpacking is necessary.
02189  *      (2) Any existing colormap is removed.
02190  *      (3) If the input image has 1 bpp and no colormap, the operation is
02191  *          lossless and a copy is returned.
02192  */     
02193 PIX *
02194 pixConvertTo1(PIX     *pixs,
02195               l_int32  threshold)
02196 {
02197 l_int32   d, color0, color1, rval, gval, bval;
02198 PIX      *pixg, *pixd;
02199 PIXCMAP  *cmap;
02200 
02201     PROCNAME("pixConvertTo1");
02202 
02203     if (!pixs)
02204         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02205     d = pixGetDepth(pixs);
02206     if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
02207         return (PIX *)ERROR_PTR("depth not {1,2,4,8,16,32}", procName, NULL);
02208 
02209     cmap = pixGetColormap(pixs);
02210     if (d == 1) {
02211         if (!cmap)
02212             return pixCopy(NULL, pixs);
02213         else {  /* strip the colormap off, and invert if reasonable
02214                    for standard binary photometry.  */
02215             pixcmapGetColor(cmap, 0, &rval, &gval, &bval);
02216             color0 = rval + gval + bval;
02217             pixcmapGetColor(cmap, 1, &rval, &gval, &bval);
02218             color1 = rval + gval + bval;
02219             pixd = pixCopy(NULL, pixs);
02220             pixDestroyColormap(pixd);
02221             if (color1 > color0)
02222                 pixInvert(pixd, pixd);
02223             return pixd;
02224         }
02225     }
02226 
02227         /* For all other depths, use 8 bpp as an intermediary */
02228     pixg = pixConvertTo8(pixs, FALSE);
02229     pixd = pixThresholdToBinary(pixg, threshold);
02230     pixDestroy(&pixg);
02231     return pixd;
02232 }
02233 
02234 
02235 /*!
02236  *  pixConvertTo1BySampling()
02237  *
02238  *      Input:  pixs (1, 2, 4, 8, 16 or 32 bpp)
02239  *              factor (submsampling factor; integer >= 1)
02240  *              threshold (for final binarization, relative to 8 bpp)
02241  *      Return: pixd (1 bpp), or null on error
02242  *
02243  *  Notes:
02244  *      (1) This is a fast, quick/dirty, top-level converter.
02245  *      (2) See pixConvertTo1() for default values.
02246  */     
02247 PIX *
02248 pixConvertTo1BySampling(PIX     *pixs,
02249                         l_int32  factor,
02250                         l_int32  threshold)
02251 {
02252 l_float32  scalefactor;
02253 PIX       *pixt, *pixd;
02254 
02255     PROCNAME("pixConvertTo1BySampling");
02256 
02257     if (!pixs)
02258         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02259     if (factor < 1)
02260         return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
02261 
02262     scalefactor = 1. / (l_float32)factor;
02263     pixt = pixScaleBySampling(pixs, scalefactor, scalefactor);
02264     pixd = pixConvertTo1(pixt, threshold);
02265 
02266     pixDestroy(&pixt);
02267     return pixd;
02268 }
02269 
02270 
02271 /*---------------------------------------------------------------------------*
02272  *                     Top-level conversion to 8 bpp                         *
02273  *---------------------------------------------------------------------------*/
02274 /*!
02275  *  pixConvertTo8()
02276  *
02277  *      Input:  pixs (1, 2, 4, 8, 16 or 32 bpp)
02278  *              cmapflag (TRUE if pixd is to have a colormap; FALSE otherwise)
02279  *      Return: pixd (8 bpp), or null on error
02280  *
02281  *  Notes:
02282  *      (1) This is a top-level function, with simple default values
02283  *          for unpacking.
02284  *      (2) The result, pixd, is made with a colormap if specified.
02285  *      (3) If d == 8, and cmapflag matches the existence of a cmap
02286  *          in pixs, the operation is lossless and it returns a copy.
02287  *      (4) The default values used are:
02288  *          - 1 bpp: val0 = 255, val1 = 0
02289  *          - 2 bpp: 4 bpp:  even increments over dynamic range
02290  *          - 8 bpp: lossless if cmap matches cmapflag
02291  *          - 16 bpp: use most significant byte
02292  *      (5) If 32 bpp RGB, this is converted to gray.  If you want
02293  *          to do color quantization, you must specify the type
02294  *          explicitly, using the color quantization code.
02295  */     
02296 PIX *
02297 pixConvertTo8(PIX     *pixs,
02298               l_int32  cmapflag)
02299 {
02300 l_int32   d;
02301 PIX      *pixd;
02302 PIXCMAP  *cmap;
02303 
02304     PROCNAME("pixConvertTo8");
02305 
02306     if (!pixs)
02307         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02308     d = pixGetDepth(pixs);
02309     if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
02310         return (PIX *)ERROR_PTR("depth not {1,2,4,8,16,32}", procName, NULL);
02311 
02312     if (d == 1) {
02313         if (!cmapflag)
02314             return pixConvert1To8(NULL, pixs, 255, 0);
02315         else {
02316             pixd = pixConvert1To8(NULL, pixs, 0, 1);
02317             cmap = pixcmapCreate(8);
02318             pixcmapAddColor(cmap, 255, 255, 255);
02319             pixcmapAddColor(cmap, 0, 0, 0);
02320             pixSetColormap(pixd, cmap);
02321             return pixd;
02322         }
02323     }
02324     else if (d == 2)
02325         return pixConvert2To8(pixs, 0, 85, 170, 255, cmapflag);
02326     else if (d == 4)
02327         return pixConvert4To8(pixs, cmapflag);
02328     else if (d == 8) {
02329         cmap = pixGetColormap(pixs);
02330         if ((cmap && cmapflag) || (!cmap && !cmapflag))
02331             return pixCopy(NULL, pixs);
02332         else if (cmap)  /* !cmapflag */
02333             return pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
02334         else {  /* !cmap && cmapflag; add colormap to pixd */
02335             pixd = pixCopy(NULL, pixs);
02336             pixAddGrayColormap8(pixd);
02337             return pixd;
02338         }
02339     }
02340     else if (d == 16) {
02341         pixd = pixConvert16To8(pixs, 1);
02342         if (cmapflag)
02343             pixAddGrayColormap8(pixd);
02344         return pixd;
02345     }
02346     else { /* d == 32 */
02347         pixd = pixConvertRGBToLuminance(pixs);
02348         if (cmapflag)
02349             pixAddGrayColormap8(pixd);
02350         return pixd;
02351     }
02352 }
02353 
02354 
02355 /*!
02356  *  pixConvertTo8BySampling()
02357  *
02358  *      Input:  pixs (1, 2, 4, 8, 16 or 32 bpp)
02359  *              factor (submsampling factor; integer >= 1)
02360  *              cmapflag (TRUE if pixd is to have a colormap; FALSE otherwise)
02361  *      Return: pixd (8 bpp), or null on error
02362  *
02363  *  Notes:
02364  *      (1) This is a fast, quick/dirty, top-level converter.
02365  *      (2) See pixConvertTo8() for default values.
02366  */     
02367 PIX *
02368 pixConvertTo8BySampling(PIX     *pixs,
02369                         l_int32  factor,
02370                         l_int32  cmapflag)
02371 {
02372 l_float32  scalefactor;
02373 PIX       *pixt, *pixd;
02374 
02375     PROCNAME("pixConvertTo8BySampling");
02376 
02377     if (!pixs)
02378         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02379     if (factor < 1)
02380         return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
02381 
02382     scalefactor = 1. / (l_float32)factor;
02383     pixt = pixScaleBySampling(pixs, scalefactor, scalefactor);
02384     pixd = pixConvertTo8(pixt, cmapflag);
02385 
02386     pixDestroy(&pixt);
02387     return pixd;
02388 }
02389 
02390 
02391 /*---------------------------------------------------------------------------*
02392  *                    Top-level conversion to 16 bpp                         *
02393  *---------------------------------------------------------------------------*/
02394 /*!
02395  *  pixConvertTo16()
02396  *
02397  *      Input:  pixs (1, 8 bpp)
02398  *      Return: pixd (16 bpp), or null on error
02399  *
02400  *  Usage: Top-level function, with simple default values for unpacking.
02401  *      1 bpp:  val0 = 0xffff, val1 = 0
02402  *      8 bpp:  replicates the 8 bit value in both the MSB and LSB
02403  *              of the 16 bit pixel.
02404  */     
02405 PIX *
02406 pixConvertTo16(PIX  *pixs)
02407 {
02408 l_int32  d;
02409 
02410     PROCNAME("pixConvertTo16");
02411 
02412     if (!pixs)
02413         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02414 
02415     d = pixGetDepth(pixs);
02416     if (d == 1)
02417         return pixConvert1To16(NULL, pixs, 0xffff, 0);
02418     else if (d == 8)
02419         return pixConvert8To16(pixs, 8);
02420     else
02421         return (PIX *)ERROR_PTR("src depth not 1 or 8 bpp", procName, NULL);
02422 }
02423 
02424 
02425 
02426 /*---------------------------------------------------------------------------*
02427  *                    Top-level conversion to 32 bpp                         *
02428  *---------------------------------------------------------------------------*/
02429 /*!
02430  *  pixConvertTo32()
02431  *
02432  *      Input:  pixs (1, 2, 4, 8, 16 or 32 bpp)
02433  *      Return: pixd (32 bpp), or null on error
02434  *
02435  *  Usage: Top-level function, with simple default values for unpacking.
02436  *      1 bpp:  val0 = 255, val1 = 0
02437  *              and then replication into R, G and B components
02438  *      2 bpp:  if colormapped, use the colormap values; otherwise,
02439  *              use val0 = 0, val1 = 0x55, val2 = 0xaa, val3 = 255
02440  *              and replicate gray into R, G and B components
02441  *      4 bpp:  if colormapped, use the colormap values; otherwise,
02442  *              replicate 2 nybs into a byte, and then into R,G,B components
02443  *      8 bpp:  if colormapped, use the colormap values; otherwise,
02444  *              replicate gray values into R, G and B components
02445  *      16 bpp: replicate MSB into R, G and B components
02446  *      24 bpp: unpack the pixels, maintaining word alignment on each scanline
02447  *      32 bpp: makes a copy
02448  *
02449  *  Notes:
02450  *      (1) Implicit assumption about RGB component ordering.
02451  */     
02452 PIX *
02453 pixConvertTo32(PIX  *pixs)
02454 {
02455 l_int32  d;
02456 PIX     *pixt, *pixd;
02457 
02458     PROCNAME("pixConvertTo32");
02459 
02460     if (!pixs)
02461         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02462 
02463     d = pixGetDepth(pixs);
02464     if (d == 1)
02465         return pixConvert1To32(NULL, pixs, 0xffffffff, 0);
02466     else if (d == 2) {
02467         pixt = pixConvert2To8(pixs, 0, 85, 170, 255, TRUE);
02468         pixd = pixConvert8To32(pixt);
02469         pixDestroy(&pixt);
02470         return pixd;
02471     }
02472     else if (d == 4) {
02473         pixt = pixConvert4To8(pixs, TRUE);
02474         pixd = pixConvert8To32(pixt);
02475         pixDestroy(&pixt);
02476         return pixd;
02477     }
02478     else if (d == 8)
02479         return pixConvert8To32(pixs);
02480     else if (d == 16) {
02481         pixt = pixConvert16To8(pixs, 1);
02482         pixd = pixConvert8To32(pixt);
02483         pixDestroy(&pixt);
02484         return pixd;
02485     }
02486     else if (d == 24)
02487         return pixConvert24To32(pixs);
02488     else if (d == 32)
02489         return pixCopy(NULL, pixs);
02490     else
02491         return (PIX *)ERROR_PTR("depth not 1, 2, 4, 8, 16, 32 bpp",
02492                                 procName, NULL);
02493 }
02494 
02495 
02496 /*!
02497  *  pixConvertTo32BySampling()
02498  *
02499  *      Input:  pixs (1, 2, 4, 8, 16 or 32 bpp)
02500  *              factor (submsampling factor; integer >= 1)
02501  *      Return: pixd (32 bpp), or null on error
02502  *
02503  *  Notes:
02504  *      (1) This is a fast, quick/dirty, top-level converter.
02505  *      (2) See pixConvertTo32() for default values.
02506  */     
02507 PIX *
02508 pixConvertTo32BySampling(PIX     *pixs,
02509                          l_int32  factor)
02510 {
02511 l_float32  scalefactor;
02512 PIX       *pixt, *pixd;
02513 
02514     PROCNAME("pixConvertTo32BySampling");
02515 
02516     if (!pixs)
02517         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02518     if (factor < 1)
02519         return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
02520 
02521     scalefactor = 1. / (l_float32)factor;
02522     pixt = pixScaleBySampling(pixs, scalefactor, scalefactor);
02523     pixd = pixConvertTo32(pixt);
02524 
02525     pixDestroy(&pixt);
02526     return pixd;
02527 }
02528 
02529 
02530 /*!
02531  *  pixConvert8To32()
02532  *
02533  *      Input:  pix (8 bpp)
02534  *      Return: 32 bpp rgb pix, or null on error
02535  *
02536  *  Notes:
02537  *      (1) If there is no colormap, replicates the gray value
02538  *          into the 3 MSB of the dest pixel.
02539  *      (2) Implicit assumption about RGB component ordering.
02540  */
02541 PIX *
02542 pixConvert8To32(PIX  *pixs)
02543 {
02544 l_int32    i, j, w, h, wpls, wpld, val;
02545 l_uint32  *datas, *datad, *lines, *lined;
02546 l_uint32  *tab;
02547 PIX       *pixd;
02548 
02549     PROCNAME("pixConvert8To32");
02550 
02551     if (!pixs)
02552         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02553     if (pixGetDepth(pixs) != 8)
02554         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
02555 
02556     if (pixGetColormap(pixs))
02557         return pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
02558 
02559         /* Replication table */
02560     if ((tab = (l_uint32 *)CALLOC(256, sizeof(l_uint32))) == NULL)
02561         return (PIX *)ERROR_PTR("tab not made", procName, NULL);
02562     for (i = 0; i < 256; i++)
02563       tab[i] = (i << 24) | (i << 16) | (i << 8);
02564 
02565     pixGetDimensions(pixs, &w, &h, NULL);
02566     datas = pixGetData(pixs);
02567     wpls = pixGetWpl(pixs);
02568     if ((pixd = pixCreate(w, h, 32)) == NULL)
02569         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
02570     pixCopyResolution(pixd, pixs);
02571     datad = pixGetData(pixd);
02572     wpld = pixGetWpl(pixd);
02573     
02574     for (i = 0; i < h; i++) {
02575         lines = datas + i * wpls;
02576         lined = datad + i * wpld;
02577         for (j = 0; j < w; j++) {
02578             val = GET_DATA_BYTE(lines, j);
02579             lined[j] = tab[val];
02580         }
02581     }
02582 
02583     FREE(tab);
02584     return pixd;
02585 }
02586 
02587 
02588 /*---------------------------------------------------------------------------*
02589  *           Top-level conversion to 8 or 32 bpp, without colormap           *
02590  *---------------------------------------------------------------------------*/
02591 /*!
02592  *  pixConvertTo8Or32()
02593  *
02594  *      Input:  pixs (1, 2, 4, 8, 16, with or without colormap; or 32 bpp rgb)
02595  *              copyflag (use 0 to return clone if pixs does not need to
02596  *                         be changed; 1 to return a copy in those situations)
02597  *              warnflag (1 to issue warning if colormap is removed; else 0)
02598  *      Return: pixd (8 bpp grayscale or 32 bpp rgb), or null on error
02599  *
02600  *  Notes:
02601  *      (1) If there is a colormap, the colormap is removed to 8 or 32 bpp,
02602  *          depending on whether the colors in the colormap are all gray.
02603  *      (2) If the input is either rgb or 8 bpp without a colormap,
02604  *          this returns either a clone or a copy, depending on @copyflag.
02605  *      (3) Otherwise, the pix is converted to 8 bpp grayscale.
02606  *          In all cases, pixd does not have a colormap.
02607  */
02608 PIX *
02609 pixConvertTo8Or32(PIX     *pixs,
02610                   l_int32  copyflag,
02611                   l_int32  warnflag)
02612 {
02613 l_int32  d;
02614 PIX     *pixd;
02615 
02616     PROCNAME("pixConvertTo8Or32");
02617 
02618     if (!pixs)
02619         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02620 
02621     d = pixGetDepth(pixs);
02622     if (pixGetColormap(pixs)) {
02623         if (warnflag) L_WARNING("pix has colormap; removing", procName);
02624         pixd = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
02625     }
02626     else if (d == 8 || d == 32) {
02627         if (copyflag == 0)
02628             pixd = pixClone(pixs);
02629         else
02630             pixd = pixCopy(NULL, pixs);
02631     }
02632     else
02633         pixd = pixConvertTo8(pixs, 0);
02634 
02635         /* Sanity check on result */
02636     d = pixGetDepth(pixd);
02637     if (d != 8 && d != 32) {
02638         pixDestroy(&pixd);
02639         return (PIX *)ERROR_PTR("depth not 8 or 32 bpp", procName, NULL);
02640     }
02641 
02642     return pixd;
02643 }
02644  
02645 
02646 /*---------------------------------------------------------------------------*
02647  *                 Conversion between 24 bpp and 32 bpp rgb                  *
02648  *---------------------------------------------------------------------------*/
02649 /*!
02650  *  pixConvert24To32()
02651  *
02652  *      Input:  pixs (24 bpp rgb)
02653  *      Return: pixd (32 bpp rgb), or null on error
02654  *
02655  *  Notes:
02656  *      (1) 24 bpp rgb pix are not supported in leptonica.
02657  *          The data is a byte array, with pixels in order r,g,b, and
02658  *          padded to 32 bit boundaries in each line.
02659  *      (2) Because they are conveniently generated by programs
02660  *          such as xpdf, we need to provide the ability to write them
02661  *          in png, jpeg and tiff, as well as to convert between 24 and
02662  *          32 bpp in memory.
02663  */
02664 PIX *
02665 pixConvert24To32(PIX  *pixs)
02666 {
02667 l_uint8   *lines;
02668 l_int32    w, h, d, i, j, wpls, wpld, rval, gval, bval;
02669 l_uint32   pixel;
02670 l_uint32  *datas, *datad, *lined;
02671 PIX       *pixd;
02672 
02673     PROCNAME("pixConvert24to32");
02674 
02675     if (!pixs)
02676         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02677     pixGetDimensions(pixs, &w, &h, &d);
02678     if (d != 24)
02679         return (PIX *)ERROR_PTR("pixs not 24 bpp", procName, NULL);
02680 
02681     pixd = pixCreateNoInit(w, h, 32);
02682     datas = pixGetData(pixs);
02683     datad = pixGetData(pixd);
02684     wpls = pixGetWpl(pixs);
02685     wpld = pixGetWpl(pixd);
02686     for (i = 0; i < h; i++) {
02687         lines = (l_uint8 *)(datas + i * wpls);
02688         lined = datad + i * wpld;
02689         for (j = 0; j < w; j++) {
02690             rval = *lines++;
02691             gval = *lines++;
02692             bval = *lines++;
02693             composeRGBPixel(rval, gval, bval, &pixel);
02694             lined[j] = pixel;
02695         }
02696     }
02697     pixCopyResolution(pixd, pixs);
02698     pixCopyInputFormat(pixd, pixs);
02699     return pixd;
02700 }
02701 
02702 
02703 /*!
02704  *  pixConvert32To24()
02705  *
02706  *      Input:  pixs (32 bpp rgb)
02707  *      Return: pixd (24 bpp rgb), or null on error
02708  *
02709  *  Notes:
02710  *      (1) 24 bpp rgb pix are not supported in leptonica.
02711  *          The data is a byte array, with pixels in order r,g,b, and
02712  *          padded to 32 bit boundaries in each line.
02713  *      (2) This function is put here for completeness, and so that we
02714  *          can generate 24 bpp for testing.  The test has two parts:
02715  *          (a) convert the 24 bpp pix back to 32 bpp, and test
02716  *              for pixel component equality
02717  *          (b) write the 24 bpp pix as a png and verify that it is
02718  *              identical to the file obtained by writing the 32 bpp pix.
02719  */
02720 PIX *
02721 pixConvert32To24(PIX  *pixs)
02722 {
02723 l_uint8   *rgbdata8;
02724 l_int32    w, h, d, i, j, wpls, wpld, rval, gval, bval;
02725 l_uint32  *datas, *lines, *rgbdata;
02726 PIX       *pixd;
02727 
02728     PROCNAME("pixConvert32to24");
02729 
02730     if (!pixs)
02731         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02732     pixGetDimensions(pixs, &w, &h, &d);
02733     if (d != 32)
02734         return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
02735 
02736     datas = pixGetData(pixs);
02737     wpls = pixGetWpl(pixs);
02738     pixd = pixCreateNoInit(w, h, 24);
02739     rgbdata = pixGetData(pixd);
02740     wpld = pixGetWpl(pixd);
02741     for (i = 0; i < h; i++) {
02742         lines = datas + i * wpls;
02743         rgbdata8 = (l_uint8 *)(rgbdata + i * wpld);
02744         for (j = 0; j < w; j++) {
02745             extractRGBValues(lines[j], &rval, &gval, &bval);
02746             *rgbdata8++ = rval;
02747             *rgbdata8++ = gval;
02748             *rgbdata8++ = bval;
02749         }
02750     }
02751     pixCopyResolution(pixd, pixs);
02752     pixCopyInputFormat(pixd, pixs);
02753     return pixd;
02754 }
02755 
02756 
02757 /*---------------------------------------------------------------------------*
02758  *                  Lossless depth conversion (unpacking)                    *
02759  *---------------------------------------------------------------------------*/
02760 /*!
02761  *  pixConvertLossless()
02762  *
02763  *      Input:  pixs (1, 2, 4, 8 bpp, not cmapped)
02764  *              d (destination depth: 2, 4 or 8)
02765  *      Return: pixd (2, 4 or 8 bpp), or null on error
02766  *
02767  *  Notes:
02768  *      (1) This is a lossless unpacking (depth-increasing)
02769  *          conversion.  If ds is the depth of pixs, then
02770  *           - if d < ds, returns NULL
02771  *           - if d == ds, returns a copy
02772  *           - if d > ds, does the unpacking conversion
02773  *      (2) If pixs has a colormap, this is an error.
02774  */
02775 PIX *
02776 pixConvertLossless(PIX     *pixs,
02777                    l_int32  d)
02778 {
02779 l_int32    w, h, ds, wpls, wpld, i, j, val;
02780 l_uint32  *datas, *datad, *lines, *lined;
02781 PIX       *pixd;
02782 
02783     PROCNAME("pixConvertLossless");
02784 
02785     if (!pixs)
02786         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02787     if (pixGetColormap(pixs))
02788         return (PIX *)ERROR_PTR("pixs has colormap", procName, NULL);
02789     if (d != 2 && d != 4 && d != 8)
02790         return (PIX *)ERROR_PTR("invalid dest depth", procName, NULL);
02791 
02792     pixGetDimensions(pixs, &w, &h, &ds);
02793     if (d < ds)
02794         return (PIX *)ERROR_PTR("depth > d", procName, NULL);
02795     else if (d == ds)
02796         return pixCopy(NULL, pixs);
02797 
02798     if ((pixd = pixCreate(w, h, d)) == NULL)
02799         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
02800     pixCopyResolution(pixd, pixs);
02801 
02802         /* Unpack the bits */
02803     datas = pixGetData(pixs);
02804     wpls = pixGetWpl(pixs);
02805     datad = pixGetData(pixd);
02806     wpld = pixGetWpl(pixd);
02807     for (i = 0; i < h; i++) {
02808         lines = datas + i * wpls;
02809         lined = datad + i * wpld;
02810         switch (ds)
02811         {
02812         case 1:
02813             for (j = 0; j < w; j++) {
02814                 val = GET_DATA_BIT(lines, j);
02815                 if (d == 8)
02816                     SET_DATA_BYTE(lined, j, val);
02817                 else if (d == 4)
02818                     SET_DATA_QBIT(lined, j, val);
02819                 else  /* d == 2 */
02820                     SET_DATA_DIBIT(lined, j, val);
02821             }
02822             break;
02823         case 2:
02824             for (j = 0; j < w; j++) {
02825                 val = GET_DATA_DIBIT(lines, j);
02826                 if (d == 8)
02827                     SET_DATA_BYTE(lined, j, val);
02828                 else  /* d == 4 */
02829                     SET_DATA_QBIT(lined, j, val);
02830             }
02831         case 4:
02832             for (j = 0; j < w; j++) {
02833                 val = GET_DATA_DIBIT(lines, j);
02834                 SET_DATA_BYTE(lined, j, val);
02835             }
02836             break;
02837         }
02838     }
02839 
02840     return pixd;
02841 }
02842 
02843 
02844 /*---------------------------------------------------------------------------*
02845  *                     Conversion for printing in PostScript                 *
02846  *---------------------------------------------------------------------------*/
02847 /*!
02848  *  pixConvertForPSWrap()
02849  *
02850  *      Input:  pixs (1, 2, 4, 8, 16, 32 bpp)
02851  *      Return: pixd (1, 8, or 32 bpp), or null on error
02852  *
02853  *  Notes:
02854  *      (1) For wrapping in PostScript, we convert pixs to
02855  *          1 bpp, 8 bpp (gray) and 32 bpp (RGB color).
02856  *      (2) Colormaps are removed.  For pixs with colormaps, the
02857  *          images are converted to either 8 bpp gray or 32 bpp
02858  *          RGB, depending on whether the colormap has color content.
02859  *      (3) Images without colormaps, that are not 1 bpp or 32 bpp,
02860  *          are converted to 8 bpp gray.
02861  */     
02862 PIX *
02863 pixConvertForPSWrap(PIX  *pixs)
02864 {
02865 l_int32   d;
02866 PIX      *pixd;
02867 PIXCMAP  *cmap;
02868 
02869     PROCNAME("pixConvertForPSWrap");
02870 
02871     if (!pixs)
02872         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02873 
02874     cmap = pixGetColormap(pixs);
02875     d = pixGetDepth(pixs);
02876     switch (d)
02877     {
02878     case 1:
02879     case 32:
02880         pixd = pixClone(pixs);
02881         break;
02882     case 2:
02883         if (cmap)
02884             pixd = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
02885         else
02886             pixd = pixConvert2To8(pixs, 0, 0x55, 0xaa, 0xff, FALSE);
02887         break;
02888     case 4:
02889         if (cmap)
02890             pixd = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
02891         else
02892             pixd = pixConvert4To8(pixs, FALSE);
02893         break;
02894     case 8:
02895         pixd = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
02896         break;
02897     case 16:
02898         pixd = pixConvert16To8(pixs, 1);
02899         break;
02900     default:
02901         fprintf(stderr, "depth not in {1, 2, 4, 8, 16, 32}");
02902         return NULL;
02903    }
02904 
02905    return pixd;
02906 }
02907 
02908 
02909 /*---------------------------------------------------------------------------*
02910  *                      Scaling conversion to subpixel RGB                   *
02911  *---------------------------------------------------------------------------*/
02912 /*!
02913  *  pixConvertToSubpixelRGB()
02914  *
02915  *      Input:  pixs (8 bpp grayscale, 32 bpp rgb, or colormapped)
02916  *              scalex, scaley (anisotropic scaling permitted between
02917  *                              source and destination)
02918  *              order (of subpixel rgb color components in composition of pixd:
02919  *                     L_SUBPIXEL_ORDER_RGB, L_SUBPIXEL_ORDER_BGR,
02920  *                     L_SUBPIXEL_ORDER_VRGB, L_SUBPIXEL_ORDER_VBGR)
02921  *
02922  *      Return: pixd (32 bpp), or null on error
02923  *
02924  *  Notes:
02925  *      (1) If pixs has a colormap, it is removed based on its contents
02926  *          to either 8 bpp gray or rgb.
02927  *      (2) For horizontal subpixel splitting, the input image
02928  *          is rescaled by @scaley vertically and by 3.0 times
02929  *          @scalex horizontally.  Then each horizontal triplet
02930  *          of pixels is mapped back to a single rgb pixel, with the
02931  *          r, g and b values being assigned based on the pixel triplet.
02932  *          For gray triplets, the r, g, and b values are set equal to
02933  *          the three gray values.  For color triplets, the r, g and b
02934  *          values are set equal to the components from the appropriate
02935  *          subpixel.  Vertical subpixel splitting is handled similarly.
02936  *      (3) See pixConvertGrayToSubpixelRGB() and
02937  *          pixConvertColorToSubpixelRGB() for further details.
02938  */
02939 PIX *
02940 pixConvertToSubpixelRGB(PIX       *pixs,
02941                         l_float32  scalex,
02942                         l_float32  scaley,
02943                         l_int32    order)
02944 {
02945 l_int32    d;
02946 PIX       *pixt, *pixd;
02947 PIXCMAP   *cmap;
02948 
02949     PROCNAME("pixConvertToSubpixelRGB");
02950 
02951     if (!pixs)
02952         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02953     d = pixGetDepth(pixs);
02954     cmap = pixGetColormap(pixs);
02955     if (d != 8 && d != 32 && !cmap)
02956         return (PIX *)ERROR_PTR("pix not 8 or 32 bpp and not cmapped",
02957                                 procName, NULL);
02958     if (scalex <= 0.0 || scaley <= 0.0)
02959         return (PIX *)ERROR_PTR("scale factors must be > 0", procName, NULL);
02960     if (order != L_SUBPIXEL_ORDER_RGB && order != L_SUBPIXEL_ORDER_BGR &&
02961         order != L_SUBPIXEL_ORDER_VRGB && order != L_SUBPIXEL_ORDER_VBGR)
02962         return (PIX *)ERROR_PTR("invalid subpixel order", procName, NULL);
02963     if ((pixt = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC)) == NULL)
02964         return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
02965 
02966     d = pixGetDepth(pixt);
02967     pixd = NULL;
02968     if (d == 8)
02969         pixd = pixConvertGrayToSubpixelRGB(pixt, scalex, scaley, order);
02970     else if (d == 32)
02971         pixd = pixConvertColorToSubpixelRGB(pixt, scalex, scaley, order);
02972     else
02973         L_ERROR_INT("invalid depth %d", procName, d);
02974 
02975     pixDestroy(&pixt);
02976     return pixd;
02977 }
02978 
02979 
02980 /*!
02981  *  pixConvertGrayToSubpixelRGB()
02982  *
02983  *      Input:  pixs (8 bpp or colormapped)
02984  *              scalex, scaley
02985  *              order (of subpixel rgb color components in composition of pixd:
02986  *                     L_SUBPIXEL_ORDER_RGB, L_SUBPIXEL_ORDER_BGR,
02987  *                     L_SUBPIXEL_ORDER_VRGB, L_SUBPIXEL_ORDER_VBGR)
02988  *
02989  *      Return: pixd (32 bpp), or null on error
02990  *
02991  *  Notes:
02992  *      (1) If pixs has a colormap, it is removed to 8 bpp.
02993  *      (2) For horizontal subpixel splitting, the input gray image
02994  *          is rescaled by @scaley vertically and by 3.0 times
02995  *          @scalex horizontally.  Then each horizontal triplet
02996  *          of pixels is mapped back to a single rgb pixel, with the
02997  *          r, g and b values being assigned from the triplet of gray values.
02998  *          Similar operations are used for vertical subpixel splitting.
02999  *      (3) This is a form of subpixel rendering that tends to give the
03000  *          resulting text a sharper and somewhat chromatic display.
03001  *          For horizontal subpixel splitting, the observable difference
03002  *          between @order=L_SUBPIXEL_ORDER_RGB and
03003  *          @order=L_SUBPIXEL_ORDER_BGR is reduced by optical diffusers
03004  *          in the display that make the pixel color appear to emerge
03005  *          from the entire pixel.
03006  */
03007 PIX *
03008 pixConvertGrayToSubpixelRGB(PIX       *pixs,
03009                             l_float32  scalex,
03010                             l_float32  scaley,
03011                             l_int32    order)
03012 {
03013 l_int32    w, h, d, wd, hd, wplt, wpld, i, j, rval, gval, bval, direction;
03014 l_uint32  *datat, *datad, *linet, *lined;
03015 PIX       *pixt1, *pixt2, *pixd;
03016 PIXCMAP   *cmap;
03017 
03018     PROCNAME("pixConvertGrayToSubpixelRGB");
03019 
03020     if (!pixs)
03021         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
03022     d = pixGetDepth(pixs);
03023     cmap = pixGetColormap(pixs);
03024     if (d != 8 && !cmap)
03025         return (PIX *)ERROR_PTR("pix not 8 bpp & not cmapped", procName, NULL);
03026     if (scalex <= 0.0 || scaley <= 0.0)
03027         return (PIX *)ERROR_PTR("scale factors must be > 0", procName, NULL);
03028     if (order != L_SUBPIXEL_ORDER_RGB && order != L_SUBPIXEL_ORDER_BGR &&
03029         order != L_SUBPIXEL_ORDER_VRGB && order != L_SUBPIXEL_ORDER_VBGR)
03030         return (PIX *)ERROR_PTR("invalid subpixel order", procName, NULL);
03031 
03032     direction =
03033         (order == L_SUBPIXEL_ORDER_RGB || order == L_SUBPIXEL_ORDER_BGR)
03034         ? L_HORIZ : L_VERT;
03035     pixt1 = pixRemoveColormap(pixs, REMOVE_CMAP_TO_GRAYSCALE);
03036     if (direction == L_HORIZ)
03037         pixt2 = pixScale(pixt1, 3.0 * scalex, scaley);
03038     else  /* L_VERT */
03039         pixt2 = pixScale(pixt1, scalex, 3.0 * scaley);
03040 
03041     pixGetDimensions(pixt2, &w, &h, NULL);
03042     wd = (direction == L_HORIZ) ? w / 3 : w;
03043     hd = (direction == L_VERT) ? h / 3 : h;
03044     pixd = pixCreate(wd, hd, 32);
03045     datad = pixGetData(pixd);
03046     wpld = pixGetWpl(pixd);
03047     datat = pixGetData(pixt2);
03048     wplt = pixGetWpl(pixt2);
03049     if (direction == L_HORIZ) {
03050         for (i = 0; i < hd; i++) {
03051             linet = datat + i * wplt;
03052             lined = datad + i * wpld;
03053             for (j = 0; j < wd; j++) {
03054                 rval = GET_DATA_BYTE(linet, 3 * j);
03055                 gval = GET_DATA_BYTE(linet, 3 * j + 1);
03056                 bval = GET_DATA_BYTE(linet, 3 * j + 2);
03057                 if (order == L_SUBPIXEL_ORDER_RGB)
03058                     composeRGBPixel(rval, gval, bval, &lined[j]);
03059                 else  /* order BGR */
03060                     composeRGBPixel(bval, gval, rval, &lined[j]);
03061             }
03062         }
03063     }
03064     else {  /* L_VERT */
03065         for (i = 0; i < hd; i++) {
03066             linet = datat + 3 * i * wplt;
03067             lined = datad + i * wpld;
03068             for (j = 0; j < wd; j++) {
03069                 rval = GET_DATA_BYTE(linet, j);
03070                 gval = GET_DATA_BYTE(linet + wplt, j);
03071                 bval = GET_DATA_BYTE(linet + 2 * wplt, j);
03072                 if (order == L_SUBPIXEL_ORDER_VRGB)
03073                     composeRGBPixel(rval, gval, bval, &lined[j]);
03074                 else  /* order VBGR */
03075                     composeRGBPixel(bval, gval, rval, &lined[j]);
03076             }
03077         }
03078     }
03079 
03080     pixDestroy(&pixt1);
03081     pixDestroy(&pixt2);
03082     return pixd;
03083 }
03084 
03085 
03086 /*!
03087  *  pixConvertColorToSubpixelRGB()
03088  *
03089  *      Input:  pixs (32 bpp or colormapped)
03090  *              scalex, scaley
03091  *              order (of subpixel rgb color components in composition of pixd:
03092  *                     L_SUBPIXEL_ORDER_RGB, L_SUBPIXEL_ORDER_BGR,
03093  *                     L_SUBPIXEL_ORDER_VRGB, L_SUBPIXEL_ORDER_VBGR)
03094  *
03095  *      Return: pixd (32 bpp), or null on error
03096  *
03097  *  Notes:
03098  *      (1) If pixs has a colormap, it is removed to 32 bpp rgb.
03099  *          If the colormap has no color, pixConvertGrayToSubpixelRGB()
03100  *          should be called instead, because it will give the same result
03101  *          more efficiently.  The function pixConvertToSubpixelRGB()
03102  *          will do the best thing for all cases.
03103  *      (2) For horizontal subpixel splitting, the input rgb image
03104  *          is rescaled by @scalev vertically and by 3.0 times
03105  *          @scalex horizontally.  Then for each horizontal triplet
03106  *          of pixels, the r component of the final pixel is selected
03107  *          from the r component of the appropriate pixel in the triplet,
03108  *          and likewise for g and b.  Vertical subpixel splitting is
03109  *          handled similarly.
03110  */
03111 PIX *
03112 pixConvertColorToSubpixelRGB(PIX       *pixs,
03113                              l_float32  scalex,
03114                              l_float32  scaley,
03115                              l_int32    order)
03116 {
03117 l_int32    w, h, d, wd, hd, wplt, wpld, i, j, rval, gval, bval, direction;
03118 l_uint32  *datat, *datad, *linet, *lined;
03119 PIX       *pixt1, *pixt2, *pixd;
03120 PIXCMAP   *cmap;
03121 
03122     PROCNAME("pixConvertColorToSubpixelRGB");
03123 
03124     if (!pixs)
03125         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
03126     d = pixGetDepth(pixs);
03127     cmap = pixGetColormap(pixs);
03128     if (d != 32 && !cmap)
03129         return (PIX *)ERROR_PTR("pix not 32 bpp & not cmapped", procName, NULL);
03130     if (scalex <= 0.0 || scaley <= 0.0)
03131         return (PIX *)ERROR_PTR("scale factors must be > 0", procName, NULL);
03132     if (order != L_SUBPIXEL_ORDER_RGB && order != L_SUBPIXEL_ORDER_BGR &&
03133         order != L_SUBPIXEL_ORDER_VRGB && order != L_SUBPIXEL_ORDER_VBGR)
03134         return (PIX *)ERROR_PTR("invalid subpixel order", procName, NULL);
03135 
03136     direction =
03137         (order == L_SUBPIXEL_ORDER_RGB || order == L_SUBPIXEL_ORDER_BGR)
03138         ? L_HORIZ : L_VERT;
03139     pixt1 = pixRemoveColormap(pixs, REMOVE_CMAP_TO_FULL_COLOR);
03140     if (direction == L_HORIZ)
03141         pixt2 = pixScale(pixt1, 3.0 * scalex, scaley);
03142     else  /* L_VERT */
03143         pixt2 = pixScale(pixt1, scalex, 3.0 * scaley);
03144 
03145     pixGetDimensions(pixt2, &w, &h, NULL);
03146     wd = (direction == L_HORIZ) ? w / 3 : w;
03147     hd = (direction == L_VERT) ? h / 3 : h;
03148     pixd = pixCreate(wd, hd, 32);
03149     datad = pixGetData(pixd);
03150     wpld = pixGetWpl(pixd);
03151     datat = pixGetData(pixt2);
03152     wplt = pixGetWpl(pixt2);
03153     if (direction == L_HORIZ) {
03154         for (i = 0; i < hd; i++) {
03155             linet = datat + i * wplt;
03156             lined = datad + i * wpld;
03157             for (j = 0; j < wd; j++) {
03158                 if (order == L_SUBPIXEL_ORDER_RGB) {
03159                     extractRGBValues(linet[3 * j], &rval, NULL, NULL);
03160                     extractRGBValues(linet[3 * j + 1], NULL, &gval, NULL);
03161                     extractRGBValues(linet[3 * j + 2], NULL, NULL, &bval);
03162                 }
03163                 else {  /* order BGR */
03164                     extractRGBValues(linet[3 * j], NULL, NULL, &bval);
03165                     extractRGBValues(linet[3 * j + 1], NULL, &gval, NULL);
03166                     extractRGBValues(linet[3 * j + 2], &rval, NULL, NULL);
03167                 }
03168                 composeRGBPixel(rval, gval, bval, &lined[j]);
03169             }
03170         }
03171     }
03172     else {  /* L_VERT */
03173         for (i = 0; i < hd; i++) {
03174             linet = datat + 3 * i * wplt;
03175             lined = datad + i * wpld;
03176             for (j = 0; j < wd; j++) {
03177                 if (order == L_SUBPIXEL_ORDER_VRGB) {
03178                     extractRGBValues(linet[j], &rval, NULL, NULL);
03179                     extractRGBValues((linet + wplt)[j], NULL, &gval, NULL);
03180                     extractRGBValues((linet + 2 * wplt)[j], NULL, NULL, &bval);
03181                 }
03182                 else {  /* order VBGR */
03183                     extractRGBValues(linet[j], NULL, NULL, &bval);
03184                     extractRGBValues((linet + wplt)[j], NULL, &gval, NULL);
03185                     extractRGBValues((linet + 2 * wplt)[j], &rval, NULL, NULL);
03186                 }
03187                 composeRGBPixel(rval, gval, bval, &lined[j]);
03188             }
03189         }
03190     }
03191 
03192     pixDestroy(&pixt1);
03193     pixDestroy(&pixt2);
03194     return pixd;
03195 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines