Leptonica 1.68
C Image Processing Library

scale.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  *  scale.c
00018  *
00019  *         Top-level scaling
00020  *               PIX    *pixScale()     ***
00021  *               PIX    *pixScaleToSize()     ***
00022  *               PIX    *pixScaleGeneral()     ***
00023  *
00024  *         Linearly interpreted (usually up-) scaling
00025  *               PIX    *pixScaleLI()     ***
00026  *               PIX    *pixScaleColorLI()
00027  *               PIX    *pixScaleColor2xLI()   ***
00028  *               PIX    *pixScaleColor4xLI()   ***
00029  *               PIX    *pixScaleGrayLI()
00030  *               PIX    *pixScaleGray2xLI()
00031  *               PIX    *pixScaleGray4xLI()
00032  *
00033  *         Scaling by closest pixel sampling
00034  *               PIX    *pixScaleBySampling()
00035  *               PIX    *pixScaleByIntSubsampling()
00036  *
00037  *         Fast integer factor subsampling RGB to gray and to binary
00038  *               PIX    *pixScaleRGBToGrayFast()
00039  *               PIX    *pixScaleRGBToBinaryFast()
00040  *               PIX    *pixScaleGrayToBinaryFast()
00041  *
00042  *         Downscaling with (antialias) smoothing
00043  *               PIX    *pixScaleSmooth() ***
00044  *               PIX    *pixScaleRGBToGray2()   [special 2x reduction to gray]
00045  *
00046  *         Downscaling with (antialias) area mapping
00047  *               PIX    *pixScaleAreaMap()     ***
00048  *               PIX    *pixScaleAreaMap2()
00049  *
00050  *         Binary scaling by closest pixel sampling
00051  *               PIX    *pixScaleBinary()
00052  *
00053  *         Scale-to-gray (1 bpp --> 8 bpp; arbitrary downscaling)
00054  *               PIX    *pixScaleToGray()
00055  *               PIX    *pixScaleToGrayFast()
00056  *
00057  *         Scale-to-gray (1 bpp --> 8 bpp; integer downscaling)
00058  *               PIX    *pixScaleToGray2()
00059  *               PIX    *pixScaleToGray3()
00060  *               PIX    *pixScaleToGray4()
00061  *               PIX    *pixScaleToGray6()
00062  *               PIX    *pixScaleToGray8()
00063  *               PIX    *pixScaleToGray16()
00064  *
00065  *         Scale-to-gray by mipmap(1 bpp --> 8 bpp, arbitrary reduction)
00066  *               PIX    *pixScaleToGrayMipmap()
00067  *
00068  *         Grayscale scaling using mipmap
00069  *               PIX    *pixScaleMipmap()
00070  *
00071  *         Replicated (integer) expansion (all depths)
00072  *               PIX    *pixExpandReplicate()
00073  *
00074  *         Upscale 2x followed by binarization
00075  *               PIX    *pixScaleGray2xLIThresh()
00076  *               PIX    *pixScaleGray2xLIDither()
00077  *
00078  *         Upscale 4x followed by binarization
00079  *               PIX    *pixScaleGray4xLIThresh()
00080  *               PIX    *pixScaleGray4xLIDither()
00081  *
00082  *         Grayscale downscaling using min and max
00083  *               PIX    *pixScaleGrayMinMax()
00084  *               PIX    *pixScaleGrayMinMax2()
00085  *
00086  *         Grayscale downscaling using rank value
00087  *               PIX    *pixScaleGrayRankCascade()
00088  *               PIX    *pixScaleGrayRank2()
00089  *
00090  *         RGB scaling including alpha (blend) component and gamma transform
00091  *               PIX    *pixScaleWithAlpha()   ***
00092  *               PIX    *pixScaleGammaXform()  ***
00093  *
00094  *  *** Note: these functions make an implicit assumption about RGB
00095  *            component ordering.
00096  */
00097 
00098 #include <string.h>
00099 #include "allheaders.h"
00100 
00101 extern l_float32  AlphaMaskBorderVals[2];
00102 
00103 
00104 /*------------------------------------------------------------------*
00105  *                    Top level scaling dispatcher                  *
00106  *------------------------------------------------------------------*/
00107 /*!
00108  *  pixScale()
00109  *
00110  *      Input:  pixs (1, 2, 4, 8, 16 and 32 bpp)
00111  *              scalex, scaley
00112  *      Return: pixd, or null on error
00113  * 
00114  *  This function scales 32 bpp RGB; 2, 4 or 8 bpp palette color;
00115  *  2, 4, 8 or 16 bpp gray; and binary images.
00116  *
00117  *  When the input has palette color, the colormap is removed and
00118  *  the result is either 8 bpp gray or 32 bpp RGB, depending on whether
00119  *  the colormap has color entries.  Images with 2, 4 or 16 bpp are
00120  *  converted to 8 bpp.
00121  *
00122  *  Because pixScale() is meant to be a very simple interface to a
00123  *  number of scaling functions, including the use of unsharp masking,
00124  *  the type of scaling and the sharpening parameters are chosen
00125  *  by default.  Grayscale and color images are scaled using one
00126  *  of four methods, depending on the scale factors:
00127  *   (1) antialiased subsampling (lowpass filtering followed by
00128  *       subsampling, implemented here by area mapping), for scale factors
00129  *       less than 0.2
00130  *   (2) antialiased subsampling with sharpening, for scale factors
00131  *       between 0.2 and 0.7
00132  *   (3) linear interpolation with sharpening, for scale factors between
00133  *       0.7 and 1.4
00134  *   (4) linear interpolation without sharpening, for scale factors >= 1.4.
00135  *
00136  *  One could use subsampling for scale factors very close to 1.0,
00137  *  because it preserves sharp edges.  Linear interpolation blurs
00138  *  edges because the dest pixels will typically straddle two src edge
00139  *  pixels.  Subsmpling removes entire columns and rows, so the edge is
00140  *  not blurred.  However, there are two reasons for not doing this.
00141  *  First, it moves edges, so that a straight line at a large angle to
00142  *  both horizontal and vertical will have noticable kinks where
00143  *  horizontal and vertical rasters are removed.  Second, although it
00144  *  is very fast, you get good results on sharp edges by applying
00145  *  a sharpening filter.
00146  *
00147  *  For images with sharp edges, sharpening substantially improves the
00148  *  image quality for scale factors between about 0.2 and about 2.0.  However,
00149  *  the generic sharpening operation is about 3 times slower than linear
00150  *  interpolation, so there is a speed-vs-quality tradeoff.  (Note: the
00151  *  cases where the sharpening halfwidth is 1 or 2 have special
00152  *  implementations and are about twice as fast as the general case).
00153  *  When the scale factor is larger than 1.4, the cost, which is
00154  *  proportional to image area, is very large for the incremental
00155  *  quality improvement, so we cut off the use of sharpening at 1.4.
00156  *  For scale factors greater than 1.4, these high-level scaling
00157  *  functions only do linear interpolation.
00158  *
00159  *  Because sharpening is computationally expensive, we provide the
00160  *  option of not doing it.  To avoid sharpening, call pixScaleGeneral()
00161  *  with @sharpfract = 0.0.  pixScale() uses a small amount of
00162  *  of sharpening because it strengthens edge pixels that are weak
00163  *  due to anti-aliasing.  The sharpening factors are:
00164  *      * for scaling factors < 0.7:   sharpfract = 0.2    sharpwidth = 1
00165  *      * for scaling factors >= 0.7:  sharpfract = 0.4    sharpwidth = 2
00166  *
00167  *  The constraints that tie sharpening to the scale factor
00168  *  in pixScaleGeneral() can be circumvented by calling with
00169  *  @sharpfract = 0.0.  This can be followed by the sharpening of
00170  *  choice; e.g., pixUnsharpMasking().
00171  *
00172  *  Binary images are scaled by sampling the closest pixel, without
00173  *  any low-pass filtering (averaging of neighboring pixels).
00174  *  This will introduce aliasing for reductions, which can be
00175  *  prevented by using pixScaleToGray() instead.
00176  *
00177  *  *** Warning: implicit assumption about RGB component order
00178  *               for LI color scaling
00179  */
00180 PIX *
00181 pixScale(PIX       *pixs,
00182          l_float32  scalex,
00183          l_float32  scaley)
00184 {
00185 l_int32    sharpwidth;
00186 l_float32  maxscale, sharpfract;
00187 
00188         /* Reduce the default sharpening factors by 2 if maxscale < 0.7 */
00189     maxscale = L_MAX(scalex, scaley);
00190     sharpfract = (maxscale < 0.7) ? 0.2 : 0.4;
00191     sharpwidth = (maxscale < 0.7) ? 1 : 2;
00192 
00193     return pixScaleGeneral(pixs, scalex, scaley, sharpfract, sharpwidth);
00194 }
00195 
00196 
00197 /*!
00198  *  pixScaleToSize()
00199  *
00200  *      Input:  pixs (1, 2, 4, 8, 16 and 32 bpp)
00201  *              wd  (target width; use 0 if using height as target)
00202  *              hd  (target height; use 0 if using width as target)
00203  *      Return: pixd, or null on error
00204  * 
00205  *  Notes:
00206  *      (1) The guarantees that the output scaled image has the
00207  *          dimension(s) you specify.
00208  *           - To specify the width with isotropic scaling, set @hd = 0.
00209  *           - To specify the height with isotropic scaling, set @wd = 0.
00210  *           - If both @wd and @hd are specified, the image is scaled
00211  *             (in general, anisotropically) to that size.
00212  *           - It is an error to set both @wd and @hd to 0.
00213  */
00214 PIX *
00215 pixScaleToSize(PIX     *pixs,
00216                l_int32  wd,
00217                l_int32  hd)
00218 {
00219 l_int32    w, h;
00220 l_float32  scalex, scaley;
00221 
00222     PROCNAME("pixScaleToSize");
00223 
00224     if (!pixs)
00225         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00226     if (wd <= 0 && hd <= 0)
00227         return (PIX *)ERROR_PTR("neither wd nor hd > 0", procName, NULL);
00228 
00229     pixGetDimensions(pixs, &w, &h, NULL);
00230     if (wd <= 0) {
00231         scaley = (l_float32)hd / (l_float32)h;
00232         scalex = scaley;
00233     }
00234     else if (hd <= 0) {
00235         scalex = (l_float32)wd / (l_float32)w;
00236         scaley = scalex;
00237     }
00238     else {
00239         scalex = (l_float32)wd / (l_float32)w;
00240         scaley = (l_float32)hd / (l_float32)h;
00241     }
00242 
00243     return pixScale(pixs, scalex, scaley);
00244 }
00245 
00246 
00247 /*!
00248  *  pixScaleGeneral()
00249  *
00250  *      Input:  pixs (1, 2, 4, 8, 16 and 32 bpp)
00251  *              scalex, scaley
00252  *              sharpfract (use 0.0 to skip sharpening)
00253  *              sharpwidth (halfwidth of low-pass filter; typ. 1 or 2)
00254  *      Return: pixd, or null on error
00255  * 
00256  *  Notes:
00257  *      (1) See pixScale() for usage.
00258  *      (2) This interface may change in the future, as other special
00259  *          cases are added.
00260  *      (3) The actual sharpening factors used depend on the maximum
00261  *          of the two scale factors (maxscale):
00262  *            maxscale <= 0.2:        no sharpening
00263  *            0.2 < maxscale < 1.4:   uses the input parameters
00264  *            maxscale >= 1.4:        no sharpening
00265  *      (4) To avoid sharpening for grayscale and color images with
00266  *          scaling factors between 0.2 and 1.4, call this function
00267  *          with @sharpfract == 0.0.
00268  *      (5) To use arbitrary sharpening in conjunction with scaling,
00269  *          call this function with @sharpfract = 0.0, and follow this
00270  *          with a call to pixUnsharpMasking() with your chosen parameters.
00271  */
00272 PIX *
00273 pixScaleGeneral(PIX       *pixs,
00274                 l_float32  scalex,
00275                 l_float32  scaley,
00276                 l_float32  sharpfract,
00277                 l_int32    sharpwidth)
00278 {
00279 l_int32    d;
00280 l_float32  maxscale;
00281 PIX       *pixt, *pixt2, *pixd;
00282 
00283     PROCNAME("pixScaleGeneral");
00284 
00285     if (!pixs)
00286         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00287     d = pixGetDepth(pixs);
00288     if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
00289         return (PIX *)ERROR_PTR("pixs not {1,2,4,8,16,32} bpp", procName, NULL);
00290     if (scalex == 1.0 && scaley == 1.0)
00291         return pixCopy(NULL, pixs);
00292 
00293     if (d == 1)
00294         return pixScaleBinary(pixs, scalex, scaley);
00295     
00296         /* Remove colormap; clone if possible; result is either 8 or 32 bpp */
00297     if ((pixt = pixConvertTo8Or32(pixs, 0, 1)) == NULL)
00298         return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
00299 
00300         /* Scale (up or down) */
00301     d = pixGetDepth(pixt);
00302     maxscale = L_MAX(scalex, scaley);
00303     if (maxscale < 0.7) {  /* area mapping for anti-aliasing */
00304         pixt2 = pixScaleAreaMap(pixt, scalex, scaley);
00305         if (maxscale > 0.2 && sharpfract > 0.0 && sharpwidth > 0)
00306             pixd = pixUnsharpMasking(pixt2, sharpwidth, sharpfract);
00307         else
00308             pixd = pixClone(pixt2);
00309     } 
00310     else {  /* use linear interpolation */
00311         if (d == 8)
00312             pixt2 = pixScaleGrayLI(pixt, scalex, scaley);
00313         else  /* d == 32 */
00314             pixt2 = pixScaleColorLI(pixt, scalex, scaley);
00315         if (maxscale < 1.4 && sharpfract > 0.0 && sharpwidth > 0)
00316             pixd = pixUnsharpMasking(pixt2, sharpwidth, sharpfract);
00317         else
00318             pixd = pixClone(pixt2);
00319     }
00320 
00321     pixDestroy(&pixt);
00322     pixDestroy(&pixt2);
00323     return pixd;
00324 }
00325 
00326 
00327 /*------------------------------------------------------------------*
00328  *                  Scaling by linear interpolation                 *
00329  *------------------------------------------------------------------*/
00330 /*!
00331  *  pixScaleLI()
00332  *
00333  *      Input:  pixs (2, 4, 8 or 32 bpp; with or without colormap)
00334  *              scalex, scaley (must both be >= 0.7)
00335  *      Return: pixd, or null on error
00336  * 
00337  *  Notes:
00338  *      (1) This function should only be used when the scale factors are
00339  *          greater than or equal to 0.7, and typically greater than 1.
00340  *          If either scale factor is smaller than 0.7, we issue a warning
00341  *          and invoke pixScale().
00342  *      (2) This works on 2, 4, 8, 16 and 32 bpp images, as well as on
00343  *          2, 4 and 8 bpp images that have a colormap.  If there is a
00344  *          colormap, it is removed to either gray or RGB, depending
00345  *          on the colormap.
00346  *      (3) The does a linear interpolation on the src image.
00347  *      (4) It dispatches to much faster implementations for
00348  *          the special cases of 2x and 4x expansion.
00349  *
00350  *  *** Warning: implicit assumption about RGB component ordering ***
00351  */
00352 PIX *
00353 pixScaleLI(PIX       *pixs,
00354            l_float32  scalex,
00355            l_float32  scaley)
00356 {
00357 l_int32    d;
00358 l_float32  maxscale;
00359 PIX       *pixt, *pixd;
00360 
00361     PROCNAME("pixScaleLI");
00362 
00363     if (!pixs || (pixGetDepth(pixs) == 1))
00364         return (PIX *)ERROR_PTR("pixs not defined or 1 bpp", procName, NULL);
00365     maxscale = L_MAX(scalex, scaley);
00366     if (maxscale < 0.7) {
00367         L_WARNING("scaling factors < 0.7; doing regular scaling", procName);
00368         return pixScale(pixs, scalex, scaley);
00369     }
00370     d = pixGetDepth(pixs);
00371     if (d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
00372         return (PIX *)ERROR_PTR("pixs not {2,4,8,16,32} bpp", procName, NULL);
00373 
00374         /* Remove colormap; clone if possible; result is either 8 or 32 bpp */
00375     if ((pixt = pixConvertTo8Or32(pixs, 0, 1)) == NULL)
00376         return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
00377 
00378     d = pixGetDepth(pixt);
00379     if (d == 8)
00380         pixd = pixScaleGrayLI(pixt, scalex, scaley);
00381     else if (d == 32)
00382         pixd = pixScaleColorLI(pixt, scalex, scaley);
00383 
00384     pixDestroy(&pixt);
00385     return pixd;
00386 }
00387 
00388 
00389 /*!
00390  *  pixScaleColorLI()
00391  *
00392  *      Input:  pixs  (32 bpp, representing rgb)
00393  *              scalex, scaley
00394  *      Return: pixd, or null on error
00395  *
00396  *  Notes:
00397  *      (1) If this is used for scale factors less than 0.7,
00398  *          it will suffer from antialiasing.  A warning is issued.
00399  *          Particularly for document images with sharp edges,
00400  *          use pixScaleSmooth() or pixScaleAreaMap() instead.  
00401  *      (2) For the general case, it's about 4x faster to manipulate
00402  *          the color pixels directly, rather than to make images
00403  *          out of each of the 3 components, scale each component
00404  *          using the pixScaleGrayLI(), and combine the results back
00405  *          into an rgb image.
00406  *      (3) The speed on intel hardware for the general case (not 2x)
00407  *          is about 10 * 10^6 dest-pixels/sec/GHz.  (The special 2x
00408  *          case runs at about 80 * 10^6 dest-pixels/sec/GHz.)
00409  */
00410 PIX *
00411 pixScaleColorLI(PIX      *pixs,
00412                l_float32  scalex,
00413                l_float32  scaley)
00414 {
00415 l_int32    ws, hs, wpls, wd, hd, wpld;
00416 l_uint32  *datas, *datad;
00417 l_float32  maxscale;
00418 PIX       *pixd;
00419 
00420     PROCNAME("pixScaleColorLI");
00421 
00422     if (!pixs || (pixGetDepth(pixs) != 32))
00423         return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
00424     maxscale = L_MAX(scalex, scaley);
00425     if (maxscale < 0.7) {
00426         L_WARNING("scaling factors < 0.7; doing regular scaling", procName);
00427         return pixScale(pixs, scalex, scaley);
00428     }
00429 
00430         /* Do fast special cases if possible */
00431     if (scalex == 1.0 && scaley == 1.0)
00432         return pixCopy(NULL, pixs);
00433     if (scalex == 2.0 && scaley == 2.0)
00434         return pixScaleColor2xLI(pixs);
00435     if (scalex == 4.0 && scaley == 4.0)
00436         return pixScaleColor4xLI(pixs);
00437 
00438         /* General case */
00439     pixGetDimensions(pixs, &ws, &hs, NULL);
00440     datas = pixGetData(pixs);
00441     wpls = pixGetWpl(pixs);
00442     wd = (l_int32)(scalex * (l_float32)ws + 0.5);
00443     hd = (l_int32)(scaley * (l_float32)hs + 0.5);
00444     if ((pixd = pixCreate(wd, hd, 32)) == NULL)
00445         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00446     pixCopyResolution(pixd, pixs);
00447     pixScaleResolution(pixd, scalex, scaley);
00448     datad = pixGetData(pixd);
00449     wpld = pixGetWpl(pixd);
00450     scaleColorLILow(datad, wd, hd, wpld, datas, ws, hs, wpls);
00451     return pixd;
00452 }
00453 
00454 
00455 /*!
00456  *  pixScaleColor2xLI()
00457  * 
00458  *      Input:  pixs  (32 bpp, representing rgb)
00459  *      Return: pixd, or null on error
00460  *
00461  *  Notes:
00462  *      (1) This is a special case of linear interpolated scaling,
00463  *          for 2x upscaling.  It is about 8x faster than using
00464  *          the generic pixScaleColorLI(), and about 4x faster than
00465  *          using the special 2x scale function pixScaleGray2xLI()
00466  *          on each of the three components separately.
00467  *      (2) The speed on intel hardware is about
00468  *          80 * 10^6 dest-pixels/sec/GHz (!!)
00469  *
00470  *  *** Warning: implicit assumption about RGB component ordering ***
00471  */
00472 PIX *
00473 pixScaleColor2xLI(PIX  *pixs)
00474 {
00475 l_int32    ws, hs, wpls, wpld;
00476 l_uint32  *datas, *datad;
00477 PIX       *pixd;
00478 
00479     PROCNAME("pixScaleColor2xLI");
00480 
00481     if (!pixs || (pixGetDepth(pixs) != 32))
00482         return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
00483     
00484     pixGetDimensions(pixs, &ws, &hs, NULL);
00485     datas = pixGetData(pixs);
00486     wpls = pixGetWpl(pixs);
00487     if ((pixd = pixCreate(2 * ws, 2 * hs, 32)) == NULL)
00488         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00489     pixCopyResolution(pixd, pixs);
00490     pixScaleResolution(pixd, 2.0, 2.0);
00491     datad = pixGetData(pixd);
00492     wpld = pixGetWpl(pixd);
00493     scaleColor2xLILow(datad, wpld, datas, ws, hs, wpls);
00494     return pixd;
00495 }
00496 
00497 
00498 /*!
00499  *  pixScaleColor4xLI()
00500  *
00501  *      Input:  pixs  (32 bpp, representing rgb)
00502  *      Return: pixd, or null on error
00503  *
00504  *  Notes:
00505  *      (1) This is a special case of color linear interpolated scaling,
00506  *          for 4x upscaling.  It is about 3x faster than using
00507  *          the generic pixScaleColorLI().
00508  *      (2) The speed on intel hardware is about
00509  *          30 * 10^6 dest-pixels/sec/GHz 
00510  *      (3) This scales each component separately, using pixScaleGray4xLI().
00511  *          It would be about 4x faster to inline the color code properly,
00512  *          in analogy to scaleColor4xLILow(), and I leave this as
00513  *          an exercise for someone who really needs it.
00514  */
00515 PIX *
00516 pixScaleColor4xLI(PIX  *pixs)
00517 {
00518 PIX  *pixr, *pixg, *pixb;
00519 PIX  *pixrs, *pixgs, *pixbs;
00520 PIX  *pixd;
00521 
00522     PROCNAME("pixScaleColor4xLI");
00523 
00524     if (!pixs || (pixGetDepth(pixs) != 32))
00525         return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
00526 
00527     pixr = pixGetRGBComponent(pixs, COLOR_RED);
00528     pixrs = pixScaleGray4xLI(pixr);
00529     pixDestroy(&pixr);
00530     pixg = pixGetRGBComponent(pixs, COLOR_GREEN);
00531     pixgs = pixScaleGray4xLI(pixg);
00532     pixDestroy(&pixg);
00533     pixb = pixGetRGBComponent(pixs, COLOR_BLUE);
00534     pixbs = pixScaleGray4xLI(pixb);
00535     pixDestroy(&pixb);
00536 
00537     if ((pixd = pixCreateRGBImage(pixrs, pixgs, pixbs)) == NULL)
00538         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00539 
00540     pixDestroy(&pixrs);
00541     pixDestroy(&pixgs);
00542     pixDestroy(&pixbs);
00543     return pixd;
00544 }
00545 
00546 
00547 /*!
00548  *  pixScaleGrayLI()
00549  *
00550  *      Input:  pixs (8 bpp grayscale)
00551  *              scalex 
00552  *              scaley 
00553  *      Return: pixd, or null on error
00554  *
00555  *  This function is appropriate for upscaling
00556  *  (magnification: scale factors > 1), and for a
00557  *  small amount of downscaling (reduction: scale
00558  *  factors > 0.5).   For scale factors less than 0.5,
00559  *  the best result is obtained by area mapping,
00560  *  but this is very expensive.  So for such large
00561  *  reductions, it is more appropriate to do low pass
00562  *  filtering followed by subsampling, a combination
00563  *  which is effectively a cheap form of area mapping.
00564  *
00565  *  Some details follow.
00566  *
00567  *  For each pixel in the dest, this does a linear
00568  *  interpolation of 4 neighboring pixels in the src.
00569  *  Specifically, consider the UL corner of src and
00570  *  dest pixels.  The UL corner of the dest falls within
00571  *  a src pixel, whose four corners are the UL corners
00572  *  of 4 adjacent src pixels.  The value of the dest
00573  *  is taken by linear interpolation using the values of
00574  *  the four src pixels and the distance of the UL corner
00575  *  of the dest from each corner.
00576  *
00577  *  If the image is expanded so that the dest pixel is
00578  *  smaller than the src pixel, such interpolation
00579  *  is a reasonable approach.  This interpolation is
00580  *  also good for a small image reduction factor that
00581  *  is not more than a 2x reduction.
00582  *
00583  *  Note that the linear interpolation algorithm for scaling
00584  *  is identical in form to the area-mapping algorithm
00585  *  for grayscale rotation.  The latter corresponds to a
00586  *  translation of each pixel without scaling.
00587  * 
00588  *  This function is NOT optimal if the scaling involves
00589  *  a large reduction.    If the image is significantly
00590  *  reduced, so that the dest pixel is much larger than
00591  *  the src pixels, this interpolation, which is over src
00592  *  pixels only near the UL corner of the dest pixel,
00593  *  is not going to give a good area-mapping average.
00594  *  Because area mapping for image scaling is considerably
00595  *  more computationally intensive than linear interpolation,
00596  *  we choose not to use it.   For large image reduction,
00597  *  linear interpolation over adjacent src pixels
00598  *  degenerates asymptotically to subsampling.  But
00599  *  subsampling without a low-pass pre-filter causes
00600  *  aliasing by the nyquist theorem.  To avoid aliasing,
00601  *  a low-pass filter (e.g., an averaging filter) of
00602  *  size roughly equal to the dest pixel (i.e., the
00603  *  reduction factor) should be applied to the src before
00604  *  subsampling.
00605  *
00606  *  As an alternative to low-pass filtering and subsampling
00607  *  for large reduction factors, linear interpolation can
00608  *  also be done between the (widely separated) src pixels in
00609  *  which the corners of the dest pixel lie.  This also is
00610  *  not optimal, as it samples src pixels only near the
00611  *  corners of the dest pixel, and it is not implemented.
00612  *
00613  *  Summary:
00614  *    (1) If this is used for scale factors less than 0.7,
00615  *        it will suffer from antialiasing.  A warning is issued.
00616  *        Particularly for document images with sharp edges,
00617  *        use pixScaleSmooth() or pixScaleAreaMap() instead.
00618  *    (2) The speed on intel hardware for the general case (not 2x)
00619  *        is about 13 * 10^6 dest-pixels/sec/GHz.  (The special 2x
00620  *        case runs at about 100 * 10^6 dest-pixels/sec/GHz.)
00621  */
00622 PIX *
00623 pixScaleGrayLI(PIX       *pixs,
00624                l_float32  scalex,
00625                l_float32  scaley)
00626 {
00627 l_int32    ws, hs, wpls, wd, hd, wpld;
00628 l_uint32  *datas, *datad;
00629 l_float32  maxscale;
00630 PIX       *pixd;
00631 
00632     PROCNAME("pixScaleGrayLI");
00633 
00634     if (!pixs || (pixGetDepth(pixs) != 8))
00635         return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
00636     maxscale = L_MAX(scalex, scaley);
00637     if (maxscale < 0.7) {
00638         L_WARNING("scaling factors < 0.7; doing regular scaling", procName);
00639         return pixScale(pixs, scalex, scaley);
00640     }
00641     if (pixGetColormap(pixs))
00642         L_WARNING("pix has colormap; poor results are likely", procName);
00643 
00644         /* Do fast special cases if possible */
00645     if (scalex == 1.0 && scaley == 1.0)
00646         return pixCopy(NULL, pixs);
00647     if (scalex == 2.0 && scaley == 2.0)
00648         return pixScaleGray2xLI(pixs);
00649     if (scalex == 4.0 && scaley == 4.0)
00650         return pixScaleGray4xLI(pixs);
00651     
00652         /* General case */
00653     pixGetDimensions(pixs, &ws, &hs, NULL);
00654     datas = pixGetData(pixs);
00655     wpls = pixGetWpl(pixs);
00656     wd = (l_int32)(scalex * (l_float32)ws + 0.5);
00657     hd = (l_int32)(scaley * (l_float32)hs + 0.5);
00658     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
00659         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00660     pixCopyResolution(pixd, pixs);
00661     pixScaleResolution(pixd, scalex, scaley);
00662     datad = pixGetData(pixd);
00663     wpld = pixGetWpl(pixd);
00664     scaleGrayLILow(datad, wd, hd, wpld, datas, ws, hs, wpls);
00665     return pixd;
00666 }
00667 
00668 
00669 /*!
00670  *  pixScaleGray2xLI()
00671  * 
00672  *      Input:  pixs (8 bpp grayscale)
00673  *      Return: pixd, or null on error
00674  *
00675  *  Notes:
00676  *      (1) This is a special case of gray linear interpolated scaling,
00677  *          for 2x upscaling.  It is about 6x faster than using
00678  *          the generic pixScaleGrayLI().
00679  *      (2) The speed on intel hardware is about
00680  *          100 * 10^6 dest-pixels/sec/GHz
00681  */
00682 PIX *
00683 pixScaleGray2xLI(PIX  *pixs)
00684 {
00685 l_int32    ws, hs, wpls, wpld;
00686 l_uint32  *datas, *datad;
00687 PIX       *pixd;
00688 
00689     PROCNAME("pixScaleGray2xLI");
00690 
00691     if (!pixs || (pixGetDepth(pixs) != 8))
00692         return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
00693     if (pixGetColormap(pixs))
00694         L_WARNING("pix has colormap", procName);
00695     
00696     pixGetDimensions(pixs, &ws, &hs, NULL);
00697     datas = pixGetData(pixs);
00698     wpls = pixGetWpl(pixs);
00699     if ((pixd = pixCreate(2 * ws, 2 * hs, 8)) == NULL)
00700         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00701     pixCopyResolution(pixd, pixs);
00702     pixScaleResolution(pixd, 2.0, 2.0);
00703     datad = pixGetData(pixd);
00704     wpld = pixGetWpl(pixd);
00705     scaleGray2xLILow(datad, wpld, datas, ws, hs, wpls);
00706     return pixd;
00707 }
00708 
00709 
00710 /*!
00711  *  pixScaleGray4xLI()
00712  * 
00713  *      Input:  pixs (8 bpp grayscale)
00714  *      Return: pixd, or null on error
00715  *
00716  *  Notes:
00717  *      (1) This is a special case of gray linear interpolated scaling,
00718  *          for 4x upscaling.  It is about 12x faster than using
00719  *          the generic pixScaleGrayLI().
00720  *      (2) The speed on intel hardware is about
00721  *          160 * 10^6 dest-pixels/sec/GHz  (!!)
00722  */
00723 PIX *
00724 pixScaleGray4xLI(PIX  *pixs)
00725 {
00726 l_int32    ws, hs, wpls, wpld;
00727 l_uint32  *datas, *datad;
00728 PIX       *pixd;
00729 
00730     PROCNAME("pixScaleGray4xLI");
00731 
00732     if (!pixs || (pixGetDepth(pixs) != 8))
00733         return (PIX *)ERROR_PTR("pixs undefined or not 8 bpp", procName, NULL);
00734     if (pixGetColormap(pixs))
00735         L_WARNING("pix has colormap", procName);
00736 
00737     pixGetDimensions(pixs, &ws, &hs, NULL);
00738     datas = pixGetData(pixs);
00739     wpls = pixGetWpl(pixs);
00740     if ((pixd = pixCreate(4 * ws, 4 * hs, 8)) == NULL)
00741         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00742     pixCopyResolution(pixd, pixs);
00743     pixScaleResolution(pixd, 4.0, 4.0);
00744     datad = pixGetData(pixd);
00745     wpld = pixGetWpl(pixd);
00746     scaleGray4xLILow(datad, wpld, datas, ws, hs, wpls);
00747     return pixd;
00748 }
00749 
00750 
00751 
00752 /*------------------------------------------------------------------*
00753  *                  Scaling by closest pixel sampling               *
00754  *------------------------------------------------------------------*/
00755 /*!
00756  *  pixScaleBySampling()
00757  *
00758  *      Input:  pixs (1, 2, 4, 8, 16, 32 bpp)
00759  *              scalex, scaley
00760  *      Return: pixd, or null on error
00761  * 
00762  *  Notes:
00763  *      (1) This function samples from the source without
00764  *          filtering.  As a result, aliasing will occur for
00765  *          subsampling (@scalex and/or @scaley < 1.0).
00766  *      (2) If @scalex == 1.0 and @scaley == 1.0, returns a copy.
00767  */
00768 PIX *
00769 pixScaleBySampling(PIX       *pixs,
00770                    l_float32  scalex,
00771                    l_float32  scaley)
00772 {
00773 l_int32    ws, hs, d, wpls, wd, hd, wpld;
00774 l_uint32  *datas, *datad;
00775 PIX       *pixd;
00776 
00777     PROCNAME("pixScaleBySampling");
00778 
00779     if (!pixs)
00780         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00781     if (scalex == 1.0 && scaley == 1.0)
00782         return pixCopy(NULL, pixs);
00783     if ((d = pixGetDepth(pixs)) == 1)
00784         return pixScaleBinary(pixs, scalex, scaley);
00785 
00786     pixGetDimensions(pixs, &ws, &hs, NULL);
00787     datas = pixGetData(pixs);
00788     wpls = pixGetWpl(pixs);
00789     wd = (l_int32)(scalex * (l_float32)ws + 0.5);
00790     hd = (l_int32)(scaley * (l_float32)hs + 0.5);
00791     if ((pixd = pixCreate(wd, hd, d)) == NULL)
00792         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00793     pixCopyResolution(pixd, pixs);
00794     pixScaleResolution(pixd, scalex, scaley);
00795     pixCopyColormap(pixd, pixs);
00796     datad = pixGetData(pixd);
00797     wpld = pixGetWpl(pixd);
00798     scaleBySamplingLow(datad, wd, hd, wpld, datas, ws, hs, d, wpls);
00799     return pixd;
00800 }
00801 
00802 
00803 /*!
00804  *  pixScaleByIntSubsampling()
00805  *
00806  *      Input:  pixs (1, 2, 4, 8, 16, 32 bpp)
00807  *              factor (integer subsampling)
00808  *      Return: pixd, or null on error
00809  *
00810  *  Notes:
00811  *      (1) Simple interface to pixScaleBySampling(), for
00812  *          isotropic integer reduction.
00813  *      (2) If @factor == 1, returns a copy.
00814  */
00815 PIX *
00816 pixScaleByIntSubsampling(PIX     *pixs,
00817                          l_int32  factor)
00818 {
00819 l_float32  scale;
00820 
00821     PROCNAME("pixScaleByIntSubsampling");
00822 
00823     if (!pixs)
00824         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00825     if (factor <= 1) {
00826         if (factor < 1)
00827             L_ERROR("factor must be >= 1; returning a copy", procName);
00828         return pixCopy(NULL, pixs);
00829     }
00830 
00831     scale = 1. / (l_float32)factor;
00832     return pixScaleBySampling(pixs, scale, scale);
00833 }
00834 
00835 
00836 /*------------------------------------------------------------------*
00837  *            Fast integer factor subsampling RGB to gray           *
00838  *------------------------------------------------------------------*/
00839 /*!
00840  *  pixScaleRGBToGrayFast()
00841  *
00842  *      Input:  pixs (32 bpp rgb)
00843  *              factor (integer reduction factor >= 1)
00844  *              color (one of COLOR_RED, COLOR_GREEN, COLOR_BLUE)
00845  *      Return: pixd (8 bpp), or null on error
00846  * 
00847  *  Notes:
00848  *      (1) This does simultaneous subsampling by an integer factor and
00849  *          extraction of the color from the RGB pix.
00850  *      (2) It is designed for maximum speed, and is used for quickly
00851  *          generating a downsized grayscale image from a higher resolution
00852  *          RGB image.  This would typically be used for image analysis.
00853  *      (3) The standard color byte order (RGBA) is assumed.
00854  */
00855 PIX *
00856 pixScaleRGBToGrayFast(PIX     *pixs,
00857                       l_int32  factor,
00858                       l_int32  color)
00859 {
00860 l_int32    byteval, shift;
00861 l_int32    i, j, ws, hs, wd, hd, wpls, wpld;
00862 l_uint32  *datas, *words, *datad, *lined;
00863 l_float32  scale;
00864 PIX       *pixd;
00865 
00866     PROCNAME("pixScaleRGBToGrayFast");
00867 
00868     if (!pixs)
00869         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00870     if (pixGetDepth(pixs) != 32)
00871         return (PIX *)ERROR_PTR("depth not 32 bpp", procName, NULL);
00872     if (factor < 1)
00873         return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
00874 
00875     if (color == COLOR_RED)
00876         shift = L_RED_SHIFT;
00877     else if (color == COLOR_GREEN)
00878         shift = L_GREEN_SHIFT;
00879     else if (color == COLOR_BLUE)
00880         shift = L_BLUE_SHIFT;
00881     else
00882         return (PIX *)ERROR_PTR("invalid color", procName, NULL);
00883 
00884     pixGetDimensions(pixs, &ws, &hs, NULL);
00885     datas = pixGetData(pixs);
00886     wpls = pixGetWpl(pixs);
00887 
00888     wd = ws / factor;
00889     hd = hs / factor;
00890     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
00891         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00892     pixCopyResolution(pixd, pixs);
00893     scale = 1. / (l_float32) factor;
00894     pixScaleResolution(pixd, scale, scale);
00895     datad = pixGetData(pixd);
00896     wpld = pixGetWpl(pixd);
00897     
00898     for (i = 0; i < hd; i++) {
00899         words = datas + i * factor * wpls;
00900         lined = datad + i * wpld;
00901         for (j = 0; j < wd; j++, words += factor) {
00902             byteval = ((*words) >> shift) & 0xff;
00903             SET_DATA_BYTE(lined, j, byteval);
00904         }
00905     }
00906 
00907     return pixd;
00908 }
00909 
00910 
00911 /*!
00912  *  pixScaleRGBToBinaryFast()
00913  *
00914  *      Input:  pixs (32 bpp RGB)
00915  *              factor (integer reduction factor >= 1)
00916  *              thresh (binarization threshold)
00917  *      Return: pixd (1 bpp), or null on error
00918  * 
00919  *  Notes:
00920  *      (1) This does simultaneous subsampling by an integer factor and
00921  *          conversion from RGB to gray to binary.
00922  *      (2) It is designed for maximum speed, and is used for quickly
00923  *          generating a downsized binary image from a higher resolution
00924  *          RGB image.  This would typically be used for image analysis.
00925  *      (3) It uses the green channel to represent the RGB pixel intensity.
00926  */
00927 PIX *
00928 pixScaleRGBToBinaryFast(PIX     *pixs,
00929                         l_int32  factor,
00930                         l_int32  thresh)
00931 {
00932 l_int32    byteval;
00933 l_int32    i, j, ws, hs, wd, hd, wpls, wpld;
00934 l_uint32  *datas, *words, *datad, *lined;
00935 l_float32  scale;
00936 PIX       *pixd;
00937 
00938     PROCNAME("pixScaleRGBToBinaryFast");
00939 
00940     if (!pixs)
00941         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
00942     if (factor < 1)
00943         return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
00944     if (pixGetDepth(pixs) != 32)
00945         return (PIX *)ERROR_PTR("depth not 32 bpp", procName, NULL);
00946 
00947     pixGetDimensions(pixs, &ws, &hs, NULL);
00948     datas = pixGetData(pixs);
00949     wpls = pixGetWpl(pixs);
00950 
00951     wd = ws / factor;
00952     hd = hs / factor;
00953     if ((pixd = pixCreate(wd, hd, 1)) == NULL)
00954         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
00955     pixCopyResolution(pixd, pixs);
00956     scale = 1. / (l_float32) factor;
00957     pixScaleResolution(pixd, scale, scale);
00958     datad = pixGetData(pixd);
00959     wpld = pixGetWpl(pixd);
00960 
00961     for (i = 0; i < hd; i++) {
00962         words = datas + i * factor * wpls;
00963         lined = datad + i * wpld;
00964         for (j = 0; j < wd; j++, words += factor) {
00965             byteval = ((*words) >> L_GREEN_SHIFT) & 0xff;
00966             if (byteval < thresh)
00967                 SET_DATA_BIT(lined, j);
00968         }
00969     }
00970 
00971     return pixd;
00972 }
00973 
00974 
00975 /*!
00976  *  pixScaleGrayToBinaryFast()
00977  *
00978  *      Input:  pixs (8 bpp grayscale)
00979  *              factor (integer reduction factor >= 1)
00980  *              thresh (binarization threshold)
00981  *      Return: pixd (1 bpp), or null on error
00982  * 
00983  *  Notes:
00984  *      (1) This does simultaneous subsampling by an integer factor and
00985  *          thresholding from gray to binary.
00986  *      (2) It is designed for maximum speed, and is used for quickly
00987  *          generating a downsized binary image from a higher resolution
00988  *          gray image.  This would typically be used for image analysis.
00989  */
00990 PIX *
00991 pixScaleGrayToBinaryFast(PIX     *pixs,
00992                          l_int32  factor,
00993                          l_int32  thresh)
00994 {
00995 l_int32    byteval;
00996 l_int32    i, j, ws, hs, wd, hd, wpls, wpld, sj;
00997 l_uint32  *datas, *datad, *lines, *lined;
00998 l_float32  scale;
00999 PIX       *pixd;
01000 
01001     PROCNAME("pixScaleGrayToBinaryFast");
01002 
01003     if (!pixs)
01004         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01005     if (factor < 1)
01006         return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
01007     if (pixGetDepth(pixs) != 8)
01008         return (PIX *)ERROR_PTR("depth not 8 bpp", procName, NULL);
01009 
01010     pixGetDimensions(pixs, &ws, &hs, NULL);
01011     datas = pixGetData(pixs);
01012     wpls = pixGetWpl(pixs);
01013 
01014     wd = ws / factor;
01015     hd = hs / factor;
01016     if ((pixd = pixCreate(wd, hd, 1)) == NULL)
01017         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01018     pixCopyResolution(pixd, pixs);
01019     scale = 1. / (l_float32) factor;
01020     pixScaleResolution(pixd, scale, scale);
01021     datad = pixGetData(pixd);
01022     wpld = pixGetWpl(pixd);
01023 
01024     for (i = 0; i < hd; i++) {
01025         lines = datas + i * factor * wpls;
01026         lined = datad + i * wpld;
01027         for (j = 0, sj = 0; j < wd; j++, sj += factor) {
01028             byteval = GET_DATA_BYTE(lines, sj);
01029             if (byteval < thresh)
01030                 SET_DATA_BIT(lined, j);
01031         }
01032     }
01033 
01034     return pixd;
01035 }
01036 
01037 
01038 /*------------------------------------------------------------------*
01039  *               Downscaling with (antialias) smoothing             *
01040  *------------------------------------------------------------------*/
01041 /*!
01042  *  pixScaleSmooth()
01043  *
01044  *      Input:  pixs (2, 4, 8 or 32 bpp; and 2, 4, 8 bpp with colormap)
01045  *              scalex, scaley (must both be < 0.7)
01046  *      Return: pixd, or null on error
01047  * 
01048  *  Notes:
01049  *      (1) This function should only be used when the scale factors are less
01050  *          than or equal to 0.7 (i.e., more than about 1.42x reduction).
01051  *          If either scale factor is larger than 0.7, we issue a warning
01052  *          and invoke pixScale().
01053  *      (2) This works only on 2, 4, 8 and 32 bpp images, and if there is
01054  *          a colormap, it is removed by converting to RGB.  In other
01055  *          cases, we issue a warning and invoke pixScale().
01056  *      (3) It does simple (flat filter) convolution, with a filter size
01057  *          commensurate with the amount of reduction, to avoid antialiasing.
01058  *      (4) It does simple subsampling after smoothing, which is appropriate
01059  *          for this range of scaling.  Linear interpolation gives essentially
01060  *          the same result with more computation for these scale factors,
01061  *          so we don't use it.
01062  *      (5) The result is the same as doing a full block convolution followed by
01063  *          subsampling, but this is faster because the results of the block
01064  *          convolution are only computed at the subsampling locations.
01065  *          In fact, the computation time is approximately independent of
01066  *          the scale factor, because the convolution kernel is adjusted
01067  *          so that each source pixel is summed approximately once.
01068  *
01069  *  *** Warning: implicit assumption about RGB component ordering ***
01070  */
01071 PIX *
01072 pixScaleSmooth(PIX       *pix,
01073                l_float32  scalex,
01074                l_float32  scaley)
01075 {
01076 l_int32    ws, hs, d, wd, hd, wpls, wpld, isize;
01077 l_uint32  *datas, *datad;
01078 l_float32  minscale, size;
01079 PIX       *pixs, *pixd;
01080 
01081     PROCNAME("pixScaleSmooth");
01082 
01083     if (!pix)
01084         return (PIX *)ERROR_PTR("pix not defined", procName, NULL);
01085     if (scalex >= 0.7 || scaley >= 0.7) {
01086         L_WARNING("scaling factor not < 0.7; doing regular scaling", procName);
01087         return pixScale(pix, scalex, scaley);
01088     }
01089 
01090         /* Remove colormap if necessary.
01091          * If 2 bpp or 4 bpp gray, convert to 8 bpp */
01092     d = pixGetDepth(pix);
01093     if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
01094         L_WARNING("pix has colormap; removing", procName);
01095         pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC);
01096         d = pixGetDepth(pixs);
01097     }
01098     else if (d == 2 || d == 4) {
01099         pixs = pixConvertTo8(pix, FALSE);
01100         d = 8;
01101     }
01102     else
01103         pixs = pixClone(pix);
01104 
01105     if (d != 8 && d != 32) {   /* d == 1 or d == 16 */
01106         L_WARNING("depth not 8 or 32 bpp; doing regular scaling", procName);
01107         pixDestroy(&pixs);
01108         return pixScale(pix, scalex, scaley);
01109     }
01110 
01111         /* If 1.42 < 1/minscale < 2.5, use isize = 2
01112          * If 2.5 =< 1/minscale < 3.5, use isize = 3, etc.
01113          * Under no conditions use isize < 2  */
01114     minscale = L_MIN(scalex, scaley);
01115     size = 1.0 / minscale;   /* ideal filter full width */
01116     isize = L_MAX(2, (l_int32)(size + 0.5));
01117 
01118     pixGetDimensions(pixs, &ws, &hs, NULL);
01119     if ((ws < isize) || (hs < isize)) {
01120         pixDestroy(&pixs);
01121         return (PIX *)ERROR_PTR("pixs too small", procName, NULL);
01122     }
01123     datas = pixGetData(pixs);
01124     wpls = pixGetWpl(pixs);
01125     wd = (l_int32)(scalex * (l_float32)ws + 0.5);
01126     hd = (l_int32)(scaley * (l_float32)hs + 0.5);
01127     if (wd < 1 || hd < 1) {
01128         pixDestroy(&pixs);
01129         return (PIX *)ERROR_PTR("pixd too small", procName, NULL);
01130     }
01131     if ((pixd = pixCreate(wd, hd, d)) == NULL) {
01132         pixDestroy(&pixs);
01133         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01134     }
01135     pixCopyResolution(pixd, pixs);
01136     pixScaleResolution(pixd, scalex, scaley);
01137     datad = pixGetData(pixd);
01138     wpld = pixGetWpl(pixd);
01139     scaleSmoothLow(datad, wd, hd, wpld, datas, ws, hs, d, wpls, isize);
01140 
01141     pixDestroy(&pixs);
01142     return pixd;
01143 }
01144 
01145 
01146 /*!
01147  *  pixScaleRGBToGray2()
01148  *
01149  *      Input:  pixs (32 bpp rgb)
01150  *              rwt, gwt, bwt (must sum to 1.0)
01151  *      Return: pixd, (8 bpp, 2x reduced), or null on error
01152  */
01153 PIX *
01154 pixScaleRGBToGray2(PIX       *pixs,
01155                    l_float32  rwt,
01156                    l_float32  gwt,
01157                    l_float32  bwt)
01158 {
01159 l_int32    wd, hd, wpls, wpld;
01160 l_uint32  *datas, *datad;
01161 PIX       *pixd;
01162 
01163     PROCNAME("pixScaleRGBToGray2");
01164 
01165     if (!pixs)
01166         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01167     if (pixGetDepth(pixs) != 32)
01168         return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
01169     if (rwt + gwt + bwt < 0.98 || rwt + gwt + bwt > 1.02)
01170         return (PIX *)ERROR_PTR("sum of wts should be 1.0", procName, NULL);
01171 
01172     wd = pixGetWidth(pixs) / 2;
01173     hd = pixGetHeight(pixs) / 2;
01174     wpls = pixGetWpl(pixs);
01175     datas = pixGetData(pixs);
01176     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
01177         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01178     pixCopyResolution(pixd, pixs);
01179     pixScaleResolution(pixd, 0.5, 0.5);
01180     wpld = pixGetWpl(pixd);
01181     datad = pixGetData(pixd);
01182     scaleRGBToGray2Low(datad, wd, hd, wpld, datas, wpls, rwt, gwt, bwt);
01183     return pixd;
01184 }
01185 
01186 
01187 /*------------------------------------------------------------------*
01188  *             Downscaling with (antialias) area mapping            *
01189  *------------------------------------------------------------------*/
01190 /*!
01191  *  pixScaleAreaMap()
01192  *
01193  *      Input:  pixs (2, 4, 8 or 32 bpp; and 2, 4, 8 bpp with colormap)
01194  *              scalex, scaley (must both be <= 0.7)
01195  *      Return: pixd, or null on error
01196  * 
01197  *  Notes:
01198  *      (1) This function should only be used when the scale factors are less
01199  *          than or equal to 0.7 (i.e., more than about 1.42x reduction).
01200  *          If either scale factor is larger than 0.7, we issue a warning
01201  *          and invoke pixScale().
01202  *      (2) This works only on 2, 4, 8 and 32 bpp images.  If there is
01203  *          a colormap, it is removed by converting to RGB.  In other
01204  *          cases, we issue a warning and invoke pixScale().
01205  *      (3) It does a relatively expensive area mapping computation, to
01206  *          avoid antialiasing.  It is about 2x slower than pixScaleSmooth(),
01207  *          but the results are much better on fine text.
01208  *      (4) This is typically about 20% faster for the special cases of
01209  *          2x, 4x, 8x and 16x reduction.
01210  *      (5) Surprisingly, there is no speedup (and a slight quality
01211  *          impairment) if you do as many successive 2x reductions as
01212  *          possible, ending with a reduction with a scale factor larger
01213  *          than 0.5.
01214  *
01215  *  *** Warning: implicit assumption about RGB component ordering ***
01216  */
01217 PIX *
01218 pixScaleAreaMap(PIX       *pix,
01219                 l_float32  scalex,
01220                 l_float32  scaley)
01221 {
01222 l_int32    ws, hs, d, wd, hd, wpls, wpld;
01223 l_uint32  *datas, *datad;
01224 l_float32  maxscale;
01225 PIX       *pixs, *pixd, *pixt1, *pixt2, *pixt3;
01226 
01227     PROCNAME("pixScaleAreaMap");
01228 
01229     if (!pix)
01230         return (PIX *)ERROR_PTR("pix not defined", procName, NULL);
01231     d = pixGetDepth(pix);
01232     if (d != 2 && d != 4 && d != 8 && d != 32)
01233         return (PIX *)ERROR_PTR("pix not 2, 4, 8 or 32 bpp", procName, NULL);
01234     maxscale = L_MAX(scalex, scaley);
01235     if (maxscale >= 0.7) {
01236         L_WARNING("scaling factors not < 0.7; doing regular scaling", procName);
01237         return pixScale(pix, scalex, scaley);
01238     }
01239 
01240         /* Special cases: 2x, 4x, 8x, 16x reduction */
01241     if (scalex == 0.5 && scaley == 0.5)
01242         return pixScaleAreaMap2(pix);
01243     if (scalex == 0.25 && scaley == 0.25) {
01244         pixt1 = pixScaleAreaMap2(pix);
01245         pixd = pixScaleAreaMap2(pixt1);
01246         pixDestroy(&pixt1);
01247         return pixd;
01248     }
01249     if (scalex == 0.125 && scaley == 0.125) {
01250         pixt1 = pixScaleAreaMap2(pix);
01251         pixt2 = pixScaleAreaMap2(pixt1);
01252         pixd = pixScaleAreaMap2(pixt2);
01253         pixDestroy(&pixt1);
01254         pixDestroy(&pixt2);
01255         return pixd;
01256     }
01257     if (scalex == 0.0625 && scaley == 0.0625) {
01258         pixt1 = pixScaleAreaMap2(pix);
01259         pixt2 = pixScaleAreaMap2(pixt1);
01260         pixt3 = pixScaleAreaMap2(pixt2);
01261         pixd = pixScaleAreaMap2(pixt3);
01262         pixDestroy(&pixt1);
01263         pixDestroy(&pixt2);
01264         pixDestroy(&pixt3);
01265         return pixd;
01266     }
01267 
01268         /* Remove colormap if necessary.
01269          * If 2 bpp or 4 bpp gray, convert to 8 bpp */
01270     if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
01271         L_WARNING("pix has colormap; removing", procName);
01272         pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC);
01273         d = pixGetDepth(pixs);
01274     }
01275     else if (d == 2 || d == 4) {
01276         pixs = pixConvertTo8(pix, FALSE);
01277         d = 8;
01278     }
01279     else
01280         pixs = pixClone(pix);
01281 
01282     pixGetDimensions(pixs, &ws, &hs, NULL);
01283     datas = pixGetData(pixs);
01284     wpls = pixGetWpl(pixs);
01285     wd = (l_int32)(scalex * (l_float32)ws + 0.5);
01286     hd = (l_int32)(scaley * (l_float32)hs + 0.5);
01287     if (wd < 1 || hd < 1) {
01288         pixDestroy(&pixs);
01289         return (PIX *)ERROR_PTR("pixd too small", procName, NULL);
01290     }
01291     if ((pixd = pixCreate(wd, hd, d)) == NULL) {
01292         pixDestroy(&pixs);
01293         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01294     }
01295     pixCopyResolution(pixd, pixs);
01296     pixScaleResolution(pixd, scalex, scaley);
01297     datad = pixGetData(pixd);
01298     wpld = pixGetWpl(pixd);
01299     if (d == 8)
01300         scaleGrayAreaMapLow(datad, wd, hd, wpld, datas, ws, hs, wpls);
01301     else  /* RGB, d == 32 */
01302         scaleColorAreaMapLow(datad, wd, hd, wpld, datas, ws, hs, wpls);
01303 
01304     pixDestroy(&pixs);
01305     return pixd;
01306 }
01307 
01308 
01309 /*!
01310  *  pixScaleAreaMap2()
01311  *
01312  *      Input:  pixs (2, 4, 8 or 32 bpp; and 2, 4, 8 bpp with colormap)
01313  *      Return: pixd, or null on error
01314  * 
01315  *  Notes:
01316  *      (1) This function does an area mapping (average) for 2x
01317  *          reduction.
01318  *      (2) This works only on 2, 4, 8 and 32 bpp images.  If there is
01319  *          a colormap, it is removed by converting to RGB.
01320  *      (3) Speed on 3 GHz processor:
01321  *             Color: 160 Mpix/sec
01322  *             Gray: 700 Mpix/sec
01323  *          This contrasts with the speed of the general pixScaleAreaMap():
01324  *             Color: 35 Mpix/sec
01325  *             Gray: 50 Mpix/sec
01326  *      (4) From (3), we see that this special function is about 4.5x
01327  *          faster for color and 14x faster for grayscale
01328  *      (5) Consequently, pixScaleAreaMap2() is incorporated into the
01329  *          general area map scaling function, for the special cases
01330  *          of 2x, 4x, 8x and 16x reduction.
01331  */
01332 PIX *
01333 pixScaleAreaMap2(PIX  *pix)
01334 {
01335 l_int32    wd, hd, d, wpls, wpld;
01336 l_uint32  *datas, *datad;
01337 PIX       *pixs, *pixd;
01338 
01339     PROCNAME("pixScaleAreaMap2");
01340 
01341     if (!pix)
01342         return (PIX *)ERROR_PTR("pix not defined", procName, NULL);
01343     d = pixGetDepth(pix);
01344     if (d != 2 && d != 4 && d != 8 && d != 32)
01345         return (PIX *)ERROR_PTR("pix not 2, 4, 8 or 32 bpp", procName, NULL);
01346 
01347         /* Remove colormap if necessary.
01348          * If 2 bpp or 4 bpp gray, convert to 8 bpp */
01349     if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
01350         L_WARNING("pix has colormap; removing", procName);
01351         pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC);
01352         d = pixGetDepth(pixs);
01353     }
01354     else if (d == 2 || d == 4) {
01355         pixs = pixConvertTo8(pix, FALSE);
01356         d = 8;
01357     }
01358     else
01359         pixs = pixClone(pix);
01360 
01361     wd = pixGetWidth(pixs) / 2;
01362     hd = pixGetHeight(pixs) / 2;
01363     datas = pixGetData(pixs);
01364     wpls = pixGetWpl(pixs);
01365     pixd = pixCreate(wd, hd, d);
01366     datad = pixGetData(pixd);
01367     wpld = pixGetWpl(pixd);
01368     pixCopyResolution(pixd, pixs);
01369     pixScaleResolution(pixd, 0.5, 0.5);
01370     scaleAreaMapLow2(datad, wd, hd, wpld, datas, d, wpls);
01371     pixDestroy(&pixs);
01372     return pixd;
01373 }
01374 
01375 
01376 /*------------------------------------------------------------------*
01377  *               Binary scaling by closest pixel sampling           *
01378  *------------------------------------------------------------------*/
01379 /*!
01380  *  pixScaleBinary()
01381  *
01382  *      Input:  pixs (1 bpp)
01383  *              scalex, scaley
01384  *      Return: pixd, or null on error
01385  * 
01386  *  Notes:
01387  *      (1) This function samples from the source without
01388  *          filtering.  As a result, aliasing will occur for
01389  *          subsampling (scalex and scaley < 1.0).
01390  */
01391 PIX *
01392 pixScaleBinary(PIX       *pixs,
01393                l_float32  scalex,
01394                l_float32  scaley)
01395 {
01396 l_int32    ws, hs, wpls, wd, hd, wpld;
01397 l_uint32  *datas, *datad;
01398 PIX       *pixd;
01399 
01400     PROCNAME("pixScaleBinary");
01401 
01402     if (!pixs)
01403         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01404     if (pixGetDepth(pixs) != 1)
01405         return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, NULL);
01406     if (scalex == 1.0 && scaley == 1.0)
01407         return pixCopy(NULL, pixs);
01408 
01409     pixGetDimensions(pixs, &ws, &hs, NULL);
01410     datas = pixGetData(pixs);
01411     wpls = pixGetWpl(pixs);
01412     wd = (l_int32)(scalex * (l_float32)ws + 0.5);
01413     hd = (l_int32)(scaley * (l_float32)hs + 0.5);
01414     if ((pixd = pixCreate(wd, hd, 1)) == NULL)
01415         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01416     pixCopyColormap(pixd, pixs);
01417     pixCopyResolution(pixd, pixs);
01418     pixScaleResolution(pixd, scalex, scaley);
01419     datad = pixGetData(pixd);
01420     wpld = pixGetWpl(pixd);
01421     scaleBinaryLow(datad, wd, hd, wpld, datas, ws, hs, wpls);
01422     return pixd;
01423 }
01424 
01425 
01426 
01427 /*------------------------------------------------------------------*
01428  *      Scale-to-gray (1 bpp --> 8 bpp; arbitrary downscaling)      *
01429  *------------------------------------------------------------------*/
01430 /*!
01431  *  pixScaleToGray()
01432  *
01433  *      Input:  pixs (1 bpp)
01434  *              scalefactor (reduction, < 1.0)
01435  *      Return: pixd (8 bpp), scaled down by scalefactor in each direction,
01436  *              or NULL on error.
01437  *
01438  *  Notes:
01439  *
01440  *  For faster scaling in the range of scalefactors from 0.0625 to 0.5,
01441  *  with very little difference in quality, use pixScaleToGrayFast().
01442  *
01443  *  Binary images have sharp edges, so they intrinsically have very
01444  *  high frequency content.  To avoid aliasing, they must be low-pass
01445  *  filtered, which tends to blur the edges.  How can we keep relatively
01446  *  crisp edges without aliasing?  The trick is to do binary upscaling
01447  *  followed by a power-of-2 scaleToGray.  For large reductions, where
01448  *  you don't end up with much detail, some corners can be cut.
01449  *
01450  *  The intent here is to get high quality reduced grayscale
01451  *  images with relatively little computation.  We do binary
01452  *  pre-scaling followed by scaleToGrayN() for best results,
01453  *  esp. to avoid excess blur when the scale factor is near
01454  *  an inverse power of 2.  Where a low-pass filter is required,
01455  *  we use simple convolution kernels: either the hat filter for
01456  *  linear interpolation or a flat filter for larger downscaling.
01457  *  Other choices, such as a perfect bandpass filter with infinite extent
01458  *  (the sinc) or various approximations to it (e.g., lanczos), are
01459  *  unnecessarily expensive.
01460  *
01461  *  The choices made are as follows:
01462  *      (1) Do binary upscaling before scaleToGrayN() for scalefactors > 1/8
01463  *      (2) Do binary downscaling before scaleToGray8() for scalefactors
01464  *          between 1/16 and 1/8.
01465  *      (3) Use scaleToGray16() before grayscale downscaling for
01466  *          scalefactors less than 1/16
01467  *  Another reasonable choice would be to start binary downscaling
01468  *  for scalefactors below 1/4, rather than below 1/8 as we do here.
01469  *
01470  *  The general scaling rules, not all of which are used here, go as follows:
01471  *      (1) For grayscale upscaling, use pixScaleGrayLI().  However,
01472  *          note that edges will be visibly blurred for scalefactors
01473  *          near (but above) 1.0.  Replication will avoid edge blur,
01474  *          and should be considered for factors very near 1.0.
01475  *      (2) For grayscale downscaling with a scale factor larger than
01476  *          about 0.7, use pixScaleGrayLI().  For scalefactors near
01477  *          (but below) 1.0, you tread between Scylla and Charybdis.
01478  *          pixScaleGrayLI() again gives edge blurring, but
01479  *          pixScaleBySampling() gives visible aliasing.
01480  *      (3) For grayscale downscaling with a scale factor smaller than
01481  *          about 0.7, use pixScaleSmooth()
01482  *      (4) For binary input images, do as much scale to gray as possible
01483  *          using the special integer functions (2, 3, 4, 8 and 16).
01484  *      (5) It is better to upscale in binary, followed by scaleToGrayN()
01485  *          than to do scaleToGrayN() followed by an upscale using either
01486  *          LI or oversampling.
01487  *      (6) It may be better to downscale in binary, followed by
01488  *          scaleToGrayN() than to first use scaleToGrayN() followed by
01489  *          downscaling.  For downscaling between 8x and 16x, this is
01490  *          a reasonable option.
01491  *      (7) For reductions greater than 16x, it's reasonable to use
01492  *          scaleToGray16() followed by further grayscale downscaling.
01493  */
01494 PIX *
01495 pixScaleToGray(PIX       *pixs,
01496                l_float32  scalefactor)
01497 {
01498 l_int32    w, h, minsrc, mindest;
01499 l_float32  mag, red;
01500 PIX       *pixt, *pixd;
01501 
01502     PROCNAME("pixScaleToGray");
01503 
01504     if (!pixs)
01505         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01506     if (pixGetDepth(pixs) != 1)
01507         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
01508     if (scalefactor >= 1.0)
01509         return (PIX *)ERROR_PTR("scalefactor not < 1.0", procName, NULL);
01510     pixGetDimensions(pixs, &w, &h, NULL);
01511     minsrc = L_MIN(w, h);
01512     mindest = (l_int32)((l_float32)minsrc * scalefactor);
01513     if (mindest < 2)
01514         return (PIX *)ERROR_PTR("scalefactor too small", procName, NULL);
01515 
01516     if (scalefactor > 0.5) {   /* see note (5) */
01517         mag = 2.0 * scalefactor;  /* will be < 2.0 */
01518 /*        fprintf(stderr, "2x with mag %7.3f\n", mag);  */
01519         if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL)
01520             return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
01521         pixd = pixScaleToGray2(pixt);
01522     }
01523     else if (scalefactor == 0.5)
01524         return pixd = pixScaleToGray2(pixs);
01525     else if (scalefactor > 0.33333) {   /* see note (5) */
01526         mag = 3.0 * scalefactor;   /* will be < 1.5 */
01527 /*        fprintf(stderr, "3x with mag %7.3f\n", mag);  */
01528         if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL)
01529             return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
01530         pixd = pixScaleToGray3(pixt);
01531     }
01532     else if (scalefactor > 0.25) {  /* see note (5) */
01533         mag = 4.0 * scalefactor;   /* will be < 1.3333 */
01534 /*        fprintf(stderr, "4x with mag %7.3f\n", mag);  */
01535         if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL)
01536             return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
01537         pixd = pixScaleToGray4(pixt);
01538     }
01539     else if (scalefactor == 0.25)
01540         return pixd = pixScaleToGray4(pixs);
01541     else if (scalefactor > 0.16667) {  /* see note (5) */
01542         mag = 6.0 * scalefactor;   /* will be < 1.5 */
01543 /*        fprintf(stderr, "6x with mag %7.3f\n", mag); */
01544         if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL)
01545             return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
01546         pixd = pixScaleToGray6(pixt);
01547     }
01548     else if (scalefactor == 0.16667)
01549         return pixd = pixScaleToGray6(pixs);
01550     else if (scalefactor > 0.125) {  /* see note (5) */
01551         mag = 8.0 * scalefactor;   /*  will be < 1.3333  */
01552 /*        fprintf(stderr, "8x with mag %7.3f\n", mag);  */
01553         if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL)
01554             return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
01555         pixd = pixScaleToGray8(pixt);
01556     }
01557     else if (scalefactor == 0.125)
01558         return pixd = pixScaleToGray8(pixs);
01559     else if (scalefactor > 0.0625) {  /* see note (6) */
01560         red = 8.0 * scalefactor;   /* will be > 0.5 */
01561 /*        fprintf(stderr, "8x with red %7.3f\n", red);  */
01562         if ((pixt = pixScaleBinary(pixs, red, red)) == NULL)
01563             return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
01564         pixd = pixScaleToGray8(pixt);
01565     }
01566     else if (scalefactor == 0.0625)
01567         return pixd = pixScaleToGray16(pixs);
01568     else {  /* see note (7) */
01569         red = 16.0 * scalefactor;  /* will be <= 1.0 */
01570 /*        fprintf(stderr, "16x with red %7.3f\n", red);  */
01571         if ((pixt = pixScaleToGray16(pixs)) == NULL)
01572             return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
01573         if (red < 0.7)
01574             pixd = pixScaleSmooth(pixt, red, red);  /* see note (3) */
01575         else        
01576             pixd = pixScaleGrayLI(pixt, red, red);  /* see note (2) */
01577     }
01578 
01579     pixDestroy(&pixt);
01580     if (!pixd)
01581         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01582     else
01583         return pixd;
01584 }
01585 
01586 
01587 
01588 /*!
01589  *  pixScaleToGrayFast()
01590  *
01591  *      Input:  pixs (1 bpp)
01592  *              scalefactor (reduction, < 1.0)
01593  *      Return: pixd (8 bpp), scaled down by scalefactor in each direction,
01594  *              or NULL on error.
01595  *
01596  *  Notes:
01597  *      (1) See notes in pixScaleToGray() for the basic approach.
01598  *      (2) This function is considerably less expensive than pixScaleToGray()
01599  *          for scalefactor in the range (0.0625 ... 0.5), and the
01600  *          quality is nearly as good.
01601  *      (3) Unlike pixScaleToGray(), which does binary upscaling before
01602  *          downscaling for scale factors >= 0.0625, pixScaleToGrayFast()
01603  *          first downscales in binary for all scale factors < 0.5, and
01604  *          then does a 2x scale-to-gray as the final step.  For
01605  *          scale factors < 0.0625, both do a 16x scale-to-gray, followed
01606  *          by further grayscale reduction.
01607  */
01608 PIX *
01609 pixScaleToGrayFast(PIX       *pixs,
01610                    l_float32  scalefactor)
01611 {
01612 l_int32    w, h, minsrc, mindest;
01613 l_float32  eps, factor;
01614 PIX       *pixt, *pixd;
01615 
01616     PROCNAME("pixScaleToGrayFast");
01617 
01618     if (!pixs)
01619         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01620     if (pixGetDepth(pixs) != 1)
01621         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
01622     if (scalefactor >= 1.0)
01623         return (PIX *)ERROR_PTR("scalefactor not < 1.0", procName, NULL);
01624     pixGetDimensions(pixs, &w, &h, NULL);
01625     minsrc = L_MIN(w, h);
01626     mindest = (l_int32)((l_float32)minsrc * scalefactor);
01627     if (mindest < 2)
01628         return (PIX *)ERROR_PTR("scalefactor too small", procName, NULL);
01629     eps = 0.0001;
01630 
01631         /* Handle the special cases */
01632     if (scalefactor > 0.5 - eps && scalefactor < 0.5 + eps)
01633         return pixScaleToGray2(pixs);
01634     else if (scalefactor > 0.33333 - eps && scalefactor < 0.33333 + eps)
01635         return pixScaleToGray3(pixs);
01636     else if (scalefactor > 0.25 - eps && scalefactor < 0.25 + eps)
01637         return pixScaleToGray4(pixs);
01638     else if (scalefactor > 0.16666 - eps && scalefactor < 0.16666 + eps)
01639         return pixScaleToGray6(pixs);
01640     else if (scalefactor > 0.125 - eps && scalefactor < 0.125 + eps)
01641         return pixScaleToGray8(pixs);
01642     else if (scalefactor > 0.0625 - eps && scalefactor < 0.0625 + eps)
01643         return pixScaleToGray16(pixs);
01644 
01645     if (scalefactor > 0.0625) {  /* scale binary first */
01646         factor = 2.0 * scalefactor;
01647         if ((pixt = pixScaleBinary(pixs, factor, factor)) == NULL)
01648             return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
01649         pixd = pixScaleToGray2(pixt);
01650     }
01651     else {  /* scalefactor < 0.0625; scale-to-gray first */
01652         factor = 16.0 * scalefactor;  /* will be < 1.0 */
01653         if ((pixt = pixScaleToGray16(pixs)) == NULL)
01654             return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
01655         if (factor < 0.7)
01656             pixd = pixScaleSmooth(pixt, factor, factor);
01657         else        
01658             pixd = pixScaleGrayLI(pixt, factor, factor);
01659     }
01660     pixDestroy(&pixt);
01661     if (!pixd)
01662         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01663     else
01664         return pixd;
01665 }
01666 
01667 
01668 /*-----------------------------------------------------------------------*
01669  *          Scale-to-gray (1 bpp --> 8 bpp; integer downscaling)         *
01670  *-----------------------------------------------------------------------*/
01671 /*!
01672  *  pixScaleToGray2()
01673  *
01674  *      Input:  pixs (1 bpp)
01675  *      Return: pixd (8 bpp), scaled down by 2x in each direction,
01676  *              or null on error.
01677  */
01678 PIX *
01679 pixScaleToGray2(PIX  *pixs)
01680 {
01681 l_uint8   *valtab;
01682 l_int32    ws, hs, wd, hd;
01683 l_int32    wpld, wpls;
01684 l_uint32  *sumtab;
01685 l_uint32  *datas, *datad;
01686 PIX       *pixd;
01687 
01688     PROCNAME("pixScaleToGray2");
01689 
01690     if (!pixs)
01691         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01692     if (pixGetDepth(pixs) != 1)
01693         return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, NULL);
01694 
01695     pixGetDimensions(pixs, &ws, &hs, NULL);
01696     wd = ws / 2;
01697     hd = hs / 2;
01698     if (wd == 0 || hd == 0)
01699         return (PIX *)ERROR_PTR("pixs too small", procName, NULL);
01700 
01701     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
01702         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01703     pixCopyResolution(pixd, pixs);
01704     pixScaleResolution(pixd, 0.5, 0.5);
01705     datas = pixGetData(pixs);
01706     datad = pixGetData(pixd);
01707     wpls = pixGetWpl(pixs);
01708     wpld = pixGetWpl(pixd);
01709 
01710     if ((sumtab = makeSumTabSG2()) == NULL)
01711         return (PIX *)ERROR_PTR("sumtab not made", procName, NULL);
01712     if ((valtab = makeValTabSG2()) == NULL)
01713         return (PIX *)ERROR_PTR("valtab not made", procName, NULL);
01714 
01715     scaleToGray2Low(datad, wd, hd, wpld, datas, wpls, sumtab, valtab);
01716 
01717     FREE(sumtab);
01718     FREE(valtab);
01719     return pixd;
01720 }
01721 
01722 
01723 /*!
01724  *  pixScaleToGray3()
01725  *
01726  *      Input:  pixs (1 bpp)
01727  *      Return: pixd (8 bpp), scaled down by 3x in each direction,
01728  *              or null on error.
01729  *
01730  *  Notes:
01731  *      (1) Speed is about 100 x 10^6 src-pixels/sec/GHz.
01732  *          Another way to express this is it processes 1 src pixel
01733  *          in about 10 cycles.
01734  *      (2) The width of pixd is truncated is truncated to a factor of 8.
01735  */
01736 PIX *
01737 pixScaleToGray3(PIX  *pixs)
01738 {
01739 l_uint8   *valtab;
01740 l_int32    ws, hs, wd, hd;
01741 l_int32    wpld, wpls;
01742 l_uint32  *sumtab;
01743 l_uint32  *datas, *datad;
01744 PIX       *pixd;
01745 
01746     PROCNAME("pixScaleToGray3");
01747 
01748     if (!pixs)
01749         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01750     if (pixGetDepth(pixs) != 1)
01751         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
01752 
01753     pixGetDimensions(pixs, &ws, &hs, NULL);
01754     wd = (ws / 3) & 0xfffffff8;    /* truncate to factor of 8 */
01755     hd = hs / 3;
01756     if (wd == 0 || hd == 0)
01757         return (PIX *)ERROR_PTR("pixs too small", procName, NULL);
01758 
01759     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
01760         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01761     pixCopyResolution(pixd, pixs);
01762     pixScaleResolution(pixd, 0.33333, 0.33333);
01763     datas = pixGetData(pixs);
01764     datad = pixGetData(pixd);
01765     wpls = pixGetWpl(pixs);
01766     wpld = pixGetWpl(pixd);
01767 
01768     if ((sumtab = makeSumTabSG3()) == NULL)
01769         return (PIX *)ERROR_PTR("sumtab not made", procName, NULL);
01770     if ((valtab = makeValTabSG3()) == NULL)
01771         return (PIX *)ERROR_PTR("valtab not made", procName, NULL);
01772 
01773     scaleToGray3Low(datad, wd, hd, wpld, datas, wpls, sumtab, valtab);
01774 
01775     FREE(sumtab);
01776     FREE(valtab);
01777     return pixd;
01778 }
01779 
01780 
01781 /*!
01782  *  pixScaleToGray4()
01783  *
01784  *      Input:  pixs (1 bpp)
01785  *      Return: pixd (8 bpp), scaled down by 4x in each direction,
01786  *              or null on error.
01787  *
01788  *  Notes:
01789  *      (1) The width of pixd is truncated is truncated to a factor of 2.
01790  */
01791 PIX *
01792 pixScaleToGray4(PIX  *pixs)
01793 {
01794 l_uint8   *valtab;
01795 l_int32    ws, hs, wd, hd;
01796 l_int32    wpld, wpls;
01797 l_uint32  *sumtab;
01798 l_uint32  *datas, *datad;
01799 PIX       *pixd;
01800 
01801     PROCNAME("pixScaleToGray4");
01802 
01803     if (!pixs)
01804         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01805     if (pixGetDepth(pixs) != 1)
01806         return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, NULL);
01807 
01808     pixGetDimensions(pixs, &ws, &hs, NULL);
01809     wd = (ws / 4) & 0xfffffffe;    /* truncate to factor of 2 */
01810     hd = hs / 4;
01811     if (wd == 0 || hd == 0)
01812         return (PIX *)ERROR_PTR("pixs too small", procName, NULL);
01813 
01814     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
01815         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01816     pixCopyResolution(pixd, pixs);
01817     pixScaleResolution(pixd, 0.25, 0.25);
01818     datas = pixGetData(pixs);
01819     datad = pixGetData(pixd);
01820     wpls = pixGetWpl(pixs);
01821     wpld = pixGetWpl(pixd);
01822 
01823     if ((sumtab = makeSumTabSG4()) == NULL)
01824         return (PIX *)ERROR_PTR("sumtab not made", procName, NULL);
01825     if ((valtab = makeValTabSG4()) == NULL)
01826         return (PIX *)ERROR_PTR("valtab not made", procName, NULL);
01827 
01828     scaleToGray4Low(datad, wd, hd, wpld, datas, wpls, sumtab, valtab);
01829 
01830     FREE(sumtab);
01831     FREE(valtab);
01832     return pixd;
01833 }
01834 
01835 
01836 
01837 /*!
01838  *  pixScaleToGray6()
01839  *
01840  *      Input:  pixs (1 bpp)
01841  *      Return: pixd (8 bpp), scaled down by 6x in each direction,
01842  *              or null on error.
01843  *
01844  *  Notes:
01845  *      (1) The width of pixd is truncated is truncated to a factor of 8.
01846  */
01847 PIX *
01848 pixScaleToGray6(PIX  *pixs)
01849 {
01850 l_uint8   *valtab;
01851 l_int32    ws, hs, wd, hd, wpld, wpls;
01852 l_int32   *tab8;
01853 l_uint32  *datas, *datad;
01854 PIX       *pixd;
01855 
01856     PROCNAME("pixScaleToGray6");
01857 
01858     if (!pixs)
01859         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01860     if (pixGetDepth(pixs) != 1)
01861         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
01862 
01863     pixGetDimensions(pixs, &ws, &hs, NULL);
01864     wd = (ws / 6) & 0xfffffff8;    /* truncate to factor of 8 */
01865     hd = hs / 6;
01866     if (wd == 0 || hd == 0)
01867         return (PIX *)ERROR_PTR("pixs too small", procName, NULL);
01868 
01869     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
01870         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01871     pixCopyResolution(pixd, pixs);
01872     pixScaleResolution(pixd, 0.16667, 0.16667);
01873     datas = pixGetData(pixs);
01874     datad = pixGetData(pixd);
01875     wpls = pixGetWpl(pixs);
01876     wpld = pixGetWpl(pixd);
01877 
01878     if ((tab8 = makePixelSumTab8()) == NULL)
01879         return (PIX *)ERROR_PTR("tab8 not made", procName, NULL);
01880     if ((valtab = makeValTabSG6()) == NULL)
01881         return (PIX *)ERROR_PTR("valtab not made", procName, NULL);
01882 
01883     scaleToGray6Low(datad, wd, hd, wpld, datas, wpls, tab8, valtab);
01884 
01885     FREE(tab8);
01886     FREE(valtab);
01887     return pixd;
01888 }
01889 
01890 
01891 /*!
01892  *  pixScaleToGray8()
01893  *
01894  *      Input:  pixs (1 bpp)
01895  *      Return: pixd (8 bpp), scaled down by 8x in each direction,
01896  *              or null on error
01897  */
01898 PIX *
01899 pixScaleToGray8(PIX  *pixs)
01900 {
01901 l_uint8   *valtab;
01902 l_int32    ws, hs, wd, hd;
01903 l_int32    wpld, wpls;
01904 l_int32   *tab8;
01905 l_uint32  *datas, *datad;
01906 PIX       *pixd;
01907 
01908     PROCNAME("pixScaleToGray8");
01909 
01910     if (!pixs)
01911         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01912     if (pixGetDepth(pixs) != 1)
01913         return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, NULL);
01914 
01915     pixGetDimensions(pixs, &ws, &hs, NULL);
01916     wd = ws / 8;  /* truncate to nearest dest byte */
01917     hd = hs / 8;
01918     if (wd == 0 || hd == 0)
01919         return (PIX *)ERROR_PTR("pixs too small", procName, NULL);
01920 
01921     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
01922         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01923     pixCopyResolution(pixd, pixs);
01924     pixScaleResolution(pixd, 0.125, 0.125);
01925     datas = pixGetData(pixs);
01926     datad = pixGetData(pixd);
01927     wpls = pixGetWpl(pixs);
01928     wpld = pixGetWpl(pixd);
01929 
01930     if ((tab8 = makePixelSumTab8()) == NULL)
01931         return (PIX *)ERROR_PTR("tab8 not made", procName, NULL);
01932     if ((valtab = makeValTabSG8()) == NULL)
01933         return (PIX *)ERROR_PTR("valtab not made", procName, NULL);
01934 
01935     scaleToGray8Low(datad, wd, hd, wpld, datas, wpls, tab8, valtab);
01936 
01937     FREE(tab8);
01938     FREE(valtab);
01939     return pixd;
01940 }
01941 
01942 
01943 /*!
01944  *  pixScaleToGray16()
01945  *
01946  *      Input:  pixs (1 bpp)
01947  *      Return: pixd (8 bpp), scaled down by 16x in each direction,
01948  *              or null on error.
01949  */
01950 PIX *
01951 pixScaleToGray16(PIX  *pixs)
01952 {
01953 l_int32    ws, hs, wd, hd;
01954 l_int32    wpld, wpls;
01955 l_int32   *tab8;
01956 l_uint32  *datas, *datad;
01957 PIX       *pixd;
01958 
01959     PROCNAME("pixScaleToGray16");
01960 
01961     if (!pixs)
01962         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01963     if (pixGetDepth(pixs) != 1)
01964         return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, NULL);
01965 
01966     pixGetDimensions(pixs, &ws, &hs, NULL);
01967     wd = ws / 16;
01968     hd = hs / 16;
01969     if (wd == 0 || hd == 0)
01970         return (PIX *)ERROR_PTR("pixs too small", procName, NULL);
01971 
01972     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
01973         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01974     pixCopyResolution(pixd, pixs);
01975     pixScaleResolution(pixd, 0.0625, 0.0625);
01976     datas = pixGetData(pixs);
01977     datad = pixGetData(pixd);
01978     wpls = pixGetWpl(pixs);
01979     wpld = pixGetWpl(pixd);
01980 
01981     if ((tab8 = makePixelSumTab8()) == NULL)
01982         return (PIX *)ERROR_PTR("tab8 not made", procName, NULL);
01983 
01984     scaleToGray16Low(datad, wd, hd, wpld, datas, wpls, tab8);
01985 
01986     FREE(tab8);
01987     return pixd;
01988 }
01989 
01990 
01991 /*------------------------------------------------------------------*
01992  *    Scale-to-gray mipmap(1 bpp --> 8 bpp, arbitrary reduction)    *
01993  *------------------------------------------------------------------*/
01994 /*!
01995  *  pixScaleToGrayMipmap()
01996  *
01997  *      Input:  pixs (1 bpp)
01998  *              scalefactor (reduction, < 1.0)
01999  *      Return: pixd (8 bpp), scaled down by scalefactor in each direction,
02000  *              or NULL on error.
02001  *
02002  *  Notes:
02003  *
02004  *  This function is here mainly for pedagogical reasons.
02005  *  Mip-mapping is widely used in graphics for texture mapping, because
02006  *  the texture changes smoothly with scale.  This is accomplished by
02007  *  constructing a multiresolution pyramid and, for each pixel,
02008  *  doing a linear interpolation between corresponding pixels in
02009  *  the two planes of the pyramid that bracket the desired resolution.
02010  *  The computation is very efficient, and is implemented in hardware
02011  *  in high-end graphics cards.
02012  *
02013  *  We can use mip-mapping for scale-to-gray by using two scale-to-gray
02014  *  reduced images (we don't need the entire pyramid) selected from
02015  *  the set {2x, 4x, ... 16x}, and interpolating.  However, we get
02016  *  severe aliasing, probably because we are subsampling from the
02017  *  higher resolution image.  The method is very fast, but the result
02018  *  is very poor.  In fact, the results don't look any better than
02019  *  either subsampling off the higher-res grayscale image or oversampling
02020  *  on the lower-res image.  Consequently, this method should NOT be used
02021  *  for generating reduced images, scale-to-gray or otherwise.
02022  */
02023 PIX *
02024 pixScaleToGrayMipmap(PIX       *pixs,
02025                      l_float32  scalefactor)
02026 {
02027 l_int32    w, h, minsrc, mindest;
02028 l_float32  red;
02029 PIX       *pixs1, *pixs2, *pixt, *pixd;
02030 
02031     PROCNAME("pixScaleToGrayMipmap");
02032 
02033     if (!pixs)
02034         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02035     if (pixGetDepth(pixs) != 1)
02036         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
02037     if (scalefactor >= 1.0)
02038         return (PIX *)ERROR_PTR("scalefactor not < 1.0", procName, NULL);
02039     pixGetDimensions(pixs, &w, &h, NULL);
02040     minsrc = L_MIN(w, h);
02041     mindest = (l_int32)((l_float32)minsrc * scalefactor);
02042     if (mindest < 2)
02043         return (PIX *)ERROR_PTR("scalefactor too small", procName, NULL);
02044 
02045     if (scalefactor > 0.5) {
02046         pixs1 = pixConvert1To8(NULL, pixs, 255, 0);
02047         pixs2 = pixScaleToGray2(pixs);
02048         red = scalefactor;
02049     }
02050     else if (scalefactor == 0.5) {
02051         return pixScaleToGray2(pixs);
02052     }
02053     else if (scalefactor > 0.25) {
02054         pixs1 = pixScaleToGray2(pixs);
02055         pixs2 = pixScaleToGray4(pixs);
02056         red = 2. * scalefactor;
02057     }
02058     else if (scalefactor == 0.25) {
02059         return pixScaleToGray4(pixs);
02060     }
02061     else if (scalefactor > 0.125) {
02062         pixs1 = pixScaleToGray4(pixs);
02063         pixs2 = pixScaleToGray8(pixs);
02064         red = 4. * scalefactor;
02065     }
02066     else if (scalefactor == 0.125) {
02067         return pixScaleToGray8(pixs);
02068     }
02069     else if (scalefactor > 0.0625) {
02070         pixs1 = pixScaleToGray8(pixs);
02071         pixs2 = pixScaleToGray16(pixs);
02072         red = 8. * scalefactor;
02073     }
02074     else if (scalefactor == 0.0625) {
02075         return pixScaleToGray16(pixs);
02076     }
02077     else {  /* end of the pyramid; just do it */
02078         red = 16.0 * scalefactor;  /* will be <= 1.0 */
02079         if ((pixt = pixScaleToGray16(pixs)) == NULL)
02080             return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
02081         if (red < 0.7)
02082             pixd = pixScaleSmooth(pixt, red, red);
02083         else        
02084             pixd = pixScaleGrayLI(pixt, red, red);
02085         pixDestroy(&pixt);
02086         return pixd;
02087     }
02088 
02089     pixd = pixScaleMipmap(pixs1, pixs2, red);
02090 
02091     pixDestroy(&pixs1);
02092     pixDestroy(&pixs2);
02093     return pixd;
02094 }
02095 
02096 
02097 /*------------------------------------------------------------------*
02098  *                  Grayscale scaling using mipmap                  *
02099  *------------------------------------------------------------------*/
02100 /*!
02101  *  pixScaleMipmap()
02102  *
02103  *      Input:  pixs1 (high res 8 bpp)
02104  *              pixs2 (low res -- 2x reduced -- 8 bpp)
02105  *              scale (reduction with respect to high res image, > 0.5)
02106  *      Return: 8 bpp pix, scaled down by reduction in each direction,
02107  *              or NULL on error.
02108  *
02109  *  Notes:
02110  *      (1) See notes in pixScaleToGrayMipmap().
02111  *      (2) This function suffers from aliasing effects that are
02112  *          easily seen in document images.
02113  */
02114 PIX *
02115 pixScaleMipmap(PIX       *pixs1,
02116                PIX       *pixs2,
02117                l_float32  scale)
02118 {
02119 l_int32    ws1, hs1, ds1, ws2, hs2, ds2, wd, hd, wpls1, wpls2, wpld;
02120 l_uint32  *datas1, *datas2, *datad;
02121 PIX       *pixd;
02122 
02123     PROCNAME("pixScaleMipmap");
02124 
02125     if (!pixs1)
02126         return (PIX *)ERROR_PTR("pixs1 not defined", procName, NULL);
02127     if (!pixs2)
02128         return (PIX *)ERROR_PTR("pixs2 not defined", procName, NULL);
02129     pixGetDimensions(pixs1, &ws1, &hs1, &ds1);
02130     pixGetDimensions(pixs2, &ws2, &hs2, &ds2);
02131     if (ds1 != 8 || ds2 != 8)
02132         return (PIX *)ERROR_PTR("pixs1, pixs2 not both 8 bpp", procName, NULL);
02133     if (scale > 1.0 || scale < 0.5)
02134         return (PIX *)ERROR_PTR("scale not in [0.5, 1.0]", procName, NULL);
02135     if (pixGetColormap(pixs1) || pixGetColormap(pixs2))
02136         L_WARNING("pixs1 or pixs2 has colormap", procName);
02137     if (ws1 < 2 * ws2)
02138         return (PIX *)ERROR_PTR("invalid width ratio", procName, NULL);
02139     if (hs1 < 2 * hs2)
02140         return (PIX *)ERROR_PTR("invalid height ratio", procName, NULL);
02141 
02142         /* Generate wd and hd from the lower resolution dimensions,
02143          * to guarantee staying within both src images */
02144     datas1 = pixGetData(pixs1);
02145     wpls1 = pixGetWpl(pixs1);
02146     datas2 = pixGetData(pixs2);
02147     wpls2 = pixGetWpl(pixs2);
02148     wd = (l_int32)(2. * scale * pixGetWidth(pixs2));
02149     hd = (l_int32)(2. * scale * pixGetHeight(pixs2));
02150     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
02151         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
02152     pixCopyResolution(pixd, pixs1);
02153     pixScaleResolution(pixd, scale, scale);
02154     datad = pixGetData(pixd);
02155     wpld = pixGetWpl(pixd);
02156 
02157     scaleMipmapLow(datad, wd, hd, wpld, datas1, wpls1, datas2, wpls2, scale);
02158     return pixd;
02159 }
02160 
02161 
02162 /*------------------------------------------------------------------*
02163  *                  Replicated (integer) expansion                  *
02164  *------------------------------------------------------------------*/
02165 /*!
02166  *  pixExpandReplicate()
02167  *
02168  *      Input:  pixs (1, 2, 4, 8, 16, 32 bpp)
02169  *              factor (integer scale factor for replicative expansion)
02170  *      Return: pixd (scaled up), or null on error.
02171  */
02172 PIX *
02173 pixExpandReplicate(PIX     *pixs,
02174                    l_int32  factor)
02175 {
02176 l_int32    w, h, d, wd, hd, wpls, wpld, bpld, start, i, j, k;
02177 l_uint8    sval;
02178 l_uint16   sval16;
02179 l_uint32   sval32;
02180 l_uint32  *lines, *datas, *lined, *datad;
02181 PIX       *pixd;
02182 
02183     PROCNAME("pixExpandReplicate");
02184 
02185     if (!pixs)
02186         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02187     pixGetDimensions(pixs, &w, &h, &d);
02188     if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
02189         return (PIX *)ERROR_PTR("depth not in {1,2,4,8,16,32}", procName, NULL);
02190     if (factor <= 0)
02191         return (PIX *)ERROR_PTR("factor <= 0; invalid", procName, NULL);
02192     if (factor == 1)
02193         return pixCopy(NULL, pixs);
02194 
02195     if (d == 1)
02196         return pixExpandBinaryReplicate(pixs, factor);
02197 
02198     wd = factor * w;
02199     hd = factor * h;
02200     if ((pixd = pixCreate(wd, hd, d)) == NULL)
02201         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
02202     pixCopyColormap(pixd, pixs);
02203     pixCopyResolution(pixd, pixs);
02204     pixScaleResolution(pixd, (l_float32)factor, (l_float32)factor);
02205     datas = pixGetData(pixs);
02206     wpls = pixGetWpl(pixs);
02207     datad = pixGetData(pixd);
02208     wpld = pixGetWpl(pixd);
02209 
02210     switch (d) {
02211     case 2:
02212         bpld = (wd + 3) / 4;  /* occupied bytes only */
02213         for (i = 0; i < h; i++) {
02214             lines = datas + i * wpls;
02215             lined = datad + factor * i * wpld;
02216             for (j = 0; j < w; j++) {
02217                 sval = GET_DATA_DIBIT(lines, j);
02218                 start = factor * j;
02219                 for (k = 0; k < factor; k++)
02220                     SET_DATA_DIBIT(lined, start + k, sval);
02221             }
02222             for (k = 1; k < factor; k++)
02223                 memcpy(lined + k * wpld, lined, 4 * wpld);
02224         }
02225         break;
02226     case 4:
02227         bpld = (wd + 1) / 2;  /* occupied bytes only */
02228         for (i = 0; i < h; i++) {
02229             lines = datas + i * wpls;
02230             lined = datad + factor * i * wpld;
02231             for (j = 0; j < w; j++) {
02232                 sval = GET_DATA_QBIT(lines, j);
02233                 start = factor * j;
02234                 for (k = 0; k < factor; k++)
02235                     SET_DATA_QBIT(lined, start + k, sval);
02236             }
02237             for (k = 1; k < factor; k++)
02238                 memcpy(lined + k * wpld, lined, 4 * wpld);
02239         }
02240         break;
02241     case 8:
02242         for (i = 0; i < h; i++) {
02243             lines = datas + i * wpls;
02244             lined = datad + factor * i * wpld;
02245             for (j = 0; j < w; j++) {
02246                 sval = GET_DATA_BYTE(lines, j);
02247                 start = factor * j;
02248                 for (k = 0; k < factor; k++)
02249                     SET_DATA_BYTE(lined, start + k, sval);
02250             }
02251             for (k = 1; k < factor; k++)
02252                 memcpy(lined + k * wpld, lined, 4 * wpld);
02253         }
02254         break;
02255     case 16:
02256         for (i = 0; i < h; i++) {
02257             lines = datas + i * wpls;
02258             lined = datad + factor * i * wpld;
02259             for (j = 0; j < w; j++) {
02260                 sval16 = GET_DATA_TWO_BYTES(lines, j);
02261                 start = factor * j;
02262                 for (k = 0; k < factor; k++)
02263                     SET_DATA_TWO_BYTES(lined, start + k, sval16);
02264             }
02265             for (k = 1; k < factor; k++)
02266                 memcpy(lined + k * wpld, lined, 4 * wpld);
02267         }
02268         break;
02269     case 32:
02270         for (i = 0; i < h; i++) {
02271             lines = datas + i * wpls;
02272             lined = datad + factor * i * wpld;
02273             for (j = 0; j < w; j++) {
02274                 sval32 = *(lines + j);
02275                 start = factor * j;
02276                 for (k = 0; k < factor; k++)
02277                     *(lined + start + k) = sval32;
02278             }
02279             for (k = 1; k < factor; k++)
02280                 memcpy(lined + k * wpld, lined, 4 * wpld);
02281         }
02282         break;
02283     default:
02284         fprintf(stderr, "invalid depth\n");
02285     }
02286 
02287     return pixd;
02288 }
02289 
02290 
02291 /*------------------------------------------------------------------*
02292  *                Scale 2x followed by binarization                 *
02293  *------------------------------------------------------------------*/
02294 /*!
02295  *  pixScaleGray2xLIThresh()
02296  *
02297  *      Input:  pixs (8 bpp)
02298  *              thresh  (between 0 and 256)
02299  *      Return: pixd (1 bpp), or null on error
02300  *
02301  *  Notes:
02302  *      (1) This does 2x upscale on pixs, using linear interpolation,
02303  *          followed by thresholding to binary.
02304  *      (2) Buffers are used to avoid making a large grayscale image.
02305  */
02306 PIX *
02307 pixScaleGray2xLIThresh(PIX     *pixs,
02308                        l_int32  thresh)
02309 {
02310 l_int32    i, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
02311 l_uint32  *datas, *datad, *lines, *lined, *lineb;
02312 PIX       *pixd;
02313 
02314     PROCNAME("pixScaleGray2xLIThresh");
02315 
02316     if (!pixs)
02317         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02318     if (pixGetDepth(pixs) != 8)
02319         return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL);
02320     if (thresh < 0 || thresh > 256)
02321         return (PIX *)ERROR_PTR("thresh must be in [0, ... 256]",
02322             procName, NULL);
02323     if (pixGetColormap(pixs))
02324         L_WARNING("pixs has colormap", procName);
02325 
02326     pixGetDimensions(pixs, &ws, &hs, NULL);
02327     wd = 2 * ws;
02328     hd = 2 * hs;
02329     hsm = hs - 1;
02330     datas = pixGetData(pixs);
02331     wpls = pixGetWpl(pixs);
02332 
02333         /* Make line buffer for 2 lines of virtual intermediate image */
02334     wplb = (wd + 3) / 4;
02335     if ((lineb = (l_uint32 *)CALLOC(2 * wplb, sizeof(l_uint32))) == NULL)
02336         return (PIX *)ERROR_PTR("lineb not made", procName, NULL);
02337 
02338         /* Make dest binary image */
02339     if ((pixd = pixCreate(wd, hd, 1)) == NULL)
02340         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
02341     pixCopyResolution(pixd, pixs);
02342     pixScaleResolution(pixd, 2.0, 2.0);
02343     wpld = pixGetWpl(pixd);
02344     datad = pixGetData(pixd);
02345 
02346         /* Do all but last src line */
02347     for (i = 0; i < hsm; i++) {
02348         lines = datas + i * wpls;
02349         lined = datad + 2 * i * wpld;  /* do 2 dest lines at a time */
02350         scaleGray2xLILineLow(lineb, wplb, lines, ws, wpls, 0);
02351         thresholdToBinaryLineLow(lined, wd, lineb, 8, thresh);
02352         thresholdToBinaryLineLow(lined + wpld, wd, lineb + wplb, 8, thresh);
02353     }
02354 
02355         /* Do last src line */
02356     lines = datas + hsm * wpls;
02357     lined = datad + 2 * hsm * wpld;
02358     scaleGray2xLILineLow(lineb, wplb, lines, ws, wpls, 1);
02359     thresholdToBinaryLineLow(lined, wd, lineb, 8, thresh);
02360     thresholdToBinaryLineLow(lined + wpld, wd, lineb + wplb, 8, thresh);
02361 
02362     FREE(lineb);
02363     return pixd;
02364 }
02365 
02366 
02367 /*!
02368  *  pixScaleGray2xLIDither()
02369  *
02370  *      Input:  pixs (8 bpp)
02371  *      Return: pixd (1 bpp), or null on error
02372  *
02373  *  Notes:
02374  *      (1) This does 2x upscale on pixs, using linear interpolation,
02375  *          followed by Floyd-Steinberg dithering to binary.
02376  *      (2) Buffers are used to avoid making a large grayscale image.
02377  *          - Two line buffers are used for the src, required for the 2x
02378  *            LI upscale.
02379  *          - Three line buffers are used for the intermediate image.
02380  *            Two are filled with each 2xLI row operation; the third is
02381  *            needed because the upscale and dithering ops are out of sync.
02382  */
02383 PIX *
02384 pixScaleGray2xLIDither(PIX  *pixs)
02385 {
02386 l_int32    i, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
02387 l_uint32  *datas, *datad;
02388 l_uint32  *lined;
02389 l_uint32  *lineb;   /* 2 intermediate buffer lines */
02390 l_uint32  *linebp;  /* 1 intermediate buffer line */
02391 l_uint32  *bufs;    /* 2 source buffer lines */
02392 PIX       *pixd;
02393 
02394     PROCNAME("pixScaleGray2xLIDither");
02395 
02396     if (!pixs)
02397         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02398     if (pixGetDepth(pixs) != 8)
02399         return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL);
02400     if (pixGetColormap(pixs))
02401         L_WARNING("pixs has colormap", procName);
02402 
02403     pixGetDimensions(pixs, &ws, &hs, NULL);
02404     wd = 2 * ws;
02405     hd = 2 * hs;
02406     hsm = hs - 1;
02407     datas = pixGetData(pixs);
02408     wpls = pixGetWpl(pixs);
02409 
02410         /* Make line buffers for 2 lines of src image */
02411     if ((bufs = (l_uint32 *)CALLOC(2 * wpls, sizeof(l_uint32))) == NULL)
02412         return (PIX *)ERROR_PTR("bufs not made", procName, NULL);
02413 
02414         /* Make line buffer for 2 lines of virtual intermediate image */
02415     wplb = (wd + 3) / 4;
02416     if ((lineb = (l_uint32 *)CALLOC(2 * wplb, sizeof(l_uint32))) == NULL)
02417         return (PIX *)ERROR_PTR("lineb not made", procName, NULL);
02418 
02419         /* Make line buffer for 1 line of virtual intermediate image */
02420     if ((linebp = (l_uint32 *)CALLOC(wplb, sizeof(l_uint32))) == NULL)
02421         return (PIX *)ERROR_PTR("linebp not made", procName, NULL);
02422 
02423         /* Make dest binary image */
02424     if ((pixd = pixCreate(wd, hd, 1)) == NULL)
02425         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
02426     pixCopyResolution(pixd, pixs);
02427     pixScaleResolution(pixd, 2.0, 2.0);
02428     wpld = pixGetWpl(pixd);
02429     datad = pixGetData(pixd);
02430 
02431         /* Start with the first src and the first dest line */
02432     memcpy(bufs, datas, 4 * wpls);   /* first src line */
02433     memcpy(bufs + wpls, datas + wpls, 4 * wpls);  /* 2nd src line */
02434     scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 0);  /* 2 i lines */
02435     lined = datad;
02436     ditherToBinaryLineLow(lined, wd, lineb, lineb + wplb,
02437                           DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
02438                                                     /* 1st d line */
02439 
02440         /* Do all but last src line */
02441     for (i = 1; i < hsm; i++) {
02442         memcpy(bufs, datas + i * wpls, 4 * wpls);  /* i-th src line */
02443         memcpy(bufs + wpls, datas + (i + 1) * wpls, 4 * wpls);
02444         memcpy(linebp, lineb + wplb, 4 * wplb);
02445         scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 0);  /* 2 i lines */
02446         lined = datad + 2 * i * wpld;
02447         ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb,
02448                               DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
02449                                                    /* odd dest line */
02450         ditherToBinaryLineLow(lined, wd, lineb, lineb + wplb,
02451                               DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
02452                                                    /* even dest line */
02453     }
02454 
02455         /* Do the last src line and the last 3 dest lines */
02456     memcpy(bufs, datas + hsm * wpls, 4 * wpls);  /* hsm-th src line */
02457     memcpy(linebp, lineb + wplb, 4 * wplb);   /* 1 i line */
02458     scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 1);  /* 2 i lines */
02459     ditherToBinaryLineLow(lined + wpld, wd, linebp, lineb,
02460                           DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
02461                                                    /* odd dest line */
02462     ditherToBinaryLineLow(lined + 2 * wpld, wd, lineb, lineb + wplb,
02463                           DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
02464                                                    /* even dest line */
02465     ditherToBinaryLineLow(lined + 3 * wpld, wd, lineb + wplb, NULL,
02466                           DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 1);
02467                                                    /* last dest line */
02468 
02469     FREE(bufs);
02470     FREE(lineb);
02471     FREE(linebp);
02472     return pixd;
02473 }
02474 
02475 
02476 /*------------------------------------------------------------------*
02477  *                Scale 4x followed by binarization                 *
02478  *------------------------------------------------------------------*/
02479 /*!
02480  *  pixScaleGray4xLIThresh()
02481  *
02482  *      Input:  pixs (8 bpp)
02483  *              thresh  (between 0 and 256)
02484  *      Return: pixd (1 bpp), or null on error
02485  *
02486  *  Notes:
02487  *      (1) This does 4x upscale on pixs, using linear interpolation,
02488  *          followed by thresholding to binary.
02489  *      (2) Buffers are used to avoid making a large grayscale image.
02490  *      (3) If a full 4x expanded grayscale image can be kept in memory,
02491  *          this function is only about 10% faster than separately doing
02492  *          a linear interpolation to a large grayscale image, followed
02493  *          by thresholding to binary.
02494  */
02495 PIX *
02496 pixScaleGray4xLIThresh(PIX     *pixs,
02497                        l_int32  thresh)
02498 {
02499 l_int32    i, j, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
02500 l_uint32  *datas, *datad, *lines, *lined, *lineb;
02501 PIX       *pixd;
02502 
02503     PROCNAME("pixScaleGray4xLIThresh");
02504 
02505     if (!pixs)
02506         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02507     if (pixGetDepth(pixs) != 8)
02508         return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL);
02509     if (thresh < 0 || thresh > 256)
02510         return (PIX *)ERROR_PTR("thresh must be in [0, ... 256]",
02511             procName, NULL);
02512     if (pixGetColormap(pixs))
02513         L_WARNING("pixs has colormap", procName);
02514 
02515     pixGetDimensions(pixs, &ws, &hs, NULL);
02516     wd = 4 * ws;
02517     hd = 4 * hs;
02518     hsm = hs - 1;
02519     datas = pixGetData(pixs);
02520     wpls = pixGetWpl(pixs);
02521 
02522         /* Make line buffer for 4 lines of virtual intermediate image */
02523     wplb = (wd + 3) / 4;
02524     if ((lineb = (l_uint32 *)CALLOC(4 * wplb, sizeof(l_uint32))) == NULL)
02525         return (PIX *)ERROR_PTR("lineb not made", procName, NULL);
02526 
02527         /* Make dest binary image */
02528     if ((pixd = pixCreate(wd, hd, 1)) == NULL)
02529         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
02530     pixCopyResolution(pixd, pixs);
02531     pixScaleResolution(pixd, 4.0, 4.0);
02532     wpld = pixGetWpl(pixd);
02533     datad = pixGetData(pixd);
02534 
02535         /* Do all but last src line */
02536     for (i = 0; i < hsm; i++) {
02537         lines = datas + i * wpls;
02538         lined = datad + 4 * i * wpld;  /* do 4 dest lines at a time */
02539         scaleGray4xLILineLow(lineb, wplb, lines, ws, wpls, 0);
02540         for (j = 0; j < 4; j++) {
02541             thresholdToBinaryLineLow(lined + j * wpld, wd,
02542                                      lineb + j * wplb, 8, thresh);
02543         }
02544     }
02545 
02546         /* Do last src line */
02547     lines = datas + hsm * wpls;
02548     lined = datad + 4 * hsm * wpld;
02549     scaleGray4xLILineLow(lineb, wplb, lines, ws, wpls, 1);
02550     for (j = 0; j < 4; j++) {
02551         thresholdToBinaryLineLow(lined + j * wpld, wd,
02552                                  lineb + j * wplb, 8, thresh);
02553     }
02554 
02555     FREE(lineb);
02556     return pixd;
02557 }
02558 
02559 
02560 /*!
02561  *  pixScaleGray4xLIDither()
02562  *
02563  *      Input:  pixs (8 bpp)
02564  *      Return: pixd (1 bpp), or null on error
02565  *
02566  *  Notes:
02567  *      (1) This does 4x upscale on pixs, using linear interpolation,
02568  *          followed by Floyd-Steinberg dithering to binary.
02569  *      (2) Buffers are used to avoid making a large grayscale image.
02570  *          - Two line buffers are used for the src, required for the
02571  *            4xLI upscale.
02572  *          - Five line buffers are used for the intermediate image.
02573  *            Four are filled with each 4xLI row operation; the fifth
02574  *            is needed because the upscale and dithering ops are
02575  *            out of sync.
02576  *      (3) If a full 4x expanded grayscale image can be kept in memory,
02577  *          this function is only about 5% faster than separately doing
02578  *          a linear interpolation to a large grayscale image, followed
02579  *          by error-diffusion dithering to binary.
02580  */
02581 PIX *
02582 pixScaleGray4xLIDither(PIX  *pixs)
02583 {
02584 l_int32    i, j, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
02585 l_uint32  *datas, *datad;
02586 l_uint32  *lined;
02587 l_uint32  *lineb;   /* 4 intermediate buffer lines */
02588 l_uint32  *linebp;  /* 1 intermediate buffer line */
02589 l_uint32  *bufs;    /* 2 source buffer lines */
02590 PIX       *pixd;
02591 
02592     PROCNAME("pixScaleGray4xLIDither");
02593 
02594     if (!pixs)
02595         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02596     if (pixGetDepth(pixs) != 8)
02597         return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL);
02598     if (pixGetColormap(pixs))
02599         L_WARNING("pixs has colormap", procName);
02600 
02601     pixGetDimensions(pixs, &ws, &hs, NULL);
02602     wd = 4 * ws;
02603     hd = 4 * hs;
02604     hsm = hs - 1;
02605     datas = pixGetData(pixs);
02606     wpls = pixGetWpl(pixs);
02607 
02608         /* Make line buffers for 2 lines of src image */
02609     if ((bufs = (l_uint32 *)CALLOC(2 * wpls, sizeof(l_uint32))) == NULL)
02610         return (PIX *)ERROR_PTR("bufs not made", procName, NULL);
02611 
02612         /* Make line buffer for 4 lines of virtual intermediate image */
02613     wplb = (wd + 3) / 4;
02614     if ((lineb = (l_uint32 *)CALLOC(4 * wplb, sizeof(l_uint32))) == NULL)
02615         return (PIX *)ERROR_PTR("lineb not made", procName, NULL);
02616 
02617         /* Make line buffer for 1 line of virtual intermediate image */
02618     if ((linebp = (l_uint32 *)CALLOC(wplb, sizeof(l_uint32))) == NULL)
02619         return (PIX *)ERROR_PTR("linebp not made", procName, NULL);
02620 
02621         /* Make dest binary image */
02622     if ((pixd = pixCreate(wd, hd, 1)) == NULL)
02623         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
02624     pixCopyResolution(pixd, pixs);
02625     pixScaleResolution(pixd, 4.0, 4.0);
02626     wpld = pixGetWpl(pixd);
02627     datad = pixGetData(pixd);
02628 
02629         /* Start with the first src and the first 3 dest lines */
02630     memcpy(bufs, datas, 4 * wpls);   /* first src line */
02631     memcpy(bufs + wpls, datas + wpls, 4 * wpls);  /* 2nd src line */
02632     scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 0);  /* 4 b lines */
02633     lined = datad;
02634     for (j = 0; j < 3; j++) {  /* first 3 d lines of Q */
02635         ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb,
02636                               lineb + (j + 1) * wplb,
02637                               DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
02638     }
02639 
02640         /* Do all but last src line */
02641     for (i = 1; i < hsm; i++) {
02642         memcpy(bufs, datas + i * wpls, 4 * wpls);  /* i-th src line */
02643         memcpy(bufs + wpls, datas + (i + 1) * wpls, 4 * wpls);
02644         memcpy(linebp, lineb + 3 * wplb, 4 * wplb);
02645         scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 0);  /* 4 b lines */
02646         lined = datad + 4 * i * wpld;
02647         ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb,
02648                               DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
02649                                                      /* 4th dest line of Q */
02650         for (j = 0; j < 3; j++) {  /* next 3 d lines of Quad */
02651             ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb,
02652                                   lineb + (j + 1) * wplb,
02653                                  DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
02654         }                             
02655     }
02656 
02657         /* Do the last src line and the last 5 dest lines */
02658     memcpy(bufs, datas + hsm * wpls, 4 * wpls);  /* hsm-th src line */
02659     memcpy(linebp, lineb + 3 * wplb, 4 * wplb);   /* 1 b line */
02660     scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 1);  /* 4 b lines */
02661     lined = datad + 4 * hsm * wpld;
02662     ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb,
02663                           DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
02664                                                    /* 4th dest line of Q */
02665     for (j = 0; j < 3; j++) {  /* next 3 d lines of Quad */
02666         ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb,
02667                               lineb + (j + 1) * wplb,
02668                               DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
02669     }
02670         /* And finally, the last dest line */
02671     ditherToBinaryLineLow(lined + 3 * wpld, wd, lineb + 3 * wplb, NULL,
02672                               DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 1);
02673 
02674     FREE(bufs);
02675     FREE(lineb);
02676     FREE(linebp);
02677     return pixd;
02678 }
02679 
02680 
02681 /*-----------------------------------------------------------------------*
02682  *                    Downscaling using min or max                       *
02683  *-----------------------------------------------------------------------*/
02684 /*!
02685  *  pixScaleGrayMinMax()
02686  *
02687  *      Input:  pixs (8 bpp)
02688  *              xfact (x downscaling factor; integer)
02689  *              yfact (y downscaling factor; integer)
02690  *              type (L_CHOOSE_MIN, L_CHOOSE_MAX, L_CHOOSE_MAX_MIN_DIFF)
02691  *      Return: pixd (8 bpp)
02692  *
02693  *  Notes:
02694  *      (1) The downscaled pixels in pixd are the min, max or (max - min)
02695  *          of the corresponding set of xfact * yfact pixels in pixs.
02696  *      (2) Using L_CHOOSE_MIN is equivalent to a grayscale erosion,
02697  *          using a brick Sel of size (xfact * yfact), followed by
02698  *          subsampling within each (xfact * yfact) cell.  Using
02699  *          L_CHOOSE_MAX is equivalent to the corresponding dilation.
02700  *      (3) Using L_CHOOSE_MAX_MIN_DIFF finds the difference between max
02701  *          and min values in each cell.
02702  *      (4) For the special case of downscaling by 2x in both directions,
02703  *          pixScaleGrayMinMax2() is about 2x more efficient.
02704  */
02705 PIX *
02706 pixScaleGrayMinMax(PIX     *pixs,
02707                    l_int32  xfact,
02708                    l_int32  yfact,
02709                    l_int32  type)
02710 {
02711 l_int32    ws, hs, d, wd, hd, wpls, wpld, i, j, k, m;
02712 l_int32    minval, maxval, val;
02713 l_uint32  *datas, *datad, *lines, *lined;
02714 PIX       *pixd;
02715 
02716     PROCNAME("pixScaleGrayMinMax");
02717 
02718     if (!pixs)
02719         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02720     pixGetDimensions(pixs, &ws, &hs, &d);
02721     if (d != 8)
02722         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
02723     if (type != L_CHOOSE_MIN && type != L_CHOOSE_MAX &&
02724         type != L_CHOOSE_MAX_MIN_DIFF)
02725         return (PIX *)ERROR_PTR("invalid type", procName, NULL);
02726     if (xfact < 1 || yfact < 1)
02727         return (PIX *)ERROR_PTR("xfact and yfact must be > 0", procName, NULL);
02728 
02729     if (xfact == 2 && yfact == 2)
02730         return pixScaleGrayMinMax2(pixs, type);
02731 
02732     wd = ws / xfact;
02733     if (wd == 0) {  /* single tile */
02734         wd = 1;
02735         xfact = ws;
02736     }
02737     hd = hs / yfact;
02738     if (hd == 0) {  /* single tile */
02739         hd = 1;
02740         yfact = hs;
02741     }
02742     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
02743         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
02744     datas = pixGetData(pixs);
02745     datad = pixGetData(pixd);
02746     wpls = pixGetWpl(pixs);
02747     wpld = pixGetWpl(pixd);
02748     for (i = 0; i < hd; i++) {
02749         lined = datad + i * wpld;
02750         for (j = 0; j < wd; j++) {
02751             if (type == L_CHOOSE_MIN || type == L_CHOOSE_MAX_MIN_DIFF) {
02752                 minval = 255;
02753                 for (k = 0; k < yfact; k++) {
02754                     lines = datas + (yfact * i + k) * wpls;
02755                     for (m = 0; m < xfact; m++) {
02756                         val = GET_DATA_BYTE(lines, xfact * j + m);
02757                         if (val < minval)
02758                             minval = val;
02759                     }
02760                 }
02761             }
02762             if (type == L_CHOOSE_MAX || type == L_CHOOSE_MAX_MIN_DIFF) {
02763                 maxval = 0;
02764                 for (k = 0; k < yfact; k++) {
02765                     lines = datas + (yfact * i + k) * wpls;
02766                     for (m = 0; m < xfact; m++) {
02767                         val = GET_DATA_BYTE(lines, xfact * j + m);
02768                         if (val > maxval)
02769                             maxval = val;
02770                     }
02771                 }
02772             }
02773             if (type == L_CHOOSE_MIN)
02774                 SET_DATA_BYTE(lined, j, minval);
02775             else if (type == L_CHOOSE_MAX)
02776                 SET_DATA_BYTE(lined, j, maxval);
02777             else  /* type == L_CHOOSE_MAX_MIN_DIFF */
02778                 SET_DATA_BYTE(lined, j, maxval - minval);
02779         }
02780     }
02781             
02782     return pixd;
02783 }
02784 
02785 
02786 /*!
02787  *  pixScaleGrayMinMax2()
02788  *
02789  *      Input:  pixs (8 bpp)
02790  *              type (L_CHOOSE_MIN, L_CHOOSE_MAX, L_CHOOSE_MAX_MIN_DIFF)
02791  *      Return: pixd (8 bpp downscaled by 2x)
02792  *
02793  *  Notes:
02794  *      (1) Special version for 2x reduction.  The downscaled pixels
02795  *          in pixd are the min, max or (max - min) of the corresponding
02796  *          set of 4 pixels in pixs.
02797  *      (2) The max and min operations are a special case (for levels 1
02798  *          and 4) of grayscale analog to the binary rank scaling operation
02799  *          pixReduceRankBinary2().  Note, however, that because of
02800  *          the photometric definition that higher gray values are
02801  *          lighter, the erosion-like L_CHOOSE_MIN will darken
02802  *          the resulting image, corresponding to a threshold level 1
02803  *          in the binary case.  Likewise, L_CHOOSE_MAX will lighten
02804  *          the pixd, corresponding to a threshold level of 4.
02805  *      (3) To choose any of the four rank levels in a 2x grayscale
02806  *          reduction, use pixScaleGrayRank2().
02807  *      (4) This runs at about 70 MPix/sec/GHz of source data for
02808  *          erosion and dilation.
02809  */
02810 PIX *
02811 pixScaleGrayMinMax2(PIX     *pixs,
02812                     l_int32  type)
02813 {
02814 l_int32    ws, hs, d, wd, hd, wpls, wpld, i, j, k;
02815 l_int32    minval, maxval;
02816 l_int32    val[4];
02817 l_uint32  *datas, *datad, *lines, *lined;
02818 PIX       *pixd;
02819 
02820     PROCNAME("pixScaleGrayMinMax2");
02821 
02822     if (!pixs)
02823         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02824     pixGetDimensions(pixs, &ws, &hs, &d);
02825     if (ws < 2 || hs < 2)
02826         return (PIX *)ERROR_PTR("too small: ws < 2 or hs < 2", procName, NULL);
02827     if (d != 8)
02828         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
02829     if (type != L_CHOOSE_MIN && type != L_CHOOSE_MAX &&
02830         type != L_CHOOSE_MAX_MIN_DIFF)
02831         return (PIX *)ERROR_PTR("invalid type", procName, NULL);
02832 
02833     wd = ws / 2;
02834     hd = hs / 2;
02835     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
02836         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
02837     datas = pixGetData(pixs);
02838     datad = pixGetData(pixd);
02839     wpls = pixGetWpl(pixs);
02840     wpld = pixGetWpl(pixd);
02841     for (i = 0; i < hd; i++) {
02842         lines = datas + 2 * i * wpls;
02843         lined = datad + i * wpld;
02844         for (j = 0; j < wd; j++) {
02845             val[0] = GET_DATA_BYTE(lines, 2 * j);
02846             val[1] = GET_DATA_BYTE(lines, 2 * j + 1);
02847             val[2] = GET_DATA_BYTE(lines + wpls, 2 * j);
02848             val[3] = GET_DATA_BYTE(lines + wpls, 2 * j + 1);
02849             if (type == L_CHOOSE_MIN || type == L_CHOOSE_MAX_MIN_DIFF) {
02850                 minval = 255;
02851                 for (k = 0; k < 4; k++) {
02852                     if (val[k] < minval)
02853                         minval = val[k];
02854                 }
02855             }
02856             if (type == L_CHOOSE_MAX || type == L_CHOOSE_MAX_MIN_DIFF) {
02857                 maxval = 0;
02858                 for (k = 0; k < 4; k++) {
02859                     if (val[k] > maxval)
02860                         maxval = val[k];
02861                 }
02862             }
02863             if (type == L_CHOOSE_MIN)
02864                 SET_DATA_BYTE(lined, j, minval);
02865             else if (type == L_CHOOSE_MAX)
02866                 SET_DATA_BYTE(lined, j, maxval);
02867             else  /* type == L_CHOOSE_MAX_MIN_DIFF */
02868                 SET_DATA_BYTE(lined, j, maxval - minval);
02869         }
02870     }
02871             
02872     return pixd;
02873 }
02874 
02875 
02876 /*-----------------------------------------------------------------------*
02877  *                  Grayscale downscaling using rank value               *
02878  *-----------------------------------------------------------------------*/
02879 /*!
02880  *  pixScaleGrayRankCascade()
02881  *
02882  *      Input:  pixs (8 bpp)
02883  *              level1, ... level4 (rank thresholds, in set {0, 1, 2, 3, 4})
02884  *      Return: pixd (8 bpp, downscaled by up to 16x)
02885  *
02886  *  Notes:
02887  *      (1) This performs up to four cascaded 2x rank reductions.
02888  *      (2) Use level = 0 to truncate the cascade.
02889  */
02890 PIX *
02891 pixScaleGrayRankCascade(PIX     *pixs,
02892                         l_int32  level1,
02893                         l_int32  level2,
02894                         l_int32  level3,
02895                         l_int32  level4)
02896 {
02897 PIX  *pixt1, *pixt2, *pixt3, *pixt4;
02898 
02899     PROCNAME("pixScaleGrayRankCascade");
02900 
02901     if (!pixs)
02902         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02903     if (pixGetDepth(pixs) != 8)
02904         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
02905     if (level1 > 4 || level2 > 4 || level3 > 4 || level4 > 4)
02906         return (PIX *)ERROR_PTR("levels must not exceed 4", procName, NULL);
02907 
02908     if (level1 <= 0) {
02909         L_WARNING("no reduction because level1 not > 0", procName);
02910         return pixCopy(NULL, pixs);
02911     }
02912 
02913     pixt1 = pixScaleGrayRank2(pixs, level1);
02914     if (level2 <= 0)
02915         return pixt1;
02916 
02917     pixt2 = pixScaleGrayRank2(pixt1, level2);
02918     pixDestroy(&pixt1);
02919     if (level3 <= 0)
02920         return pixt2;
02921 
02922     pixt3 = pixScaleGrayRank2(pixt2, level3);
02923     pixDestroy(&pixt2);
02924     if (level4 <= 0)
02925         return pixt3;
02926 
02927     pixt4 = pixScaleGrayRank2(pixt3, level4);
02928     pixDestroy(&pixt3);
02929     return pixt4;
02930 }
02931 
02932 
02933 /*!
02934  *  pixScaleGrayRank2()
02935  *
02936  *      Input:  pixs (8 bpp)
02937  *              rank (1 (darkest), 2, 3, 4 (lightest))
02938  *      Return: pixd (8 bpp, downscaled by 2x)
02939  *
02940  *  Notes:
02941  *      (1) Rank 2x reduction.  If rank == 1(4), the downscaled pixels
02942  *          in pixd are the min(max) of the corresponding set of
02943  *          4 pixels in pixs.  Values 2 and 3 are intermediate.
02944  *      (2) This is the grayscale analog to the binary rank scaling operation
02945  *          pixReduceRankBinary2().  Here, because of the photometric
02946  *          definition that higher gray values are lighter, rank 1 gives
02947  *          the darkest pixel, whereas rank 4 gives the lightest pixel.
02948  *          This is opposite to the binary rank operation.
02949  *      (3) For rank = 1 and 4, this calls pixScaleGrayMinMax2(),
02950  *          which runs at about 70 MPix/sec/GHz of source data.
02951  *          For rank 2 and 3, this runs 3x slower, at about 25 MPix/sec/GHz.
02952  */
02953 PIX *
02954 pixScaleGrayRank2(PIX     *pixs,
02955                   l_int32  rank)
02956 {
02957 l_int32    d, ws, hs, wd, hd, wpls, wpld, i, j, k, m;
02958 l_int32    minval, maxval, rankval, minindex, maxindex;
02959 l_int32    val[4];
02960 l_int32    midval[4];  /* should only use 2 of these */
02961 l_uint32  *datas, *datad, *lines, *lined;
02962 PIX       *pixd;
02963 
02964     PROCNAME("pixScaleGrayRank2");
02965 
02966     if (!pixs)
02967         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
02968     pixGetDimensions(pixs, &ws, &hs, &d);
02969     if (d != 8)
02970         return (PIX *)ERROR_PTR("pixs not 8 bpp", procName, NULL);
02971     if (rank < 1 || rank > 4)
02972         return (PIX *)ERROR_PTR("invalid rank", procName, NULL);
02973 
02974     if (rank == 1)
02975         return pixScaleGrayMinMax2(pixs, L_CHOOSE_MIN);
02976     if (rank == 4)
02977         return pixScaleGrayMinMax2(pixs, L_CHOOSE_MAX);
02978 
02979     wd = ws / 2;
02980     hd = hs / 2;
02981     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
02982         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
02983     datas = pixGetData(pixs);
02984     datad = pixGetData(pixd);
02985     wpls = pixGetWpl(pixs);
02986     wpld = pixGetWpl(pixd);
02987     for (i = 0; i < hd; i++) {
02988         lines = datas + 2 * i * wpls;
02989         lined = datad + i * wpld;
02990         for (j = 0; j < wd; j++) {
02991             val[0] = GET_DATA_BYTE(lines, 2 * j);
02992             val[1] = GET_DATA_BYTE(lines, 2 * j + 1);
02993             val[2] = GET_DATA_BYTE(lines + wpls, 2 * j);
02994             val[3] = GET_DATA_BYTE(lines + wpls, 2 * j + 1);
02995             minval = maxval = val[0];
02996             minindex = maxindex = 0;
02997             for (k = 1; k < 4; k++) {
02998                 if (val[k] < minval) {
02999                     minval = val[k];
03000                     minindex = k;
03001                     continue;
03002                 }
03003                 if (val[k] > maxval) {
03004                     maxval = val[k];
03005                     maxindex = k;
03006                 }
03007             }
03008             for (k = 0, m = 0; k < 4; k++) {
03009                 if (k == minindex || k == maxindex)
03010                     continue;
03011                 midval[m++] = val[k];
03012             }
03013             if (m > 2)  /* minval == maxval; all val[k] are the same */
03014                 rankval = minval;
03015             else if (rank == 2)
03016                 rankval = L_MIN(midval[0], midval[1]);
03017             else  /* rank == 3 */
03018                 rankval = L_MAX(midval[0], midval[1]);
03019             SET_DATA_BYTE(lined, j, rankval);
03020         }
03021     }
03022             
03023     return pixd;
03024 }
03025 
03026 
03027 /*------------------------------------------------------------------------*
03028  *    RGB scaling including alpha (blend) component and gamma transform   *
03029  *------------------------------------------------------------------------*/
03030 /*!
03031  *  pixScaleWithAlpha()
03032  *
03033  *      Input:  pixs (32 bpp rgb)
03034  *              scalex, scaley
03035  *              pixg (<optional> 8 bpp, can be null)
03036  *              fract (between 0.0 and 1.0, with 0.0 fully transparent
03037  *                     and 1.0 fully opaque)
03038  *      Return: pixd, or null on error
03039  *
03040  *  Notes:
03041  *      (1) The alpha channel is transformed separately from pixs,
03042  *          and aligns with it, being fully transparent outside the
03043  *          boundary of the transformed pixs.  For pixels that are fully
03044  *          transparent, a blending function like pixBlendWithGrayMask()
03045  *          will give zero weight to corresponding pixels in pixs.
03046  *      (2) Scaling is done with area mapping or linear interpolation,
03047  *          depending on the scale factors.  Default sharpening is done.
03048  *      (3) If pixg is NULL, it is generated as an alpha layer that is
03049  *          partially opaque, using @fract.  Otherwise, it is cropped
03050  *          to pixs if required, and @fract is ignored.  The alpha
03051  *          channel in pixs is never used.
03052  *      (4) Colormaps are removed.
03053  *      (5) The default setting for the border values in the alpha channel
03054  *          is 0 (transparent) for the outermost ring of pixels and
03055  *          (0.5 * fract * 255) for the second ring.  When blended over
03056  *          a second image, this
03057  *          (a) shrinks the visible image to make a clean overlap edge
03058  *              with an image below, and
03059  *          (b) softens the edges by weakening the aliasing there.
03060  *          Use l_setAlphaMaskBorder() to change these values.
03061  *
03062  *  *** Warning: implicit assumption about RGB component ordering ***
03063  */
03064 PIX *
03065 pixScaleWithAlpha(PIX       *pixs,
03066                   l_float32  scalex,
03067                   l_float32  scaley,
03068                   PIX       *pixg,
03069                   l_float32  fract)
03070 {
03071 l_int32  ws, hs, d;
03072 PIX     *pixd, *pixg2, *pixgs;
03073 
03074     PROCNAME("pixScaleWithAlpha");
03075 
03076     if (!pixs)
03077         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
03078     pixGetDimensions(pixs, &ws, &hs, &d);
03079     if (d != 32 && pixGetColormap(pixs) == NULL)
03080         return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", procName, NULL);
03081     if (pixg && pixGetDepth(pixg) != 8) {
03082         L_WARNING("pixg not 8 bpp; using @fract transparent alpha", procName);
03083         pixg = NULL;
03084     }
03085     if (!pixg && (fract < 0.0 || fract > 1.0)) {
03086         L_WARNING("invalid fract; using 1.0 (fully transparent)", procName);
03087         fract = 1.0;
03088     }
03089     if (!pixg && fract == 0.0)
03090         L_WARNING("fully opaque alpha; image will not be blended", procName);
03091 
03092         /* Do separate scaling of rgb channels of pixs and of pixg */
03093     pixd = pixScale(pixs, scalex, scaley);
03094     if (!pixg) {
03095         pixg2 = pixCreate(ws, hs, 8);
03096         if (fract == 1.0)
03097             pixSetAll(pixg2);
03098         else
03099             pixSetAllArbitrary(pixg2, (l_int32)(255.0 * fract));
03100     }
03101     else
03102         pixg2 = pixResizeToMatch(pixg, NULL, ws, hs);
03103     if (ws > 10 && hs > 10) {  /* see note 4 */
03104         pixSetBorderRingVal(pixg2, 1,
03105                             (l_int32)(255.0 * fract * AlphaMaskBorderVals[0]));
03106         pixSetBorderRingVal(pixg2, 2,
03107                             (l_int32)(255.0 * fract * AlphaMaskBorderVals[1]));
03108     }
03109     pixgs = pixScaleGeneral(pixg2, scalex, scaley, 0.0, 0);
03110     pixSetRGBComponent(pixd, pixgs, L_ALPHA_CHANNEL);
03111 
03112     pixDestroy(&pixg2);
03113     pixDestroy(&pixgs);
03114     return pixd;
03115 }
03116 
03117 
03118 /*!
03119  *  pixScaleGammaXform()
03120  *
03121  *      Input:  pixs (32 bpp rgb)
03122  *              gamma (gamma correction; must be > 0.0)
03123  *              scalex, scaley
03124  *              fract (between 0.0 and 1.0, with 1.0 fully transparent)
03125  *      Return: pixd, or null on error
03126  *
03127  *  Notes:
03128  *      (1) This wraps a gamma/inverse-gamma photometric transform
03129  *          around pixScaleWithAlpha().
03130  *      (2) For usage, see notes in pixScaleWithAlpha() and
03131  *          pixGammaTRCWithAlpha().
03132  *      (3) The basic idea of a gamma/inverse-gamma transform is
03133  *          to remove gamma correction before scaling and restore
03134  *          it afterward.  The effects can be subtle, but important for
03135  *          some applications.  For example, using gamma > 1.0 will
03136  *          cause the dark areas to become somewhat lighter and slightly
03137  *          reduce aliasing effects when blending using the alpha channel.
03138  */
03139 PIX *
03140 pixScaleGammaXform(PIX       *pixs,
03141                    l_float32  gamma,
03142                    l_float32  scalex,
03143                    l_float32  scaley,
03144                    l_float32  fract)
03145 {
03146 PIX  *pixg, *pixd;
03147 
03148     PROCNAME("pixScaleGammaXform");
03149 
03150     if (!pixs || (pixGetDepth(pixs) != 32))
03151         return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
03152     if (fract == 0.0)
03153         L_WARNING("fully opaque alpha; image cannot be blended", procName);
03154     if (gamma <= 0.0)  {
03155         L_WARNING("gamma must be > 0.0; setting to 1.0", procName);
03156         gamma = 1.0;
03157     }
03158 
03159     pixg = pixGammaTRCWithAlpha(NULL, pixs, 1.0 / gamma, 0, 255);
03160     pixd = pixScaleWithAlpha(pixg, scalex, scaley, NULL, fract);
03161     pixGammaTRCWithAlpha(pixd, pixd, gamma, 0, 255);
03162     pixDestroy(&pixg);
03163     return pixd;
03164 }
03165 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines