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