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