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 scale2.c
29  * <pre>
30  *         Scale-to-gray (1 bpp --> 8 bpp; arbitrary downscaling)
31  *               PIX      *pixScaleToGray()
32  *               PIX      *pixScaleToGrayFast()
33  *
34  *         Scale-to-gray (1 bpp --> 8 bpp; integer downscaling)
35  *               PIX      *pixScaleToGray2()
36  *               PIX      *pixScaleToGray3()
37  *               PIX      *pixScaleToGray4()
38  *               PIX      *pixScaleToGray6()
39  *               PIX      *pixScaleToGray8()
40  *               PIX      *pixScaleToGray16()
41  *
42  *         Scale-to-gray by mipmap(1 bpp --> 8 bpp, arbitrary reduction)
43  *               PIX      *pixScaleToGrayMipmap()
44  *
45  *         Grayscale scaling using mipmap
46  *               PIX      *pixScaleMipmap()
47  *
48  *         Replicated (integer) expansion (all depths)
49  *               PIX      *pixExpandReplicate()
50  *
51  *         Grayscale downscaling using min and max
52  *               PIX      *pixScaleGrayMinMax()
53  *               PIX      *pixScaleGrayMinMax2()
54  *
55  *         Grayscale downscaling using rank value
56  *               PIX      *pixScaleGrayRankCascade()
57  *               PIX      *pixScaleGrayRank2()
58  *
59  *         Helper function for transferring alpha with scaling
60  *               l_int32   pixScaleAndTransferAlpha()
61  *
62  *         RGB scaling including alpha (blend) component
63  *               PIX      *pixScaleWithAlpha()
64  *
65  *     Low-level static functions:
66  *
67  *         Scale-to-gray 2x
68  *                  static void       scaleToGray2Low()
69  *                  static l_uint32  *makeSumTabSG2()
70  *                  static l_uint8   *makeValTabSG2()
71  *
72  *         Scale-to-gray 3x
73  *                  static void       scaleToGray3Low()
74  *                  static l_uint32  *makeSumTabSG3()
75  *                  static l_uint8   *makeValTabSG3()
76  *
77  *         Scale-to-gray 4x
78  *                  static void       scaleToGray4Low()
79  *                  static l_uint32  *makeSumTabSG4()
80  *                  static l_uint8   *makeValTabSG4()
81  *
82  *         Scale-to-gray 6x
83  *                  static void       scaleToGray6Low()
84  *                  static l_uint8   *makeValTabSG6()
85  *
86  *         Scale-to-gray 8x
87  *                  static void       scaleToGray8Low()
88  *                  static l_uint8   *makeValTabSG8()
89  *
90  *         Scale-to-gray 16x
91  *                  static void       scaleToGray16Low()
92  *
93  *         Grayscale mipmap
94  *                  static l_int32    scaleMipmapLow()
95  * </pre>
96  */
97 
98 #include <string.h>
99 #include "allheaders.h"
100 
101 static void scaleToGray2Low(l_uint32 *datad, l_int32 wd, l_int32 hd,
102                             l_int32 wpld, l_uint32 *datas, l_int32 wpls,
103                             l_uint32 *sumtab, l_uint8 *valtab);
104 static l_uint32 *makeSumTabSG2(void);
105 static l_uint8 *makeValTabSG2(void);
106 static void scaleToGray3Low(l_uint32 *datad, l_int32 wd, l_int32 hd,
107                             l_int32 wpld, l_uint32 *datas, l_int32 wpls,
108                             l_uint32 *sumtab, l_uint8 *valtab);
109 static l_uint32 *makeSumTabSG3(void);
110 static l_uint8 *makeValTabSG3(void);
111 static void scaleToGray4Low(l_uint32 *datad, l_int32 wd, l_int32 hd,
112                             l_int32 wpld, l_uint32 *datas, l_int32 wpls,
113                             l_uint32 *sumtab, l_uint8 *valtab);
114 static l_uint32 *makeSumTabSG4(void);
115 static l_uint8 *makeValTabSG4(void);
116 static void scaleToGray6Low(l_uint32 *datad, l_int32 wd, l_int32 hd,
117                             l_int32 wpld, l_uint32 *datas, l_int32 wpls,
118                             l_int32 *tab8, l_uint8 *valtab);
119 static l_uint8 *makeValTabSG6(void);
120 static void scaleToGray8Low(l_uint32 *datad, l_int32 wd, l_int32 hd,
121                             l_int32 wpld, l_uint32 *datas, l_int32 wpls,
122                             l_int32 *tab8, l_uint8 *valtab);
123 static l_uint8 *makeValTabSG8(void);
124 static void scaleToGray16Low(l_uint32 *datad, l_int32 wd, l_int32 hd,
125                              l_int32 wpld, l_uint32 *datas, l_int32 wpls,
126                              l_int32 *tab8);
127 static l_int32 scaleMipmapLow(l_uint32 *datad, l_int32 wd, l_int32 hd,
128                               l_int32 wpld, l_uint32 *datas1, l_int32 wpls1,
129                               l_uint32 *datas2, l_int32 wpls2, l_float32 red);
130 
131 extern l_float32  AlphaMaskBorderVals[2];
132 
133 
134 /*------------------------------------------------------------------*
135  *      Scale-to-gray (1 bpp --> 8 bpp; arbitrary downscaling)      *
136  *------------------------------------------------------------------*/
137 /*!
138  * \brief   pixScaleToGray()
139  *
140  * \param[in]    pixs 1 bpp
141  * \param[in]    scalefactor reduction: must be > 0.0 and < 1.0
142  * \return  pixd 8 bpp, scaled down by scalefactor in each direction,
143  *              or NULL on error.
144  *
145  * <pre>
146  * Notes:
147  *
148  *  For faster scaling in the range of scalefactors from 0.0625 to 0.5,
149  *  with very little difference in quality, use pixScaleToGrayFast().
150  *
151  *  Binary images have sharp edges, so they intrinsically have very
152  *  high frequency content.  To avoid aliasing, they must be low-pass
153  *  filtered, which tends to blur the edges.  How can we keep relatively
154  *  crisp edges without aliasing?  The trick is to do binary upscaling
155  *  followed by a power-of-2 scaleToGray.  For large reductions, where
156  *  you don't end up with much detail, some corners can be cut.
157  *
158  *  The intent here is to get high quality reduced grayscale
159  *  images with relatively little computation.  We do binary
160  *  pre-scaling followed by scaleToGrayN() for best results,
161  *  esp. to avoid excess blur when the scale factor is near
162  *  an inverse power of 2.  Where a low-pass filter is required,
163  *  we use simple convolution kernels: either the hat filter for
164  *  linear interpolation or a flat filter for larger downscaling.
165  *  Other choices, such as a perfect bandpass filter with infinite extent
166  *  (the sinc) or various approximations to it (e.g., lanczos), are
167  *  unnecessarily expensive.
168  *
169  *  The choices made are as follows:
170  *      (1) Do binary upscaling before scaleToGrayN() for scalefactors > 1/8
171  *      (2) Do binary downscaling before scaleToGray8() for scalefactors
172  *          between 1/16 and 1/8.
173  *      (3) Use scaleToGray16() before grayscale downscaling for
174  *          scalefactors less than 1/16
175  *  Another reasonable choice would be to start binary downscaling
176  *  for scalefactors below 1/4, rather than below 1/8 as we do here.
177  *
178  *  The general scaling rules, not all of which are used here, go as follows:
179  *      (1) For grayscale upscaling, use pixScaleGrayLI().  However,
180  *          note that edges will be visibly blurred for scalefactors
181  *          near (but above) 1.0.  Replication will avoid edge blur,
182  *          and should be considered for factors very near 1.0.
183  *      (2) For grayscale downscaling with a scale factor larger than
184  *          about 0.7, use pixScaleGrayLI().  For scalefactors near
185  *          (but below) 1.0, you tread between Scylla and Charybdis.
186  *          pixScaleGrayLI() again gives edge blurring, but
187  *          pixScaleBySampling() gives visible aliasing.
188  *      (3) For grayscale downscaling with a scale factor smaller than
189  *          about 0.7, use pixScaleSmooth()
190  *      (4) For binary input images, do as much scale to gray as possible
191  *          using the special integer functions (2, 3, 4, 8 and 16).
192  *      (5) It is better to upscale in binary, followed by scaleToGrayN()
193  *          than to do scaleToGrayN() followed by an upscale using either
194  *          LI or oversampling.
195  *      (6) It may be better to downscale in binary, followed by
196  *          scaleToGrayN() than to first use scaleToGrayN() followed by
197  *          downscaling.  For downscaling between 8x and 16x, this is
198  *          a reasonable option.
199  *      (7) For reductions greater than 16x, it's reasonable to use
200  *          scaleToGray16() followed by further grayscale downscaling.
201  * </pre>
202  */
203 PIX *
pixScaleToGray(PIX * pixs,l_float32 scalefactor)204 pixScaleToGray(PIX       *pixs,
205                l_float32  scalefactor)
206 {
207 l_int32    w, h, minsrc, mindest;
208 l_float32  mag, red;
209 PIX       *pixt, *pixd;
210 
211     PROCNAME("pixScaleToGray");
212 
213     if (!pixs)
214         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
215     if (pixGetDepth(pixs) != 1)
216         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
217     if (scalefactor <= 0.0)
218         return (PIX *)ERROR_PTR("scalefactor <= 0.0", procName, NULL);
219     if (scalefactor >= 1.0)
220         return (PIX *)ERROR_PTR("scalefactor >= 1.0", procName, NULL);
221     pixGetDimensions(pixs, &w, &h, NULL);
222     minsrc = L_MIN(w, h);
223     mindest = (l_int32)((l_float32)minsrc * scalefactor);
224     if (mindest < 2)
225         return (PIX *)ERROR_PTR("scalefactor too small", procName, NULL);
226 
227     if (scalefactor > 0.5) {   /* see note (5) */
228         mag = 2.0 * scalefactor;  /* will be < 2.0 */
229 /*        fprintf(stderr, "2x with mag %7.3f\n", mag);  */
230         if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL)
231             return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
232         pixd = pixScaleToGray2(pixt);
233     } else if (scalefactor == 0.5) {
234         return pixd = pixScaleToGray2(pixs);
235     } else if (scalefactor > 0.33333) {   /* see note (5) */
236         mag = 3.0 * scalefactor;   /* will be < 1.5 */
237 /*        fprintf(stderr, "3x with mag %7.3f\n", mag);  */
238         if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL)
239             return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
240         pixd = pixScaleToGray3(pixt);
241     } else if (scalefactor > 0.25) {  /* see note (5) */
242         mag = 4.0 * scalefactor;   /* will be < 1.3333 */
243 /*        fprintf(stderr, "4x with mag %7.3f\n", mag);  */
244         if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL)
245             return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
246         pixd = pixScaleToGray4(pixt);
247     } else if (scalefactor == 0.25) {
248         return pixd = pixScaleToGray4(pixs);
249     } else if (scalefactor > 0.16667) {  /* see note (5) */
250         mag = 6.0 * scalefactor;   /* will be < 1.5 */
251 /*        fprintf(stderr, "6x with mag %7.3f\n", mag); */
252         if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL)
253             return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
254         pixd = pixScaleToGray6(pixt);
255     } else if (scalefactor == 0.16667) {
256         return pixd = pixScaleToGray6(pixs);
257     } else if (scalefactor > 0.125) {  /* see note (5) */
258         mag = 8.0 * scalefactor;   /*  will be < 1.3333  */
259 /*        fprintf(stderr, "8x with mag %7.3f\n", mag);  */
260         if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL)
261             return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
262         pixd = pixScaleToGray8(pixt);
263     } else if (scalefactor == 0.125) {
264         return pixd = pixScaleToGray8(pixs);
265     } else if (scalefactor > 0.0625) {  /* see note (6) */
266         red = 8.0 * scalefactor;   /* will be > 0.5 */
267 /*        fprintf(stderr, "8x with red %7.3f\n", red);  */
268         if ((pixt = pixScaleBinary(pixs, red, red)) == NULL)
269             return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
270         pixd = pixScaleToGray8(pixt);
271     } else if (scalefactor == 0.0625) {
272         return pixd = pixScaleToGray16(pixs);
273     } else {  /* see note (7) */
274         red = 16.0 * scalefactor;  /* will be <= 1.0 */
275 /*        fprintf(stderr, "16x with red %7.3f\n", red);  */
276         if ((pixt = pixScaleToGray16(pixs)) == NULL)
277             return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
278         if (red < 0.7)
279             pixd = pixScaleSmooth(pixt, red, red);  /* see note (3) */
280         else
281             pixd = pixScaleGrayLI(pixt, red, red);  /* see note (2) */
282     }
283 
284     pixDestroy(&pixt);
285     if (!pixd)
286         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
287     pixCopyInputFormat(pixd, pixs);
288     return pixd;
289 }
290 
291 
292 /*!
293  * \brief   pixScaleToGrayFast()
294  *
295  * \param[in]    pixs 1 bpp
296  * \param[in]    scalefactor reduction: must be > 0.0 and < 1.0
297  * \return  pixd 8 bpp, scaled down by scalefactor in each direction,
298  *              or NULL on error.
299  *
300  * <pre>
301  * Notes:
302  *      (1) See notes in pixScaleToGray() for the basic approach.
303  *      (2) This function is considerably less expensive than pixScaleToGray()
304  *          for scalefactor in the range (0.0625 ... 0.5), and the
305  *          quality is nearly as good.
306  *      (3) Unlike pixScaleToGray(), which does binary upscaling before
307  *          downscaling for scale factors >= 0.0625, pixScaleToGrayFast()
308  *          first downscales in binary for all scale factors < 0.5, and
309  *          then does a 2x scale-to-gray as the final step.  For
310  *          scale factors < 0.0625, both do a 16x scale-to-gray, followed
311  *          by further grayscale reduction.
312  * </pre>
313  */
314 PIX *
pixScaleToGrayFast(PIX * pixs,l_float32 scalefactor)315 pixScaleToGrayFast(PIX       *pixs,
316                    l_float32  scalefactor)
317 {
318 l_int32    w, h, minsrc, mindest;
319 l_float32  eps, factor;
320 PIX       *pixt, *pixd;
321 
322     PROCNAME("pixScaleToGrayFast");
323 
324     if (!pixs)
325         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
326     if (pixGetDepth(pixs) != 1)
327         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
328     if (scalefactor <= 0.0)
329         return (PIX *)ERROR_PTR("scalefactor <= 0.0", procName, NULL);
330     if (scalefactor >= 1.0)
331         return (PIX *)ERROR_PTR("scalefactor >= 1.0", procName, NULL);
332     pixGetDimensions(pixs, &w, &h, NULL);
333     minsrc = L_MIN(w, h);
334     mindest = (l_int32)((l_float32)minsrc * scalefactor);
335     if (mindest < 2)
336         return (PIX *)ERROR_PTR("scalefactor too small", procName, NULL);
337     eps = 0.0001;
338 
339         /* Handle the special cases */
340     if (scalefactor > 0.5 - eps && scalefactor < 0.5 + eps)
341         return pixScaleToGray2(pixs);
342     else if (scalefactor > 0.33333 - eps && scalefactor < 0.33333 + eps)
343         return pixScaleToGray3(pixs);
344     else if (scalefactor > 0.25 - eps && scalefactor < 0.25 + eps)
345         return pixScaleToGray4(pixs);
346     else if (scalefactor > 0.16666 - eps && scalefactor < 0.16666 + eps)
347         return pixScaleToGray6(pixs);
348     else if (scalefactor > 0.125 - eps && scalefactor < 0.125 + eps)
349         return pixScaleToGray8(pixs);
350     else if (scalefactor > 0.0625 - eps && scalefactor < 0.0625 + eps)
351         return pixScaleToGray16(pixs);
352 
353     if (scalefactor > 0.0625) {  /* scale binary first */
354         factor = 2.0 * scalefactor;
355         if ((pixt = pixScaleBinary(pixs, factor, factor)) == NULL)
356             return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
357         pixd = pixScaleToGray2(pixt);
358     } else {  /* scalefactor < 0.0625; scale-to-gray first */
359         factor = 16.0 * scalefactor;  /* will be < 1.0 */
360         if ((pixt = pixScaleToGray16(pixs)) == NULL)
361             return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
362         if (factor < 0.7)
363             pixd = pixScaleSmooth(pixt, factor, factor);
364         else
365             pixd = pixScaleGrayLI(pixt, factor, factor);
366     }
367     pixDestroy(&pixt);
368     if (!pixd)
369         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
370     pixCopyInputFormat(pixd, pixs);
371     return pixd;
372 }
373 
374 
375 /*-----------------------------------------------------------------------*
376  *          Scale-to-gray (1 bpp --> 8 bpp; integer downscaling)         *
377  *-----------------------------------------------------------------------*/
378 /*!
379  * \brief   pixScaleToGray2()
380  *
381  * \param[in]    pixs 1 bpp
382  * \return  pixd 8 bpp, scaled down by 2x in each direction,
383  *              or NULL on error.
384  */
385 PIX *
pixScaleToGray2(PIX * pixs)386 pixScaleToGray2(PIX  *pixs)
387 {
388 l_uint8   *valtab;
389 l_int32    ws, hs, wd, hd;
390 l_int32    wpld, wpls;
391 l_uint32  *sumtab;
392 l_uint32  *datas, *datad;
393 PIX       *pixd;
394 
395     PROCNAME("pixScaleToGray2");
396 
397     if (!pixs)
398         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
399     if (pixGetDepth(pixs) != 1)
400         return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, NULL);
401 
402     pixGetDimensions(pixs, &ws, &hs, NULL);
403     wd = ws / 2;
404     hd = hs / 2;
405     if (wd == 0 || hd == 0)
406         return (PIX *)ERROR_PTR("pixs too small", procName, NULL);
407 
408     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
409         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
410     pixCopyInputFormat(pixd, pixs);
411     pixCopyResolution(pixd, pixs);
412     pixScaleResolution(pixd, 0.5, 0.5);
413     datas = pixGetData(pixs);
414     datad = pixGetData(pixd);
415     wpls = pixGetWpl(pixs);
416     wpld = pixGetWpl(pixd);
417 
418     sumtab = makeSumTabSG2();
419     valtab = makeValTabSG2();
420     scaleToGray2Low(datad, wd, hd, wpld, datas, wpls, sumtab, valtab);
421     LEPT_FREE(sumtab);
422     LEPT_FREE(valtab);
423     return pixd;
424 }
425 
426 
427 /*!
428  * \brief   pixScaleToGray3()
429  *
430  * \param[in]    pixs 1 bpp
431  * \return  pixd 8 bpp, scaled down by 3x in each direction,
432  *              or NULL on error.
433  *
434  * <pre>
435  * Notes:
436  *      (1) Speed is about 100 x 10^6 src-pixels/sec/GHz.
437  *          Another way to express this is it processes 1 src pixel
438  *          in about 10 cycles.
439  *      (2) The width of pixd is truncated is truncated to a factor of 8.
440  * </pre>
441  */
442 PIX *
pixScaleToGray3(PIX * pixs)443 pixScaleToGray3(PIX  *pixs)
444 {
445 l_uint8   *valtab;
446 l_int32    ws, hs, wd, hd;
447 l_int32    wpld, wpls;
448 l_uint32  *sumtab;
449 l_uint32  *datas, *datad;
450 PIX       *pixd;
451 
452     PROCNAME("pixScaleToGray3");
453 
454     if (!pixs)
455         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
456     if (pixGetDepth(pixs) != 1)
457         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
458 
459     pixGetDimensions(pixs, &ws, &hs, NULL);
460     wd = (ws / 3) & 0xfffffff8;    /* truncate to factor of 8 */
461     hd = hs / 3;
462     if (wd == 0 || hd == 0)
463         return (PIX *)ERROR_PTR("pixs too small", procName, NULL);
464 
465     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
466         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
467     pixCopyInputFormat(pixd, pixs);
468     pixCopyResolution(pixd, pixs);
469     pixScaleResolution(pixd, 0.33333, 0.33333);
470     datas = pixGetData(pixs);
471     datad = pixGetData(pixd);
472     wpls = pixGetWpl(pixs);
473     wpld = pixGetWpl(pixd);
474 
475     sumtab = makeSumTabSG3();
476     valtab = makeValTabSG3();
477     scaleToGray3Low(datad, wd, hd, wpld, datas, wpls, sumtab, valtab);
478     LEPT_FREE(sumtab);
479     LEPT_FREE(valtab);
480     return pixd;
481 }
482 
483 
484 /*!
485  * \brief   pixScaleToGray4()
486  *
487  * \param[in]    pixs 1 bpp
488  * \return  pixd 8 bpp, scaled down by 4x in each direction,
489  *              or NULL on error.
490  *
491  * <pre>
492  * Notes:
493  *      (1) The width of pixd is truncated is truncated to a factor of 2.
494  * </pre>
495  */
496 PIX *
pixScaleToGray4(PIX * pixs)497 pixScaleToGray4(PIX  *pixs)
498 {
499 l_uint8   *valtab;
500 l_int32    ws, hs, wd, hd;
501 l_int32    wpld, wpls;
502 l_uint32  *sumtab;
503 l_uint32  *datas, *datad;
504 PIX       *pixd;
505 
506     PROCNAME("pixScaleToGray4");
507 
508     if (!pixs)
509         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
510     if (pixGetDepth(pixs) != 1)
511         return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, NULL);
512 
513     pixGetDimensions(pixs, &ws, &hs, NULL);
514     wd = (ws / 4) & 0xfffffffe;    /* truncate to factor of 2 */
515     hd = hs / 4;
516     if (wd == 0 || hd == 0)
517         return (PIX *)ERROR_PTR("pixs too small", procName, NULL);
518 
519     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
520         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
521     pixCopyInputFormat(pixd, pixs);
522     pixCopyResolution(pixd, pixs);
523     pixScaleResolution(pixd, 0.25, 0.25);
524     datas = pixGetData(pixs);
525     datad = pixGetData(pixd);
526     wpls = pixGetWpl(pixs);
527     wpld = pixGetWpl(pixd);
528 
529     sumtab = makeSumTabSG4();
530     valtab = makeValTabSG4();
531     scaleToGray4Low(datad, wd, hd, wpld, datas, wpls, sumtab, valtab);
532     LEPT_FREE(sumtab);
533     LEPT_FREE(valtab);
534     return pixd;
535 }
536 
537 
538 
539 /*!
540  * \brief   pixScaleToGray6()
541  *
542  * \param[in]    pixs 1 bpp
543  * \return  pixd 8 bpp, scaled down by 6x in each direction,
544  *              or NULL on error.
545  *
546  * <pre>
547  * Notes:
548  *      (1) The width of pixd is truncated is truncated to a factor of 8.
549  * </pre>
550  */
551 PIX *
pixScaleToGray6(PIX * pixs)552 pixScaleToGray6(PIX  *pixs)
553 {
554 l_uint8   *valtab;
555 l_int32    ws, hs, wd, hd, wpld, wpls;
556 l_int32   *tab8;
557 l_uint32  *datas, *datad;
558 PIX       *pixd;
559 
560     PROCNAME("pixScaleToGray6");
561 
562     if (!pixs)
563         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
564     if (pixGetDepth(pixs) != 1)
565         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
566 
567     pixGetDimensions(pixs, &ws, &hs, NULL);
568     wd = (ws / 6) & 0xfffffff8;    /* truncate to factor of 8 */
569     hd = hs / 6;
570     if (wd == 0 || hd == 0)
571         return (PIX *)ERROR_PTR("pixs too small", procName, NULL);
572 
573     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
574         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
575     pixCopyInputFormat(pixd, pixs);
576     pixCopyResolution(pixd, pixs);
577     pixScaleResolution(pixd, 0.16667, 0.16667);
578     datas = pixGetData(pixs);
579     datad = pixGetData(pixd);
580     wpls = pixGetWpl(pixs);
581     wpld = pixGetWpl(pixd);
582 
583     tab8 = makePixelSumTab8();
584     valtab = makeValTabSG6();
585     scaleToGray6Low(datad, wd, hd, wpld, datas, wpls, tab8, valtab);
586     LEPT_FREE(tab8);
587     LEPT_FREE(valtab);
588     return pixd;
589 }
590 
591 
592 /*!
593  * \brief   pixScaleToGray8()
594  *
595  * \param[in]    pixs 1 bpp
596  * \return  pixd 8 bpp, scaled down by 8x in each direction,
597  *              or NULL on error
598  */
599 PIX *
pixScaleToGray8(PIX * pixs)600 pixScaleToGray8(PIX  *pixs)
601 {
602 l_uint8   *valtab;
603 l_int32    ws, hs, wd, hd;
604 l_int32    wpld, wpls;
605 l_int32   *tab8;
606 l_uint32  *datas, *datad;
607 PIX       *pixd;
608 
609     PROCNAME("pixScaleToGray8");
610 
611     if (!pixs)
612         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
613     if (pixGetDepth(pixs) != 1)
614         return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, NULL);
615 
616     pixGetDimensions(pixs, &ws, &hs, NULL);
617     wd = ws / 8;  /* truncate to nearest dest byte */
618     hd = hs / 8;
619     if (wd == 0 || hd == 0)
620         return (PIX *)ERROR_PTR("pixs too small", procName, NULL);
621 
622     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
623         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
624     pixCopyInputFormat(pixd, pixs);
625     pixCopyResolution(pixd, pixs);
626     pixScaleResolution(pixd, 0.125, 0.125);
627     datas = pixGetData(pixs);
628     datad = pixGetData(pixd);
629     wpls = pixGetWpl(pixs);
630     wpld = pixGetWpl(pixd);
631 
632     tab8 = makePixelSumTab8();
633     valtab = makeValTabSG8();
634     scaleToGray8Low(datad, wd, hd, wpld, datas, wpls, tab8, valtab);
635     LEPT_FREE(tab8);
636     LEPT_FREE(valtab);
637     return pixd;
638 }
639 
640 
641 /*!
642  * \brief   pixScaleToGray16()
643  *
644  * \param[in]    pixs 1 bpp
645  * \return  pixd 8 bpp, scaled down by 16x in each direction,
646  *              or NULL on error.
647  */
648 PIX *
pixScaleToGray16(PIX * pixs)649 pixScaleToGray16(PIX  *pixs)
650 {
651 l_int32    ws, hs, wd, hd;
652 l_int32    wpld, wpls;
653 l_int32   *tab8;
654 l_uint32  *datas, *datad;
655 PIX       *pixd;
656 
657     PROCNAME("pixScaleToGray16");
658 
659     if (!pixs)
660         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
661     if (pixGetDepth(pixs) != 1)
662         return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, NULL);
663 
664     pixGetDimensions(pixs, &ws, &hs, NULL);
665     wd = ws / 16;
666     hd = hs / 16;
667     if (wd == 0 || hd == 0)
668         return (PIX *)ERROR_PTR("pixs too small", procName, NULL);
669 
670     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
671         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
672     pixCopyInputFormat(pixd, pixs);
673     pixCopyResolution(pixd, pixs);
674     pixScaleResolution(pixd, 0.0625, 0.0625);
675     datas = pixGetData(pixs);
676     datad = pixGetData(pixd);
677     wpls = pixGetWpl(pixs);
678     wpld = pixGetWpl(pixd);
679 
680     tab8 = makePixelSumTab8();
681     scaleToGray16Low(datad, wd, hd, wpld, datas, wpls, tab8);
682     LEPT_FREE(tab8);
683     return pixd;
684 }
685 
686 
687 /*------------------------------------------------------------------*
688  *    Scale-to-gray mipmap(1 bpp --> 8 bpp, arbitrary reduction)    *
689  *------------------------------------------------------------------*/
690 /*!
691  * \brief   pixScaleToGrayMipmap()
692  *
693  * \param[in]    pixs 1 bpp
694  * \param[in]    scalefactor reduction: must be > 0.0 and < 1.0
695  * \return  pixd 8 bpp, scaled down by scalefactor in each direction,
696  *              or NULL on error.
697  *
698  * <pre>
699  * Notes:
700  *
701  *  This function is here mainly for pedagogical reasons.
702  *  Mip-mapping is widely used in graphics for texture mapping, because
703  *  the texture changes smoothly with scale.  This is accomplished by
704  *  constructing a multiresolution pyramid and, for each pixel,
705  *  doing a linear interpolation between corresponding pixels in
706  *  the two planes of the pyramid that bracket the desired resolution.
707  *  The computation is very efficient, and is implemented in hardware
708  *  in high-end graphics cards.
709  *
710  *  We can use mip-mapping for scale-to-gray by using two scale-to-gray
711  *  reduced images (we don't need the entire pyramid) selected from
712  *  the set {2x, 4x, ... 16x}, and interpolating.  However, we get
713  *  severe aliasing, probably because we are subsampling from the
714  *  higher resolution image.  The method is very fast, but the result
715  *  is very poor.  In fact, the results don't look any better than
716  *  either subsampling off the higher-res grayscale image or oversampling
717  *  on the lower-res image.  Consequently, this method should NOT be used
718  *  for generating reduced images, scale-to-gray or otherwise.
719  * </pre>
720  */
721 PIX *
pixScaleToGrayMipmap(PIX * pixs,l_float32 scalefactor)722 pixScaleToGrayMipmap(PIX       *pixs,
723                      l_float32  scalefactor)
724 {
725 l_int32    w, h, minsrc, mindest;
726 l_float32  red;
727 PIX       *pixs1, *pixs2, *pixt, *pixd;
728 
729     PROCNAME("pixScaleToGrayMipmap");
730 
731     if (!pixs)
732         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
733     if (pixGetDepth(pixs) != 1)
734         return (PIX *)ERROR_PTR("pixs not 1 bpp", procName, NULL);
735     if (scalefactor <= 0.0)
736         return (PIX *)ERROR_PTR("scalefactor <= 0.0", procName, NULL);
737     if (scalefactor >= 1.0)
738         return (PIX *)ERROR_PTR("scalefactor >= 1.0", procName, NULL);
739     pixGetDimensions(pixs, &w, &h, NULL);
740     minsrc = L_MIN(w, h);
741     mindest = (l_int32)((l_float32)minsrc * scalefactor);
742     if (mindest < 2)
743         return (PIX *)ERROR_PTR("scalefactor too small", procName, NULL);
744 
745     if (scalefactor > 0.5) {
746         pixs1 = pixConvert1To8(NULL, pixs, 255, 0);
747         pixs2 = pixScaleToGray2(pixs);
748         red = scalefactor;
749     } else if (scalefactor == 0.5) {
750         return pixScaleToGray2(pixs);
751     } else if (scalefactor > 0.25) {
752         pixs1 = pixScaleToGray2(pixs);
753         pixs2 = pixScaleToGray4(pixs);
754         red = 2. * scalefactor;
755     } else if (scalefactor == 0.25) {
756         return pixScaleToGray4(pixs);
757     } else if (scalefactor > 0.125) {
758         pixs1 = pixScaleToGray4(pixs);
759         pixs2 = pixScaleToGray8(pixs);
760         red = 4. * scalefactor;
761     } else if (scalefactor == 0.125) {
762         return pixScaleToGray8(pixs);
763     } else if (scalefactor > 0.0625) {
764         pixs1 = pixScaleToGray8(pixs);
765         pixs2 = pixScaleToGray16(pixs);
766         red = 8. * scalefactor;
767     } else if (scalefactor == 0.0625) {
768         return pixScaleToGray16(pixs);
769     } else {  /* end of the pyramid; just do it */
770         red = 16.0 * scalefactor;  /* will be <= 1.0 */
771         if ((pixt = pixScaleToGray16(pixs)) == NULL)
772             return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
773         if (red < 0.7)
774             pixd = pixScaleSmooth(pixt, red, red);
775         else
776             pixd = pixScaleGrayLI(pixt, red, red);
777         pixDestroy(&pixt);
778         return pixd;
779     }
780 
781     pixd = pixScaleMipmap(pixs1, pixs2, red);
782     pixCopyInputFormat(pixd, pixs);
783 
784     pixDestroy(&pixs1);
785     pixDestroy(&pixs2);
786     return pixd;
787 }
788 
789 
790 /*------------------------------------------------------------------*
791  *                  Grayscale scaling using mipmap                  *
792  *------------------------------------------------------------------*/
793 /*!
794  * \brief   pixScaleMipmap()
795  *
796  * \param[in]    pixs1 high res 8 bpp, no cmap
797  * \param[in]    pixs2 low res -- 2x reduced -- 8 bpp, no cmap
798  * \param[in]    scale reduction with respect to high res image, > 0.5
799  * \return  8 bpp pix, scaled down by reduction in each direction,
800  *              or NULL on error.
801  *
802  * <pre>
803  * Notes:
804  *      (1) See notes in pixScaleToGrayMipmap().
805  *      (2) This function suffers from aliasing effects that are
806  *          easily seen in document images.
807  * </pre>
808  */
809 PIX *
pixScaleMipmap(PIX * pixs1,PIX * pixs2,l_float32 scale)810 pixScaleMipmap(PIX       *pixs1,
811                PIX       *pixs2,
812                l_float32  scale)
813 {
814 l_int32    ws1, hs1, ws2, hs2, wd, hd, wpls1, wpls2, wpld;
815 l_uint32  *datas1, *datas2, *datad;
816 PIX       *pixd;
817 
818     PROCNAME("pixScaleMipmap");
819 
820     if (!pixs1 || pixGetDepth(pixs1) != 8 || pixGetColormap(pixs1))
821         return (PIX *)ERROR_PTR("pixs1 underdefined, not 8 bpp, or cmapped",
822                                 procName, NULL);
823     if (!pixs2 || pixGetDepth(pixs2) != 8 || pixGetColormap(pixs2))
824         return (PIX *)ERROR_PTR("pixs2 underdefined, not 8 bpp, or cmapped",
825                                 procName, NULL);
826     pixGetDimensions(pixs1, &ws1, &hs1, NULL);
827     pixGetDimensions(pixs2, &ws2, &hs2, NULL);
828     if (scale > 1.0 || scale < 0.5)
829         return (PIX *)ERROR_PTR("scale not in [0.5, 1.0]", procName, NULL);
830     if (ws1 < 2 * ws2)
831         return (PIX *)ERROR_PTR("invalid width ratio", procName, NULL);
832     if (hs1 < 2 * hs2)
833         return (PIX *)ERROR_PTR("invalid height ratio", procName, NULL);
834 
835         /* Generate wd and hd from the lower resolution dimensions,
836          * to guarantee staying within both src images */
837     datas1 = pixGetData(pixs1);
838     wpls1 = pixGetWpl(pixs1);
839     datas2 = pixGetData(pixs2);
840     wpls2 = pixGetWpl(pixs2);
841     wd = (l_int32)(2. * scale * pixGetWidth(pixs2));
842     hd = (l_int32)(2. * scale * pixGetHeight(pixs2));
843     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
844         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
845     pixCopyInputFormat(pixd, pixs1);
846     pixCopyResolution(pixd, pixs1);
847     pixScaleResolution(pixd, scale, scale);
848     datad = pixGetData(pixd);
849     wpld = pixGetWpl(pixd);
850 
851     scaleMipmapLow(datad, wd, hd, wpld, datas1, wpls1, datas2, wpls2, scale);
852     return pixd;
853 }
854 
855 
856 /*------------------------------------------------------------------*
857  *                  Replicated (integer) expansion                  *
858  *------------------------------------------------------------------*/
859 /*!
860  * \brief   pixExpandReplicate()
861  *
862  * \param[in]    pixs 1, 2, 4, 8, 16, 32 bpp
863  * \param[in]    factor integer scale factor for replicative expansion
864  * \return  pixd scaled up, or NULL on error.
865  */
866 PIX *
pixExpandReplicate(PIX * pixs,l_int32 factor)867 pixExpandReplicate(PIX     *pixs,
868                    l_int32  factor)
869 {
870 l_int32    w, h, d, wd, hd, wpls, wpld, start, i, j, k;
871 l_uint8    sval;
872 l_uint16   sval16;
873 l_uint32   sval32;
874 l_uint32  *lines, *datas, *lined, *datad;
875 PIX       *pixd;
876 
877     PROCNAME("pixExpandReplicate");
878 
879     if (!pixs)
880         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
881     pixGetDimensions(pixs, &w, &h, &d);
882     if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
883         return (PIX *)ERROR_PTR("depth not in {1,2,4,8,16,32}", procName, NULL);
884     if (factor <= 0)
885         return (PIX *)ERROR_PTR("factor <= 0; invalid", procName, NULL);
886     if (factor == 1)
887         return pixCopy(NULL, pixs);
888 
889     if (d == 1)
890         return pixExpandBinaryReplicate(pixs, factor, factor);
891 
892     wd = factor * w;
893     hd = factor * h;
894     if ((pixd = pixCreate(wd, hd, d)) == NULL)
895         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
896     pixCopyColormap(pixd, pixs);
897     pixCopyInputFormat(pixd, pixs);
898     pixCopyResolution(pixd, pixs);
899     pixScaleResolution(pixd, (l_float32)factor, (l_float32)factor);
900     datas = pixGetData(pixs);
901     wpls = pixGetWpl(pixs);
902     datad = pixGetData(pixd);
903     wpld = pixGetWpl(pixd);
904 
905     switch (d) {
906     case 2:
907         for (i = 0; i < h; i++) {
908             lines = datas + i * wpls;
909             lined = datad + factor * i * wpld;
910             for (j = 0; j < w; j++) {
911                 sval = GET_DATA_DIBIT(lines, j);
912                 start = factor * j;
913                 for (k = 0; k < factor; k++)
914                     SET_DATA_DIBIT(lined, start + k, sval);
915             }
916             for (k = 1; k < factor; k++)
917                 memcpy(lined + k * wpld, lined, 4 * wpld);
918         }
919         break;
920     case 4:
921         for (i = 0; i < h; i++) {
922             lines = datas + i * wpls;
923             lined = datad + factor * i * wpld;
924             for (j = 0; j < w; j++) {
925                 sval = GET_DATA_QBIT(lines, j);
926                 start = factor * j;
927                 for (k = 0; k < factor; k++)
928                     SET_DATA_QBIT(lined, start + k, sval);
929             }
930             for (k = 1; k < factor; k++)
931                 memcpy(lined + k * wpld, lined, 4 * wpld);
932         }
933         break;
934     case 8:
935         for (i = 0; i < h; i++) {
936             lines = datas + i * wpls;
937             lined = datad + factor * i * wpld;
938             for (j = 0; j < w; j++) {
939                 sval = GET_DATA_BYTE(lines, j);
940                 start = factor * j;
941                 for (k = 0; k < factor; k++)
942                     SET_DATA_BYTE(lined, start + k, sval);
943             }
944             for (k = 1; k < factor; k++)
945                 memcpy(lined + k * wpld, lined, 4 * wpld);
946         }
947         break;
948     case 16:
949         for (i = 0; i < h; i++) {
950             lines = datas + i * wpls;
951             lined = datad + factor * i * wpld;
952             for (j = 0; j < w; j++) {
953                 sval16 = GET_DATA_TWO_BYTES(lines, j);
954                 start = factor * j;
955                 for (k = 0; k < factor; k++)
956                     SET_DATA_TWO_BYTES(lined, start + k, sval16);
957             }
958             for (k = 1; k < factor; k++)
959                 memcpy(lined + k * wpld, lined, 4 * wpld);
960         }
961         break;
962     case 32:
963         for (i = 0; i < h; i++) {
964             lines = datas + i * wpls;
965             lined = datad + factor * i * wpld;
966             for (j = 0; j < w; j++) {
967                 sval32 = *(lines + j);
968                 start = factor * j;
969                 for (k = 0; k < factor; k++)
970                     *(lined + start + k) = sval32;
971             }
972             for (k = 1; k < factor; k++)
973                 memcpy(lined + k * wpld, lined, 4 * wpld);
974         }
975         break;
976     default:
977         fprintf(stderr, "invalid depth\n");
978     }
979 
980     if (d == 32 && pixGetSpp(pixs) == 4)
981         pixScaleAndTransferAlpha(pixd, pixs, (l_float32)factor,
982                                  (l_float32)factor);
983     return pixd;
984 }
985 
986 
987 /*-----------------------------------------------------------------------*
988  *                    Downscaling using min or max                       *
989  *-----------------------------------------------------------------------*/
990 /*!
991  * \brief   pixScaleGrayMinMax()
992  *
993  * \param[in]    pixs 8 bpp, not cmapped
994  * \param[in]    xfact x downscaling factor; integer
995  * \param[in]    yfact y downscaling factor; integer
996  * \param[in]    type L_CHOOSE_MIN, L_CHOOSE_MAX, L_CHOOSE_MAXDIFF
997  * \return  pixd 8 bpp
998  *
999  * <pre>
1000  * Notes:
1001  *      (1) The downscaled pixels in pixd are the min, max or (max - min)
1002  *          of the corresponding set of xfact * yfact pixels in pixs.
1003  *      (2) Using L_CHOOSE_MIN is equivalent to a grayscale erosion,
1004  *          using a brick Sel of size (xfact * yfact), followed by
1005  *          subsampling within each (xfact * yfact) cell.  Using
1006  *          L_CHOOSE_MAX is equivalent to the corresponding dilation.
1007  *      (3) Using L_CHOOSE_MAXDIFF finds the difference between max
1008  *          and min values in each cell.
1009  *      (4) For the special case of downscaling by 2x in both directions,
1010  *          pixScaleGrayMinMax2() is about 2x more efficient.
1011  * </pre>
1012  */
1013 PIX *
pixScaleGrayMinMax(PIX * pixs,l_int32 xfact,l_int32 yfact,l_int32 type)1014 pixScaleGrayMinMax(PIX     *pixs,
1015                    l_int32  xfact,
1016                    l_int32  yfact,
1017                    l_int32  type)
1018 {
1019 l_int32    ws, hs, wd, hd, wpls, wpld, i, j, k, m;
1020 l_int32    minval, maxval, val;
1021 l_uint32  *datas, *datad, *lines, *lined;
1022 PIX       *pixd;
1023 
1024     PROCNAME("pixScaleGrayMinMax");
1025 
1026     if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
1027         return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
1028                                 procName, NULL);
1029     pixGetDimensions(pixs, &ws, &hs, NULL);
1030     if (type != L_CHOOSE_MIN && type != L_CHOOSE_MAX &&
1031         type != L_CHOOSE_MAXDIFF)
1032         return (PIX *)ERROR_PTR("invalid type", procName, NULL);
1033     if (xfact < 1 || yfact < 1)
1034         return (PIX *)ERROR_PTR("xfact and yfact must be >= 1", procName, NULL);
1035 
1036     if (xfact == 2 && yfact == 2)
1037         return pixScaleGrayMinMax2(pixs, type);
1038 
1039     wd = ws / xfact;
1040     if (wd == 0) {  /* single tile */
1041         wd = 1;
1042         xfact = ws;
1043     }
1044     hd = hs / yfact;
1045     if (hd == 0) {  /* single tile */
1046         hd = 1;
1047         yfact = hs;
1048     }
1049     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1050         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1051     pixCopyInputFormat(pixd, pixs);
1052     datas = pixGetData(pixs);
1053     datad = pixGetData(pixd);
1054     wpls = pixGetWpl(pixs);
1055     wpld = pixGetWpl(pixd);
1056     for (i = 0; i < hd; i++) {
1057         lined = datad + i * wpld;
1058         for (j = 0; j < wd; j++) {
1059             if (type == L_CHOOSE_MIN || type == L_CHOOSE_MAXDIFF) {
1060                 minval = 255;
1061                 for (k = 0; k < yfact; k++) {
1062                     lines = datas + (yfact * i + k) * wpls;
1063                     for (m = 0; m < xfact; m++) {
1064                         val = GET_DATA_BYTE(lines, xfact * j + m);
1065                         if (val < minval)
1066                             minval = val;
1067                     }
1068                 }
1069             }
1070             if (type == L_CHOOSE_MAX || type == L_CHOOSE_MAXDIFF) {
1071                 maxval = 0;
1072                 for (k = 0; k < yfact; k++) {
1073                     lines = datas + (yfact * i + k) * wpls;
1074                     for (m = 0; m < xfact; m++) {
1075                         val = GET_DATA_BYTE(lines, xfact * j + m);
1076                         if (val > maxval)
1077                             maxval = val;
1078                     }
1079                 }
1080             }
1081             if (type == L_CHOOSE_MIN)
1082                 SET_DATA_BYTE(lined, j, minval);
1083             else if (type == L_CHOOSE_MAX)
1084                 SET_DATA_BYTE(lined, j, maxval);
1085             else  /* type == L_CHOOSE_MAXDIFF */
1086                 SET_DATA_BYTE(lined, j, maxval - minval);
1087         }
1088     }
1089 
1090     return pixd;
1091 }
1092 
1093 
1094 /*!
1095  * \brief   pixScaleGrayMinMax2()
1096  *
1097  * \param[in]    pixs 8 bpp, not cmapped
1098  * \param[in]    type L_CHOOSE_MIN, L_CHOOSE_MAX, L_CHOOSE_MAXDIFF
1099  * \return  pixd 8 bpp downscaled by 2x
1100  *
1101  * <pre>
1102  * Notes:
1103  *      (1) Special version for 2x reduction.  The downscaled pixels
1104  *          in pixd are the min, max or (max - min) of the corresponding
1105  *          set of 4 pixels in pixs.
1106  *      (2) The max and min operations are a special case (for levels 1
1107  *          and 4) of grayscale analog to the binary rank scaling operation
1108  *          pixReduceRankBinary2().  Note, however, that because of
1109  *          the photometric definition that higher gray values are
1110  *          lighter, the erosion-like L_CHOOSE_MIN will darken
1111  *          the resulting image, corresponding to a threshold level 1
1112  *          in the binary case.  Likewise, L_CHOOSE_MAX will lighten
1113  *          the pixd, corresponding to a threshold level of 4.
1114  *      (3) To choose any of the four rank levels in a 2x grayscale
1115  *          reduction, use pixScaleGrayRank2().
1116  *      (4) This runs at about 70 MPix/sec/GHz of source data for
1117  *          erosion and dilation.
1118  * </pre>
1119  */
1120 PIX *
pixScaleGrayMinMax2(PIX * pixs,l_int32 type)1121 pixScaleGrayMinMax2(PIX     *pixs,
1122                     l_int32  type)
1123 {
1124 l_int32    ws, hs, wd, hd, wpls, wpld, i, j, k;
1125 l_int32    minval, maxval;
1126 l_int32    val[4];
1127 l_uint32  *datas, *datad, *lines, *lined;
1128 PIX       *pixd;
1129 
1130     PROCNAME("pixScaleGrayMinMax2");
1131 
1132     if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
1133         return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
1134                                 procName, NULL);
1135     pixGetDimensions(pixs, &ws, &hs, NULL);
1136     if (ws < 2 || hs < 2)
1137         return (PIX *)ERROR_PTR("too small: ws < 2 or hs < 2", procName, NULL);
1138     if (type != L_CHOOSE_MIN && type != L_CHOOSE_MAX &&
1139         type != L_CHOOSE_MAXDIFF)
1140         return (PIX *)ERROR_PTR("invalid type", procName, NULL);
1141 
1142     wd = ws / 2;
1143     hd = hs / 2;
1144     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1145         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1146     pixCopyInputFormat(pixd, pixs);
1147     datas = pixGetData(pixs);
1148     datad = pixGetData(pixd);
1149     wpls = pixGetWpl(pixs);
1150     wpld = pixGetWpl(pixd);
1151     for (i = 0; i < hd; i++) {
1152         lines = datas + 2 * i * wpls;
1153         lined = datad + i * wpld;
1154         for (j = 0; j < wd; j++) {
1155             val[0] = GET_DATA_BYTE(lines, 2 * j);
1156             val[1] = GET_DATA_BYTE(lines, 2 * j + 1);
1157             val[2] = GET_DATA_BYTE(lines + wpls, 2 * j);
1158             val[3] = GET_DATA_BYTE(lines + wpls, 2 * j + 1);
1159             if (type == L_CHOOSE_MIN || type == L_CHOOSE_MAXDIFF) {
1160                 minval = 255;
1161                 for (k = 0; k < 4; k++) {
1162                     if (val[k] < minval)
1163                         minval = val[k];
1164                 }
1165             }
1166             if (type == L_CHOOSE_MAX || type == L_CHOOSE_MAXDIFF) {
1167                 maxval = 0;
1168                 for (k = 0; k < 4; k++) {
1169                     if (val[k] > maxval)
1170                         maxval = val[k];
1171                 }
1172             }
1173             if (type == L_CHOOSE_MIN)
1174                 SET_DATA_BYTE(lined, j, minval);
1175             else if (type == L_CHOOSE_MAX)
1176                 SET_DATA_BYTE(lined, j, maxval);
1177             else  /* type == L_CHOOSE_MAXDIFF */
1178                 SET_DATA_BYTE(lined, j, maxval - minval);
1179         }
1180     }
1181 
1182     return pixd;
1183 }
1184 
1185 
1186 /*-----------------------------------------------------------------------*
1187  *                  Grayscale downscaling using rank value               *
1188  *-----------------------------------------------------------------------*/
1189 /*!
1190  * \brief   pixScaleGrayRankCascade()
1191  *
1192  * \param[in]    pixs 8 bpp, not cmapped
1193  * \param[in]    level1, ... level4 rank thresholds, in set {0, 1, 2, 3, 4}
1194  * \return  pixd 8 bpp, downscaled by up to 16x
1195  *
1196  * <pre>
1197  * Notes:
1198  *      (1) This performs up to four cascaded 2x rank reductions.
1199  *      (2) Use level = 0 to truncate the cascade.
1200  * </pre>
1201  */
1202 PIX *
pixScaleGrayRankCascade(PIX * pixs,l_int32 level1,l_int32 level2,l_int32 level3,l_int32 level4)1203 pixScaleGrayRankCascade(PIX     *pixs,
1204                         l_int32  level1,
1205                         l_int32  level2,
1206                         l_int32  level3,
1207                         l_int32  level4)
1208 {
1209 PIX  *pixt1, *pixt2, *pixt3, *pixt4;
1210 
1211     PROCNAME("pixScaleGrayRankCascade");
1212 
1213     if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
1214         return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
1215                                 procName, NULL);
1216     if (level1 > 4 || level2 > 4 || level3 > 4 || level4 > 4)
1217         return (PIX *)ERROR_PTR("levels must not exceed 4", procName, NULL);
1218 
1219     if (level1 <= 0) {
1220         L_WARNING("no reduction because level1 not > 0\n", procName);
1221         return pixCopy(NULL, pixs);
1222     }
1223 
1224     pixt1 = pixScaleGrayRank2(pixs, level1);
1225     if (level2 <= 0)
1226         return pixt1;
1227 
1228     pixt2 = pixScaleGrayRank2(pixt1, level2);
1229     pixDestroy(&pixt1);
1230     if (level3 <= 0)
1231         return pixt2;
1232 
1233     pixt3 = pixScaleGrayRank2(pixt2, level3);
1234     pixDestroy(&pixt2);
1235     if (level4 <= 0)
1236         return pixt3;
1237 
1238     pixt4 = pixScaleGrayRank2(pixt3, level4);
1239     pixDestroy(&pixt3);
1240     return pixt4;
1241 }
1242 
1243 
1244 /*!
1245  * \brief   pixScaleGrayRank2()
1246  *
1247  * \param[in]    pixs 8 bpp, no cmap
1248  * \param[in]    rank 1 (darkest), 2, 3, 4 (lightest)
1249  * \return  pixd 8 bpp, downscaled by 2x
1250  *
1251  * <pre>
1252  * Notes:
1253  *      (1) Rank 2x reduction.  If rank == 1(4), the downscaled pixels
1254  *          in pixd are the min(max) of the corresponding set of
1255  *          4 pixels in pixs.  Values 2 and 3 are intermediate.
1256  *      (2) This is the grayscale analog to the binary rank scaling operation
1257  *          pixReduceRankBinary2().  Here, because of the photometric
1258  *          definition that higher gray values are lighter, rank 1 gives
1259  *          the darkest pixel, whereas rank 4 gives the lightest pixel.
1260  *          This is opposite to the binary rank operation.
1261  *      (3) For rank = 1 and 4, this calls pixScaleGrayMinMax2(),
1262  *          which runs at about 70 MPix/sec/GHz of source data.
1263  *          For rank 2 and 3, this runs 3x slower, at about 25 MPix/sec/GHz.
1264  * </pre>
1265  */
1266 PIX *
pixScaleGrayRank2(PIX * pixs,l_int32 rank)1267 pixScaleGrayRank2(PIX     *pixs,
1268                   l_int32  rank)
1269 {
1270 l_int32    ws, hs, wd, hd, wpls, wpld, i, j, k, m;
1271 l_int32    minval, maxval, rankval, minindex, maxindex;
1272 l_int32    val[4];
1273 l_int32    midval[4];  /* should only use 2 of these */
1274 l_uint32  *datas, *datad, *lines, *lined;
1275 PIX       *pixd;
1276 
1277     PROCNAME("pixScaleGrayRank2");
1278 
1279     if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
1280         return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
1281                                 procName, NULL);
1282     if (rank < 1 || rank > 4)
1283         return (PIX *)ERROR_PTR("invalid rank", procName, NULL);
1284 
1285     if (rank == 1)
1286         return pixScaleGrayMinMax2(pixs, L_CHOOSE_MIN);
1287     if (rank == 4)
1288         return pixScaleGrayMinMax2(pixs, L_CHOOSE_MAX);
1289 
1290     pixGetDimensions(pixs, &ws, &hs, NULL);
1291     wd = ws / 2;
1292     hd = hs / 2;
1293     if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1294         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1295     pixCopyInputFormat(pixd, pixs);
1296     datas = pixGetData(pixs);
1297     datad = pixGetData(pixd);
1298     wpls = pixGetWpl(pixs);
1299     wpld = pixGetWpl(pixd);
1300     for (i = 0; i < hd; i++) {
1301         lines = datas + 2 * i * wpls;
1302         lined = datad + i * wpld;
1303         for (j = 0; j < wd; j++) {
1304             val[0] = GET_DATA_BYTE(lines, 2 * j);
1305             val[1] = GET_DATA_BYTE(lines, 2 * j + 1);
1306             val[2] = GET_DATA_BYTE(lines + wpls, 2 * j);
1307             val[3] = GET_DATA_BYTE(lines + wpls, 2 * j + 1);
1308             minval = maxval = val[0];
1309             minindex = maxindex = 0;
1310             for (k = 1; k < 4; k++) {
1311                 if (val[k] < minval) {
1312                     minval = val[k];
1313                     minindex = k;
1314                     continue;
1315                 }
1316                 if (val[k] > maxval) {
1317                     maxval = val[k];
1318                     maxindex = k;
1319                 }
1320             }
1321             for (k = 0, m = 0; k < 4; k++) {
1322                 if (k == minindex || k == maxindex)
1323                     continue;
1324                 midval[m++] = val[k];
1325             }
1326             if (m > 2)  /* minval == maxval; all val[k] are the same */
1327                 rankval = minval;
1328             else if (rank == 2)
1329                 rankval = L_MIN(midval[0], midval[1]);
1330             else  /* rank == 3 */
1331                 rankval = L_MAX(midval[0], midval[1]);
1332             SET_DATA_BYTE(lined, j, rankval);
1333         }
1334     }
1335 
1336     return pixd;
1337 }
1338 
1339 
1340 /*------------------------------------------------------------------------*
1341  *           Helper function for transferring alpha with scaling          *
1342  *------------------------------------------------------------------------*/
1343 /*!
1344  * \brief   pixScaleAndTransferAlpha()
1345  *
1346  * \param[in]    pixd  32 bpp, scaled image
1347  * \param[in]    pixs  32 bpp, original unscaled image
1348  * \param[in]    scalex, scaley both > 0.0
1349  * \return  0 if OK; 1 on error
1350  *
1351  * <pre>
1352  * Notes:
1353  *      (1) This scales the alpha component of pixs and inserts into pixd.
1354  * </pre>
1355  */
1356 l_int32
pixScaleAndTransferAlpha(PIX * pixd,PIX * pixs,l_float32 scalex,l_float32 scaley)1357 pixScaleAndTransferAlpha(PIX       *pixd,
1358                          PIX       *pixs,
1359                          l_float32  scalex,
1360                          l_float32  scaley)
1361 {
1362 PIX  *pix1, *pix2;
1363 
1364     PROCNAME("pixScaleAndTransferAlpha");
1365 
1366     if (!pixs || !pixd)
1367         return ERROR_INT("pixs and pixd not both defined", procName, 1);
1368     if (pixGetDepth(pixs) != 32 || pixGetSpp(pixs) != 4)
1369         return ERROR_INT("pixs not 32 bpp and 4 spp", procName, 1);
1370     if (pixGetDepth(pixd) != 32)
1371         return ERROR_INT("pixd not 32 bpp", procName, 1);
1372 
1373     if (scalex == 1.0 && scaley == 1.0) {
1374         pixCopyRGBComponent(pixd, pixs, L_ALPHA_CHANNEL);
1375         return 0;
1376     }
1377 
1378     pix1 = pixGetRGBComponent(pixs, L_ALPHA_CHANNEL);
1379     pix2 = pixScale(pix1, scalex, scaley);
1380     pixSetRGBComponent(pixd, pix2, L_ALPHA_CHANNEL);
1381     pixDestroy(&pix1);
1382     pixDestroy(&pix2);
1383     return 0;
1384 }
1385 
1386 
1387 /*------------------------------------------------------------------------*
1388  *    RGB scaling including alpha (blend) component and gamma transform   *
1389  *------------------------------------------------------------------------*/
1390 /*!
1391  * \brief   pixScaleWithAlpha()
1392  *
1393  * \param[in]    pixs 32 bpp rgb or cmapped
1394  * \param[in]    scalex, scaley must be > 0.0
1395  * \param[in]    pixg [optional] 8 bpp, can be null
1396  * \param[in]    fract between 0.0 and 1.0, with 0.0 fully transparent
1397  *                     and 1.0 fully opaque
1398  * \return  pixd 32 bpp rgba, or NULL on error
1399  *
1400  * <pre>
1401  * Notes:
1402  *      (1) The alpha channel is transformed separately from pixs,
1403  *          and aligns with it, being fully transparent outside the
1404  *          boundary of the transformed pixs.  For pixels that are fully
1405  *          transparent, a blending function like pixBlendWithGrayMask()
1406  *          will give zero weight to corresponding pixels in pixs.
1407  *      (2) Scaling is done with area mapping or linear interpolation,
1408  *          depending on the scale factors.  Default sharpening is done.
1409  *      (3) If pixg is NULL, it is generated as an alpha layer that is
1410  *          partially opaque, using %fract.  Otherwise, it is cropped
1411  *          to pixs if required, and %fract is ignored.  The alpha
1412  *          channel in pixs is never used.
1413  *      (4) Colormaps are removed to 32 bpp.
1414  *      (5) The default setting for the border values in the alpha channel
1415  *          is 0 (transparent) for the outermost ring of pixels and
1416  *          (0.5 * fract * 255) for the second ring.  When blended over
1417  *          a second image, this
1418  *          (a) shrinks the visible image to make a clean overlap edge
1419  *              with an image below, and
1420  *          (b) softens the edges by weakening the aliasing there.
1421  *          Use l_setAlphaMaskBorder() to change these values.
1422  *      (6) A subtle use of gamma correction is to remove gamma correction
1423  *          before scaling and restore it afterwards.  This is done
1424  *          by sandwiching this function between a gamma/inverse-gamma
1425  *          photometric transform:
1426  *              pixt = pixGammaTRCWithAlpha(NULL, pixs, 1.0 / gamma, 0, 255);
1427  *              pixd = pixScaleWithAlpha(pixt, scalex, scaley, NULL, fract);
1428  *              pixGammaTRCWithAlpha(pixd, pixd, gamma, 0, 255);
1429  *              pixDestroy(&pixt);
1430  *          This has the side-effect of producing artifacts in the very
1431  *          dark regions.
1432  * </pre>
1433  */
1434 PIX *
pixScaleWithAlpha(PIX * pixs,l_float32 scalex,l_float32 scaley,PIX * pixg,l_float32 fract)1435 pixScaleWithAlpha(PIX       *pixs,
1436                   l_float32  scalex,
1437                   l_float32  scaley,
1438                   PIX       *pixg,
1439                   l_float32  fract)
1440 {
1441 l_int32  ws, hs, d, spp;
1442 PIX     *pixd, *pix32, *pixg2, *pixgs;
1443 
1444     PROCNAME("pixScaleWithAlpha");
1445 
1446     if (!pixs)
1447         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1448     pixGetDimensions(pixs, &ws, &hs, &d);
1449     if (d != 32 && !pixGetColormap(pixs))
1450         return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", procName, NULL);
1451     if (scalex <= 0.0 || scaley <= 0.0)
1452         return (PIX *)ERROR_PTR("scale factor <= 0.0", procName, NULL);
1453     if (pixg && pixGetDepth(pixg) != 8) {
1454         L_WARNING("pixg not 8 bpp; using 'fract' transparent alpha\n",
1455                   procName);
1456         pixg = NULL;
1457     }
1458     if (!pixg && (fract < 0.0 || fract > 1.0)) {
1459         L_WARNING("invalid fract; using fully opaque\n", procName);
1460         fract = 1.0;
1461     }
1462     if (!pixg && fract == 0.0)
1463         L_WARNING("transparent alpha; image will not be blended\n", procName);
1464 
1465         /* Make sure input to scaling is 32 bpp rgb, and scale it */
1466     if (d != 32)
1467         pix32 = pixConvertTo32(pixs);
1468     else
1469         pix32 = pixClone(pixs);
1470     spp = pixGetSpp(pix32);
1471     pixSetSpp(pix32, 3);  /* ignore the alpha channel for scaling */
1472     pixd = pixScale(pix32, scalex, scaley);
1473     pixSetSpp(pix32, spp);  /* restore initial value in case it's a clone */
1474     pixDestroy(&pix32);
1475 
1476         /* Set up alpha layer with a fading border and scale it */
1477     if (!pixg) {
1478         pixg2 = pixCreate(ws, hs, 8);
1479         if (fract == 1.0)
1480             pixSetAll(pixg2);
1481         else if (fract > 0.0)
1482             pixSetAllArbitrary(pixg2, (l_int32)(255.0 * fract));
1483     } else {
1484         pixg2 = pixResizeToMatch(pixg, NULL, ws, hs);
1485     }
1486     if (ws > 10 && hs > 10) {  /* see note 4 */
1487         pixSetBorderRingVal(pixg2, 1,
1488                             (l_int32)(255.0 * fract * AlphaMaskBorderVals[0]));
1489         pixSetBorderRingVal(pixg2, 2,
1490                             (l_int32)(255.0 * fract * AlphaMaskBorderVals[1]));
1491     }
1492     pixgs = pixScaleGeneral(pixg2, scalex, scaley, 0.0, 0);
1493 
1494         /* Combine into a 4 spp result */
1495     pixSetRGBComponent(pixd, pixgs, L_ALPHA_CHANNEL);
1496     pixCopyInputFormat(pixd, pixs);
1497 
1498     pixDestroy(&pixg2);
1499     pixDestroy(&pixgs);
1500     return pixd;
1501 }
1502 
1503 
1504 /* ================================================================ *
1505  *                    Low level static functions                    *
1506  * ================================================================ */
1507 
1508 /*------------------------------------------------------------------*
1509  *                         Scale-to-gray 2x                         *
1510  *------------------------------------------------------------------*/
1511 /*!
1512  * \brief   scaleToGray2Low()
1513  *
1514  * \param[in]    datad   dest data
1515  * \param[in]    wd, hd  dest width, height
1516  * \param[in]    wpld    dest words/line
1517  * \param[in]    datas   src data
1518  * \param[in]    wpls    src words/line
1519  * \param[in]    sumtab  made from makeSumTabSG2()
1520  * \param[in]    valtab  made from makeValTabSG2()
1521  * \return  0 if OK; 1 on error.
1522  *
1523  *  The output is processed in sets of 4 output bytes on a row,
1524  *  corresponding to 4 2x2 bit-blocks in the input image.
1525  *  Two lookup tables are used.  The first, sumtab, gets the
1526  *  sum of ON pixels in 4 sets of two adjacent bits,
1527  *  storing the result in 4 adjacent bytes.  After sums from
1528  *  two rows have been added, the second table, valtab,
1529  *  converts from the sum of ON pixels in the 2x2 block to
1530  *  an 8 bpp grayscale value between 0 for 4 bits ON
1531  *  and 255 for 0 bits ON.
1532  */
1533 static void
scaleToGray2Low(l_uint32 * datad,l_int32 wd,l_int32 hd,l_int32 wpld,l_uint32 * datas,l_int32 wpls,l_uint32 * sumtab,l_uint8 * valtab)1534 scaleToGray2Low(l_uint32  *datad,
1535                 l_int32    wd,
1536                 l_int32    hd,
1537                 l_int32    wpld,
1538                 l_uint32  *datas,
1539                 l_int32    wpls,
1540                 l_uint32  *sumtab,
1541                 l_uint8   *valtab)
1542 {
1543 l_int32    i, j, l, k, m, wd4, extra;
1544 l_uint32   sbyte1, sbyte2, sum;
1545 l_uint32  *lines, *lined;
1546 
1547         /* i indexes the dest lines
1548          * l indexes the source lines
1549          * j indexes the dest bytes
1550          * k indexes the source bytes
1551          * We take two bytes from the source (in 2 lines of 8 pixels
1552          * each) and convert them into four 8 bpp bytes of the dest. */
1553     wd4 = wd & 0xfffffffc;
1554     extra = wd - wd4;
1555     for (i = 0, l = 0; i < hd; i++, l += 2) {
1556         lines = datas + l * wpls;
1557         lined = datad + i * wpld;
1558         for (j = 0, k = 0; j < wd4; j += 4, k++) {
1559             sbyte1 = GET_DATA_BYTE(lines, k);
1560             sbyte2 = GET_DATA_BYTE(lines + wpls, k);
1561             sum = sumtab[sbyte1] + sumtab[sbyte2];
1562             SET_DATA_BYTE(lined, j, valtab[sum >> 24]);
1563             SET_DATA_BYTE(lined, j + 1, valtab[(sum >> 16) & 0xff]);
1564             SET_DATA_BYTE(lined, j + 2, valtab[(sum >> 8) & 0xff]);
1565             SET_DATA_BYTE(lined, j + 3, valtab[sum & 0xff]);
1566         }
1567         if (extra > 0) {
1568             sbyte1 = GET_DATA_BYTE(lines, k);
1569             sbyte2 = GET_DATA_BYTE(lines + wpls, k);
1570             sum = sumtab[sbyte1] + sumtab[sbyte2];
1571             for (m = 0; m < extra; m++) {
1572                 SET_DATA_BYTE(lined, j + m,
1573                               valtab[((sum >> (24 - 8 * m)) & 0xff)]);
1574             }
1575         }
1576 
1577     }
1578 
1579     return;
1580 }
1581 
1582 
1583 /*!
1584  * \brief   makeSumTabSG2()
1585  *
1586  *  Returns a table of 256 l_uint32s, giving the four output
1587  *  8-bit grayscale sums corresponding to 8 input bits of a binary
1588  *  image, for a 2x scale-to-gray op.  The sums from two
1589  *  adjacent scanlines are then added and transformed to
1590  *  output four 8 bpp pixel values, using makeValTabSG2().
1591  */
1592 static l_uint32  *
makeSumTabSG2(void)1593 makeSumTabSG2(void)
1594 {
1595 l_int32    i;
1596 l_int32    sum[] = {0, 1, 1, 2};
1597 l_uint32  *tab;
1598 
1599     PROCNAME("makeSumTabSG2");
1600 
1601     if ((tab = (l_uint32 *)LEPT_CALLOC(256, sizeof(l_uint32))) == NULL)
1602         return (l_uint32 *)ERROR_PTR("tab not made", procName, NULL);
1603 
1604         /* Pack the four sums separately in four bytes */
1605     for (i = 0; i < 256; i++) {
1606         tab[i] = (sum[i & 0x3] | sum[(i >> 2) & 0x3] << 8 |
1607                   sum[(i >> 4) & 0x3] << 16 | sum[(i >> 6) & 0x3] << 24);
1608     }
1609     return tab;
1610 }
1611 
1612 
1613 /*!
1614  * \brief   makeValTabSG2()
1615  *
1616  *  Returns an 8 bit value for the sum of ON pixels
1617  *  in a 2x2 square, according to
1618  *
1619  *         val = 255 - (255 * sum)/4
1620  *
1621  *  where sum is in set {0,1,2,3,4}
1622  */
1623 static l_uint8 *
makeValTabSG2(void)1624 makeValTabSG2(void)
1625 {
1626 l_int32   i;
1627 l_uint8  *tab;
1628 
1629     PROCNAME("makeValTabSG2");
1630 
1631     if ((tab = (l_uint8 *)LEPT_CALLOC(5, sizeof(l_uint8))) == NULL)
1632         return (l_uint8 *)ERROR_PTR("tab not made", procName, NULL);
1633     for (i = 0; i < 5; i++)
1634         tab[i] = 255 - (i * 255) / 4;
1635     return tab;
1636 }
1637 
1638 
1639 /*------------------------------------------------------------------*
1640  *                         Scale-to-gray 3x                         *
1641  *------------------------------------------------------------------*/
1642 /*!
1643  * \brief   scaleToGray3Low()
1644  *
1645  * \param[in]    datad   dest data
1646  * \param[in]    wd, hd  dest width, height
1647  * \param[in]    wpld    dest words/line
1648  * \param[in]    datas   src data
1649  * \param[in]    wpls    src words/line
1650  * \param[in]    sumtab  made from makeSumTabSG3()
1651  * \param[in]    valtab  made from makeValTabSG3()
1652  * \return  0 if OK; 1 on error
1653  *
1654  * <pre>
1655  * Notes:
1656  *  Each set of 8 3x3 bit-blocks in the source image, which
1657  *  consist of 72 pixels arranged 24 pixels wide by 3 scanlines,
1658  *  is converted to a row of 8 8-bit pixels in the dest image.
1659  *  These 72 pixels of the input image are runs of 24 pixels
1660  *  in three adjacent scanlines.  Each run of 24 pixels is
1661  *  stored in the 24 LSbits of a 32-bit word.  We use 2 LUTs.
1662  *  The first, sumtab, takes 6 of these bits and stores
1663  *  sum, taken 3 bits at a time, in two bytes.  (See
1664  *  makeSumTabSG3).  This is done for each of the 3 scanlines,
1665  *  and the results are added.  We now have the sum of ON pixels
1666  *  in the first two 3x3 blocks in two bytes.  The valtab LUT
1667  *  then converts these values (which go from 0 to 9) to
1668  *  grayscale values between between 255 and 0.  (See makeValTabSG3).
1669  *  This process is repeated for each of the other 3 sets of
1670  *  6x3 input pixels, giving 8 output pixels in total.
1671  *
1672  *  Note: because the input image is processed in groups of
1673  *        24 x 3 pixels, the process clips the input height to
1674  *        (h - h % 3) and the input width to (w - w % 24).
1675  * </pre>
1676  */
1677 static void
scaleToGray3Low(l_uint32 * datad,l_int32 wd,l_int32 hd,l_int32 wpld,l_uint32 * datas,l_int32 wpls,l_uint32 * sumtab,l_uint8 * valtab)1678 scaleToGray3Low(l_uint32  *datad,
1679                 l_int32    wd,
1680                 l_int32    hd,
1681                 l_int32    wpld,
1682                 l_uint32  *datas,
1683                 l_int32    wpls,
1684                 l_uint32  *sumtab,
1685                 l_uint8   *valtab)
1686 {
1687 l_int32    i, j, l, k;
1688 l_uint32   threebytes1, threebytes2, threebytes3, sum;
1689 l_uint32  *lines, *lined;
1690 
1691         /* i indexes the dest lines
1692          * l indexes the source lines
1693          * j indexes the dest bytes
1694          * k indexes the source bytes
1695          * We take 9 bytes from the source (72 binary pixels
1696          * in three lines of 24 pixels each) and convert it
1697          * into 8 bytes of the dest (8 8bpp pixels in one line)   */
1698     for (i = 0, l = 0; i < hd; i++, l += 3) {
1699         lines = datas + l * wpls;
1700         lined = datad + i * wpld;
1701         for (j = 0, k = 0; j < wd; j += 8, k += 3) {
1702             threebytes1 = (GET_DATA_BYTE(lines, k) << 16) |
1703                           (GET_DATA_BYTE(lines, k + 1) << 8) |
1704                           GET_DATA_BYTE(lines, k + 2);
1705             threebytes2 = (GET_DATA_BYTE(lines + wpls, k) << 16) |
1706                           (GET_DATA_BYTE(lines + wpls, k + 1) << 8) |
1707                           GET_DATA_BYTE(lines + wpls, k + 2);
1708             threebytes3 = (GET_DATA_BYTE(lines + 2 * wpls, k) << 16) |
1709                           (GET_DATA_BYTE(lines + 2 * wpls, k + 1) << 8) |
1710                           GET_DATA_BYTE(lines + 2 * wpls, k + 2);
1711 
1712             sum = sumtab[(threebytes1 >> 18)] +
1713                   sumtab[(threebytes2 >> 18)] +
1714                   sumtab[(threebytes3 >> 18)];
1715             SET_DATA_BYTE(lined, j, valtab[GET_DATA_BYTE(&sum, 2)]);
1716             SET_DATA_BYTE(lined, j + 1, valtab[GET_DATA_BYTE(&sum, 3)]);
1717 
1718             sum = sumtab[((threebytes1 >> 12) & 0x3f)] +
1719                   sumtab[((threebytes2 >> 12) & 0x3f)] +
1720                   sumtab[((threebytes3 >> 12) & 0x3f)];
1721             SET_DATA_BYTE(lined, j + 2, valtab[GET_DATA_BYTE(&sum, 2)]);
1722             SET_DATA_BYTE(lined, j + 3, valtab[GET_DATA_BYTE(&sum, 3)]);
1723 
1724             sum = sumtab[((threebytes1 >> 6) & 0x3f)] +
1725                   sumtab[((threebytes2 >> 6) & 0x3f)] +
1726                   sumtab[((threebytes3 >> 6) & 0x3f)];
1727             SET_DATA_BYTE(lined, j + 4, valtab[GET_DATA_BYTE(&sum, 2)]);
1728             SET_DATA_BYTE(lined, j + 5, valtab[GET_DATA_BYTE(&sum, 3)]);
1729 
1730             sum = sumtab[(threebytes1 & 0x3f)] +
1731                   sumtab[(threebytes2 & 0x3f)] +
1732                   sumtab[(threebytes3 & 0x3f)];
1733             SET_DATA_BYTE(lined, j + 6, valtab[GET_DATA_BYTE(&sum, 2)]);
1734             SET_DATA_BYTE(lined, j + 7, valtab[GET_DATA_BYTE(&sum, 3)]);
1735         }
1736     }
1737 
1738     return;
1739 }
1740 
1741 
1742 
1743 /*!
1744  * \brief   makeSumTabSG3()
1745  *
1746  *  Returns a table of 64 l_uint32s, giving the two output
1747  *  8-bit grayscale sums corresponding to 6 input bits of a binary
1748  *  image, for a 3x scale-to-gray op.  In practice, this would
1749  *  be used three times (on adjacent scanlines), and the sums would
1750  *  be added and then transformed to output 8 bpp pixel values,
1751  *  using makeValTabSG3().
1752  */
1753 static l_uint32  *
makeSumTabSG3(void)1754 makeSumTabSG3(void)
1755 {
1756 l_int32    i;
1757 l_int32    sum[] = {0, 1, 1, 2, 1, 2, 2, 3};
1758 l_uint32  *tab;
1759 
1760     PROCNAME("makeSumTabSG3");
1761 
1762     if ((tab = (l_uint32 *)LEPT_CALLOC(64, sizeof(l_uint32))) == NULL)
1763         return (l_uint32 *)ERROR_PTR("tab not made", procName, NULL);
1764 
1765         /* Pack the two sums separately in two bytes */
1766     for (i = 0; i < 64; i++) {
1767         tab[i] = (sum[i & 0x07]) | (sum[(i >> 3) & 0x07] << 8);
1768     }
1769     return tab;
1770 }
1771 
1772 
1773 /*!
1774  * \brief   makeValTabSG3()
1775  *
1776  *  Returns an 8 bit value for the sum of ON pixels
1777  *  in a 3x3 square, according to
1778  *      val = 255 - (255 * sum)/9
1779  *  where sum is in set {0, ... ,9}
1780  */
1781 static l_uint8 *
makeValTabSG3(void)1782 makeValTabSG3(void)
1783 {
1784 l_int32   i;
1785 l_uint8  *tab;
1786 
1787     PROCNAME("makeValTabSG3");
1788 
1789     if ((tab = (l_uint8 *)LEPT_CALLOC(10, sizeof(l_uint8))) == NULL)
1790         return (l_uint8 *)ERROR_PTR("tab not made", procName, NULL);
1791     for (i = 0; i < 10; i++)
1792         tab[i] = 0xff - (i * 255) / 9;
1793     return tab;
1794 }
1795 
1796 
1797 /*------------------------------------------------------------------*
1798  *                         Scale-to-gray 4x                         *
1799  *------------------------------------------------------------------*/
1800 /*!
1801  * \brief   scaleToGray4Low()
1802  *
1803  * \param[in]    datad   dest data
1804  * \param[in]    wd, hd  dest width, height
1805  * \param[in]    wpld    dest words/line
1806  * \param[in]    datas   src data
1807  * \param[in]    wpls    src words/line
1808  * \param[in]    sumtab  made from makeSumTabSG4()
1809  * \param[in]    valtab  made from makeValTabSG4()
1810  * \return  0 if OK; 1 on error.
1811  *
1812  *  The output is processed in sets of 2 output bytes on a row,
1813  *  corresponding to 2 4x4 bit-blocks in the input image.
1814  *  Two lookup tables are used.  The first, sumtab, gets the
1815  *  sum of ON pixels in two sets of four adjacent bits,
1816  *  storing the result in 2 adjacent bytes.  After sums from
1817  *  four rows have been added, the second table, valtab,
1818  *  converts from the sum of ON pixels in the 4x4 block to
1819  *  an 8 bpp grayscale value between 0 for 16 bits ON
1820  *  and 255 for 0 bits ON.
1821  */
1822 static void
scaleToGray4Low(l_uint32 * datad,l_int32 wd,l_int32 hd,l_int32 wpld,l_uint32 * datas,l_int32 wpls,l_uint32 * sumtab,l_uint8 * valtab)1823 scaleToGray4Low(l_uint32  *datad,
1824                 l_int32    wd,
1825                 l_int32    hd,
1826                 l_int32    wpld,
1827                 l_uint32  *datas,
1828                 l_int32    wpls,
1829                 l_uint32  *sumtab,
1830                 l_uint8   *valtab)
1831 {
1832 l_int32    i, j, l, k;
1833 l_uint32   sbyte1, sbyte2, sbyte3, sbyte4, sum;
1834 l_uint32  *lines, *lined;
1835 
1836         /* i indexes the dest lines
1837          * l indexes the source lines
1838          * j indexes the dest bytes
1839          * k indexes the source bytes
1840          * We take four bytes from the source (in 4 lines of 8 pixels
1841          * each) and convert it into two 8 bpp bytes of the dest. */
1842     for (i = 0, l = 0; i < hd; i++, l += 4) {
1843         lines = datas + l * wpls;
1844         lined = datad + i * wpld;
1845         for (j = 0, k = 0; j < wd; j += 2, k++) {
1846             sbyte1 = GET_DATA_BYTE(lines, k);
1847             sbyte2 = GET_DATA_BYTE(lines + wpls, k);
1848             sbyte3 = GET_DATA_BYTE(lines + 2 * wpls, k);
1849             sbyte4 = GET_DATA_BYTE(lines + 3 * wpls, k);
1850             sum = sumtab[sbyte1] + sumtab[sbyte2] +
1851                   sumtab[sbyte3] + sumtab[sbyte4];
1852             SET_DATA_BYTE(lined, j, valtab[GET_DATA_BYTE(&sum, 2)]);
1853             SET_DATA_BYTE(lined, j + 1, valtab[GET_DATA_BYTE(&sum, 3)]);
1854         }
1855     }
1856 
1857     return;
1858 }
1859 
1860 
1861 /*!
1862  * \brief   makeSumTabSG4()
1863  *
1864  *  Returns a table of 256 l_uint32s, giving the two output
1865  *  8-bit grayscale sums corresponding to 8 input bits of a binary
1866  *  image, for a 4x scale-to-gray op.  The sums from four
1867  *  adjacent scanlines are then added and transformed to
1868  *  output 8 bpp pixel values, using makeValTabSG4().
1869  */
1870 static l_uint32  *
makeSumTabSG4(void)1871 makeSumTabSG4(void)
1872 {
1873 l_int32    i;
1874 l_int32    sum[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
1875 l_uint32  *tab;
1876 
1877     PROCNAME("makeSumTabSG4");
1878 
1879     if ((tab = (l_uint32 *)LEPT_CALLOC(256, sizeof(l_uint32))) == NULL)
1880         return (l_uint32 *)ERROR_PTR("tab not made", procName, NULL);
1881 
1882         /* Pack the two sums separately in two bytes */
1883     for (i = 0; i < 256; i++) {
1884         tab[i] = (sum[i & 0xf]) | (sum[(i >> 4) & 0xf] << 8);
1885     }
1886     return tab;
1887 }
1888 
1889 
1890 /*!
1891  * \brief   makeValTabSG4()
1892  *
1893  *  Returns an 8 bit value for the sum of ON pixels
1894  *  in a 4x4 square, according to
1895  *
1896  *         val = 255 - (255 * sum)/16
1897  *
1898  *  where sum is in set {0, ... ,16}
1899  */
1900 static l_uint8 *
makeValTabSG4(void)1901 makeValTabSG4(void)
1902 {
1903 l_int32   i;
1904 l_uint8  *tab;
1905 
1906     PROCNAME("makeValTabSG4");
1907 
1908     if ((tab = (l_uint8 *)LEPT_CALLOC(17, sizeof(l_uint8))) == NULL)
1909         return (l_uint8 *)ERROR_PTR("tab not made", procName, NULL);
1910     for (i = 0; i < 17; i++)
1911         tab[i] = 0xff - (i * 255) / 16;
1912     return tab;
1913 }
1914 
1915 
1916 /*------------------------------------------------------------------*
1917  *                         Scale-to-gray 6x                         *
1918  *------------------------------------------------------------------*/
1919 /*!
1920  * \brief   scaleToGray6Low()
1921  *
1922  * \param[in]    datad   dest data
1923  * \param[in]    wd, hd  dest width, height
1924  * \param[in]    wpld    dest words/line
1925  * \param[in]    datas   src data
1926  * \param[in]    wpls    src words/line
1927  * \param[in]    tab8  made from makePixelSumTab8()
1928  * \param[in]    valtab  made from makeValTabSG6()
1929  * \return  0 if OK; 1 on error
1930  *
1931  * <pre>
1932  * Notes:
1933  *  Each set of 4 6x6 bit-blocks in the source image, which
1934  *  consist of 144 pixels arranged 24 pixels wide by 6 scanlines,
1935  *  is converted to a row of 4 8-bit pixels in the dest image.
1936  *  These 144 pixels of the input image are runs of 24 pixels
1937  *  in six adjacent scanlines.  Each run of 24 pixels is
1938  *  stored in the 24 LSbits of a 32-bit word.  We use 2 LUTs.
1939  *  The first, tab8, takes 6 of these bits and stores
1940  *  sum in one byte.  This is done for each of the 6 scanlines,
1941  *  and the results are added.
1942  *  We now have the sum of ON pixels in the first 6x6 block.  The
1943  *  valtab LUT then converts these values (which go from 0 to 36) to
1944  *  grayscale values between between 255 and 0.  (See makeValTabSG6).
1945  *  This process is repeated for each of the other 3 sets of
1946  *  6x6 input pixels, giving 4 output pixels in total.
1947  *
1948  *  Note: because the input image is processed in groups of
1949  *        24 x 6 pixels, the process clips the input height to
1950  *        (h - h % 6) and the input width to (w - w % 24).
1951  *
1952  * </pre>
1953  */
1954 static void
scaleToGray6Low(l_uint32 * datad,l_int32 wd,l_int32 hd,l_int32 wpld,l_uint32 * datas,l_int32 wpls,l_int32 * tab8,l_uint8 * valtab)1955 scaleToGray6Low(l_uint32  *datad,
1956                 l_int32    wd,
1957                 l_int32    hd,
1958                 l_int32    wpld,
1959                 l_uint32  *datas,
1960                 l_int32    wpls,
1961                 l_int32   *tab8,
1962                 l_uint8   *valtab)
1963 {
1964 l_int32    i, j, l, k;
1965 l_uint32   threebytes1, threebytes2, threebytes3;
1966 l_uint32   threebytes4, threebytes5, threebytes6, sum;
1967 l_uint32  *lines, *lined;
1968 
1969         /* i indexes the dest lines
1970          * l indexes the source lines
1971          * j indexes the dest bytes
1972          * k indexes the source bytes
1973          * We take 18 bytes from the source (144 binary pixels
1974          * in six lines of 24 pixels each) and convert it
1975          * into 4 bytes of the dest (four 8 bpp pixels in one line)   */
1976     for (i = 0, l = 0; i < hd; i++, l += 6) {
1977         lines = datas + l * wpls;
1978         lined = datad + i * wpld;
1979         for (j = 0, k = 0; j < wd; j += 4, k += 3) {
1980                 /* First grab the 18 bytes, 3 at a time, and put each set
1981                  * of 3 bytes into the LS bytes of a 32-bit word. */
1982             threebytes1 = (GET_DATA_BYTE(lines, k) << 16) |
1983                           (GET_DATA_BYTE(lines, k + 1) << 8) |
1984                           GET_DATA_BYTE(lines, k + 2);
1985             threebytes2 = (GET_DATA_BYTE(lines + wpls, k) << 16) |
1986                           (GET_DATA_BYTE(lines + wpls, k + 1) << 8) |
1987                           GET_DATA_BYTE(lines + wpls, k + 2);
1988             threebytes3 = (GET_DATA_BYTE(lines + 2 * wpls, k) << 16) |
1989                           (GET_DATA_BYTE(lines + 2 * wpls, k + 1) << 8) |
1990                           GET_DATA_BYTE(lines + 2 * wpls, k + 2);
1991             threebytes4 = (GET_DATA_BYTE(lines + 3 * wpls, k) << 16) |
1992                           (GET_DATA_BYTE(lines + 3 * wpls, k + 1) << 8) |
1993                           GET_DATA_BYTE(lines + 3 * wpls, k + 2);
1994             threebytes5 = (GET_DATA_BYTE(lines + 4 * wpls, k) << 16) |
1995                           (GET_DATA_BYTE(lines + 4 * wpls, k + 1) << 8) |
1996                           GET_DATA_BYTE(lines + 4 * wpls, k + 2);
1997             threebytes6 = (GET_DATA_BYTE(lines + 5 * wpls, k) << 16) |
1998                           (GET_DATA_BYTE(lines + 5 * wpls, k + 1) << 8) |
1999                           GET_DATA_BYTE(lines + 5 * wpls, k + 2);
2000 
2001                 /* Sum first set of 36 bits and convert to 0-255 */
2002             sum = tab8[(threebytes1 >> 18)] +
2003                   tab8[(threebytes2 >> 18)] +
2004                   tab8[(threebytes3 >> 18)] +
2005                   tab8[(threebytes4 >> 18)] +
2006                   tab8[(threebytes5 >> 18)] +
2007                    tab8[(threebytes6 >> 18)];
2008             SET_DATA_BYTE(lined, j, valtab[GET_DATA_BYTE(&sum, 3)]);
2009 
2010                 /* Ditto for second set */
2011             sum = tab8[((threebytes1 >> 12) & 0x3f)] +
2012                   tab8[((threebytes2 >> 12) & 0x3f)] +
2013                   tab8[((threebytes3 >> 12) & 0x3f)] +
2014                   tab8[((threebytes4 >> 12) & 0x3f)] +
2015                   tab8[((threebytes5 >> 12) & 0x3f)] +
2016                   tab8[((threebytes6 >> 12) & 0x3f)];
2017             SET_DATA_BYTE(lined, j + 1, valtab[GET_DATA_BYTE(&sum, 3)]);
2018 
2019             sum = tab8[((threebytes1 >> 6) & 0x3f)] +
2020                   tab8[((threebytes2 >> 6) & 0x3f)] +
2021                   tab8[((threebytes3 >> 6) & 0x3f)] +
2022                   tab8[((threebytes4 >> 6) & 0x3f)] +
2023                   tab8[((threebytes5 >> 6) & 0x3f)] +
2024                   tab8[((threebytes6 >> 6) & 0x3f)];
2025             SET_DATA_BYTE(lined, j + 2, valtab[GET_DATA_BYTE(&sum, 3)]);
2026 
2027             sum = tab8[(threebytes1 & 0x3f)] +
2028                   tab8[(threebytes2 & 0x3f)] +
2029                   tab8[(threebytes3 & 0x3f)] +
2030                   tab8[(threebytes4 & 0x3f)] +
2031                   tab8[(threebytes5 & 0x3f)] +
2032                   tab8[(threebytes6 & 0x3f)];
2033             SET_DATA_BYTE(lined, j + 3, valtab[GET_DATA_BYTE(&sum, 3)]);
2034         }
2035     }
2036     return;
2037 }
2038 
2039 
2040 /*!
2041  * \brief   makeValTabSG6()
2042  *
2043  *  Returns an 8 bit value for the sum of ON pixels
2044  *  in a 6x6 square, according to
2045  *      val = 255 - (255 * sum)/36
2046  *  where sum is in set {0, ... ,36}
2047  */
2048 static l_uint8 *
makeValTabSG6(void)2049 makeValTabSG6(void)
2050 {
2051 l_int32   i;
2052 l_uint8  *tab;
2053 
2054     PROCNAME("makeValTabSG6");
2055 
2056     if ((tab = (l_uint8 *)LEPT_CALLOC(37, sizeof(l_uint8))) == NULL)
2057         return (l_uint8 *)ERROR_PTR("tab not made", procName, NULL);
2058     for (i = 0; i < 37; i++)
2059         tab[i] = 0xff - (i * 255) / 36;
2060     return tab;
2061 }
2062 
2063 
2064 /*------------------------------------------------------------------*
2065  *                         Scale-to-gray 8x                         *
2066  *------------------------------------------------------------------*/
2067 /*!
2068  * \brief   scaleToGray8Low()
2069  *
2070  * \param[in]    datad   dest data
2071  * \param[in]    wd, hd  dest width, height
2072  * \param[in]    wpld    dest words/line
2073  * \param[in]    datas   src data
2074  * \param[in]    wpls    src words/line
2075  * \param[in]    tab8  made from makePixelSumTab8()
2076  * \param[in]    valtab  made from makeValTabSG8()
2077  * \return  0 if OK; 1 on error.
2078  *
2079  *  The output is processed one dest byte at a time,
2080  *  corresponding to 8 rows of src bytes in the input image.
2081  *  Two lookup tables are used.  The first, tab8, gets the
2082  *  sum of ON pixels in a byte.  After sums from 8 rows have
2083  *  been added, the second table, valtab, converts from this
2084  *  value which is between 0 and 64 to an 8 bpp grayscale
2085  *  value between 0 for all 64 bits ON) and 255 (for 0 bits ON.
2086  */
2087 static void
scaleToGray8Low(l_uint32 * datad,l_int32 wd,l_int32 hd,l_int32 wpld,l_uint32 * datas,l_int32 wpls,l_int32 * tab8,l_uint8 * valtab)2088 scaleToGray8Low(l_uint32  *datad,
2089                 l_int32    wd,
2090                 l_int32    hd,
2091                 l_int32    wpld,
2092                 l_uint32  *datas,
2093                 l_int32    wpls,
2094                 l_int32   *tab8,
2095                 l_uint8   *valtab)
2096 {
2097 l_int32    i, j, k;
2098 l_int32    sbyte0, sbyte1, sbyte2, sbyte3, sbyte4, sbyte5, sbyte6, sbyte7, sum;
2099 l_uint32  *lines, *lined;
2100 
2101         /* i indexes the dest lines
2102          * k indexes the source lines
2103          * j indexes the src and dest bytes
2104          * We take 8 bytes from the source (in 8 lines of 8 pixels
2105          * each) and convert it into one 8 bpp byte of the dest. */
2106     for (i = 0, k = 0; i < hd; i++, k += 8) {
2107         lines = datas + k * wpls;
2108         lined = datad + i * wpld;
2109         for (j = 0; j < wd; j++) {
2110             sbyte0 = GET_DATA_BYTE(lines, j);
2111             sbyte1 = GET_DATA_BYTE(lines + wpls, j);
2112             sbyte2 = GET_DATA_BYTE(lines + 2 * wpls, j);
2113             sbyte3 = GET_DATA_BYTE(lines + 3 * wpls, j);
2114             sbyte4 = GET_DATA_BYTE(lines + 4 * wpls, j);
2115             sbyte5 = GET_DATA_BYTE(lines + 5 * wpls, j);
2116             sbyte6 = GET_DATA_BYTE(lines + 6 * wpls, j);
2117             sbyte7 = GET_DATA_BYTE(lines + 7 * wpls, j);
2118             sum = tab8[sbyte0] + tab8[sbyte1] +
2119                   tab8[sbyte2] + tab8[sbyte3] +
2120                   tab8[sbyte4] + tab8[sbyte5] +
2121                   tab8[sbyte6] + tab8[sbyte7];
2122             SET_DATA_BYTE(lined, j, valtab[sum]);
2123         }
2124     }
2125 
2126     return;
2127 }
2128 
2129 
2130 /*!
2131  * \brief   makeValTabSG8()
2132  *
2133  *  Returns an 8 bit value for the sum of ON pixels
2134  *  in an 8x8 square, according to
2135  *      val = 255 - (255 * sum)/64
2136  *  where sum is in set {0, ... ,64}
2137  */
2138 static l_uint8 *
makeValTabSG8(void)2139 makeValTabSG8(void)
2140 {
2141 l_int32   i;
2142 l_uint8  *tab;
2143 
2144     PROCNAME("makeValTabSG8");
2145 
2146     if ((tab = (l_uint8 *)LEPT_CALLOC(65, sizeof(l_uint8))) == NULL)
2147         return (l_uint8 *)ERROR_PTR("tab not made", procName, NULL);
2148     for (i = 0; i < 65; i++)
2149         tab[i] = 0xff - (i * 255) / 64;
2150     return tab;
2151 }
2152 
2153 
2154 /*------------------------------------------------------------------*
2155  *                         Scale-to-gray 16x                        *
2156  *------------------------------------------------------------------*/
2157 /*!
2158  * \brief   scaleToGray16Low()
2159  *
2160  * \param[in]    datad   dest data
2161  * \param[in]    wd, hd  dest width, height
2162  * \param[in]    wpld    dest words/line
2163  * \param[in]    datas   src data
2164  * \param[in]    wpls    src words/line
2165  * \param[in]    tab8    made from makePixelSumTab8()
2166  * \return  0 if OK; 1 on error.
2167  *
2168  *  The output is processed one dest byte at a time, corresponding
2169  *  to 16 rows consisting each of 2 src bytes in the input image.
2170  *  This uses one lookup table, tab8, which gives the sum of
2171  *  ON pixels in a byte.  After summing for all ON pixels in the
2172  *  32 src bytes, which is between 0 and 256, this is converted
2173  *  to an 8 bpp grayscale value between 0 for 255 or 256 bits ON
2174  *  and 255 for 0 bits ON.
2175  */
2176 static void
scaleToGray16Low(l_uint32 * datad,l_int32 wd,l_int32 hd,l_int32 wpld,l_uint32 * datas,l_int32 wpls,l_int32 * tab8)2177 scaleToGray16Low(l_uint32  *datad,
2178                   l_int32    wd,
2179                  l_int32    hd,
2180                  l_int32    wpld,
2181                  l_uint32  *datas,
2182                  l_int32    wpls,
2183                  l_int32   *tab8)
2184 {
2185 l_int32    i, j, k, m;
2186 l_int32    sum;
2187 l_uint32  *lines, *lined;
2188 
2189         /* i indexes the dest lines
2190          * k indexes the source lines
2191          * j indexes the dest bytes
2192          * m indexes the src bytes
2193          * We take 32 bytes from the source (in 16 lines of 16 pixels
2194          * each) and convert it into one 8 bpp byte of the dest. */
2195     for (i = 0, k = 0; i < hd; i++, k += 16) {
2196         lines = datas + k * wpls;
2197         lined = datad + i * wpld;
2198         for (j = 0; j < wd; j++) {
2199             m = 2 * j;
2200             sum = tab8[GET_DATA_BYTE(lines, m)];
2201             sum += tab8[GET_DATA_BYTE(lines, m + 1)];
2202             sum += tab8[GET_DATA_BYTE(lines + wpls, m)];
2203             sum += tab8[GET_DATA_BYTE(lines + wpls, m + 1)];
2204             sum += tab8[GET_DATA_BYTE(lines + 2 * wpls, m)];
2205             sum += tab8[GET_DATA_BYTE(lines + 2 * wpls, m + 1)];
2206             sum += tab8[GET_DATA_BYTE(lines + 3 * wpls, m)];
2207             sum += tab8[GET_DATA_BYTE(lines + 3 * wpls, m + 1)];
2208             sum += tab8[GET_DATA_BYTE(lines + 4 * wpls, m)];
2209             sum += tab8[GET_DATA_BYTE(lines + 4 * wpls, m + 1)];
2210             sum += tab8[GET_DATA_BYTE(lines + 5 * wpls, m)];
2211             sum += tab8[GET_DATA_BYTE(lines + 5 * wpls, m + 1)];
2212             sum += tab8[GET_DATA_BYTE(lines + 6 * wpls, m)];
2213             sum += tab8[GET_DATA_BYTE(lines + 6 * wpls, m + 1)];
2214             sum += tab8[GET_DATA_BYTE(lines + 7 * wpls, m)];
2215             sum += tab8[GET_DATA_BYTE(lines + 7 * wpls, m + 1)];
2216             sum += tab8[GET_DATA_BYTE(lines + 8 * wpls, m)];
2217             sum += tab8[GET_DATA_BYTE(lines + 8 * wpls, m + 1)];
2218             sum += tab8[GET_DATA_BYTE(lines + 9 * wpls, m)];
2219             sum += tab8[GET_DATA_BYTE(lines + 9 * wpls, m + 1)];
2220             sum += tab8[GET_DATA_BYTE(lines + 10 * wpls, m)];
2221             sum += tab8[GET_DATA_BYTE(lines + 10 * wpls, m + 1)];
2222             sum += tab8[GET_DATA_BYTE(lines + 11 * wpls, m)];
2223             sum += tab8[GET_DATA_BYTE(lines + 11 * wpls, m + 1)];
2224             sum += tab8[GET_DATA_BYTE(lines + 12 * wpls, m)];
2225             sum += tab8[GET_DATA_BYTE(lines + 12 * wpls, m + 1)];
2226             sum += tab8[GET_DATA_BYTE(lines + 13 * wpls, m)];
2227             sum += tab8[GET_DATA_BYTE(lines + 13 * wpls, m + 1)];
2228             sum += tab8[GET_DATA_BYTE(lines + 14 * wpls, m)];
2229             sum += tab8[GET_DATA_BYTE(lines + 14 * wpls, m + 1)];
2230             sum += tab8[GET_DATA_BYTE(lines + 15 * wpls, m)];
2231             sum += tab8[GET_DATA_BYTE(lines + 15 * wpls, m + 1)];
2232             sum = L_MIN(sum, 255);
2233             SET_DATA_BYTE(lined, j, 255 - sum);
2234         }
2235     }
2236 
2237     return;
2238 }
2239 
2240 
2241 
2242 /*------------------------------------------------------------------*
2243  *                         Grayscale mipmap                         *
2244  *------------------------------------------------------------------*/
2245 /*!
2246  * \brief   scaleMipmapLow()
2247  *
2248  *  See notes in scale.c for pixScaleToGrayMipmap().  This function
2249  *  is here for pedagogical reasons.  It gives poor results on document
2250  *  images because of aliasing.
2251  */
2252 static l_int32
scaleMipmapLow(l_uint32 * datad,l_int32 wd,l_int32 hd,l_int32 wpld,l_uint32 * datas1,l_int32 wpls1,l_uint32 * datas2,l_int32 wpls2,l_float32 red)2253 scaleMipmapLow(l_uint32  *datad,
2254                l_int32    wd,
2255                l_int32    hd,
2256                l_int32    wpld,
2257                l_uint32  *datas1,
2258                l_int32    wpls1,
2259                l_uint32  *datas2,
2260                l_int32    wpls2,
2261                l_float32  red)
2262 {
2263 l_int32    i, j, val1, val2, val, row2, col2;
2264 l_int32   *srow, *scol;
2265 l_uint32  *lines1, *lines2, *lined;
2266 l_float32  ratio, w1, w2;
2267 
2268     PROCNAME("scaleMipmapLow");
2269 
2270         /* Clear dest */
2271     memset((char *)datad, 0, 4 * wpld * hd);
2272 
2273         /* Each dest pixel at (j,i) is computed by interpolating
2274            between the two src images at the corresponding location.
2275            We store the UL corner locations of the square of
2276            src pixels in thelower-resolution image that correspond
2277            to dest pixel (j,i).  The are labeled by the arrays
2278            srow[i], scol[j].  The UL corner locations of the higher
2279            resolution src pixels are obtained from these arrays
2280            by multiplying by 2. */
2281     if ((srow = (l_int32 *)LEPT_CALLOC(hd, sizeof(l_int32))) == NULL)
2282         return ERROR_INT("srow not made", procName, 1);
2283     if ((scol = (l_int32 *)LEPT_CALLOC(wd, sizeof(l_int32))) == NULL) {
2284         LEPT_FREE(srow);
2285         return ERROR_INT("scol not made", procName, 1);
2286     }
2287     ratio = 1. / (2. * red);  /* 0.5 for red = 1, 1 for red = 0.5 */
2288     for (i = 0; i < hd; i++)
2289         srow[i] = (l_int32)(ratio * i);
2290     for (j = 0; j < wd; j++)
2291         scol[j] = (l_int32)(ratio * j);
2292 
2293         /* Get weights for linear interpolation: these are the
2294          * 'distances' of the dest image plane from the two
2295          * src image planes. */
2296     w1 = 2. * red - 1.;   /* w1 --> 1 as red --> 1 */
2297     w2 = 1. - w1;
2298 
2299         /* For each dest pixel, compute linear interpolation */
2300     for (i = 0; i < hd; i++) {
2301         row2 = srow[i];
2302         lines1 = datas1 + 2 * row2 * wpls1;
2303         lines2 = datas2 + row2 * wpls2;
2304         lined = datad + i * wpld;
2305         for (j = 0; j < wd; j++) {
2306             col2 = scol[j];
2307             val1 = GET_DATA_BYTE(lines1, 2 * col2);
2308             val2 = GET_DATA_BYTE(lines2, col2);
2309             val = (l_int32)(w1 * val1 + w2 * val2);
2310             SET_DATA_BYTE(lined, j, val);
2311         }
2312     }
2313 
2314     LEPT_FREE(srow);
2315     LEPT_FREE(scol);
2316     return 0;
2317 }
2318