comparison mupdf-source/thirdparty/leptonica/src/scale2.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
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 {
211 l_int32 w, h, minsrc, mindest;
212 l_float32 mag, red;
213 PIX *pixt, *pixd;
214
215 if (!pixs)
216 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
217 if (pixGetDepth(pixs) != 1)
218 return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, NULL);
219 if (scalefactor <= 0.0f)
220 return (PIX *)ERROR_PTR("scalefactor <= 0.0", __func__, NULL);
221 if (scalefactor >= 1.0f)
222 return (PIX *)ERROR_PTR("scalefactor >= 1.0", __func__, NULL);
223 pixGetDimensions(pixs, &w, &h, NULL);
224 minsrc = L_MIN(w, h);
225 mindest = (l_int32)((l_float32)minsrc * scalefactor);
226 if (mindest < 2)
227 return (PIX *)ERROR_PTR("scalefactor too small", __func__, NULL);
228
229 if (scalefactor > 0.5f) { /* see note (5) */
230 mag = 2.0f * scalefactor; /* will be < 2.0 */
231 /* lept_stderr("2x with mag %7.3f\n", mag); */
232 if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL)
233 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL);
234 pixd = pixScaleToGray2(pixt);
235 } else if (scalefactor == 0.5f) {
236 return pixd = pixScaleToGray2(pixs);
237 } else if (scalefactor > 0.33333f) { /* see note (5) */
238 mag = 3.0f * scalefactor; /* will be < 1.5 */
239 /* lept_stderr("3x with mag %7.3f\n", mag); */
240 if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL)
241 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL);
242 pixd = pixScaleToGray3(pixt);
243 } else if (scalefactor > 0.25f) { /* see note (5) */
244 mag = 4.0f * scalefactor; /* will be < 1.3333 */
245 /* lept_stderr("4x with mag %7.3f\n", mag); */
246 if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL)
247 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL);
248 pixd = pixScaleToGray4(pixt);
249 } else if (scalefactor == 0.25f) {
250 return pixd = pixScaleToGray4(pixs);
251 } else if (scalefactor > 0.16667f) { /* see note (5) */
252 mag = 6.0f * scalefactor; /* will be < 1.5 */
253 /* lept_stderr("6x with mag %7.3f\n", mag); */
254 if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL)
255 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL);
256 pixd = pixScaleToGray6(pixt);
257 } else if (scalefactor == 0.16667f) {
258 return pixd = pixScaleToGray6(pixs);
259 } else if (scalefactor > 0.125f) { /* see note (5) */
260 mag = 8.0f * scalefactor; /* will be < 1.3333 */
261 /* lept_stderr("8x with mag %7.3f\n", mag); */
262 if ((pixt = pixScaleBinary(pixs, mag, mag)) == NULL)
263 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL);
264 pixd = pixScaleToGray8(pixt);
265 } else if (scalefactor == 0.125f) {
266 return pixd = pixScaleToGray8(pixs);
267 } else if (scalefactor > 0.0625f) { /* see note (6) */
268 red = 8.0f * scalefactor; /* will be > 0.5 */
269 /* lept_stderr("8x with red %7.3f\n", red); */
270 if ((pixt = pixScaleBinary(pixs, red, red)) == NULL)
271 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL);
272 pixd = pixScaleToGray8(pixt);
273 } else if (scalefactor == 0.0625f) {
274 return pixd = pixScaleToGray16(pixs);
275 } else { /* see note (7) */
276 red = 16.0f * scalefactor; /* will be <= 1.0 */
277 /* lept_stderr("16x with red %7.3f\n", red); */
278 if ((pixt = pixScaleToGray16(pixs)) == NULL)
279 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL);
280 if (red < 0.7f)
281 pixd = pixScaleSmooth(pixt, red, red); /* see note (3) */
282 else
283 pixd = pixScaleGrayLI(pixt, red, red); /* see note (2) */
284 }
285
286 pixDestroy(&pixt);
287 if (!pixd)
288 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
289 pixCopyInputFormat(pixd, pixs);
290 return pixd;
291 }
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 {
320 l_int32 w, h, minsrc, mindest;
321 l_float32 eps, factor;
322 PIX *pixt, *pixd;
323
324 if (!pixs)
325 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
326 if (pixGetDepth(pixs) != 1)
327 return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, NULL);
328 if (scalefactor <= 0.0f)
329 return (PIX *)ERROR_PTR("scalefactor <= 0.0", __func__, NULL);
330 if (scalefactor >= 1.0f)
331 return (PIX *)ERROR_PTR("scalefactor >= 1.0", __func__, NULL);
332 pixGetDimensions(pixs, &w, &h, NULL);
333 minsrc = L_MIN(w, h);
334 mindest = (l_int32)((l_float32)minsrc * scalefactor);
335 if (mindest < 2)
336 return (PIX *)ERROR_PTR("scalefactor too small", __func__, NULL);
337 eps = 0.0001f;
338
339 /* Handle the special cases */
340 if (scalefactor > 0.5f - eps && scalefactor < 0.5f + eps)
341 return pixScaleToGray2(pixs);
342 else if (scalefactor > 0.33333f - eps && scalefactor < 0.33333f + eps)
343 return pixScaleToGray3(pixs);
344 else if (scalefactor > 0.25f - eps && scalefactor < 0.25f + eps)
345 return pixScaleToGray4(pixs);
346 else if (scalefactor > 0.16666f - eps && scalefactor < 0.16666f + eps)
347 return pixScaleToGray6(pixs);
348 else if (scalefactor > 0.125f - eps && scalefactor < 0.125f + eps)
349 return pixScaleToGray8(pixs);
350 else if (scalefactor > 0.0625f - eps && scalefactor < 0.0625f + eps)
351 return pixScaleToGray16(pixs);
352
353 if (scalefactor > 0.0625f) { /* scale binary first */
354 factor = 2.0f * scalefactor;
355 if ((pixt = pixScaleBinary(pixs, factor, factor)) == NULL)
356 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL);
357 pixd = pixScaleToGray2(pixt);
358 } else { /* scalefactor < 0.0625; scale-to-gray first */
359 factor = 16.0f * scalefactor; /* will be < 1.0 */
360 if ((pixt = pixScaleToGray16(pixs)) == NULL)
361 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL);
362 if (factor < 0.7f)
363 pixd = pixScaleSmooth(pixt, factor, factor);
364 else
365 pixd = pixScaleGrayLI(pixt, factor, factor);
366 }
367 pixDestroy(&pixt);
368 if (!pixd)
369 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
370 pixCopyInputFormat(pixd, pixs);
371 return pixd;
372 }
373
374
375 /*-----------------------------------------------------------------------*
376 * Scale-to-gray (1 bpp --> 8 bpp; integer downscaling) *
377 *-----------------------------------------------------------------------*/
378 /*!
379 * \brief pixScaleToGray2()
380 *
381 * \param[in] pixs 1 bpp
382 * \return pixd 8 bpp, scaled down by 2x in each direction,
383 * or NULL on error.
384 */
385 PIX *
386 pixScaleToGray2(PIX *pixs)
387 {
388 l_uint8 *valtab;
389 l_int32 ws, hs, wd, hd;
390 l_int32 wpld, wpls;
391 l_uint32 *sumtab;
392 l_uint32 *datas, *datad;
393 PIX *pixd;
394
395 if (!pixs)
396 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
397 if (pixGetDepth(pixs) != 1)
398 return (PIX *)ERROR_PTR("pixs must be 1 bpp", __func__, NULL);
399
400 pixGetDimensions(pixs, &ws, &hs, NULL);
401 wd = ws / 2;
402 hd = hs / 2;
403 if (wd == 0 || hd == 0)
404 return (PIX *)ERROR_PTR("pixs too small", __func__, NULL);
405
406 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
407 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
408 pixSetPadBits(pixs, 0);
409 pixCopyInputFormat(pixd, pixs);
410 pixCopyResolution(pixd, pixs);
411 pixScaleResolution(pixd, 0.5, 0.5);
412 datas = pixGetData(pixs);
413 datad = pixGetData(pixd);
414 wpls = pixGetWpl(pixs);
415 wpld = pixGetWpl(pixd);
416
417 sumtab = makeSumTabSG2();
418 valtab = makeValTabSG2();
419 scaleToGray2Low(datad, wd, hd, wpld, datas, wpls, sumtab, valtab);
420 LEPT_FREE(sumtab);
421 LEPT_FREE(valtab);
422 return pixd;
423 }
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 {
444 l_uint8 *valtab;
445 l_int32 ws, hs, wd, hd;
446 l_int32 wpld, wpls;
447 l_uint32 *sumtab;
448 l_uint32 *datas, *datad;
449 PIX *pixd;
450
451 if (!pixs)
452 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
453 if (pixGetDepth(pixs) != 1)
454 return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, NULL);
455
456 pixGetDimensions(pixs, &ws, &hs, NULL);
457 wd = (ws / 3) & 0xfffffff8; /* truncate to factor of 8 */
458 hd = hs / 3;
459 if (wd == 0 || hd == 0)
460 return (PIX *)ERROR_PTR("pixs too small", __func__, NULL);
461
462 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
463 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
464 pixCopyInputFormat(pixd, pixs);
465 pixCopyResolution(pixd, pixs);
466 pixScaleResolution(pixd, 0.33333f, 0.33333f);
467 datas = pixGetData(pixs);
468 datad = pixGetData(pixd);
469 wpls = pixGetWpl(pixs);
470 wpld = pixGetWpl(pixd);
471
472 sumtab = makeSumTabSG3();
473 valtab = makeValTabSG3();
474 scaleToGray3Low(datad, wd, hd, wpld, datas, wpls, sumtab, valtab);
475 LEPT_FREE(sumtab);
476 LEPT_FREE(valtab);
477 return pixd;
478 }
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 {
496 l_uint8 *valtab;
497 l_int32 ws, hs, wd, hd;
498 l_int32 wpld, wpls;
499 l_uint32 *sumtab;
500 l_uint32 *datas, *datad;
501 PIX *pixd;
502
503 if (!pixs)
504 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
505 if (pixGetDepth(pixs) != 1)
506 return (PIX *)ERROR_PTR("pixs must be 1 bpp", __func__, NULL);
507
508 pixGetDimensions(pixs, &ws, &hs, NULL);
509 wd = (ws / 4) & 0xfffffffe; /* truncate to factor of 2 */
510 hd = hs / 4;
511 if (wd == 0 || hd == 0)
512 return (PIX *)ERROR_PTR("pixs too small", __func__, NULL);
513
514 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
515 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
516 pixCopyInputFormat(pixd, pixs);
517 pixCopyResolution(pixd, pixs);
518 pixScaleResolution(pixd, 0.25, 0.25);
519 datas = pixGetData(pixs);
520 datad = pixGetData(pixd);
521 wpls = pixGetWpl(pixs);
522 wpld = pixGetWpl(pixd);
523
524 sumtab = makeSumTabSG4();
525 valtab = makeValTabSG4();
526 scaleToGray4Low(datad, wd, hd, wpld, datas, wpls, sumtab, valtab);
527 LEPT_FREE(sumtab);
528 LEPT_FREE(valtab);
529 return pixd;
530 }
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 {
549 l_uint8 *valtab;
550 l_int32 ws, hs, wd, hd, wpld, wpls;
551 l_int32 *tab8;
552 l_uint32 *datas, *datad;
553 PIX *pixd;
554
555 if (!pixs)
556 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
557 if (pixGetDepth(pixs) != 1)
558 return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, NULL);
559
560 pixGetDimensions(pixs, &ws, &hs, NULL);
561 wd = (ws / 6) & 0xfffffff8; /* truncate to factor of 8 */
562 hd = hs / 6;
563 if (wd == 0 || hd == 0)
564 return (PIX *)ERROR_PTR("pixs too small", __func__, NULL);
565
566 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
567 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
568 pixCopyInputFormat(pixd, pixs);
569 pixCopyResolution(pixd, pixs);
570 pixScaleResolution(pixd, 0.16667f, 0.16667f);
571 datas = pixGetData(pixs);
572 datad = pixGetData(pixd);
573 wpls = pixGetWpl(pixs);
574 wpld = pixGetWpl(pixd);
575
576 tab8 = makePixelSumTab8();
577 valtab = makeValTabSG6();
578 scaleToGray6Low(datad, wd, hd, wpld, datas, wpls, tab8, valtab);
579 LEPT_FREE(tab8);
580 LEPT_FREE(valtab);
581 return pixd;
582 }
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 {
595 l_uint8 *valtab;
596 l_int32 ws, hs, wd, hd;
597 l_int32 wpld, wpls;
598 l_int32 *tab8;
599 l_uint32 *datas, *datad;
600 PIX *pixd;
601
602 if (!pixs)
603 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
604 if (pixGetDepth(pixs) != 1)
605 return (PIX *)ERROR_PTR("pixs must be 1 bpp", __func__, NULL);
606
607 pixGetDimensions(pixs, &ws, &hs, NULL);
608 wd = ws / 8; /* truncate to nearest dest byte */
609 hd = hs / 8;
610 if (wd == 0 || hd == 0)
611 return (PIX *)ERROR_PTR("pixs too small", __func__, NULL);
612
613 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
614 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
615 pixCopyInputFormat(pixd, pixs);
616 pixCopyResolution(pixd, pixs);
617 pixScaleResolution(pixd, 0.125, 0.125);
618 datas = pixGetData(pixs);
619 datad = pixGetData(pixd);
620 wpls = pixGetWpl(pixs);
621 wpld = pixGetWpl(pixd);
622
623 tab8 = makePixelSumTab8();
624 valtab = makeValTabSG8();
625 scaleToGray8Low(datad, wd, hd, wpld, datas, wpls, tab8, valtab);
626 LEPT_FREE(tab8);
627 LEPT_FREE(valtab);
628 return pixd;
629 }
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 {
642 l_int32 ws, hs, wd, hd;
643 l_int32 wpld, wpls;
644 l_int32 *tab8;
645 l_uint32 *datas, *datad;
646 PIX *pixd;
647
648 if (!pixs)
649 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
650 if (pixGetDepth(pixs) != 1)
651 return (PIX *)ERROR_PTR("pixs must be 1 bpp", __func__, NULL);
652
653 pixGetDimensions(pixs, &ws, &hs, NULL);
654 wd = ws / 16;
655 hd = hs / 16;
656 if (wd == 0 || hd == 0)
657 return (PIX *)ERROR_PTR("pixs too small", __func__, NULL);
658
659 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
660 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
661 pixCopyInputFormat(pixd, pixs);
662 pixCopyResolution(pixd, pixs);
663 pixScaleResolution(pixd, 0.0625, 0.0625);
664 datas = pixGetData(pixs);
665 datad = pixGetData(pixd);
666 wpls = pixGetWpl(pixs);
667 wpld = pixGetWpl(pixd);
668
669 tab8 = makePixelSumTab8();
670 scaleToGray16Low(datad, wd, hd, wpld, datas, wpls, tab8);
671 LEPT_FREE(tab8);
672 return pixd;
673 }
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 {
714 l_int32 w, h, minsrc, mindest;
715 l_float32 red;
716 PIX *pixs1, *pixs2, *pixt, *pixd;
717
718 if (!pixs)
719 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
720 if (pixGetDepth(pixs) != 1)
721 return (PIX *)ERROR_PTR("pixs not 1 bpp", __func__, NULL);
722 if (scalefactor <= 0.0)
723 return (PIX *)ERROR_PTR("scalefactor <= 0.0", __func__, NULL);
724 if (scalefactor >= 1.0)
725 return (PIX *)ERROR_PTR("scalefactor >= 1.0", __func__, NULL);
726 pixGetDimensions(pixs, &w, &h, NULL);
727 minsrc = L_MIN(w, h);
728 mindest = (l_int32)((l_float32)minsrc * scalefactor);
729 if (mindest < 2)
730 return (PIX *)ERROR_PTR("scalefactor too small", __func__, NULL);
731
732 if (scalefactor > 0.5) {
733 pixs1 = pixConvert1To8(NULL, pixs, 255, 0);
734 pixs2 = pixScaleToGray2(pixs);
735 red = scalefactor;
736 } else if (scalefactor == 0.5) {
737 return pixScaleToGray2(pixs);
738 } else if (scalefactor > 0.25) {
739 pixs1 = pixScaleToGray2(pixs);
740 pixs2 = pixScaleToGray4(pixs);
741 red = 2.f * scalefactor;
742 } else if (scalefactor == 0.25) {
743 return pixScaleToGray4(pixs);
744 } else if (scalefactor > 0.125) {
745 pixs1 = pixScaleToGray4(pixs);
746 pixs2 = pixScaleToGray8(pixs);
747 red = 4.f * scalefactor;
748 } else if (scalefactor == 0.125) {
749 return pixScaleToGray8(pixs);
750 } else if (scalefactor > 0.0625) {
751 pixs1 = pixScaleToGray8(pixs);
752 pixs2 = pixScaleToGray16(pixs);
753 red = 8.f * scalefactor;
754 } else if (scalefactor == 0.0625) {
755 return pixScaleToGray16(pixs);
756 } else { /* end of the pyramid; just do it */
757 red = 16.0f * scalefactor; /* will be <= 1.0 */
758 if ((pixt = pixScaleToGray16(pixs)) == NULL)
759 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL);
760 if (red < 0.7)
761 pixd = pixScaleSmooth(pixt, red, red);
762 else
763 pixd = pixScaleGrayLI(pixt, red, red);
764 pixDestroy(&pixt);
765 return pixd;
766 }
767
768 pixd = pixScaleMipmap(pixs1, pixs2, red);
769 pixCopyInputFormat(pixd, pixs);
770
771 pixDestroy(&pixs1);
772 pixDestroy(&pixs2);
773 return pixd;
774 }
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 {
801 l_int32 ws1, hs1, ws2, hs2, wd, hd, wpls1, wpls2, wpld;
802 l_uint32 *datas1, *datas2, *datad;
803 PIX *pixd;
804
805 if (!pixs1 || pixGetDepth(pixs1) != 8 || pixGetColormap(pixs1))
806 return (PIX *)ERROR_PTR("pixs1 underdefined, not 8 bpp, or cmapped",
807 __func__, NULL);
808 if (!pixs2 || pixGetDepth(pixs2) != 8 || pixGetColormap(pixs2))
809 return (PIX *)ERROR_PTR("pixs2 underdefined, not 8 bpp, or cmapped",
810 __func__, NULL);
811 pixGetDimensions(pixs1, &ws1, &hs1, NULL);
812 pixGetDimensions(pixs2, &ws2, &hs2, NULL);
813 if (scale > 1.0 || scale < 0.5)
814 return (PIX *)ERROR_PTR("scale not in [0.5, 1.0]", __func__, NULL);
815 if (ws1 < 2 * ws2)
816 return (PIX *)ERROR_PTR("invalid width ratio", __func__, NULL);
817 if (hs1 < 2 * hs2)
818 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 datas1 = pixGetData(pixs1);
823 wpls1 = pixGetWpl(pixs1);
824 datas2 = pixGetData(pixs2);
825 wpls2 = pixGetWpl(pixs2);
826 wd = (l_int32)(2. * scale * pixGetWidth(pixs2));
827 hd = (l_int32)(2. * scale * pixGetHeight(pixs2));
828 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
829 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
830 pixCopyInputFormat(pixd, pixs1);
831 pixCopyResolution(pixd, pixs1);
832 pixScaleResolution(pixd, scale, scale);
833 datad = pixGetData(pixd);
834 wpld = pixGetWpl(pixd);
835
836 scaleMipmapLow(datad, wd, hd, wpld, datas1, wpls1, datas2, wpls2, scale);
837 return pixd;
838 }
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 {
855 l_int32 w, h, d, wd, hd, wpls, wpld, start, i, j, k;
856 l_uint8 sval;
857 l_uint16 sval16;
858 l_uint32 sval32;
859 l_uint32 *lines, *datas, *lined, *datad;
860 PIX *pixd;
861
862 if (!pixs)
863 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
864 pixGetDimensions(pixs, &w, &h, &d);
865 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
866 return (PIX *)ERROR_PTR("depth not in {1,2,4,8,16,32}", __func__, NULL);
867 if (factor <= 0)
868 return (PIX *)ERROR_PTR("factor <= 0; invalid", __func__, NULL);
869 if (factor == 1)
870 return pixCopy(NULL, pixs);
871
872 if (d == 1)
873 return pixExpandBinaryReplicate(pixs, factor, factor);
874
875 wd = factor * w;
876 hd = factor * h;
877 if ((pixd = pixCreate(wd, hd, d)) == NULL)
878 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
879 pixCopyColormap(pixd, pixs);
880 pixCopyInputFormat(pixd, pixs);
881 pixCopyResolution(pixd, pixs);
882 pixScaleResolution(pixd, (l_float32)factor, (l_float32)factor);
883 datas = pixGetData(pixs);
884 wpls = pixGetWpl(pixs);
885 datad = pixGetData(pixd);
886 wpld = pixGetWpl(pixd);
887
888 switch (d) {
889 case 2:
890 for (i = 0; i < h; i++) {
891 lines = datas + i * wpls;
892 lined = datad + factor * i * wpld;
893 for (j = 0; j < w; j++) {
894 sval = GET_DATA_DIBIT(lines, j);
895 start = factor * j;
896 for (k = 0; k < factor; k++)
897 SET_DATA_DIBIT(lined, start + k, sval);
898 }
899 for (k = 1; k < factor; k++)
900 memcpy(lined + k * wpld, lined, 4 * wpld);
901 }
902 break;
903 case 4:
904 for (i = 0; i < h; i++) {
905 lines = datas + i * wpls;
906 lined = datad + factor * i * wpld;
907 for (j = 0; j < w; j++) {
908 sval = GET_DATA_QBIT(lines, j);
909 start = factor * j;
910 for (k = 0; k < factor; k++)
911 SET_DATA_QBIT(lined, start + k, sval);
912 }
913 for (k = 1; k < factor; k++)
914 memcpy(lined + k * wpld, lined, 4 * wpld);
915 }
916 break;
917 case 8:
918 for (i = 0; i < h; i++) {
919 lines = datas + i * wpls;
920 lined = datad + factor * i * wpld;
921 for (j = 0; j < w; j++) {
922 sval = GET_DATA_BYTE(lines, j);
923 start = factor * j;
924 for (k = 0; k < factor; k++)
925 SET_DATA_BYTE(lined, start + k, sval);
926 }
927 for (k = 1; k < factor; k++)
928 memcpy(lined + k * wpld, lined, 4 * wpld);
929 }
930 break;
931 case 16:
932 for (i = 0; i < h; i++) {
933 lines = datas + i * wpls;
934 lined = datad + factor * i * wpld;
935 for (j = 0; j < w; j++) {
936 sval16 = GET_DATA_TWO_BYTES(lines, j);
937 start = factor * j;
938 for (k = 0; k < factor; k++)
939 SET_DATA_TWO_BYTES(lined, start + k, sval16);
940 }
941 for (k = 1; k < factor; k++)
942 memcpy(lined + k * wpld, lined, 4 * wpld);
943 }
944 break;
945 case 32:
946 for (i = 0; i < h; i++) {
947 lines = datas + i * wpls;
948 lined = datad + factor * i * wpld;
949 for (j = 0; j < w; j++) {
950 sval32 = *(lines + j);
951 start = factor * j;
952 for (k = 0; k < factor; k++)
953 *(lined + start + k) = sval32;
954 }
955 for (k = 1; k < factor; k++)
956 memcpy(lined + k * wpld, lined, 4 * wpld);
957 }
958 break;
959 default:
960 lept_stderr("invalid depth\n");
961 }
962
963 if (d == 32 && pixGetSpp(pixs) == 4)
964 pixScaleAndTransferAlpha(pixd, pixs, (l_float32)factor,
965 (l_float32)factor);
966 return pixd;
967 }
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 {
1002 l_int32 ws, hs, wd, hd, wpls, wpld, i, j, k, m;
1003 l_int32 minval, maxval, val;
1004 l_uint32 *datas, *datad, *lines, *lined;
1005 PIX *pixd;
1006
1007 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
1008 return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
1009 __func__, NULL);
1010 pixGetDimensions(pixs, &ws, &hs, NULL);
1011 if (type != L_CHOOSE_MIN && type != L_CHOOSE_MAX &&
1012 type != L_CHOOSE_MAXDIFF)
1013 return (PIX *)ERROR_PTR("invalid type", __func__, NULL);
1014 if (xfact < 1 || yfact < 1)
1015 return (PIX *)ERROR_PTR("xfact and yfact must be >= 1", __func__, NULL);
1016
1017 if (xfact == 2 && yfact == 2)
1018 return pixScaleGrayMinMax2(pixs, type);
1019
1020 wd = ws / xfact;
1021 if (wd == 0) { /* single tile */
1022 wd = 1;
1023 xfact = ws;
1024 }
1025 hd = hs / yfact;
1026 if (hd == 0) { /* single tile */
1027 hd = 1;
1028 yfact = hs;
1029 }
1030 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1031 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1032 pixCopyInputFormat(pixd, pixs);
1033 datas = pixGetData(pixs);
1034 datad = pixGetData(pixd);
1035 wpls = pixGetWpl(pixs);
1036 wpld = pixGetWpl(pixd);
1037 for (i = 0; i < hd; i++) {
1038 lined = datad + i * wpld;
1039 for (j = 0; j < wd; j++) {
1040 if (type == L_CHOOSE_MIN || type == L_CHOOSE_MAXDIFF) {
1041 minval = 255;
1042 for (k = 0; k < yfact; k++) {
1043 lines = datas + (yfact * i + k) * wpls;
1044 for (m = 0; m < xfact; m++) {
1045 val = GET_DATA_BYTE(lines, xfact * j + m);
1046 if (val < minval)
1047 minval = val;
1048 }
1049 }
1050 }
1051 if (type == L_CHOOSE_MAX || type == L_CHOOSE_MAXDIFF) {
1052 maxval = 0;
1053 for (k = 0; k < yfact; k++) {
1054 lines = datas + (yfact * i + k) * wpls;
1055 for (m = 0; m < xfact; m++) {
1056 val = GET_DATA_BYTE(lines, xfact * j + m);
1057 if (val > maxval)
1058 maxval = val;
1059 }
1060 }
1061 }
1062 if (type == L_CHOOSE_MIN)
1063 SET_DATA_BYTE(lined, j, minval);
1064 else if (type == L_CHOOSE_MAX)
1065 SET_DATA_BYTE(lined, j, maxval);
1066 else /* type == L_CHOOSE_MAXDIFF */
1067 SET_DATA_BYTE(lined, j, maxval - minval);
1068 }
1069 }
1070
1071 return pixd;
1072 }
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 {
1105 l_int32 ws, hs, wd, hd, wpls, wpld, i, j, k;
1106 l_int32 minval, maxval;
1107 l_int32 val[4];
1108 l_uint32 *datas, *datad, *lines, *lined;
1109 PIX *pixd;
1110
1111 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
1112 return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
1113 __func__, NULL);
1114 pixGetDimensions(pixs, &ws, &hs, NULL);
1115 if (ws < 2 || hs < 2)
1116 return (PIX *)ERROR_PTR("too small: ws < 2 or hs < 2", __func__, NULL);
1117 if (type != L_CHOOSE_MIN && type != L_CHOOSE_MAX &&
1118 type != L_CHOOSE_MAXDIFF)
1119 return (PIX *)ERROR_PTR("invalid type", __func__, NULL);
1120
1121 wd = ws / 2;
1122 hd = hs / 2;
1123 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1124 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1125 pixCopyInputFormat(pixd, pixs);
1126 datas = pixGetData(pixs);
1127 datad = pixGetData(pixd);
1128 wpls = pixGetWpl(pixs);
1129 wpld = pixGetWpl(pixd);
1130 for (i = 0; i < hd; i++) {
1131 lines = datas + 2 * i * wpls;
1132 lined = datad + i * wpld;
1133 for (j = 0; j < wd; j++) {
1134 val[0] = GET_DATA_BYTE(lines, 2 * j);
1135 val[1] = GET_DATA_BYTE(lines, 2 * j + 1);
1136 val[2] = GET_DATA_BYTE(lines + wpls, 2 * j);
1137 val[3] = GET_DATA_BYTE(lines + wpls, 2 * j + 1);
1138 if (type == L_CHOOSE_MIN || type == L_CHOOSE_MAXDIFF) {
1139 minval = 255;
1140 for (k = 0; k < 4; k++) {
1141 if (val[k] < minval)
1142 minval = val[k];
1143 }
1144 }
1145 if (type == L_CHOOSE_MAX || type == L_CHOOSE_MAXDIFF) {
1146 maxval = 0;
1147 for (k = 0; k < 4; k++) {
1148 if (val[k] > maxval)
1149 maxval = val[k];
1150 }
1151 }
1152 if (type == L_CHOOSE_MIN)
1153 SET_DATA_BYTE(lined, j, minval);
1154 else if (type == L_CHOOSE_MAX)
1155 SET_DATA_BYTE(lined, j, maxval);
1156 else /* type == L_CHOOSE_MAXDIFF */
1157 SET_DATA_BYTE(lined, j, maxval - minval);
1158 }
1159 }
1160
1161 return pixd;
1162 }
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 {
1189 PIX *pixt1, *pixt2, *pixt3, *pixt4;
1190
1191 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
1192 return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
1193 __func__, NULL);
1194 if (level1 > 4 || level2 > 4 || level3 > 4 || level4 > 4)
1195 return (PIX *)ERROR_PTR("levels must not exceed 4", __func__, NULL);
1196
1197 if (level1 <= 0) {
1198 L_WARNING("no reduction because level1 not > 0\n", __func__);
1199 return pixCopy(NULL, pixs);
1200 }
1201
1202 pixt1 = pixScaleGrayRank2(pixs, level1);
1203 if (level2 <= 0)
1204 return pixt1;
1205
1206 pixt2 = pixScaleGrayRank2(pixt1, level2);
1207 pixDestroy(&pixt1);
1208 if (level3 <= 0)
1209 return pixt2;
1210
1211 pixt3 = pixScaleGrayRank2(pixt2, level3);
1212 pixDestroy(&pixt2);
1213 if (level4 <= 0)
1214 return pixt3;
1215
1216 pixt4 = pixScaleGrayRank2(pixt3, level4);
1217 pixDestroy(&pixt3);
1218 return pixt4;
1219 }
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 {
1248 l_int32 ws, hs, wd, hd, wpls, wpld, i, j, k, m;
1249 l_int32 minval, maxval, rankval, minindex, maxindex;
1250 l_int32 val[4];
1251 l_int32 midval[4]; /* should only use 2 of these */
1252 l_uint32 *datas, *datad, *lines, *lined;
1253 PIX *pixd;
1254
1255 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
1256 return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
1257 __func__, NULL);
1258 if (rank < 1 || rank > 4)
1259 return (PIX *)ERROR_PTR("invalid rank", __func__, NULL);
1260
1261 if (rank == 1)
1262 return pixScaleGrayMinMax2(pixs, L_CHOOSE_MIN);
1263 if (rank == 4)
1264 return pixScaleGrayMinMax2(pixs, L_CHOOSE_MAX);
1265
1266 pixGetDimensions(pixs, &ws, &hs, NULL);
1267 wd = ws / 2;
1268 hd = hs / 2;
1269 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1270 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1271 pixCopyInputFormat(pixd, pixs);
1272 datas = pixGetData(pixs);
1273 datad = pixGetData(pixd);
1274 wpls = pixGetWpl(pixs);
1275 wpld = pixGetWpl(pixd);
1276 for (i = 0; i < hd; i++) {
1277 lines = datas + 2 * i * wpls;
1278 lined = datad + i * wpld;
1279 for (j = 0; j < wd; j++) {
1280 val[0] = GET_DATA_BYTE(lines, 2 * j);
1281 val[1] = GET_DATA_BYTE(lines, 2 * j + 1);
1282 val[2] = GET_DATA_BYTE(lines + wpls, 2 * j);
1283 val[3] = GET_DATA_BYTE(lines + wpls, 2 * j + 1);
1284 minval = maxval = val[0];
1285 minindex = maxindex = 0;
1286 for (k = 1; k < 4; k++) {
1287 if (val[k] < minval) {
1288 minval = val[k];
1289 minindex = k;
1290 continue;
1291 }
1292 if (val[k] > maxval) {
1293 maxval = val[k];
1294 maxindex = k;
1295 }
1296 }
1297 for (k = 0, m = 0; k < 4; k++) {
1298 if (k == minindex || k == maxindex)
1299 continue;
1300 midval[m++] = val[k];
1301 }
1302 if (m > 2) /* minval == maxval; all val[k] are the same */
1303 rankval = minval;
1304 else if (rank == 2)
1305 rankval = L_MIN(midval[0], midval[1]);
1306 else /* rank == 3 */
1307 rankval = L_MAX(midval[0], midval[1]);
1308 SET_DATA_BYTE(lined, j, rankval);
1309 }
1310 }
1311
1312 return pixd;
1313 }
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 {
1339 PIX *pix1, *pix2;
1340
1341 if (!pixs || !pixd)
1342 return ERROR_INT("pixs and pixd not both defined", __func__, 1);
1343 if (pixGetDepth(pixs) != 32 || pixGetSpp(pixs) != 4)
1344 return ERROR_INT("pixs not 32 bpp and 4 spp", __func__, 1);
1345 if (pixGetDepth(pixd) != 32)
1346 return ERROR_INT("pixd not 32 bpp", __func__, 1);
1347
1348 if (scalex == 1.0 && scaley == 1.0) {
1349 pixCopyRGBComponent(pixd, pixs, L_ALPHA_CHANNEL);
1350 return 0;
1351 }
1352
1353 pix1 = pixGetRGBComponent(pixs, L_ALPHA_CHANNEL);
1354 pix2 = pixScale(pix1, scalex, scaley);
1355 pixSetRGBComponent(pixd, pix2, L_ALPHA_CHANNEL);
1356 pixDestroy(&pix1);
1357 pixDestroy(&pix2);
1358 return 0;
1359 }
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 {
1417 l_int32 ws, hs, d, spp;
1418 PIX *pixd, *pix32, *pixg2, *pixgs;
1419
1420 if (!pixs)
1421 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1422 pixGetDimensions(pixs, &ws, &hs, &d);
1423 if (d != 32 && !pixGetColormap(pixs))
1424 return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", __func__, NULL);
1425 if (scalex <= 0.0 || scaley <= 0.0)
1426 return (PIX *)ERROR_PTR("scale factor <= 0.0", __func__, NULL);
1427 if (pixg && pixGetDepth(pixg) != 8) {
1428 L_WARNING("pixg not 8 bpp; using 'fract' transparent alpha\n",
1429 __func__);
1430 pixg = NULL;
1431 }
1432 if (!pixg && (fract < 0.0 || fract > 1.0)) {
1433 L_WARNING("invalid fract; using fully opaque\n", __func__);
1434 fract = 1.0;
1435 }
1436 if (!pixg && fract == 0.0)
1437 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 if (d != 32)
1441 pix32 = pixConvertTo32(pixs);
1442 else
1443 pix32 = pixClone(pixs);
1444 spp = pixGetSpp(pix32);
1445 pixSetSpp(pix32, 3); /* ignore the alpha channel for scaling */
1446 pixd = pixScale(pix32, scalex, scaley);
1447 pixSetSpp(pix32, spp); /* restore initial value in case it's a clone */
1448 pixDestroy(&pix32);
1449
1450 /* Set up alpha layer with a fading border and scale it */
1451 if (!pixg) {
1452 pixg2 = pixCreate(ws, hs, 8);
1453 if (fract == 1.0)
1454 pixSetAll(pixg2);
1455 else if (fract > 0.0)
1456 pixSetAllArbitrary(pixg2, (l_int32)(255.0 * fract));
1457 } else {
1458 pixg2 = pixResizeToMatch(pixg, NULL, ws, hs);
1459 }
1460 if (ws > 10 && hs > 10) { /* see note 4 */
1461 pixSetBorderRingVal(pixg2, 1,
1462 (l_int32)(255.0 * fract * AlphaMaskBorderVals[0]));
1463 pixSetBorderRingVal(pixg2, 2,
1464 (l_int32)(255.0 * fract * AlphaMaskBorderVals[1]));
1465 }
1466 pixgs = pixScaleGeneral(pixg2, scalex, scaley, 0.0, 0);
1467
1468 /* Combine into a 4 spp result */
1469 pixSetRGBComponent(pixd, pixgs, L_ALPHA_CHANNEL);
1470 pixCopyInputFormat(pixd, pixs);
1471
1472 pixDestroy(&pixg2);
1473 pixDestroy(&pixgs);
1474 return pixd;
1475 }
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 {
1520 l_int32 i, j, l, k, m, wd4, extra;
1521 l_uint32 sbyte1, sbyte2, sum;
1522 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 wd4 = wd & 0xfffffffc;
1531 extra = wd - wd4;
1532 for (i = 0, l = 0; i < hd; i++, l += 2) {
1533 lines = datas + l * wpls;
1534 lined = datad + i * wpld;
1535 for (j = 0, k = 0; j < wd4; j += 4, k++) {
1536 sbyte1 = GET_DATA_BYTE(lines, k);
1537 sbyte2 = GET_DATA_BYTE(lines + wpls, k);
1538 sum = sumtab[sbyte1] + sumtab[sbyte2];
1539 SET_DATA_BYTE(lined, j, valtab[sum >> 24]);
1540 SET_DATA_BYTE(lined, j + 1, valtab[(sum >> 16) & 0xff]);
1541 SET_DATA_BYTE(lined, j + 2, valtab[(sum >> 8) & 0xff]);
1542 SET_DATA_BYTE(lined, j + 3, valtab[sum & 0xff]);
1543 }
1544 if (extra > 0) {
1545 sbyte1 = GET_DATA_BYTE(lines, k);
1546 sbyte2 = GET_DATA_BYTE(lines + wpls, k);
1547 sum = sumtab[sbyte1] + sumtab[sbyte2];
1548 for (m = 0; m < extra; m++) {
1549 SET_DATA_BYTE(lined, j + m,
1550 valtab[((sum >> (24 - 8 * m)) & 0xff)]);
1551 }
1552 }
1553
1554 }
1555 }
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 {
1573 l_int32 i;
1574 l_int32 sum[] = {0, 1, 1, 2};
1575 l_uint32 *tab;
1576
1577 /* Pack the four sums separately in four bytes */
1578 tab = (l_uint32 *)LEPT_CALLOC(256, sizeof(l_uint32));
1579 for (i = 0; i < 256; i++) {
1580 tab[i] = (sum[i & 0x3] | sum[(i >> 2) & 0x3] << 8 |
1581 sum[(i >> 4) & 0x3] << 16 | sum[(i >> 6) & 0x3] << 24);
1582 }
1583 return tab;
1584 }
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 {
1601 l_int32 i;
1602 l_uint8 *tab;
1603
1604 tab = (l_uint8 *)LEPT_CALLOC(5, sizeof(l_uint8));
1605 for (i = 0; i < 5; i++)
1606 tab[i] = 255 - (i * 255) / 4;
1607 return tab;
1608 }
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 {
1658 l_int32 i, j, l, k;
1659 l_uint32 threebytes1, threebytes2, threebytes3, sum;
1660 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 for (i = 0, l = 0; i < hd; i++, l += 3) {
1670 lines = datas + l * wpls;
1671 lined = datad + i * wpld;
1672 for (j = 0, k = 0; j < wd; j += 8, k += 3) {
1673 threebytes1 = (GET_DATA_BYTE(lines, k) << 16) |
1674 (GET_DATA_BYTE(lines, k + 1) << 8) |
1675 GET_DATA_BYTE(lines, k + 2);
1676 threebytes2 = (GET_DATA_BYTE(lines + wpls, k) << 16) |
1677 (GET_DATA_BYTE(lines + wpls, k + 1) << 8) |
1678 GET_DATA_BYTE(lines + wpls, k + 2);
1679 threebytes3 = (GET_DATA_BYTE(lines + 2 * wpls, k) << 16) |
1680 (GET_DATA_BYTE(lines + 2 * wpls, k + 1) << 8) |
1681 GET_DATA_BYTE(lines + 2 * wpls, k + 2);
1682
1683 sum = sumtab[(threebytes1 >> 18)] +
1684 sumtab[(threebytes2 >> 18)] +
1685 sumtab[(threebytes3 >> 18)];
1686 SET_DATA_BYTE(lined, j, valtab[GET_DATA_BYTE(&sum, 2)]);
1687 SET_DATA_BYTE(lined, j + 1, valtab[GET_DATA_BYTE(&sum, 3)]);
1688
1689 sum = sumtab[((threebytes1 >> 12) & 0x3f)] +
1690 sumtab[((threebytes2 >> 12) & 0x3f)] +
1691 sumtab[((threebytes3 >> 12) & 0x3f)];
1692 SET_DATA_BYTE(lined, j + 2, valtab[GET_DATA_BYTE(&sum, 2)]);
1693 SET_DATA_BYTE(lined, j + 3, valtab[GET_DATA_BYTE(&sum, 3)]);
1694
1695 sum = sumtab[((threebytes1 >> 6) & 0x3f)] +
1696 sumtab[((threebytes2 >> 6) & 0x3f)] +
1697 sumtab[((threebytes3 >> 6) & 0x3f)];
1698 SET_DATA_BYTE(lined, j + 4, valtab[GET_DATA_BYTE(&sum, 2)]);
1699 SET_DATA_BYTE(lined, j + 5, valtab[GET_DATA_BYTE(&sum, 3)]);
1700
1701 sum = sumtab[(threebytes1 & 0x3f)] +
1702 sumtab[(threebytes2 & 0x3f)] +
1703 sumtab[(threebytes3 & 0x3f)];
1704 SET_DATA_BYTE(lined, j + 6, valtab[GET_DATA_BYTE(&sum, 2)]);
1705 SET_DATA_BYTE(lined, j + 7, valtab[GET_DATA_BYTE(&sum, 3)]);
1706 }
1707 }
1708 }
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 {
1728 l_int32 i;
1729 l_int32 sum[] = {0, 1, 1, 2, 1, 2, 2, 3};
1730 l_uint32 *tab;
1731
1732 /* Pack the two sums separately in two bytes */
1733 tab = (l_uint32 *)LEPT_CALLOC(64, sizeof(l_uint32));
1734 for (i = 0; i < 64; i++) {
1735 tab[i] = (sum[i & 0x07]) | (sum[(i >> 3) & 0x07] << 8);
1736 }
1737 return tab;
1738 }
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 {
1755 l_int32 i;
1756 l_uint8 *tab;
1757
1758 tab = (l_uint8 *)LEPT_CALLOC(10, sizeof(l_uint8));
1759 for (i = 0; i < 10; i++)
1760 tab[i] = 0xff - (i * 255) / 9;
1761 return tab;
1762 }
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 {
1803 l_int32 i, j, l, k;
1804 l_uint32 sbyte1, sbyte2, sbyte3, sbyte4, sum;
1805 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 for (i = 0, l = 0; i < hd; i++, l += 4) {
1814 lines = datas + l * wpls;
1815 lined = datad + i * wpld;
1816 for (j = 0, k = 0; j < wd; j += 2, k++) {
1817 sbyte1 = GET_DATA_BYTE(lines, k);
1818 sbyte2 = GET_DATA_BYTE(lines + wpls, k);
1819 sbyte3 = GET_DATA_BYTE(lines + 2 * wpls, k);
1820 sbyte4 = GET_DATA_BYTE(lines + 3 * wpls, k);
1821 sum = sumtab[sbyte1] + sumtab[sbyte2] +
1822 sumtab[sbyte3] + sumtab[sbyte4];
1823 SET_DATA_BYTE(lined, j, valtab[GET_DATA_BYTE(&sum, 2)]);
1824 SET_DATA_BYTE(lined, j + 1, valtab[GET_DATA_BYTE(&sum, 3)]);
1825 }
1826 }
1827 }
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 {
1845 l_int32 i;
1846 l_int32 sum[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
1847 l_uint32 *tab;
1848
1849 /* Pack the two sums separately in two bytes */
1850 tab = (l_uint32 *)LEPT_CALLOC(256, sizeof(l_uint32));
1851 for (i = 0; i < 256; i++) {
1852 tab[i] = (sum[i & 0xf]) | (sum[(i >> 4) & 0xf] << 8);
1853 }
1854 return tab;
1855 }
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 {
1872 l_int32 i;
1873 l_uint8 *tab;
1874
1875 tab = (l_uint8 *)LEPT_CALLOC(17, sizeof(l_uint8));
1876 for (i = 0; i < 17; i++)
1877 tab[i] = 0xff - (i * 255) / 16;
1878 return tab;
1879 }
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 {
1928 l_int32 i, j, l, k;
1929 l_uint32 threebytes1, threebytes2, threebytes3;
1930 l_uint32 threebytes4, threebytes5, threebytes6, sum;
1931 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 for (i = 0, l = 0; i < hd; i++, l += 6) {
1941 lines = datas + l * wpls;
1942 lined = datad + i * wpld;
1943 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 threebytes1 = (GET_DATA_BYTE(lines, k) << 16) |
1947 (GET_DATA_BYTE(lines, k + 1) << 8) |
1948 GET_DATA_BYTE(lines, k + 2);
1949 threebytes2 = (GET_DATA_BYTE(lines + wpls, k) << 16) |
1950 (GET_DATA_BYTE(lines + wpls, k + 1) << 8) |
1951 GET_DATA_BYTE(lines + wpls, k + 2);
1952 threebytes3 = (GET_DATA_BYTE(lines + 2 * wpls, k) << 16) |
1953 (GET_DATA_BYTE(lines + 2 * wpls, k + 1) << 8) |
1954 GET_DATA_BYTE(lines + 2 * wpls, k + 2);
1955 threebytes4 = (GET_DATA_BYTE(lines + 3 * wpls, k) << 16) |
1956 (GET_DATA_BYTE(lines + 3 * wpls, k + 1) << 8) |
1957 GET_DATA_BYTE(lines + 3 * wpls, k + 2);
1958 threebytes5 = (GET_DATA_BYTE(lines + 4 * wpls, k) << 16) |
1959 (GET_DATA_BYTE(lines + 4 * wpls, k + 1) << 8) |
1960 GET_DATA_BYTE(lines + 4 * wpls, k + 2);
1961 threebytes6 = (GET_DATA_BYTE(lines + 5 * wpls, k) << 16) |
1962 (GET_DATA_BYTE(lines + 5 * wpls, k + 1) << 8) |
1963 GET_DATA_BYTE(lines + 5 * wpls, k + 2);
1964
1965 /* Sum first set of 36 bits and convert to 0-255 */
1966 sum = tab8[(threebytes1 >> 18)] +
1967 tab8[(threebytes2 >> 18)] +
1968 tab8[(threebytes3 >> 18)] +
1969 tab8[(threebytes4 >> 18)] +
1970 tab8[(threebytes5 >> 18)] +
1971 tab8[(threebytes6 >> 18)];
1972 SET_DATA_BYTE(lined, j, valtab[GET_DATA_BYTE(&sum, 3)]);
1973
1974 /* Ditto for second set */
1975 sum = tab8[((threebytes1 >> 12) & 0x3f)] +
1976 tab8[((threebytes2 >> 12) & 0x3f)] +
1977 tab8[((threebytes3 >> 12) & 0x3f)] +
1978 tab8[((threebytes4 >> 12) & 0x3f)] +
1979 tab8[((threebytes5 >> 12) & 0x3f)] +
1980 tab8[((threebytes6 >> 12) & 0x3f)];
1981 SET_DATA_BYTE(lined, j + 1, valtab[GET_DATA_BYTE(&sum, 3)]);
1982
1983 sum = tab8[((threebytes1 >> 6) & 0x3f)] +
1984 tab8[((threebytes2 >> 6) & 0x3f)] +
1985 tab8[((threebytes3 >> 6) & 0x3f)] +
1986 tab8[((threebytes4 >> 6) & 0x3f)] +
1987 tab8[((threebytes5 >> 6) & 0x3f)] +
1988 tab8[((threebytes6 >> 6) & 0x3f)];
1989 SET_DATA_BYTE(lined, j + 2, valtab[GET_DATA_BYTE(&sum, 3)]);
1990
1991 sum = tab8[(threebytes1 & 0x3f)] +
1992 tab8[(threebytes2 & 0x3f)] +
1993 tab8[(threebytes3 & 0x3f)] +
1994 tab8[(threebytes4 & 0x3f)] +
1995 tab8[(threebytes5 & 0x3f)] +
1996 tab8[(threebytes6 & 0x3f)];
1997 SET_DATA_BYTE(lined, j + 3, valtab[GET_DATA_BYTE(&sum, 3)]);
1998 }
1999 }
2000 }
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 {
2017 l_int32 i;
2018 l_uint8 *tab;
2019
2020 tab = (l_uint8 *)LEPT_CALLOC(37, sizeof(l_uint8));
2021 for (i = 0; i < 37; i++)
2022 tab[i] = 0xff - (i * 255) / 36;
2023 return tab;
2024 }
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 {
2064 l_int32 i, j, k;
2065 l_int32 sbyte0, sbyte1, sbyte2, sbyte3, sbyte4, sbyte5, sbyte6, sbyte7, sum;
2066 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 for (i = 0, k = 0; i < hd; i++, k += 8) {
2074 lines = datas + k * wpls;
2075 lined = datad + i * wpld;
2076 for (j = 0; j < wd; j++) {
2077 sbyte0 = GET_DATA_BYTE(lines, j);
2078 sbyte1 = GET_DATA_BYTE(lines + wpls, j);
2079 sbyte2 = GET_DATA_BYTE(lines + 2 * wpls, j);
2080 sbyte3 = GET_DATA_BYTE(lines + 3 * wpls, j);
2081 sbyte4 = GET_DATA_BYTE(lines + 4 * wpls, j);
2082 sbyte5 = GET_DATA_BYTE(lines + 5 * wpls, j);
2083 sbyte6 = GET_DATA_BYTE(lines + 6 * wpls, j);
2084 sbyte7 = GET_DATA_BYTE(lines + 7 * wpls, j);
2085 sum = tab8[sbyte0] + tab8[sbyte1] +
2086 tab8[sbyte2] + tab8[sbyte3] +
2087 tab8[sbyte4] + tab8[sbyte5] +
2088 tab8[sbyte6] + tab8[sbyte7];
2089 SET_DATA_BYTE(lined, j, valtab[sum]);
2090 }
2091 }
2092 }
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 {
2109 l_int32 i;
2110 l_uint8 *tab;
2111
2112 tab = (l_uint8 *)LEPT_CALLOC(65, sizeof(l_uint8));
2113 for (i = 0; i < 65; i++)
2114 tab[i] = 0xff - (i * 255) / 64;
2115 return tab;
2116 }
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 {
2153 l_int32 i, j, k, m;
2154 l_int32 sum;
2155 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 for (i = 0, k = 0; i < hd; i++, k += 16) {
2164 lines = datas + k * wpls;
2165 lined = datad + i * wpld;
2166 for (j = 0; j < wd; j++) {
2167 m = 2 * j;
2168 sum = tab8[GET_DATA_BYTE(lines, m)];
2169 sum += tab8[GET_DATA_BYTE(lines, m + 1)];
2170 sum += tab8[GET_DATA_BYTE(lines + wpls, m)];
2171 sum += tab8[GET_DATA_BYTE(lines + wpls, m + 1)];
2172 sum += tab8[GET_DATA_BYTE(lines + 2 * wpls, m)];
2173 sum += tab8[GET_DATA_BYTE(lines + 2 * wpls, m + 1)];
2174 sum += tab8[GET_DATA_BYTE(lines + 3 * wpls, m)];
2175 sum += tab8[GET_DATA_BYTE(lines + 3 * wpls, m + 1)];
2176 sum += tab8[GET_DATA_BYTE(lines + 4 * wpls, m)];
2177 sum += tab8[GET_DATA_BYTE(lines + 4 * wpls, m + 1)];
2178 sum += tab8[GET_DATA_BYTE(lines + 5 * wpls, m)];
2179 sum += tab8[GET_DATA_BYTE(lines + 5 * wpls, m + 1)];
2180 sum += tab8[GET_DATA_BYTE(lines + 6 * wpls, m)];
2181 sum += tab8[GET_DATA_BYTE(lines + 6 * wpls, m + 1)];
2182 sum += tab8[GET_DATA_BYTE(lines + 7 * wpls, m)];
2183 sum += tab8[GET_DATA_BYTE(lines + 7 * wpls, m + 1)];
2184 sum += tab8[GET_DATA_BYTE(lines + 8 * wpls, m)];
2185 sum += tab8[GET_DATA_BYTE(lines + 8 * wpls, m + 1)];
2186 sum += tab8[GET_DATA_BYTE(lines + 9 * wpls, m)];
2187 sum += tab8[GET_DATA_BYTE(lines + 9 * wpls, m + 1)];
2188 sum += tab8[GET_DATA_BYTE(lines + 10 * wpls, m)];
2189 sum += tab8[GET_DATA_BYTE(lines + 10 * wpls, m + 1)];
2190 sum += tab8[GET_DATA_BYTE(lines + 11 * wpls, m)];
2191 sum += tab8[GET_DATA_BYTE(lines + 11 * wpls, m + 1)];
2192 sum += tab8[GET_DATA_BYTE(lines + 12 * wpls, m)];
2193 sum += tab8[GET_DATA_BYTE(lines + 12 * wpls, m + 1)];
2194 sum += tab8[GET_DATA_BYTE(lines + 13 * wpls, m)];
2195 sum += tab8[GET_DATA_BYTE(lines + 13 * wpls, m + 1)];
2196 sum += tab8[GET_DATA_BYTE(lines + 14 * wpls, m)];
2197 sum += tab8[GET_DATA_BYTE(lines + 14 * wpls, m + 1)];
2198 sum += tab8[GET_DATA_BYTE(lines + 15 * wpls, m)];
2199 sum += tab8[GET_DATA_BYTE(lines + 15 * wpls, m + 1)];
2200 sum = L_MIN(sum, 255);
2201 SET_DATA_BYTE(lined, j, 255 - sum);
2202 }
2203 }
2204 }
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 {
2232 l_int32 i, j, val1, val2, val, row2, col2;
2233 l_int32 *srow, *scol;
2234 l_uint32 *lines1, *lines2, *lined;
2235 l_float32 ratio, w1, w2;
2236
2237 /* Clear dest */
2238 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 if ((srow = (l_int32 *)LEPT_CALLOC(hd, sizeof(l_int32))) == NULL)
2249 return ERROR_INT("srow not made", __func__, 1);
2250 if ((scol = (l_int32 *)LEPT_CALLOC(wd, sizeof(l_int32))) == NULL) {
2251 LEPT_FREE(srow);
2252 return ERROR_INT("scol not made", __func__, 1);
2253 }
2254 ratio = 1.f / (2.f * red); /* 0.5 for red = 1, 1 for red = 0.5 */
2255 for (i = 0; i < hd; i++)
2256 srow[i] = (l_int32)(ratio * i);
2257 for (j = 0; j < wd; j++)
2258 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 w1 = 2.f * red - 1.f; /* w1 --> 1 as red --> 1 */
2264 w2 = 1.f - w1;
2265
2266 /* For each dest pixel, compute linear interpolation */
2267 for (i = 0; i < hd; i++) {
2268 row2 = srow[i];
2269 lines1 = datas1 + 2 * row2 * wpls1;
2270 lines2 = datas2 + row2 * wpls2;
2271 lined = datad + i * wpld;
2272 for (j = 0; j < wd; j++) {
2273 col2 = scol[j];
2274 val1 = GET_DATA_BYTE(lines1, 2 * col2);
2275 val2 = GET_DATA_BYTE(lines2, col2);
2276 val = (l_int32)(w1 * val1 + w2 * val2);
2277 SET_DATA_BYTE(lined, j, val);
2278 }
2279 }
2280
2281 LEPT_FREE(srow);
2282 LEPT_FREE(scol);
2283 return 0;
2284 }