Leptonica 1.68
C Image Processing Library

scalelow.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 /*
00018  *  scalelow.c
00019  *
00020  *         Color (interpolated) scaling: general case
00021  *                  void       scaleColorLILow()
00022  *
00023  *         Grayscale (interpolated) scaling: general case
00024  *                  void       scaleGrayLILow()
00025  *
00026  *         Color (interpolated) scaling: 2x upscaling
00027  *                  void       scaleColor2xLILow()
00028  *                  void       scaleColor2xLILineLow()
00029  *
00030  *         Grayscale (interpolated) scaling: 2x upscaling
00031  *                  void       scaleGray2xLILow()
00032  *                  void       scaleGray2xLILineLow()
00033  *
00034  *         Grayscale (interpolated) scaling: 4x upscaling
00035  *                  void       scaleGray4xLILow()
00036  *                  void       scaleGray4xLILineLow()
00037  *
00038  *         Grayscale and color scaling by closest pixel sampling
00039  *                  l_int32    scaleBySamplingLow()
00040  *
00041  *         Color and grayscale downsampling with (antialias) lowpass filter
00042  *                  l_int32    scaleSmoothLow()
00043  *                  void       scaleRGBToGray2Low()
00044  *
00045  *         Color and grayscale downsampling with (antialias) area mapping
00046  *                  l_int32    scaleColorAreaMapLow()
00047  *                  l_int32    scaleGrayAreaMapLow()
00048  *                  l_int32    scaleAreaMapLow2()
00049  *
00050  *         Binary scaling by closest pixel sampling
00051  *                  l_int32    scaleBinaryLow()
00052  *
00053  *         Scale-to-gray 2x
00054  *                  void       scaleToGray2Low()
00055  *                  l_uint32  *makeSumTabSG2()
00056  *                  l_uint8   *makeValTabSG2()
00057  *
00058  *         Scale-to-gray 3x
00059  *                  void       scaleToGray3Low()
00060  *                  l_uint32  *makeSumTabSG3()
00061  *                  l_uint8   *makeValTabSG3()
00062  *
00063  *         Scale-to-gray 4x
00064  *                  void       scaleToGray4Low()
00065  *                  l_uint32  *makeSumTabSG4()
00066  *                  l_uint8   *makeValTabSG4()
00067  *
00068  *         Scale-to-gray 6x
00069  *                  void       scaleToGray6Low()
00070  *                  l_uint8   *makeValTabSG6()
00071  *
00072  *         Scale-to-gray 8x
00073  *                  void       scaleToGray8Low()
00074  *                  l_uint8   *makeValTabSG8()
00075  *
00076  *         Scale-to-gray 16x
00077  *                  void       scaleToGray16Low()
00078  *
00079  *         Grayscale mipmap
00080  *                  l_int32    scaleMipmapLow()
00081  *
00082  */
00083 
00084 #include <stdio.h>
00085 #include <stdlib.h>
00086 #include <string.h>
00087 #include "allheaders.h"
00088 
00089 #ifndef  NO_CONSOLE_IO
00090 #define  DEBUG_OVERFLOW   0
00091 #define  DEBUG_UNROLLING  0
00092 #endif  /* ~NO_CONSOLE_IO */
00093 
00094 
00095 /*------------------------------------------------------------------*
00096  *            General linear interpolated color scaling             *
00097  *------------------------------------------------------------------*/
00098 /*!
00099  *  scaleColorLILow()
00100  *
00101  *  We choose to divide each pixel into 16 x 16 sub-pixels.
00102  *  Linear interpolation is equivalent to finding the 
00103  *  fractional area (i.e., number of sub-pixels divided
00104  *  by 256) associated with each of the four nearest src pixels,
00105  *  and weighting each pixel value by this fractional area.
00106  *
00107  *  P3 speed is about 7 x 10^6 dst pixels/sec/GHz
00108  */
00109 void
00110 scaleColorLILow(l_uint32  *datad,
00111                l_int32    wd,
00112                l_int32    hd,
00113                l_int32    wpld,
00114                l_uint32  *datas,
00115                l_int32    ws,
00116                l_int32    hs,
00117                l_int32    wpls)
00118 {
00119 l_int32    i, j, wm2, hm2;
00120 l_int32    xpm, ypm;  /* location in src image, to 1/16 of a pixel */
00121 l_int32    xp, yp, xf, yf;  /* src pixel and pixel fraction coordinates */
00122 l_int32    v00r, v01r, v10r, v11r, v00g, v01g, v10g, v11g;
00123 l_int32    v00b, v01b, v10b, v11b, area00, area01, area10, area11;
00124 l_uint32   pixels1, pixels2, pixels3, pixels4, pixel;
00125 l_uint32  *lines, *lined;
00126 l_float32  scx, scy;
00127 
00128         /* (scx, scy) are scaling factors that are applied to the
00129          * dest coords to get the corresponding src coords.
00130          * We need them because we iterate over dest pixels
00131          * and must find the corresponding set of src pixels. */
00132     scx = 16. * (l_float32)ws / (l_float32)wd;
00133     scy = 16. * (l_float32)hs / (l_float32)hd;
00134 
00135     wm2 = ws - 2;
00136     hm2 = hs - 2;
00137 
00138         /* Iterate over the destination pixels */
00139     for (i = 0; i < hd; i++) {
00140         ypm = (l_int32)(scy * (l_float32)i);
00141         yp = ypm >> 4;
00142         yf = ypm & 0x0f;
00143         lined = datad + i * wpld;
00144         lines = datas + yp * wpls;
00145         for (j = 0; j < wd; j++) {
00146             xpm = (l_int32)(scx * (l_float32)j);
00147             xp = xpm >> 4;
00148             xf = xpm & 0x0f;
00149 
00150                 /* Do bilinear interpolation.  This is a simple
00151                  * generalization of the calculation in scaleGrayLILow().
00152                  * Without this, we could simply subsample:
00153                  *     *(lined + j) = *(lines + xp);
00154                  * which is faster but gives lousy results!  */
00155             pixels1 = *(lines + xp);
00156 
00157             if (xp > wm2 || yp > hm2) {
00158                 if (yp > hm2 && xp <= wm2) {  /* pixels near bottom */
00159                     pixels2 = *(lines + xp + 1);
00160                     pixels3 = pixels1;
00161                     pixels4 = pixels2;
00162                 }
00163                 else if (xp > wm2 && yp <= hm2) {  /* pixels near right side */
00164                     pixels2 = pixels1;
00165                     pixels3 = *(lines + wpls + xp);
00166                     pixels4 = pixels3;
00167                 }
00168                 else {  /* pixels at LR corner */
00169                     pixels4 = pixels3 = pixels2 = pixels1;
00170                 }
00171             }
00172             else {
00173                 pixels2 = *(lines + xp + 1);
00174                 pixels3 = *(lines + wpls + xp);
00175                 pixels4 = *(lines + wpls + xp + 1);
00176             }
00177 
00178             area00 = (16 - xf) * (16 - yf);
00179             area10 = xf * (16 - yf);
00180             area01 = (16 - xf) * yf;
00181             area11 = xf * yf;
00182             v00r = area00 * ((pixels1 >> L_RED_SHIFT) & 0xff);
00183             v00g = area00 * ((pixels1 >> L_GREEN_SHIFT) & 0xff);
00184             v00b = area00 * ((pixels1 >> L_BLUE_SHIFT) & 0xff);
00185             v10r = area10 * ((pixels2 >> L_RED_SHIFT) & 0xff);
00186             v10g = area10 * ((pixels2 >> L_GREEN_SHIFT) & 0xff);
00187             v10b = area10 * ((pixels2 >> L_BLUE_SHIFT) & 0xff);
00188             v01r = area01 * ((pixels3 >> L_RED_SHIFT) & 0xff);
00189             v01g = area01 * ((pixels3 >> L_GREEN_SHIFT) & 0xff);
00190             v01b = area01 * ((pixels3 >> L_BLUE_SHIFT) & 0xff);
00191             v11r = area11 * ((pixels4 >> L_RED_SHIFT) & 0xff);
00192             v11g = area11 * ((pixels4 >> L_GREEN_SHIFT) & 0xff);
00193             v11b = area11 * ((pixels4 >> L_BLUE_SHIFT) & 0xff);
00194             pixel = (((v00r + v10r + v01r + v11r + 128) << 16) & 0xff000000) |
00195                     (((v00g + v10g + v01g + v11g + 128) << 8) & 0x00ff0000) |
00196                     ((v00b + v10b + v01b + v11b + 128) & 0x0000ff00);
00197             *(lined + j) = pixel;
00198         }
00199     }
00200 
00201     return;
00202 }
00203 
00204 
00205 /*------------------------------------------------------------------*
00206  *            General linear interpolated gray scaling              *
00207  *------------------------------------------------------------------*/
00208 /*!
00209  *  scaleGrayLILow()
00210  *
00211  *  We choose to divide each pixel into 16 x 16 sub-pixels.
00212  *  Linear interpolation is equivalent to finding the 
00213  *  fractional area (i.e., number of sub-pixels divided
00214  *  by 256) associated with each of the four nearest src pixels,
00215  *  and weighting each pixel value by this fractional area.
00216  */
00217 void
00218 scaleGrayLILow(l_uint32  *datad,
00219                l_int32    wd,
00220                l_int32    hd,
00221                l_int32    wpld,
00222                l_uint32  *datas,
00223                l_int32    ws,
00224                l_int32    hs,
00225                l_int32    wpls)
00226 {
00227 l_int32    i, j, wm2, hm2;
00228 l_int32    xpm, ypm;  /* location in src image, to 1/16 of a pixel */
00229 l_int32    xp, yp, xf, yf;  /* src pixel and pixel fraction coordinates */
00230 l_int32    v00, v01, v10, v11, v00_val, v01_val, v10_val, v11_val;
00231 l_uint8    val;
00232 l_uint32  *lines, *lined;
00233 l_float32  scx, scy;
00234 
00235         /* (scx, scy) are scaling factors that are applied to the
00236          * dest coords to get the corresponding src coords.
00237          * We need them because we iterate over dest pixels
00238          * and must find the corresponding set of src pixels. */
00239     scx = 16. * (l_float32)ws / (l_float32)wd;
00240     scy = 16. * (l_float32)hs / (l_float32)hd;
00241 
00242     wm2 = ws - 2;
00243     hm2 = hs - 2;
00244 
00245         /* Iterate over the destination pixels */
00246     for (i = 0; i < hd; i++) {
00247         ypm = (l_int32)(scy * (l_float32)i);
00248         yp = ypm >> 4;
00249         yf = ypm & 0x0f;
00250         lined = datad + i * wpld;
00251         lines = datas + yp * wpls;
00252         for (j = 0; j < wd; j++) {
00253             xpm = (l_int32)(scx * (l_float32)j);
00254             xp = xpm >> 4;
00255             xf = xpm & 0x0f;
00256 
00257                 /* Do bilinear interpolation.  Without this, we could
00258                  * simply subsample:
00259                  *   SET_DATA_BYTE(lined, j, GET_DATA_BYTE(lines, xp));
00260                  * which is faster but gives lousy results!  */
00261             v00_val = GET_DATA_BYTE(lines, xp);
00262             if (xp > wm2 || yp > hm2) {
00263                 if (yp > hm2 && xp <= wm2) {  /* pixels near bottom */
00264                     v01_val = v00_val;
00265                     v10_val = GET_DATA_BYTE(lines, xp + 1);
00266                     v11_val = v10_val;
00267                 }
00268                 else if (xp > wm2 && yp <= hm2) {  /* pixels near right side */
00269                     v01_val = GET_DATA_BYTE(lines + wpls, xp);
00270                     v10_val = v00_val;
00271                     v11_val = v01_val;
00272                 }
00273                 else {  /* pixels at LR corner */
00274                     v10_val = v01_val = v11_val = v00_val;
00275                 }
00276             }
00277             else {
00278                 v10_val = GET_DATA_BYTE(lines, xp + 1);
00279                 v01_val = GET_DATA_BYTE(lines + wpls, xp);
00280                 v11_val = GET_DATA_BYTE(lines + wpls, xp + 1);
00281             }
00282 
00283             v00 = (16 - xf) * (16 - yf) * v00_val;
00284             v10 = xf * (16 - yf) * v10_val;
00285             v01 = (16 - xf) * yf * v01_val;
00286             v11 = xf * yf * v11_val;
00287 
00288             val = (l_uint8)((v00 + v01 + v10 + v11 + 128) / 256);
00289             SET_DATA_BYTE(lined, j, val);
00290         }
00291     }
00292 
00293     return;
00294 }
00295 
00296 
00297 /*------------------------------------------------------------------*
00298  *                2x linear interpolated color scaling              *
00299  *------------------------------------------------------------------*/
00300 /*!
00301  *  scaleColor2xLILow()
00302  *
00303  *  This is a special case of 2x expansion by linear
00304  *  interpolation.  Each src pixel contains 4 dest pixels.
00305  *  The 4 dest pixels in src pixel 1 are numbered at
00306  *  their UL corners.  The 4 dest pixels in src pixel 1
00307  *  are related to that src pixel and its 3 neighboring
00308  *  src pixels as follows:
00309  *
00310  *             1-----2-----|-----|-----|
00311  *             |     |     |     |     |
00312  *             |     |     |     |     |
00313  *  src 1 -->  3-----4-----|     |     |  <-- src 2
00314  *             |     |     |     |     |
00315  *             |     |     |     |     |
00316  *             |-----|-----|-----|-----|
00317  *             |     |     |     |     |
00318  *             |     |     |     |     |
00319  *  src 3 -->  |     |     |     |     |  <-- src 4
00320  *             |     |     |     |     |
00321  *             |     |     |     |     |
00322  *             |-----|-----|-----|-----|
00323  *
00324  *           dest      src
00325  *           ----      ---
00326  *           dp1    =  sp1
00327  *           dp2    =  (sp1 + sp2) / 2
00328  *           dp3    =  (sp1 + sp3) / 2
00329  *           dp4    =  (sp1 + sp2 + sp3 + sp4) / 4
00330  *
00331  *  We iterate over the src pixels, and unroll the calculation
00332  *  for each set of 4 dest pixels corresponding to that src
00333  *  pixel, caching pixels for the next src pixel whenever possible.
00334  *  The method is exactly analogous to the one we use for
00335  *  scaleGray2xLILow() and its line version.
00336  *
00337  *  P3 speed is about 5 x 10^7 dst pixels/sec/GHz
00338  */
00339 void
00340 scaleColor2xLILow(l_uint32  *datad,
00341                   l_int32    wpld,
00342                   l_uint32  *datas,
00343                   l_int32    ws,
00344                   l_int32    hs,
00345                   l_int32    wpls)
00346 {
00347 l_int32    i, hsm;
00348 l_uint32  *lines, *lined;
00349 
00350     hsm = hs - 1;
00351 
00352         /* We're taking 2 src and 2 dest lines at a time,
00353          * and for each src line, we're computing 2 dest lines.
00354          * Call these 2 dest lines:  destline1 and destline2.
00355          * The first src line is used for destline 1.
00356          * On all but the last src line, both src lines are 
00357          * used in the linear interpolation for destline2.
00358          * On the last src line, both destline1 and destline2
00359          * are computed using only that src line (because there
00360          * isn't a lower src line). */
00361 
00362         /* iterate over all but the last src line */
00363     for (i = 0; i < hsm; i++) {
00364         lines = datas + i * wpls;
00365         lined = datad + 2 * i * wpld;
00366         scaleColor2xLILineLow(lined, wpld, lines, ws, wpls, 0);
00367     }
00368     
00369         /* last src line */
00370     lines = datas + hsm * wpls;
00371     lined = datad + 2 * hsm * wpld;
00372     scaleColor2xLILineLow(lined, wpld, lines, ws, wpls, 1);
00373 
00374     return;
00375 }
00376 
00377 
00378 /*!
00379  *  scaleColor2xLILineLow()
00380  *
00381  *      Input:  lined   (ptr to top destline, to be made from current src line)
00382  *              wpld
00383  *              lines   (ptr to current src line)
00384  *              ws
00385  *              wpls
00386  *              lastlineflag  (1 if last src line; 0 otherwise)
00387  *      Return: void
00388  *
00389  *  *** Warning: implicit assumption about RGB component ordering ***
00390  */
00391 void
00392 scaleColor2xLILineLow(l_uint32  *lined,
00393                       l_int32    wpld,
00394                       l_uint32  *lines,
00395                       l_int32    ws,
00396                       l_int32    wpls,
00397                       l_int32    lastlineflag)
00398 {
00399 l_int32    j, jd, wsm;
00400 l_int32    rval1, rval2, rval3, rval4, gval1, gval2, gval3, gval4;
00401 l_int32    bval1, bval2, bval3, bval4;
00402 l_uint32   pixels1, pixels2, pixels3, pixels4, pixel;
00403 l_uint32  *linesp, *linedp;
00404 
00405     wsm = ws - 1;
00406 
00407     if (lastlineflag == 0) {
00408         linesp = lines + wpls;
00409         linedp = lined + wpld;
00410         pixels1 = *lines;
00411         pixels3 = *linesp;
00412 
00413             /* initialize with v(2) and v(4) */
00414         rval2 = pixels1 >> 24;
00415         gval2 = (pixels1 >> 16) & 0xff;
00416         bval2 = (pixels1 >> 8) & 0xff;
00417         rval4 = pixels3 >> 24;
00418         gval4 = (pixels3 >> 16) & 0xff;
00419         bval4 = (pixels3 >> 8) & 0xff;
00420 
00421         for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
00422                 /* shift in previous src values */
00423             rval1 = rval2;
00424             gval1 = gval2;
00425             bval1 = bval2;
00426             rval3 = rval4;
00427             gval3 = gval4;
00428             bval3 = bval4;
00429                 /* get new src values */
00430             pixels2 = *(lines + j + 1);
00431             pixels4 = *(linesp + j + 1);
00432             rval2 = pixels2 >> 24;
00433             gval2 = (pixels2 >> 16) & 0xff;
00434             bval2 = (pixels2 >> 8) & 0xff;
00435             rval4 = pixels4 >> 24;
00436             gval4 = (pixels4 >> 16) & 0xff;
00437             bval4 = (pixels4 >> 8) & 0xff;
00438                 /* save dest values */
00439             pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
00440             *(lined + jd) = pixel;                               /* pix 1 */
00441             pixel = ((((rval1 + rval2) << 23) & 0xff000000) |
00442                      (((gval1 + gval2) << 15) & 0x00ff0000) |
00443                      (((bval1 + bval2) << 7) & 0x0000ff00));
00444             *(lined + jd + 1) = pixel;                           /* pix 2 */
00445             pixel = ((((rval1 + rval3) << 23) & 0xff000000) |
00446                      (((gval1 + gval3) << 15) & 0x00ff0000) |
00447                      (((bval1 + bval3) << 7) & 0x0000ff00));
00448             *(linedp + jd) = pixel;                              /* pix 3 */
00449             pixel = ((((rval1 + rval2 + rval3 + rval4) << 22) & 0xff000000) | 
00450                      (((gval1 + gval2 + gval3 + gval4) << 14) & 0x00ff0000) |
00451                      (((bval1 + bval2 + bval3 + bval4) << 6) & 0x0000ff00));
00452             *(linedp + jd + 1) = pixel;                          /* pix 4 */
00453         }  
00454             /* last src pixel on line */
00455         rval1 = rval2;
00456         gval1 = gval2;
00457         bval1 = bval2;
00458         rval3 = rval4;
00459         gval3 = gval4;
00460         bval3 = bval4;
00461         pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
00462         *(lined + 2 * wsm) = pixel;                        /* pix 1 */
00463         *(lined + 2 * wsm + 1) = pixel;                    /* pix 2 */
00464         pixel = ((((rval1 + rval3) << 23) & 0xff000000) |
00465                  (((gval1 + gval3) << 15) & 0x00ff0000) |
00466                  (((bval1 + bval3) << 7) & 0x0000ff00));
00467         *(linedp + 2 * wsm) = pixel;                       /* pix 3 */
00468         *(linedp + 2 * wsm + 1) = pixel;                   /* pix 4 */
00469     }
00470     else {   /* last row of src pixels: lastlineflag == 1 */
00471         linedp = lined + wpld;
00472         pixels2 = *lines;
00473         rval2 = pixels2 >> 24;
00474         gval2 = (pixels2 >> 16) & 0xff;
00475         bval2 = (pixels2 >> 8) & 0xff;
00476         for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
00477             rval1 = rval2;
00478             gval1 = gval2;
00479             bval1 = bval2;
00480             pixels2 = *(lines + j + 1);
00481             rval2 = pixels2 >> 24;
00482             gval2 = (pixels2 >> 16) & 0xff;
00483             bval2 = (pixels2 >> 8) & 0xff;
00484             pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
00485             *(lined + jd) = pixel;                            /* pix 1 */
00486             *(linedp + jd) = pixel;                           /* pix 2 */
00487             pixel = ((((rval1 + rval2) << 23) & 0xff000000) |
00488                      (((gval1 + gval2) << 15) & 0x00ff0000) |
00489                      (((bval1 + bval2) << 7) & 0x0000ff00));
00490             *(lined + jd + 1) = pixel;                        /* pix 3 */
00491             *(linedp + jd + 1) = pixel;                       /* pix 4 */
00492         }  
00493         rval1 = rval2;
00494         gval1 = gval2;
00495         bval1 = bval2;
00496         pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
00497         *(lined + 2 * wsm) = pixel;                           /* pix 1 */
00498         *(lined + 2 * wsm + 1) = pixel;                       /* pix 2 */
00499         *(linedp + 2 * wsm) = pixel;                          /* pix 3 */
00500         *(linedp + 2 * wsm + 1) = pixel;                      /* pix 4 */
00501     }
00502         
00503     return;
00504 }
00505 
00506 
00507 /*------------------------------------------------------------------*
00508  *                2x linear interpolated gray scaling               *
00509  *------------------------------------------------------------------*/
00510 /*!
00511  *  scaleGray2xLILow()
00512  *
00513  *  This is a special case of 2x expansion by linear
00514  *  interpolation.  Each src pixel contains 4 dest pixels.
00515  *  The 4 dest pixels in src pixel 1 are numbered at
00516  *  their UL corners.  The 4 dest pixels in src pixel 1
00517  *  are related to that src pixel and its 3 neighboring
00518  *  src pixels as follows:
00519  *
00520  *             1-----2-----|-----|-----|
00521  *             |     |     |     |     |
00522  *             |     |     |     |     |
00523  *  src 1 -->  3-----4-----|     |     |  <-- src 2
00524  *             |     |     |     |     |
00525  *             |     |     |     |     |
00526  *             |-----|-----|-----|-----|
00527  *             |     |     |     |     |
00528  *             |     |     |     |     |
00529  *  src 3 -->  |     |     |     |     |  <-- src 4
00530  *             |     |     |     |     |
00531  *             |     |     |     |     |
00532  *             |-----|-----|-----|-----|
00533  *
00534  *           dest      src
00535  *           ----      ---
00536  *           dp1    =  sp1
00537  *           dp2    =  (sp1 + sp2) / 2
00538  *           dp3    =  (sp1 + sp3) / 2
00539  *           dp4    =  (sp1 + sp2 + sp3 + sp4) / 4
00540  *
00541  *  We iterate over the src pixels, and unroll the calculation
00542  *  for each set of 4 dest pixels corresponding to that src
00543  *  pixel, caching pixels for the next src pixel whenever possible.
00544  */
00545 void
00546 scaleGray2xLILow(l_uint32  *datad,
00547                  l_int32    wpld,
00548                  l_uint32  *datas,
00549                  l_int32    ws,
00550                  l_int32    hs,
00551                  l_int32    wpls)
00552 {
00553 l_int32    i, hsm;
00554 l_uint32  *lines, *lined;
00555 
00556     hsm = hs - 1;
00557 
00558         /* We're taking 2 src and 2 dest lines at a time,
00559          * and for each src line, we're computing 2 dest lines.
00560          * Call these 2 dest lines:  destline1 and destline2.
00561          * The first src line is used for destline 1.
00562          * On all but the last src line, both src lines are 
00563          * used in the linear interpolation for destline2.
00564          * On the last src line, both destline1 and destline2
00565          * are computed using only that src line (because there
00566          * isn't a lower src line). */
00567 
00568         /* iterate over all but the last src line */
00569     for (i = 0; i < hsm; i++) {
00570         lines = datas + i * wpls;
00571         lined = datad + 2 * i * wpld;
00572         scaleGray2xLILineLow(lined, wpld, lines, ws, wpls, 0);
00573     }
00574     
00575         /* last src line */
00576     lines = datas + hsm * wpls;
00577     lined = datad + 2 * hsm * wpld;
00578     scaleGray2xLILineLow(lined, wpld, lines, ws, wpls, 1);
00579 
00580     return;
00581 }
00582 
00583 
00584 /*!
00585  *  scaleGray2xLILineLow()
00586  *
00587  *      Input:  lined   (ptr to top destline, to be made from current src line)
00588  *              wpld
00589  *              lines   (ptr to current src line)
00590  *              ws
00591  *              wpls
00592  *              lastlineflag  (1 if last src line; 0 otherwise)
00593  *      Return: void
00594  */
00595 void
00596 scaleGray2xLILineLow(l_uint32  *lined,
00597                      l_int32    wpld,
00598                      l_uint32  *lines,
00599                      l_int32    ws,
00600                      l_int32    wpls,
00601                      l_int32    lastlineflag)
00602 {
00603 l_int32    j, jd, wsm, w;
00604 l_int32    sval1, sval2, sval3, sval4;
00605 l_uint32  *linesp, *linedp;
00606 l_uint32   words, wordsp, wordd, worddp;
00607 
00608     wsm = ws - 1;
00609 
00610     if (lastlineflag == 0) {
00611         linesp = lines + wpls;
00612         linedp = lined + wpld;
00613 
00614             /* Unroll the loop 4x and work on full words */
00615         words = lines[0];
00616         wordsp = linesp[0];
00617         sval2 = (words >> 24) & 0xff;
00618         sval4 = (wordsp >> 24) & 0xff;
00619         for (j = 0, jd = 0, w = 0; j + 3 < wsm; j += 4, jd += 8, w++) {
00620                 /* At the top of the loop,
00621                  * words == lines[w], wordsp == linesp[w]
00622                  * and the top bytes of those have been loaded into
00623                  * sval2 and sval4. */
00624             sval1 = sval2;
00625             sval2 = (words >> 16) & 0xff;
00626             sval3 = sval4;
00627             sval4 = (wordsp >> 16) & 0xff;
00628             wordd = (sval1 << 24) | (((sval1 + sval2) >> 1) << 16);
00629             worddp = (((sval1 + sval3) >> 1) << 24) |
00630                 (((sval1 + sval2 + sval3 + sval4) >> 2) << 16);
00631 
00632             sval1 = sval2;
00633             sval2 = (words >> 8) & 0xff;
00634             sval3 = sval4;
00635             sval4 = (wordsp >> 8) & 0xff;
00636             wordd |= (sval1 << 8) | ((sval1 + sval2) >> 1);
00637             worddp |= (((sval1 + sval3) >> 1) << 8) |
00638                 ((sval1 + sval2 + sval3 + sval4) >> 2);
00639             lined[w * 2] = wordd;
00640             linedp[w * 2] = worddp;
00641 
00642             sval1 = sval2;
00643             sval2 = words & 0xff;
00644             sval3 = sval4;
00645             sval4 = wordsp & 0xff;
00646             wordd = (sval1 << 24) |                              /* pix 1 */
00647                 (((sval1 + sval2) >> 1) << 16);                  /* pix 2 */
00648             worddp = (((sval1 + sval3) >> 1) << 24) |            /* pix 3 */
00649                 (((sval1 + sval2 + sval3 + sval4) >> 2) << 16);  /* pix 4 */
00650 
00651                 /* Load the next word as we need its first byte */
00652             words = lines[w + 1];
00653             wordsp = linesp[w + 1];
00654             sval1 = sval2;
00655             sval2 = (words >> 24) & 0xff;
00656             sval3 = sval4;
00657             sval4 = (wordsp >> 24) & 0xff;
00658             wordd |= (sval1 << 8) |                              /* pix 1 */
00659                 ((sval1 + sval2) >> 1);                          /* pix 2 */
00660             worddp |= (((sval1 + sval3) >> 1) << 8) |            /* pix 3 */
00661                 ((sval1 + sval2 + sval3 + sval4) >> 2);          /* pix 4 */
00662             lined[w * 2 + 1] = wordd;
00663             linedp[w * 2 + 1] = worddp;
00664         }
00665 
00666             /* Finish up the last word */
00667         for (; j < wsm; j++, jd += 2) {
00668             sval1 = sval2;
00669             sval3 = sval4;
00670             sval2 = GET_DATA_BYTE(lines, j + 1);
00671             sval4 = GET_DATA_BYTE(linesp, j + 1);
00672             SET_DATA_BYTE(lined, jd, sval1);                     /* pix 1 */
00673             SET_DATA_BYTE(lined, jd + 1, (sval1 + sval2) / 2);   /* pix 2 */
00674             SET_DATA_BYTE(linedp, jd, (sval1 + sval3) / 2);      /* pix 3 */
00675             SET_DATA_BYTE(linedp, jd + 1,
00676                           (sval1 + sval2 + sval3 + sval4) / 4);  /* pix 4 */
00677         }
00678         sval1 = sval2;
00679         sval3 = sval4;
00680         SET_DATA_BYTE(lined, 2 * wsm, sval1);                     /* pix 1 */
00681         SET_DATA_BYTE(lined, 2 * wsm + 1, sval1);                 /* pix 2 */
00682         SET_DATA_BYTE(linedp, 2 * wsm, (sval1 + sval3) / 2);      /* pix 3 */
00683         SET_DATA_BYTE(linedp, 2 * wsm + 1, (sval1 + sval3) / 2);  /* pix 4 */
00684 
00685 #if DEBUG_UNROLLING
00686 #define CHECK_BYTE(a, b, c) if (GET_DATA_BYTE(a, b) != c) {\
00687      fprintf(stderr, "Error: mismatch at %d, %d vs %d\n", \
00688              j, GET_DATA_BYTE(a, b), c); }
00689 
00690         sval2 = GET_DATA_BYTE(lines, 0);
00691         sval4 = GET_DATA_BYTE(linesp, 0);
00692         for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
00693             sval1 = sval2;
00694             sval3 = sval4;
00695             sval2 = GET_DATA_BYTE(lines, j + 1);
00696             sval4 = GET_DATA_BYTE(linesp, j + 1);
00697             CHECK_BYTE(lined, jd, sval1);                     /* pix 1 */
00698             CHECK_BYTE(lined, jd + 1, (sval1 + sval2) / 2);   /* pix 2 */
00699             CHECK_BYTE(linedp, jd, (sval1 + sval3) / 2);      /* pix 3 */
00700             CHECK_BYTE(linedp, jd + 1,
00701                           (sval1 + sval2 + sval3 + sval4) / 4);  /* pix 4 */
00702         }
00703         sval1 = sval2;
00704         sval3 = sval4;
00705         CHECK_BYTE(lined, 2 * wsm, sval1);                     /* pix 1 */
00706         CHECK_BYTE(lined, 2 * wsm + 1, sval1);                 /* pix 2 */
00707         CHECK_BYTE(linedp, 2 * wsm, (sval1 + sval3) / 2);      /* pix 3 */
00708         CHECK_BYTE(linedp, 2 * wsm + 1, (sval1 + sval3) / 2);  /* pix 4 */
00709 #undef CHECK_BYTE
00710 #endif
00711     }
00712     else {   /* last row of src pixels: lastlineflag == 1 */
00713         linedp = lined + wpld;
00714         sval2 = GET_DATA_BYTE(lines, 0);
00715         for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
00716             sval1 = sval2;
00717             sval2 = GET_DATA_BYTE(lines, j + 1);
00718             SET_DATA_BYTE(lined, jd, sval1);                       /* pix 1 */
00719             SET_DATA_BYTE(linedp, jd, sval1);                      /* pix 3 */
00720             SET_DATA_BYTE(lined, jd + 1, (sval1 + sval2) / 2);     /* pix 2 */
00721             SET_DATA_BYTE(linedp, jd + 1, (sval1 + sval2) / 2);    /* pix 4 */
00722         }  
00723         sval1 = sval2;
00724         SET_DATA_BYTE(lined, 2 * wsm, sval1);                     /* pix 1 */
00725         SET_DATA_BYTE(lined, 2 * wsm + 1, sval1);                 /* pix 2 */
00726         SET_DATA_BYTE(linedp, 2 * wsm, sval1);                    /* pix 3 */
00727         SET_DATA_BYTE(linedp, 2 * wsm + 1, sval1);                /* pix 4 */
00728     }
00729         
00730     return;
00731 }
00732 
00733 
00734 /*------------------------------------------------------------------*
00735  *               4x linear interpolated gray scaling                *
00736  *------------------------------------------------------------------*/
00737 /*!
00738  *  scaleGray4xLILow()
00739  *
00740  *  This is a special case of 4x expansion by linear
00741  *  interpolation.  Each src pixel contains 16 dest pixels.
00742  *  The 16 dest pixels in src pixel 1 are numbered at
00743  *  their UL corners.  The 16 dest pixels in src pixel 1
00744  *  are related to that src pixel and its 3 neighboring
00745  *  src pixels as follows:
00746  *
00747  *             1---2---3---4---|---|---|---|---|
00748  *             |   |   |   |   |   |   |   |   |
00749  *             5---6---7---8---|---|---|---|---|
00750  *             |   |   |   |   |   |   |   |   |
00751  *  src 1 -->  9---a---b---c---|---|---|---|---|  <-- src 2
00752  *             |   |   |   |   |   |   |   |   |
00753  *             d---e---f---g---|---|---|---|---|
00754  *             |   |   |   |   |   |   |   |   |
00755  *             |===|===|===|===|===|===|===|===|
00756  *             |   |   |   |   |   |   |   |   |
00757  *             |---|---|---|---|---|---|---|---|
00758  *             |   |   |   |   |   |   |   |   |
00759  *  src 3 -->  |---|---|---|---|---|---|---|---|  <-- src 4
00760  *             |   |   |   |   |   |   |   |   |
00761  *             |---|---|---|---|---|---|---|---|
00762  *             |   |   |   |   |   |   |   |   |
00763  *             |---|---|---|---|---|---|---|---|
00764  *
00765  *           dest      src
00766  *           ----      ---
00767  *           dp1    =  sp1
00768  *           dp2    =  (3 * sp1 + sp2) / 4
00769  *           dp3    =  (sp1 + sp2) / 2
00770  *           dp4    =  (sp1 + 3 * sp2) / 4
00771  *           dp5    =  (3 * sp1 + sp3) / 4
00772  *           dp6    =  (9 * sp1 + 3 * sp2 + 3 * sp3 + sp4) / 16 
00773  *           dp7    =  (3 * sp1 + 3 * sp2 + sp3 + sp4) / 8
00774  *           dp8    =  (3 * sp1 + 9 * sp2 + 1 * sp3 + 3 * sp4) / 16 
00775  *           dp9    =  (sp1 + sp3) / 2
00776  *           dp10   =  (3 * sp1 + sp2 + 3 * sp3 + sp4) / 8
00777  *           dp11   =  (sp1 + sp2 + sp3 + sp4) / 4 
00778  *           dp12   =  (sp1 + 3 * sp2 + sp3 + 3 * sp4) / 8
00779  *           dp13   =  (sp1 + 3 * sp3) / 4
00780  *           dp14   =  (3 * sp1 + sp2 + 9 * sp3 + 3 * sp4) / 16 
00781  *           dp15   =  (sp1 + sp2 + 3 * sp3 + 3 * sp4) / 8
00782  *           dp16   =  (sp1 + 3 * sp2 + 3 * sp3 + 9 * sp4) / 16 
00783  *
00784  *  We iterate over the src pixels, and unroll the calculation
00785  *  for each set of 16 dest pixels corresponding to that src
00786  *  pixel, caching pixels for the next src pixel whenever possible.
00787  */
00788 void
00789 scaleGray4xLILow(l_uint32  *datad,
00790                  l_int32    wpld,
00791                  l_uint32  *datas,
00792                  l_int32    ws,
00793                  l_int32    hs,
00794                  l_int32    wpls)
00795 {
00796 l_int32    i, hsm;
00797 l_uint32  *lines, *lined;
00798 
00799     hsm = hs - 1;
00800 
00801         /* We're taking 2 src and 4 dest lines at a time,
00802          * and for each src line, we're computing 4 dest lines.
00803          * Call these 4 dest lines:  destline1 - destline4.
00804          * The first src line is used for destline 1.
00805          * Two src lines are used for all other dest lines,
00806          * except for the last 4 dest lines, which are computed
00807          * using only the last src line. */
00808 
00809         /* iterate over all but the last src line */
00810     for (i = 0; i < hsm; i++) {
00811         lines = datas + i * wpls;
00812         lined = datad + 4 * i * wpld;
00813         scaleGray4xLILineLow(lined, wpld, lines, ws, wpls, 0);
00814     }
00815     
00816         /* last src line */
00817     lines = datas + hsm * wpls;
00818     lined = datad + 4 * hsm * wpld;
00819     scaleGray4xLILineLow(lined, wpld, lines, ws, wpls, 1);
00820 
00821     return;
00822 }
00823 
00824 
00825 /*!
00826  *  scaleGray4xLILineLow()
00827  *
00828  *      Input:  lined   (ptr to top destline, to be made from current src line)
00829  *              wpld
00830  *              lines   (ptr to current src line)
00831  *              ws
00832  *              wpls
00833  *              lastlineflag  (1 if last src line; 0 otherwise)
00834  *      Return: void
00835  */
00836 void
00837 scaleGray4xLILineLow(l_uint32  *lined,
00838                      l_int32    wpld,
00839                      l_uint32  *lines,
00840                      l_int32    ws,
00841                      l_int32    wpls,
00842                      l_int32    lastlineflag)
00843 {
00844 l_int32    j, jd, wsm, wsm4;
00845 l_int32    s1, s2, s3, s4, s1t, s2t, s3t, s4t;
00846 l_uint32  *linesp, *linedp1, *linedp2, *linedp3;
00847 
00848     wsm = ws - 1;
00849     wsm4 = 4 * wsm;
00850 
00851     if (lastlineflag == 0) {
00852         linesp = lines + wpls;
00853         linedp1 = lined + wpld;
00854         linedp2 = lined + 2 * wpld;
00855         linedp3 = lined + 3 * wpld;
00856         s2 = GET_DATA_BYTE(lines, 0);
00857         s4 = GET_DATA_BYTE(linesp, 0);
00858         for (j = 0, jd = 0; j < wsm; j++, jd += 4) {
00859             s1 = s2;
00860             s3 = s4;
00861             s2 = GET_DATA_BYTE(lines, j + 1);
00862             s4 = GET_DATA_BYTE(linesp, j + 1);
00863             s1t = 3 * s1;
00864             s2t = 3 * s2;
00865             s3t = 3 * s3;
00866             s4t = 3 * s4;
00867             SET_DATA_BYTE(lined, jd, s1);                             /* d1 */
00868             SET_DATA_BYTE(lined, jd + 1, (s1t + s2) / 4);             /* d2 */
00869             SET_DATA_BYTE(lined, jd + 2, (s1 + s2) / 2);              /* d3 */
00870             SET_DATA_BYTE(lined, jd + 3, (s1 + s2t) / 4);             /* d4 */
00871             SET_DATA_BYTE(linedp1, jd, (s1t + s3) / 4);                /* d5 */
00872             SET_DATA_BYTE(linedp1, jd + 1, (9*s1 + s2t + s3t + s4) / 16); /*d6*/
00873             SET_DATA_BYTE(linedp1, jd + 2, (s1t + s2t + s3 + s4) / 8); /* d7 */
00874             SET_DATA_BYTE(linedp1, jd + 3, (s1t + 9*s2 + s3 + s4t) / 16);/*d8*/
00875             SET_DATA_BYTE(linedp2, jd, (s1 + s3) / 2);                /* d9 */
00876             SET_DATA_BYTE(linedp2, jd + 1, (s1t + s2 + s3t + s4) / 8);/* d10 */
00877             SET_DATA_BYTE(linedp2, jd + 2, (s1 + s2 + s3 + s4) / 4);  /* d11 */
00878             SET_DATA_BYTE(linedp2, jd + 3, (s1 + s2t + s3 + s4t) / 8);/* d12 */
00879             SET_DATA_BYTE(linedp3, jd, (s1 + s3t) / 4);               /* d13 */
00880             SET_DATA_BYTE(linedp3, jd + 1, (s1t + s2 + 9*s3 + s4t) / 16);/*d14*/
00881             SET_DATA_BYTE(linedp3, jd + 2, (s1 + s2 + s3t + s4t) / 8); /* d15 */
00882             SET_DATA_BYTE(linedp3, jd + 3, (s1 + s2t + s3t + 9*s4) / 16);/*d16*/
00883         }  
00884         s1 = s2;
00885         s3 = s4;
00886         s1t = 3 * s1;
00887         s3t = 3 * s3;
00888         SET_DATA_BYTE(lined, wsm4, s1);                               /* d1 */
00889         SET_DATA_BYTE(lined, wsm4 + 1, s1);                           /* d2 */
00890         SET_DATA_BYTE(lined, wsm4 + 2, s1);                           /* d3 */
00891         SET_DATA_BYTE(lined, wsm4 + 3, s1);                           /* d4 */
00892         SET_DATA_BYTE(linedp1, wsm4, (s1t + s3) / 4);                 /* d5 */
00893         SET_DATA_BYTE(linedp1, wsm4 + 1, (s1t + s3) / 4);             /* d6 */
00894         SET_DATA_BYTE(linedp1, wsm4 + 2, (s1t + s3) / 4);             /* d7 */
00895         SET_DATA_BYTE(linedp1, wsm4 + 3, (s1t + s3) / 4);             /* d8 */
00896         SET_DATA_BYTE(linedp2, wsm4, (s1 + s3) / 2);                  /* d9 */
00897         SET_DATA_BYTE(linedp2, wsm4 + 1, (s1 + s3) / 2);              /* d10 */
00898         SET_DATA_BYTE(linedp2, wsm4 + 2, (s1 + s3) / 2);              /* d11 */
00899         SET_DATA_BYTE(linedp2, wsm4 + 3, (s1 + s3) / 2);              /* d12 */
00900         SET_DATA_BYTE(linedp3, wsm4, (s1 + s3t) / 4);                 /* d13 */
00901         SET_DATA_BYTE(linedp3, wsm4 + 1, (s1 + s3t) / 4);             /* d14 */
00902         SET_DATA_BYTE(linedp3, wsm4 + 2, (s1 + s3t) / 4);             /* d15 */
00903         SET_DATA_BYTE(linedp3, wsm4 + 3, (s1 + s3t) / 4);             /* d16 */
00904     }
00905     else {   /* last row of src pixels: lastlineflag == 1 */
00906         linedp1 = lined + wpld;
00907         linedp2 = lined + 2 * wpld;
00908         linedp3 = lined + 3 * wpld;
00909         s2 = GET_DATA_BYTE(lines, 0);
00910         for (j = 0, jd = 0; j < wsm; j++, jd += 4) {
00911             s1 = s2;
00912             s2 = GET_DATA_BYTE(lines, j + 1);
00913             s1t = 3 * s1;
00914             s2t = 3 * s2;
00915             SET_DATA_BYTE(lined, jd, s1);                            /* d1 */
00916             SET_DATA_BYTE(lined, jd + 1, (s1t + s2) / 4 );           /* d2 */
00917             SET_DATA_BYTE(lined, jd + 2, (s1 + s2) / 2 );            /* d3 */
00918             SET_DATA_BYTE(lined, jd + 3, (s1 + s2t) / 4 );           /* d4 */
00919             SET_DATA_BYTE(linedp1, jd, s1);                          /* d5 */
00920             SET_DATA_BYTE(linedp1, jd + 1, (s1t + s2) / 4 );         /* d6 */
00921             SET_DATA_BYTE(linedp1, jd + 2, (s1 + s2) / 2 );          /* d7 */
00922             SET_DATA_BYTE(linedp1, jd + 3, (s1 + s2t) / 4 );         /* d8 */
00923             SET_DATA_BYTE(linedp2, jd, s1);                          /* d9 */
00924             SET_DATA_BYTE(linedp2, jd + 1, (s1t + s2) / 4 );         /* d10 */
00925             SET_DATA_BYTE(linedp2, jd + 2, (s1 + s2) / 2 );          /* d11 */
00926             SET_DATA_BYTE(linedp2, jd + 3, (s1 + s2t) / 4 );         /* d12 */
00927             SET_DATA_BYTE(linedp3, jd, s1);                          /* d13 */
00928             SET_DATA_BYTE(linedp3, jd + 1, (s1t + s2) / 4 );         /* d14 */
00929             SET_DATA_BYTE(linedp3, jd + 2, (s1 + s2) / 2 );          /* d15 */
00930             SET_DATA_BYTE(linedp3, jd + 3, (s1 + s2t) / 4 );         /* d16 */
00931         }  
00932         s1 = s2;
00933         SET_DATA_BYTE(lined, wsm4, s1);                              /* d1 */
00934         SET_DATA_BYTE(lined, wsm4 + 1, s1);                          /* d2 */
00935         SET_DATA_BYTE(lined, wsm4 + 2, s1);                          /* d3 */
00936         SET_DATA_BYTE(lined, wsm4 + 3, s1);                          /* d4 */
00937         SET_DATA_BYTE(linedp1, wsm4, s1);                            /* d5 */
00938         SET_DATA_BYTE(linedp1, wsm4 + 1, s1);                        /* d6 */
00939         SET_DATA_BYTE(linedp1, wsm4 + 2, s1);                        /* d7 */
00940         SET_DATA_BYTE(linedp1, wsm4 + 3, s1);                        /* d8 */
00941         SET_DATA_BYTE(linedp2, wsm4, s1);                            /* d9 */
00942         SET_DATA_BYTE(linedp2, wsm4 + 1, s1);                        /* d10 */
00943         SET_DATA_BYTE(linedp2, wsm4 + 2, s1);                        /* d11 */
00944         SET_DATA_BYTE(linedp2, wsm4 + 3, s1);                        /* d12 */
00945         SET_DATA_BYTE(linedp3, wsm4, s1);                            /* d13 */
00946         SET_DATA_BYTE(linedp3, wsm4 + 1, s1);                        /* d14 */
00947         SET_DATA_BYTE(linedp3, wsm4 + 2, s1);                        /* d15 */
00948         SET_DATA_BYTE(linedp3, wsm4 + 3, s1);                        /* d16 */
00949     }
00950         
00951     return;
00952 }
00953 
00954 
00955 /*------------------------------------------------------------------*
00956  *       Grayscale and color scaling by closest pixel sampling      *
00957  *------------------------------------------------------------------*/
00958 /*!
00959  *  scaleBySamplingLow()
00960  *
00961  *  Notes:
00962  *      (1) The dest must be cleared prior to this operation,
00963  *          and we clear it here in the low-level code.
00964  *      (2) We reuse dest pixels and dest pixel rows whenever
00965  *          possible.  This speeds the upscaling; downscaling
00966  *          is done by strict subsampling and is unaffected.
00967  *      (3) Because we are sampling and not interpolating, this
00968  *          routine works directly, without conversion to full
00969  *          RGB color, for 2, 4 or 8 bpp palette color images.
00970  */
00971 l_int32
00972 scaleBySamplingLow(l_uint32  *datad,
00973                    l_int32    wd,
00974                    l_int32    hd,
00975                    l_int32    wpld,
00976                    l_uint32  *datas,
00977                    l_int32    ws,
00978                    l_int32    hs,
00979                    l_int32    d,
00980                    l_int32    wpls)
00981 {
00982 l_int32    i, j, bpld;
00983 l_int32    xs, prevxs, sval;
00984 l_int32   *srow, *scol;
00985 l_uint32   csval;
00986 l_uint32  *lines, *prevlines, *lined, *prevlined;
00987 l_float32  wratio, hratio;
00988 
00989     PROCNAME("scaleBySamplingLow");
00990 
00991         /* clear dest */
00992     bpld = 4 * wpld;
00993     memset((char *)datad, 0, hd * bpld);
00994     
00995         /* the source row corresponding to dest row i ==> srow[i]
00996          * the source col corresponding to dest col j ==> scol[j]  */
00997     if ((srow = (l_int32 *)CALLOC(hd, sizeof(l_int32))) == NULL)
00998         return ERROR_INT("srow not made", procName, 1);
00999     if ((scol = (l_int32 *)CALLOC(wd, sizeof(l_int32))) == NULL)
01000         return ERROR_INT("scol not made", procName, 1);
01001 
01002     wratio = (l_float32)ws / (l_float32)wd;
01003     hratio = (l_float32)hs / (l_float32)hd;
01004     for (i = 0; i < hd; i++)
01005         srow[i] = L_MIN((l_int32)(hratio * i + 0.5), hs - 1);
01006     for (j = 0; j < wd; j++)
01007         scol[j] = L_MIN((l_int32)(wratio * j + 0.5), ws - 1);
01008 
01009     prevlines = NULL;
01010     for (i = 0; i < hd; i++) {
01011         lines = datas + srow[i] * wpls;
01012         lined = datad + i * wpld;
01013         if (lines != prevlines) {  /* make dest from new source row */
01014             prevxs = -1;
01015             sval = 0;
01016             csval = 0;
01017             switch (d)
01018             {
01019             case 2:
01020                 for (j = 0; j < wd; j++) {
01021                     xs = scol[j];
01022                     if (xs != prevxs) {  /* get dest pix from source col */
01023                         sval = GET_DATA_DIBIT(lines, xs);
01024                         SET_DATA_DIBIT(lined, j, sval);
01025                         prevxs = xs;
01026                     }
01027                     else   /* copy prev dest pix */
01028                         SET_DATA_DIBIT(lined, j, sval);
01029                 }
01030                 break;
01031             case 4:
01032                 for (j = 0; j < wd; j++) {
01033                     xs = scol[j];
01034                     if (xs != prevxs) {  /* get dest pix from source col */
01035                         sval = GET_DATA_QBIT(lines, xs);
01036                         SET_DATA_QBIT(lined, j, sval);
01037                         prevxs = xs;
01038                     }
01039                     else   /* copy prev dest pix */
01040                         SET_DATA_QBIT(lined, j, sval);
01041                 }
01042                 break;
01043             case 8:
01044                 for (j = 0; j < wd; j++) {
01045                     xs = scol[j];
01046                     if (xs != prevxs) {  /* get dest pix from source col */
01047                         sval = GET_DATA_BYTE(lines, xs);
01048                         SET_DATA_BYTE(lined, j, sval);
01049                         prevxs = xs;
01050                     }
01051                     else   /* copy prev dest pix */
01052                         SET_DATA_BYTE(lined, j, sval);
01053                 }
01054                 break;
01055             case 16:
01056                 for (j = 0; j < wd; j++) {
01057                     xs = scol[j];
01058                     if (xs != prevxs) {  /* get dest pix from source col */
01059                         sval = GET_DATA_TWO_BYTES(lines, xs);
01060                         SET_DATA_TWO_BYTES(lined, j, sval);
01061                         prevxs = xs;
01062                     }
01063                     else   /* copy prev dest pix */
01064                         SET_DATA_TWO_BYTES(lined, j, sval);
01065                 }
01066                 break;
01067             case 32:
01068                 for (j = 0; j < wd; j++) {
01069                     xs = scol[j];
01070                     if (xs != prevxs) {  /* get dest pix from source col */
01071                         csval = lines[xs];
01072                         lined[j] = csval;
01073                         prevxs = xs;
01074                     }
01075                     else   /* copy prev dest pix */
01076                         lined[j] = csval;
01077                 }
01078                 break;
01079             default:
01080                 return ERROR_INT("pixel depth not supported", procName, 1);
01081                 break;
01082             }
01083         }
01084         else {  /* lines == prevlines; copy prev dest row */
01085             prevlined = lined - wpld;
01086             memcpy((char *)lined, (char *)prevlined, bpld);
01087         }
01088         prevlines = lines;
01089     }
01090 
01091     FREE(srow);
01092     FREE(scol);
01093 
01094     return 0;
01095 }
01096 
01097 
01098 /*------------------------------------------------------------------*
01099  *    Color and grayscale downsampling with (antialias) smoothing   *
01100  *------------------------------------------------------------------*/
01101 /*!
01102  *  scaleSmoothLow()
01103  *
01104  *  Notes:
01105  *      (1) This function is called on 8 or 32 bpp src and dest images.
01106  *      (2) size is the full width of the lowpass smoothing filter.
01107  *          It is correlated with the reduction ratio, being the
01108  *          nearest integer such that size is approximately equal to hs / hd.
01109  */
01110 l_int32
01111 scaleSmoothLow(l_uint32  *datad,
01112                l_int32    wd,
01113                l_int32    hd,
01114                l_int32    wpld,
01115                l_uint32  *datas,
01116                l_int32    ws,
01117                l_int32    hs,
01118                l_int32    d,
01119                l_int32    wpls,
01120                l_int32    size)
01121 {
01122 l_int32    i, j, m, n, xstart;
01123 l_int32    val, rval, gval, bval;
01124 l_int32   *srow, *scol;
01125 l_uint32  *lines, *lined, *line, *ppixel;
01126 l_uint32   pixel;
01127 l_float32  wratio, hratio, norm;
01128 
01129     PROCNAME("scaleSmoothLow");
01130 
01131         /* Clear dest */
01132     memset((char *)datad, 0, 4 * wpld * hd);
01133     
01134         /* Each dest pixel at (j,i) is computed as the average
01135            of size^2 corresponding src pixels.
01136            We store the UL corner location of the square of
01137            src pixels that correspond to dest pixel (j,i).
01138            The are labelled by the arrays srow[i] and scol[j]. */
01139     if ((srow = (l_int32 *)CALLOC(hd, sizeof(l_int32))) == NULL)
01140         return ERROR_INT("srow not made", procName, 1);
01141     if ((scol = (l_int32 *)CALLOC(wd, sizeof(l_int32))) == NULL)
01142         return ERROR_INT("scol not made", procName, 1);
01143 
01144     norm = 1. / (l_float32)(size * size);
01145     wratio = (l_float32)ws / (l_float32)wd;
01146     hratio = (l_float32)hs / (l_float32)hd;
01147     for (i = 0; i < hd; i++)
01148         srow[i] = L_MIN((l_int32)(hratio * i), hs - size);
01149     for (j = 0; j < wd; j++)
01150         scol[j] = L_MIN((l_int32)(wratio * j), ws - size);
01151 
01152         /* For each dest pixel, compute average */
01153     if (d == 8) {
01154         for (i = 0; i < hd; i++) {
01155             lines = datas + srow[i] * wpls;
01156             lined = datad + i * wpld;
01157             for (j = 0; j < wd; j++) {
01158                 xstart = scol[j];
01159                 val = 0;
01160                 for (m = 0; m < size; m++) {
01161                     line = lines + m * wpls;
01162                     for (n = 0; n < size; n++) {
01163                         val += GET_DATA_BYTE(line, xstart + n);
01164                     }
01165                 }
01166                 val = (l_int32)((l_float32)val * norm);
01167                 SET_DATA_BYTE(lined, j, val);
01168             }
01169         }
01170     }
01171     else {  /* d == 32 */
01172         for (i = 0; i < hd; i++) {
01173             lines = datas + srow[i] * wpls;
01174             lined = datad + i * wpld;
01175             for (j = 0; j < wd; j++) {
01176                 xstart = scol[j];
01177                 rval = gval = bval = 0;
01178                 for (m = 0; m < size; m++) {
01179                     ppixel = lines + m * wpls + xstart;
01180                     for (n = 0; n < size; n++) {
01181                         pixel = *(ppixel + n);
01182                         rval += (pixel >> L_RED_SHIFT) & 0xff;
01183                         gval += (pixel >> L_GREEN_SHIFT) & 0xff;
01184                         bval += (pixel >> L_BLUE_SHIFT) & 0xff;
01185                     }
01186                 }
01187                 rval = (l_int32)((l_float32)rval * norm);
01188                 gval = (l_int32)((l_float32)gval * norm);
01189                 bval = (l_int32)((l_float32)bval * norm);
01190                 *(lined + j) = rval << L_RED_SHIFT |
01191                                gval << L_GREEN_SHIFT |
01192                                bval << L_BLUE_SHIFT;
01193             }
01194         }
01195     }
01196 
01197     FREE(srow);
01198     FREE(scol);
01199     return 0;
01200 }
01201 
01202 
01203 /*!
01204  *  scaleRGBToGray2Low()
01205  *
01206  *  Note: This function is called with 32 bpp RGB src and 8 bpp,
01207  *        half-resolution dest.  The weights should add to 1.0.
01208  */
01209 void
01210 scaleRGBToGray2Low(l_uint32  *datad,
01211                    l_int32    wd,
01212                    l_int32    hd,
01213                    l_int32    wpld,
01214                    l_uint32  *datas,
01215                    l_int32    wpls,
01216                    l_float32  rwt,
01217                    l_float32  gwt,
01218                    l_float32  bwt)
01219 {
01220 l_int32    i, j, val, rval, gval, bval;
01221 l_uint32  *lines, *lined;
01222 l_uint32   pixel;
01223 
01224     rwt *= 0.25;
01225     gwt *= 0.25;
01226     bwt *= 0.25;
01227     for (i = 0; i < hd; i++) {
01228         lines = datas + 2 * i * wpls;
01229         lined = datad + i * wpld;
01230         for (j = 0; j < wd; j++) {
01231                 /* Sum each of the color components from 4 src pixels */
01232             pixel = *(lines + 2 * j);
01233             rval = (pixel >> L_RED_SHIFT) & 0xff;
01234             gval = (pixel >> L_GREEN_SHIFT) & 0xff;
01235             bval = (pixel >> L_BLUE_SHIFT) & 0xff;
01236             pixel = *(lines + 2 * j + 1);
01237             rval += (pixel >> L_RED_SHIFT) & 0xff;
01238             gval += (pixel >> L_GREEN_SHIFT) & 0xff;
01239             bval += (pixel >> L_BLUE_SHIFT) & 0xff;
01240             pixel = *(lines + wpls + 2 * j);
01241             rval += (pixel >> L_RED_SHIFT) & 0xff;
01242             gval += (pixel >> L_GREEN_SHIFT) & 0xff;
01243             bval += (pixel >> L_BLUE_SHIFT) & 0xff;
01244             pixel = *(lines + wpls + 2 * j + 1);
01245             rval += (pixel >> L_RED_SHIFT) & 0xff;
01246             gval += (pixel >> L_GREEN_SHIFT) & 0xff;
01247             bval += (pixel >> L_BLUE_SHIFT) & 0xff;
01248                 /* Generate the dest byte as a weighted sum of the averages */
01249             val = (l_int32)(rwt * rval + gwt * gval + bwt * bval);
01250             SET_DATA_BYTE(lined, j, val);
01251         }
01252     }
01253 }
01254 
01255 
01256 /*------------------------------------------------------------------*
01257  *                  General area mapped gray scaling                *
01258  *------------------------------------------------------------------*/
01259 /*!
01260  *  scaleColorAreaMapLow()
01261  *
01262  *  This should only be used for downscaling.
01263  *  We choose to divide each pixel into 16 x 16 sub-pixels.
01264  *  This is much slower than scaleSmoothLow(), but it gives a
01265  *  better representation, esp. for downscaling factors between
01266  *  1.5 and 5.  All src pixels are subdivided into 256 sub-pixels,
01267  *  and are weighted by the number of sub-pixels covered by
01268  *  the dest pixel.  This is about 2x slower than scaleSmoothLow(),
01269  *  but the results are significantly better on small text.
01270  */
01271 void
01272 scaleColorAreaMapLow(l_uint32  *datad,
01273                     l_int32    wd,
01274                     l_int32    hd,
01275                     l_int32    wpld,
01276                     l_uint32  *datas,
01277                     l_int32    ws,
01278                     l_int32    hs,
01279                     l_int32    wpls)
01280 {
01281 l_int32    i, j, k, m, wm2, hm2;
01282 l_int32    area00, area10, area01, area11, areal, arear, areat, areab;
01283 l_int32    xu, yu;  /* UL corner in src image, to 1/16 of a pixel */
01284 l_int32    xl, yl;  /* LR corner in src image, to 1/16 of a pixel */
01285 l_int32    xup, yup, xuf, yuf;  /* UL src pixel: integer and fraction */
01286 l_int32    xlp, ylp, xlf, ylf;  /* LR src pixel: integer and fraction */
01287 l_int32    delx, dely, area;
01288 l_int32    v00r, v00g, v00b;  /* contrib. from UL src pixel */
01289 l_int32    v01r, v01g, v01b;  /* contrib. from LL src pixel */
01290 l_int32    v10r, v10g, v10b;  /* contrib from UR src pixel */
01291 l_int32    v11r, v11g, v11b;  /* contrib from LR src pixel */
01292 l_int32    vinr, ving, vinb;  /* contrib from all full interior src pixels */
01293 l_int32    vmidr, vmidg, vmidb;  /* contrib from side parts */
01294 l_int32    rval, gval, bval;
01295 l_uint32   pixel00, pixel10, pixel01, pixel11, pixel;
01296 l_uint32  *lines, *lined;
01297 l_float32  scx, scy;
01298 
01299         /* (scx, scy) are scaling factors that are applied to the
01300          * dest coords to get the corresponding src coords.
01301          * We need them because we iterate over dest pixels
01302          * and must find the corresponding set of src pixels. */
01303     scx = 16. * (l_float32)ws / (l_float32)wd;
01304     scy = 16. * (l_float32)hs / (l_float32)hd;
01305 
01306     wm2 = ws - 2;
01307     hm2 = hs - 2;
01308 
01309         /* Iterate over the destination pixels */
01310     for (i = 0; i < hd; i++) {
01311         yu = (l_int32)(scy * i);
01312         yl = (l_int32)(scy * (i + 1.0));
01313         yup = yu >> 4;
01314         yuf = yu & 0x0f;
01315         ylp = yl >> 4;
01316         ylf = yl & 0x0f;
01317         dely = ylp - yup;
01318         lined = datad + i * wpld;
01319         lines = datas + yup * wpls;
01320         for (j = 0; j < wd; j++) {
01321             xu = (l_int32)(scx * j);
01322             xl = (l_int32)(scx * (j + 1.0));
01323             xup = xu >> 4;
01324             xuf = xu & 0x0f;
01325             xlp = xl >> 4;
01326             xlf = xl & 0x0f;
01327             delx = xlp - xup;
01328 
01329                 /* If near the edge, just use a src pixel value */
01330             if (xlp > wm2 || ylp > hm2) {
01331                 *(lined + j) = *(lines + xup);
01332                 continue;
01333             }
01334 
01335                 /* Area summed over, in subpixels.  This varies
01336                  * due to the quantization, so we can't simply take
01337                  * the area to be a constant: area = scx * scy. */
01338             area = ((16 - xuf) + 16 * (delx - 1) + xlf) *
01339                    ((16 - yuf) + 16 * (dely - 1) + ylf);
01340 
01341                 /* Do area map summation */
01342             pixel00 = *(lines + xup);
01343             pixel10 = *(lines + xlp);
01344             pixel01 = *(lines + dely * wpls +  xup);
01345             pixel11 = *(lines + dely * wpls +  xlp);
01346             area00 = (16 - xuf) * (16 - yuf);
01347             area10 = xlf * (16 - yuf);
01348             area01 = (16 - xuf) * ylf;
01349             area11 = xlf * ylf;
01350             v00r = area00 * ((pixel00 >> L_RED_SHIFT) & 0xff);
01351             v00g = area00 * ((pixel00 >> L_GREEN_SHIFT) & 0xff);
01352             v00b = area00 * ((pixel00 >> L_BLUE_SHIFT) & 0xff);
01353             v10r = area10 * ((pixel10 >> L_RED_SHIFT) & 0xff);
01354             v10g = area10 * ((pixel10 >> L_GREEN_SHIFT) & 0xff);
01355             v10b = area10 * ((pixel10 >> L_BLUE_SHIFT) & 0xff);
01356             v01r = area01 * ((pixel01 >> L_RED_SHIFT) & 0xff);
01357             v01g = area01 * ((pixel01 >> L_GREEN_SHIFT) & 0xff);
01358             v01b = area01 * ((pixel01 >> L_BLUE_SHIFT) & 0xff);
01359             v11r = area11 * ((pixel11 >> L_RED_SHIFT) & 0xff);
01360             v11g = area11 * ((pixel11 >> L_GREEN_SHIFT) & 0xff);
01361             v11b = area11 * ((pixel11 >> L_BLUE_SHIFT) & 0xff);
01362             vinr = ving = vinb = 0;
01363             for (k = 1; k < dely; k++) {  /* for full src pixels */
01364                 for (m = 1; m < delx; m++) {
01365                     pixel = *(lines + k * wpls + xup + m);
01366                     vinr += 256 * ((pixel >> L_RED_SHIFT) & 0xff);
01367                     ving += 256 * ((pixel >> L_GREEN_SHIFT) & 0xff);
01368                     vinb += 256 * ((pixel >> L_BLUE_SHIFT) & 0xff);
01369                 }
01370             }
01371             vmidr = vmidg = vmidb = 0;
01372             areal = (16 - xuf) * 16;
01373             arear = xlf * 16;
01374             areat = 16 * (16 - yuf);
01375             areab = 16 * ylf;
01376             for (k = 1; k < dely; k++) {  /* for left side */
01377                 pixel = *(lines + k * wpls + xup);
01378                 vmidr += areal * ((pixel >> L_RED_SHIFT) & 0xff);
01379                 vmidg += areal * ((pixel >> L_GREEN_SHIFT) & 0xff);
01380                 vmidb += areal * ((pixel >> L_BLUE_SHIFT) & 0xff);
01381             }
01382             for (k = 1; k < dely; k++) {  /* for right side */
01383                 pixel = *(lines + k * wpls + xlp);
01384                 vmidr += arear * ((pixel >> L_RED_SHIFT) & 0xff);
01385                 vmidg += arear * ((pixel >> L_GREEN_SHIFT) & 0xff);
01386                 vmidb += arear * ((pixel >> L_BLUE_SHIFT) & 0xff);
01387             }
01388             for (m = 1; m < delx; m++) {  /* for top side */
01389                 pixel = *(lines + xup + m);
01390                 vmidr += areat * ((pixel >> L_RED_SHIFT) & 0xff);
01391                 vmidg += areat * ((pixel >> L_GREEN_SHIFT) & 0xff);
01392                 vmidb += areat * ((pixel >> L_BLUE_SHIFT) & 0xff);
01393             }
01394             for (m = 1; m < delx; m++) {  /* for bottom side */
01395                 pixel = *(lines + dely * wpls + xup + m);
01396                 vmidr += areab * ((pixel >> L_RED_SHIFT) & 0xff);
01397                 vmidg += areab * ((pixel >> L_GREEN_SHIFT) & 0xff);
01398                 vmidb += areab * ((pixel >> L_BLUE_SHIFT) & 0xff);
01399             }
01400 
01401                 /* Sum all the contributions */
01402             rval = (v00r + v01r + v10r + v11r + vinr + vmidr + 128) / area;
01403             gval = (v00g + v01g + v10g + v11g + ving + vmidg + 128) / area;
01404             bval = (v00b + v01b + v10b + v11b + vinb + vmidb + 128) / area;
01405 #if  DEBUG_OVERFLOW
01406             if (rval > 255) fprintf(stderr, "rval ovfl: %d\n", rval);
01407             if (rval > 255) fprintf(stderr, "gval ovfl: %d\n", gval);
01408             if (rval > 255) fprintf(stderr, "bval ovfl: %d\n", bval);
01409 #endif  /* DEBUG_OVERFLOW */
01410             composeRGBPixel(rval, gval, bval, lined + j);
01411         }
01412     }
01413 
01414     return;
01415 }
01416 
01417 
01418 /*!
01419  *  scaleGrayAreaMapLow()
01420  *
01421  *  This should only be used for downscaling.
01422  *  We choose to divide each pixel into 16 x 16 sub-pixels.
01423  *  This is about 2x slower than scaleSmoothLow(), but the results
01424  *  are significantly better on small text, esp. for downscaling
01425  *  factors between 1.5 and 5.  All src pixels are subdivided
01426  *  into 256 sub-pixels, and are weighted by the number of
01427  *  sub-pixels covered by the dest pixel.
01428  */
01429 void
01430 scaleGrayAreaMapLow(l_uint32  *datad,
01431                     l_int32    wd,
01432                     l_int32    hd,
01433                     l_int32    wpld,
01434                     l_uint32  *datas,
01435                     l_int32    ws,
01436                     l_int32    hs,
01437                     l_int32    wpls)
01438 {
01439 l_int32    i, j, k, m, wm2, hm2;
01440 l_int32    xu, yu;  /* UL corner in src image, to 1/16 of a pixel */
01441 l_int32    xl, yl;  /* LR corner in src image, to 1/16 of a pixel */
01442 l_int32    xup, yup, xuf, yuf;  /* UL src pixel: integer and fraction */
01443 l_int32    xlp, ylp, xlf, ylf;  /* LR src pixel: integer and fraction */
01444 l_int32    delx, dely, area;
01445 l_int32    v00;  /* contrib. from UL src pixel */
01446 l_int32    v01;  /* contrib. from LL src pixel */
01447 l_int32    v10;  /* contrib from UR src pixel */
01448 l_int32    v11;  /* contrib from LR src pixel */
01449 l_int32    vin;  /* contrib from all full interior src pixels */
01450 l_int32    vmid;  /* contrib from side parts that are full in 1 direction */
01451 l_int32    val;
01452 l_uint32  *lines, *lined;
01453 l_float32  scx, scy;
01454 
01455         /* (scx, scy) are scaling factors that are applied to the
01456          * dest coords to get the corresponding src coords.
01457          * We need them because we iterate over dest pixels
01458          * and must find the corresponding set of src pixels. */
01459     scx = 16. * (l_float32)ws / (l_float32)wd;
01460     scy = 16. * (l_float32)hs / (l_float32)hd;
01461 
01462     wm2 = ws - 2;
01463     hm2 = hs - 2;
01464 
01465         /* Iterate over the destination pixels */
01466     for (i = 0; i < hd; i++) {
01467         yu = (l_int32)(scy * i);
01468         yl = (l_int32)(scy * (i + 1.0));
01469         yup = yu >> 4;
01470         yuf = yu & 0x0f;
01471         ylp = yl >> 4;
01472         ylf = yl & 0x0f;
01473         dely = ylp - yup;
01474         lined = datad + i * wpld;
01475         lines = datas + yup * wpls;
01476         for (j = 0; j < wd; j++) {
01477             xu = (l_int32)(scx * j);
01478             xl = (l_int32)(scx * (j + 1.0));
01479             xup = xu >> 4;
01480             xuf = xu & 0x0f;
01481             xlp = xl >> 4;
01482             xlf = xl & 0x0f;
01483             delx = xlp - xup;
01484 
01485                 /* If near the edge, just use a src pixel value */
01486             if (xlp > wm2 || ylp > hm2) {
01487                 SET_DATA_BYTE(lined, j, GET_DATA_BYTE(lines, xup));
01488                 continue;
01489             }
01490 
01491                 /* Area summed over, in subpixels.  This varies
01492                  * due to the quantization, so we can't simply take
01493                  * the area to be a constant: area = scx * scy. */
01494             area = ((16 - xuf) + 16 * (delx - 1) + xlf) *
01495                    ((16 - yuf) + 16 * (dely - 1) + ylf);
01496 
01497                 /* Do area map summation */
01498             v00 = (16 - xuf) * (16 - yuf) * GET_DATA_BYTE(lines, xup);
01499             v10 = xlf * (16 - yuf) * GET_DATA_BYTE(lines, xlp);
01500             v01 = (16 - xuf) * ylf * GET_DATA_BYTE(lines + dely * wpls, xup);
01501             v11 = xlf * ylf * GET_DATA_BYTE(lines + dely * wpls, xlp);
01502             for (vin = 0, k = 1; k < dely; k++) {  /* for full src pixels */
01503                  for (m = 1; m < delx; m++) {
01504                      vin += 256 * GET_DATA_BYTE(lines + k * wpls, xup + m);
01505                  }
01506             }
01507             for (vmid = 0, k = 1; k < dely; k++)  /* for left side */
01508                 vmid += (16 - xuf) * 16 * GET_DATA_BYTE(lines + k * wpls, xup);
01509             for (k = 1; k < dely; k++)  /* for right side */
01510                 vmid += xlf * 16 * GET_DATA_BYTE(lines + k * wpls, xlp);
01511             for (m = 1; m < delx; m++)  /* for top side */
01512                 vmid += 16 * (16 - yuf) * GET_DATA_BYTE(lines, xup + m);
01513             for (m = 1; m < delx; m++)  /* for bottom side */
01514                 vmid += 16 * ylf * GET_DATA_BYTE(lines + dely * wpls, xup + m);
01515             val = (v00 + v01 + v10 + v11 + vin + vmid + 128) / area;
01516 #if  DEBUG_OVERFLOW
01517             if (val > 255) fprintf(stderr, "val overflow: %d\n", val);
01518 #endif  /* DEBUG_OVERFLOW */
01519             SET_DATA_BYTE(lined, j, val);
01520         }
01521     }
01522 
01523     return;
01524 }
01525 
01526 
01527 /*------------------------------------------------------------------*
01528  *                     2x area mapped downscaling                   *
01529  *------------------------------------------------------------------*/
01530 /*!
01531  *  scaleAreaMapLow2()
01532  *
01533  *  Note: This function is called with either 8 bpp gray or 32 bpp RGB.
01534  *        The result is a 2x reduced dest.
01535  */
01536 void
01537 scaleAreaMapLow2(l_uint32  *datad,
01538                  l_int32    wd,
01539                  l_int32    hd,
01540                  l_int32    wpld,
01541                  l_uint32  *datas,
01542                  l_int32    d,
01543                  l_int32    wpls)
01544 {
01545 l_int32    i, j, val, rval, gval, bval;
01546 l_uint32  *lines, *lined;
01547 l_uint32   pixel;
01548 
01549     if (d == 8) {
01550         for (i = 0; i < hd; i++) {
01551             lines = datas + 2 * i * wpls;
01552             lined = datad + i * wpld;
01553             for (j = 0; j < wd; j++) {
01554                     /* Average each dest pixel using 4 src pixels */
01555                 val = GET_DATA_BYTE(lines, 2 * j);
01556                 val += GET_DATA_BYTE(lines, 2 * j + 1);
01557                 val += GET_DATA_BYTE(lines + wpls, 2 * j);
01558                 val += GET_DATA_BYTE(lines + wpls, 2 * j + 1);
01559                 val >>= 2;
01560                 SET_DATA_BYTE(lined, j, val);
01561             }
01562         }
01563     }
01564     else {  /* d == 32 */
01565         for (i = 0; i < hd; i++) {
01566             lines = datas + 2 * i * wpls;
01567             lined = datad + i * wpld;
01568             for (j = 0; j < wd; j++) {
01569                     /* Average each of the color components from 4 src pixels */
01570                 pixel = *(lines + 2 * j);
01571                 rval = (pixel >> L_RED_SHIFT) & 0xff;
01572                 gval = (pixel >> L_GREEN_SHIFT) & 0xff;
01573                 bval = (pixel >> L_BLUE_SHIFT) & 0xff;
01574                 pixel = *(lines + 2 * j + 1);
01575                 rval += (pixel >> L_RED_SHIFT) & 0xff;
01576                 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
01577                 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
01578                 pixel = *(lines + wpls + 2 * j);
01579                 rval += (pixel >> L_RED_SHIFT) & 0xff;
01580                 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
01581                 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
01582                 pixel = *(lines + wpls + 2 * j + 1);
01583                 rval += (pixel >> L_RED_SHIFT) & 0xff;
01584                 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
01585                 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
01586                 composeRGBPixel(rval >> 2, gval >> 2, bval >> 2, &pixel);
01587                 *(lined + j) = pixel;
01588             }
01589         }
01590     }
01591     return;
01592 }
01593 
01594 
01595 /*------------------------------------------------------------------*
01596  *              Binary scaling by closest pixel sampling            *
01597  *------------------------------------------------------------------*/
01598 /*
01599  *  scaleBinaryLow()
01600  *
01601  *  Notes:
01602  *      (1) The dest must be cleared prior to this operation,
01603  *          and we clear it here in the low-level code.
01604  *      (2) We reuse dest pixels and dest pixel rows whenever
01605  *          possible for upscaling; downscaling is done by
01606  *          strict subsampling.
01607  */
01608 l_int32
01609 scaleBinaryLow(l_uint32  *datad,
01610                l_int32    wd,
01611                l_int32    hd,
01612                l_int32    wpld,
01613                l_uint32  *datas,
01614                l_int32    ws,
01615                l_int32    hs,
01616                l_int32    wpls)
01617 {
01618 l_int32    i, j, bpld;
01619 l_int32    xs, prevxs, sval;
01620 l_int32   *srow, *scol;
01621 l_uint32  *lines, *prevlines, *lined, *prevlined;
01622 l_float32  wratio, hratio;
01623 
01624     PROCNAME("scaleBinaryLow");
01625 
01626         /* clear dest */
01627     bpld = 4 * wpld;
01628     memset((char *)datad, 0, hd * bpld);
01629     
01630         /* The source row corresponding to dest row i ==> srow[i]
01631          * The source col corresponding to dest col j ==> scol[j]  */
01632     if ((srow = (l_int32 *)CALLOC(hd, sizeof(l_int32))) == NULL)
01633         return ERROR_INT("srow not made", procName, 1);
01634     if ((scol = (l_int32 *)CALLOC(wd, sizeof(l_int32))) == NULL)
01635         return ERROR_INT("scol not made", procName, 1);
01636 
01637     wratio = (l_float32)ws / (l_float32)wd;
01638     hratio = (l_float32)hs / (l_float32)hd;
01639     for (i = 0; i < hd; i++)
01640         srow[i] = L_MIN((l_int32)(hratio * i + 0.5), hs - 1);
01641     for (j = 0; j < wd; j++)
01642         scol[j] = L_MIN((l_int32)(wratio * j + 0.5), ws - 1);
01643 
01644     prevlines = NULL;
01645     prevxs = -1;
01646     sval = 0;
01647     for (i = 0; i < hd; i++) {
01648         lines = datas + srow[i] * wpls;
01649         lined = datad + i * wpld;
01650         if (lines != prevlines) {  /* make dest from new source row */
01651             for (j = 0; j < wd; j++) {
01652                 xs = scol[j];
01653                 if (xs != prevxs) {  /* get dest pix from source col */
01654                     if ((sval = GET_DATA_BIT(lines, xs)))
01655                         SET_DATA_BIT(lined, j);
01656                     prevxs = xs;
01657                 }
01658                 else {  /* copy prev dest pix, if set */
01659                     if (sval)
01660                         SET_DATA_BIT(lined, j);
01661                 }
01662             }
01663         }
01664         else {  /* lines == prevlines; copy prev dest row */
01665             prevlined = lined - wpld;
01666             memcpy((char *)lined, (char *)prevlined, bpld);
01667         }
01668         prevlines = lines;
01669     }
01670 
01671     FREE(srow);
01672     FREE(scol);
01673 
01674     return 0;
01675 }
01676 
01677 
01678 /*------------------------------------------------------------------*
01679  *                         Scale-to-gray 2x                         *
01680  *------------------------------------------------------------------*/
01681 /*!
01682  *  scaleToGray2Low()
01683  *
01684  *      Input:  usual image variables
01685  *              sumtab  (made from makeSumTabSG2())
01686  *              valtab  (made from makeValTabSG2())
01687  *      Return: 0 if OK; 1 on error.
01688  *
01689  *  The output is processed in sets of 4 output bytes on a row,
01690  *  corresponding to 4 2x2 bit-blocks in the input image.
01691  *  Two lookup tables are used.  The first, sumtab, gets the
01692  *  sum of ON pixels in 4 sets of two adjacent bits,
01693  *  storing the result in 4 adjacent bytes.  After sums from
01694  *  two rows have been added, the second table, valtab,
01695  *  converts from the sum of ON pixels in the 2x2 block to
01696  *  an 8 bpp grayscale value between 0 (for 4 bits ON)
01697  *  and 255 (for 0 bits ON).
01698  */
01699 void
01700 scaleToGray2Low(l_uint32  *datad,
01701                 l_int32    wd,
01702                 l_int32    hd,
01703                 l_int32    wpld,
01704                 l_uint32  *datas,
01705                 l_int32    wpls,
01706                 l_uint32  *sumtab,
01707                 l_uint8   *valtab)
01708 {
01709 l_int32    i, j, l, k, m, wd4, extra;
01710 l_uint32   sbyte1, sbyte2, sum;
01711 l_uint32  *lines, *lined;
01712 
01713         /* i indexes the dest lines
01714          * l indexes the source lines
01715          * j indexes the dest bytes
01716          * k indexes the source bytes
01717          * We take two bytes from the source (in 2 lines of 8 pixels
01718          * each) and convert them into four 8 bpp bytes of the dest. */
01719     wd4 = wd & 0xfffffffc;
01720     extra = wd - wd4;
01721     for (i = 0, l = 0; i < hd; i++, l += 2) {
01722         lines = datas + l * wpls;
01723         lined = datad + i * wpld; 
01724         for (j = 0, k = 0; j < wd4; j += 4, k++) {
01725             sbyte1 = GET_DATA_BYTE(lines, k);
01726             sbyte2 = GET_DATA_BYTE(lines + wpls, k);
01727             sum = sumtab[sbyte1] + sumtab[sbyte2];
01728             SET_DATA_BYTE(lined, j, valtab[sum >> 24]);
01729             SET_DATA_BYTE(lined, j + 1, valtab[(sum >> 16) & 0xff]);
01730             SET_DATA_BYTE(lined, j + 2, valtab[(sum >> 8) & 0xff]);
01731             SET_DATA_BYTE(lined, j + 3, valtab[sum & 0xff]);
01732         }
01733         if (extra > 0) {
01734             sbyte1 = GET_DATA_BYTE(lines, k);
01735             sbyte2 = GET_DATA_BYTE(lines + wpls, k);
01736             sum = sumtab[sbyte1] + sumtab[sbyte2];
01737             for (m = 0; m < extra; m++) {
01738                 SET_DATA_BYTE(lined, j + m,
01739                               valtab[((sum >> (24 - 8 * m)) & 0xff)]);
01740             }
01741         }
01742         
01743     }
01744 
01745     return;
01746 }
01747 
01748 
01749 /*!
01750  *  makeSumTabSG2()
01751  *         
01752  *  Returns a table of 256 l_uint32s, giving the four output
01753  *  8-bit grayscale sums corresponding to 8 input bits of a binary
01754  *  image, for a 2x scale-to-gray op.  The sums from two
01755  *  adjacent scanlines are then added and transformed to
01756  *  output four 8 bpp pixel values, using makeValTabSG2().
01757  */
01758 l_uint32  *
01759 makeSumTabSG2(void)
01760 {
01761 l_int32    i;
01762 l_int32    sum[] = {0, 1, 1, 2};
01763 l_uint32  *tab;
01764 
01765     PROCNAME("makeSumTabSG2");
01766 
01767     if ((tab = (l_uint32 *)CALLOC(256, sizeof(l_uint32))) == NULL)
01768         return (l_uint32 *)ERROR_PTR("calloc fail for tab", procName, NULL);
01769 
01770         /* Pack the four sums separately in four bytes */
01771     for (i = 0; i < 256; i++) {
01772         tab[i] = (sum[i & 0x3] | sum[(i >> 2) & 0x3] << 8 |
01773                   sum[(i >> 4) & 0x3] << 16 | sum[(i >> 6) & 0x3] << 24);
01774     }
01775 
01776     return tab;
01777 }
01778 
01779 
01780 /*!
01781  *  makeValTabSG2()
01782  *         
01783  *  Returns an 8 bit value for the sum of ON pixels
01784  *  in a 2x2 square, according to
01785  *
01786  *         val = 255 - (255 * sum)/4
01787  *
01788  *  where sum is in set {0,1,2,3,4}
01789  */
01790 l_uint8 *
01791 makeValTabSG2(void)
01792 {
01793 l_int32   i;
01794 l_uint8  *tab;
01795 
01796     PROCNAME("makeValTabSG2");
01797 
01798     if ((tab = (l_uint8 *)CALLOC(5, sizeof(l_uint8))) == NULL)
01799         return (l_uint8 *)ERROR_PTR("calloc fail for tab", procName, NULL);
01800 
01801     for (i = 0; i < 5; i++)
01802         tab[i] = 255 - (i * 255) / 4;
01803 
01804     return tab;
01805 }
01806 
01807 
01808 /*------------------------------------------------------------------*
01809  *                         Scale-to-gray 3x                         *
01810  *------------------------------------------------------------------*/
01811 /*!
01812  *  scaleToGray3Low()
01813  *
01814  *      Input:  usual image variables
01815  *              sumtab  (made from makeSumTabSG3())
01816  *              valtab  (made from makeValTabSG3())
01817  *      Return: 0 if OK; 1 on error
01818  *
01819  *  Each set of 8 3x3 bit-blocks in the source image, which
01820  *  consist of 72 pixels arranged 24 pixels wide by 3 scanlines,
01821  *  is converted to a row of 8 8-bit pixels in the dest image.
01822  *  These 72 pixels of the input image are runs of 24 pixels
01823  *  in three adjacent scanlines.  Each run of 24 pixels is
01824  *  stored in the 24 LSbits of a 32-bit word.  We use 2 LUTs.
01825  *  The first, sumtab, takes 6 of these bits and stores
01826  *  sum, taken 3 bits at a time, in two bytes.  (See
01827  *  makeSumTabSG3).  This is done for each of the 3 scanlines,
01828  *  and the results are added.  We now have the sum of ON pixels
01829  *  in the first two 3x3 blocks in two bytes.  The valtab LUT
01830  *  then converts these values (which go from 0 to 9) to
01831  *  grayscale values between between 255 and 0.  (See makeValTabSG3).
01832  *  This process is repeated for each of the other 3 sets of
01833  *  6x3 input pixels, giving 8 output pixels in total.
01834  *
01835  *  Note: because the input image is processed in groups of
01836  *        24 x 3 pixels, the process clips the input height to
01837  *        (h - h % 3) and the input width to (w - w % 24).
01838  */
01839 void
01840 scaleToGray3Low(l_uint32  *datad,
01841                 l_int32    wd,
01842                 l_int32    hd,
01843                 l_int32    wpld,
01844                 l_uint32  *datas,
01845                 l_int32    wpls,
01846                 l_uint32  *sumtab,
01847                 l_uint8   *valtab)
01848 {
01849 l_int32    i, j, l, k;
01850 l_uint32   threebytes1, threebytes2, threebytes3, sum;
01851 l_uint32  *lines, *lined;
01852 
01853         /* i indexes the dest lines
01854          * l indexes the source lines
01855          * j indexes the dest bytes
01856          * k indexes the source bytes
01857          * We take 9 bytes from the source (72 binary pixels
01858          * in three lines of 24 pixels each) and convert it
01859          * into 8 bytes of the dest (8 8bpp pixels in one line)   */
01860     for (i = 0, l = 0; i < hd; i++, l += 3) {
01861         lines = datas + l * wpls;
01862         lined = datad + i * wpld; 
01863         for (j = 0, k = 0; j < wd; j += 8, k += 3) {
01864             threebytes1 = (GET_DATA_BYTE(lines, k) << 16) |
01865                           (GET_DATA_BYTE(lines, k + 1) << 8) |
01866                           GET_DATA_BYTE(lines, k + 2);
01867             threebytes2 = (GET_DATA_BYTE(lines + wpls, k) << 16) |
01868                           (GET_DATA_BYTE(lines + wpls, k + 1) << 8) |
01869                           GET_DATA_BYTE(lines + wpls, k + 2);
01870             threebytes3 = (GET_DATA_BYTE(lines + 2 * wpls, k) << 16) |
01871                           (GET_DATA_BYTE(lines + 2 * wpls, k + 1) << 8) |
01872                           GET_DATA_BYTE(lines + 2 * wpls, k + 2);
01873 
01874             sum = sumtab[(threebytes1 >> 18)] +
01875                   sumtab[(threebytes2 >> 18)] +
01876                   sumtab[(threebytes3 >> 18)];
01877             SET_DATA_BYTE(lined, j, valtab[GET_DATA_BYTE(&sum, 2)]);
01878             SET_DATA_BYTE(lined, j + 1, valtab[GET_DATA_BYTE(&sum, 3)]);
01879 
01880             sum = sumtab[((threebytes1 >> 12) & 0x3f)] +
01881                   sumtab[((threebytes2 >> 12) & 0x3f)] +
01882                   sumtab[((threebytes3 >> 12) & 0x3f)];
01883             SET_DATA_BYTE(lined, j + 2, valtab[GET_DATA_BYTE(&sum, 2)]);
01884             SET_DATA_BYTE(lined, j + 3, valtab[GET_DATA_BYTE(&sum, 3)]);
01885 
01886             sum = sumtab[((threebytes1 >> 6) & 0x3f)] +
01887                   sumtab[((threebytes2 >> 6) & 0x3f)] +
01888                   sumtab[((threebytes3 >> 6) & 0x3f)];
01889             SET_DATA_BYTE(lined, j + 4, valtab[GET_DATA_BYTE(&sum, 2)]);
01890             SET_DATA_BYTE(lined, j + 5, valtab[GET_DATA_BYTE(&sum, 3)]);
01891 
01892             sum = sumtab[(threebytes1 & 0x3f)] +
01893                   sumtab[(threebytes2 & 0x3f)] +
01894                   sumtab[(threebytes3 & 0x3f)];
01895             SET_DATA_BYTE(lined, j + 6, valtab[GET_DATA_BYTE(&sum, 2)]);
01896             SET_DATA_BYTE(lined, j + 7, valtab[GET_DATA_BYTE(&sum, 3)]);
01897         }
01898     }
01899 
01900     return;
01901 }
01902 
01903 
01904 
01905 /*!
01906  *  makeSumTabSG3()
01907  *         
01908  *  Returns a table of 64 l_uint32s, giving the two output
01909  *  8-bit grayscale sums corresponding to 6 input bits of a binary
01910  *  image, for a 3x scale-to-gray op.  In practice, this would
01911  *  be used three times (on adjacent scanlines), and the sums would
01912  *  be added and then transformed to output 8 bpp pixel values,
01913  *  using makeValTabSG3().
01914  */
01915 l_uint32  *
01916 makeSumTabSG3(void)
01917 {
01918 l_int32    i;
01919 l_int32    sum[] = {0, 1, 1, 2, 1, 2, 2, 3};
01920 l_uint32  *tab;
01921 
01922     PROCNAME("makeSumTabSG3");
01923 
01924     if ((tab = (l_uint32 *)CALLOC(64, sizeof(l_uint32))) == NULL)
01925         return (l_uint32 *)ERROR_PTR("calloc fail for tab", procName, NULL);
01926 
01927         /* Pack the two sums separately in two bytes */
01928     for (i = 0; i < 64; i++) {
01929         tab[i] = (sum[i & 0x07]) | (sum[(i >> 3) & 0x07] << 8);
01930     }
01931 
01932     return tab;
01933 }
01934 
01935 
01936 /*!
01937  *  makeValTabSG3()
01938  *         
01939  *  Returns an 8 bit value for the sum of ON pixels
01940  *  in a 3x3 square, according to
01941  *      val = 255 - (255 * sum)/9
01942  *  where sum is in set {0, ... ,9}
01943  */
01944 l_uint8 *
01945 makeValTabSG3(void)
01946 {
01947 l_int32   i;
01948 l_uint8  *tab;
01949 
01950     PROCNAME("makeValTabSG3");
01951 
01952     if ((tab = (l_uint8 *)CALLOC(10, sizeof(l_uint8))) == NULL)
01953         return (l_uint8 *)ERROR_PTR("calloc fail for tab", procName, NULL);
01954 
01955     for (i = 0; i < 10; i++)
01956         tab[i] = 0xff - (i * 255) / 9;
01957 
01958     return tab;
01959 }
01960 
01961 
01962 /*------------------------------------------------------------------*
01963  *                         Scale-to-gray 4x                         *
01964  *------------------------------------------------------------------*/
01965 /*!
01966  *  scaleToGray4Low()
01967  *
01968  *      Input:  usual image variables
01969  *              sumtab  (made from makeSumTabSG4())
01970  *              valtab  (made from makeValTabSG4())
01971  *      Return: 0 if OK; 1 on error.
01972  *
01973  *  The output is processed in sets of 2 output bytes on a row,
01974  *  corresponding to 2 4x4 bit-blocks in the input image.
01975  *  Two lookup tables are used.  The first, sumtab, gets the
01976  *  sum of ON pixels in two sets of four adjacent bits,
01977  *  storing the result in 2 adjacent bytes.  After sums from
01978  *  four rows have been added, the second table, valtab,
01979  *  converts from the sum of ON pixels in the 4x4 block to
01980  *  an 8 bpp grayscale value between 0 (for 16 bits ON)
01981  *  and 255 (for 0 bits ON).
01982  */
01983 void
01984 scaleToGray4Low(l_uint32  *datad,
01985                 l_int32    wd,
01986                 l_int32    hd,
01987                 l_int32    wpld,
01988                 l_uint32  *datas,
01989                 l_int32    wpls,
01990                 l_uint32  *sumtab,
01991                 l_uint8   *valtab)
01992 {
01993 l_int32    i, j, l, k;
01994 l_uint32   sbyte1, sbyte2, sbyte3, sbyte4, sum;
01995 l_uint32  *lines, *lined;
01996 
01997         /* i indexes the dest lines
01998          * l indexes the source lines
01999          * j indexes the dest bytes
02000          * k indexes the source bytes
02001          * We take four bytes from the source (in 4 lines of 8 pixels
02002          * each) and convert it into two 8 bpp bytes of the dest. */
02003     for (i = 0, l = 0; i < hd; i++, l += 4) {
02004         lines = datas + l * wpls;
02005         lined = datad + i * wpld; 
02006         for (j = 0, k = 0; j < wd; j += 2, k++) {
02007             sbyte1 = GET_DATA_BYTE(lines, k);
02008             sbyte2 = GET_DATA_BYTE(lines + wpls, k);
02009             sbyte3 = GET_DATA_BYTE(lines + 2 * wpls, k);
02010             sbyte4 = GET_DATA_BYTE(lines + 3 * wpls, k);
02011             sum = sumtab[sbyte1] + sumtab[sbyte2] +
02012                   sumtab[sbyte3] + sumtab[sbyte4];
02013             SET_DATA_BYTE(lined, j, valtab[GET_DATA_BYTE(&sum, 2)]);
02014             SET_DATA_BYTE(lined, j + 1, valtab[GET_DATA_BYTE(&sum, 3)]);
02015         }
02016     }
02017 
02018     return;
02019 }
02020 
02021 
02022 /*!
02023  *  makeSumTabSG4()
02024  *         
02025  *  Returns a table of 256 l_uint32s, giving the two output
02026  *  8-bit grayscale sums corresponding to 8 input bits of a binary
02027  *  image, for a 4x scale-to-gray op.  The sums from four
02028  *  adjacent scanlines are then added and transformed to
02029  *  output 8 bpp pixel values, using makeValTabSG4().
02030  */
02031 l_uint32  *
02032 makeSumTabSG4(void)
02033 {
02034 l_int32    i;
02035 l_int32    sum[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
02036 l_uint32  *tab;
02037 
02038     PROCNAME("makeSumTabSG4");
02039 
02040     if ((tab = (l_uint32 *)CALLOC(256, sizeof(l_uint32))) == NULL)
02041         return (l_uint32 *)ERROR_PTR("calloc fail for tab", procName, NULL);
02042 
02043         /* Pack the two sums separately in two bytes */
02044     for (i = 0; i < 256; i++) {
02045         tab[i] = (sum[i & 0xf]) | (sum[(i >> 4) & 0xf] << 8);
02046     }
02047 
02048     return tab;
02049 }
02050 
02051 
02052 /*!
02053  *  makeValTabSG4()
02054  *         
02055  *  Returns an 8 bit value for the sum of ON pixels
02056  *  in a 4x4 square, according to
02057  *
02058  *         val = 255 - (255 * sum)/16
02059  *
02060  *  where sum is in set {0, ... ,16}
02061  */
02062 l_uint8 *
02063 makeValTabSG4(void)
02064 {
02065 l_int32   i;
02066 l_uint8  *tab;
02067 
02068     PROCNAME("makeValTabSG4");
02069 
02070     if ((tab = (l_uint8 *)CALLOC(17, sizeof(l_uint8))) == NULL)
02071         return (l_uint8 *)ERROR_PTR("calloc fail for tab", procName, NULL);
02072 
02073     for (i = 0; i < 17; i++)
02074         tab[i] = 0xff - (i * 255) / 16;
02075 
02076     return tab;
02077 }
02078 
02079 
02080 /*------------------------------------------------------------------*
02081  *                         Scale-to-gray 6x                         *
02082  *------------------------------------------------------------------*/
02083 /*!
02084  *  scaleToGray6Low()
02085  *
02086  *      Input:  usual image variables
02087  *              tab8  (made from makePixelSumTab8())
02088  *              valtab  (made from makeValTabSG6())
02089  *      Return: 0 if OK; 1 on error
02090  *
02091  *  Each set of 4 6x6 bit-blocks in the source image, which
02092  *  consist of 144 pixels arranged 24 pixels wide by 6 scanlines,
02093  *  is converted to a row of 4 8-bit pixels in the dest image.
02094  *  These 144 pixels of the input image are runs of 24 pixels
02095  *  in six adjacent scanlines.  Each run of 24 pixels is
02096  *  stored in the 24 LSbits of a 32-bit word.  We use 2 LUTs.
02097  *  The first, tab8, takes 6 of these bits and stores
02098  *  sum in one byte.  This is done for each of the 6 scanlines,
02099  *  and the results are added.
02100  *  We now have the sum of ON pixels in the first 6x6 block.  The
02101  *  valtab LUT then converts these values (which go from 0 to 36) to
02102  *  grayscale values between between 255 and 0.  (See makeValTabSG6).
02103  *  This process is repeated for each of the other 3 sets of
02104  *  6x6 input pixels, giving 4 output pixels in total.
02105  *
02106  *  Note: because the input image is processed in groups of
02107  *        24 x 6 pixels, the process clips the input height to
02108  *        (h - h % 6) and the input width to (w - w % 24).
02109  *
02110  */
02111 void
02112 scaleToGray6Low(l_uint32  *datad,
02113                 l_int32    wd,
02114                 l_int32    hd,
02115                 l_int32    wpld,
02116                 l_uint32  *datas,
02117                 l_int32    wpls,
02118                 l_int32   *tab8,
02119                 l_uint8   *valtab)
02120 {
02121 l_int32    i, j, l, k;
02122 l_uint32   threebytes1, threebytes2, threebytes3;
02123 l_uint32   threebytes4, threebytes5, threebytes6, sum;
02124 l_uint32  *lines, *lined;
02125 
02126         /* i indexes the dest lines
02127          * l indexes the source lines
02128          * j indexes the dest bytes
02129          * k indexes the source bytes
02130          * We take 18 bytes from the source (144 binary pixels
02131          * in six lines of 24 pixels each) and convert it
02132          * into 4 bytes of the dest (four 8 bpp pixels in one line)   */
02133     for (i = 0, l = 0; i < hd; i++, l += 6) {
02134         lines = datas + l * wpls;
02135         lined = datad + i * wpld; 
02136         for (j = 0, k = 0; j < wd; j += 4, k += 3) {
02137                 /* First grab the 18 bytes, 3 at a time, and put each set
02138                  * of 3 bytes into the LS bytes of a 32-bit word. */
02139             threebytes1 = (GET_DATA_BYTE(lines, k) << 16) |
02140                           (GET_DATA_BYTE(lines, k + 1) << 8) |
02141                           GET_DATA_BYTE(lines, k + 2);
02142             threebytes2 = (GET_DATA_BYTE(lines + wpls, k) << 16) |
02143                           (GET_DATA_BYTE(lines + wpls, k + 1) << 8) |
02144                           GET_DATA_BYTE(lines + wpls, k + 2);
02145             threebytes3 = (GET_DATA_BYTE(lines + 2 * wpls, k) << 16) |
02146                           (GET_DATA_BYTE(lines + 2 * wpls, k + 1) << 8) |
02147                           GET_DATA_BYTE(lines + 2 * wpls, k + 2);
02148             threebytes4 = (GET_DATA_BYTE(lines + 3 * wpls, k) << 16) |
02149                           (GET_DATA_BYTE(lines + 3 * wpls, k + 1) << 8) |
02150                           GET_DATA_BYTE(lines + 3 * wpls, k + 2);
02151             threebytes5 = (GET_DATA_BYTE(lines + 4 * wpls, k) << 16) |
02152                           (GET_DATA_BYTE(lines + 4 * wpls, k + 1) << 8) |
02153                           GET_DATA_BYTE(lines + 4 * wpls, k + 2);
02154             threebytes6 = (GET_DATA_BYTE(lines + 5 * wpls, k) << 16) |
02155                           (GET_DATA_BYTE(lines + 5 * wpls, k + 1) << 8) |
02156                           GET_DATA_BYTE(lines + 5 * wpls, k + 2);
02157 
02158                 /* Sum first set of 36 bits and convert to 0-255 */
02159             sum = tab8[(threebytes1 >> 18)] +
02160                   tab8[(threebytes2 >> 18)] +
02161                   tab8[(threebytes3 >> 18)] +
02162                   tab8[(threebytes4 >> 18)] +
02163                   tab8[(threebytes5 >> 18)] +
02164                    tab8[(threebytes6 >> 18)];
02165             SET_DATA_BYTE(lined, j, valtab[GET_DATA_BYTE(&sum, 3)]);
02166 
02167                 /* Ditto for second set */
02168             sum = tab8[((threebytes1 >> 12) & 0x3f)] +
02169                   tab8[((threebytes2 >> 12) & 0x3f)] +
02170                   tab8[((threebytes3 >> 12) & 0x3f)] +
02171                   tab8[((threebytes4 >> 12) & 0x3f)] +
02172                   tab8[((threebytes5 >> 12) & 0x3f)] +
02173                   tab8[((threebytes6 >> 12) & 0x3f)];
02174             SET_DATA_BYTE(lined, j + 1, valtab[GET_DATA_BYTE(&sum, 3)]);
02175 
02176             sum = tab8[((threebytes1 >> 6) & 0x3f)] +
02177                   tab8[((threebytes2 >> 6) & 0x3f)] +
02178                   tab8[((threebytes3 >> 6) & 0x3f)] +
02179                   tab8[((threebytes4 >> 6) & 0x3f)] +
02180                   tab8[((threebytes5 >> 6) & 0x3f)] +
02181                   tab8[((threebytes6 >> 6) & 0x3f)];
02182             SET_DATA_BYTE(lined, j + 2, valtab[GET_DATA_BYTE(&sum, 3)]);
02183 
02184             sum = tab8[(threebytes1 & 0x3f)] +
02185                   tab8[(threebytes2 & 0x3f)] +
02186                   tab8[(threebytes3 & 0x3f)] +
02187                   tab8[(threebytes4 & 0x3f)] +
02188                   tab8[(threebytes5 & 0x3f)] +
02189                   tab8[(threebytes6 & 0x3f)];
02190             SET_DATA_BYTE(lined, j + 3, valtab[GET_DATA_BYTE(&sum, 3)]);
02191         }
02192     }
02193 
02194     return;
02195 }
02196 
02197 
02198 /*!
02199  *  makeValTabSG6()
02200  *         
02201  *  Returns an 8 bit value for the sum of ON pixels
02202  *  in a 6x6 square, according to
02203  *      val = 255 - (255 * sum)/36
02204  *  where sum is in set {0, ... ,36}
02205  */
02206 l_uint8 *
02207 makeValTabSG6(void)
02208 {
02209 l_int32   i;
02210 l_uint8  *tab;
02211 
02212     PROCNAME("makeValTabSG6");
02213 
02214     if ((tab = (l_uint8 *)CALLOC(37, sizeof(l_uint8))) == NULL)
02215         return (l_uint8 *)ERROR_PTR("calloc fail for tab", procName, NULL);
02216 
02217     for (i = 0; i < 37; i++)
02218         tab[i] = 0xff - (i * 255) / 36;
02219 
02220     return tab;
02221 }
02222 
02223 
02224 /*------------------------------------------------------------------*
02225  *                         Scale-to-gray 8x                         *
02226  *------------------------------------------------------------------*/
02227 /*!
02228  *  scaleToGray8Low()
02229  *
02230  *      Input:  usual image variables
02231  *              tab8  (made from makePixelSumTab8())
02232  *              valtab  (made from makeValTabSG8())
02233  *      Return: 0 if OK; 1 on error.
02234  *
02235  *  The output is processed one dest byte at a time,
02236  *  corresponding to 8 rows of src bytes in the input image.
02237  *  Two lookup tables are used.  The first, tab8, gets the
02238  *  sum of ON pixels in a byte.  After sums from 8 rows have
02239  *  been added, the second table, valtab, converts from this
02240  *  value (which is between 0 and 64) to an 8 bpp grayscale
02241  *  value between 0 (for all 64 bits ON) and 255 (for 0 bits ON).
02242  */
02243 void
02244 scaleToGray8Low(l_uint32  *datad,
02245                 l_int32    wd,
02246                 l_int32    hd,
02247                 l_int32    wpld,
02248                 l_uint32  *datas,
02249                 l_int32    wpls,
02250                 l_int32   *tab8,
02251                 l_uint8   *valtab)
02252 {
02253 l_int32    i, j, k;
02254 l_int32    sbyte0, sbyte1, sbyte2, sbyte3, sbyte4, sbyte5, sbyte6, sbyte7, sum;
02255 l_uint32  *lines, *lined;
02256 
02257         /* i indexes the dest lines
02258          * k indexes the source lines
02259          * j indexes the src and dest bytes
02260          * We take 8 bytes from the source (in 8 lines of 8 pixels
02261          * each) and convert it into one 8 bpp byte of the dest. */
02262     for (i = 0, k = 0; i < hd; i++, k += 8) {
02263         lines = datas + k * wpls;
02264         lined = datad + i * wpld; 
02265         for (j = 0; j < wd; j++) {
02266             sbyte0 = GET_DATA_BYTE(lines, j);
02267             sbyte1 = GET_DATA_BYTE(lines + wpls, j);
02268             sbyte2 = GET_DATA_BYTE(lines + 2 * wpls, j);
02269             sbyte3 = GET_DATA_BYTE(lines + 3 * wpls, j);
02270             sbyte4 = GET_DATA_BYTE(lines + 4 * wpls, j);
02271             sbyte5 = GET_DATA_BYTE(lines + 5 * wpls, j);
02272             sbyte6 = GET_DATA_BYTE(lines + 6 * wpls, j);
02273             sbyte7 = GET_DATA_BYTE(lines + 7 * wpls, j);
02274             sum = tab8[sbyte0] + tab8[sbyte1] +
02275                   tab8[sbyte2] + tab8[sbyte3] +
02276                   tab8[sbyte4] + tab8[sbyte5] +
02277                   tab8[sbyte6] + tab8[sbyte7];
02278             SET_DATA_BYTE(lined, j, valtab[sum]);
02279         }
02280     }
02281 
02282     return;
02283 }
02284 
02285 
02286 /*!
02287  *  makeValTabSG8()
02288  *         
02289  *  Returns an 8 bit value for the sum of ON pixels
02290  *  in an 8x8 square, according to
02291  *      val = 255 - (255 * sum)/64
02292  *  where sum is in set {0, ... ,64}
02293  */
02294 l_uint8 *
02295 makeValTabSG8(void)
02296 {
02297 l_int32   i;
02298 l_uint8  *tab;
02299 
02300     PROCNAME("makeValTabSG8");
02301 
02302     if ((tab = (l_uint8 *)CALLOC(65, sizeof(l_uint8))) == NULL)
02303         return (l_uint8 *)ERROR_PTR("calloc fail for tab", procName, NULL);
02304 
02305     for (i = 0; i < 65; i++)
02306         tab[i] = 0xff - (i * 255) / 64;
02307 
02308     return tab;
02309 }
02310 
02311 
02312 /*------------------------------------------------------------------*
02313  *                         Scale-to-gray 16x                        *
02314  *------------------------------------------------------------------*/
02315 /*!
02316  *  scaleToGray16Low()
02317  *
02318  *      Input:  usual image variables
02319  *              tab8  (made from makePixelSumTab8())
02320  *      Return: 0 if OK; 1 on error.
02321  *
02322  *  The output is processed one dest byte at a time, corresponding
02323  *  to 16 rows consisting each of 2 src bytes in the input image.
02324  *  This uses one lookup table, tab8, which gives the sum of
02325  *  ON pixels in a byte.  After summing for all ON pixels in the
02326  *  32 src bytes, which is between 0 and 256, this is converted
02327  *  to an 8 bpp grayscale value between 0 (for 255 or 256 bits ON)
02328  *  and 255 (for 0 bits ON).
02329  */
02330 void
02331 scaleToGray16Low(l_uint32  *datad,
02332                   l_int32    wd,
02333                  l_int32    hd,
02334                  l_int32    wpld,
02335                  l_uint32  *datas,
02336                  l_int32    wpls,
02337                  l_int32   *tab8)
02338 {
02339 l_int32    i, j, k, m;
02340 l_int32    sum;
02341 l_uint32  *lines, *lined;
02342 
02343         /* i indexes the dest lines
02344          * k indexes the source lines
02345          * j indexes the dest bytes
02346          * m indexes the src bytes
02347          * We take 32 bytes from the source (in 16 lines of 16 pixels
02348          * each) and convert it into one 8 bpp byte of the dest. */
02349     for (i = 0, k = 0; i < hd; i++, k += 16) {
02350         lines = datas + k * wpls;
02351         lined = datad + i * wpld; 
02352         for (j = 0; j < wd; j++) {
02353             m = 2 * j;
02354             sum = tab8[GET_DATA_BYTE(lines, m)];
02355             sum += tab8[GET_DATA_BYTE(lines, m + 1)];
02356             sum += tab8[GET_DATA_BYTE(lines + wpls, m)];
02357             sum += tab8[GET_DATA_BYTE(lines + wpls, m + 1)];
02358             sum += tab8[GET_DATA_BYTE(lines + 2 * wpls, m)];
02359             sum += tab8[GET_DATA_BYTE(lines + 2 * wpls, m + 1)];
02360             sum += tab8[GET_DATA_BYTE(lines + 3 * wpls, m)];
02361             sum += tab8[GET_DATA_BYTE(lines + 3 * wpls, m + 1)];
02362             sum += tab8[GET_DATA_BYTE(lines + 4 * wpls, m)];
02363             sum += tab8[GET_DATA_BYTE(lines + 4 * wpls, m + 1)];
02364             sum += tab8[GET_DATA_BYTE(lines + 5 * wpls, m)];
02365             sum += tab8[GET_DATA_BYTE(lines + 5 * wpls, m + 1)];
02366             sum += tab8[GET_DATA_BYTE(lines + 6 * wpls, m)];
02367             sum += tab8[GET_DATA_BYTE(lines + 6 * wpls, m + 1)];
02368             sum += tab8[GET_DATA_BYTE(lines + 7 * wpls, m)];
02369             sum += tab8[GET_DATA_BYTE(lines + 7 * wpls, m + 1)];
02370             sum += tab8[GET_DATA_BYTE(lines + 8 * wpls, m)];
02371             sum += tab8[GET_DATA_BYTE(lines + 8 * wpls, m + 1)];
02372             sum += tab8[GET_DATA_BYTE(lines + 9 * wpls, m)];
02373             sum += tab8[GET_DATA_BYTE(lines + 9 * wpls, m + 1)];
02374             sum += tab8[GET_DATA_BYTE(lines + 10 * wpls, m)];
02375             sum += tab8[GET_DATA_BYTE(lines + 10 * wpls, m + 1)];
02376             sum += tab8[GET_DATA_BYTE(lines + 11 * wpls, m)];
02377             sum += tab8[GET_DATA_BYTE(lines + 11 * wpls, m + 1)];
02378             sum += tab8[GET_DATA_BYTE(lines + 12 * wpls, m)];
02379             sum += tab8[GET_DATA_BYTE(lines + 12 * wpls, m + 1)];
02380             sum += tab8[GET_DATA_BYTE(lines + 13 * wpls, m)];
02381             sum += tab8[GET_DATA_BYTE(lines + 13 * wpls, m + 1)];
02382             sum += tab8[GET_DATA_BYTE(lines + 14 * wpls, m)];
02383             sum += tab8[GET_DATA_BYTE(lines + 14 * wpls, m + 1)];
02384             sum += tab8[GET_DATA_BYTE(lines + 15 * wpls, m)];
02385             sum += tab8[GET_DATA_BYTE(lines + 15 * wpls, m + 1)];
02386             sum = L_MIN(sum, 255);
02387             SET_DATA_BYTE(lined, j, 255 - sum);
02388         }
02389     }
02390 
02391     return;
02392 }
02393 
02394 
02395 
02396 /*------------------------------------------------------------------*
02397  *                         Grayscale mipmap                         *
02398  *------------------------------------------------------------------*/
02399 /*!
02400  *  scaleMipmapLow()
02401  *
02402  *  See notes in scale.c for pixScaleToGrayMipmap().  This function
02403  *  is here for pedagogical reasons.  It gives poor results on document
02404  *  images because of aliasing.
02405  */
02406 l_int32
02407 scaleMipmapLow(l_uint32  *datad,
02408                l_int32    wd,
02409                l_int32    hd,
02410                l_int32    wpld,
02411                l_uint32  *datas1,
02412                l_int32    wpls1,
02413                l_uint32  *datas2,
02414                l_int32    wpls2,
02415                l_float32  red)
02416 {
02417 l_int32    i, j, val1, val2, val, row2, col2;
02418 l_int32   *srow, *scol;
02419 l_uint32  *lines1, *lines2, *lined;
02420 l_float32  ratio, w1, w2;
02421 
02422     PROCNAME("scaleMipmapLow");
02423 
02424         /* Clear dest */
02425     memset((char *)datad, 0, 4 * wpld * hd);
02426     
02427         /* Each dest pixel at (j,i) is computed by interpolating
02428            between the two src images at the corresponding location.
02429            We store the UL corner locations of the square of
02430            src pixels in thelower-resolution image that correspond
02431            to dest pixel (j,i).  The are labelled by the arrays
02432            srow[i], scol[j].  The UL corner locations of the higher
02433            resolution src pixels are obtained from these arrays
02434            by multiplying by 2. */
02435     if ((srow = (l_int32 *)CALLOC(hd, sizeof(l_int32))) == NULL)
02436         return ERROR_INT("srow not made", procName, 1);
02437     if ((scol = (l_int32 *)CALLOC(wd, sizeof(l_int32))) == NULL)
02438         return ERROR_INT("scol not made", procName, 1);
02439     ratio = 1. / (2. * red);  /* 0.5 for red = 1, 1 for red = 0.5 */
02440     for (i = 0; i < hd; i++)
02441         srow[i] = (l_int32)(ratio * i);
02442     for (j = 0; j < wd; j++)
02443         scol[j] = (l_int32)(ratio * j);
02444 
02445         /* Get weights for linear interpolation: these are the
02446          * 'distances' of the dest image plane from the two
02447          * src image planes. */
02448     w1 = 2. * red - 1.;   /* w1 --> 1 as red --> 1 */
02449     w2 = 1. - w1;
02450 
02451         /* For each dest pixel, compute linear interpolation */
02452     for (i = 0; i < hd; i++) {
02453         row2 = srow[i];
02454         lines1 = datas1 + 2 * row2 * wpls1;
02455         lines2 = datas2 + row2 * wpls2;
02456         lined = datad + i * wpld;
02457         for (j = 0; j < wd; j++) {
02458             col2 = scol[j];
02459             val1 = GET_DATA_BYTE(lines1, 2 * col2);
02460             val2 = GET_DATA_BYTE(lines2, col2);
02461             val = (l_int32)(w1 * val1 + w2 * val2);
02462             SET_DATA_BYTE(lined, j, val);
02463         }
02464     }
02465 
02466     FREE(srow);
02467     FREE(scol);
02468     return 0;
02469 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines