1 /*====================================================================*
2  -  Copyright (C) 2001 Leptonica.  All rights reserved.
3  -
4  -  Redistribution and use in source and binary forms, with or without
5  -  modification, are permitted provided that the following conditions
6  -  are met:
7  -  1. Redistributions of source code must retain the above copyright
8  -     notice, this list of conditions and the following disclaimer.
9  -  2. Redistributions in binary form must reproduce the above
10  -     copyright notice, this list of conditions and the following
11  -     disclaimer in the documentation and/or other materials
12  -     provided with the distribution.
13  -
14  -  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  -  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16  -  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17  -  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ANY
18  -  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  -  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  -  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  -  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  -  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23  -  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  -  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *====================================================================*/
26 
27 /*!
28  * \file scale1.c
29  * <pre>
30  *         Top-level scaling
31  *               PIX      *pixScale()
32  *               PIX      *pixScaleToSizeRel()
33  *               PIX      *pixScaleToSize()
34  *               PIX      *pixScaleGeneral()
35  *
36  *         Linearly interpreted (usually up-) scaling
37  *               PIX      *pixScaleLI()
38  *               PIX      *pixScaleColorLI()
39  *               PIX      *pixScaleColor2xLI()
40  *               PIX      *pixScaleColor4xLI()
41  *               PIX      *pixScaleGrayLI()
42  *               PIX      *pixScaleGray2xLI()
43  *               PIX      *pixScaleGray4xLI()
44  *
45  *         Upscale 2x followed by binarization
46  *               PIX      *pixScaleGray2xLIThresh()
47  *               PIX      *pixScaleGray2xLIDither()
48  *
49  *         Upscale 4x followed by binarization
50  *               PIX      *pixScaleGray4xLIThresh()
51  *               PIX      *pixScaleGray4xLIDither()
52  *
53  *         Scaling by closest pixel sampling
54  *               PIX      *pixScaleBySampling()
55  *               PIX      *pixScaleBySamplingToSize()
56  *               PIX      *pixScaleByIntSampling()
57  *
58  *         Fast integer factor subsampling RGB to gray and to binary
59  *               PIX      *pixScaleRGBToGrayFast()
60  *               PIX      *pixScaleRGBToBinaryFast()
61  *               PIX      *pixScaleGrayToBinaryFast()
62  *
63  *         Downscaling with (antialias) smoothing
64  *               PIX      *pixScaleSmooth()
65  *               PIX      *pixScaleSmoothToSize()
66  *               PIX      *pixScaleRGBToGray2()   [special 2x reduction to gray]
67  *
68  *         Downscaling with (antialias) area mapping
69  *               PIX      *pixScaleAreaMap()
70  *               PIX      *pixScaleAreaMap2()
71  *               PIX      *pixScaleAreaMapToSize()
72  *
73  *         Binary scaling by closest pixel sampling
74  *               PIX      *pixScaleBinary()
75  *
76  *     Low-level static functions:
77  *
78  *         Color (interpolated) scaling: general case
79  *               static void       scaleColorLILow()
80  *
81  *         Grayscale (interpolated) scaling: general case
82  *               static void       scaleGrayLILow()
83  *
84  *         Color (interpolated) scaling: 2x upscaling
85  *               static void       scaleColor2xLILow()
86  *               static void       scaleColor2xLILineLow()
87  *
88  *         Grayscale (interpolated) scaling: 2x upscaling
89  *               static void       scaleGray2xLILow()
90  *               static void       scaleGray2xLILineLow()
91  *
92  *         Grayscale (interpolated) scaling: 4x upscaling
93  *               static void       scaleGray4xLILow()
94  *               static void       scaleGray4xLILineLow()
95  *
96  *         Grayscale and color scaling by closest pixel sampling
97  *               static l_int32    scaleBySamplingLow()
98  *
99  *         Color and grayscale downsampling with (antialias) lowpass filter
100  *               static l_int32    scaleSmoothLow()
101  *               static void       scaleRGBToGray2Low()
102  *
103  *         Color and grayscale downsampling with (antialias) area mapping
104  *               static l_int32    scaleColorAreaMapLow()
105  *               static l_int32    scaleGrayAreaMapLow()
106  *               static l_int32    scaleAreaMapLow2()
107  *
108  *         Binary scaling by closest pixel sampling
109  *               static l_int32    scaleBinaryLow()
110  * </pre>
111  */
112 
113 #include <string.h>
114 #include "allheaders.h"
115 
116 static void scaleColorLILow(l_uint32 *datad, l_int32 wd, l_int32 hd,
117                             l_int32 wpld, l_uint32 *datas, l_int32 ws,
118                             l_int32 hs, l_int32 wpls);
119 static void scaleGrayLILow(l_uint32 *datad, l_int32 wd, l_int32 hd,
120                            l_int32 wpld, l_uint32 *datas, l_int32 ws,
121                            l_int32 hs, l_int32 wpls);
122 static void scaleColor2xLILow(l_uint32 *datad, l_int32 wpld, l_uint32 *datas,
123                               l_int32 ws, l_int32 hs, l_int32 wpls);
124 static void scaleColor2xLILineLow(l_uint32 *lined, l_int32 wpld,
125                                   l_uint32 *lines, l_int32 ws, l_int32 wpls,
126                                   l_int32 lastlineflag);
127 static void scaleGray2xLILow(l_uint32 *datad, l_int32 wpld, l_uint32 *datas,
128                              l_int32 ws, l_int32 hs, l_int32 wpls);
129 static void scaleGray2xLILineLow(l_uint32 *lined, l_int32 wpld,
130                                  l_uint32 *lines, l_int32 ws, l_int32 wpls,
131                                  l_int32 lastlineflag);
132 static void scaleGray4xLILow(l_uint32 *datad, l_int32 wpld, l_uint32 *datas,
133                              l_int32 ws, l_int32 hs, l_int32 wpls);
134 static void scaleGray4xLILineLow(l_uint32 *lined, l_int32 wpld,
135                                  l_uint32 *lines, l_int32 ws, l_int32 wpls,
136                                  l_int32 lastlineflag);
137 static l_int32 scaleBySamplingLow(l_uint32 *datad, l_int32 wd, l_int32 hd,
138                                   l_int32 wpld, l_uint32 *datas, l_int32 ws,
139                                   l_int32 hs, l_int32 d, l_int32 wpls);
140 static l_int32 scaleSmoothLow(l_uint32 *datad, l_int32 wd, l_int32 hd,
141                               l_int32 wpld, l_uint32 *datas, l_int32 ws,
142                               l_int32 hs, l_int32 d, l_int32 wpls,
143                               l_int32 size);
144 static void scaleRGBToGray2Low(l_uint32 *datad, l_int32 wd, l_int32 hd,
145                                l_int32 wpld, l_uint32 *datas, l_int32 wpls,
146                                l_float32 rwt, l_float32 gwt, l_float32 bwt);
147 static void scaleColorAreaMapLow(l_uint32 *datad, l_int32 wd, l_int32 hd,
148                                  l_int32 wpld, l_uint32 *datas, l_int32 ws,
149                                  l_int32 hs, l_int32 wpls);
150 static void scaleGrayAreaMapLow(l_uint32 *datad, l_int32 wd, l_int32 hd,
151                                 l_int32 wpld, l_uint32 *datas, l_int32 ws,
152                                 l_int32 hs, l_int32 wpls);
153 static void scaleAreaMapLow2(l_uint32 *datad, l_int32 wd, l_int32 hd,
154                              l_int32 wpld, l_uint32 *datas, l_int32 d,
155                              l_int32 wpls);
156 static l_int32 scaleBinaryLow(l_uint32 *datad, l_int32 wd, l_int32 hd,
157                               l_int32 wpld, l_uint32 *datas, l_int32 ws,
158                               l_int32 hs, l_int32 wpls);
159 
160 #ifndef  NO_CONSOLE_IO
161 #define  DEBUG_OVERFLOW   0
162 #define  DEBUG_UNROLLING  0
163 #endif  /* ~NO_CONSOLE_IO */
164 
165 
166 /*------------------------------------------------------------------*
167  *                    Top level scaling dispatcher                  *
168  *------------------------------------------------------------------*/
169 /*!
170  * \brief   pixScale()
171  *
172  * \param[in]    pixs 1, 2, 4, 8, 16 and 32 bpp
173  * \param[in]    scalex, scaley
174  * \return  pixd, or NULL on error
175  *
176  *  This function scales 32 bpp RGB; 2, 4 or 8 bpp palette color;
177  *  2, 4, 8 or 16 bpp gray; and binary images.
178  *
179  *  When the input has palette color, the colormap is removed and
180  *  the result is either 8 bpp gray or 32 bpp RGB, depending on whether
181  *  the colormap has color entries.  Images with 2, 4 or 16 bpp are
182  *  converted to 8 bpp.
183  *
184  *  Because pixScale is meant to be a very simple interface to a
185  *  number of scaling functions, including the use of unsharp masking,
186  *  the type of scaling and the sharpening parameters are chosen
187  *  by default.  Grayscale and color images are scaled using one
188  *  of four methods, depending on the scale factors:
189  *   1 antialiased subsampling (lowpass filtering followed by
190  *       subsampling, implemented here by area mapping), for scale factors
191  *       less than 0.2
192  *   2 antialiased subsampling with sharpening, for scale factors
193  *       between 0.2 and 0.7
194  *   3 linear interpolation with sharpening, for scale factors between
195  *       0.7 and 1.4
196  *   4 linear interpolation without sharpening, for scale factors >= 1.4.
197  *
198  *  One could use subsampling for scale factors very close to 1.0,
199  *  because it preserves sharp edges.  Linear interpolation blurs
200  *  edges because the dest pixels will typically straddle two src edge
201  *  pixels.  Subsmpling removes entire columns and rows, so the edge is
202  *  not blurred.  However, there are two reasons for not doing this.
203  *  First, it moves edges, so that a straight line at a large angle to
204  *  both horizontal and vertical will have noticeable kinks where
205  *  horizontal and vertical rasters are removed.  Second, although it
206  *  is very fast, you get good results on sharp edges by applying
207  *  a sharpening filter.
208  *
209  *  For images with sharp edges, sharpening substantially improves the
210  *  image quality for scale factors between about 0.2 and about 2.0.
211  *  pixScale uses a small amount of sharpening by default because
212  *  it strengthens edge pixels that are weak due to anti-aliasing.
213  *  The default sharpening factors are:
214  *      * for scaling factors < 0.7:   sharpfract = 0.2    sharpwidth = 1
215  *      * for scaling factors >= 0.7:  sharpfract = 0.4    sharpwidth = 2
216  *  The cases where the sharpening halfwidth is 1 or 2 have special
217  *  implementations and are about twice as fast as the general case.
218  *
219  *  However, sharpening is computationally expensive, and one needs
220  *  to consider the speed-quality tradeoff:
221  *      * For upscaling of RGB images, linear interpolation plus default
222  *        sharpening is about 5 times slower than upscaling alone.
223  *      * For downscaling, area mapping plus default sharpening is
224  *        about 10 times slower than downscaling alone.
225  *  When the scale factor is larger than 1.4, the cost of sharpening,
226  *  which is proportional to image area, is very large compared to the
227  *  incremental quality improvement, so we cut off the default use of
228  *  sharpening at 1.4.  Thus, for scale factors greater than 1.4,
229  *  pixScale only does linear interpolation.
230  *
231  *  In many situations you will get a satisfactory result by scaling
232  *  without sharpening: call pixScaleGeneral with %sharpfract = 0.0.
233  *  Alternatively, if you wish to sharpen but not use the default
234  *  value, first call pixScaleGeneral with %sharpfract = 0.0, and
235  *  then sharpen explicitly using pixUnsharpMasking.
236  *
237  *  Binary images are scaled to binary by sampling the closest pixel,
238  *  without any low-pass filtering averaging of neighboring pixels.
239  *  This will introduce aliasing for reductions.  Aliasing can be
240  *  prevented by using pixScaleToGray instead.
241  */
242 PIX *
pixScale(PIX * pixs,l_float32 scalex,l_float32 scaley)243 pixScale(PIX       *pixs,
244          l_float32  scalex,
245          l_float32  scaley)
246 {
247 l_int32    sharpwidth;
248 l_float32  maxscale, sharpfract;
249 
250     PROCNAME("pixScale");
251 
252     if (!pixs)
253         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
254 
255         /* Reduce the default sharpening factors by 2 if maxscale < 0.7 */
256     maxscale = L_MAX(scalex, scaley);
257     sharpfract = (maxscale < 0.7) ? 0.2 : 0.4;
258     sharpwidth = (maxscale < 0.7) ? 1 : 2;
259 
260     return pixScaleGeneral(pixs, scalex, scaley, sharpfract, sharpwidth);
261 }
262 
263 
264 /*!
265  * \brief   pixScaleToSizeRel()
266  *
267  * \param[in]    pixs
268  * \param[in]    delw  change in width, in pixels; 0 means no change
269  * \param[in]    delh  change in height, in pixels; 0 means no change
270  * \return  pixd, or NULL on error
271  */
272 PIX *
pixScaleToSizeRel(PIX * pixs,l_int32 delw,l_int32 delh)273 pixScaleToSizeRel(PIX     *pixs,
274                   l_int32  delw,
275                   l_int32  delh)
276 {
277 l_int32  w, h, wd, hd;
278 
279     PROCNAME("pixScaleToSizeRel");
280 
281     if (!pixs)
282         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
283 
284     if (delw == 0 && delh == 0)
285         return pixCopy(NULL, pixs);
286 
287     pixGetDimensions(pixs, &w, &h, NULL);
288     wd = w + delw;
289     hd = h + delh;
290     if (wd <= 0 || hd <= 0)
291         return (PIX *)ERROR_PTR("pix dimension reduced to 0", procName, NULL);
292 
293     return pixScaleToSize(pixs, wd, hd);
294 }
295 
296 
297 /*!
298  * \brief   pixScaleToSize()
299  *
300  * \param[in]    pixs 1, 2, 4, 8, 16 and 32 bpp
301  * \param[in]    wd  target width; use 0 if using height as target
302  * \param[in]    hd  target height; use 0 if using width as target
303  * \return  pixd, or NULL on error
304  *
305  * <pre>
306  * Notes:
307  *      (1) The output scaled image has the dimension(s) you specify:
308  *          * To specify the width with isotropic scaling, set %hd = 0.
309  *          * To specify the height with isotropic scaling, set %wd = 0.
310  *          * If both %wd and %hd are specified, the image is scaled
311  *             (in general, anisotropically) to that size.
312  *          * It is an error to set both %wd and %hd to 0.
313  * </pre>
314  */
315 PIX *
pixScaleToSize(PIX * pixs,l_int32 wd,l_int32 hd)316 pixScaleToSize(PIX     *pixs,
317                l_int32  wd,
318                l_int32  hd)
319 {
320 l_int32    w, h;
321 l_float32  scalex, scaley;
322 
323     PROCNAME("pixScaleToSize");
324 
325     if (!pixs)
326         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
327     if (wd <= 0 && hd <= 0)
328         return (PIX *)ERROR_PTR("neither wd nor hd > 0", procName, NULL);
329 
330     pixGetDimensions(pixs, &w, &h, NULL);
331     if (wd <= 0) {
332         scaley = (l_float32)hd / (l_float32)h;
333         scalex = scaley;
334     } else if (hd <= 0) {
335         scalex = (l_float32)wd / (l_float32)w;
336         scaley = scalex;
337     } else {
338         scalex = (l_float32)wd / (l_float32)w;
339         scaley = (l_float32)hd / (l_float32)h;
340     }
341 
342     return pixScale(pixs, scalex, scaley);
343 }
344 
345 
346 /*!
347  * \brief   pixScaleGeneral()
348  *
349  * \param[in]    pixs 1, 2, 4, 8, 16 and 32 bpp
350  * \param[in]    scalex, scaley both > 0.0
351  * \param[in]    sharpfract use 0.0 to skip sharpening
352  * \param[in]    sharpwidth halfwidth of low-pass filter; typ. 1 or 2
353  * \return  pixd, or NULL on error
354  *
355  * <pre>
356  * Notes:
357  *      (1) See pixScale() for usage.
358  *      (2) This interface may change in the future, as other special
359  *          cases are added.
360  *      (3) The actual sharpening factors used depend on the maximum
361  *          of the two scale factors (maxscale):
362  *            maxscale <= 0.2:        no sharpening
363  *            0.2 < maxscale < 1.4:   uses the input parameters
364  *            maxscale >= 1.4:        no sharpening
365  *      (4) To avoid sharpening for grayscale and color images with
366  *          scaling factors between 0.2 and 1.4, call this function
367  *          with %sharpfract == 0.0.
368  *      (5) To use arbitrary sharpening in conjunction with scaling,
369  *          call this function with %sharpfract = 0.0, and follow this
370  *          with a call to pixUnsharpMasking() with your chosen parameters.
371  * </pre>
372  */
373 PIX *
pixScaleGeneral(PIX * pixs,l_float32 scalex,l_float32 scaley,l_float32 sharpfract,l_int32 sharpwidth)374 pixScaleGeneral(PIX       *pixs,
375                 l_float32  scalex,
376                 l_float32  scaley,
377                 l_float32  sharpfract,
378                 l_int32    sharpwidth)
379 {
380 l_int32    d;
381 l_float32  maxscale;
382 PIX       *pixt, *pixt2, *pixd;
383 
384     PROCNAME("pixScaleGeneral");
385 
386     if (!pixs)
387         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
388     d = pixGetDepth(pixs);
389     if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
390         return (PIX *)ERROR_PTR("pixs not {1,2,4,8,16,32} bpp", procName, NULL);
391     if (scalex <= 0.0 || scaley <= 0.0)
392         return (PIX *)ERROR_PTR("scale factor <= 0", procName, NULL);
393     if (scalex == 1.0 && scaley == 1.0)
394         return pixCopy(NULL, pixs);
395 
396     if (d == 1)
397         return pixScaleBinary(pixs, scalex, scaley);
398 
399         /* Remove colormap; clone if possible; result is either 8 or 32 bpp */
400     if ((pixt = pixConvertTo8Or32(pixs, L_CLONE, 0)) == NULL)
401         return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
402 
403         /* Scale (up or down) */
404     d = pixGetDepth(pixt);
405     maxscale = L_MAX(scalex, scaley);
406     if (maxscale < 0.7) {  /* area mapping for anti-aliasing */
407         pixt2 = pixScaleAreaMap(pixt, scalex, scaley);
408         if (maxscale > 0.2 && sharpfract > 0.0 && sharpwidth > 0)
409             pixd = pixUnsharpMasking(pixt2, sharpwidth, sharpfract);
410         else
411             pixd = pixClone(pixt2);
412     } else {  /* use linear interpolation */
413         if (d == 8)
414             pixt2 = pixScaleGrayLI(pixt, scalex, scaley);
415         else  /* d == 32 */
416             pixt2 = pixScaleColorLI(pixt, scalex, scaley);
417         if (maxscale < 1.4 && sharpfract > 0.0 && sharpwidth > 0)
418             pixd = pixUnsharpMasking(pixt2, sharpwidth, sharpfract);
419         else
420             pixd = pixClone(pixt2);
421     }
422 
423     pixDestroy(&pixt);
424     pixDestroy(&pixt2);
425     pixCopyText(pixd, pixs);
426     pixCopyInputFormat(pixd, pixs);
427     return pixd;
428 }
429 
430 
431 /*------------------------------------------------------------------*
432  *                  Scaling by linear interpolation                 *
433  *------------------------------------------------------------------*/
434 /*!
435  * \brief   pixScaleLI()
436  *
437  * \param[in]    pixs 2, 4, 8 or 32 bpp; with or without colormap
438  * \param[in]    scalex, scaley must both be >= 0.7
439  * \return  pixd, or NULL on error
440  *
441  * <pre>
442  * Notes:
443  *      (1) This function should only be used when the scale factors are
444  *          greater than or equal to 0.7, and typically greater than 1.
445  *          If either scale factor is larger than 0.7, we issue a warning
446  *          and call pixScaleGeneral(), which will invoke area mapping
447  *          without sharpening.
448  *      (2) This works on 2, 4, 8, 16 and 32 bpp images, as well as on
449  *          2, 4 and 8 bpp images that have a colormap.  If there is a
450  *          colormap, it is removed to either gray or RGB, depending
451  *          on the colormap.
452  *      (3) This does a linear interpolation on the src image.
453  *      (4) It dispatches to much faster implementations for
454  *          the special cases of 2x and 4x expansion.
455  * </pre>
456  */
457 PIX *
pixScaleLI(PIX * pixs,l_float32 scalex,l_float32 scaley)458 pixScaleLI(PIX       *pixs,
459            l_float32  scalex,
460            l_float32  scaley)
461 {
462 l_int32    d;
463 l_float32  maxscale;
464 PIX       *pixt, *pixd;
465 
466     PROCNAME("pixScaleLI");
467 
468     if (!pixs || (pixGetDepth(pixs) == 1))
469         return (PIX *)ERROR_PTR("pixs not defined or 1 bpp", procName, NULL);
470     maxscale = L_MAX(scalex, scaley);
471     if (maxscale < 0.7) {
472         L_WARNING("scaling factors < 0.7; do regular scaling\n", procName);
473         return pixScaleGeneral(pixs, scalex, scaley, 0.0, 0);
474     }
475     d = pixGetDepth(pixs);
476     if (d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
477         return (PIX *)ERROR_PTR("pixs not {2,4,8,16,32} bpp", procName, NULL);
478 
479         /* Remove colormap; clone if possible; result is either 8 or 32 bpp */
480     if ((pixt = pixConvertTo8Or32(pixs, L_CLONE, 0)) == NULL)
481         return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
482 
483     d = pixGetDepth(pixt);
484     if (d == 8)
485         pixd = pixScaleGrayLI(pixt, scalex, scaley);
486     else  /* d == 32 */
487         pixd = pixScaleColorLI(pixt, scalex, scaley);
488 
489     pixDestroy(&pixt);
490     pixCopyInputFormat(pixd, pixs);
491     return pixd;
492 }
493 
494 
495 /*!
496  * \brief   pixScaleColorLI()
497  *
498  * \param[in]    pixs  32 bpp, representing rgb
499  * \param[in]    scalex, scaley must both be >= 0.7
500  * \return  pixd, or NULL on error
501  *
502  * <pre>
503  * Notes:
504  *      (1) If either scale factor is larger than 0.7, we issue a warning
505  *          and call pixScaleGeneral(), which will invoke area mapping
506  *          without sharpening.  This is particularly important for
507  *          document images with sharp edges.
508  *      (2) For the general case, it's about 4x faster to manipulate
509  *          the color pixels directly, rather than to make images
510  *          out of each of the 3 components, scale each component
511  *          using the pixScaleGrayLI(), and combine the results back
512  *          into an rgb image.
513  *      (3) The speed on intel hardware for the general case (not 2x)
514  *          is about 10 * 10^6 dest-pixels/sec/GHz.  (The special 2x
515  *          case runs at about 80 * 10^6 dest-pixels/sec/GHz.)
516  * </pre>
517  */
518 PIX *
pixScaleColorLI(PIX * pixs,l_float32 scalex,l_float32 scaley)519 pixScaleColorLI(PIX      *pixs,
520                l_float32  scalex,
521                l_float32  scaley)
522 {
523 l_int32    ws, hs, wpls, wd, hd, wpld;
524 l_uint32  *datas, *datad;
525 l_float32  maxscale;
526 PIX       *pixd;
527 
528     PROCNAME("pixScaleColorLI");
529 
530     if (!pixs || (pixGetDepth(pixs) != 32))
531         return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
532     maxscale = L_MAX(scalex, scaley);
533     if (maxscale < 0.7) {
534         L_WARNING("scaling factors < 0.7; do regular scaling\n", procName);
535         return pixScaleGeneral(pixs, scalex, scaley, 0.0, 0);
536     }
537 
538         /* Do fast special cases if possible */
539     if (scalex == 1.0 && scaley == 1.0)
540         return pixCopy(NULL, pixs);
541     if (scalex == 2.0 && scaley == 2.0)
542         return pixScaleColor2xLI(pixs);
543     if (scalex == 4.0 && scaley == 4.0)
544         return pixScaleColor4xLI(pixs);
545 
546         /* General case */
547     pixGetDimensions(pixs, &ws, &hs, NULL);
548     datas = pixGetData(pixs);
549     wpls = pixGetWpl(pixs);
550     wd = (l_int32)(scalex * (l_float32)ws + 0.5);
551     hd = (l_int32)(scaley * (l_float32)hs + 0.5);
552     if ((pixd = pixCreate(wd, hd, 32)) == NULL)
553         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
554     pixCopyResolution(pixd, pixs);
555     pixScaleResolution(pixd, scalex, scaley);
556     datad = pixGetData(pixd);
557     wpld = pixGetWpl(pixd);
558     scaleColorLILow(datad, wd, hd, wpld, datas, ws, hs, wpls);
559     if (pixGetSpp(pixs) == 4)
560         pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley);
561 
562     pixCopyInputFormat(pixd, pixs);
563     return pixd;
564 }
565 
566 
567 /*!
568  * \brief   pixScaleColor2xLI()
569  *
570  * \param[in]    pixs  32 bpp, representing rgb
571  * \return  pixd, or NULL on error
572  *
573  * <pre>
574  * Notes:
575  *      (1) This is a special case of linear interpolated scaling,
576  *          for 2x upscaling.  It is about 8x faster than using
577  *          the generic pixScaleColorLI(), and about 4x faster than
578  *          using the special 2x scale function pixScaleGray2xLI()
579  *          on each of the three components separately.
580  *      (2) The speed on intel hardware is about
581  *          80 * 10^6 dest-pixels/sec/GHz.
582  * </pre>
583  */
584 PIX *
pixScaleColor2xLI(PIX * pixs)585 pixScaleColor2xLI(PIX  *pixs)
586 {
587 l_int32    ws, hs, wpls, wpld;
588 l_uint32  *datas, *datad;
589 PIX       *pixd;
590 
591     PROCNAME("pixScaleColor2xLI");
592 
593     if (!pixs || (pixGetDepth(pixs) != 32))
594         return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
595 
596     pixGetDimensions(pixs, &ws, &hs, NULL);
597     datas = pixGetData(pixs);
598     wpls = pixGetWpl(pixs);
599     if ((pixd = pixCreate(2 * ws, 2 * hs, 32)) == NULL)
600         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
601     pixCopyResolution(pixd, pixs);
602     pixScaleResolution(pixd, 2.0, 2.0);
603     datad = pixGetData(pixd);
604     wpld = pixGetWpl(pixd);
605     scaleColor2xLILow(datad, wpld, datas, ws, hs, wpls);
606     if (pixGetSpp(pixs) == 4)
607         pixScaleAndTransferAlpha(pixd, pixs, 2.0, 2.0);
608 
609     pixCopyInputFormat(pixd, pixs);
610     return pixd;
611 }
612 
613 
614 /*!
615  * \brief   pixScaleColor4xLI()
616  *
617  * \param[in]    pixs  32 bpp, representing rgb
618  * \return  pixd, or NULL on error
619  *
620  * <pre>
621  * Notes:
622  *      (1) This is a special case of color linear interpolated scaling,
623  *          for 4x upscaling.  It is about 3x faster than using
624  *          the generic pixScaleColorLI().
625  *      (2) The speed on intel hardware is about
626  *          30 * 10^6 dest-pixels/sec/GHz
627  *      (3) This scales each component separately, using pixScaleGray4xLI().
628  *          It would be about 4x faster to inline the color code properly,
629  *          in analogy to scaleColor4xLILow(), and I leave this as
630  *          an exercise for someone who really needs it.
631  * </pre>
632  */
633 PIX *
pixScaleColor4xLI(PIX * pixs)634 pixScaleColor4xLI(PIX  *pixs)
635 {
636 PIX  *pixr, *pixg, *pixb;
637 PIX  *pixrs, *pixgs, *pixbs;
638 PIX  *pixd;
639 
640     PROCNAME("pixScaleColor4xLI");
641 
642     if (!pixs || (pixGetDepth(pixs) != 32))
643         return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
644 
645     pixr = pixGetRGBComponent(pixs, COLOR_RED);
646     pixrs = pixScaleGray4xLI(pixr);
647     pixDestroy(&pixr);
648     pixg = pixGetRGBComponent(pixs, COLOR_GREEN);
649     pixgs = pixScaleGray4xLI(pixg);
650     pixDestroy(&pixg);
651     pixb = pixGetRGBComponent(pixs, COLOR_BLUE);
652     pixbs = pixScaleGray4xLI(pixb);
653     pixDestroy(&pixb);
654 
655     if ((pixd = pixCreateRGBImage(pixrs, pixgs, pixbs)) == NULL) {
656         L_ERROR("pixd not made\n", procName);
657     } else {
658         if (pixGetSpp(pixs) == 4)
659             pixScaleAndTransferAlpha(pixd, pixs, 4.0, 4.0);
660         pixCopyInputFormat(pixd, pixs);
661     }
662 
663     pixDestroy(&pixrs);
664     pixDestroy(&pixgs);
665     pixDestroy(&pixbs);
666     return pixd;
667 }
668 
669 
670 /*!
671  * \brief   pixScaleGrayLI()
672  *
673  * \param[in]    pixs 8 bpp grayscale, no cmap
674  * \param[in]    scalex, scaley must both be >= 0.7
675  * \return  pixd, or NULL on error
676  *
677  *  This function is appropriate for upscaling magnification, where the
678  *  scale factor is > 1, as well as for a small amount of downscaling
679  *  reduction, with scale factor > 0.7.  If the scale factor is < 0.7,
680  *  the best result is obtained by area mapping, but this is relatiely
681  *  expensive.  A less expensive alternative with scale factor < 0.7
682  *  is low-pass filtering followed by subsampling (pixScaleSmooth()),
683  *  which is effectively a cheap form of area mapping.
684  *
685  *  Some more details follow.
686  *
687  *  For each pixel in the dest, this does a linear
688  *  interpolation of 4 neighboring pixels in the src.
689  *  Specifically, consider the UL corner of src and
690  *  dest pixels.  The UL corner of the dest falls within
691  *  a src pixel, whose four corners are the UL corners
692  *  of 4 adjacent src pixels.  The value of the dest
693  *  is taken by linear interpolation using the values of
694  *  the four src pixels and the distance of the UL corner
695  *  of the dest from each corner.
696  *
697  *  If the image is expanded so that the dest pixel is
698  *  smaller than the src pixel, such interpolation
699  *  is a reasonable approach.  This interpolation is
700  *  also good for a small image reduction factor that
701  *  is not more than a 2x reduction.
702  *
703  *  Note that the linear interpolation algorithm for scaling
704  *  is identical in form to the area-mapping algorithm
705  *  for grayscale rotation.  The latter corresponds to a
706  *  translation of each pixel without scaling.
707  *
708  *  This function is NOT optimal if the scaling involves
709  *  a large reduction.    If the image is significantly
710  *  reduced, so that the dest pixel is much larger than
711  *  the src pixels, this interpolation, which is over src
712  *  pixels only near the UL corner of the dest pixel,
713  *  is not going to give a good area-mapping average.
714  *  Because area mapping for image scaling is considerably
715  *  more computationally intensive than linear interpolation,
716  *  we choose not to use it.   For large image reduction,
717  *  linear interpolation over adjacent src pixels
718  *  degenerates asymptotically to subsampling.  But
719  *  subsampling without a low-pass pre-filter causes
720  *  aliasing by the nyquist theorem.  To avoid aliasing,
721  *  a low-pass filter e.g., an averaging filter of
722  *  size roughly equal to the dest pixel i.e., the
723  *  reduction factor should be applied to the src before
724  *  subsampling.
725  *
726  *  As an alternative to low-pass filtering and subsampling
727  *  for large reduction factors, linear interpolation can
728  *  also be done between the widely separated src pixels in
729  *  which the corners of the dest pixel lie.  This also is
730  *  not optimal, as it samples src pixels only near the
731  *  corners of the dest pixel, and it is not implemented.
732  *
733  *  The speed on circa 2005 Intel hardware for the general case (not 2x)
734  *  is about 13 * 10^6 dest-pixels/sec/GHz.  The special 2x case runs
735  *  at about 100 * 10^6 dest-pixels/sec/GHz.
736  */
737 PIX *
pixScaleGrayLI(PIX * pixs,l_float32 scalex,l_float32 scaley)738 pixScaleGrayLI(PIX       *pixs,
739                l_float32  scalex,
740                l_float32  scaley)
741 {
742 l_int32    ws, hs, wpls, wd, hd, wpld;
743 l_uint32  *datas, *datad;
744 l_float32  maxscale;
745 PIX       *pixd;
746 
747     PROCNAME("pixScaleGrayLI");
748 
749     if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
750         return (PIX *)ERROR_PTR("pixs undefined, cmapped or not 8 bpp",
751                                 procName, NULL);
752     maxscale = L_MAX(scalex, scaley);
753     if (maxscale < 0.7) {
754         L_WARNING("scaling factors < 0.7; do regular scaling\n", procName);
755         return pixScaleGeneral(pixs, scalex, scaley, 0.0, 0);
756     }
757 
758         /* Do fast special cases if possible */
759     if (scalex == 1.0 && scaley == 1.0)
760         return pixCopy(NULL, pixs);
761     if (scalex == 2.0 && scaley == 2.0)
762         return pixScaleGray2xLI(pixs);
763     if (scalex == 4.0 && scaley == 4.0)
764         return pixScaleGray4xLI(pixs);
765 
766         /* General case */
767     pixGetDimensions(pixs, &ws, &hs, NULL);
768     datas = pixGetData(pixs);
769     wpls = pixGetWpl(pixs);
770     wd = (l_int32)(scalex * (l_float32)ws + 0.5);
771     hd = (l_int32)(scaley * (l_float32)hs + 0.5);
772     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
773         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
774     pixCopyText(pixd, pixs);
775     pixCopyResolution(pixd, pixs);
776     pixCopyInputFormat(pixd, pixs);
777     pixScaleResolution(pixd, scalex, scaley);
778     datad = pixGetData(pixd);
779     wpld = pixGetWpl(pixd);
780     scaleGrayLILow(datad, wd, hd, wpld, datas, ws, hs, wpls);
781     return pixd;
782 }
783 
784 
785 /*!
786  * \brief   pixScaleGray2xLI()
787  *
788  * \param[in]    pixs 8 bpp grayscale, not cmapped
789  * \return  pixd, or NULL on error
790  *
791  * <pre>
792  * Notes:
793  *      (1) This is a special case of gray linear interpolated scaling,
794  *          for 2x upscaling.  It is about 6x faster than using
795  *          the generic pixScaleGrayLI().
796  *      (2) The speed on intel hardware is about
797  *          100 * 10^6 dest-pixels/sec/GHz
798  * </pre>
799  */
800 PIX *
pixScaleGray2xLI(PIX * pixs)801 pixScaleGray2xLI(PIX  *pixs)
802 {
803 l_int32    ws, hs, wpls, wpld;
804 l_uint32  *datas, *datad;
805 PIX       *pixd;
806 
807     PROCNAME("pixScaleGray2xLI");
808 
809     if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
810         return (PIX *)ERROR_PTR("pixs undefined, cmapped or not 8 bpp",
811                                 procName, NULL);
812 
813     pixGetDimensions(pixs, &ws, &hs, NULL);
814     datas = pixGetData(pixs);
815     wpls = pixGetWpl(pixs);
816     if ((pixd = pixCreate(2 * ws, 2 * hs, 8)) == NULL)
817         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
818     pixCopyResolution(pixd, pixs);
819     pixCopyInputFormat(pixd, pixs);
820     pixScaleResolution(pixd, 2.0, 2.0);
821     datad = pixGetData(pixd);
822     wpld = pixGetWpl(pixd);
823     scaleGray2xLILow(datad, wpld, datas, ws, hs, wpls);
824     return pixd;
825 }
826 
827 
828 /*!
829  * \brief   pixScaleGray4xLI()
830  *
831  * \param[in]    pixs 8 bpp grayscale, not cmapped
832  * \return  pixd, or NULL on error
833  *
834  * <pre>
835  * Notes:
836  *      (1) This is a special case of gray linear interpolated scaling,
837  *          for 4x upscaling.  It is about 12x faster than using
838  *          the generic pixScaleGrayLI().
839  *      (2) The speed on intel hardware is about
840  *          160 * 10^6 dest-pixels/sec/GHz.
841  * </pre>
842  */
843 PIX *
pixScaleGray4xLI(PIX * pixs)844 pixScaleGray4xLI(PIX  *pixs)
845 {
846 l_int32    ws, hs, wpls, wpld;
847 l_uint32  *datas, *datad;
848 PIX       *pixd;
849 
850     PROCNAME("pixScaleGray4xLI");
851 
852     if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
853         return (PIX *)ERROR_PTR("pixs undefined, cmapped or not 8 bpp",
854                                 procName, NULL);
855 
856     pixGetDimensions(pixs, &ws, &hs, NULL);
857     datas = pixGetData(pixs);
858     wpls = pixGetWpl(pixs);
859     if ((pixd = pixCreate(4 * ws, 4 * hs, 8)) == NULL)
860         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
861     pixCopyResolution(pixd, pixs);
862     pixCopyInputFormat(pixd, pixs);
863     pixScaleResolution(pixd, 4.0, 4.0);
864     datad = pixGetData(pixd);
865     wpld = pixGetWpl(pixd);
866     scaleGray4xLILow(datad, wpld, datas, ws, hs, wpls);
867     return pixd;
868 }
869 
870 
871 /*------------------------------------------------------------------*
872  *                Scale 2x followed by binarization                 *
873  *------------------------------------------------------------------*/
874 /*!
875  * \brief   pixScaleGray2xLIThresh()
876  *
877  * \param[in]    pixs 8 bpp, not cmapped
878  * \param[in]    thresh  between 0 and 256
879  * \return  pixd 1 bpp, or NULL on error
880  *
881  * <pre>
882  * Notes:
883  *      (1) This does 2x upscale on pixs, using linear interpolation,
884  *          followed by thresholding to binary.
885  *      (2) Buffers are used to avoid making a large grayscale image.
886  * </pre>
887  */
888 PIX *
pixScaleGray2xLIThresh(PIX * pixs,l_int32 thresh)889 pixScaleGray2xLIThresh(PIX     *pixs,
890                        l_int32  thresh)
891 {
892 l_int32    i, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
893 l_uint32  *datas, *datad, *lines, *lined, *lineb;
894 PIX       *pixd;
895 
896     PROCNAME("pixScaleGray2xLIThresh");
897 
898     if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
899         return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
900                                 procName, NULL);
901     if (thresh < 0 || thresh > 256)
902         return (PIX *)ERROR_PTR("thresh must be in [0, ... 256]",
903             procName, NULL);
904 
905     pixGetDimensions(pixs, &ws, &hs, NULL);
906     wd = 2 * ws;
907     hd = 2 * hs;
908     hsm = hs - 1;
909     datas = pixGetData(pixs);
910     wpls = pixGetWpl(pixs);
911 
912         /* Make line buffer for 2 lines of virtual intermediate image */
913     wplb = (wd + 3) / 4;
914     if ((lineb = (l_uint32 *)LEPT_CALLOC(2 * wplb, sizeof(l_uint32))) == NULL)
915         return (PIX *)ERROR_PTR("lineb not made", procName, NULL);
916 
917         /* Make dest binary image */
918     if ((pixd = pixCreate(wd, hd, 1)) == NULL) {
919         LEPT_FREE(lineb);
920         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
921     }
922     pixCopyInputFormat(pixd, pixs);
923     pixCopyResolution(pixd, pixs);
924     pixScaleResolution(pixd, 2.0, 2.0);
925     wpld = pixGetWpl(pixd);
926     datad = pixGetData(pixd);
927 
928         /* Do all but last src line */
929     for (i = 0; i < hsm; i++) {
930         lines = datas + i * wpls;
931         lined = datad + 2 * i * wpld;  /* do 2 dest lines at a time */
932         scaleGray2xLILineLow(lineb, wplb, lines, ws, wpls, 0);
933         thresholdToBinaryLineLow(lined, wd, lineb, 8, thresh);
934         thresholdToBinaryLineLow(lined + wpld, wd, lineb + wplb, 8, thresh);
935     }
936 
937         /* Do last src line */
938     lines = datas + hsm * wpls;
939     lined = datad + 2 * hsm * wpld;
940     scaleGray2xLILineLow(lineb, wplb, lines, ws, wpls, 1);
941     thresholdToBinaryLineLow(lined, wd, lineb, 8, thresh);
942     thresholdToBinaryLineLow(lined + wpld, wd, lineb + wplb, 8, thresh);
943 
944     LEPT_FREE(lineb);
945     return pixd;
946 }
947 
948 
949 /*!
950  * \brief   pixScaleGray2xLIDither()
951  *
952  * \param[in]    pixs 8 bpp, not cmapped
953  * \return  pixd 1 bpp, or NULL on error
954  *
955  * <pre>
956  * Notes:
957  *      (1) This does 2x upscale on pixs, using linear interpolation,
958  *          followed by Floyd-Steinberg dithering to binary.
959  *      (2) Buffers are used to avoid making a large grayscale image.
960  *          ~ Two line buffers are used for the src, required for the 2x
961  *            LI upscale.
962  *          ~ Three line buffers are used for the intermediate image.
963  *            Two are filled with each 2xLI row operation; the third is
964  *            needed because the upscale and dithering ops are out of sync.
965  * </pre>
966  */
967 PIX *
pixScaleGray2xLIDither(PIX * pixs)968 pixScaleGray2xLIDither(PIX  *pixs)
969 {
970 l_int32    i, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
971 l_uint32  *datas, *datad;
972 l_uint32  *lined;
973 l_uint32  *lineb = NULL;   /* 2 intermediate buffer lines */
974 l_uint32  *linebp = NULL;  /* 1 intermediate buffer line */
975 l_uint32  *bufs = NULL;    /* 2 source buffer lines */
976 PIX       *pixd = NULL;
977 
978     PROCNAME("pixScaleGray2xLIDither");
979 
980     if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
981         return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
982                                 procName, NULL);
983 
984     pixGetDimensions(pixs, &ws, &hs, NULL);
985     wd = 2 * ws;
986     hd = 2 * hs;
987     hsm = hs - 1;
988     datas = pixGetData(pixs);
989     wpls = pixGetWpl(pixs);
990 
991         /* Make line buffers for 2 lines of src image */
992     if ((bufs = (l_uint32 *)LEPT_CALLOC(2 * wpls, sizeof(l_uint32))) == NULL)
993         return (PIX *)ERROR_PTR("bufs not made", procName, NULL);
994 
995         /* Make line buffer for 2 lines of virtual intermediate image */
996     wplb = (wd + 3) / 4;
997     if ((lineb = (l_uint32 *)LEPT_CALLOC(2 * wplb, sizeof(l_uint32))) == NULL) {
998         L_ERROR("lineb not made\n", procName);
999         goto cleanup;
1000     }
1001 
1002         /* Make line buffer for 1 line of virtual intermediate image */
1003     if ((linebp = (l_uint32 *)LEPT_CALLOC(wplb, sizeof(l_uint32))) == NULL) {
1004         L_ERROR("linebp not made\n", procName);
1005         goto cleanup;
1006     }
1007 
1008         /* Make dest binary image */
1009     if ((pixd = pixCreate(wd, hd, 1)) == NULL) {
1010         L_ERROR("pixd not made\n", procName);
1011         goto cleanup;
1012     }
1013     pixCopyInputFormat(pixd, pixs);
1014     pixCopyResolution(pixd, pixs);
1015     pixScaleResolution(pixd, 2.0, 2.0);
1016     wpld = pixGetWpl(pixd);
1017     datad = pixGetData(pixd);
1018 
1019         /* Start with the first src and the first dest line */
1020     memcpy(bufs, datas, 4 * wpls);   /* first src line */
1021     memcpy(bufs + wpls, datas + wpls, 4 * wpls);  /* 2nd src line */
1022     scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 0);  /* 2 i lines */
1023     lined = datad;
1024     ditherToBinaryLineLow(lined, wd, lineb, lineb + wplb,
1025                           DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
1026                                                     /* 1st d line */
1027 
1028         /* Do all but last src line */
1029     for (i = 1; i < hsm; i++) {
1030         memcpy(bufs, datas + i * wpls, 4 * wpls);  /* i-th src line */
1031         memcpy(bufs + wpls, datas + (i + 1) * wpls, 4 * wpls);
1032         memcpy(linebp, lineb + wplb, 4 * wplb);
1033         scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 0);  /* 2 i lines */
1034         lined = datad + 2 * i * wpld;
1035         ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb,
1036                               DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
1037                                                    /* odd dest line */
1038         ditherToBinaryLineLow(lined, wd, lineb, lineb + wplb,
1039                               DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
1040                                                    /* even dest line */
1041     }
1042 
1043         /* Do the last src line and the last 3 dest lines */
1044     memcpy(bufs, datas + hsm * wpls, 4 * wpls);  /* hsm-th src line */
1045     memcpy(linebp, lineb + wplb, 4 * wplb);   /* 1 i line */
1046     scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 1);  /* 2 i lines */
1047     ditherToBinaryLineLow(lined + wpld, wd, linebp, lineb,
1048                           DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
1049                                                    /* odd dest line */
1050     ditherToBinaryLineLow(lined + 2 * wpld, wd, lineb, lineb + wplb,
1051                           DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
1052                                                    /* even dest line */
1053     ditherToBinaryLineLow(lined + 3 * wpld, wd, lineb + wplb, NULL,
1054                           DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 1);
1055                                                    /* last dest line */
1056 
1057 cleanup:
1058     LEPT_FREE(bufs);
1059     LEPT_FREE(lineb);
1060     LEPT_FREE(linebp);
1061     return pixd;
1062 }
1063 
1064 
1065 /*------------------------------------------------------------------*
1066  *                Scale 4x followed by binarization                 *
1067  *------------------------------------------------------------------*/
1068 /*!
1069  * \brief   pixScaleGray4xLIThresh()
1070  *
1071  * \param[in]    pixs 8 bpp
1072  * \param[in]    thresh  between 0 and 256
1073  * \return  pixd 1 bpp, or NULL on error
1074  *
1075  * <pre>
1076  * Notes:
1077  *      (1) This does 4x upscale on pixs, using linear interpolation,
1078  *          followed by thresholding to binary.
1079  *      (2) Buffers are used to avoid making a large grayscale image.
1080  *      (3) If a full 4x expanded grayscale image can be kept in memory,
1081  *          this function is only about 10% faster than separately doing
1082  *          a linear interpolation to a large grayscale image, followed
1083  *          by thresholding to binary.
1084  * </pre>
1085  */
1086 PIX *
pixScaleGray4xLIThresh(PIX * pixs,l_int32 thresh)1087 pixScaleGray4xLIThresh(PIX     *pixs,
1088                        l_int32  thresh)
1089 {
1090 l_int32    i, j, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
1091 l_uint32  *datas, *datad, *lines, *lined, *lineb;
1092 PIX       *pixd;
1093 
1094     PROCNAME("pixScaleGray4xLIThresh");
1095 
1096     if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
1097         return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
1098                                 procName, NULL);
1099     if (thresh < 0 || thresh > 256)
1100         return (PIX *)ERROR_PTR("thresh must be in [0, ... 256]",
1101             procName, NULL);
1102 
1103     pixGetDimensions(pixs, &ws, &hs, NULL);
1104     wd = 4 * ws;
1105     hd = 4 * hs;
1106     hsm = hs - 1;
1107     datas = pixGetData(pixs);
1108     wpls = pixGetWpl(pixs);
1109 
1110         /* Make line buffer for 4 lines of virtual intermediate image */
1111     wplb = (wd + 3) / 4;
1112     if ((lineb = (l_uint32 *)LEPT_CALLOC(4 * wplb, sizeof(l_uint32))) == NULL)
1113         return (PIX *)ERROR_PTR("lineb not made", procName, NULL);
1114 
1115         /* Make dest binary image */
1116     if ((pixd = pixCreate(wd, hd, 1)) == NULL) {
1117         LEPT_FREE(lineb);
1118         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1119     }
1120     pixCopyInputFormat(pixd, pixs);
1121     pixCopyResolution(pixd, pixs);
1122     pixScaleResolution(pixd, 4.0, 4.0);
1123     wpld = pixGetWpl(pixd);
1124     datad = pixGetData(pixd);
1125 
1126         /* Do all but last src line */
1127     for (i = 0; i < hsm; i++) {
1128         lines = datas + i * wpls;
1129         lined = datad + 4 * i * wpld;  /* do 4 dest lines at a time */
1130         scaleGray4xLILineLow(lineb, wplb, lines, ws, wpls, 0);
1131         for (j = 0; j < 4; j++) {
1132             thresholdToBinaryLineLow(lined + j * wpld, wd,
1133                                      lineb + j * wplb, 8, thresh);
1134         }
1135     }
1136 
1137         /* Do last src line */
1138     lines = datas + hsm * wpls;
1139     lined = datad + 4 * hsm * wpld;
1140     scaleGray4xLILineLow(lineb, wplb, lines, ws, wpls, 1);
1141     for (j = 0; j < 4; j++) {
1142         thresholdToBinaryLineLow(lined + j * wpld, wd,
1143                                  lineb + j * wplb, 8, thresh);
1144     }
1145 
1146     LEPT_FREE(lineb);
1147     return pixd;
1148 }
1149 
1150 
1151 /*!
1152  * \brief   pixScaleGray4xLIDither()
1153  *
1154  * \param[in]    pixs 8 bpp, not cmapped
1155  * \return  pixd 1 bpp, or NULL on error
1156  *
1157  * <pre>
1158  * Notes:
1159  *      (1) This does 4x upscale on pixs, using linear interpolation,
1160  *          followed by Floyd-Steinberg dithering to binary.
1161  *      (2) Buffers are used to avoid making a large grayscale image.
1162  *          ~ Two line buffers are used for the src, required for the
1163  *            4xLI upscale.
1164  *          ~ Five line buffers are used for the intermediate image.
1165  *            Four are filled with each 4xLI row operation; the fifth
1166  *            is needed because the upscale and dithering ops are
1167  *            out of sync.
1168  *      (3) If a full 4x expanded grayscale image can be kept in memory,
1169  *          this function is only about 5% faster than separately doing
1170  *          a linear interpolation to a large grayscale image, followed
1171  *          by error-diffusion dithering to binary.
1172  * </pre>
1173  */
1174 PIX *
pixScaleGray4xLIDither(PIX * pixs)1175 pixScaleGray4xLIDither(PIX  *pixs)
1176 {
1177 l_int32    i, j, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
1178 l_uint32  *datas, *datad;
1179 l_uint32  *lined;
1180 l_uint32  *lineb = NULL;   /* 4 intermediate buffer lines */
1181 l_uint32  *linebp = NULL;  /* 1 intermediate buffer line */
1182 l_uint32  *bufs = NULL;    /* 2 source buffer lines */
1183 PIX       *pixd = NULL;
1184 
1185     PROCNAME("pixScaleGray4xLIDither");
1186 
1187     if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
1188         return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
1189                                 procName, NULL);
1190 
1191     pixGetDimensions(pixs, &ws, &hs, NULL);
1192     wd = 4 * ws;
1193     hd = 4 * hs;
1194     hsm = hs - 1;
1195     datas = pixGetData(pixs);
1196     wpls = pixGetWpl(pixs);
1197 
1198         /* Make line buffers for 2 lines of src image */
1199     if ((bufs = (l_uint32 *)LEPT_CALLOC(2 * wpls, sizeof(l_uint32))) == NULL)
1200         return (PIX *)ERROR_PTR("bufs not made", procName, NULL);
1201 
1202         /* Make line buffer for 4 lines of virtual intermediate image */
1203     wplb = (wd + 3) / 4;
1204     if ((lineb = (l_uint32 *)LEPT_CALLOC(4 * wplb, sizeof(l_uint32))) == NULL) {
1205         L_ERROR("lineb not made\n", procName);
1206         goto cleanup;
1207     }
1208 
1209         /* Make line buffer for 1 line of virtual intermediate image */
1210     if ((linebp = (l_uint32 *)LEPT_CALLOC(wplb, sizeof(l_uint32))) == NULL) {
1211         L_ERROR("linebp not made\n", procName);
1212         goto cleanup;
1213     }
1214 
1215         /* Make dest binary image */
1216     if ((pixd = pixCreate(wd, hd, 1)) == NULL) {
1217         L_ERROR("pixd not made\n", procName);
1218         goto cleanup;
1219     }
1220     pixCopyInputFormat(pixd, pixs);
1221     pixCopyResolution(pixd, pixs);
1222     pixScaleResolution(pixd, 4.0, 4.0);
1223     wpld = pixGetWpl(pixd);
1224     datad = pixGetData(pixd);
1225 
1226         /* Start with the first src and the first 3 dest lines */
1227     memcpy(bufs, datas, 4 * wpls);   /* first src line */
1228     memcpy(bufs + wpls, datas + wpls, 4 * wpls);  /* 2nd src line */
1229     scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 0);  /* 4 b lines */
1230     lined = datad;
1231     for (j = 0; j < 3; j++) {  /* first 3 d lines of Q */
1232         ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb,
1233                               lineb + (j + 1) * wplb,
1234                               DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
1235     }
1236 
1237         /* Do all but last src line */
1238     for (i = 1; i < hsm; i++) {
1239         memcpy(bufs, datas + i * wpls, 4 * wpls);  /* i-th src line */
1240         memcpy(bufs + wpls, datas + (i + 1) * wpls, 4 * wpls);
1241         memcpy(linebp, lineb + 3 * wplb, 4 * wplb);
1242         scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 0);  /* 4 b lines */
1243         lined = datad + 4 * i * wpld;
1244         ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb,
1245                               DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
1246                                                      /* 4th dest line of Q */
1247         for (j = 0; j < 3; j++) {  /* next 3 d lines of Quad */
1248             ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb,
1249                                   lineb + (j + 1) * wplb,
1250                                  DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
1251         }
1252     }
1253 
1254         /* Do the last src line and the last 5 dest lines */
1255     memcpy(bufs, datas + hsm * wpls, 4 * wpls);  /* hsm-th src line */
1256     memcpy(linebp, lineb + 3 * wplb, 4 * wplb);   /* 1 b line */
1257     scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 1);  /* 4 b lines */
1258     lined = datad + 4 * hsm * wpld;
1259     ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb,
1260                           DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
1261                                                    /* 4th dest line of Q */
1262     for (j = 0; j < 3; j++) {  /* next 3 d lines of Quad */
1263         ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb,
1264                               lineb + (j + 1) * wplb,
1265                               DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 0);
1266     }
1267         /* And finally, the last dest line */
1268     ditherToBinaryLineLow(lined + 3 * wpld, wd, lineb + 3 * wplb, NULL,
1269                               DEFAULT_CLIP_LOWER_1, DEFAULT_CLIP_UPPER_1, 1);
1270 
1271 cleanup:
1272     LEPT_FREE(bufs);
1273     LEPT_FREE(lineb);
1274     LEPT_FREE(linebp);
1275     return pixd;
1276 }
1277 
1278 
1279 /*------------------------------------------------------------------*
1280  *                  Scaling by closest pixel sampling               *
1281  *------------------------------------------------------------------*/
1282 /*!
1283  * \brief   pixScaleBySampling()
1284  *
1285  * \param[in]    pixs 1, 2, 4, 8, 16, 32 bpp
1286  * \param[in]    scalex, scaley both > 0.0
1287  * \return  pixd, or NULL on error
1288  *
1289  * <pre>
1290  * Notes:
1291  *      (1) This function samples from the source without
1292  *          filtering.  As a result, aliasing will occur for
1293  *          subsampling (%scalex and/or %scaley < 1.0).
1294  *      (2) If %scalex == 1.0 and %scaley == 1.0, returns a copy.
1295  * </pre>
1296  */
1297 PIX *
pixScaleBySampling(PIX * pixs,l_float32 scalex,l_float32 scaley)1298 pixScaleBySampling(PIX       *pixs,
1299                    l_float32  scalex,
1300                    l_float32  scaley)
1301 {
1302 l_int32    ws, hs, d, wpls, wd, hd, wpld;
1303 l_uint32  *datas, *datad;
1304 PIX       *pixd;
1305 
1306     PROCNAME("pixScaleBySampling");
1307 
1308     if (!pixs)
1309         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1310     if (scalex <= 0.0 || scaley <= 0.0)
1311         return (PIX *)ERROR_PTR("scale factor <= 0", procName, NULL);
1312     if (scalex == 1.0 && scaley == 1.0)
1313         return pixCopy(NULL, pixs);
1314     if ((d = pixGetDepth(pixs)) == 1)
1315         return pixScaleBinary(pixs, scalex, scaley);
1316 
1317     pixGetDimensions(pixs, &ws, &hs, NULL);
1318     datas = pixGetData(pixs);
1319     wpls = pixGetWpl(pixs);
1320     wd = (l_int32)(scalex * (l_float32)ws + 0.5);
1321     hd = (l_int32)(scaley * (l_float32)hs + 0.5);
1322     if ((pixd = pixCreate(wd, hd, d)) == NULL)
1323         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1324     pixCopyResolution(pixd, pixs);
1325     pixScaleResolution(pixd, scalex, scaley);
1326     pixCopyColormap(pixd, pixs);
1327     pixCopyText(pixd, pixs);
1328     pixCopyInputFormat(pixd, pixs);
1329     pixCopySpp(pixd, pixs);
1330     datad = pixGetData(pixd);
1331     wpld = pixGetWpl(pixd);
1332     scaleBySamplingLow(datad, wd, hd, wpld, datas, ws, hs, d, wpls);
1333     if (d == 32 && pixGetSpp(pixs) == 4)
1334         pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley);
1335 
1336     return pixd;
1337 }
1338 
1339 
1340 /*!
1341  * \brief   pixScaleBySamplingToSize()
1342  *
1343  * \param[in]    pixs 1, 2, 4, 8, 16 and 32 bpp
1344  * \param[in]    wd  target width; use 0 if using height as target
1345  * \param[in]    hd  target height; use 0 if using width as target
1346  * \return  pixd, or NULL on error
1347  *
1348  * <pre>
1349  * Notes:
1350  *      (1) This guarantees that the output scaled image has the
1351  *          dimension(s) you specify.
1352  *           ~ To specify the width with isotropic scaling, set %hd = 0.
1353  *           ~ To specify the height with isotropic scaling, set %wd = 0.
1354  *           ~ If both %wd and %hd are specified, the image is scaled
1355  *             (in general, anisotropically) to that size.
1356  *           ~ It is an error to set both %wd and %hd to 0.
1357  * </pre>
1358  */
1359 PIX *
pixScaleBySamplingToSize(PIX * pixs,l_int32 wd,l_int32 hd)1360 pixScaleBySamplingToSize(PIX     *pixs,
1361                          l_int32  wd,
1362                          l_int32  hd)
1363 {
1364 l_int32    w, h;
1365 l_float32  scalex, scaley;
1366 
1367     PROCNAME("pixScaleBySamplingToSize");
1368 
1369     if (!pixs)
1370         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1371     if (wd <= 0 && hd <= 0)
1372         return (PIX *)ERROR_PTR("neither wd nor hd > 0", procName, NULL);
1373 
1374     pixGetDimensions(pixs, &w, &h, NULL);
1375     if (wd <= 0) {
1376         scaley = (l_float32)hd / (l_float32)h;
1377         scalex = scaley;
1378     } else if (hd <= 0) {
1379         scalex = (l_float32)wd / (l_float32)w;
1380         scaley = scalex;
1381     } else {
1382         scalex = (l_float32)wd / (l_float32)w;
1383         scaley = (l_float32)hd / (l_float32)h;
1384     }
1385 
1386     return pixScaleBySampling(pixs, scalex, scaley);
1387 }
1388 
1389 
1390 /*!
1391  * \brief   pixScaleByIntSampling()
1392  *
1393  * \param[in]    pixs 1, 2, 4, 8, 16, 32 bpp
1394  * \param[in]    factor integer subsampling
1395  * \return  pixd, or NULL on error
1396  *
1397  * <pre>
1398  * Notes:
1399  *      (1) Simple interface to pixScaleBySampling(), for
1400  *          isotropic integer reduction.
1401  *      (2) If %factor == 1, returns a copy.
1402  * </pre>
1403  */
1404 PIX *
pixScaleByIntSampling(PIX * pixs,l_int32 factor)1405 pixScaleByIntSampling(PIX     *pixs,
1406                       l_int32  factor)
1407 {
1408 l_float32  scale;
1409 
1410     PROCNAME("pixScaleByIntSampling");
1411 
1412     if (!pixs)
1413         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1414     if (factor <= 1) {
1415         if (factor < 1)
1416             L_ERROR("factor must be >= 1; returning a copy\n", procName);
1417         return pixCopy(NULL, pixs);
1418     }
1419 
1420     scale = 1. / (l_float32)factor;
1421     return pixScaleBySampling(pixs, scale, scale);
1422 }
1423 
1424 
1425 /*------------------------------------------------------------------*
1426  *            Fast integer factor subsampling RGB to gray           *
1427  *------------------------------------------------------------------*/
1428 /*!
1429  * \brief   pixScaleRGBToGrayFast()
1430  *
1431  * \param[in]    pixs 32 bpp rgb
1432  * \param[in]    factor integer reduction factor >= 1
1433  * \param[in]    color one of COLOR_RED, COLOR_GREEN, COLOR_BLUE
1434  * \return  pixd 8 bpp, or NULL on error
1435  *
1436  * <pre>
1437  * Notes:
1438  *      (1) This does simultaneous subsampling by an integer factor and
1439  *          extraction of the color from the RGB pix.
1440  *      (2) It is designed for maximum speed, and is used for quickly
1441  *          generating a downsized grayscale image from a higher resolution
1442  *          RGB image.  This would typically be used for image analysis.
1443  *      (3) The standard color byte order (RGBA) is assumed.
1444  * </pre>
1445  */
1446 PIX *
pixScaleRGBToGrayFast(PIX * pixs,l_int32 factor,l_int32 color)1447 pixScaleRGBToGrayFast(PIX     *pixs,
1448                       l_int32  factor,
1449                       l_int32  color)
1450 {
1451 l_int32    byteval, shift;
1452 l_int32    i, j, ws, hs, wd, hd, wpls, wpld;
1453 l_uint32  *datas, *words, *datad, *lined;
1454 l_float32  scale;
1455 PIX       *pixd;
1456 
1457     PROCNAME("pixScaleRGBToGrayFast");
1458 
1459     if (!pixs)
1460         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1461     if (pixGetDepth(pixs) != 32)
1462         return (PIX *)ERROR_PTR("depth not 32 bpp", procName, NULL);
1463     if (factor < 1)
1464         return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
1465 
1466     if (color == COLOR_RED)
1467         shift = L_RED_SHIFT;
1468     else if (color == COLOR_GREEN)
1469         shift = L_GREEN_SHIFT;
1470     else if (color == COLOR_BLUE)
1471         shift = L_BLUE_SHIFT;
1472     else
1473         return (PIX *)ERROR_PTR("invalid color", procName, NULL);
1474 
1475     pixGetDimensions(pixs, &ws, &hs, NULL);
1476     datas = pixGetData(pixs);
1477     wpls = pixGetWpl(pixs);
1478 
1479     wd = ws / factor;
1480     hd = hs / factor;
1481     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1482         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1483     pixCopyResolution(pixd, pixs);
1484     pixCopyInputFormat(pixd, pixs);
1485     scale = 1. / (l_float32) factor;
1486     pixScaleResolution(pixd, scale, scale);
1487     datad = pixGetData(pixd);
1488     wpld = pixGetWpl(pixd);
1489 
1490     for (i = 0; i < hd; i++) {
1491         words = datas + i * factor * wpls;
1492         lined = datad + i * wpld;
1493         for (j = 0; j < wd; j++, words += factor) {
1494             byteval = ((*words) >> shift) & 0xff;
1495             SET_DATA_BYTE(lined, j, byteval);
1496         }
1497     }
1498 
1499     return pixd;
1500 }
1501 
1502 
1503 /*!
1504  * \brief   pixScaleRGBToBinaryFast()
1505  *
1506  * \param[in]    pixs 32 bpp RGB
1507  * \param[in]    factor integer reduction factor >= 1
1508  * \param[in]    thresh binarization threshold
1509  * \return  pixd 1 bpp, or NULL on error
1510  *
1511  * <pre>
1512  * Notes:
1513  *      (1) This does simultaneous subsampling by an integer factor and
1514  *          conversion from RGB to gray to binary.
1515  *      (2) It is designed for maximum speed, and is used for quickly
1516  *          generating a downsized binary image from a higher resolution
1517  *          RGB image.  This would typically be used for image analysis.
1518  *      (3) It uses the green channel to represent the RGB pixel intensity.
1519  * </pre>
1520  */
1521 PIX *
pixScaleRGBToBinaryFast(PIX * pixs,l_int32 factor,l_int32 thresh)1522 pixScaleRGBToBinaryFast(PIX     *pixs,
1523                         l_int32  factor,
1524                         l_int32  thresh)
1525 {
1526 l_int32    byteval;
1527 l_int32    i, j, ws, hs, wd, hd, wpls, wpld;
1528 l_uint32  *datas, *words, *datad, *lined;
1529 l_float32  scale;
1530 PIX       *pixd;
1531 
1532     PROCNAME("pixScaleRGBToBinaryFast");
1533 
1534     if (!pixs)
1535         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1536     if (factor < 1)
1537         return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
1538     if (pixGetDepth(pixs) != 32)
1539         return (PIX *)ERROR_PTR("depth not 32 bpp", procName, NULL);
1540 
1541     pixGetDimensions(pixs, &ws, &hs, NULL);
1542     datas = pixGetData(pixs);
1543     wpls = pixGetWpl(pixs);
1544 
1545     wd = ws / factor;
1546     hd = hs / factor;
1547     if ((pixd = pixCreate(wd, hd, 1)) == NULL)
1548         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1549     pixCopyResolution(pixd, pixs);
1550     pixCopyInputFormat(pixd, pixs);
1551     scale = 1. / (l_float32) factor;
1552     pixScaleResolution(pixd, scale, scale);
1553     datad = pixGetData(pixd);
1554     wpld = pixGetWpl(pixd);
1555 
1556     for (i = 0; i < hd; i++) {
1557         words = datas + i * factor * wpls;
1558         lined = datad + i * wpld;
1559         for (j = 0; j < wd; j++, words += factor) {
1560             byteval = ((*words) >> L_GREEN_SHIFT) & 0xff;
1561             if (byteval < thresh)
1562                 SET_DATA_BIT(lined, j);
1563         }
1564     }
1565 
1566     return pixd;
1567 }
1568 
1569 
1570 /*!
1571  * \brief   pixScaleGrayToBinaryFast()
1572  *
1573  * \param[in]    pixs 8 bpp grayscale
1574  * \param[in]    factor integer reduction factor >= 1
1575  * \param[in]    thresh binarization threshold
1576  * \return  pixd 1 bpp, or NULL on error
1577  *
1578  * <pre>
1579  * Notes:
1580  *      (1) This does simultaneous subsampling by an integer factor and
1581  *          thresholding from gray to binary.
1582  *      (2) It is designed for maximum speed, and is used for quickly
1583  *          generating a downsized binary image from a higher resolution
1584  *          gray image.  This would typically be used for image analysis.
1585  * </pre>
1586  */
1587 PIX *
pixScaleGrayToBinaryFast(PIX * pixs,l_int32 factor,l_int32 thresh)1588 pixScaleGrayToBinaryFast(PIX     *pixs,
1589                          l_int32  factor,
1590                          l_int32  thresh)
1591 {
1592 l_int32    byteval;
1593 l_int32    i, j, ws, hs, wd, hd, wpls, wpld, sj;
1594 l_uint32  *datas, *datad, *lines, *lined;
1595 l_float32  scale;
1596 PIX       *pixd;
1597 
1598     PROCNAME("pixScaleGrayToBinaryFast");
1599 
1600     if (!pixs)
1601         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1602     if (factor < 1)
1603         return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
1604     if (pixGetDepth(pixs) != 8)
1605         return (PIX *)ERROR_PTR("depth not 8 bpp", procName, NULL);
1606 
1607     pixGetDimensions(pixs, &ws, &hs, NULL);
1608     datas = pixGetData(pixs);
1609     wpls = pixGetWpl(pixs);
1610 
1611     wd = ws / factor;
1612     hd = hs / factor;
1613     if ((pixd = pixCreate(wd, hd, 1)) == NULL)
1614         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1615     pixCopyResolution(pixd, pixs);
1616     pixCopyInputFormat(pixd, pixs);
1617     scale = 1. / (l_float32) factor;
1618     pixScaleResolution(pixd, scale, scale);
1619     datad = pixGetData(pixd);
1620     wpld = pixGetWpl(pixd);
1621 
1622     for (i = 0; i < hd; i++) {
1623         lines = datas + i * factor * wpls;
1624         lined = datad + i * wpld;
1625         for (j = 0, sj = 0; j < wd; j++, sj += factor) {
1626             byteval = GET_DATA_BYTE(lines, sj);
1627             if (byteval < thresh)
1628                 SET_DATA_BIT(lined, j);
1629         }
1630     }
1631 
1632     return pixd;
1633 }
1634 
1635 
1636 /*------------------------------------------------------------------*
1637  *               Downscaling with (antialias) smoothing             *
1638  *------------------------------------------------------------------*/
1639 /*!
1640  * \brief   pixScaleSmooth()
1641  *
1642  * \param[in]    pix 2, 4, 8 or 32 bpp; and 2, 4, 8 bpp with colormap
1643  * \param[in]    scalex, scaley must both be < 0.7
1644  * \return  pixd, or NULL on error
1645  *
1646  * <pre>
1647  * Notes:
1648  *      (1) This function should only be used when the scale factors are less
1649  *          than or equal to 0.7 (i.e., more than about 1.42x reduction).
1650  *          If either scale factor is larger than 0.7, we issue a warning
1651  *          and call pixScaleGeneral(), which will invoke linear
1652  *          interpolation without sharpening.
1653  *      (2) This works only on 2, 4, 8 and 32 bpp images, and if there is
1654  *          a colormap, it is removed by converting to RGB.  In other
1655  *          cases, we issue a warning and call pixScaleGeneral().
1656  *      (3) It does simple (flat filter) convolution, with a filter size
1657  *          commensurate with the amount of reduction, to avoid antialiasing.
1658  *      (4) It does simple subsampling after smoothing, which is appropriate
1659  *          for this range of scaling.  Linear interpolation gives essentially
1660  *          the same result with more computation for these scale factors,
1661  *          so we don't use it.
1662  *      (5) The result is the same as doing a full block convolution followed by
1663  *          subsampling, but this is faster because the results of the block
1664  *          convolution are only computed at the subsampling locations.
1665  *          In fact, the computation time is approximately independent of
1666  *          the scale factor, because the convolution kernel is adjusted
1667  *          so that each source pixel is summed approximately once.
1668  * </pre>
1669  */
1670 PIX *
pixScaleSmooth(PIX * pix,l_float32 scalex,l_float32 scaley)1671 pixScaleSmooth(PIX       *pix,
1672                l_float32  scalex,
1673                l_float32  scaley)
1674 {
1675 l_int32    ws, hs, d, wd, hd, wpls, wpld, isize;
1676 l_uint32  *datas, *datad;
1677 l_float32  minscale, size;
1678 PIX       *pixs, *pixd;
1679 
1680     PROCNAME("pixScaleSmooth");
1681 
1682     if (!pix)
1683         return (PIX *)ERROR_PTR("pix not defined", procName, NULL);
1684     if (scalex >= 0.7 || scaley >= 0.7) {
1685         L_WARNING("scaling factor not < 0.7; do regular scaling\n", procName);
1686         return pixScaleGeneral(pix, scalex, scaley, 0.0, 0);
1687     }
1688 
1689         /* Remove colormap if necessary.
1690          * If 2 bpp or 4 bpp gray, convert to 8 bpp */
1691     d = pixGetDepth(pix);
1692     if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
1693         L_WARNING("pix has colormap; removing\n", procName);
1694         pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC);
1695         d = pixGetDepth(pixs);
1696     } else if (d == 2 || d == 4) {
1697         pixs = pixConvertTo8(pix, FALSE);
1698         d = 8;
1699     } else {
1700         pixs = pixClone(pix);
1701     }
1702 
1703     if (d != 8 && d != 32) {   /* d == 1 or d == 16 */
1704         L_WARNING("depth not 8 or 32 bpp; do regular scaling\n", procName);
1705         pixDestroy(&pixs);
1706         return pixScaleGeneral(pix, scalex, scaley, 0.0, 0);
1707     }
1708 
1709         /* If 1.42 < 1/minscale < 2.5, use isize = 2
1710          * If 2.5 =< 1/minscale < 3.5, use isize = 3, etc.
1711          * Under no conditions use isize < 2  */
1712     minscale = L_MIN(scalex, scaley);
1713     size = 1.0 / minscale;   /* ideal filter full width */
1714     isize = L_MAX(2, (l_int32)(size + 0.5));
1715 
1716     pixGetDimensions(pixs, &ws, &hs, NULL);
1717     if ((ws < isize) || (hs < isize)) {
1718         pixDestroy(&pixs);
1719         return (PIX *)ERROR_PTR("pixs too small", procName, NULL);
1720     }
1721     datas = pixGetData(pixs);
1722     wpls = pixGetWpl(pixs);
1723     wd = (l_int32)(scalex * (l_float32)ws + 0.5);
1724     hd = (l_int32)(scaley * (l_float32)hs + 0.5);
1725     if (wd < 1 || hd < 1) {
1726         pixDestroy(&pixs);
1727         return (PIX *)ERROR_PTR("pixd too small", procName, NULL);
1728     }
1729     if ((pixd = pixCreate(wd, hd, d)) == NULL) {
1730         pixDestroy(&pixs);
1731         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1732     }
1733     pixCopyResolution(pixd, pixs);
1734     pixCopyInputFormat(pixd, pixs);
1735     pixScaleResolution(pixd, scalex, scaley);
1736     datad = pixGetData(pixd);
1737     wpld = pixGetWpl(pixd);
1738     scaleSmoothLow(datad, wd, hd, wpld, datas, ws, hs, d, wpls, isize);
1739     if (d == 32 && pixGetSpp(pixs) == 4)
1740         pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley);
1741 
1742     pixDestroy(&pixs);
1743     return pixd;
1744 }
1745 
1746 
1747 /*!
1748  * \brief   pixScaleSmoothToSize()
1749  *
1750  * \param[in]    pix 2, 4, 8 or 32 bpp; and 2, 4, 8 bpp with colormap
1751  * \param[in]    wd  target width; use 0 if using height as target
1752  * \param[in]    hd  target height; use 0 if using width as target
1753  * \return  pixd, or NULL on error
1754  *
1755  * <pre>
1756  * Notes:
1757  *      (1) See notes in pixScaleSmooth().
1758  *      (2) The output scaled image has the dimension(s) you specify:
1759  *          * To specify the width with isotropic scaling, set %hd = 0.
1760  *          * To specify the height with isotropic scaling, set %wd = 0.
1761  *          * If both %wd and %hd are specified, the image is scaled
1762  *             (in general, anisotropically) to that size.
1763  *          * It is an error to set both %wd and %hd to 0.
1764  * </pre>
1765  */
1766 PIX *
pixScaleSmoothToSize(PIX * pixs,l_int32 wd,l_int32 hd)1767 pixScaleSmoothToSize(PIX     *pixs,
1768                      l_int32  wd,
1769                      l_int32  hd)
1770 {
1771 l_int32    w, h;
1772 l_float32  scalex, scaley;
1773 
1774     PROCNAME("pixScaleSmoothToSize");
1775 
1776     if (!pixs)
1777         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1778     if (wd <= 0 && hd <= 0)
1779         return (PIX *)ERROR_PTR("neither wd nor hd > 0", procName, NULL);
1780 
1781     pixGetDimensions(pixs, &w, &h, NULL);
1782     if (wd <= 0) {
1783         scaley = (l_float32)hd / (l_float32)h;
1784         scalex = scaley;
1785     } else if (hd <= 0) {
1786         scalex = (l_float32)wd / (l_float32)w;
1787         scaley = scalex;
1788     } else {
1789         scalex = (l_float32)wd / (l_float32)w;
1790         scaley = (l_float32)hd / (l_float32)h;
1791     }
1792 
1793     return pixScaleSmooth(pixs, scalex, scaley);
1794 }
1795 
1796 
1797 /*!
1798  * \brief   pixScaleRGBToGray2()
1799  *
1800  * \param[in]    pixs 32 bpp rgb
1801  * \param[in]    rwt, gwt, bwt must sum to 1.0
1802  * \return  pixd, 8 bpp, 2x reduced, or NULL on error
1803  */
1804 PIX *
pixScaleRGBToGray2(PIX * pixs,l_float32 rwt,l_float32 gwt,l_float32 bwt)1805 pixScaleRGBToGray2(PIX       *pixs,
1806                    l_float32  rwt,
1807                    l_float32  gwt,
1808                    l_float32  bwt)
1809 {
1810 l_int32    wd, hd, wpls, wpld;
1811 l_uint32  *datas, *datad;
1812 PIX       *pixd;
1813 
1814     PROCNAME("pixScaleRGBToGray2");
1815 
1816     if (!pixs)
1817         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1818     if (pixGetDepth(pixs) != 32)
1819         return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
1820     if (rwt + gwt + bwt < 0.98 || rwt + gwt + bwt > 1.02)
1821         return (PIX *)ERROR_PTR("sum of wts should be 1.0", procName, NULL);
1822 
1823     wd = pixGetWidth(pixs) / 2;
1824     hd = pixGetHeight(pixs) / 2;
1825     wpls = pixGetWpl(pixs);
1826     datas = pixGetData(pixs);
1827     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1828         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1829     pixCopyResolution(pixd, pixs);
1830     pixCopyInputFormat(pixd, pixs);
1831     pixScaleResolution(pixd, 0.5, 0.5);
1832     wpld = pixGetWpl(pixd);
1833     datad = pixGetData(pixd);
1834     scaleRGBToGray2Low(datad, wd, hd, wpld, datas, wpls, rwt, gwt, bwt);
1835     return pixd;
1836 }
1837 
1838 
1839 /*------------------------------------------------------------------*
1840  *             Downscaling with (antialias) area mapping            *
1841  *------------------------------------------------------------------*/
1842 /*!
1843  * \brief   pixScaleAreaMap()
1844  *
1845  * \param[in]    pix 2, 4, 8 or 32 bpp; and 2, 4, 8 bpp with colormap
1846  * \param[in]    scalex, scaley must both be <= 0.7
1847  * \return  pixd, or NULL on error
1848  *
1849  * <pre>
1850  * Notes:
1851  *      (1) This function should only be used when the scale factors are less
1852  *          than or equal to 0.7 (i.e., more than about 1.42x reduction).
1853  *          If either scale factor is larger than 0.7, we issue a warning
1854  *          and call pixScaleGeneral(), which will invoke linear
1855  *          interpolation without sharpening.
1856  *      (2) This works only on 2, 4, 8 and 32 bpp images.  If there is
1857  *          a colormap, it is removed by converting to RGB.  In other
1858  *          cases, we issue a warning and call pixScaleGeneral().
1859  *      (3) This is faster than pixScale() because it does not do sharpening.
1860  *      (4) It does a relatively expensive area mapping computation, to
1861  *          avoid antialiasing.  It is about 2x slower than pixScaleSmooth(),
1862  *          but the results are much better on fine text.
1863  *      (5) This is typically about 20% faster for the special cases of
1864  *          2x, 4x, 8x and 16x reduction.
1865  *      (6) Surprisingly, there is no speedup (and a slight quality
1866  *          impairment) if you do as many successive 2x reductions as
1867  *          possible, ending with a reduction with a scale factor larger
1868  *          than 0.5.
1869  * </pre>
1870  */
1871 PIX *
pixScaleAreaMap(PIX * pix,l_float32 scalex,l_float32 scaley)1872 pixScaleAreaMap(PIX       *pix,
1873                 l_float32  scalex,
1874                 l_float32  scaley)
1875 {
1876 l_int32    ws, hs, d, wd, hd, wpls, wpld;
1877 l_uint32  *datas, *datad;
1878 l_float32  maxscale;
1879 PIX       *pixs, *pixd, *pixt1, *pixt2, *pixt3;
1880 
1881     PROCNAME("pixScaleAreaMap");
1882 
1883     if (!pix)
1884         return (PIX *)ERROR_PTR("pix not defined", procName, NULL);
1885     d = pixGetDepth(pix);
1886     if (d != 2 && d != 4 && d != 8 && d != 32)
1887         return (PIX *)ERROR_PTR("pix not 2, 4, 8 or 32 bpp", procName, NULL);
1888     maxscale = L_MAX(scalex, scaley);
1889     if (maxscale >= 0.7) {
1890         L_WARNING("scaling factors not < 0.7; do regular scaling\n", procName);
1891         return pixScaleGeneral(pix, scalex, scaley, 0.0, 0);
1892     }
1893 
1894         /* Special cases: 2x, 4x, 8x, 16x reduction */
1895     if (scalex == 0.5 && scaley == 0.5)
1896         return pixScaleAreaMap2(pix);
1897     if (scalex == 0.25 && scaley == 0.25) {
1898         pixt1 = pixScaleAreaMap2(pix);
1899         pixd = pixScaleAreaMap2(pixt1);
1900         pixDestroy(&pixt1);
1901         return pixd;
1902     }
1903     if (scalex == 0.125 && scaley == 0.125) {
1904         pixt1 = pixScaleAreaMap2(pix);
1905         pixt2 = pixScaleAreaMap2(pixt1);
1906         pixd = pixScaleAreaMap2(pixt2);
1907         pixDestroy(&pixt1);
1908         pixDestroy(&pixt2);
1909         return pixd;
1910     }
1911     if (scalex == 0.0625 && scaley == 0.0625) {
1912         pixt1 = pixScaleAreaMap2(pix);
1913         pixt2 = pixScaleAreaMap2(pixt1);
1914         pixt3 = pixScaleAreaMap2(pixt2);
1915         pixd = pixScaleAreaMap2(pixt3);
1916         pixDestroy(&pixt1);
1917         pixDestroy(&pixt2);
1918         pixDestroy(&pixt3);
1919         return pixd;
1920     }
1921 
1922         /* Remove colormap if necessary.
1923          * If 2 bpp or 4 bpp gray, convert to 8 bpp */
1924     if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
1925         L_WARNING("pix has colormap; removing\n", procName);
1926         pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC);
1927         d = pixGetDepth(pixs);
1928     } else if (d == 2 || d == 4) {
1929         pixs = pixConvertTo8(pix, FALSE);
1930         d = 8;
1931     } else {
1932         pixs = pixClone(pix);
1933     }
1934 
1935     pixGetDimensions(pixs, &ws, &hs, NULL);
1936     datas = pixGetData(pixs);
1937     wpls = pixGetWpl(pixs);
1938     wd = (l_int32)(scalex * (l_float32)ws + 0.5);
1939     hd = (l_int32)(scaley * (l_float32)hs + 0.5);
1940     if (wd < 1 || hd < 1) {
1941         pixDestroy(&pixs);
1942         return (PIX *)ERROR_PTR("pixd too small", procName, NULL);
1943     }
1944     if ((pixd = pixCreate(wd, hd, d)) == NULL) {
1945         pixDestroy(&pixs);
1946         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1947     }
1948     pixCopyInputFormat(pixd, pixs);
1949     pixCopyResolution(pixd, pixs);
1950     pixScaleResolution(pixd, scalex, scaley);
1951     datad = pixGetData(pixd);
1952     wpld = pixGetWpl(pixd);
1953     if (d == 8) {
1954         scaleGrayAreaMapLow(datad, wd, hd, wpld, datas, ws, hs, wpls);
1955     } else {  /* RGB, d == 32 */
1956         scaleColorAreaMapLow(datad, wd, hd, wpld, datas, ws, hs, wpls);
1957         if (pixGetSpp(pixs) == 4)
1958             pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley);
1959     }
1960 
1961     pixDestroy(&pixs);
1962     return pixd;
1963 }
1964 
1965 
1966 /*!
1967  * \brief   pixScaleAreaMap2()
1968  *
1969  * \param[in]    pix 2, 4, 8 or 32 bpp; and 2, 4, 8 bpp with colormap
1970  * \return  pixd, or NULL on error
1971  *
1972  * <pre>
1973  * Notes:
1974  *      (1) This function does an area mapping (average) for 2x
1975  *          reduction.
1976  *      (2) This works only on 2, 4, 8 and 32 bpp images.  If there is
1977  *          a colormap, it is removed by converting to RGB.
1978  *      (3) Speed on 3 GHz processor:
1979  *             Color: 160 Mpix/sec
1980  *             Gray: 700 Mpix/sec
1981  *          This contrasts with the speed of the general pixScaleAreaMap():
1982  *             Color: 35 Mpix/sec
1983  *             Gray: 50 Mpix/sec
1984  *      (4) From (3), we see that this special function is about 4.5x
1985  *          faster for color and 14x faster for grayscale
1986  *      (5) Consequently, pixScaleAreaMap2() is incorporated into the
1987  *          general area map scaling function, for the special cases
1988  *          of 2x, 4x, 8x and 16x reduction.
1989  * </pre>
1990  */
1991 PIX *
pixScaleAreaMap2(PIX * pix)1992 pixScaleAreaMap2(PIX  *pix)
1993 {
1994 l_int32    wd, hd, d, wpls, wpld;
1995 l_uint32  *datas, *datad;
1996 PIX       *pixs, *pixd;
1997 
1998     PROCNAME("pixScaleAreaMap2");
1999 
2000     if (!pix)
2001         return (PIX *)ERROR_PTR("pix not defined", procName, NULL);
2002     d = pixGetDepth(pix);
2003     if (d != 2 && d != 4 && d != 8 && d != 32)
2004         return (PIX *)ERROR_PTR("pix not 2, 4, 8 or 32 bpp", procName, NULL);
2005 
2006         /* Remove colormap if necessary.
2007          * If 2 bpp or 4 bpp gray, convert to 8 bpp */
2008     if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
2009         L_WARNING("pix has colormap; removing\n", procName);
2010         pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC);
2011         d = pixGetDepth(pixs);
2012     } else if (d == 2 || d == 4) {
2013         pixs = pixConvertTo8(pix, FALSE);
2014         d = 8;
2015     } else {
2016         pixs = pixClone(pix);
2017     }
2018 
2019     wd = pixGetWidth(pixs) / 2;
2020     hd = pixGetHeight(pixs) / 2;
2021     datas = pixGetData(pixs);
2022     wpls = pixGetWpl(pixs);
2023     pixd = pixCreate(wd, hd, d);
2024     datad = pixGetData(pixd);
2025     wpld = pixGetWpl(pixd);
2026     pixCopyInputFormat(pixd, pixs);
2027     pixCopyResolution(pixd, pixs);
2028     pixScaleResolution(pixd, 0.5, 0.5);
2029     scaleAreaMapLow2(datad, wd, hd, wpld, datas, d, wpls);
2030     if (pixGetSpp(pixs) == 4)
2031         pixScaleAndTransferAlpha(pixd, pixs, 0.5, 0.5);
2032     pixDestroy(&pixs);
2033     return pixd;
2034 }
2035 
2036 
2037 /*!
2038  * \brief   pixScaleAreaMapToSize()
2039  *
2040  * \param[in]    pix 2, 4, 8 or 32 bpp; and 2, 4, 8 bpp with colormap
2041  * \param[in]    wd  target width; use 0 if using height as target
2042  * \param[in]    hd  target height; use 0 if using width as target
2043  * \return  pixd, or NULL on error
2044  *
2045  * <pre>
2046  * Notes:
2047  *      (1) See notes in pixScaleAreaMap().
2048  *      (2) The output scaled image has the dimension(s) you specify:
2049  *          * To specify the width with isotropic scaling, set %hd = 0.
2050  *          * To specify the height with isotropic scaling, set %wd = 0.
2051  *          * If both %wd and %hd are specified, the image is scaled
2052  *             (in general, anisotropically) to that size.
2053  *          * It is an error to set both %wd and %hd to 0.
2054  * </pre>
2055  */
2056 PIX *
pixScaleAreaMapToSize(PIX * pixs,l_int32 wd,l_int32 hd)2057 pixScaleAreaMapToSize(PIX     *pixs,
2058                       l_int32  wd,
2059                       l_int32  hd)
2060 {
2061 l_int32    w, h;
2062 l_float32  scalex, scaley;
2063 
2064     PROCNAME("pixScaleAreaMapToSize");
2065 
2066     if (!pixs)
2067         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2068     if (wd <= 0 && hd <= 0)
2069         return (PIX *)ERROR_PTR("neither wd nor hd > 0", procName, NULL);
2070 
2071     pixGetDimensions(pixs, &w, &h, NULL);
2072     if (wd <= 0) {
2073         scaley = (l_float32)hd / (l_float32)h;
2074         scalex = scaley;
2075     } else if (hd <= 0) {
2076         scalex = (l_float32)wd / (l_float32)w;
2077         scaley = scalex;
2078     } else {
2079         scalex = (l_float32)wd / (l_float32)w;
2080         scaley = (l_float32)hd / (l_float32)h;
2081     }
2082 
2083     return pixScaleAreaMap(pixs, scalex, scaley);
2084 }
2085 
2086 
2087 /*------------------------------------------------------------------*
2088  *               Binary scaling by closest pixel sampling           *
2089  *------------------------------------------------------------------*/
2090 /*!
2091  * \brief   pixScaleBinary()
2092  *
2093  * \param[in]    pixs 1 bpp
2094  * \param[in]    scalex, scaley both > 0.0
2095  * \return  pixd, or NULL on error
2096  *
2097  * <pre>
2098  * Notes:
2099  *      (1) This function samples from the source without
2100  *          filtering.  As a result, aliasing will occur for
2101  *          subsampling (scalex and scaley < 1.0).
2102  * </pre>
2103  */
2104 PIX *
pixScaleBinary(PIX * pixs,l_float32 scalex,l_float32 scaley)2105 pixScaleBinary(PIX       *pixs,
2106                l_float32  scalex,
2107                l_float32  scaley)
2108 {
2109 l_int32    ws, hs, wpls, wd, hd, wpld;
2110 l_uint32  *datas, *datad;
2111 PIX       *pixd;
2112 
2113     PROCNAME("pixScaleBinary");
2114 
2115     if (!pixs)
2116         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2117     if (pixGetDepth(pixs) != 1)
2118         return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, NULL);
2119     if (scalex <= 0.0 || scaley <= 0.0)
2120         return (PIX *)ERROR_PTR("scale factor <= 0", procName, NULL);
2121     if (scalex == 1.0 && scaley == 1.0)
2122         return pixCopy(NULL, pixs);
2123 
2124     pixGetDimensions(pixs, &ws, &hs, NULL);
2125     datas = pixGetData(pixs);
2126     wpls = pixGetWpl(pixs);
2127     wd = (l_int32)(scalex * (l_float32)ws + 0.5);
2128     hd = (l_int32)(scaley * (l_float32)hs + 0.5);
2129     if ((pixd = pixCreate(wd, hd, 1)) == NULL)
2130         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2131     pixCopyColormap(pixd, pixs);
2132     pixCopyText(pixd, pixs);
2133     pixCopyInputFormat(pixd, pixs);
2134     pixCopyResolution(pixd, pixs);
2135     pixScaleResolution(pixd, scalex, scaley);
2136     datad = pixGetData(pixd);
2137     wpld = pixGetWpl(pixd);
2138     scaleBinaryLow(datad, wd, hd, wpld, datas, ws, hs, wpls);
2139     return pixd;
2140 }
2141 
2142 
2143 /* ================================================================ *
2144  *                    Low level static functions                    *
2145  * ================================================================ */
2146 
2147 /*------------------------------------------------------------------*
2148  *            General linear interpolated color scaling             *
2149  *------------------------------------------------------------------*/
2150 /*!
2151  * \brief   scaleColorLILow()
2152  *
2153  *  We choose to divide each pixel into 16 x 16 sub-pixels.
2154  *  Linear interpolation is equivalent to finding the
2155  *  fractional area (i.e., number of sub-pixels divided
2156  *  by 256) associated with each of the four nearest src pixels,
2157  *  and weighting each pixel value by this fractional area.
2158  *
2159  *  P3 speed is about 7 x 10^6 dst pixels/sec/GHz
2160  */
2161 static void
scaleColorLILow(l_uint32 * datad,l_int32 wd,l_int32 hd,l_int32 wpld,l_uint32 * datas,l_int32 ws,l_int32 hs,l_int32 wpls)2162 scaleColorLILow(l_uint32  *datad,
2163                l_int32    wd,
2164                l_int32    hd,
2165                l_int32    wpld,
2166                l_uint32  *datas,
2167                l_int32    ws,
2168                l_int32    hs,
2169                l_int32    wpls)
2170 {
2171 l_int32    i, j, wm2, hm2;
2172 l_int32    xpm, ypm;  /* location in src image, to 1/16 of a pixel */
2173 l_int32    xp, yp, xf, yf;  /* src pixel and pixel fraction coordinates */
2174 l_int32    v00r, v01r, v10r, v11r, v00g, v01g, v10g, v11g;
2175 l_int32    v00b, v01b, v10b, v11b, area00, area01, area10, area11;
2176 l_uint32   pixels1, pixels2, pixels3, pixels4, pixel;
2177 l_uint32  *lines, *lined;
2178 l_float32  scx, scy;
2179 
2180         /* (scx, scy) are scaling factors that are applied to the
2181          * dest coords to get the corresponding src coords.
2182          * We need them because we iterate over dest pixels
2183          * and must find the corresponding set of src pixels. */
2184     scx = 16. * (l_float32)ws / (l_float32)wd;
2185     scy = 16. * (l_float32)hs / (l_float32)hd;
2186     wm2 = ws - 2;
2187     hm2 = hs - 2;
2188 
2189         /* Iterate over the destination pixels */
2190     for (i = 0; i < hd; i++) {
2191         ypm = (l_int32)(scy * (l_float32)i);
2192         yp = ypm >> 4;
2193         yf = ypm & 0x0f;
2194         lined = datad + i * wpld;
2195         lines = datas + yp * wpls;
2196         for (j = 0; j < wd; j++) {
2197             xpm = (l_int32)(scx * (l_float32)j);
2198             xp = xpm >> 4;
2199             xf = xpm & 0x0f;
2200 
2201                 /* Do bilinear interpolation.  This is a simple
2202                  * generalization of the calculation in scaleGrayLILow().
2203                  * Without this, we could simply subsample:
2204                  *     *(lined + j) = *(lines + xp);
2205                  * which is faster but gives lousy results!  */
2206             pixels1 = *(lines + xp);
2207 
2208             if (xp > wm2 || yp > hm2) {
2209                 if (yp > hm2 && xp <= wm2) {  /* pixels near bottom */
2210                     pixels2 = *(lines + xp + 1);
2211                     pixels3 = pixels1;
2212                     pixels4 = pixels2;
2213                 } else if (xp > wm2 && yp <= hm2) {  /* pixels near rt side */
2214                     pixels2 = pixels1;
2215                     pixels3 = *(lines + wpls + xp);
2216                     pixels4 = pixels3;
2217                 } else {  /* pixels at LR corner */
2218                     pixels4 = pixels3 = pixels2 = pixels1;
2219                 }
2220             } else {
2221                 pixels2 = *(lines + xp + 1);
2222                 pixels3 = *(lines + wpls + xp);
2223                 pixels4 = *(lines + wpls + xp + 1);
2224             }
2225 
2226             area00 = (16 - xf) * (16 - yf);
2227             area10 = xf * (16 - yf);
2228             area01 = (16 - xf) * yf;
2229             area11 = xf * yf;
2230             v00r = area00 * ((pixels1 >> L_RED_SHIFT) & 0xff);
2231             v00g = area00 * ((pixels1 >> L_GREEN_SHIFT) & 0xff);
2232             v00b = area00 * ((pixels1 >> L_BLUE_SHIFT) & 0xff);
2233             v10r = area10 * ((pixels2 >> L_RED_SHIFT) & 0xff);
2234             v10g = area10 * ((pixels2 >> L_GREEN_SHIFT) & 0xff);
2235             v10b = area10 * ((pixels2 >> L_BLUE_SHIFT) & 0xff);
2236             v01r = area01 * ((pixels3 >> L_RED_SHIFT) & 0xff);
2237             v01g = area01 * ((pixels3 >> L_GREEN_SHIFT) & 0xff);
2238             v01b = area01 * ((pixels3 >> L_BLUE_SHIFT) & 0xff);
2239             v11r = area11 * ((pixels4 >> L_RED_SHIFT) & 0xff);
2240             v11g = area11 * ((pixels4 >> L_GREEN_SHIFT) & 0xff);
2241             v11b = area11 * ((pixels4 >> L_BLUE_SHIFT) & 0xff);
2242             pixel = (((v00r + v10r + v01r + v11r + 128) << 16) & 0xff000000) |
2243                     (((v00g + v10g + v01g + v11g + 128) << 8) & 0x00ff0000) |
2244                     ((v00b + v10b + v01b + v11b + 128) & 0x0000ff00);
2245             *(lined + j) = pixel;
2246         }
2247     }
2248 }
2249 
2250 
2251 /*------------------------------------------------------------------*
2252  *            General linear interpolated gray scaling              *
2253  *------------------------------------------------------------------*/
2254 /*!
2255  * \brief   scaleGrayLILow()
2256  *
2257  *  We choose to divide each pixel into 16 x 16 sub-pixels.
2258  *  Linear interpolation is equivalent to finding the
2259  *  fractional area (i.e., number of sub-pixels divided
2260  *  by 256) associated with each of the four nearest src pixels,
2261  *  and weighting each pixel value by this fractional area.
2262  */
2263 static void
scaleGrayLILow(l_uint32 * datad,l_int32 wd,l_int32 hd,l_int32 wpld,l_uint32 * datas,l_int32 ws,l_int32 hs,l_int32 wpls)2264 scaleGrayLILow(l_uint32  *datad,
2265                l_int32    wd,
2266                l_int32    hd,
2267                l_int32    wpld,
2268                l_uint32  *datas,
2269                l_int32    ws,
2270                l_int32    hs,
2271                l_int32    wpls)
2272 {
2273 l_int32    i, j, wm2, hm2;
2274 l_int32    xpm, ypm;  /* location in src image, to 1/16 of a pixel */
2275 l_int32    xp, yp, xf, yf;  /* src pixel and pixel fraction coordinates */
2276 l_int32    v00, v01, v10, v11, v00_val, v01_val, v10_val, v11_val;
2277 l_uint8    val;
2278 l_uint32  *lines, *lined;
2279 l_float32  scx, scy;
2280 
2281         /* (scx, scy) are scaling factors that are applied to the
2282          * dest coords to get the corresponding src coords.
2283          * We need them because we iterate over dest pixels
2284          * and must find the corresponding set of src pixels. */
2285     scx = 16. * (l_float32)ws / (l_float32)wd;
2286     scy = 16. * (l_float32)hs / (l_float32)hd;
2287     wm2 = ws - 2;
2288     hm2 = hs - 2;
2289 
2290         /* Iterate over the destination pixels */
2291     for (i = 0; i < hd; i++) {
2292         ypm = (l_int32)(scy * (l_float32)i);
2293         yp = ypm >> 4;
2294         yf = ypm & 0x0f;
2295         lined = datad + i * wpld;
2296         lines = datas + yp * wpls;
2297         for (j = 0; j < wd; j++) {
2298             xpm = (l_int32)(scx * (l_float32)j);
2299             xp = xpm >> 4;
2300             xf = xpm & 0x0f;
2301 
2302                 /* Do bilinear interpolation.  Without this, we could
2303                  * simply subsample:
2304                  *   SET_DATA_BYTE(lined, j, GET_DATA_BYTE(lines, xp));
2305                  * which is faster but gives lousy results!  */
2306             v00_val = GET_DATA_BYTE(lines, xp);
2307             if (xp > wm2 || yp > hm2) {
2308                 if (yp > hm2 && xp <= wm2) {  /* pixels near bottom */
2309                     v01_val = v00_val;
2310                     v10_val = GET_DATA_BYTE(lines, xp + 1);
2311                     v11_val = v10_val;
2312                 } else if (xp > wm2 && yp <= hm2) {  /* pixels near rt side */
2313                     v01_val = GET_DATA_BYTE(lines + wpls, xp);
2314                     v10_val = v00_val;
2315                     v11_val = v01_val;
2316                 } else {  /* pixels at LR corner */
2317                     v10_val = v01_val = v11_val = v00_val;
2318                 }
2319             } else {
2320                 v10_val = GET_DATA_BYTE(lines, xp + 1);
2321                 v01_val = GET_DATA_BYTE(lines + wpls, xp);
2322                 v11_val = GET_DATA_BYTE(lines + wpls, xp + 1);
2323             }
2324 
2325             v00 = (16 - xf) * (16 - yf) * v00_val;
2326             v10 = xf * (16 - yf) * v10_val;
2327             v01 = (16 - xf) * yf * v01_val;
2328             v11 = xf * yf * v11_val;
2329 
2330             val = (l_uint8)((v00 + v01 + v10 + v11 + 128) / 256);
2331             SET_DATA_BYTE(lined, j, val);
2332         }
2333     }
2334 }
2335 
2336 
2337 /*------------------------------------------------------------------*
2338  *                2x linear interpolated color scaling              *
2339  *------------------------------------------------------------------*/
2340 /*!
2341  * \brief   scaleColor2xLILow()
2342  *
2343  *  This is a special case of 2x expansion by linear
2344  *  interpolation.  Each src pixel contains 4 dest pixels.
2345  *  The 4 dest pixels in src pixel 1 are numbered at
2346  *  their UL corners.  The 4 dest pixels in src pixel 1
2347  *  are related to that src pixel and its 3 neighboring
2348  *  src pixels as follows:
2349  *
2350  *             1-----2-----|-----|-----|
2351  *             |     |     |     |     |
2352  *             |     |     |     |     |
2353  *  src 1 -->  3-----4-----|     |     |  <-- src 2
2354  *             |     |     |     |     |
2355  *             |     |     |     |     |
2356  *             |-----|-----|-----|-----|
2357  *             |     |     |     |     |
2358  *             |     |     |     |     |
2359  *  src 3 -->  |     |     |     |     |  <-- src 4
2360  *             |     |     |     |     |
2361  *             |     |     |     |     |
2362  *             |-----|-----|-----|-----|
2363  *
2364  *           dest      src
2365  *           ----      ---
2366  *           dp1    =  sp1
2367  *           dp2    =  (sp1 + sp2) / 2
2368  *           dp3    =  (sp1 + sp3) / 2
2369  *           dp4    =  (sp1 + sp2 + sp3 + sp4) / 4
2370  *
2371  *  We iterate over the src pixels, and unroll the calculation
2372  *  for each set of 4 dest pixels corresponding to that src
2373  *  pixel, caching pixels for the next src pixel whenever possible.
2374  *  The method is exactly analogous to the one we use for
2375  *  scaleGray2xLILow() and its line version.
2376  *
2377  *  P3 speed is about 5 x 10^7 dst pixels/sec/GHz
2378  */
2379 static void
scaleColor2xLILow(l_uint32 * datad,l_int32 wpld,l_uint32 * datas,l_int32 ws,l_int32 hs,l_int32 wpls)2380 scaleColor2xLILow(l_uint32  *datad,
2381                   l_int32    wpld,
2382                   l_uint32  *datas,
2383                   l_int32    ws,
2384                   l_int32    hs,
2385                   l_int32    wpls)
2386 {
2387 l_int32    i, hsm;
2388 l_uint32  *lines, *lined;
2389 
2390     hsm = hs - 1;
2391 
2392         /* We're taking 2 src and 2 dest lines at a time,
2393          * and for each src line, we're computing 2 dest lines.
2394          * Call these 2 dest lines:  destline1 and destline2.
2395          * The first src line is used for destline 1.
2396          * On all but the last src line, both src lines are
2397          * used in the linear interpolation for destline2.
2398          * On the last src line, both destline1 and destline2
2399          * are computed using only that src line (because there
2400          * isn't a lower src line). */
2401 
2402         /* iterate over all but the last src line */
2403     for (i = 0; i < hsm; i++) {
2404         lines = datas + i * wpls;
2405         lined = datad + 2 * i * wpld;
2406         scaleColor2xLILineLow(lined, wpld, lines, ws, wpls, 0);
2407     }
2408 
2409         /* last src line */
2410     lines = datas + hsm * wpls;
2411     lined = datad + 2 * hsm * wpld;
2412     scaleColor2xLILineLow(lined, wpld, lines, ws, wpls, 1);
2413 }
2414 
2415 
2416 /*!
2417  * \brief   scaleColor2xLILineLow()
2418  *
2419  * \param[in]    lined   ptr to top destline, to be made from current src line
2420  * \param[in]    wpld
2421  * \param[in]    lines   ptr to current src line
2422  * \param[in]    ws
2423  * \param[in]    wpls
2424  * \param[in]    lastlineflag  1 if last src line; 0 otherwise
2425  * \return  void
2426  */
2427 static void
scaleColor2xLILineLow(l_uint32 * lined,l_int32 wpld,l_uint32 * lines,l_int32 ws,l_int32 wpls,l_int32 lastlineflag)2428 scaleColor2xLILineLow(l_uint32  *lined,
2429                       l_int32    wpld,
2430                       l_uint32  *lines,
2431                       l_int32    ws,
2432                       l_int32    wpls,
2433                       l_int32    lastlineflag)
2434 {
2435 l_int32    j, jd, wsm;
2436 l_int32    rval1, rval2, rval3, rval4, gval1, gval2, gval3, gval4;
2437 l_int32    bval1, bval2, bval3, bval4;
2438 l_uint32   pixels1, pixels2, pixels3, pixels4, pixel;
2439 l_uint32  *linesp, *linedp;
2440 
2441     wsm = ws - 1;
2442 
2443     if (lastlineflag == 0) {
2444         linesp = lines + wpls;
2445         linedp = lined + wpld;
2446         pixels1 = *lines;
2447         pixels3 = *linesp;
2448 
2449             /* initialize with v(2) and v(4) */
2450         rval2 = pixels1 >> 24;
2451         gval2 = (pixels1 >> 16) & 0xff;
2452         bval2 = (pixels1 >> 8) & 0xff;
2453         rval4 = pixels3 >> 24;
2454         gval4 = (pixels3 >> 16) & 0xff;
2455         bval4 = (pixels3 >> 8) & 0xff;
2456 
2457         for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
2458                 /* shift in previous src values */
2459             rval1 = rval2;
2460             gval1 = gval2;
2461             bval1 = bval2;
2462             rval3 = rval4;
2463             gval3 = gval4;
2464             bval3 = bval4;
2465                 /* get new src values */
2466             pixels2 = *(lines + j + 1);
2467             pixels4 = *(linesp + j + 1);
2468             rval2 = pixels2 >> 24;
2469             gval2 = (pixels2 >> 16) & 0xff;
2470             bval2 = (pixels2 >> 8) & 0xff;
2471             rval4 = pixels4 >> 24;
2472             gval4 = (pixels4 >> 16) & 0xff;
2473             bval4 = (pixels4 >> 8) & 0xff;
2474                 /* save dest values */
2475             pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
2476             *(lined + jd) = pixel;                               /* pix 1 */
2477             pixel = ((((rval1 + rval2) << 23) & 0xff000000) |
2478                      (((gval1 + gval2) << 15) & 0x00ff0000) |
2479                      (((bval1 + bval2) << 7) & 0x0000ff00));
2480             *(lined + jd + 1) = pixel;                           /* pix 2 */
2481             pixel = ((((rval1 + rval3) << 23) & 0xff000000) |
2482                      (((gval1 + gval3) << 15) & 0x00ff0000) |
2483                      (((bval1 + bval3) << 7) & 0x0000ff00));
2484             *(linedp + jd) = pixel;                              /* pix 3 */
2485             pixel = ((((rval1 + rval2 + rval3 + rval4) << 22) & 0xff000000) |
2486                      (((gval1 + gval2 + gval3 + gval4) << 14) & 0x00ff0000) |
2487                      (((bval1 + bval2 + bval3 + bval4) << 6) & 0x0000ff00));
2488             *(linedp + jd + 1) = pixel;                          /* pix 4 */
2489         }
2490             /* last src pixel on line */
2491         rval1 = rval2;
2492         gval1 = gval2;
2493         bval1 = bval2;
2494         rval3 = rval4;
2495         gval3 = gval4;
2496         bval3 = bval4;
2497         pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
2498         *(lined + 2 * wsm) = pixel;                        /* pix 1 */
2499         *(lined + 2 * wsm + 1) = pixel;                    /* pix 2 */
2500         pixel = ((((rval1 + rval3) << 23) & 0xff000000) |
2501                  (((gval1 + gval3) << 15) & 0x00ff0000) |
2502                  (((bval1 + bval3) << 7) & 0x0000ff00));
2503         *(linedp + 2 * wsm) = pixel;                       /* pix 3 */
2504         *(linedp + 2 * wsm + 1) = pixel;                   /* pix 4 */
2505     } else {   /* last row of src pixels: lastlineflag == 1 */
2506         linedp = lined + wpld;
2507         pixels2 = *lines;
2508         rval2 = pixels2 >> 24;
2509         gval2 = (pixels2 >> 16) & 0xff;
2510         bval2 = (pixels2 >> 8) & 0xff;
2511         for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
2512             rval1 = rval2;
2513             gval1 = gval2;
2514             bval1 = bval2;
2515             pixels2 = *(lines + j + 1);
2516             rval2 = pixels2 >> 24;
2517             gval2 = (pixels2 >> 16) & 0xff;
2518             bval2 = (pixels2 >> 8) & 0xff;
2519             pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
2520             *(lined + jd) = pixel;                            /* pix 1 */
2521             *(linedp + jd) = pixel;                           /* pix 2 */
2522             pixel = ((((rval1 + rval2) << 23) & 0xff000000) |
2523                      (((gval1 + gval2) << 15) & 0x00ff0000) |
2524                      (((bval1 + bval2) << 7) & 0x0000ff00));
2525             *(lined + jd + 1) = pixel;                        /* pix 3 */
2526             *(linedp + jd + 1) = pixel;                       /* pix 4 */
2527         }
2528         rval1 = rval2;
2529         gval1 = gval2;
2530         bval1 = bval2;
2531         pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
2532         *(lined + 2 * wsm) = pixel;                           /* pix 1 */
2533         *(lined + 2 * wsm + 1) = pixel;                       /* pix 2 */
2534         *(linedp + 2 * wsm) = pixel;                          /* pix 3 */
2535         *(linedp + 2 * wsm + 1) = pixel;                      /* pix 4 */
2536     }
2537 }
2538 
2539 
2540 /*------------------------------------------------------------------*
2541  *                2x linear interpolated gray scaling               *
2542  *------------------------------------------------------------------*/
2543 /*!
2544  * \brief   scaleGray2xLILow()
2545  *
2546  *  This is a special case of 2x expansion by linear
2547  *  interpolation.  Each src pixel contains 4 dest pixels.
2548  *  The 4 dest pixels in src pixel 1 are numbered at
2549  *  their UL corners.  The 4 dest pixels in src pixel 1
2550  *  are related to that src pixel and its 3 neighboring
2551  *  src pixels as follows:
2552  *
2553  *             1-----2-----|-----|-----|
2554  *             |     |     |     |     |
2555  *             |     |     |     |     |
2556  *  src 1 -->  3-----4-----|     |     |  <-- src 2
2557  *             |     |     |     |     |
2558  *             |     |     |     |     |
2559  *             |-----|-----|-----|-----|
2560  *             |     |     |     |     |
2561  *             |     |     |     |     |
2562  *  src 3 -->  |     |     |     |     |  <-- src 4
2563  *             |     |     |     |     |
2564  *             |     |     |     |     |
2565  *             |-----|-----|-----|-----|
2566  *
2567  *           dest      src
2568  *           ----      ---
2569  *           dp1    =  sp1
2570  *           dp2    =  (sp1 + sp2) / 2
2571  *           dp3    =  (sp1 + sp3) / 2
2572  *           dp4    =  (sp1 + sp2 + sp3 + sp4) / 4
2573  *
2574  *  We iterate over the src pixels, and unroll the calculation
2575  *  for each set of 4 dest pixels corresponding to that src
2576  *  pixel, caching pixels for the next src pixel whenever possible.
2577  */
2578 static void
scaleGray2xLILow(l_uint32 * datad,l_int32 wpld,l_uint32 * datas,l_int32 ws,l_int32 hs,l_int32 wpls)2579 scaleGray2xLILow(l_uint32  *datad,
2580                  l_int32    wpld,
2581                  l_uint32  *datas,
2582                  l_int32    ws,
2583                  l_int32    hs,
2584                  l_int32    wpls)
2585 {
2586 l_int32    i, hsm;
2587 l_uint32  *lines, *lined;
2588 
2589     hsm = hs - 1;
2590 
2591         /* We're taking 2 src and 2 dest lines at a time,
2592          * and for each src line, we're computing 2 dest lines.
2593          * Call these 2 dest lines:  destline1 and destline2.
2594          * The first src line is used for destline 1.
2595          * On all but the last src line, both src lines are
2596          * used in the linear interpolation for destline2.
2597          * On the last src line, both destline1 and destline2
2598          * are computed using only that src line (because there
2599          * isn't a lower src line). */
2600 
2601         /* iterate over all but the last src line */
2602     for (i = 0; i < hsm; i++) {
2603         lines = datas + i * wpls;
2604         lined = datad + 2 * i * wpld;
2605         scaleGray2xLILineLow(lined, wpld, lines, ws, wpls, 0);
2606     }
2607 
2608         /* last src line */
2609     lines = datas + hsm * wpls;
2610     lined = datad + 2 * hsm * wpld;
2611     scaleGray2xLILineLow(lined, wpld, lines, ws, wpls, 1);
2612 }
2613 
2614 
2615 /*!
2616  * \brief   scaleGray2xLILineLow()
2617  *
2618  * \param[in]    lined   ptr to top destline, to be made from current src line
2619  * \param[in]    wpld
2620  * \param[in]    lines   ptr to current src line
2621  * \param[in]    ws
2622  * \param[in]    wpls
2623  * \param[in]    lastlineflag  1 if last src line; 0 otherwise
2624  * \return  void
2625  */
2626 static void
scaleGray2xLILineLow(l_uint32 * lined,l_int32 wpld,l_uint32 * lines,l_int32 ws,l_int32 wpls,l_int32 lastlineflag)2627 scaleGray2xLILineLow(l_uint32  *lined,
2628                      l_int32    wpld,
2629                      l_uint32  *lines,
2630                      l_int32    ws,
2631                      l_int32    wpls,
2632                      l_int32    lastlineflag)
2633 {
2634 l_int32    j, jd, wsm, w;
2635 l_int32    sval1, sval2, sval3, sval4;
2636 l_uint32  *linesp, *linedp;
2637 l_uint32   words, wordsp, wordd, worddp;
2638 
2639     wsm = ws - 1;
2640 
2641     if (lastlineflag == 0) {
2642         linesp = lines + wpls;
2643         linedp = lined + wpld;
2644 
2645             /* Unroll the loop 4x and work on full words */
2646         words = lines[0];
2647         wordsp = linesp[0];
2648         sval2 = (words >> 24) & 0xff;
2649         sval4 = (wordsp >> 24) & 0xff;
2650         for (j = 0, jd = 0, w = 0; j + 3 < wsm; j += 4, jd += 8, w++) {
2651                 /* At the top of the loop,
2652                  * words == lines[w], wordsp == linesp[w]
2653                  * and the top bytes of those have been loaded into
2654                  * sval2 and sval4. */
2655             sval1 = sval2;
2656             sval2 = (words >> 16) & 0xff;
2657             sval3 = sval4;
2658             sval4 = (wordsp >> 16) & 0xff;
2659             wordd = (sval1 << 24) | (((sval1 + sval2) >> 1) << 16);
2660             worddp = (((sval1 + sval3) >> 1) << 24) |
2661                 (((sval1 + sval2 + sval3 + sval4) >> 2) << 16);
2662 
2663             sval1 = sval2;
2664             sval2 = (words >> 8) & 0xff;
2665             sval3 = sval4;
2666             sval4 = (wordsp >> 8) & 0xff;
2667             wordd |= (sval1 << 8) | ((sval1 + sval2) >> 1);
2668             worddp |= (((sval1 + sval3) >> 1) << 8) |
2669                 ((sval1 + sval2 + sval3 + sval4) >> 2);
2670             lined[w * 2] = wordd;
2671             linedp[w * 2] = worddp;
2672 
2673             sval1 = sval2;
2674             sval2 = words & 0xff;
2675             sval3 = sval4;
2676             sval4 = wordsp & 0xff;
2677             wordd = (sval1 << 24) |                              /* pix 1 */
2678                 (((sval1 + sval2) >> 1) << 16);                  /* pix 2 */
2679             worddp = (((sval1 + sval3) >> 1) << 24) |            /* pix 3 */
2680                 (((sval1 + sval2 + sval3 + sval4) >> 2) << 16);  /* pix 4 */
2681 
2682                 /* Load the next word as we need its first byte */
2683             words = lines[w + 1];
2684             wordsp = linesp[w + 1];
2685             sval1 = sval2;
2686             sval2 = (words >> 24) & 0xff;
2687             sval3 = sval4;
2688             sval4 = (wordsp >> 24) & 0xff;
2689             wordd |= (sval1 << 8) |                              /* pix 1 */
2690                 ((sval1 + sval2) >> 1);                          /* pix 2 */
2691             worddp |= (((sval1 + sval3) >> 1) << 8) |            /* pix 3 */
2692                 ((sval1 + sval2 + sval3 + sval4) >> 2);          /* pix 4 */
2693             lined[w * 2 + 1] = wordd;
2694             linedp[w * 2 + 1] = worddp;
2695         }
2696 
2697             /* Finish up the last word */
2698         for (; j < wsm; j++, jd += 2) {
2699             sval1 = sval2;
2700             sval3 = sval4;
2701             sval2 = GET_DATA_BYTE(lines, j + 1);
2702             sval4 = GET_DATA_BYTE(linesp, j + 1);
2703             SET_DATA_BYTE(lined, jd, sval1);                     /* pix 1 */
2704             SET_DATA_BYTE(lined, jd + 1, (sval1 + sval2) / 2);   /* pix 2 */
2705             SET_DATA_BYTE(linedp, jd, (sval1 + sval3) / 2);      /* pix 3 */
2706             SET_DATA_BYTE(linedp, jd + 1,
2707                           (sval1 + sval2 + sval3 + sval4) / 4);  /* pix 4 */
2708         }
2709         sval1 = sval2;
2710         sval3 = sval4;
2711         SET_DATA_BYTE(lined, 2 * wsm, sval1);                     /* pix 1 */
2712         SET_DATA_BYTE(lined, 2 * wsm + 1, sval1);                 /* pix 2 */
2713         SET_DATA_BYTE(linedp, 2 * wsm, (sval1 + sval3) / 2);      /* pix 3 */
2714         SET_DATA_BYTE(linedp, 2 * wsm + 1, (sval1 + sval3) / 2);  /* pix 4 */
2715 
2716 #if DEBUG_UNROLLING
2717 #define CHECK_BYTE(a, b, c) if (GET_DATA_BYTE(a, b) != c) {\
2718      fprintf(stderr, "Error: mismatch at %d, %d vs %d\n", \
2719              j, GET_DATA_BYTE(a, b), c); }
2720 
2721         sval2 = GET_DATA_BYTE(lines, 0);
2722         sval4 = GET_DATA_BYTE(linesp, 0);
2723         for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
2724             sval1 = sval2;
2725             sval3 = sval4;
2726             sval2 = GET_DATA_BYTE(lines, j + 1);
2727             sval4 = GET_DATA_BYTE(linesp, j + 1);
2728             CHECK_BYTE(lined, jd, sval1);                     /* pix 1 */
2729             CHECK_BYTE(lined, jd + 1, (sval1 + sval2) / 2);   /* pix 2 */
2730             CHECK_BYTE(linedp, jd, (sval1 + sval3) / 2);      /* pix 3 */
2731             CHECK_BYTE(linedp, jd + 1,
2732                           (sval1 + sval2 + sval3 + sval4) / 4);  /* pix 4 */
2733         }
2734         sval1 = sval2;
2735         sval3 = sval4;
2736         CHECK_BYTE(lined, 2 * wsm, sval1);                     /* pix 1 */
2737         CHECK_BYTE(lined, 2 * wsm + 1, sval1);                 /* pix 2 */
2738         CHECK_BYTE(linedp, 2 * wsm, (sval1 + sval3) / 2);      /* pix 3 */
2739         CHECK_BYTE(linedp, 2 * wsm + 1, (sval1 + sval3) / 2);  /* pix 4 */
2740 #undef CHECK_BYTE
2741 #endif
2742     } else {  /* last row of src pixels: lastlineflag == 1 */
2743         linedp = lined + wpld;
2744         sval2 = GET_DATA_BYTE(lines, 0);
2745         for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
2746             sval1 = sval2;
2747             sval2 = GET_DATA_BYTE(lines, j + 1);
2748             SET_DATA_BYTE(lined, jd, sval1);                       /* pix 1 */
2749             SET_DATA_BYTE(linedp, jd, sval1);                      /* pix 3 */
2750             SET_DATA_BYTE(lined, jd + 1, (sval1 + sval2) / 2);     /* pix 2 */
2751             SET_DATA_BYTE(linedp, jd + 1, (sval1 + sval2) / 2);    /* pix 4 */
2752         }
2753         sval1 = sval2;
2754         SET_DATA_BYTE(lined, 2 * wsm, sval1);                     /* pix 1 */
2755         SET_DATA_BYTE(lined, 2 * wsm + 1, sval1);                 /* pix 2 */
2756         SET_DATA_BYTE(linedp, 2 * wsm, sval1);                    /* pix 3 */
2757         SET_DATA_BYTE(linedp, 2 * wsm + 1, sval1);                /* pix 4 */
2758     }
2759 }
2760 
2761 
2762 /*------------------------------------------------------------------*
2763  *               4x linear interpolated gray scaling                *
2764  *------------------------------------------------------------------*/
2765 /*!
2766  * \brief   scaleGray4xLILow()
2767  *
2768  *  This is a special case of 4x expansion by linear
2769  *  interpolation.  Each src pixel contains 16 dest pixels.
2770  *  The 16 dest pixels in src pixel 1 are numbered at
2771  *  their UL corners.  The 16 dest pixels in src pixel 1
2772  *  are related to that src pixel and its 3 neighboring
2773  *  src pixels as follows:
2774  *
2775  *             1---2---3---4---|---|---|---|---|
2776  *             |   |   |   |   |   |   |   |   |
2777  *             5---6---7---8---|---|---|---|---|
2778  *             |   |   |   |   |   |   |   |   |
2779  *  src 1 -->  9---a---b---c---|---|---|---|---|  <-- src 2
2780  *             |   |   |   |   |   |   |   |   |
2781  *             d---e---f---g---|---|---|---|---|
2782  *             |   |   |   |   |   |   |   |   |
2783  *             |===|===|===|===|===|===|===|===|
2784  *             |   |   |   |   |   |   |   |   |
2785  *             |---|---|---|---|---|---|---|---|
2786  *             |   |   |   |   |   |   |   |   |
2787  *  src 3 -->  |---|---|---|---|---|---|---|---|  <-- src 4
2788  *             |   |   |   |   |   |   |   |   |
2789  *             |---|---|---|---|---|---|---|---|
2790  *             |   |   |   |   |   |   |   |   |
2791  *             |---|---|---|---|---|---|---|---|
2792  *
2793  *           dest      src
2794  *           ----      ---
2795  *           dp1    =  sp1
2796  *           dp2    =  (3 * sp1 + sp2) / 4
2797  *           dp3    =  (sp1 + sp2) / 2
2798  *           dp4    =  (sp1 + 3 * sp2) / 4
2799  *           dp5    =  (3 * sp1 + sp3) / 4
2800  *           dp6    =  (9 * sp1 + 3 * sp2 + 3 * sp3 + sp4) / 16
2801  *           dp7    =  (3 * sp1 + 3 * sp2 + sp3 + sp4) / 8
2802  *           dp8    =  (3 * sp1 + 9 * sp2 + 1 * sp3 + 3 * sp4) / 16
2803  *           dp9    =  (sp1 + sp3) / 2
2804  *           dp10   =  (3 * sp1 + sp2 + 3 * sp3 + sp4) / 8
2805  *           dp11   =  (sp1 + sp2 + sp3 + sp4) / 4
2806  *           dp12   =  (sp1 + 3 * sp2 + sp3 + 3 * sp4) / 8
2807  *           dp13   =  (sp1 + 3 * sp3) / 4
2808  *           dp14   =  (3 * sp1 + sp2 + 9 * sp3 + 3 * sp4) / 16
2809  *           dp15   =  (sp1 + sp2 + 3 * sp3 + 3 * sp4) / 8
2810  *           dp16   =  (sp1 + 3 * sp2 + 3 * sp3 + 9 * sp4) / 16
2811  *
2812  *  We iterate over the src pixels, and unroll the calculation
2813  *  for each set of 16 dest pixels corresponding to that src
2814  *  pixel, caching pixels for the next src pixel whenever possible.
2815  */
2816 static void
scaleGray4xLILow(l_uint32 * datad,l_int32 wpld,l_uint32 * datas,l_int32 ws,l_int32 hs,l_int32 wpls)2817 scaleGray4xLILow(l_uint32  *datad,
2818                  l_int32    wpld,
2819                  l_uint32  *datas,
2820                  l_int32    ws,
2821                  l_int32    hs,
2822                  l_int32    wpls)
2823 {
2824 l_int32    i, hsm;
2825 l_uint32  *lines, *lined;
2826 
2827     hsm = hs - 1;
2828 
2829         /* We're taking 2 src and 4 dest lines at a time,
2830          * and for each src line, we're computing 4 dest lines.
2831          * Call these 4 dest lines:  destline1 - destline4.
2832          * The first src line is used for destline 1.
2833          * Two src lines are used for all other dest lines,
2834          * except for the last 4 dest lines, which are computed
2835          * using only the last src line. */
2836 
2837         /* iterate over all but the last src line */
2838     for (i = 0; i < hsm; i++) {
2839         lines = datas + i * wpls;
2840         lined = datad + 4 * i * wpld;
2841         scaleGray4xLILineLow(lined, wpld, lines, ws, wpls, 0);
2842     }
2843 
2844         /* last src line */
2845     lines = datas + hsm * wpls;
2846     lined = datad + 4 * hsm * wpld;
2847     scaleGray4xLILineLow(lined, wpld, lines, ws, wpls, 1);
2848 }
2849 
2850 
2851 /*!
2852  * \brief   scaleGray4xLILineLow()
2853  *
2854  * \param[in]    lined   ptr to top destline, to be made from current src line
2855  * \param[in]    wpld
2856  * \param[in]    lines   ptr to current src line
2857  * \param[in]    ws
2858  * \param[in]    wpls
2859  * \param[in]    lastlineflag  1 if last src line; 0 otherwise
2860  * \return  void
2861  */
2862 static void
scaleGray4xLILineLow(l_uint32 * lined,l_int32 wpld,l_uint32 * lines,l_int32 ws,l_int32 wpls,l_int32 lastlineflag)2863 scaleGray4xLILineLow(l_uint32  *lined,
2864                      l_int32    wpld,
2865                      l_uint32  *lines,
2866                      l_int32    ws,
2867                      l_int32    wpls,
2868                      l_int32    lastlineflag)
2869 {
2870 l_int32    j, jd, wsm, wsm4;
2871 l_int32    s1, s2, s3, s4, s1t, s2t, s3t, s4t;
2872 l_uint32  *linesp, *linedp1, *linedp2, *linedp3;
2873 
2874     wsm = ws - 1;
2875     wsm4 = 4 * wsm;
2876 
2877     if (lastlineflag == 0) {
2878         linesp = lines + wpls;
2879         linedp1 = lined + wpld;
2880         linedp2 = lined + 2 * wpld;
2881         linedp3 = lined + 3 * wpld;
2882         s2 = GET_DATA_BYTE(lines, 0);
2883         s4 = GET_DATA_BYTE(linesp, 0);
2884         for (j = 0, jd = 0; j < wsm; j++, jd += 4) {
2885             s1 = s2;
2886             s3 = s4;
2887             s2 = GET_DATA_BYTE(lines, j + 1);
2888             s4 = GET_DATA_BYTE(linesp, j + 1);
2889             s1t = 3 * s1;
2890             s2t = 3 * s2;
2891             s3t = 3 * s3;
2892             s4t = 3 * s4;
2893             SET_DATA_BYTE(lined, jd, s1);                             /* d1 */
2894             SET_DATA_BYTE(lined, jd + 1, (s1t + s2) / 4);             /* d2 */
2895             SET_DATA_BYTE(lined, jd + 2, (s1 + s2) / 2);              /* d3 */
2896             SET_DATA_BYTE(lined, jd + 3, (s1 + s2t) / 4);             /* d4 */
2897             SET_DATA_BYTE(linedp1, jd, (s1t + s3) / 4);                /* d5 */
2898             SET_DATA_BYTE(linedp1, jd + 1, (9*s1 + s2t + s3t + s4) / 16); /*d6*/
2899             SET_DATA_BYTE(linedp1, jd + 2, (s1t + s2t + s3 + s4) / 8); /* d7 */
2900             SET_DATA_BYTE(linedp1, jd + 3, (s1t + 9*s2 + s3 + s4t) / 16);/*d8*/
2901             SET_DATA_BYTE(linedp2, jd, (s1 + s3) / 2);                /* d9 */
2902             SET_DATA_BYTE(linedp2, jd + 1, (s1t + s2 + s3t + s4) / 8);/* d10 */
2903             SET_DATA_BYTE(linedp2, jd + 2, (s1 + s2 + s3 + s4) / 4);  /* d11 */
2904             SET_DATA_BYTE(linedp2, jd + 3, (s1 + s2t + s3 + s4t) / 8);/* d12 */
2905             SET_DATA_BYTE(linedp3, jd, (s1 + s3t) / 4);               /* d13 */
2906             SET_DATA_BYTE(linedp3, jd + 1, (s1t + s2 + 9*s3 + s4t) / 16);/*d14*/
2907             SET_DATA_BYTE(linedp3, jd + 2, (s1 + s2 + s3t + s4t) / 8); /* d15 */
2908             SET_DATA_BYTE(linedp3, jd + 3, (s1 + s2t + s3t + 9*s4) / 16);/*d16*/
2909         }
2910         s1 = s2;
2911         s3 = s4;
2912         s1t = 3 * s1;
2913         s3t = 3 * s3;
2914         SET_DATA_BYTE(lined, wsm4, s1);                               /* d1 */
2915         SET_DATA_BYTE(lined, wsm4 + 1, s1);                           /* d2 */
2916         SET_DATA_BYTE(lined, wsm4 + 2, s1);                           /* d3 */
2917         SET_DATA_BYTE(lined, wsm4 + 3, s1);                           /* d4 */
2918         SET_DATA_BYTE(linedp1, wsm4, (s1t + s3) / 4);                 /* d5 */
2919         SET_DATA_BYTE(linedp1, wsm4 + 1, (s1t + s3) / 4);             /* d6 */
2920         SET_DATA_BYTE(linedp1, wsm4 + 2, (s1t + s3) / 4);             /* d7 */
2921         SET_DATA_BYTE(linedp1, wsm4 + 3, (s1t + s3) / 4);             /* d8 */
2922         SET_DATA_BYTE(linedp2, wsm4, (s1 + s3) / 2);                  /* d9 */
2923         SET_DATA_BYTE(linedp2, wsm4 + 1, (s1 + s3) / 2);              /* d10 */
2924         SET_DATA_BYTE(linedp2, wsm4 + 2, (s1 + s3) / 2);              /* d11 */
2925         SET_DATA_BYTE(linedp2, wsm4 + 3, (s1 + s3) / 2);              /* d12 */
2926         SET_DATA_BYTE(linedp3, wsm4, (s1 + s3t) / 4);                 /* d13 */
2927         SET_DATA_BYTE(linedp3, wsm4 + 1, (s1 + s3t) / 4);             /* d14 */
2928         SET_DATA_BYTE(linedp3, wsm4 + 2, (s1 + s3t) / 4);             /* d15 */
2929         SET_DATA_BYTE(linedp3, wsm4 + 3, (s1 + s3t) / 4);             /* d16 */
2930     } else {   /* last row of src pixels: lastlineflag == 1 */
2931         linedp1 = lined + wpld;
2932         linedp2 = lined + 2 * wpld;
2933         linedp3 = lined + 3 * wpld;
2934         s2 = GET_DATA_BYTE(lines, 0);
2935         for (j = 0, jd = 0; j < wsm; j++, jd += 4) {
2936             s1 = s2;
2937             s2 = GET_DATA_BYTE(lines, j + 1);
2938             s1t = 3 * s1;
2939             s2t = 3 * s2;
2940             SET_DATA_BYTE(lined, jd, s1);                            /* d1 */
2941             SET_DATA_BYTE(lined, jd + 1, (s1t + s2) / 4 );           /* d2 */
2942             SET_DATA_BYTE(lined, jd + 2, (s1 + s2) / 2 );            /* d3 */
2943             SET_DATA_BYTE(lined, jd + 3, (s1 + s2t) / 4 );           /* d4 */
2944             SET_DATA_BYTE(linedp1, jd, s1);                          /* d5 */
2945             SET_DATA_BYTE(linedp1, jd + 1, (s1t + s2) / 4 );         /* d6 */
2946             SET_DATA_BYTE(linedp1, jd + 2, (s1 + s2) / 2 );          /* d7 */
2947             SET_DATA_BYTE(linedp1, jd + 3, (s1 + s2t) / 4 );         /* d8 */
2948             SET_DATA_BYTE(linedp2, jd, s1);                          /* d9 */
2949             SET_DATA_BYTE(linedp2, jd + 1, (s1t + s2) / 4 );         /* d10 */
2950             SET_DATA_BYTE(linedp2, jd + 2, (s1 + s2) / 2 );          /* d11 */
2951             SET_DATA_BYTE(linedp2, jd + 3, (s1 + s2t) / 4 );         /* d12 */
2952             SET_DATA_BYTE(linedp3, jd, s1);                          /* d13 */
2953             SET_DATA_BYTE(linedp3, jd + 1, (s1t + s2) / 4 );         /* d14 */
2954             SET_DATA_BYTE(linedp3, jd + 2, (s1 + s2) / 2 );          /* d15 */
2955             SET_DATA_BYTE(linedp3, jd + 3, (s1 + s2t) / 4 );         /* d16 */
2956         }
2957         s1 = s2;
2958         SET_DATA_BYTE(lined, wsm4, s1);                              /* d1 */
2959         SET_DATA_BYTE(lined, wsm4 + 1, s1);                          /* d2 */
2960         SET_DATA_BYTE(lined, wsm4 + 2, s1);                          /* d3 */
2961         SET_DATA_BYTE(lined, wsm4 + 3, s1);                          /* d4 */
2962         SET_DATA_BYTE(linedp1, wsm4, s1);                            /* d5 */
2963         SET_DATA_BYTE(linedp1, wsm4 + 1, s1);                        /* d6 */
2964         SET_DATA_BYTE(linedp1, wsm4 + 2, s1);                        /* d7 */
2965         SET_DATA_BYTE(linedp1, wsm4 + 3, s1);                        /* d8 */
2966         SET_DATA_BYTE(linedp2, wsm4, s1);                            /* d9 */
2967         SET_DATA_BYTE(linedp2, wsm4 + 1, s1);                        /* d10 */
2968         SET_DATA_BYTE(linedp2, wsm4 + 2, s1);                        /* d11 */
2969         SET_DATA_BYTE(linedp2, wsm4 + 3, s1);                        /* d12 */
2970         SET_DATA_BYTE(linedp3, wsm4, s1);                            /* d13 */
2971         SET_DATA_BYTE(linedp3, wsm4 + 1, s1);                        /* d14 */
2972         SET_DATA_BYTE(linedp3, wsm4 + 2, s1);                        /* d15 */
2973         SET_DATA_BYTE(linedp3, wsm4 + 3, s1);                        /* d16 */
2974     }
2975 }
2976 
2977 
2978 /*------------------------------------------------------------------*
2979  *       Grayscale and color scaling by closest pixel sampling      *
2980  *------------------------------------------------------------------*/
2981 /*!
2982  * \brief   scaleBySamplingLow()
2983  *
2984  *  Notes:
2985  *      (1) The dest must be cleared prior to this operation,
2986  *          and we clear it here in the low-level code.
2987  *      (2) We reuse dest pixels and dest pixel rows whenever
2988  *          possible.  This speeds the upscaling; downscaling
2989  *          is done by strict subsampling and is unaffected.
2990  *      (3) Because we are sampling and not interpolating, this
2991  *          routine works directly, without conversion to full
2992  *          RGB color, for 2, 4 or 8 bpp palette color images.
2993  */
2994 static l_int32
scaleBySamplingLow(l_uint32 * datad,l_int32 wd,l_int32 hd,l_int32 wpld,l_uint32 * datas,l_int32 ws,l_int32 hs,l_int32 d,l_int32 wpls)2995 scaleBySamplingLow(l_uint32  *datad,
2996                    l_int32    wd,
2997                    l_int32    hd,
2998                    l_int32    wpld,
2999                    l_uint32  *datas,
3000                    l_int32    ws,
3001                    l_int32    hs,
3002                    l_int32    d,
3003                    l_int32    wpls)
3004 {
3005 l_int32    i, j, bpld;
3006 l_int32    xs, prevxs, sval;
3007 l_int32   *srow, *scol;
3008 l_uint32   csval;
3009 l_uint32  *lines, *prevlines, *lined, *prevlined;
3010 l_float32  wratio, hratio;
3011 
3012     PROCNAME("scaleBySamplingLow");
3013 
3014     if (d != 2 && d != 4 && d !=8 && d != 16 && d != 32)
3015         return ERROR_INT("pixel depth not supported", procName, 1);
3016 
3017         /* clear dest */
3018     bpld = 4 * wpld;
3019     memset((char *)datad, 0, hd * bpld);
3020 
3021         /* the source row corresponding to dest row i ==> srow[i]
3022          * the source col corresponding to dest col j ==> scol[j]  */
3023     if ((srow = (l_int32 *)LEPT_CALLOC(hd, sizeof(l_int32))) == NULL)
3024         return ERROR_INT("srow not made", procName, 1);
3025     if ((scol = (l_int32 *)LEPT_CALLOC(wd, sizeof(l_int32))) == NULL) {
3026         LEPT_FREE(srow);
3027         return ERROR_INT("scol not made", procName, 1);
3028     }
3029 
3030     wratio = (l_float32)ws / (l_float32)wd;
3031     hratio = (l_float32)hs / (l_float32)hd;
3032     for (i = 0; i < hd; i++)
3033         srow[i] = L_MIN((l_int32)(hratio * i + 0.5), hs - 1);
3034     for (j = 0; j < wd; j++)
3035         scol[j] = L_MIN((l_int32)(wratio * j + 0.5), ws - 1);
3036 
3037     prevlines = NULL;
3038     for (i = 0; i < hd; i++) {
3039         lines = datas + srow[i] * wpls;
3040         lined = datad + i * wpld;
3041         if (lines != prevlines) {  /* make dest from new source row */
3042             prevxs = -1;
3043             sval = 0;
3044             csval = 0;
3045             if (d == 2) {
3046                 for (j = 0; j < wd; j++) {
3047                     xs = scol[j];
3048                     if (xs != prevxs) {  /* get dest pix from source col */
3049                         sval = GET_DATA_DIBIT(lines, xs);
3050                         SET_DATA_DIBIT(lined, j, sval);
3051                         prevxs = xs;
3052                     } else {  /* copy prev dest pix */
3053                         SET_DATA_DIBIT(lined, j, sval);
3054                     }
3055                 }
3056             } else if (d == 4) {
3057                 for (j = 0; j < wd; j++) {
3058                     xs = scol[j];
3059                     if (xs != prevxs) {  /* get dest pix from source col */
3060                         sval = GET_DATA_QBIT(lines, xs);
3061                         SET_DATA_QBIT(lined, j, sval);
3062                         prevxs = xs;
3063                     } else {  /* copy prev dest pix */
3064                         SET_DATA_QBIT(lined, j, sval);
3065                     }
3066                 }
3067             } else if (d == 8) {
3068                 for (j = 0; j < wd; j++) {
3069                     xs = scol[j];
3070                     if (xs != prevxs) {  /* get dest pix from source col */
3071                         sval = GET_DATA_BYTE(lines, xs);
3072                         SET_DATA_BYTE(lined, j, sval);
3073                         prevxs = xs;
3074                     } else {  /* copy prev dest pix */
3075                         SET_DATA_BYTE(lined, j, sval);
3076                     }
3077                 }
3078             } else if (d == 16) {
3079                 for (j = 0; j < wd; j++) {
3080                     xs = scol[j];
3081                     if (xs != prevxs) {  /* get dest pix from source col */
3082                         sval = GET_DATA_TWO_BYTES(lines, xs);
3083                         SET_DATA_TWO_BYTES(lined, j, sval);
3084                         prevxs = xs;
3085                     } else {  /* copy prev dest pix */
3086                         SET_DATA_TWO_BYTES(lined, j, sval);
3087                     }
3088                 }
3089             } else {  /* d == 32 */
3090                 for (j = 0; j < wd; j++) {
3091                     xs = scol[j];
3092                     if (xs != prevxs) {  /* get dest pix from source col */
3093                         csval = lines[xs];
3094                         lined[j] = csval;
3095                         prevxs = xs;
3096                     } else {  /* copy prev dest pix */
3097                         lined[j] = csval;
3098                     }
3099                 }
3100             }
3101         } else {  /* lines == prevlines; copy prev dest row */
3102             prevlined = lined - wpld;
3103             memcpy((char *)lined, (char *)prevlined, bpld);
3104         }
3105         prevlines = lines;
3106     }
3107 
3108     LEPT_FREE(srow);
3109     LEPT_FREE(scol);
3110     return 0;
3111 }
3112 
3113 
3114 /*------------------------------------------------------------------*
3115  *    Color and grayscale downsampling with (antialias) smoothing   *
3116  *------------------------------------------------------------------*/
3117 /*!
3118  * \brief   scaleSmoothLow()
3119  *
3120  *  Notes:
3121  *      (1) This function is called on 8 or 32 bpp src and dest images.
3122  *      (2) size is the full width of the lowpass smoothing filter.
3123  *          It is correlated with the reduction ratio, being the
3124  *          nearest integer such that size is approximately equal to hs / hd.
3125  */
3126 static l_int32
scaleSmoothLow(l_uint32 * datad,l_int32 wd,l_int32 hd,l_int32 wpld,l_uint32 * datas,l_int32 ws,l_int32 hs,l_int32 d,l_int32 wpls,l_int32 size)3127 scaleSmoothLow(l_uint32  *datad,
3128                l_int32    wd,
3129                l_int32    hd,
3130                l_int32    wpld,
3131                l_uint32  *datas,
3132                l_int32    ws,
3133                l_int32    hs,
3134                l_int32    d,
3135                l_int32    wpls,
3136                l_int32    size)
3137 {
3138 l_int32    i, j, m, n, xstart;
3139 l_int32    val, rval, gval, bval;
3140 l_int32   *srow, *scol;
3141 l_uint32  *lines, *lined, *line, *ppixel;
3142 l_uint32   pixel;
3143 l_float32  wratio, hratio, norm;
3144 
3145     PROCNAME("scaleSmoothLow");
3146 
3147         /* Clear dest */
3148     memset((char *)datad, 0, 4 * wpld * hd);
3149 
3150         /* Each dest pixel at (j,i) is computed as the average
3151            of size^2 corresponding src pixels.
3152            We store the UL corner location of the square of
3153            src pixels that correspond to dest pixel (j,i).
3154            The are labeled by the arrays srow[i] and scol[j]. */
3155     if ((srow = (l_int32 *)LEPT_CALLOC(hd, sizeof(l_int32))) == NULL)
3156         return ERROR_INT("srow not made", procName, 1);
3157     if ((scol = (l_int32 *)LEPT_CALLOC(wd, sizeof(l_int32))) == NULL) {
3158         LEPT_FREE(srow);
3159         return ERROR_INT("scol not made", procName, 1);
3160     }
3161 
3162     norm = 1. / (l_float32)(size * size);
3163     wratio = (l_float32)ws / (l_float32)wd;
3164     hratio = (l_float32)hs / (l_float32)hd;
3165     for (i = 0; i < hd; i++)
3166         srow[i] = L_MIN((l_int32)(hratio * i), hs - size);
3167     for (j = 0; j < wd; j++)
3168         scol[j] = L_MIN((l_int32)(wratio * j), ws - size);
3169 
3170         /* For each dest pixel, compute average */
3171     if (d == 8) {
3172         for (i = 0; i < hd; i++) {
3173             lines = datas + srow[i] * wpls;
3174             lined = datad + i * wpld;
3175             for (j = 0; j < wd; j++) {
3176                 xstart = scol[j];
3177                 val = 0;
3178                 for (m = 0; m < size; m++) {
3179                     line = lines + m * wpls;
3180                     for (n = 0; n < size; n++) {
3181                         val += GET_DATA_BYTE(line, xstart + n);
3182                     }
3183                 }
3184                 val = (l_int32)((l_float32)val * norm);
3185                 SET_DATA_BYTE(lined, j, val);
3186             }
3187         }
3188     } else {  /* d == 32 */
3189         for (i = 0; i < hd; i++) {
3190             lines = datas + srow[i] * wpls;
3191             lined = datad + i * wpld;
3192             for (j = 0; j < wd; j++) {
3193                 xstart = scol[j];
3194                 rval = gval = bval = 0;
3195                 for (m = 0; m < size; m++) {
3196                     ppixel = lines + m * wpls + xstart;
3197                     for (n = 0; n < size; n++) {
3198                         pixel = *(ppixel + n);
3199                         rval += (pixel >> L_RED_SHIFT) & 0xff;
3200                         gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3201                         bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3202                     }
3203                 }
3204                 rval = (l_int32)((l_float32)rval * norm);
3205                 gval = (l_int32)((l_float32)gval * norm);
3206                 bval = (l_int32)((l_float32)bval * norm);
3207                 *(lined + j) = rval << L_RED_SHIFT |
3208                                gval << L_GREEN_SHIFT |
3209                                bval << L_BLUE_SHIFT;
3210             }
3211         }
3212     }
3213 
3214     LEPT_FREE(srow);
3215     LEPT_FREE(scol);
3216     return 0;
3217 }
3218 
3219 
3220 /*!
3221  * \brief   scaleRGBToGray2Low()
3222  *
3223  *  Notes:
3224  *      (1) This function is called with 32 bpp RGB src and 8 bpp,
3225  *          half-resolution dest.  The weights should add to 1.0.
3226  */
3227 static void
scaleRGBToGray2Low(l_uint32 * datad,l_int32 wd,l_int32 hd,l_int32 wpld,l_uint32 * datas,l_int32 wpls,l_float32 rwt,l_float32 gwt,l_float32 bwt)3228 scaleRGBToGray2Low(l_uint32  *datad,
3229                    l_int32    wd,
3230                    l_int32    hd,
3231                    l_int32    wpld,
3232                    l_uint32  *datas,
3233                    l_int32    wpls,
3234                    l_float32  rwt,
3235                    l_float32  gwt,
3236                    l_float32  bwt)
3237 {
3238 l_int32    i, j, val, rval, gval, bval;
3239 l_uint32  *lines, *lined;
3240 l_uint32   pixel;
3241 
3242     rwt *= 0.25;
3243     gwt *= 0.25;
3244     bwt *= 0.25;
3245     for (i = 0; i < hd; i++) {
3246         lines = datas + 2 * i * wpls;
3247         lined = datad + i * wpld;
3248         for (j = 0; j < wd; j++) {
3249                 /* Sum each of the color components from 4 src pixels */
3250             pixel = *(lines + 2 * j);
3251             rval = (pixel >> L_RED_SHIFT) & 0xff;
3252             gval = (pixel >> L_GREEN_SHIFT) & 0xff;
3253             bval = (pixel >> L_BLUE_SHIFT) & 0xff;
3254             pixel = *(lines + 2 * j + 1);
3255             rval += (pixel >> L_RED_SHIFT) & 0xff;
3256             gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3257             bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3258             pixel = *(lines + wpls + 2 * j);
3259             rval += (pixel >> L_RED_SHIFT) & 0xff;
3260             gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3261             bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3262             pixel = *(lines + wpls + 2 * j + 1);
3263             rval += (pixel >> L_RED_SHIFT) & 0xff;
3264             gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3265             bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3266                 /* Generate the dest byte as a weighted sum of the averages */
3267             val = (l_int32)(rwt * rval + gwt * gval + bwt * bval);
3268             SET_DATA_BYTE(lined, j, val);
3269         }
3270     }
3271 }
3272 
3273 
3274 /*------------------------------------------------------------------*
3275  *                  General area mapped gray scaling                *
3276  *------------------------------------------------------------------*/
3277 /*!
3278  * \brief   scaleColorAreaMapLow()
3279  *
3280  *  This should only be used for downscaling.
3281  *  We choose to divide each pixel into 16 x 16 sub-pixels.
3282  *  This is much slower than scaleSmoothLow(), but it gives a
3283  *  better representation, esp. for downscaling factors between
3284  *  1.5 and 5.  All src pixels are subdivided into 256 sub-pixels,
3285  *  and are weighted by the number of sub-pixels covered by
3286  *  the dest pixel.  This is about 2x slower than scaleSmoothLow(),
3287  *  but the results are significantly better on small text.
3288  */
3289 static void
scaleColorAreaMapLow(l_uint32 * datad,l_int32 wd,l_int32 hd,l_int32 wpld,l_uint32 * datas,l_int32 ws,l_int32 hs,l_int32 wpls)3290 scaleColorAreaMapLow(l_uint32  *datad,
3291                     l_int32    wd,
3292                     l_int32    hd,
3293                     l_int32    wpld,
3294                     l_uint32  *datas,
3295                     l_int32    ws,
3296                     l_int32    hs,
3297                     l_int32    wpls)
3298 {
3299 l_int32    i, j, k, m, wm2, hm2;
3300 l_int32    area00, area10, area01, area11, areal, arear, areat, areab;
3301 l_int32    xu, yu;  /* UL corner in src image, to 1/16 of a pixel */
3302 l_int32    xl, yl;  /* LR corner in src image, to 1/16 of a pixel */
3303 l_int32    xup, yup, xuf, yuf;  /* UL src pixel: integer and fraction */
3304 l_int32    xlp, ylp, xlf, ylf;  /* LR src pixel: integer and fraction */
3305 l_int32    delx, dely, area;
3306 l_int32    v00r, v00g, v00b;  /* contrib. from UL src pixel */
3307 l_int32    v01r, v01g, v01b;  /* contrib. from LL src pixel */
3308 l_int32    v10r, v10g, v10b;  /* contrib from UR src pixel */
3309 l_int32    v11r, v11g, v11b;  /* contrib from LR src pixel */
3310 l_int32    vinr, ving, vinb;  /* contrib from all full interior src pixels */
3311 l_int32    vmidr, vmidg, vmidb;  /* contrib from side parts */
3312 l_int32    rval, gval, bval;
3313 l_uint32   pixel00, pixel10, pixel01, pixel11, pixel;
3314 l_uint32  *lines, *lined;
3315 l_float32  scx, scy;
3316 
3317         /* (scx, scy) are scaling factors that are applied to the
3318          * dest coords to get the corresponding src coords.
3319          * We need them because we iterate over dest pixels
3320          * and must find the corresponding set of src pixels. */
3321     scx = 16. * (l_float32)ws / (l_float32)wd;
3322     scy = 16. * (l_float32)hs / (l_float32)hd;
3323     wm2 = ws - 2;
3324     hm2 = hs - 2;
3325 
3326         /* Iterate over the destination pixels */
3327     for (i = 0; i < hd; i++) {
3328         yu = (l_int32)(scy * i);
3329         yl = (l_int32)(scy * (i + 1.0));
3330         yup = yu >> 4;
3331         yuf = yu & 0x0f;
3332         ylp = yl >> 4;
3333         ylf = yl & 0x0f;
3334         dely = ylp - yup;
3335         lined = datad + i * wpld;
3336         lines = datas + yup * wpls;
3337         for (j = 0; j < wd; j++) {
3338             xu = (l_int32)(scx * j);
3339             xl = (l_int32)(scx * (j + 1.0));
3340             xup = xu >> 4;
3341             xuf = xu & 0x0f;
3342             xlp = xl >> 4;
3343             xlf = xl & 0x0f;
3344             delx = xlp - xup;
3345 
3346                 /* If near the edge, just use a src pixel value */
3347             if (xlp > wm2 || ylp > hm2) {
3348                 *(lined + j) = *(lines + xup);
3349                 continue;
3350             }
3351 
3352                 /* Area summed over, in subpixels.  This varies
3353                  * due to the quantization, so we can't simply take
3354                  * the area to be a constant: area = scx * scy. */
3355             area = ((16 - xuf) + 16 * (delx - 1) + xlf) *
3356                    ((16 - yuf) + 16 * (dely - 1) + ylf);
3357 
3358                 /* Do area map summation */
3359             pixel00 = *(lines + xup);
3360             pixel10 = *(lines + xlp);
3361             pixel01 = *(lines + dely * wpls +  xup);
3362             pixel11 = *(lines + dely * wpls +  xlp);
3363             area00 = (16 - xuf) * (16 - yuf);
3364             area10 = xlf * (16 - yuf);
3365             area01 = (16 - xuf) * ylf;
3366             area11 = xlf * ylf;
3367             v00r = area00 * ((pixel00 >> L_RED_SHIFT) & 0xff);
3368             v00g = area00 * ((pixel00 >> L_GREEN_SHIFT) & 0xff);
3369             v00b = area00 * ((pixel00 >> L_BLUE_SHIFT) & 0xff);
3370             v10r = area10 * ((pixel10 >> L_RED_SHIFT) & 0xff);
3371             v10g = area10 * ((pixel10 >> L_GREEN_SHIFT) & 0xff);
3372             v10b = area10 * ((pixel10 >> L_BLUE_SHIFT) & 0xff);
3373             v01r = area01 * ((pixel01 >> L_RED_SHIFT) & 0xff);
3374             v01g = area01 * ((pixel01 >> L_GREEN_SHIFT) & 0xff);
3375             v01b = area01 * ((pixel01 >> L_BLUE_SHIFT) & 0xff);
3376             v11r = area11 * ((pixel11 >> L_RED_SHIFT) & 0xff);
3377             v11g = area11 * ((pixel11 >> L_GREEN_SHIFT) & 0xff);
3378             v11b = area11 * ((pixel11 >> L_BLUE_SHIFT) & 0xff);
3379             vinr = ving = vinb = 0;
3380             for (k = 1; k < dely; k++) {  /* for full src pixels */
3381                 for (m = 1; m < delx; m++) {
3382                     pixel = *(lines + k * wpls + xup + m);
3383                     vinr += 256 * ((pixel >> L_RED_SHIFT) & 0xff);
3384                     ving += 256 * ((pixel >> L_GREEN_SHIFT) & 0xff);
3385                     vinb += 256 * ((pixel >> L_BLUE_SHIFT) & 0xff);
3386                 }
3387             }
3388             vmidr = vmidg = vmidb = 0;
3389             areal = (16 - xuf) * 16;
3390             arear = xlf * 16;
3391             areat = 16 * (16 - yuf);
3392             areab = 16 * ylf;
3393             for (k = 1; k < dely; k++) {  /* for left side */
3394                 pixel = *(lines + k * wpls + xup);
3395                 vmidr += areal * ((pixel >> L_RED_SHIFT) & 0xff);
3396                 vmidg += areal * ((pixel >> L_GREEN_SHIFT) & 0xff);
3397                 vmidb += areal * ((pixel >> L_BLUE_SHIFT) & 0xff);
3398             }
3399             for (k = 1; k < dely; k++) {  /* for right side */
3400                 pixel = *(lines + k * wpls + xlp);
3401                 vmidr += arear * ((pixel >> L_RED_SHIFT) & 0xff);
3402                 vmidg += arear * ((pixel >> L_GREEN_SHIFT) & 0xff);
3403                 vmidb += arear * ((pixel >> L_BLUE_SHIFT) & 0xff);
3404             }
3405             for (m = 1; m < delx; m++) {  /* for top side */
3406                 pixel = *(lines + xup + m);
3407                 vmidr += areat * ((pixel >> L_RED_SHIFT) & 0xff);
3408                 vmidg += areat * ((pixel >> L_GREEN_SHIFT) & 0xff);
3409                 vmidb += areat * ((pixel >> L_BLUE_SHIFT) & 0xff);
3410             }
3411             for (m = 1; m < delx; m++) {  /* for bottom side */
3412                 pixel = *(lines + dely * wpls + xup + m);
3413                 vmidr += areab * ((pixel >> L_RED_SHIFT) & 0xff);
3414                 vmidg += areab * ((pixel >> L_GREEN_SHIFT) & 0xff);
3415                 vmidb += areab * ((pixel >> L_BLUE_SHIFT) & 0xff);
3416             }
3417 
3418                 /* Sum all the contributions */
3419             rval = (v00r + v01r + v10r + v11r + vinr + vmidr + 128) / area;
3420             gval = (v00g + v01g + v10g + v11g + ving + vmidg + 128) / area;
3421             bval = (v00b + v01b + v10b + v11b + vinb + vmidb + 128) / area;
3422 #if  DEBUG_OVERFLOW
3423             if (rval > 255) fprintf(stderr, "rval ovfl: %d\n", rval);
3424             if (gval > 255) fprintf(stderr, "gval ovfl: %d\n", gval);
3425             if (bval > 255) fprintf(stderr, "bval ovfl: %d\n", bval);
3426 #endif  /* DEBUG_OVERFLOW */
3427             composeRGBPixel(rval, gval, bval, lined + j);
3428         }
3429     }
3430 }
3431 
3432 
3433 /*!
3434  * \brief   scaleGrayAreaMapLow()
3435  *
3436  *  This should only be used for downscaling.
3437  *  We choose to divide each pixel into 16 x 16 sub-pixels.
3438  *  This is about 2x slower than scaleSmoothLow(), but the results
3439  *  are significantly better on small text, esp. for downscaling
3440  *  factors between 1.5 and 5.  All src pixels are subdivided
3441  *  into 256 sub-pixels, and are weighted by the number of
3442  *  sub-pixels covered by the dest pixel.
3443  */
3444 static void
scaleGrayAreaMapLow(l_uint32 * datad,l_int32 wd,l_int32 hd,l_int32 wpld,l_uint32 * datas,l_int32 ws,l_int32 hs,l_int32 wpls)3445 scaleGrayAreaMapLow(l_uint32  *datad,
3446                     l_int32    wd,
3447                     l_int32    hd,
3448                     l_int32    wpld,
3449                     l_uint32  *datas,
3450                     l_int32    ws,
3451                     l_int32    hs,
3452                     l_int32    wpls)
3453 {
3454 l_int32    i, j, k, m, wm2, hm2;
3455 l_int32    xu, yu;  /* UL corner in src image, to 1/16 of a pixel */
3456 l_int32    xl, yl;  /* LR corner in src image, to 1/16 of a pixel */
3457 l_int32    xup, yup, xuf, yuf;  /* UL src pixel: integer and fraction */
3458 l_int32    xlp, ylp, xlf, ylf;  /* LR src pixel: integer and fraction */
3459 l_int32    delx, dely, area;
3460 l_int32    v00;  /* contrib. from UL src pixel */
3461 l_int32    v01;  /* contrib. from LL src pixel */
3462 l_int32    v10;  /* contrib from UR src pixel */
3463 l_int32    v11;  /* contrib from LR src pixel */
3464 l_int32    vin;  /* contrib from all full interior src pixels */
3465 l_int32    vmid;  /* contrib from side parts that are full in 1 direction */
3466 l_int32    val;
3467 l_uint32  *lines, *lined;
3468 l_float32  scx, scy;
3469 
3470         /* (scx, scy) are scaling factors that are applied to the
3471          * dest coords to get the corresponding src coords.
3472          * We need them because we iterate over dest pixels
3473          * and must find the corresponding set of src pixels. */
3474     scx = 16. * (l_float32)ws / (l_float32)wd;
3475     scy = 16. * (l_float32)hs / (l_float32)hd;
3476     wm2 = ws - 2;
3477     hm2 = hs - 2;
3478 
3479         /* Iterate over the destination pixels */
3480     for (i = 0; i < hd; i++) {
3481         yu = (l_int32)(scy * i);
3482         yl = (l_int32)(scy * (i + 1.0));
3483         yup = yu >> 4;
3484         yuf = yu & 0x0f;
3485         ylp = yl >> 4;
3486         ylf = yl & 0x0f;
3487         dely = ylp - yup;
3488         lined = datad + i * wpld;
3489         lines = datas + yup * wpls;
3490         for (j = 0; j < wd; j++) {
3491             xu = (l_int32)(scx * j);
3492             xl = (l_int32)(scx * (j + 1.0));
3493             xup = xu >> 4;
3494             xuf = xu & 0x0f;
3495             xlp = xl >> 4;
3496             xlf = xl & 0x0f;
3497             delx = xlp - xup;
3498 
3499                 /* If near the edge, just use a src pixel value */
3500             if (xlp > wm2 || ylp > hm2) {
3501                 SET_DATA_BYTE(lined, j, GET_DATA_BYTE(lines, xup));
3502                 continue;
3503             }
3504 
3505                 /* Area summed over, in subpixels.  This varies
3506                  * due to the quantization, so we can't simply take
3507                  * the area to be a constant: area = scx * scy. */
3508             area = ((16 - xuf) + 16 * (delx - 1) + xlf) *
3509                    ((16 - yuf) + 16 * (dely - 1) + ylf);
3510 
3511                 /* Do area map summation */
3512             v00 = (16 - xuf) * (16 - yuf) * GET_DATA_BYTE(lines, xup);
3513             v10 = xlf * (16 - yuf) * GET_DATA_BYTE(lines, xlp);
3514             v01 = (16 - xuf) * ylf * GET_DATA_BYTE(lines + dely * wpls, xup);
3515             v11 = xlf * ylf * GET_DATA_BYTE(lines + dely * wpls, xlp);
3516             for (vin = 0, k = 1; k < dely; k++) {  /* for full src pixels */
3517                  for (m = 1; m < delx; m++) {
3518                      vin += 256 * GET_DATA_BYTE(lines + k * wpls, xup + m);
3519                  }
3520             }
3521             for (vmid = 0, k = 1; k < dely; k++)  /* for left side */
3522                 vmid += (16 - xuf) * 16 * GET_DATA_BYTE(lines + k * wpls, xup);
3523             for (k = 1; k < dely; k++)  /* for right side */
3524                 vmid += xlf * 16 * GET_DATA_BYTE(lines + k * wpls, xlp);
3525             for (m = 1; m < delx; m++)  /* for top side */
3526                 vmid += 16 * (16 - yuf) * GET_DATA_BYTE(lines, xup + m);
3527             for (m = 1; m < delx; m++)  /* for bottom side */
3528                 vmid += 16 * ylf * GET_DATA_BYTE(lines + dely * wpls, xup + m);
3529             val = (v00 + v01 + v10 + v11 + vin + vmid + 128) / area;
3530 #if  DEBUG_OVERFLOW
3531             if (val > 255) fprintf(stderr, "val overflow: %d\n", val);
3532 #endif  /* DEBUG_OVERFLOW */
3533             SET_DATA_BYTE(lined, j, val);
3534         }
3535     }
3536 }
3537 
3538 
3539 /*------------------------------------------------------------------*
3540  *                     2x area mapped downscaling                   *
3541  *------------------------------------------------------------------*/
3542 /*!
3543  * \brief   scaleAreaMapLow2()
3544  *
3545  *  Notes:
3546  *        This function is called with either 8 bpp gray or 32 bpp RGB.
3547  *        The result is a 2x reduced dest.
3548  */
3549 static void
scaleAreaMapLow2(l_uint32 * datad,l_int32 wd,l_int32 hd,l_int32 wpld,l_uint32 * datas,l_int32 d,l_int32 wpls)3550 scaleAreaMapLow2(l_uint32  *datad,
3551                  l_int32    wd,
3552                  l_int32    hd,
3553                  l_int32    wpld,
3554                  l_uint32  *datas,
3555                  l_int32    d,
3556                  l_int32    wpls)
3557 {
3558 l_int32    i, j, val, rval, gval, bval;
3559 l_uint32  *lines, *lined;
3560 l_uint32   pixel;
3561 
3562     if (d == 8) {
3563         for (i = 0; i < hd; i++) {
3564             lines = datas + 2 * i * wpls;
3565             lined = datad + i * wpld;
3566             for (j = 0; j < wd; j++) {
3567                     /* Average each dest pixel using 4 src pixels */
3568                 val = GET_DATA_BYTE(lines, 2 * j);
3569                 val += GET_DATA_BYTE(lines, 2 * j + 1);
3570                 val += GET_DATA_BYTE(lines + wpls, 2 * j);
3571                 val += GET_DATA_BYTE(lines + wpls, 2 * j + 1);
3572                 val >>= 2;
3573                 SET_DATA_BYTE(lined, j, val);
3574             }
3575         }
3576     } else {  /* d == 32 */
3577         for (i = 0; i < hd; i++) {
3578             lines = datas + 2 * i * wpls;
3579             lined = datad + i * wpld;
3580             for (j = 0; j < wd; j++) {
3581                     /* Average each of the color components from 4 src pixels */
3582                 pixel = *(lines + 2 * j);
3583                 rval = (pixel >> L_RED_SHIFT) & 0xff;
3584                 gval = (pixel >> L_GREEN_SHIFT) & 0xff;
3585                 bval = (pixel >> L_BLUE_SHIFT) & 0xff;
3586                 pixel = *(lines + 2 * j + 1);
3587                 rval += (pixel >> L_RED_SHIFT) & 0xff;
3588                 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3589                 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3590                 pixel = *(lines + wpls + 2 * j);
3591                 rval += (pixel >> L_RED_SHIFT) & 0xff;
3592                 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3593                 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3594                 pixel = *(lines + wpls + 2 * j + 1);
3595                 rval += (pixel >> L_RED_SHIFT) & 0xff;
3596                 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3597                 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3598                 composeRGBPixel(rval >> 2, gval >> 2, bval >> 2, &pixel);
3599                 *(lined + j) = pixel;
3600             }
3601         }
3602     }
3603 }
3604 
3605 
3606 /*------------------------------------------------------------------*
3607  *              Binary scaling by closest pixel sampling            *
3608  *------------------------------------------------------------------*/
3609 /*
3610  *  scaleBinaryLow()
3611  *
3612  *  Notes:
3613  *      (1) The dest must be cleared prior to this operation,
3614  *          and we clear it here in the low-level code.
3615  *      (2) We reuse dest pixels and dest pixel rows whenever
3616  *          possible for upscaling; downscaling is done by
3617  *          strict subsampling.
3618  */
3619 static l_int32
scaleBinaryLow(l_uint32 * datad,l_int32 wd,l_int32 hd,l_int32 wpld,l_uint32 * datas,l_int32 ws,l_int32 hs,l_int32 wpls)3620 scaleBinaryLow(l_uint32  *datad,
3621                l_int32    wd,
3622                l_int32    hd,
3623                l_int32    wpld,
3624                l_uint32  *datas,
3625                l_int32    ws,
3626                l_int32    hs,
3627                l_int32    wpls)
3628 {
3629 l_int32    i, j, bpld;
3630 l_int32    xs, prevxs, sval;
3631 l_int32   *srow, *scol;
3632 l_uint32  *lines, *prevlines, *lined, *prevlined;
3633 l_float32  wratio, hratio;
3634 
3635     PROCNAME("scaleBinaryLow");
3636 
3637         /* clear dest */
3638     bpld = 4 * wpld;
3639     memset((char *)datad, 0, hd * bpld);
3640 
3641         /* The source row corresponding to dest row i ==> srow[i]
3642          * The source col corresponding to dest col j ==> scol[j]  */
3643     if ((srow = (l_int32 *)LEPT_CALLOC(hd, sizeof(l_int32))) == NULL)
3644         return ERROR_INT("srow not made", procName, 1);
3645     if ((scol = (l_int32 *)LEPT_CALLOC(wd, sizeof(l_int32))) == NULL) {
3646         LEPT_FREE(srow);
3647         return ERROR_INT("scol not made", procName, 1);
3648     }
3649 
3650     wratio = (l_float32)ws / (l_float32)wd;
3651     hratio = (l_float32)hs / (l_float32)hd;
3652     for (i = 0; i < hd; i++)
3653         srow[i] = L_MIN((l_int32)(hratio * i + 0.5), hs - 1);
3654     for (j = 0; j < wd; j++)
3655         scol[j] = L_MIN((l_int32)(wratio * j + 0.5), ws - 1);
3656 
3657     prevlines = NULL;
3658     prevxs = -1;
3659     sval = 0;
3660     for (i = 0; i < hd; i++) {
3661         lines = datas + srow[i] * wpls;
3662         lined = datad + i * wpld;
3663         if (lines != prevlines) {  /* make dest from new source row */
3664             for (j = 0; j < wd; j++) {
3665                 xs = scol[j];
3666                 if (xs != prevxs) {  /* get dest pix from source col */
3667                     if ((sval = GET_DATA_BIT(lines, xs)))
3668                         SET_DATA_BIT(lined, j);
3669                     prevxs = xs;
3670                 } else {  /* copy prev dest pix, if set */
3671                     if (sval)
3672                         SET_DATA_BIT(lined, j);
3673                 }
3674             }
3675         } else {  /* lines == prevlines; copy prev dest row */
3676             prevlined = lined - wpld;
3677             memcpy((char *)lined, (char *)prevlined, bpld);
3678         }
3679         prevlines = lines;
3680     }
3681 
3682     LEPT_FREE(srow);
3683     LEPT_FREE(scol);
3684     return 0;
3685 }
3686 
3687