Coverage Report

Created: 2024-06-18 06:05

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