Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
scale1.c
Go to the documentation of this file.
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
116#ifdef HAVE_CONFIG_H
117#include <config_auto.h>
118#endif /* HAVE_CONFIG_H */
119
120#include <string.h>
121#include "allheaders.h"
122
123static void scaleColorLILow(l_uint32 *datad, l_int32 wd, l_int32 hd,
124 l_int32 wpld, l_uint32 *datas, l_int32 ws,
125 l_int32 hs, l_int32 wpls);
126static void scaleGrayLILow(l_uint32 *datad, l_int32 wd, l_int32 hd,
127 l_int32 wpld, l_uint32 *datas, l_int32 ws,
128 l_int32 hs, l_int32 wpls);
129static void scaleColor2xLILow(l_uint32 *datad, l_int32 wpld, l_uint32 *datas,
130 l_int32 ws, l_int32 hs, l_int32 wpls);
131static void scaleColor2xLILineLow(l_uint32 *lined, l_int32 wpld,
132 l_uint32 *lines, l_int32 ws, l_int32 wpls,
133 l_int32 lastlineflag);
134static void scaleGray2xLILow(l_uint32 *datad, l_int32 wpld, l_uint32 *datas,
135 l_int32 ws, l_int32 hs, l_int32 wpls);
136static void scaleGray2xLILineLow(l_uint32 *lined, l_int32 wpld,
137 l_uint32 *lines, l_int32 ws, l_int32 wpls,
138 l_int32 lastlineflag);
139static void scaleGray4xLILow(l_uint32 *datad, l_int32 wpld, l_uint32 *datas,
140 l_int32 ws, l_int32 hs, l_int32 wpls);
141static void scaleGray4xLILineLow(l_uint32 *lined, l_int32 wpld,
142 l_uint32 *lines, l_int32 ws, l_int32 wpls,
143 l_int32 lastlineflag);
144static l_int32 scaleBySamplingLow(l_uint32 *datad, l_int32 wd, l_int32 hd,
145 l_int32 wpld, l_uint32 *datas, l_int32 ws,
146 l_int32 hs, l_int32 d, l_int32 wpls,
147 l_float32 shiftx, l_float32 shifty);
148static l_int32 scaleSmoothLow(l_uint32 *datad, l_int32 wd, l_int32 hd,
149 l_int32 wpld, l_uint32 *datas, l_int32 ws,
150 l_int32 hs, l_int32 d, l_int32 wpls,
151 l_int32 size);
152static void scaleRGBToGray2Low(l_uint32 *datad, l_int32 wd, l_int32 hd,
153 l_int32 wpld, l_uint32 *datas, l_int32 wpls,
154 l_float32 rwt, l_float32 gwt, l_float32 bwt);
155static void scaleColorAreaMapLow(l_uint32 *datad, l_int32 wd, l_int32 hd,
156 l_int32 wpld, l_uint32 *datas, l_int32 ws,
157 l_int32 hs, l_int32 wpls);
158static void scaleGrayAreaMapLow(l_uint32 *datad, l_int32 wd, l_int32 hd,
159 l_int32 wpld, l_uint32 *datas, l_int32 ws,
160 l_int32 hs, l_int32 wpls);
161static void scaleAreaMapLow2(l_uint32 *datad, l_int32 wd, l_int32 hd,
162 l_int32 wpld, l_uint32 *datas, l_int32 d,
163 l_int32 wpls);
164static l_int32 scaleBinaryLow(l_uint32 *datad, l_int32 wd, l_int32 hd,
165 l_int32 wpld, l_uint32 *datas, l_int32 ws,
166 l_int32 hs, l_int32 wpls,
167 l_float32 shiftx, l_float32 shifty);
168
169#ifndef NO_CONSOLE_IO
170#define DEBUG_OVERFLOW 0
171#define DEBUG_UNROLLING 0
172#endif /* ~NO_CONSOLE_IO */
173
174/*------------------------------------------------------------------*
175 * Top level scaling dispatcher *
176 *------------------------------------------------------------------*/
253PIX *
255 l_float32 scalex,
256 l_float32 scaley)
257{
258l_int32 sharpwidth;
259l_float32 maxscale, sharpfract;
260
261 if (!pixs)
262 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
263
264 /* Reduce the default sharpening factors by 2 if maxscale < 0.7 */
265 maxscale = L_MAX(scalex, scaley);
266 sharpfract = (maxscale < 0.7) ? 0.2f : 0.4f;
267 sharpwidth = (maxscale < 0.7) ? 1 : 2;
268
269 return pixScaleGeneral(pixs, scalex, scaley, sharpfract, sharpwidth);
270}
271
272
281PIX *
283 l_int32 delw,
284 l_int32 delh)
285{
286l_int32 w, h, wd, hd;
287
288 if (!pixs)
289 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
290
291 if (delw == 0 && delh == 0)
292 return pixCopy(NULL, pixs);
293
294 pixGetDimensions(pixs, &w, &h, NULL);
295 wd = w + delw;
296 hd = h + delh;
297 if (wd <= 0 || hd <= 0)
298 return (PIX *)ERROR_PTR("pix dimension reduced to 0", __func__, NULL);
299
300 return pixScaleToSize(pixs, wd, hd);
301}
302
303
322PIX *
324 l_int32 wd,
325 l_int32 hd)
326{
327l_int32 w, h;
328l_float32 scalex, scaley;
329
330 if (!pixs)
331 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
332 if (wd <= 0 && hd <= 0)
333 return (PIX *)ERROR_PTR("neither wd nor hd > 0", __func__, NULL);
334
335 pixGetDimensions(pixs, &w, &h, NULL);
336 if (wd <= 0) {
337 scaley = (l_float32)hd / (l_float32)h;
338 scalex = scaley;
339 } else if (hd <= 0) {
340 scalex = (l_float32)wd / (l_float32)w;
341 scaley = scalex;
342 } else {
343 scalex = (l_float32)wd / (l_float32)w;
344 scaley = (l_float32)hd / (l_float32)h;
345 }
346
347 return pixScale(pixs, scalex, scaley);
348}
349
350
360PIX *
362 l_float32 target,
363 l_float32 assumed,
364 l_float32 *pscalefact)
365{
366l_int32 xres;
367l_float32 factor;
368
369 if (pscalefact) *pscalefact = 1.0;
370 if (!pixs)
371 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
372 if (target <= 0)
373 return (PIX *)ERROR_PTR("target resolution <= 0", __func__, NULL);
374
375 xres = pixGetXRes(pixs);
376 if (xres <= 0) {
377 if (assumed == 0)
378 return pixCopy(NULL, pixs);
379 xres = assumed;
380 }
381 factor = target / (l_float32)xres;
382 if (pscalefact) *pscalefact = factor;
383
384 return pixScale(pixs, factor, factor);
385}
386
387
418PIX *
420 l_float32 scalex,
421 l_float32 scaley,
422 l_float32 sharpfract,
423 l_int32 sharpwidth)
424{
425l_int32 d;
426l_float32 maxscale, minscale;
427PIX *pix1, *pix2, *pixd;
428
429 if (!pixs)
430 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
431 d = pixGetDepth(pixs);
432 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
433 return (PIX *)ERROR_PTR("pixs not {1,2,4,8,16,32} bpp", __func__, NULL);
434 if (scalex <= 0.0 || scaley <= 0.0)
435 return (PIX *)ERROR_PTR("scale factor <= 0", __func__, NULL);
436 if (scalex == 1.0 && scaley == 1.0)
437 return pixCopy(NULL, pixs);
438
439 if (d == 1)
440 return pixScaleBinary(pixs, scalex, scaley);
441
442 /* Remove colormap; clone if possible; result is either 8 or 32 bpp */
443 if ((pix1 = pixConvertTo8Or32(pixs, L_CLONE, 0)) == NULL)
444 return (PIX *)ERROR_PTR("pix1 not made", __func__, NULL);
445
446 /* Scale (up or down) */
447 d = pixGetDepth(pix1);
448 maxscale = L_MAX(scalex, scaley);
449 minscale = L_MIN(scalex, scaley);
450 if (maxscale < 0.7) { /* use low-pass filter for anti-aliasing */
451 if (minscale < 0.02) { /* whole-pixel low-pass filter */
452 pix2 = pixScaleSmooth(pix1, scalex, scaley);
453 } else { /* fractional pixel low-pass filter */
454 pix2 = pixScaleAreaMap(pix1, scalex, scaley);
455 }
456 if (maxscale > 0.2 && sharpfract > 0.0 && sharpwidth > 0) {
457 pixd = pixUnsharpMasking(pix2, sharpwidth, sharpfract);
458 } else {
459 pixd = pixClone(pix2);
460 }
461 } else { /* use linear interpolation */
462 if (d == 8) {
463 pix2 = pixScaleGrayLI(pix1, scalex, scaley);
464 } else { /* d == 32 */
465 pix2 = pixScaleColorLI(pix1, scalex, scaley);
466 }
467 if (maxscale < 1.4 && sharpfract > 0.0 && sharpwidth > 0) {
468 pixd = pixUnsharpMasking(pix2, sharpwidth, sharpfract);
469 } else {
470 pixd = pixClone(pix2);
471 }
472 }
473
474 pixDestroy(&pix1);
475 pixDestroy(&pix2);
476 pixCopyText(pixd, pixs);
477 pixCopyInputFormat(pixd, pixs);
478 return pixd;
479}
480
481
482/*------------------------------------------------------------------*
483 * Scaling by linear interpolation *
484 *------------------------------------------------------------------*/
509PIX *
511 l_float32 scalex,
512 l_float32 scaley)
513{
514l_int32 d;
515l_float32 maxscale;
516PIX *pixt, *pixd;
517
518 if (!pixs || (pixGetDepth(pixs) == 1))
519 return (PIX *)ERROR_PTR("pixs not defined or 1 bpp", __func__, NULL);
520 maxscale = L_MAX(scalex, scaley);
521 if (maxscale < 0.7) {
522 L_WARNING("scaling factors < 0.7; do regular scaling\n", __func__);
523 return pixScaleGeneral(pixs, scalex, scaley, 0.0, 0);
524 }
525 d = pixGetDepth(pixs);
526 if (d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
527 return (PIX *)ERROR_PTR("pixs not {2,4,8,16,32} bpp", __func__, NULL);
528
529 /* Remove colormap; clone if possible; result is either 8 or 32 bpp */
530 if ((pixt = pixConvertTo8Or32(pixs, L_CLONE, 0)) == NULL)
531 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL);
532
533 d = pixGetDepth(pixt);
534 if (d == 8)
535 pixd = pixScaleGrayLI(pixt, scalex, scaley);
536 else /* d == 32 */
537 pixd = pixScaleColorLI(pixt, scalex, scaley);
538
539 pixDestroy(&pixt);
540 pixCopyInputFormat(pixd, pixs);
541 return pixd;
542}
543
544
566PIX *
568 l_float32 scalex,
569 l_float32 scaley)
570{
571l_int32 ws, hs, wpls, wd, hd, wpld;
572l_uint32 *datas, *datad;
573l_float32 maxscale;
574PIX *pixd;
575
576 if (!pixs || (pixGetDepth(pixs) != 32))
577 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", __func__, NULL);
578 maxscale = L_MAX(scalex, scaley);
579 if (maxscale < 0.7) {
580 L_WARNING("scaling factors < 0.7; do regular scaling\n", __func__);
581 return pixScaleGeneral(pixs, scalex, scaley, 0.0, 0);
582 }
583
584 /* Do fast special cases if possible */
585 if (scalex == 1.0 && scaley == 1.0)
586 return pixCopy(NULL, pixs);
587 if (scalex == 2.0 && scaley == 2.0)
588 return pixScaleColor2xLI(pixs);
589 if (scalex == 4.0 && scaley == 4.0)
590 return pixScaleColor4xLI(pixs);
591
592 /* General case */
593 pixGetDimensions(pixs, &ws, &hs, NULL);
594 datas = pixGetData(pixs);
595 wpls = pixGetWpl(pixs);
596 wd = (l_int32)(scalex * (l_float32)ws + 0.5);
597 hd = (l_int32)(scaley * (l_float32)hs + 0.5);
598 if ((pixd = pixCreate(wd, hd, 32)) == NULL)
599 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
600 pixCopyResolution(pixd, pixs);
601 pixScaleResolution(pixd, scalex, scaley);
602 datad = pixGetData(pixd);
603 wpld = pixGetWpl(pixd);
604 scaleColorLILow(datad, wd, hd, wpld, datas, ws, hs, wpls);
605 if (pixGetSpp(pixs) == 4)
606 pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley);
607
608 pixCopyInputFormat(pixd, pixs);
609 return pixd;
610}
611
612
628PIX *
630{
631l_int32 ws, hs, wpls, wpld;
632l_uint32 *datas, *datad;
633PIX *pixd;
634
635 if (!pixs || (pixGetDepth(pixs) != 32))
636 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", __func__, NULL);
637
638 pixGetDimensions(pixs, &ws, &hs, NULL);
639 datas = pixGetData(pixs);
640 wpls = pixGetWpl(pixs);
641 if ((pixd = pixCreate(2 * ws, 2 * hs, 32)) == NULL)
642 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
643 pixCopyResolution(pixd, pixs);
644 pixScaleResolution(pixd, 2.0, 2.0);
645 datad = pixGetData(pixd);
646 wpld = pixGetWpl(pixd);
647 scaleColor2xLILow(datad, wpld, datas, ws, hs, wpls);
648 if (pixGetSpp(pixs) == 4)
649 pixScaleAndTransferAlpha(pixd, pixs, 2.0, 2.0);
650
651 pixCopyInputFormat(pixd, pixs);
652 return pixd;
653}
654
655
673PIX *
675{
676PIX *pixr, *pixg, *pixb;
677PIX *pixrs, *pixgs, *pixbs;
678PIX *pixd;
679
680 if (!pixs || (pixGetDepth(pixs) != 32))
681 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", __func__, NULL);
682
683 pixr = pixGetRGBComponent(pixs, COLOR_RED);
684 pixrs = pixScaleGray4xLI(pixr);
685 pixDestroy(&pixr);
686 pixg = pixGetRGBComponent(pixs, COLOR_GREEN);
687 pixgs = pixScaleGray4xLI(pixg);
688 pixDestroy(&pixg);
689 pixb = pixGetRGBComponent(pixs, COLOR_BLUE);
690 pixbs = pixScaleGray4xLI(pixb);
691 pixDestroy(&pixb);
692
693 if ((pixd = pixCreateRGBImage(pixrs, pixgs, pixbs)) == NULL) {
694 L_ERROR("pixd not made\n", __func__);
695 } else {
696 if (pixGetSpp(pixs) == 4)
697 pixScaleAndTransferAlpha(pixd, pixs, 4.0, 4.0);
698 pixCopyInputFormat(pixd, pixs);
699 }
700
701 pixDestroy(&pixrs);
702 pixDestroy(&pixgs);
703 pixDestroy(&pixbs);
704 return pixd;
705}
706
707
765PIX *
767 l_float32 scalex,
768 l_float32 scaley)
769{
770l_int32 ws, hs, wpls, wd, hd, wpld;
771l_uint32 *datas, *datad;
772l_float32 maxscale;
773PIX *pixd;
774
775 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
776 return (PIX *)ERROR_PTR("pixs undefined, cmapped or not 8 bpp",
777 __func__, NULL);
778 maxscale = L_MAX(scalex, scaley);
779 if (maxscale < 0.7) {
780 L_WARNING("scaling factors < 0.7; do regular scaling\n", __func__);
781 return pixScaleGeneral(pixs, scalex, scaley, 0.0, 0);
782 }
783
784 /* Do fast special cases if possible */
785 if (scalex == 1.0 && scaley == 1.0)
786 return pixCopy(NULL, pixs);
787 if (scalex == 2.0 && scaley == 2.0)
788 return pixScaleGray2xLI(pixs);
789 if (scalex == 4.0 && scaley == 4.0)
790 return pixScaleGray4xLI(pixs);
791
792 /* General case */
793 pixGetDimensions(pixs, &ws, &hs, NULL);
794 datas = pixGetData(pixs);
795 wpls = pixGetWpl(pixs);
796 wd = (l_int32)(scalex * (l_float32)ws + 0.5);
797 hd = (l_int32)(scaley * (l_float32)hs + 0.5);
798 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
799 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
800 pixCopyText(pixd, pixs);
801 pixCopyResolution(pixd, pixs);
802 pixCopyInputFormat(pixd, pixs);
803 pixScaleResolution(pixd, scalex, scaley);
804 datad = pixGetData(pixd);
805 wpld = pixGetWpl(pixd);
806 scaleGrayLILow(datad, wd, hd, wpld, datas, ws, hs, wpls);
807 return pixd;
808}
809
810
824PIX *
826{
827l_int32 ws, hs, wpls, wpld;
828l_uint32 *datas, *datad;
829PIX *pixd;
830
831 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
832 return (PIX *)ERROR_PTR("pixs undefined, cmapped or not 8 bpp",
833 __func__, NULL);
834
835 pixGetDimensions(pixs, &ws, &hs, NULL);
836 datas = pixGetData(pixs);
837 wpls = pixGetWpl(pixs);
838 if ((pixd = pixCreate(2 * ws, 2 * hs, 8)) == NULL)
839 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
840 pixCopyResolution(pixd, pixs);
841 pixCopyInputFormat(pixd, pixs);
842 pixScaleResolution(pixd, 2.0, 2.0);
843 datad = pixGetData(pixd);
844 wpld = pixGetWpl(pixd);
845 scaleGray2xLILow(datad, wpld, datas, ws, hs, wpls);
846 return pixd;
847}
848
849
863PIX *
865{
866l_int32 ws, hs, wpls, wpld;
867l_uint32 *datas, *datad;
868PIX *pixd;
869
870 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
871 return (PIX *)ERROR_PTR("pixs undefined, cmapped or not 8 bpp",
872 __func__, NULL);
873
874 pixGetDimensions(pixs, &ws, &hs, NULL);
875 datas = pixGetData(pixs);
876 wpls = pixGetWpl(pixs);
877 if ((pixd = pixCreate(4 * ws, 4 * hs, 8)) == NULL)
878 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
879 pixCopyResolution(pixd, pixs);
880 pixCopyInputFormat(pixd, pixs);
881 pixScaleResolution(pixd, 4.0, 4.0);
882 datad = pixGetData(pixd);
883 wpld = pixGetWpl(pixd);
884 scaleGray4xLILow(datad, wpld, datas, ws, hs, wpls);
885 return pixd;
886}
887
888
889/*------------------------------------------------------------------*
890 * Scale 2x followed by binarization *
891 *------------------------------------------------------------------*/
906PIX *
908 l_int32 thresh)
909{
910l_int32 i, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
911l_uint32 *datas, *datad, *lines, *lined, *lineb;
912PIX *pixd;
913
914 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
915 return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
916 __func__, NULL);
917 if (thresh < 0 || thresh > 256)
918 return (PIX *)ERROR_PTR("thresh must be in [0, ... 256]",
919 __func__, NULL);
920
921 pixGetDimensions(pixs, &ws, &hs, NULL);
922 wd = 2 * ws;
923 hd = 2 * hs;
924 hsm = hs - 1;
925 datas = pixGetData(pixs);
926 wpls = pixGetWpl(pixs);
927
928 /* Make line buffer for 2 lines of virtual intermediate image */
929 wplb = (wd + 3) / 4;
930 if ((lineb = (l_uint32 *)LEPT_CALLOC(2 * wplb, sizeof(l_uint32))) == NULL)
931 return (PIX *)ERROR_PTR("lineb not made", __func__, NULL);
932
933 /* Make dest binary image */
934 if ((pixd = pixCreate(wd, hd, 1)) == NULL) {
935 LEPT_FREE(lineb);
936 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
937 }
938 pixCopyInputFormat(pixd, pixs);
939 pixCopyResolution(pixd, pixs);
940 pixScaleResolution(pixd, 2.0, 2.0);
941 wpld = pixGetWpl(pixd);
942 datad = pixGetData(pixd);
943
944 /* Do all but last src line */
945 for (i = 0; i < hsm; i++) {
946 lines = datas + i * wpls;
947 lined = datad + 2 * i * wpld; /* do 2 dest lines at a time */
948 scaleGray2xLILineLow(lineb, wplb, lines, ws, wpls, 0);
949 thresholdToBinaryLineLow(lined, wd, lineb, 8, thresh);
950 thresholdToBinaryLineLow(lined + wpld, wd, lineb + wplb, 8, thresh);
951 }
952
953 /* Do last src line */
954 lines = datas + hsm * wpls;
955 lined = datad + 2 * hsm * wpld;
956 scaleGray2xLILineLow(lineb, wplb, lines, ws, wpls, 1);
957 thresholdToBinaryLineLow(lined, wd, lineb, 8, thresh);
958 thresholdToBinaryLineLow(lined + wpld, wd, lineb + wplb, 8, thresh);
959
960 LEPT_FREE(lineb);
961 return pixd;
962}
963
964
983PIX *
985{
986l_int32 i, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
987l_uint32 *datas, *datad;
988l_uint32 *lined;
989l_uint32 *lineb = NULL; /* 2 intermediate buffer lines */
990l_uint32 *linebp = NULL; /* 1 intermediate buffer line */
991l_uint32 *bufs = NULL; /* 2 source buffer lines */
992PIX *pixd = NULL;
993
994 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
995 return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
996 __func__, NULL);
997
998 pixGetDimensions(pixs, &ws, &hs, NULL);
999 wd = 2 * ws;
1000 hd = 2 * hs;
1001 hsm = hs - 1;
1002 datas = pixGetData(pixs);
1003 wpls = pixGetWpl(pixs);
1004
1005 /* Make line buffers for 2 lines of src image */
1006 if ((bufs = (l_uint32 *)LEPT_CALLOC(2 * wpls, sizeof(l_uint32))) == NULL)
1007 return (PIX *)ERROR_PTR("bufs not made", __func__, NULL);
1008
1009 /* Make line buffer for 2 lines of virtual intermediate image */
1010 wplb = (wd + 3) / 4;
1011 if ((lineb = (l_uint32 *)LEPT_CALLOC(2 * wplb, sizeof(l_uint32))) == NULL) {
1012 L_ERROR("lineb not made\n", __func__);
1013 goto cleanup;
1014 }
1015
1016 /* Make line buffer for 1 line of virtual intermediate image */
1017 if ((linebp = (l_uint32 *)LEPT_CALLOC(wplb, sizeof(l_uint32))) == NULL) {
1018 L_ERROR("linebp not made\n", __func__);
1019 goto cleanup;
1020 }
1021
1022 /* Make dest binary image */
1023 if ((pixd = pixCreate(wd, hd, 1)) == NULL) {
1024 L_ERROR("pixd not made\n", __func__);
1025 goto cleanup;
1026 }
1027 pixCopyInputFormat(pixd, pixs);
1028 pixCopyResolution(pixd, pixs);
1029 pixScaleResolution(pixd, 2.0, 2.0);
1030 wpld = pixGetWpl(pixd);
1031 datad = pixGetData(pixd);
1032
1033 /* Start with the first src and the first dest line */
1034 memcpy(bufs, datas, 4 * wpls); /* first src line */
1035 memcpy(bufs + wpls, datas + wpls, 4 * wpls); /* 2nd src line */
1036 scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 2 i lines */
1037 lined = datad;
1038 ditherToBinaryLineLow(lined, wd, lineb, lineb + wplb,
1040 /* 1st d line */
1041
1042 /* Do all but last src line */
1043 for (i = 1; i < hsm; i++) {
1044 memcpy(bufs, datas + i * wpls, 4 * wpls); /* i-th src line */
1045 memcpy(bufs + wpls, datas + (i + 1) * wpls, 4 * wpls);
1046 memcpy(linebp, lineb + wplb, 4 * wplb);
1047 scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 2 i lines */
1048 lined = datad + 2 * i * wpld;
1049 ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb,
1051 /* odd dest line */
1052 ditherToBinaryLineLow(lined, wd, lineb, lineb + wplb,
1054 /* even dest line */
1055 }
1056
1057 /* Do the last src line and the last 3 dest lines */
1058 memcpy(bufs, datas + hsm * wpls, 4 * wpls); /* hsm-th src line */
1059 memcpy(linebp, lineb + wplb, 4 * wplb); /* 1 i line */
1060 scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 1); /* 2 i lines */
1061 ditherToBinaryLineLow(lined + wpld, wd, linebp, lineb,
1063 /* odd dest line */
1064 ditherToBinaryLineLow(lined + 2 * wpld, wd, lineb, lineb + wplb,
1066 /* even dest line */
1067 ditherToBinaryLineLow(lined + 3 * wpld, wd, lineb + wplb, NULL,
1069 /* last dest line */
1070
1071cleanup:
1072 LEPT_FREE(bufs);
1073 LEPT_FREE(lineb);
1074 LEPT_FREE(linebp);
1075 return pixd;
1076}
1077
1078
1079/*------------------------------------------------------------------*
1080 * Scale 4x followed by binarization *
1081 *------------------------------------------------------------------*/
1100PIX *
1102 l_int32 thresh)
1103{
1104l_int32 i, j, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
1105l_uint32 *datas, *datad, *lines, *lined, *lineb;
1106PIX *pixd;
1107
1108 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
1109 return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
1110 __func__, NULL);
1111 if (thresh < 0 || thresh > 256)
1112 return (PIX *)ERROR_PTR("thresh must be in [0, ... 256]",
1113 __func__, NULL);
1114
1115 pixGetDimensions(pixs, &ws, &hs, NULL);
1116 wd = 4 * ws;
1117 hd = 4 * hs;
1118 hsm = hs - 1;
1119 datas = pixGetData(pixs);
1120 wpls = pixGetWpl(pixs);
1121
1122 /* Make line buffer for 4 lines of virtual intermediate image */
1123 wplb = (wd + 3) / 4;
1124 if ((lineb = (l_uint32 *)LEPT_CALLOC(4 * wplb, sizeof(l_uint32))) == NULL)
1125 return (PIX *)ERROR_PTR("lineb not made", __func__, NULL);
1126
1127 /* Make dest binary image */
1128 if ((pixd = pixCreate(wd, hd, 1)) == NULL) {
1129 LEPT_FREE(lineb);
1130 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1131 }
1132 pixCopyInputFormat(pixd, pixs);
1133 pixCopyResolution(pixd, pixs);
1134 pixScaleResolution(pixd, 4.0, 4.0);
1135 wpld = pixGetWpl(pixd);
1136 datad = pixGetData(pixd);
1137
1138 /* Do all but last src line */
1139 for (i = 0; i < hsm; i++) {
1140 lines = datas + i * wpls;
1141 lined = datad + 4 * i * wpld; /* do 4 dest lines at a time */
1142 scaleGray4xLILineLow(lineb, wplb, lines, ws, wpls, 0);
1143 for (j = 0; j < 4; j++) {
1144 thresholdToBinaryLineLow(lined + j * wpld, wd,
1145 lineb + j * wplb, 8, thresh);
1146 }
1147 }
1148
1149 /* Do last src line */
1150 lines = datas + hsm * wpls;
1151 lined = datad + 4 * hsm * wpld;
1152 scaleGray4xLILineLow(lineb, wplb, lines, ws, wpls, 1);
1153 for (j = 0; j < 4; j++) {
1154 thresholdToBinaryLineLow(lined + j * wpld, wd,
1155 lineb + j * wplb, 8, thresh);
1156 }
1157
1158 LEPT_FREE(lineb);
1159 return pixd;
1160}
1161
1162
1186PIX *
1188{
1189l_int32 i, j, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
1190l_uint32 *datas, *datad;
1191l_uint32 *lined;
1192l_uint32 *lineb = NULL; /* 4 intermediate buffer lines */
1193l_uint32 *linebp = NULL; /* 1 intermediate buffer line */
1194l_uint32 *bufs = NULL; /* 2 source buffer lines */
1195PIX *pixd = NULL;
1196
1197 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
1198 return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
1199 __func__, NULL);
1200
1201 pixGetDimensions(pixs, &ws, &hs, NULL);
1202 wd = 4 * ws;
1203 hd = 4 * hs;
1204 hsm = hs - 1;
1205 datas = pixGetData(pixs);
1206 wpls = pixGetWpl(pixs);
1207
1208 /* Make line buffers for 2 lines of src image */
1209 if ((bufs = (l_uint32 *)LEPT_CALLOC(2 * wpls, sizeof(l_uint32))) == NULL)
1210 return (PIX *)ERROR_PTR("bufs not made", __func__, NULL);
1211
1212 /* Make line buffer for 4 lines of virtual intermediate image */
1213 wplb = (wd + 3) / 4;
1214 if ((lineb = (l_uint32 *)LEPT_CALLOC(4 * wplb, sizeof(l_uint32))) == NULL) {
1215 L_ERROR("lineb not made\n", __func__);
1216 goto cleanup;
1217 }
1218
1219 /* Make line buffer for 1 line of virtual intermediate image */
1220 if ((linebp = (l_uint32 *)LEPT_CALLOC(wplb, sizeof(l_uint32))) == NULL) {
1221 L_ERROR("linebp not made\n", __func__);
1222 goto cleanup;
1223 }
1224
1225 /* Make dest binary image */
1226 if ((pixd = pixCreate(wd, hd, 1)) == NULL) {
1227 L_ERROR("pixd not made\n", __func__);
1228 goto cleanup;
1229 }
1230 pixCopyInputFormat(pixd, pixs);
1231 pixCopyResolution(pixd, pixs);
1232 pixScaleResolution(pixd, 4.0, 4.0);
1233 wpld = pixGetWpl(pixd);
1234 datad = pixGetData(pixd);
1235
1236 /* Start with the first src and the first 3 dest lines */
1237 memcpy(bufs, datas, 4 * wpls); /* first src line */
1238 memcpy(bufs + wpls, datas + wpls, 4 * wpls); /* 2nd src line */
1239 scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 4 b lines */
1240 lined = datad;
1241 for (j = 0; j < 3; j++) { /* first 3 d lines of Q */
1242 ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb,
1243 lineb + (j + 1) * wplb,
1245 }
1246
1247 /* Do all but last src line */
1248 for (i = 1; i < hsm; i++) {
1249 memcpy(bufs, datas + i * wpls, 4 * wpls); /* i-th src line */
1250 memcpy(bufs + wpls, datas + (i + 1) * wpls, 4 * wpls);
1251 memcpy(linebp, lineb + 3 * wplb, 4 * wplb);
1252 scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 4 b lines */
1253 lined = datad + 4 * i * wpld;
1254 ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb,
1256 /* 4th dest line of Q */
1257 for (j = 0; j < 3; j++) { /* next 3 d lines of Quad */
1258 ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb,
1259 lineb + (j + 1) * wplb,
1261 }
1262 }
1263
1264 /* Do the last src line and the last 5 dest lines */
1265 memcpy(bufs, datas + hsm * wpls, 4 * wpls); /* hsm-th src line */
1266 memcpy(linebp, lineb + 3 * wplb, 4 * wplb); /* 1 b line */
1267 scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 1); /* 4 b lines */
1268 lined = datad + 4 * hsm * wpld;
1269 ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb,
1271 /* 4th dest line of Q */
1272 for (j = 0; j < 3; j++) { /* next 3 d lines of Quad */
1273 ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb,
1274 lineb + (j + 1) * wplb,
1276 }
1277 /* And finally, the last dest line */
1278 ditherToBinaryLineLow(lined + 3 * wpld, wd, lineb + 3 * wplb, NULL,
1280
1281cleanup:
1282 LEPT_FREE(bufs);
1283 LEPT_FREE(lineb);
1284 LEPT_FREE(linebp);
1285 return pixd;
1286}
1287
1288
1289/*------------------------------------------------------------------*
1290 * Scaling by closest pixel sampling *
1291 *------------------------------------------------------------------*/
1316PIX *
1318 l_float32 scalex,
1319 l_float32 scaley)
1320{
1321 if (!pixs)
1322 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1323 return pixScaleBySamplingWithShift(pixs, scalex, scaley, 0.5, 0.5);
1324}
1325
1326
1344PIX *
1346 l_float32 scalex,
1347 l_float32 scaley,
1348 l_float32 shiftx,
1349 l_float32 shifty)
1350{
1351l_int32 ws, hs, d, wpls, wd, hd, wpld;
1352l_uint32 *datas, *datad;
1353PIX *pixd;
1354
1355 if (!pixs)
1356 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1357 if (scalex <= 0.0 || scaley <= 0.0)
1358 return (PIX *)ERROR_PTR("scale factor <= 0", __func__, NULL);
1359 if (scalex == 1.0 && scaley == 1.0)
1360 return pixCopy(NULL, pixs);
1361 if (shiftx != 0.0 && shiftx != 0.5)
1362 return (PIX *)ERROR_PTR("shiftx != 0.0 or 0.5", __func__, NULL);
1363 if (shifty != 0.0 && shifty != 0.5)
1364 return (PIX *)ERROR_PTR("shifty != 0.0 or 0.5", __func__, NULL);
1365 if ((d = pixGetDepth(pixs)) == 1)
1366 return pixScaleBinaryWithShift(pixs, scalex, scaley, shiftx, shifty);
1367
1368 pixGetDimensions(pixs, &ws, &hs, NULL);
1369 datas = pixGetData(pixs);
1370 wpls = pixGetWpl(pixs);
1371 wd = (l_int32)(scalex * (l_float32)ws + 0.5);
1372 hd = (l_int32)(scaley * (l_float32)hs + 0.5);
1373 if ((pixd = pixCreate(wd, hd, d)) == NULL)
1374 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1375 pixCopyResolution(pixd, pixs);
1376 pixScaleResolution(pixd, scalex, scaley);
1377 pixCopyColormap(pixd, pixs);
1378 pixCopyText(pixd, pixs);
1379 pixCopyInputFormat(pixd, pixs);
1380 pixCopySpp(pixd, pixs);
1381 datad = pixGetData(pixd);
1382 wpld = pixGetWpl(pixd);
1383 scaleBySamplingLow(datad, wd, hd, wpld, datas, ws, hs, d, wpls,
1384 shiftx, shifty);
1385 if (d == 32 && pixGetSpp(pixs) == 4)
1386 pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley);
1387
1388 return pixd;
1389}
1390
1391
1411PIX *
1413 l_int32 wd,
1414 l_int32 hd)
1415{
1416l_int32 w, h;
1417l_float32 scalex, scaley;
1418
1419 if (!pixs)
1420 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1421 if (wd <= 0 && hd <= 0)
1422 return (PIX *)ERROR_PTR("neither wd nor hd > 0", __func__, NULL);
1423
1424 pixGetDimensions(pixs, &w, &h, NULL);
1425 if (wd <= 0) {
1426 scaley = (l_float32)hd / (l_float32)h;
1427 scalex = scaley;
1428 } else if (hd <= 0) {
1429 scalex = (l_float32)wd / (l_float32)w;
1430 scaley = scalex;
1431 } else {
1432 scalex = (l_float32)wd / (l_float32)w;
1433 scaley = (l_float32)hd / (l_float32)h;
1434 }
1435
1436 return pixScaleBySampling(pixs, scalex, scaley);
1437}
1438
1439
1453PIX *
1455 l_int32 factor)
1456{
1457l_float32 scale;
1458
1459 if (!pixs)
1460 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1461 if (factor <= 1) {
1462 if (factor < 1)
1463 L_ERROR("factor must be >= 1; returning a copy\n", __func__);
1464 return pixCopy(NULL, pixs);
1465 }
1466
1467 scale = 1.f / (l_float32)factor;
1468 return pixScaleBySampling(pixs, scale, scale);
1469}
1470
1471
1472/*------------------------------------------------------------------*
1473 * Fast integer factor subsampling RGB to gray *
1474 *------------------------------------------------------------------*/
1493PIX *
1495 l_int32 factor,
1496 l_int32 color)
1497{
1498l_int32 byteval, shift;
1499l_int32 i, j, ws, hs, wd, hd, wpls, wpld;
1500l_uint32 *datas, *words, *datad, *lined;
1501l_float32 scale;
1502PIX *pixd;
1503
1504 if (!pixs)
1505 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1506 if (pixGetDepth(pixs) != 32)
1507 return (PIX *)ERROR_PTR("depth not 32 bpp", __func__, NULL);
1508 if (factor < 1)
1509 return (PIX *)ERROR_PTR("factor must be >= 1", __func__, NULL);
1510
1511 if (color == COLOR_RED)
1512 shift = L_RED_SHIFT;
1513 else if (color == COLOR_GREEN)
1514 shift = L_GREEN_SHIFT;
1515 else if (color == COLOR_BLUE)
1516 shift = L_BLUE_SHIFT;
1517 else
1518 return (PIX *)ERROR_PTR("invalid color", __func__, NULL);
1519
1520 pixGetDimensions(pixs, &ws, &hs, NULL);
1521 datas = pixGetData(pixs);
1522 wpls = pixGetWpl(pixs);
1523
1524 wd = ws / factor;
1525 hd = hs / factor;
1526 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1527 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1528 pixCopyResolution(pixd, pixs);
1529 pixCopyInputFormat(pixd, pixs);
1530 scale = 1.f / (l_float32) factor;
1531 pixScaleResolution(pixd, scale, scale);
1532 datad = pixGetData(pixd);
1533 wpld = pixGetWpl(pixd);
1534
1535 for (i = 0; i < hd; i++) {
1536 words = datas + i * factor * wpls;
1537 lined = datad + i * wpld;
1538 for (j = 0; j < wd; j++, words += factor) {
1539 byteval = ((*words) >> shift) & 0xff;
1540 SET_DATA_BYTE(lined, j, byteval);
1541 }
1542 }
1543
1544 return pixd;
1545}
1546
1547
1566PIX *
1568 l_int32 factor,
1569 l_int32 thresh)
1570{
1571l_int32 byteval;
1572l_int32 i, j, ws, hs, wd, hd, wpls, wpld;
1573l_uint32 *datas, *words, *datad, *lined;
1574l_float32 scale;
1575PIX *pixd;
1576
1577 if (!pixs)
1578 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1579 if (factor < 1)
1580 return (PIX *)ERROR_PTR("factor must be >= 1", __func__, NULL);
1581 if (pixGetDepth(pixs) != 32)
1582 return (PIX *)ERROR_PTR("depth not 32 bpp", __func__, NULL);
1583
1584 pixGetDimensions(pixs, &ws, &hs, NULL);
1585 datas = pixGetData(pixs);
1586 wpls = pixGetWpl(pixs);
1587
1588 wd = ws / factor;
1589 hd = hs / factor;
1590 if ((pixd = pixCreate(wd, hd, 1)) == NULL)
1591 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1592 pixCopyResolution(pixd, pixs);
1593 pixCopyInputFormat(pixd, pixs);
1594 scale = 1. / (l_float32) factor;
1595 pixScaleResolution(pixd, scale, scale);
1596 datad = pixGetData(pixd);
1597 wpld = pixGetWpl(pixd);
1598
1599 for (i = 0; i < hd; i++) {
1600 words = datas + i * factor * wpls;
1601 lined = datad + i * wpld;
1602 for (j = 0; j < wd; j++, words += factor) {
1603 byteval = ((*words) >> L_GREEN_SHIFT) & 0xff;
1604 if (byteval < thresh)
1605 SET_DATA_BIT(lined, j);
1606 }
1607 }
1608
1609 return pixd;
1610}
1611
1612
1630PIX *
1632 l_int32 factor,
1633 l_int32 thresh)
1634{
1635l_int32 byteval;
1636l_int32 i, j, ws, hs, wd, hd, wpls, wpld, sj;
1637l_uint32 *datas, *datad, *lines, *lined;
1638l_float32 scale;
1639PIX *pixd;
1640
1641 if (!pixs)
1642 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1643 if (factor < 1)
1644 return (PIX *)ERROR_PTR("factor must be >= 1", __func__, NULL);
1645 if (pixGetDepth(pixs) != 8)
1646 return (PIX *)ERROR_PTR("depth not 8 bpp", __func__, NULL);
1647
1648 pixGetDimensions(pixs, &ws, &hs, NULL);
1649 datas = pixGetData(pixs);
1650 wpls = pixGetWpl(pixs);
1651
1652 wd = ws / factor;
1653 hd = hs / factor;
1654 if ((pixd = pixCreate(wd, hd, 1)) == NULL)
1655 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1656 pixCopyResolution(pixd, pixs);
1657 pixCopyInputFormat(pixd, pixs);
1658 scale = 1.f / (l_float32) factor;
1659 pixScaleResolution(pixd, scale, scale);
1660 datad = pixGetData(pixd);
1661 wpld = pixGetWpl(pixd);
1662
1663 for (i = 0; i < hd; i++) {
1664 lines = datas + i * factor * wpls;
1665 lined = datad + i * wpld;
1666 for (j = 0, sj = 0; j < wd; j++, sj += factor) {
1667 byteval = GET_DATA_BYTE(lines, sj);
1668 if (byteval < thresh)
1669 SET_DATA_BIT(lined, j);
1670 }
1671 }
1672
1673 return pixd;
1674}
1675
1676
1677/*------------------------------------------------------------------*
1678 * Downscaling with (antialias) smoothing *
1679 *------------------------------------------------------------------*/
1710PIX *
1712 l_float32 scalex,
1713 l_float32 scaley)
1714{
1715l_int32 ws, hs, d, wd, hd, wpls, wpld, isize;
1716l_uint32 val;
1717l_uint32 *datas, *datad;
1718l_float32 minscale, size;
1719PIX *pixs, *pixd;
1720
1721 if (!pix)
1722 return (PIX *)ERROR_PTR("pix not defined", __func__, NULL);
1723 if (scalex >= 0.7 || scaley >= 0.7) {
1724 L_WARNING("scaling factor not < 0.7; do regular scaling\n", __func__);
1725 return pixScaleGeneral(pix, scalex, scaley, 0.0, 0);
1726 }
1727 d = pixGetDepth(pix);
1728 if (d != 2 && d != 4 && d !=8 && d != 32)
1729 return (PIX *)ERROR_PTR("pix not 2, 4, 8 or 32 bpp", __func__, NULL);
1730
1731 /* Remove colormap; clone if possible; result is either 8 or 32 bpp */
1732 if ((pixs = pixConvertTo8Or32(pix, L_CLONE, 0)) == NULL)
1733 return (PIX *)ERROR_PTR("pixs not made", __func__, NULL);
1734 d = pixGetDepth(pixs);
1735
1736 /* If 1.42 < 1/minscale < 2.5, use isize = 2
1737 * If 2.5 =< 1/minscale < 3.5, use isize = 3, etc.
1738 * Under no conditions use isize < 2 */
1739 minscale = L_MIN(scalex, scaley);
1740 size = 1.0f / minscale; /* ideal filter full width */
1741 isize = L_MIN(10000, L_MAX(2, (l_int32)(size + 0.5)));
1742
1743 pixGetDimensions(pixs, &ws, &hs, NULL);
1744 if ((ws < isize) || (hs < isize)) {
1745 pixd = pixCreate(1, 1, d);
1746 pixGetPixel(pixs, ws / 2, hs / 2, &val);
1747 pixSetPixel(pixd, 0, 0, val);
1748 L_WARNING("ridiculously small scaling factor %f\n", __func__, minscale);
1749 pixDestroy(&pixs);
1750 return pixd;
1751 }
1752
1753 datas = pixGetData(pixs);
1754 wpls = pixGetWpl(pixs);
1755 wd = L_MAX(1, (l_int32)(scalex * (l_float32)ws + 0.5));
1756 hd = L_MAX(1, (l_int32)(scaley * (l_float32)hs + 0.5));
1757 if ((pixd = pixCreate(wd, hd, d)) == NULL) {
1758 pixDestroy(&pixs);
1759 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1760 }
1761 pixCopyResolution(pixd, pixs);
1762 pixCopyInputFormat(pixd, pixs);
1763 pixScaleResolution(pixd, scalex, scaley);
1764 datad = pixGetData(pixd);
1765 wpld = pixGetWpl(pixd);
1766 scaleSmoothLow(datad, wd, hd, wpld, datas, ws, hs, d, wpls, isize);
1767 if (d == 32 && pixGetSpp(pixs) == 4)
1768 pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley);
1769
1770 pixDestroy(&pixs);
1771 return pixd;
1772}
1773
1774
1794PIX *
1796 l_int32 wd,
1797 l_int32 hd)
1798{
1799l_int32 w, h;
1800l_float32 scalex, scaley;
1801
1802 if (!pixs)
1803 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1804 if (wd <= 0 && hd <= 0)
1805 return (PIX *)ERROR_PTR("neither wd nor hd > 0", __func__, NULL);
1806
1807 pixGetDimensions(pixs, &w, &h, NULL);
1808 if (wd <= 0) {
1809 scaley = (l_float32)hd / (l_float32)h;
1810 scalex = scaley;
1811 } else if (hd <= 0) {
1812 scalex = (l_float32)wd / (l_float32)w;
1813 scaley = scalex;
1814 } else {
1815 scalex = (l_float32)wd / (l_float32)w;
1816 scaley = (l_float32)hd / (l_float32)h;
1817 }
1818
1819 return pixScaleSmooth(pixs, scalex, scaley);
1820}
1821
1822
1830PIX *
1832 l_float32 rwt,
1833 l_float32 gwt,
1834 l_float32 bwt)
1835{
1836l_int32 wd, hd, wpls, wpld;
1837l_uint32 *datas, *datad;
1838PIX *pixd;
1839
1840 if (!pixs)
1841 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1842 if (pixGetDepth(pixs) != 32)
1843 return (PIX *)ERROR_PTR("pixs not 32 bpp", __func__, NULL);
1844 if (rwt + gwt + bwt < 0.98 || rwt + gwt + bwt > 1.02)
1845 return (PIX *)ERROR_PTR("sum of wts should be 1.0", __func__, NULL);
1846
1847 wd = pixGetWidth(pixs) / 2;
1848 hd = pixGetHeight(pixs) / 2;
1849 wpls = pixGetWpl(pixs);
1850 datas = pixGetData(pixs);
1851 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1852 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1853 pixCopyResolution(pixd, pixs);
1854 pixCopyInputFormat(pixd, pixs);
1855 pixScaleResolution(pixd, 0.5, 0.5);
1856 wpld = pixGetWpl(pixd);
1857 datad = pixGetData(pixd);
1858 scaleRGBToGray2Low(datad, wd, hd, wpld, datas, wpls, rwt, gwt, bwt);
1859 return pixd;
1860}
1861
1862
1863/*------------------------------------------------------------------*
1864 * Downscaling with (antialias) area mapping *
1865 *------------------------------------------------------------------*/
1909PIX *
1911 l_float32 scalex,
1912 l_float32 scaley)
1913{
1914l_int32 ws, hs, d, wd, hd, wpls, wpld;
1915l_uint32 *datas, *datad;
1916l_float32 maxscale, minscale;
1917PIX *pixs, *pixd, *pix1, *pix2, *pix3;
1918
1919 if (!pix)
1920 return (PIX *)ERROR_PTR("pix not defined", __func__, NULL);
1921 d = pixGetDepth(pix);
1922 if (d != 2 && d != 4 && d != 8 && d != 32)
1923 return (PIX *)ERROR_PTR("pix not 2, 4, 8 or 32 bpp", __func__, NULL);
1924
1925 minscale = L_MIN(scalex, scaley);
1926 if (minscale < 0.02) { /* too small for area mapping */
1927 L_WARNING("tiny scaling factor; using pixScaleSmooth()\n", __func__);
1928 return pixScaleSmooth(pix, scalex, scaley);
1929 }
1930
1931 maxscale = L_MAX(scalex, scaley);
1932 if (maxscale >= 0.7) { /* too large for area mapping */
1933 L_WARNING("scaling factor >= 0.7; do regular scaling\n", __func__);
1934 return pixScaleGeneral(pix, scalex, scaley, 0.0, 0);
1935 }
1936
1937 /* Special cases: 2x, 4x, 8x, 16x reduction */
1938 if (scalex == 0.5 && scaley == 0.5)
1939 return pixScaleAreaMap2(pix);
1940 if (scalex == 0.25 && scaley == 0.25) {
1941 pix1 = pixScaleAreaMap2(pix);
1942 pixd = pixScaleAreaMap2(pix1);
1943 pixDestroy(&pix1);
1944 return pixd;
1945 }
1946 if (scalex == 0.125 && scaley == 0.125) {
1947 pix1 = pixScaleAreaMap2(pix);
1948 pix2 = pixScaleAreaMap2(pix1);
1949 pixd = pixScaleAreaMap2(pix2);
1950 pixDestroy(&pix1);
1951 pixDestroy(&pix2);
1952 return pixd;
1953 }
1954 if (scalex == 0.0625 && scaley == 0.0625) {
1955 pix1 = pixScaleAreaMap2(pix);
1956 pix2 = pixScaleAreaMap2(pix1);
1957 pix3 = pixScaleAreaMap2(pix2);
1958 pixd = pixScaleAreaMap2(pix3);
1959 pixDestroy(&pix1);
1960 pixDestroy(&pix2);
1961 pixDestroy(&pix3);
1962 return pixd;
1963 }
1964
1965#if 0 /* Not enabled because it breaks too many tests that rely on exact
1966 * pixel matches. */
1967 /* Special case where it is significantly faster to downscale first
1968 * by 2x, with relatively little degradation in image quality. */
1969 if (scalex > 0.35 && scalex < 0.5) {
1970 pix1 = pixScaleAreaMap2(pix);
1971 pixd = pixScaleAreaMap(pix1, 2.0 * scalex, 2.0 * scaley);
1972 pixDestroy(&pix1);
1973 return pixd;
1974 }
1975#endif
1976
1977 /* Remove colormap if necessary.
1978 * If 2 bpp or 4 bpp gray, convert to 8 bpp */
1979 if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
1980 L_WARNING("pix has colormap; removing\n", __func__);
1981 pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC);
1982 d = pixGetDepth(pixs);
1983 } else if (d == 2 || d == 4) {
1984 pixs = pixConvertTo8(pix, FALSE);
1985 d = 8;
1986 } else {
1987 pixs = pixClone(pix);
1988 }
1989
1990 pixGetDimensions(pixs, &ws, &hs, NULL);
1991 datas = pixGetData(pixs);
1992 wpls = pixGetWpl(pixs);
1993 wd = (l_int32)(scalex * (l_float32)ws + 0.5);
1994 hd = (l_int32)(scaley * (l_float32)hs + 0.5);
1995 if (wd < 1 || hd < 1) {
1996 pixDestroy(&pixs);
1997 return (PIX *)ERROR_PTR("pixd too small", __func__, NULL);
1998 }
1999 if ((pixd = pixCreate(wd, hd, d)) == NULL) {
2000 pixDestroy(&pixs);
2001 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
2002 }
2003 pixCopyInputFormat(pixd, pixs);
2004 pixCopyResolution(pixd, pixs);
2005 pixScaleResolution(pixd, scalex, scaley);
2006 datad = pixGetData(pixd);
2007 wpld = pixGetWpl(pixd);
2008 if (d == 8) {
2009 scaleGrayAreaMapLow(datad, wd, hd, wpld, datas, ws, hs, wpls);
2010 } else { /* RGB, d == 32 */
2011 scaleColorAreaMapLow(datad, wd, hd, wpld, datas, ws, hs, wpls);
2012 if (pixGetSpp(pixs) == 4)
2013 pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley);
2014 }
2015
2016 pixDestroy(&pixs);
2017 return pixd;
2018}
2019
2020
2040PIX *
2042{
2043l_int32 wd, hd, d, wpls, wpld;
2044l_uint32 *datas, *datad;
2045PIX *pixs, *pixd;
2046
2047 if (!pix)
2048 return (PIX *)ERROR_PTR("pix not defined", __func__, NULL);
2049 d = pixGetDepth(pix);
2050 if (d != 2 && d != 4 && d != 8 && d != 32)
2051 return (PIX *)ERROR_PTR("pix not 2, 4, 8 or 32 bpp", __func__, NULL);
2052
2053 /* Remove colormap if necessary.
2054 * If 2 bpp or 4 bpp gray, convert to 8 bpp */
2055 if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
2056 L_WARNING("pix has colormap; removing\n", __func__);
2057 pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC);
2058 d = pixGetDepth(pixs);
2059 } else if (d == 2 || d == 4) {
2060 pixs = pixConvertTo8(pix, FALSE);
2061 d = 8;
2062 } else {
2063 pixs = pixClone(pix);
2064 }
2065
2066 wd = pixGetWidth(pixs) / 2;
2067 hd = pixGetHeight(pixs) / 2;
2068 datas = pixGetData(pixs);
2069 wpls = pixGetWpl(pixs);
2070 pixd = pixCreate(wd, hd, d);
2071 datad = pixGetData(pixd);
2072 wpld = pixGetWpl(pixd);
2073 pixCopyInputFormat(pixd, pixs);
2074 pixCopyResolution(pixd, pixs);
2075 pixScaleResolution(pixd, 0.5, 0.5);
2076 scaleAreaMapLow2(datad, wd, hd, wpld, datas, d, wpls);
2077 if (pixGetSpp(pixs) == 4)
2078 pixScaleAndTransferAlpha(pixd, pixs, 0.5, 0.5);
2079 pixDestroy(&pixs);
2080 return pixd;
2081}
2082
2083
2103PIX *
2105 l_int32 wd,
2106 l_int32 hd)
2107{
2108l_int32 w, h;
2109l_float32 scalex, scaley;
2110
2111 if (!pixs)
2112 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2113 if (wd <= 0 && hd <= 0)
2114 return (PIX *)ERROR_PTR("neither wd nor hd > 0", __func__, NULL);
2115
2116 pixGetDimensions(pixs, &w, &h, NULL);
2117 if (wd <= 0) {
2118 scaley = (l_float32)hd / (l_float32)h;
2119 scalex = scaley;
2120 } else if (hd <= 0) {
2121 scalex = (l_float32)wd / (l_float32)w;
2122 scaley = scalex;
2123 } else {
2124 scalex = (l_float32)wd / (l_float32)w;
2125 scaley = (l_float32)hd / (l_float32)h;
2126 }
2127
2128 return pixScaleAreaMap(pixs, scalex, scaley);
2129}
2130
2131
2132/*------------------------------------------------------------------*
2133 * Binary scaling by closest pixel sampling *
2134 *------------------------------------------------------------------*/
2157PIX *
2159 l_float32 scalex,
2160 l_float32 scaley)
2161{
2162 if (!pixs)
2163 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2164 if (pixGetDepth(pixs) != 1)
2165 return (PIX *)ERROR_PTR("pixs must be 1 bpp", __func__, NULL);
2166 return pixScaleBinaryWithShift(pixs, scalex, scaley, 0.5, 0.5);
2167}
2168
2169
2187PIX *
2189 l_float32 scalex,
2190 l_float32 scaley,
2191 l_float32 shiftx,
2192 l_float32 shifty)
2193{
2194l_int32 ws, hs, wpls, wd, hd, wpld;
2195l_uint32 *datas, *datad;
2196PIX *pixd;
2197
2198 if (!pixs)
2199 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2200 if (pixGetDepth(pixs) != 1)
2201 return (PIX *)ERROR_PTR("pixs must be 1 bpp", __func__, NULL);
2202 if (scalex <= 0.0 || scaley <= 0.0)
2203 return (PIX *)ERROR_PTR("scale factor <= 0", __func__, NULL);
2204 if (scalex == 1.0 && scaley == 1.0)
2205 return pixCopy(NULL, pixs);
2206 if (shiftx != 0.0 && shiftx != 0.5)
2207 return (PIX *)ERROR_PTR("shiftx != 0.0 or 0.5", __func__, NULL);
2208 if (shifty != 0.0 && shifty != 0.5)
2209 return (PIX *)ERROR_PTR("shifty != 0.0 or 0.5", __func__, NULL);
2210
2211 pixGetDimensions(pixs, &ws, &hs, NULL);
2212 datas = pixGetData(pixs);
2213 wpls = pixGetWpl(pixs);
2214 wd = (l_int32)(scalex * (l_float32)ws + 0.5);
2215 hd = (l_int32)(scaley * (l_float32)hs + 0.5);
2216 if ((pixd = pixCreate(wd, hd, 1)) == NULL)
2217 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
2218 pixCopyColormap(pixd, pixs);
2219 pixCopyText(pixd, pixs);
2220 pixCopyInputFormat(pixd, pixs);
2221 pixCopyResolution(pixd, pixs);
2222 pixScaleResolution(pixd, scalex, scaley);
2223 datad = pixGetData(pixd);
2224 wpld = pixGetWpl(pixd);
2225 scaleBinaryLow(datad, wd, hd, wpld, datas, ws, hs, wpls, shiftx, shifty);
2226 return pixd;
2227}
2228
2229
2230/* ================================================================ *
2231 * Low level static functions *
2232 * ================================================================ */
2233
2234/*------------------------------------------------------------------*
2235 * General linear interpolated color scaling *
2236 *------------------------------------------------------------------*/
2249static void
2250scaleColorLILow(l_uint32 *datad,
2251 l_int32 wd,
2252 l_int32 hd,
2253 l_int32 wpld,
2254 l_uint32 *datas,
2255 l_int32 ws,
2256 l_int32 hs,
2257 l_int32 wpls)
2258{
2259l_int32 i, j, wm2, hm2;
2260l_int32 xpm, ypm; /* location in src image, to 1/16 of a pixel */
2261l_int32 xp, yp, xf, yf; /* src pixel and pixel fraction coordinates */
2262l_uint32 v00r, v01r, v10r, v11r, v00g, v01g, v10g, v11g;
2263l_uint32 v00b, v01b, v10b, v11b, area00, area01, area10, area11;
2264l_uint32 pixels1, pixels2, pixels3, pixels4, pixel;
2265l_uint32 *lines, *lined;
2266l_float32 scx, scy;
2267
2268 /* (scx, scy) are scaling factors that are applied to the
2269 * dest coords to get the corresponding src coords.
2270 * We need them because we iterate over dest pixels
2271 * and must find the corresponding set of src pixels. */
2272 scx = 16.f * (l_float32)ws / (l_float32)wd;
2273 scy = 16.f * (l_float32)hs / (l_float32)hd;
2274 wm2 = ws - 2;
2275 hm2 = hs - 2;
2276
2277 /* Iterate over the destination pixels */
2278 for (i = 0; i < hd; i++) {
2279 ypm = (l_int32)(scy * (l_float32)i);
2280 yp = ypm >> 4;
2281 yf = ypm & 0x0f;
2282 lined = datad + i * wpld;
2283 lines = datas + yp * wpls;
2284 for (j = 0; j < wd; j++) {
2285 xpm = (l_int32)(scx * (l_float32)j);
2286 xp = xpm >> 4;
2287 xf = xpm & 0x0f;
2288
2289 /* Do bilinear interpolation. This is a simple
2290 * generalization of the calculation in scaleGrayLILow().
2291 * Without this, we could simply subsample:
2292 * *(lined + j) = *(lines + xp);
2293 * which is faster but gives lousy results! */
2294 pixels1 = *(lines + xp);
2295
2296 if (xp > wm2 || yp > hm2) {
2297 if (yp > hm2 && xp <= wm2) { /* pixels near bottom */
2298 pixels2 = *(lines + xp + 1);
2299 pixels3 = pixels1;
2300 pixels4 = pixels2;
2301 } else if (xp > wm2 && yp <= hm2) { /* pixels near rt side */
2302 pixels2 = pixels1;
2303 pixels3 = *(lines + wpls + xp);
2304 pixels4 = pixels3;
2305 } else { /* pixels at LR corner */
2306 pixels4 = pixels3 = pixels2 = pixels1;
2307 }
2308 } else {
2309 pixels2 = *(lines + xp + 1);
2310 pixels3 = *(lines + wpls + xp);
2311 pixels4 = *(lines + wpls + xp + 1);
2312 }
2313
2314 area00 = (16 - xf) * (16 - yf);
2315 area10 = xf * (16 - yf);
2316 area01 = (16 - xf) * yf;
2317 area11 = xf * yf;
2318 v00r = area00 * ((pixels1 >> L_RED_SHIFT) & 0xff);
2319 v00g = area00 * ((pixels1 >> L_GREEN_SHIFT) & 0xff);
2320 v00b = area00 * ((pixels1 >> L_BLUE_SHIFT) & 0xff);
2321 v10r = area10 * ((pixels2 >> L_RED_SHIFT) & 0xff);
2322 v10g = area10 * ((pixels2 >> L_GREEN_SHIFT) & 0xff);
2323 v10b = area10 * ((pixels2 >> L_BLUE_SHIFT) & 0xff);
2324 v01r = area01 * ((pixels3 >> L_RED_SHIFT) & 0xff);
2325 v01g = area01 * ((pixels3 >> L_GREEN_SHIFT) & 0xff);
2326 v01b = area01 * ((pixels3 >> L_BLUE_SHIFT) & 0xff);
2327 v11r = area11 * ((pixels4 >> L_RED_SHIFT) & 0xff);
2328 v11g = area11 * ((pixels4 >> L_GREEN_SHIFT) & 0xff);
2329 v11b = area11 * ((pixels4 >> L_BLUE_SHIFT) & 0xff);
2330 pixel = (((v00r + v10r + v01r + v11r + 128) << 16) & 0xff000000) |
2331 (((v00g + v10g + v01g + v11g + 128) << 8) & 0x00ff0000) |
2332 ((v00b + v10b + v01b + v11b + 128) & 0x0000ff00);
2333 *(lined + j) = pixel;
2334 }
2335 }
2336}
2337
2338
2339/*------------------------------------------------------------------*
2340 * General linear interpolated gray scaling *
2341 *------------------------------------------------------------------*/
2354static void
2355scaleGrayLILow(l_uint32 *datad,
2356 l_int32 wd,
2357 l_int32 hd,
2358 l_int32 wpld,
2359 l_uint32 *datas,
2360 l_int32 ws,
2361 l_int32 hs,
2362 l_int32 wpls)
2363{
2364l_int32 i, j, wm2, hm2;
2365l_int32 xpm, ypm; /* location in src image, to 1/16 of a pixel */
2366l_int32 xp, yp, xf, yf; /* src pixel and pixel fraction coordinates */
2367l_int32 v00, v01, v10, v11, v00_val, v01_val, v10_val, v11_val;
2368l_uint8 val;
2369l_uint32 *lines, *lined;
2370l_float32 scx, scy;
2371
2372 /* (scx, scy) are scaling factors that are applied to the
2373 * dest coords to get the corresponding src coords.
2374 * We need them because we iterate over dest pixels
2375 * and must find the corresponding set of src pixels. */
2376 scx = 16.f * (l_float32)ws / (l_float32)wd;
2377 scy = 16.f * (l_float32)hs / (l_float32)hd;
2378 wm2 = ws - 2;
2379 hm2 = hs - 2;
2380
2381 /* Iterate over the destination pixels */
2382 for (i = 0; i < hd; i++) {
2383 ypm = (l_int32)(scy * (l_float32)i);
2384 yp = ypm >> 4;
2385 yf = ypm & 0x0f;
2386 lined = datad + i * wpld;
2387 lines = datas + yp * wpls;
2388 for (j = 0; j < wd; j++) {
2389 xpm = (l_int32)(scx * (l_float32)j);
2390 xp = xpm >> 4;
2391 xf = xpm & 0x0f;
2392
2393 /* Do bilinear interpolation. Without this, we could
2394 * simply subsample:
2395 * SET_DATA_BYTE(lined, j, GET_DATA_BYTE(lines, xp));
2396 * which is faster but gives lousy results! */
2397 v00_val = GET_DATA_BYTE(lines, xp);
2398 if (xp > wm2 || yp > hm2) {
2399 if (yp > hm2 && xp <= wm2) { /* pixels near bottom */
2400 v01_val = v00_val;
2401 v10_val = GET_DATA_BYTE(lines, xp + 1);
2402 v11_val = v10_val;
2403 } else if (xp > wm2 && yp <= hm2) { /* pixels near rt side */
2404 v01_val = GET_DATA_BYTE(lines + wpls, xp);
2405 v10_val = v00_val;
2406 v11_val = v01_val;
2407 } else { /* pixels at LR corner */
2408 v10_val = v01_val = v11_val = v00_val;
2409 }
2410 } else {
2411 v10_val = GET_DATA_BYTE(lines, xp + 1);
2412 v01_val = GET_DATA_BYTE(lines + wpls, xp);
2413 v11_val = GET_DATA_BYTE(lines + wpls, xp + 1);
2414 }
2415
2416 v00 = (16 - xf) * (16 - yf) * v00_val;
2417 v10 = xf * (16 - yf) * v10_val;
2418 v01 = (16 - xf) * yf * v01_val;
2419 v11 = xf * yf * v11_val;
2420
2421 val = (l_uint8)((v00 + v01 + v10 + v11 + 128) / 256);
2422 SET_DATA_BYTE(lined, j, val);
2423 }
2424 }
2425}
2426
2427
2428/*------------------------------------------------------------------*
2429 * 2x linear interpolated color scaling *
2430 *------------------------------------------------------------------*/
2471static void
2472scaleColor2xLILow(l_uint32 *datad,
2473 l_int32 wpld,
2474 l_uint32 *datas,
2475 l_int32 ws,
2476 l_int32 hs,
2477 l_int32 wpls)
2478{
2479l_int32 i, hsm;
2480l_uint32 *lines, *lined;
2481
2482 hsm = hs - 1;
2483
2484 /* We're taking 2 src and 2 dest lines at a time,
2485 * and for each src line, we're computing 2 dest lines.
2486 * Call these 2 dest lines: destline1 and destline2.
2487 * The first src line is used for destline 1.
2488 * On all but the last src line, both src lines are
2489 * used in the linear interpolation for destline2.
2490 * On the last src line, both destline1 and destline2
2491 * are computed using only that src line (because there
2492 * isn't a lower src line). */
2493
2494 /* iterate over all but the last src line */
2495 for (i = 0; i < hsm; i++) {
2496 lines = datas + i * wpls;
2497 lined = datad + 2 * i * wpld;
2498 scaleColor2xLILineLow(lined, wpld, lines, ws, wpls, 0);
2499 }
2500
2501 /* last src line */
2502 lines = datas + hsm * wpls;
2503 lined = datad + 2 * hsm * wpld;
2504 scaleColor2xLILineLow(lined, wpld, lines, ws, wpls, 1);
2505}
2506
2507
2519static void
2521 l_int32 wpld,
2522 l_uint32 *lines,
2523 l_int32 ws,
2524 l_int32 wpls,
2525 l_int32 lastlineflag)
2526{
2527l_int32 j, jd, wsm;
2528l_uint32 rval1, rval2, rval3, rval4, gval1, gval2, gval3, gval4;
2529l_uint32 bval1, bval2, bval3, bval4;
2530l_uint32 pixels1, pixels2, pixels3, pixels4, pixel;
2531l_uint32 *linesp, *linedp;
2532
2533 wsm = ws - 1;
2534
2535 if (lastlineflag == 0) {
2536 linesp = lines + wpls;
2537 linedp = lined + wpld;
2538 pixels1 = *lines;
2539 pixels3 = *linesp;
2540
2541 /* initialize with v(2) and v(4) */
2542 rval2 = pixels1 >> 24;
2543 gval2 = (pixels1 >> 16) & 0xff;
2544 bval2 = (pixels1 >> 8) & 0xff;
2545 rval4 = pixels3 >> 24;
2546 gval4 = (pixels3 >> 16) & 0xff;
2547 bval4 = (pixels3 >> 8) & 0xff;
2548
2549 for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
2550 /* shift in previous src values */
2551 rval1 = rval2;
2552 gval1 = gval2;
2553 bval1 = bval2;
2554 rval3 = rval4;
2555 gval3 = gval4;
2556 bval3 = bval4;
2557 /* get new src values */
2558 pixels2 = *(lines + j + 1);
2559 pixels4 = *(linesp + j + 1);
2560 rval2 = pixels2 >> 24;
2561 gval2 = (pixels2 >> 16) & 0xff;
2562 bval2 = (pixels2 >> 8) & 0xff;
2563 rval4 = pixels4 >> 24;
2564 gval4 = (pixels4 >> 16) & 0xff;
2565 bval4 = (pixels4 >> 8) & 0xff;
2566 /* save dest values */
2567 pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
2568 *(lined + jd) = pixel; /* pix 1 */
2569 pixel = ((((rval1 + rval2) << 23) & 0xff000000) |
2570 (((gval1 + gval2) << 15) & 0x00ff0000) |
2571 (((bval1 + bval2) << 7) & 0x0000ff00));
2572 *(lined + jd + 1) = pixel; /* pix 2 */
2573 pixel = ((((rval1 + rval3) << 23) & 0xff000000) |
2574 (((gval1 + gval3) << 15) & 0x00ff0000) |
2575 (((bval1 + bval3) << 7) & 0x0000ff00));
2576 *(linedp + jd) = pixel; /* pix 3 */
2577 pixel = ((((rval1 + rval2 + rval3 + rval4) << 22) & 0xff000000) |
2578 (((gval1 + gval2 + gval3 + gval4) << 14) & 0x00ff0000) |
2579 (((bval1 + bval2 + bval3 + bval4) << 6) & 0x0000ff00));
2580 *(linedp + jd + 1) = pixel; /* pix 4 */
2581 }
2582 /* last src pixel on line */
2583 rval1 = rval2;
2584 gval1 = gval2;
2585 bval1 = bval2;
2586 rval3 = rval4;
2587 gval3 = gval4;
2588 bval3 = bval4;
2589 pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
2590 *(lined + 2 * wsm) = pixel; /* pix 1 */
2591 *(lined + 2 * wsm + 1) = pixel; /* pix 2 */
2592 pixel = ((((rval1 + rval3) << 23) & 0xff000000) |
2593 (((gval1 + gval3) << 15) & 0x00ff0000) |
2594 (((bval1 + bval3) << 7) & 0x0000ff00));
2595 *(linedp + 2 * wsm) = pixel; /* pix 3 */
2596 *(linedp + 2 * wsm + 1) = pixel; /* pix 4 */
2597 } else { /* last row of src pixels: lastlineflag == 1 */
2598 linedp = lined + wpld;
2599 pixels2 = *lines;
2600 rval2 = pixels2 >> 24;
2601 gval2 = (pixels2 >> 16) & 0xff;
2602 bval2 = (pixels2 >> 8) & 0xff;
2603 for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
2604 rval1 = rval2;
2605 gval1 = gval2;
2606 bval1 = bval2;
2607 pixels2 = *(lines + j + 1);
2608 rval2 = pixels2 >> 24;
2609 gval2 = (pixels2 >> 16) & 0xff;
2610 bval2 = (pixels2 >> 8) & 0xff;
2611 pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
2612 *(lined + jd) = pixel; /* pix 1 */
2613 *(linedp + jd) = pixel; /* pix 2 */
2614 pixel = ((((rval1 + rval2) << 23) & 0xff000000) |
2615 (((gval1 + gval2) << 15) & 0x00ff0000) |
2616 (((bval1 + bval2) << 7) & 0x0000ff00));
2617 *(lined + jd + 1) = pixel; /* pix 3 */
2618 *(linedp + jd + 1) = pixel; /* pix 4 */
2619 }
2620 rval1 = rval2;
2621 gval1 = gval2;
2622 bval1 = bval2;
2623 pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
2624 *(lined + 2 * wsm) = pixel; /* pix 1 */
2625 *(lined + 2 * wsm + 1) = pixel; /* pix 2 */
2626 *(linedp + 2 * wsm) = pixel; /* pix 3 */
2627 *(linedp + 2 * wsm + 1) = pixel; /* pix 4 */
2628 }
2629}
2630
2631
2632/*------------------------------------------------------------------*
2633 * 2x linear interpolated gray scaling *
2634 *------------------------------------------------------------------*/
2673static void
2674scaleGray2xLILow(l_uint32 *datad,
2675 l_int32 wpld,
2676 l_uint32 *datas,
2677 l_int32 ws,
2678 l_int32 hs,
2679 l_int32 wpls)
2680{
2681l_int32 i, hsm;
2682l_uint32 *lines, *lined;
2683
2684 hsm = hs - 1;
2685
2686 /* We're taking 2 src and 2 dest lines at a time,
2687 * and for each src line, we're computing 2 dest lines.
2688 * Call these 2 dest lines: destline1 and destline2.
2689 * The first src line is used for destline 1.
2690 * On all but the last src line, both src lines are
2691 * used in the linear interpolation for destline2.
2692 * On the last src line, both destline1 and destline2
2693 * are computed using only that src line (because there
2694 * isn't a lower src line). */
2695
2696 /* iterate over all but the last src line */
2697 for (i = 0; i < hsm; i++) {
2698 lines = datas + i * wpls;
2699 lined = datad + 2 * i * wpld;
2700 scaleGray2xLILineLow(lined, wpld, lines, ws, wpls, 0);
2701 }
2702
2703 /* last src line */
2704 lines = datas + hsm * wpls;
2705 lined = datad + 2 * hsm * wpld;
2706 scaleGray2xLILineLow(lined, wpld, lines, ws, wpls, 1);
2707}
2708
2709
2721static void
2722scaleGray2xLILineLow(l_uint32 *lined,
2723 l_int32 wpld,
2724 l_uint32 *lines,
2725 l_int32 ws,
2726 l_int32 wpls,
2727 l_int32 lastlineflag)
2728{
2729l_int32 j, jd, wsm, w;
2730l_uint32 sval1, sval2, sval3, sval4;
2731l_uint32 *linesp, *linedp;
2732l_uint32 words, wordsp, wordd, worddp;
2733
2734 wsm = ws - 1;
2735
2736 if (lastlineflag == 0) {
2737 linesp = lines + wpls;
2738 linedp = lined + wpld;
2739
2740 /* Unroll the loop 4x and work on full words */
2741 words = lines[0];
2742 wordsp = linesp[0];
2743 sval2 = (words >> 24) & 0xff;
2744 sval4 = (wordsp >> 24) & 0xff;
2745 for (j = 0, jd = 0, w = 0; j + 3 < wsm; j += 4, jd += 8, w++) {
2746 /* At the top of the loop,
2747 * words == lines[w], wordsp == linesp[w]
2748 * and the top bytes of those have been loaded into
2749 * sval2 and sval4. */
2750 sval1 = sval2;
2751 sval2 = (words >> 16) & 0xff;
2752 sval3 = sval4;
2753 sval4 = (wordsp >> 16) & 0xff;
2754 wordd = (sval1 << 24) | (((sval1 + sval2) >> 1) << 16);
2755 worddp = (((sval1 + sval3) >> 1) << 24) |
2756 (((sval1 + sval2 + sval3 + sval4) >> 2) << 16);
2757
2758 sval1 = sval2;
2759 sval2 = (words >> 8) & 0xff;
2760 sval3 = sval4;
2761 sval4 = (wordsp >> 8) & 0xff;
2762 wordd |= (sval1 << 8) | ((sval1 + sval2) >> 1);
2763 worddp |= (((sval1 + sval3) >> 1) << 8) |
2764 ((sval1 + sval2 + sval3 + sval4) >> 2);
2765 lined[w * 2] = wordd;
2766 linedp[w * 2] = worddp;
2767
2768 sval1 = sval2;
2769 sval2 = words & 0xff;
2770 sval3 = sval4;
2771 sval4 = wordsp & 0xff;
2772 wordd = (sval1 << 24) | /* pix 1 */
2773 (((sval1 + sval2) >> 1) << 16); /* pix 2 */
2774 worddp = (((sval1 + sval3) >> 1) << 24) | /* pix 3 */
2775 (((sval1 + sval2 + sval3 + sval4) >> 2) << 16); /* pix 4 */
2776
2777 /* Load the next word as we need its first byte */
2778 words = lines[w + 1];
2779 wordsp = linesp[w + 1];
2780 sval1 = sval2;
2781 sval2 = (words >> 24) & 0xff;
2782 sval3 = sval4;
2783 sval4 = (wordsp >> 24) & 0xff;
2784 wordd |= (sval1 << 8) | /* pix 1 */
2785 ((sval1 + sval2) >> 1); /* pix 2 */
2786 worddp |= (((sval1 + sval3) >> 1) << 8) | /* pix 3 */
2787 ((sval1 + sval2 + sval3 + sval4) >> 2); /* pix 4 */
2788 lined[w * 2 + 1] = wordd;
2789 linedp[w * 2 + 1] = worddp;
2790 }
2791
2792 /* Finish up the last word */
2793 for (; j < wsm; j++, jd += 2) {
2794 sval1 = sval2;
2795 sval3 = sval4;
2796 sval2 = GET_DATA_BYTE(lines, j + 1);
2797 sval4 = GET_DATA_BYTE(linesp, j + 1);
2798 SET_DATA_BYTE(lined, jd, sval1); /* pix 1 */
2799 SET_DATA_BYTE(lined, jd + 1, (sval1 + sval2) / 2); /* pix 2 */
2800 SET_DATA_BYTE(linedp, jd, (sval1 + sval3) / 2); /* pix 3 */
2801 SET_DATA_BYTE(linedp, jd + 1,
2802 (sval1 + sval2 + sval3 + sval4) / 4); /* pix 4 */
2803 }
2804 sval1 = sval2;
2805 sval3 = sval4;
2806 SET_DATA_BYTE(lined, 2 * wsm, sval1); /* pix 1 */
2807 SET_DATA_BYTE(lined, 2 * wsm + 1, sval1); /* pix 2 */
2808 SET_DATA_BYTE(linedp, 2 * wsm, (sval1 + sval3) / 2); /* pix 3 */
2809 SET_DATA_BYTE(linedp, 2 * wsm + 1, (sval1 + sval3) / 2); /* pix 4 */
2810
2811#if DEBUG_UNROLLING
2812#define CHECK_BYTE(a, b, c) if (GET_DATA_BYTE(a, b) != c) {\
2813 lept_stderr("Error: mismatch at %d, %d vs %d\n", \
2814 j, GET_DATA_BYTE(a, b), c); }
2815
2816 sval2 = GET_DATA_BYTE(lines, 0);
2817 sval4 = GET_DATA_BYTE(linesp, 0);
2818 for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
2819 sval1 = sval2;
2820 sval3 = sval4;
2821 sval2 = GET_DATA_BYTE(lines, j + 1);
2822 sval4 = GET_DATA_BYTE(linesp, j + 1);
2823 CHECK_BYTE(lined, jd, sval1); /* pix 1 */
2824 CHECK_BYTE(lined, jd + 1, (sval1 + sval2) / 2); /* pix 2 */
2825 CHECK_BYTE(linedp, jd, (sval1 + sval3) / 2); /* pix 3 */
2826 CHECK_BYTE(linedp, jd + 1,
2827 (sval1 + sval2 + sval3 + sval4) / 4); /* pix 4 */
2828 }
2829 sval1 = sval2;
2830 sval3 = sval4;
2831 CHECK_BYTE(lined, 2 * wsm, sval1); /* pix 1 */
2832 CHECK_BYTE(lined, 2 * wsm + 1, sval1); /* pix 2 */
2833 CHECK_BYTE(linedp, 2 * wsm, (sval1 + sval3) / 2); /* pix 3 */
2834 CHECK_BYTE(linedp, 2 * wsm + 1, (sval1 + sval3) / 2); /* pix 4 */
2835#undef CHECK_BYTE
2836#endif
2837 } else { /* last row of src pixels: lastlineflag == 1 */
2838 linedp = lined + wpld;
2839 sval2 = GET_DATA_BYTE(lines, 0);
2840 for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
2841 sval1 = sval2;
2842 sval2 = GET_DATA_BYTE(lines, j + 1);
2843 SET_DATA_BYTE(lined, jd, sval1); /* pix 1 */
2844 SET_DATA_BYTE(linedp, jd, sval1); /* pix 3 */
2845 SET_DATA_BYTE(lined, jd + 1, (sval1 + sval2) / 2); /* pix 2 */
2846 SET_DATA_BYTE(linedp, jd + 1, (sval1 + sval2) / 2); /* pix 4 */
2847 }
2848 sval1 = sval2;
2849 SET_DATA_BYTE(lined, 2 * wsm, sval1); /* pix 1 */
2850 SET_DATA_BYTE(lined, 2 * wsm + 1, sval1); /* pix 2 */
2851 SET_DATA_BYTE(linedp, 2 * wsm, sval1); /* pix 3 */
2852 SET_DATA_BYTE(linedp, 2 * wsm + 1, sval1); /* pix 4 */
2853 }
2854}
2855
2856
2857/*------------------------------------------------------------------*
2858 * 4x linear interpolated gray scaling *
2859 *------------------------------------------------------------------*/
2914static void
2915scaleGray4xLILow(l_uint32 *datad,
2916 l_int32 wpld,
2917 l_uint32 *datas,
2918 l_int32 ws,
2919 l_int32 hs,
2920 l_int32 wpls)
2921{
2922l_int32 i, hsm;
2923l_uint32 *lines, *lined;
2924
2925 hsm = hs - 1;
2926
2927 /* We're taking 2 src and 4 dest lines at a time,
2928 * and for each src line, we're computing 4 dest lines.
2929 * Call these 4 dest lines: destline1 - destline4.
2930 * The first src line is used for destline 1.
2931 * Two src lines are used for all other dest lines,
2932 * except for the last 4 dest lines, which are computed
2933 * using only the last src line. */
2934
2935 /* iterate over all but the last src line */
2936 for (i = 0; i < hsm; i++) {
2937 lines = datas + i * wpls;
2938 lined = datad + 4 * i * wpld;
2939 scaleGray4xLILineLow(lined, wpld, lines, ws, wpls, 0);
2940 }
2941
2942 /* last src line */
2943 lines = datas + hsm * wpls;
2944 lined = datad + 4 * hsm * wpld;
2945 scaleGray4xLILineLow(lined, wpld, lines, ws, wpls, 1);
2946}
2947
2948
2960static void
2961scaleGray4xLILineLow(l_uint32 *lined,
2962 l_int32 wpld,
2963 l_uint32 *lines,
2964 l_int32 ws,
2965 l_int32 wpls,
2966 l_int32 lastlineflag)
2967{
2968l_int32 j, jd, wsm, wsm4;
2969l_int32 s1, s2, s3, s4, s1t, s2t, s3t, s4t;
2970l_uint32 *linesp, *linedp1, *linedp2, *linedp3;
2971
2972 wsm = ws - 1;
2973 wsm4 = 4 * wsm;
2974
2975 if (lastlineflag == 0) {
2976 linesp = lines + wpls;
2977 linedp1 = lined + wpld;
2978 linedp2 = lined + 2 * wpld;
2979 linedp3 = lined + 3 * wpld;
2980 s2 = GET_DATA_BYTE(lines, 0);
2981 s4 = GET_DATA_BYTE(linesp, 0);
2982 for (j = 0, jd = 0; j < wsm; j++, jd += 4) {
2983 s1 = s2;
2984 s3 = s4;
2985 s2 = GET_DATA_BYTE(lines, j + 1);
2986 s4 = GET_DATA_BYTE(linesp, j + 1);
2987 s1t = 3 * s1;
2988 s2t = 3 * s2;
2989 s3t = 3 * s3;
2990 s4t = 3 * s4;
2991 SET_DATA_BYTE(lined, jd, s1); /* d1 */
2992 SET_DATA_BYTE(lined, jd + 1, (s1t + s2) / 4); /* d2 */
2993 SET_DATA_BYTE(lined, jd + 2, (s1 + s2) / 2); /* d3 */
2994 SET_DATA_BYTE(lined, jd + 3, (s1 + s2t) / 4); /* d4 */
2995 SET_DATA_BYTE(linedp1, jd, (s1t + s3) / 4); /* d5 */
2996 SET_DATA_BYTE(linedp1, jd + 1, (9*s1 + s2t + s3t + s4) / 16); /*d6*/
2997 SET_DATA_BYTE(linedp1, jd + 2, (s1t + s2t + s3 + s4) / 8); /* d7 */
2998 SET_DATA_BYTE(linedp1, jd + 3, (s1t + 9*s2 + s3 + s4t) / 16);/*d8*/
2999 SET_DATA_BYTE(linedp2, jd, (s1 + s3) / 2); /* d9 */
3000 SET_DATA_BYTE(linedp2, jd + 1, (s1t + s2 + s3t + s4) / 8);/* d10 */
3001 SET_DATA_BYTE(linedp2, jd + 2, (s1 + s2 + s3 + s4) / 4); /* d11 */
3002 SET_DATA_BYTE(linedp2, jd + 3, (s1 + s2t + s3 + s4t) / 8);/* d12 */
3003 SET_DATA_BYTE(linedp3, jd, (s1 + s3t) / 4); /* d13 */
3004 SET_DATA_BYTE(linedp3, jd + 1, (s1t + s2 + 9*s3 + s4t) / 16);/*d14*/
3005 SET_DATA_BYTE(linedp3, jd + 2, (s1 + s2 + s3t + s4t) / 8); /* d15 */
3006 SET_DATA_BYTE(linedp3, jd + 3, (s1 + s2t + s3t + 9*s4) / 16);/*d16*/
3007 }
3008 s1 = s2;
3009 s3 = s4;
3010 s1t = 3 * s1;
3011 s3t = 3 * s3;
3012 SET_DATA_BYTE(lined, wsm4, s1); /* d1 */
3013 SET_DATA_BYTE(lined, wsm4 + 1, s1); /* d2 */
3014 SET_DATA_BYTE(lined, wsm4 + 2, s1); /* d3 */
3015 SET_DATA_BYTE(lined, wsm4 + 3, s1); /* d4 */
3016 SET_DATA_BYTE(linedp1, wsm4, (s1t + s3) / 4); /* d5 */
3017 SET_DATA_BYTE(linedp1, wsm4 + 1, (s1t + s3) / 4); /* d6 */
3018 SET_DATA_BYTE(linedp1, wsm4 + 2, (s1t + s3) / 4); /* d7 */
3019 SET_DATA_BYTE(linedp1, wsm4 + 3, (s1t + s3) / 4); /* d8 */
3020 SET_DATA_BYTE(linedp2, wsm4, (s1 + s3) / 2); /* d9 */
3021 SET_DATA_BYTE(linedp2, wsm4 + 1, (s1 + s3) / 2); /* d10 */
3022 SET_DATA_BYTE(linedp2, wsm4 + 2, (s1 + s3) / 2); /* d11 */
3023 SET_DATA_BYTE(linedp2, wsm4 + 3, (s1 + s3) / 2); /* d12 */
3024 SET_DATA_BYTE(linedp3, wsm4, (s1 + s3t) / 4); /* d13 */
3025 SET_DATA_BYTE(linedp3, wsm4 + 1, (s1 + s3t) / 4); /* d14 */
3026 SET_DATA_BYTE(linedp3, wsm4 + 2, (s1 + s3t) / 4); /* d15 */
3027 SET_DATA_BYTE(linedp3, wsm4 + 3, (s1 + s3t) / 4); /* d16 */
3028 } else { /* last row of src pixels: lastlineflag == 1 */
3029 linedp1 = lined + wpld;
3030 linedp2 = lined + 2 * wpld;
3031 linedp3 = lined + 3 * wpld;
3032 s2 = GET_DATA_BYTE(lines, 0);
3033 for (j = 0, jd = 0; j < wsm; j++, jd += 4) {
3034 s1 = s2;
3035 s2 = GET_DATA_BYTE(lines, j + 1);
3036 s1t = 3 * s1;
3037 s2t = 3 * s2;
3038 SET_DATA_BYTE(lined, jd, s1); /* d1 */
3039 SET_DATA_BYTE(lined, jd + 1, (s1t + s2) / 4 ); /* d2 */
3040 SET_DATA_BYTE(lined, jd + 2, (s1 + s2) / 2 ); /* d3 */
3041 SET_DATA_BYTE(lined, jd + 3, (s1 + s2t) / 4 ); /* d4 */
3042 SET_DATA_BYTE(linedp1, jd, s1); /* d5 */
3043 SET_DATA_BYTE(linedp1, jd + 1, (s1t + s2) / 4 ); /* d6 */
3044 SET_DATA_BYTE(linedp1, jd + 2, (s1 + s2) / 2 ); /* d7 */
3045 SET_DATA_BYTE(linedp1, jd + 3, (s1 + s2t) / 4 ); /* d8 */
3046 SET_DATA_BYTE(linedp2, jd, s1); /* d9 */
3047 SET_DATA_BYTE(linedp2, jd + 1, (s1t + s2) / 4 ); /* d10 */
3048 SET_DATA_BYTE(linedp2, jd + 2, (s1 + s2) / 2 ); /* d11 */
3049 SET_DATA_BYTE(linedp2, jd + 3, (s1 + s2t) / 4 ); /* d12 */
3050 SET_DATA_BYTE(linedp3, jd, s1); /* d13 */
3051 SET_DATA_BYTE(linedp3, jd + 1, (s1t + s2) / 4 ); /* d14 */
3052 SET_DATA_BYTE(linedp3, jd + 2, (s1 + s2) / 2 ); /* d15 */
3053 SET_DATA_BYTE(linedp3, jd + 3, (s1 + s2t) / 4 ); /* d16 */
3054 }
3055 s1 = s2;
3056 SET_DATA_BYTE(lined, wsm4, s1); /* d1 */
3057 SET_DATA_BYTE(lined, wsm4 + 1, s1); /* d2 */
3058 SET_DATA_BYTE(lined, wsm4 + 2, s1); /* d3 */
3059 SET_DATA_BYTE(lined, wsm4 + 3, s1); /* d4 */
3060 SET_DATA_BYTE(linedp1, wsm4, s1); /* d5 */
3061 SET_DATA_BYTE(linedp1, wsm4 + 1, s1); /* d6 */
3062 SET_DATA_BYTE(linedp1, wsm4 + 2, s1); /* d7 */
3063 SET_DATA_BYTE(linedp1, wsm4 + 3, s1); /* d8 */
3064 SET_DATA_BYTE(linedp2, wsm4, s1); /* d9 */
3065 SET_DATA_BYTE(linedp2, wsm4 + 1, s1); /* d10 */
3066 SET_DATA_BYTE(linedp2, wsm4 + 2, s1); /* d11 */
3067 SET_DATA_BYTE(linedp2, wsm4 + 3, s1); /* d12 */
3068 SET_DATA_BYTE(linedp3, wsm4, s1); /* d13 */
3069 SET_DATA_BYTE(linedp3, wsm4 + 1, s1); /* d14 */
3070 SET_DATA_BYTE(linedp3, wsm4 + 2, s1); /* d15 */
3071 SET_DATA_BYTE(linedp3, wsm4 + 3, s1); /* d16 */
3072 }
3073}
3074
3075
3076/*------------------------------------------------------------------*
3077 * Grayscale and color scaling by closest pixel sampling *
3078 *------------------------------------------------------------------*/
3094static l_int32
3095scaleBySamplingLow(l_uint32 *datad,
3096 l_int32 wd,
3097 l_int32 hd,
3098 l_int32 wpld,
3099 l_uint32 *datas,
3100 l_int32 ws,
3101 l_int32 hs,
3102 l_int32 d,
3103 l_int32 wpls,
3104 l_float32 shiftx,
3105 l_float32 shifty)
3106{
3107l_int32 i, j;
3108l_int32 xs, prevxs, sval;
3109l_int32 *srow, *scol;
3110l_uint32 csval;
3111l_uint32 *lines, *prevlines, *lined, *prevlined;
3112l_float32 wratio, hratio;
3113
3114 if (d != 2 && d != 4 && d !=8 && d != 16 && d != 32)
3115 return ERROR_INT("pixel depth not supported", __func__, 1);
3116
3117 /* Clear dest */
3118 memset(datad, 0, 4LL * hd * wpld);
3119
3120 /* the source row corresponding to dest row i ==> srow[i]
3121 * the source col corresponding to dest col j ==> scol[j] */
3122 if ((srow = (l_int32 *)LEPT_CALLOC(hd, sizeof(l_int32))) == NULL)
3123 return ERROR_INT("srow not made", __func__, 1);
3124 if ((scol = (l_int32 *)LEPT_CALLOC(wd, sizeof(l_int32))) == NULL) {
3125 LEPT_FREE(srow);
3126 return ERROR_INT("scol not made", __func__, 1);
3127 }
3128
3129 wratio = (l_float32)ws / (l_float32)wd;
3130 hratio = (l_float32)hs / (l_float32)hd;
3131 for (i = 0; i < hd; i++)
3132 srow[i] = L_MIN((l_int32)(hratio * i + shifty), hs - 1);
3133 for (j = 0; j < wd; j++)
3134 scol[j] = L_MIN((l_int32)(wratio * j + shiftx), ws - 1);
3135
3136 prevlines = NULL;
3137 for (i = 0; i < hd; i++) {
3138 lines = datas + srow[i] * wpls;
3139 lined = datad + i * wpld;
3140 if (lines != prevlines) { /* make dest from new source row */
3141 prevxs = -1;
3142 sval = 0;
3143 csval = 0;
3144 if (d == 2) {
3145 for (j = 0; j < wd; j++) {
3146 xs = scol[j];
3147 if (xs != prevxs) { /* get dest pix from source col */
3148 sval = GET_DATA_DIBIT(lines, xs);
3149 SET_DATA_DIBIT(lined, j, sval);
3150 prevxs = xs;
3151 } else { /* copy prev dest pix */
3152 SET_DATA_DIBIT(lined, j, sval);
3153 }
3154 }
3155 } else if (d == 4) {
3156 for (j = 0; j < wd; j++) {
3157 xs = scol[j];
3158 if (xs != prevxs) { /* get dest pix from source col */
3159 sval = GET_DATA_QBIT(lines, xs);
3160 SET_DATA_QBIT(lined, j, sval);
3161 prevxs = xs;
3162 } else { /* copy prev dest pix */
3163 SET_DATA_QBIT(lined, j, sval);
3164 }
3165 }
3166 } else if (d == 8) {
3167 for (j = 0; j < wd; j++) {
3168 xs = scol[j];
3169 if (xs != prevxs) { /* get dest pix from source col */
3170 sval = GET_DATA_BYTE(lines, xs);
3171 SET_DATA_BYTE(lined, j, sval);
3172 prevxs = xs;
3173 } else { /* copy prev dest pix */
3174 SET_DATA_BYTE(lined, j, sval);
3175 }
3176 }
3177 } else if (d == 16) {
3178 for (j = 0; j < wd; j++) {
3179 xs = scol[j];
3180 if (xs != prevxs) { /* get dest pix from source col */
3181 sval = GET_DATA_TWO_BYTES(lines, xs);
3182 SET_DATA_TWO_BYTES(lined, j, sval);
3183 prevxs = xs;
3184 } else { /* copy prev dest pix */
3185 SET_DATA_TWO_BYTES(lined, j, sval);
3186 }
3187 }
3188 } else { /* d == 32 */
3189 for (j = 0; j < wd; j++) {
3190 xs = scol[j];
3191 if (xs != prevxs) { /* get dest pix from source col */
3192 csval = lines[xs];
3193 lined[j] = csval;
3194 prevxs = xs;
3195 } else { /* copy prev dest pix */
3196 lined[j] = csval;
3197 }
3198 }
3199 }
3200 } else { /* lines == prevlines; copy prev dest row */
3201 prevlined = lined - wpld;
3202 memcpy(lined, prevlined, 4 * wpld);
3203 }
3204 prevlines = lines;
3205 }
3206
3207 LEPT_FREE(srow);
3208 LEPT_FREE(scol);
3209 return 0;
3210}
3211
3212
3213/*------------------------------------------------------------------*
3214 * Color and grayscale downsampling with (antialias) smoothing *
3215 *------------------------------------------------------------------*/
3227static l_int32
3228scaleSmoothLow(l_uint32 *datad,
3229 l_int32 wd,
3230 l_int32 hd,
3231 l_int32 wpld,
3232 l_uint32 *datas,
3233 l_int32 ws,
3234 l_int32 hs,
3235 l_int32 d,
3236 l_int32 wpls,
3237 l_int32 size)
3238{
3239l_int32 i, j, m, n, xstart;
3240l_int32 val, rval, gval, bval;
3241l_int32 *srow, *scol;
3242l_uint32 *lines, *lined, *line, *ppixel;
3243l_uint32 pixel;
3244l_float32 wratio, hratio, norm;
3245
3246 /* Clear dest */
3247 memset(datad, 0, 4LL * wpld * hd);
3248
3249 /* Each dest pixel at (j,i) is computed as the average
3250 of size^2 corresponding src pixels.
3251 We store the UL corner location of the square of
3252 src pixels that correspond to dest pixel (j,i).
3253 The are labeled by the arrays srow[i] and scol[j]. */
3254 if ((srow = (l_int32 *)LEPT_CALLOC(hd, sizeof(l_int32))) == NULL)
3255 return ERROR_INT("srow not made", __func__, 1);
3256 if ((scol = (l_int32 *)LEPT_CALLOC(wd, sizeof(l_int32))) == NULL) {
3257 LEPT_FREE(srow);
3258 return ERROR_INT("scol not made", __func__, 1);
3259 }
3260
3261 norm = 1.f / (l_float32)(size * size);
3262 wratio = (l_float32)ws / (l_float32)wd;
3263 hratio = (l_float32)hs / (l_float32)hd;
3264 for (i = 0; i < hd; i++)
3265 srow[i] = L_MIN((l_int32)(hratio * i), hs - size);
3266 for (j = 0; j < wd; j++)
3267 scol[j] = L_MIN((l_int32)(wratio * j), ws - size);
3268
3269 /* For each dest pixel, compute average */
3270 if (d == 8) {
3271 for (i = 0; i < hd; i++) {
3272 lines = datas + srow[i] * wpls;
3273 lined = datad + i * wpld;
3274 for (j = 0; j < wd; j++) {
3275 xstart = scol[j];
3276 val = 0;
3277 for (m = 0; m < size; m++) {
3278 line = lines + m * wpls;
3279 for (n = 0; n < size; n++) {
3280 val += GET_DATA_BYTE(line, xstart + n);
3281 }
3282 }
3283 val = (l_int32)((l_float32)val * norm);
3284 SET_DATA_BYTE(lined, j, val);
3285 }
3286 }
3287 } else { /* d == 32 */
3288 for (i = 0; i < hd; i++) {
3289 lines = datas + srow[i] * wpls;
3290 lined = datad + i * wpld;
3291 for (j = 0; j < wd; j++) {
3292 xstart = scol[j];
3293 rval = gval = bval = 0;
3294 for (m = 0; m < size; m++) {
3295 ppixel = lines + m * wpls + xstart;
3296 for (n = 0; n < size; n++) {
3297 pixel = *(ppixel + n);
3298 rval += (pixel >> L_RED_SHIFT) & 0xff;
3299 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3300 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3301 }
3302 }
3303 rval = (l_int32)((l_float32)rval * norm);
3304 gval = (l_int32)((l_float32)gval * norm);
3305 bval = (l_int32)((l_float32)bval * norm);
3306 composeRGBPixel(rval, gval, bval, lined + j);
3307 }
3308 }
3309 }
3310
3311 LEPT_FREE(srow);
3312 LEPT_FREE(scol);
3313 return 0;
3314}
3315
3316
3326static void
3327scaleRGBToGray2Low(l_uint32 *datad,
3328 l_int32 wd,
3329 l_int32 hd,
3330 l_int32 wpld,
3331 l_uint32 *datas,
3332 l_int32 wpls,
3333 l_float32 rwt,
3334 l_float32 gwt,
3335 l_float32 bwt)
3336{
3337l_int32 i, j, val, rval, gval, bval;
3338l_uint32 *lines, *lined;
3339l_uint32 pixel;
3340
3341 rwt *= 0.25;
3342 gwt *= 0.25;
3343 bwt *= 0.25;
3344 for (i = 0; i < hd; i++) {
3345 lines = datas + 2 * i * wpls;
3346 lined = datad + i * wpld;
3347 for (j = 0; j < wd; j++) {
3348 /* Sum each of the color components from 4 src pixels */
3349 pixel = *(lines + 2 * j);
3350 rval = (pixel >> L_RED_SHIFT) & 0xff;
3351 gval = (pixel >> L_GREEN_SHIFT) & 0xff;
3352 bval = (pixel >> L_BLUE_SHIFT) & 0xff;
3353 pixel = *(lines + 2 * j + 1);
3354 rval += (pixel >> L_RED_SHIFT) & 0xff;
3355 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3356 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3357 pixel = *(lines + wpls + 2 * j);
3358 rval += (pixel >> L_RED_SHIFT) & 0xff;
3359 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3360 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3361 pixel = *(lines + wpls + 2 * j + 1);
3362 rval += (pixel >> L_RED_SHIFT) & 0xff;
3363 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3364 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3365 /* Generate the dest byte as a weighted sum of the averages */
3366 val = (l_int32)(rwt * rval + gwt * gval + bwt * bval);
3367 SET_DATA_BYTE(lined, j, val);
3368 }
3369 }
3370}
3371
3372
3373/*------------------------------------------------------------------*
3374 * General area mapped gray scaling *
3375 *------------------------------------------------------------------*/
3391static void
3392scaleColorAreaMapLow(l_uint32 *datad,
3393 l_int32 wd,
3394 l_int32 hd,
3395 l_int32 wpld,
3396 l_uint32 *datas,
3397 l_int32 ws,
3398 l_int32 hs,
3399 l_int32 wpls)
3400{
3401l_int32 i, j, k, m, wm2, hm2;
3402l_int32 area00, area10, area01, area11, areal, arear, areat, areab;
3403l_int32 xu, yu; /* UL corner in src image, to 1/16 of a pixel */
3404l_int32 xl, yl; /* LR corner in src image, to 1/16 of a pixel */
3405l_int32 xup, yup, xuf, yuf; /* UL src pixel: integer and fraction */
3406l_int32 xlp, ylp, xlf, ylf; /* LR src pixel: integer and fraction */
3407l_int32 delx, dely, area;
3408l_int32 v00r, v00g, v00b; /* contrib. from UL src pixel */
3409l_int32 v01r, v01g, v01b; /* contrib. from LL src pixel */
3410l_int32 v10r, v10g, v10b; /* contrib from UR src pixel */
3411l_int32 v11r, v11g, v11b; /* contrib from LR src pixel */
3412l_int32 vinr, ving, vinb; /* contrib from all full interior src pixels */
3413l_int32 vmidr, vmidg, vmidb; /* contrib from side parts */
3414l_int32 rval, gval, bval;
3415l_uint32 pixel00, pixel10, pixel01, pixel11, pixel;
3416l_uint32 *lines, *lined;
3417l_float32 scx, scy;
3418
3419 /* (scx, scy) are scaling factors that are applied to the
3420 * dest coords to get the corresponding src coords.
3421 * We need them because we iterate over dest pixels
3422 * and must find the corresponding set of src pixels. */
3423 scx = 16.f * (l_float32)ws / (l_float32)wd;
3424 scy = 16.f * (l_float32)hs / (l_float32)hd;
3425 wm2 = ws - 2;
3426 hm2 = hs - 2;
3427
3428 /* Iterate over the destination pixels */
3429 for (i = 0; i < hd; i++) {
3430 yu = (l_int32)(scy * i);
3431 yl = (l_int32)(scy * (i + 1.0));
3432 yup = yu >> 4;
3433 yuf = yu & 0x0f;
3434 ylp = yl >> 4;
3435 ylf = yl & 0x0f;
3436 dely = ylp - yup;
3437 lined = datad + i * wpld;
3438 lines = datas + yup * wpls;
3439 for (j = 0; j < wd; j++) {
3440 xu = (l_int32)(scx * j);
3441 xl = (l_int32)(scx * (j + 1.0));
3442 xup = xu >> 4;
3443 xuf = xu & 0x0f;
3444 xlp = xl >> 4;
3445 xlf = xl & 0x0f;
3446 delx = xlp - xup;
3447
3448 /* If near the edge, just use a src pixel value */
3449 if (xlp > wm2 || ylp > hm2) {
3450 *(lined + j) = *(lines + xup);
3451 continue;
3452 }
3453
3454 /* Area summed over, in subpixels. This varies
3455 * due to the quantization, so we can't simply take
3456 * the area to be a constant: area = scx * scy. */
3457 area = ((16 - xuf) + 16 * (delx - 1) + xlf) *
3458 ((16 - yuf) + 16 * (dely - 1) + ylf);
3459
3460 /* Do area map summation */
3461 pixel00 = *(lines + xup);
3462 pixel10 = *(lines + xlp);
3463 pixel01 = *(lines + dely * wpls + xup);
3464 pixel11 = *(lines + dely * wpls + xlp);
3465 area00 = (16 - xuf) * (16 - yuf);
3466 area10 = xlf * (16 - yuf);
3467 area01 = (16 - xuf) * ylf;
3468 area11 = xlf * ylf;
3469 v00r = area00 * ((pixel00 >> L_RED_SHIFT) & 0xff);
3470 v00g = area00 * ((pixel00 >> L_GREEN_SHIFT) & 0xff);
3471 v00b = area00 * ((pixel00 >> L_BLUE_SHIFT) & 0xff);
3472 v10r = area10 * ((pixel10 >> L_RED_SHIFT) & 0xff);
3473 v10g = area10 * ((pixel10 >> L_GREEN_SHIFT) & 0xff);
3474 v10b = area10 * ((pixel10 >> L_BLUE_SHIFT) & 0xff);
3475 v01r = area01 * ((pixel01 >> L_RED_SHIFT) & 0xff);
3476 v01g = area01 * ((pixel01 >> L_GREEN_SHIFT) & 0xff);
3477 v01b = area01 * ((pixel01 >> L_BLUE_SHIFT) & 0xff);
3478 v11r = area11 * ((pixel11 >> L_RED_SHIFT) & 0xff);
3479 v11g = area11 * ((pixel11 >> L_GREEN_SHIFT) & 0xff);
3480 v11b = area11 * ((pixel11 >> L_BLUE_SHIFT) & 0xff);
3481 vinr = ving = vinb = 0;
3482 for (k = 1; k < dely; k++) { /* for full src pixels */
3483 for (m = 1; m < delx; m++) {
3484 pixel = *(lines + k * wpls + xup + m);
3485 vinr += 256 * ((pixel >> L_RED_SHIFT) & 0xff);
3486 ving += 256 * ((pixel >> L_GREEN_SHIFT) & 0xff);
3487 vinb += 256 * ((pixel >> L_BLUE_SHIFT) & 0xff);
3488 }
3489 }
3490 vmidr = vmidg = vmidb = 0;
3491 areal = (16 - xuf) * 16;
3492 arear = xlf * 16;
3493 areat = 16 * (16 - yuf);
3494 areab = 16 * ylf;
3495 for (k = 1; k < dely; k++) { /* for left side */
3496 pixel = *(lines + k * wpls + xup);
3497 vmidr += areal * ((pixel >> L_RED_SHIFT) & 0xff);
3498 vmidg += areal * ((pixel >> L_GREEN_SHIFT) & 0xff);
3499 vmidb += areal * ((pixel >> L_BLUE_SHIFT) & 0xff);
3500 }
3501 for (k = 1; k < dely; k++) { /* for right side */
3502 pixel = *(lines + k * wpls + xlp);
3503 vmidr += arear * ((pixel >> L_RED_SHIFT) & 0xff);
3504 vmidg += arear * ((pixel >> L_GREEN_SHIFT) & 0xff);
3505 vmidb += arear * ((pixel >> L_BLUE_SHIFT) & 0xff);
3506 }
3507 for (m = 1; m < delx; m++) { /* for top side */
3508 pixel = *(lines + xup + m);
3509 vmidr += areat * ((pixel >> L_RED_SHIFT) & 0xff);
3510 vmidg += areat * ((pixel >> L_GREEN_SHIFT) & 0xff);
3511 vmidb += areat * ((pixel >> L_BLUE_SHIFT) & 0xff);
3512 }
3513 for (m = 1; m < delx; m++) { /* for bottom side */
3514 pixel = *(lines + dely * wpls + xup + m);
3515 vmidr += areab * ((pixel >> L_RED_SHIFT) & 0xff);
3516 vmidg += areab * ((pixel >> L_GREEN_SHIFT) & 0xff);
3517 vmidb += areab * ((pixel >> L_BLUE_SHIFT) & 0xff);
3518 }
3519
3520 /* Sum all the contributions */
3521 rval = (v00r + v01r + v10r + v11r + vinr + vmidr + 128) / area;
3522 gval = (v00g + v01g + v10g + v11g + ving + vmidg + 128) / area;
3523 bval = (v00b + v01b + v10b + v11b + vinb + vmidb + 128) / area;
3524#if DEBUG_OVERFLOW
3525 if (rval > 255) lept_stderr("rval ovfl: %d\n", rval);
3526 if (gval > 255) lept_stderr("gval ovfl: %d\n", gval);
3527 if (bval > 255) lept_stderr("bval ovfl: %d\n", bval);
3528#endif /* DEBUG_OVERFLOW */
3529 composeRGBPixel(rval, gval, bval, lined + j);
3530 }
3531 }
3532}
3533
3534
3549static void
3550scaleGrayAreaMapLow(l_uint32 *datad,
3551 l_int32 wd,
3552 l_int32 hd,
3553 l_int32 wpld,
3554 l_uint32 *datas,
3555 l_int32 ws,
3556 l_int32 hs,
3557 l_int32 wpls)
3558{
3559l_int32 i, j, k, m, wm2, hm2;
3560l_int32 xu, yu; /* UL corner in src image, to 1/16 of a pixel */
3561l_int32 xl, yl; /* LR corner in src image, to 1/16 of a pixel */
3562l_int32 xup, yup, xuf, yuf; /* UL src pixel: integer and fraction */
3563l_int32 xlp, ylp, xlf, ylf; /* LR src pixel: integer and fraction */
3564l_int32 delx, dely, area;
3565l_int32 v00; /* contrib. from UL src pixel */
3566l_int32 v01; /* contrib. from LL src pixel */
3567l_int32 v10; /* contrib from UR src pixel */
3568l_int32 v11; /* contrib from LR src pixel */
3569l_int32 vin; /* contrib from all full interior src pixels */
3570l_int32 vmid; /* contrib from side parts that are full in 1 direction */
3571l_int32 val;
3572l_uint32 *lines, *lined;
3573l_float32 scx, scy;
3574
3575 /* (scx, scy) are scaling factors that are applied to the
3576 * dest coords to get the corresponding src coords.
3577 * We need them because we iterate over dest pixels
3578 * and must find the corresponding set of src pixels. */
3579 scx = 16.f * (l_float32)ws / (l_float32)wd;
3580 scy = 16.f * (l_float32)hs / (l_float32)hd;
3581 wm2 = ws - 2;
3582 hm2 = hs - 2;
3583
3584 /* Iterate over the destination pixels */
3585 for (i = 0; i < hd; i++) {
3586 yu = (l_int32)(scy * i);
3587 yl = (l_int32)(scy * (i + 1.0));
3588 yup = yu >> 4;
3589 yuf = yu & 0x0f;
3590 ylp = yl >> 4;
3591 ylf = yl & 0x0f;
3592 dely = ylp - yup;
3593 lined = datad + i * wpld;
3594 lines = datas + yup * wpls;
3595 for (j = 0; j < wd; j++) {
3596 xu = (l_int32)(scx * j);
3597 xl = (l_int32)(scx * (j + 1.0));
3598 xup = xu >> 4;
3599 xuf = xu & 0x0f;
3600 xlp = xl >> 4;
3601 xlf = xl & 0x0f;
3602 delx = xlp - xup;
3603
3604 /* If near the edge, just use a src pixel value */
3605 if (xlp > wm2 || ylp > hm2) {
3606 SET_DATA_BYTE(lined, j, GET_DATA_BYTE(lines, xup));
3607 continue;
3608 }
3609
3610 /* Area summed over, in subpixels. This varies
3611 * due to the quantization, so we can't simply take
3612 * the area to be a constant: area = scx * scy. */
3613 area = ((16 - xuf) + 16 * (delx - 1) + xlf) *
3614 ((16 - yuf) + 16 * (dely - 1) + ylf);
3615
3616 /* Do area map summation */
3617 v00 = (16 - xuf) * (16 - yuf) * GET_DATA_BYTE(lines, xup);
3618 v10 = xlf * (16 - yuf) * GET_DATA_BYTE(lines, xlp);
3619 v01 = (16 - xuf) * ylf * GET_DATA_BYTE(lines + dely * wpls, xup);
3620 v11 = xlf * ylf * GET_DATA_BYTE(lines + dely * wpls, xlp);
3621 for (vin = 0, k = 1; k < dely; k++) { /* for full src pixels */
3622 for (m = 1; m < delx; m++) {
3623 vin += 256 * GET_DATA_BYTE(lines + k * wpls, xup + m);
3624 }
3625 }
3626 for (vmid = 0, k = 1; k < dely; k++) /* for left side */
3627 vmid += (16 - xuf) * 16 * GET_DATA_BYTE(lines + k * wpls, xup);
3628 for (k = 1; k < dely; k++) /* for right side */
3629 vmid += xlf * 16 * GET_DATA_BYTE(lines + k * wpls, xlp);
3630 for (m = 1; m < delx; m++) /* for top side */
3631 vmid += 16 * (16 - yuf) * GET_DATA_BYTE(lines, xup + m);
3632 for (m = 1; m < delx; m++) /* for bottom side */
3633 vmid += 16 * ylf * GET_DATA_BYTE(lines + dely * wpls, xup + m);
3634 val = (v00 + v01 + v10 + v11 + vin + vmid + 128) / area;
3635#if DEBUG_OVERFLOW
3636 if (val > 255) lept_stderr("val overflow: %d\n", val);
3637#endif /* DEBUG_OVERFLOW */
3638 SET_DATA_BYTE(lined, j, val);
3639 }
3640 }
3641}
3642
3643
3644/*------------------------------------------------------------------*
3645 * 2x area mapped downscaling *
3646 *------------------------------------------------------------------*/
3656static void
3657scaleAreaMapLow2(l_uint32 *datad,
3658 l_int32 wd,
3659 l_int32 hd,
3660 l_int32 wpld,
3661 l_uint32 *datas,
3662 l_int32 d,
3663 l_int32 wpls)
3664{
3665l_int32 i, j, val, rval, gval, bval;
3666l_uint32 *lines, *lined;
3667l_uint32 pixel;
3668
3669 if (d == 8) {
3670 for (i = 0; i < hd; i++) {
3671 lines = datas + 2 * i * wpls;
3672 lined = datad + i * wpld;
3673 for (j = 0; j < wd; j++) {
3674 /* Average each dest pixel using 4 src pixels */
3675 val = GET_DATA_BYTE(lines, 2 * j);
3676 val += GET_DATA_BYTE(lines, 2 * j + 1);
3677 val += GET_DATA_BYTE(lines + wpls, 2 * j);
3678 val += GET_DATA_BYTE(lines + wpls, 2 * j + 1);
3679 val >>= 2;
3680 SET_DATA_BYTE(lined, j, val);
3681 }
3682 }
3683 } else { /* d == 32 */
3684 for (i = 0; i < hd; i++) {
3685 lines = datas + 2 * i * wpls;
3686 lined = datad + i * wpld;
3687 for (j = 0; j < wd; j++) {
3688 /* Average each of the color components from 4 src pixels */
3689 pixel = *(lines + 2 * j);
3690 rval = (pixel >> L_RED_SHIFT) & 0xff;
3691 gval = (pixel >> L_GREEN_SHIFT) & 0xff;
3692 bval = (pixel >> L_BLUE_SHIFT) & 0xff;
3693 pixel = *(lines + 2 * j + 1);
3694 rval += (pixel >> L_RED_SHIFT) & 0xff;
3695 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3696 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3697 pixel = *(lines + wpls + 2 * j);
3698 rval += (pixel >> L_RED_SHIFT) & 0xff;
3699 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3700 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3701 pixel = *(lines + wpls + 2 * j + 1);
3702 rval += (pixel >> L_RED_SHIFT) & 0xff;
3703 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3704 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3705 composeRGBPixel(rval >> 2, gval >> 2, bval >> 2, &pixel);
3706 *(lined + j) = pixel;
3707 }
3708 }
3709 }
3710}
3711
3712
3713/*------------------------------------------------------------------*
3714 * Binary scaling by closest pixel sampling *
3715 *------------------------------------------------------------------*/
3716/*
3717 * \brief scaleBinaryLow()
3718 *
3719 * <pre>
3720 * Notes:
3721 * (1) The dest must be cleared prior to this operation,
3722 * and we clear it here in the low-level code.
3723 * (2) We reuse dest pixels and dest pixel rows whenever
3724 * possible for upscaling; downscaling is done by
3725 * strict subsampling.
3726 * </pre>
3727 */
3728static l_int32
3729scaleBinaryLow(l_uint32 *datad,
3730 l_int32 wd,
3731 l_int32 hd,
3732 l_int32 wpld,
3733 l_uint32 *datas,
3734 l_int32 ws,
3735 l_int32 hs,
3736 l_int32 wpls,
3737 l_float32 shiftx,
3738 l_float32 shifty)
3739{
3740l_int32 i, j;
3741l_int32 xs, prevxs, sval;
3742l_int32 *srow, *scol;
3743l_uint32 *lines, *prevlines, *lined, *prevlined;
3744l_float32 wratio, hratio;
3745
3746 /* Clear dest */
3747 memset(datad, 0, 4LL * hd * wpld);
3748
3749 /* The source row corresponding to dest row i ==> srow[i]
3750 * The source col corresponding to dest col j ==> scol[j] */
3751 if ((srow = (l_int32 *)LEPT_CALLOC(hd, sizeof(l_int32))) == NULL)
3752 return ERROR_INT("srow not made", __func__, 1);
3753 if ((scol = (l_int32 *)LEPT_CALLOC(wd, sizeof(l_int32))) == NULL) {
3754 LEPT_FREE(srow);
3755 return ERROR_INT("scol not made", __func__, 1);
3756 }
3757
3758 wratio = (l_float32)ws / (l_float32)wd;
3759 hratio = (l_float32)hs / (l_float32)hd;
3760 for (i = 0; i < hd; i++)
3761 srow[i] = L_MIN((l_int32)(hratio * i + shifty), hs - 1);
3762 for (j = 0; j < wd; j++)
3763 scol[j] = L_MIN((l_int32)(wratio * j + shiftx), ws - 1);
3764
3765 prevlines = NULL;
3766 prevxs = -1;
3767 sval = 0;
3768 for (i = 0; i < hd; i++) {
3769 lines = datas + srow[i] * wpls;
3770 lined = datad + i * wpld;
3771 if (lines != prevlines) { /* make dest from new source row */
3772 for (j = 0; j < wd; j++) {
3773 xs = scol[j];
3774 if (xs != prevxs) { /* get dest pix from source col */
3775 if ((sval = GET_DATA_BIT(lines, xs)))
3776 SET_DATA_BIT(lined, j);
3777 prevxs = xs;
3778 } else { /* copy prev dest pix, if set */
3779 if (sval)
3780 SET_DATA_BIT(lined, j);
3781 }
3782 }
3783 } else { /* lines == prevlines; copy prev dest row */
3784 prevlined = lined - wpld;
3785 memcpy(lined, prevlined, 4 * wpld);
3786 }
3787 prevlines = lines;
3788 }
3789
3790 LEPT_FREE(srow);
3791 LEPT_FREE(scol);
3792 return 0;
3793}
#define GET_DATA_QBIT(pdata, n)
#define GET_DATA_TWO_BYTES(pdata, n)
#define SET_DATA_BIT(pdata, n)
#define SET_DATA_DIBIT(pdata, n, val)
#define SET_DATA_TWO_BYTES(pdata, n, val)
#define GET_DATA_BYTE(pdata, n)
#define GET_DATA_DIBIT(pdata, n)
#define SET_DATA_BYTE(pdata, n, val)
#define GET_DATA_BIT(pdata, n)
#define SET_DATA_QBIT(pdata, n, val)
@ COLOR_BLUE
Definition pix.h:330
@ COLOR_RED
Definition pix.h:328
@ COLOR_GREEN
Definition pix.h:329
@ DEFAULT_CLIP_LOWER_1
Definition pix.h:728
@ DEFAULT_CLIP_UPPER_1
Definition pix.h:729
@ REMOVE_CMAP_BASED_ON_SRC
Definition pix.h:384
@ L_CLONE
Definition pix.h:506
PIX * pixScaleGray4xLIDither(PIX *pixs)
pixScaleGray4xLIDither()
Definition scale1.c:1187
PIX * pixScaleLI(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleLI()
Definition scale1.c:510
PIX * pixScaleBinaryWithShift(PIX *pixs, l_float32 scalex, l_float32 scaley, l_float32 shiftx, l_float32 shifty)
pixScaleBinaryWithShift()
Definition scale1.c:2188
static void scaleAreaMapLow2(l_uint32 *datad, l_int32 wd, l_int32 hd, l_int32 wpld, l_uint32 *datas, l_int32 d, l_int32 wpls)
scaleAreaMapLow2()
Definition scale1.c:3657
PIX * pixScaleAreaMap2(PIX *pix)
pixScaleAreaMap2()
Definition scale1.c:2041
PIX * pixScaleGrayToBinaryFast(PIX *pixs, l_int32 factor, l_int32 thresh)
pixScaleGrayToBinaryFast()
Definition scale1.c:1631
static void scaleGray4xLILineLow(l_uint32 *lined, l_int32 wpld, l_uint32 *lines, l_int32 ws, l_int32 wpls, l_int32 lastlineflag)
scaleGray4xLILineLow()
Definition scale1.c:2961
static void scaleGray2xLILineLow(l_uint32 *lined, l_int32 wpld, l_uint32 *lines, l_int32 ws, l_int32 wpls, l_int32 lastlineflag)
scaleGray2xLILineLow()
Definition scale1.c:2722
PIX * pixScaleBySamplingWithShift(PIX *pixs, l_float32 scalex, l_float32 scaley, l_float32 shiftx, l_float32 shifty)
pixScaleBySamplingWithShift()
Definition scale1.c:1345
PIX * pixScaleColor4xLI(PIX *pixs)
pixScaleColor4xLI()
Definition scale1.c:674
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)
scaleColorAreaMapLow()
Definition scale1.c:3392
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)
scaleGrayLILow()
Definition scale1.c:2355
PIX * pixScaleBinary(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleBinary()
Definition scale1.c:2158
PIX * pixScaleGray2xLIThresh(PIX *pixs, l_int32 thresh)
pixScaleGray2xLIThresh()
Definition scale1.c:907
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, l_float32 shiftx, l_float32 shifty)
scaleBySamplingLow()
Definition scale1.c:3095
PIX * pixScaleByIntSampling(PIX *pixs, l_int32 factor)
pixScaleByIntSampling()
Definition scale1.c:1454
PIX * pixScaleGray2xLI(PIX *pixs)
pixScaleGray2xLI()
Definition scale1.c:825
PIX * pixScaleSmooth(PIX *pix, l_float32 scalex, l_float32 scaley)
pixScaleSmooth()
Definition scale1.c:1711
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)
scaleColorLILow()
Definition scale1.c:2250
PIX * pixScaleColor2xLI(PIX *pixs)
pixScaleColor2xLI()
Definition scale1.c:629
PIX * pixScaleGray2xLIDither(PIX *pixs)
pixScaleGray2xLIDither()
Definition scale1.c:984
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)
scaleSmoothLow()
Definition scale1.c:3228
PIX * pixScaleGray4xLIThresh(PIX *pixs, l_int32 thresh)
pixScaleGray4xLIThresh()
Definition scale1.c:1101
PIX * pixScaleGray4xLI(PIX *pixs)
pixScaleGray4xLI()
Definition scale1.c:864
PIX * pixScaleBySamplingToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleBySamplingToSize()
Definition scale1.c:1412
PIX * pixScaleBySampling(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleBySampling()
Definition scale1.c:1317
PIX * pixScaleColorLI(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleColorLI()
Definition scale1.c:567
PIX * pixScale(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScale()
Definition scale1.c:254
static void scaleColor2xLILow(l_uint32 *datad, l_int32 wpld, l_uint32 *datas, l_int32 ws, l_int32 hs, l_int32 wpls)
scaleColor2xLILow()
Definition scale1.c:2472
PIX * pixScaleToSizeRel(PIX *pixs, l_int32 delw, l_int32 delh)
pixScaleToSizeRel()
Definition scale1.c:282
static void scaleGray4xLILow(l_uint32 *datad, l_int32 wpld, l_uint32 *datas, l_int32 ws, l_int32 hs, l_int32 wpls)
scaleGray4xLILow()
Definition scale1.c:2915
PIX * pixScaleRGBToGray2(PIX *pixs, l_float32 rwt, l_float32 gwt, l_float32 bwt)
pixScaleRGBToGray2()
Definition scale1.c:1831
PIX * pixScaleSmoothToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleSmoothToSize()
Definition scale1.c:1795
PIX * pixScaleRGBToBinaryFast(PIX *pixs, l_int32 factor, l_int32 thresh)
pixScaleRGBToBinaryFast()
Definition scale1.c:1567
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)
scaleRGBToGray2Low()
Definition scale1.c:3327
PIX * pixScaleRGBToGrayFast(PIX *pixs, l_int32 factor, l_int32 color)
pixScaleRGBToGrayFast()
Definition scale1.c:1494
PIX * pixScaleToResolution(PIX *pixs, l_float32 target, l_float32 assumed, l_float32 *pscalefact)
pixScaleToResolution()
Definition scale1.c:361
static void scaleGray2xLILow(l_uint32 *datad, l_int32 wpld, l_uint32 *datas, l_int32 ws, l_int32 hs, l_int32 wpls)
scaleGray2xLILow()
Definition scale1.c:2674
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)
scaleGrayAreaMapLow()
Definition scale1.c:3550
PIX * pixScaleToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleToSize()
Definition scale1.c:323
PIX * pixScaleAreaMapToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleAreaMapToSize()
Definition scale1.c:2104
PIX * pixScaleGrayLI(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleGrayLI()
Definition scale1.c:766
PIX * pixScaleGeneral(PIX *pixs, l_float32 scalex, l_float32 scaley, l_float32 sharpfract, l_int32 sharpwidth)
pixScaleGeneral()
Definition scale1.c:419
static void scaleColor2xLILineLow(l_uint32 *lined, l_int32 wpld, l_uint32 *lines, l_int32 ws, l_int32 wpls, l_int32 lastlineflag)
scaleColor2xLILineLow()
Definition scale1.c:2520
PIX * pixScaleAreaMap(PIX *pix, l_float32 scalex, l_float32 scaley)
pixScaleAreaMap()
Definition scale1.c:1910