Leptonica 1.82.0
Image processing and image analysis suite
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
114#ifdef HAVE_CONFIG_H
115#include <config_auto.h>
116#endif /* HAVE_CONFIG_H */
117
118#include <string.h>
119#include "allheaders.h"
120
121static void scaleColorLILow(l_uint32 *datad, l_int32 wd, l_int32 hd,
122 l_int32 wpld, l_uint32 *datas, l_int32 ws,
123 l_int32 hs, l_int32 wpls);
124static void scaleGrayLILow(l_uint32 *datad, l_int32 wd, l_int32 hd,
125 l_int32 wpld, l_uint32 *datas, l_int32 ws,
126 l_int32 hs, l_int32 wpls);
127static void scaleColor2xLILow(l_uint32 *datad, l_int32 wpld, l_uint32 *datas,
128 l_int32 ws, l_int32 hs, l_int32 wpls);
129static void scaleColor2xLILineLow(l_uint32 *lined, l_int32 wpld,
130 l_uint32 *lines, l_int32 ws, l_int32 wpls,
131 l_int32 lastlineflag);
132static void scaleGray2xLILow(l_uint32 *datad, l_int32 wpld, l_uint32 *datas,
133 l_int32 ws, l_int32 hs, l_int32 wpls);
134static void scaleGray2xLILineLow(l_uint32 *lined, l_int32 wpld,
135 l_uint32 *lines, l_int32 ws, l_int32 wpls,
136 l_int32 lastlineflag);
137static void scaleGray4xLILow(l_uint32 *datad, l_int32 wpld, l_uint32 *datas,
138 l_int32 ws, l_int32 hs, l_int32 wpls);
139static void scaleGray4xLILineLow(l_uint32 *lined, l_int32 wpld,
140 l_uint32 *lines, l_int32 ws, l_int32 wpls,
141 l_int32 lastlineflag);
142static l_int32 scaleBySamplingLow(l_uint32 *datad, l_int32 wd, l_int32 hd,
143 l_int32 wpld, l_uint32 *datas, l_int32 ws,
144 l_int32 hs, l_int32 d, l_int32 wpls);
145static l_int32 scaleSmoothLow(l_uint32 *datad, l_int32 wd, l_int32 hd,
146 l_int32 wpld, l_uint32 *datas, l_int32 ws,
147 l_int32 hs, l_int32 d, l_int32 wpls,
148 l_int32 size);
149static void scaleRGBToGray2Low(l_uint32 *datad, l_int32 wd, l_int32 hd,
150 l_int32 wpld, l_uint32 *datas, l_int32 wpls,
151 l_float32 rwt, l_float32 gwt, l_float32 bwt);
152static void scaleColorAreaMapLow(l_uint32 *datad, l_int32 wd, l_int32 hd,
153 l_int32 wpld, l_uint32 *datas, l_int32 ws,
154 l_int32 hs, l_int32 wpls);
155static void scaleGrayAreaMapLow(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 scaleAreaMapLow2(l_uint32 *datad, l_int32 wd, l_int32 hd,
159 l_int32 wpld, l_uint32 *datas, l_int32 d,
160 l_int32 wpls);
161static l_int32 scaleBinaryLow(l_uint32 *datad, l_int32 wd, l_int32 hd,
162 l_int32 wpld, l_uint32 *datas, l_int32 ws,
163 l_int32 hs, l_int32 wpls);
164
165#ifndef NO_CONSOLE_IO
166#define DEBUG_OVERFLOW 0
167#define DEBUG_UNROLLING 0
168#endif /* ~NO_CONSOLE_IO */
169
170/*------------------------------------------------------------------*
171 * Top level scaling dispatcher *
172 *------------------------------------------------------------------*/
249PIX *
251 l_float32 scalex,
252 l_float32 scaley)
253{
254l_int32 sharpwidth;
255l_float32 maxscale, sharpfract;
256
257 PROCNAME("pixScale");
258
259 if (!pixs)
260 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
261
262 /* Reduce the default sharpening factors by 2 if maxscale < 0.7 */
263 maxscale = L_MAX(scalex, scaley);
264 sharpfract = (maxscale < 0.7) ? 0.2 : 0.4;
265 sharpwidth = (maxscale < 0.7) ? 1 : 2;
266
267 return pixScaleGeneral(pixs, scalex, scaley, sharpfract, sharpwidth);
268}
269
270
279PIX *
281 l_int32 delw,
282 l_int32 delh)
283{
284l_int32 w, h, wd, hd;
285
286 PROCNAME("pixScaleToSizeRel");
287
288 if (!pixs)
289 return (PIX *)ERROR_PTR("pixs not defined", procName, 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", procName, 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 PROCNAME("pixScaleToSize");
331
332 if (!pixs)
333 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
334 if (wd <= 0 && hd <= 0)
335 return (PIX *)ERROR_PTR("neither wd nor hd > 0", procName, NULL);
336
337 pixGetDimensions(pixs, &w, &h, NULL);
338 if (wd <= 0) {
339 scaley = (l_float32)hd / (l_float32)h;
340 scalex = scaley;
341 } else if (hd <= 0) {
342 scalex = (l_float32)wd / (l_float32)w;
343 scaley = scalex;
344 } else {
345 scalex = (l_float32)wd / (l_float32)w;
346 scaley = (l_float32)hd / (l_float32)h;
347 }
348
349 return pixScale(pixs, scalex, scaley);
350}
351
352
362PIX *
364 l_float32 target,
365 l_float32 assumed,
366 l_float32 *pscalefact)
367{
368l_int32 xres;
369l_float32 factor;
370
371 PROCNAME("pixScaleToResolution");
372
373 if (pscalefact) *pscalefact = 1.0;
374 if (!pixs)
375 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
376 if (target <= 0)
377 return (PIX *)ERROR_PTR("target resolution <= 0", procName, NULL);
378
379 xres = pixGetXRes(pixs);
380 if (xres <= 0) {
381 if (assumed == 0)
382 return pixCopy(NULL, pixs);
383 xres = assumed;
384 }
385 factor = target / (l_float32)xres;
386 if (pscalefact) *pscalefact = factor;
387
388 return pixScale(pixs, factor, factor);
389}
390
391
422PIX *
424 l_float32 scalex,
425 l_float32 scaley,
426 l_float32 sharpfract,
427 l_int32 sharpwidth)
428{
429l_int32 d;
430l_float32 maxscale, minscale;
431PIX *pix1, *pix2, *pixd;
432
433 PROCNAME("pixScaleGeneral");
434
435 if (!pixs)
436 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
437 d = pixGetDepth(pixs);
438 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
439 return (PIX *)ERROR_PTR("pixs not {1,2,4,8,16,32} bpp", procName, NULL);
440 if (scalex <= 0.0 || scaley <= 0.0)
441 return (PIX *)ERROR_PTR("scale factor <= 0", procName, NULL);
442 if (scalex == 1.0 && scaley == 1.0)
443 return pixCopy(NULL, pixs);
444
445 if (d == 1)
446 return pixScaleBinary(pixs, scalex, scaley);
447
448 /* Remove colormap; clone if possible; result is either 8 or 32 bpp */
449 if ((pix1 = pixConvertTo8Or32(pixs, L_CLONE, 0)) == NULL)
450 return (PIX *)ERROR_PTR("pix1 not made", procName, NULL);
451
452 /* Scale (up or down) */
453 d = pixGetDepth(pix1);
454 maxscale = L_MAX(scalex, scaley);
455 minscale = L_MIN(scalex, scaley);
456 if (maxscale < 0.7) { /* use low-pass filter for anti-aliasing */
457 if (minscale < 0.02) { /* whole-pixel low-pass filter */
458 pix2 = pixScaleSmooth(pix1, scalex, scaley);
459 } else { /* fractional pixel low-pass filter */
460 pix2 = pixScaleAreaMap(pix1, scalex, scaley);
461 }
462 if (maxscale > 0.2 && sharpfract > 0.0 && sharpwidth > 0) {
463 pixd = pixUnsharpMasking(pix2, sharpwidth, sharpfract);
464 } else {
465 pixd = pixClone(pix2);
466 }
467 } else { /* use linear interpolation */
468 if (d == 8) {
469 pix2 = pixScaleGrayLI(pix1, scalex, scaley);
470 } else { /* d == 32 */
471 pix2 = pixScaleColorLI(pix1, scalex, scaley);
472 }
473 if (maxscale < 1.4 && sharpfract > 0.0 && sharpwidth > 0) {
474 pixd = pixUnsharpMasking(pix2, sharpwidth, sharpfract);
475 } else {
476 pixd = pixClone(pix2);
477 }
478 }
479
480 pixDestroy(&pix1);
481 pixDestroy(&pix2);
482 pixCopyText(pixd, pixs);
483 pixCopyInputFormat(pixd, pixs);
484 return pixd;
485}
486
487
488/*------------------------------------------------------------------*
489 * Scaling by linear interpolation *
490 *------------------------------------------------------------------*/
515PIX *
517 l_float32 scalex,
518 l_float32 scaley)
519{
520l_int32 d;
521l_float32 maxscale;
522PIX *pixt, *pixd;
523
524 PROCNAME("pixScaleLI");
525
526 if (!pixs || (pixGetDepth(pixs) == 1))
527 return (PIX *)ERROR_PTR("pixs not defined or 1 bpp", procName, NULL);
528 maxscale = L_MAX(scalex, scaley);
529 if (maxscale < 0.7) {
530 L_WARNING("scaling factors < 0.7; do regular scaling\n", procName);
531 return pixScaleGeneral(pixs, scalex, scaley, 0.0, 0);
532 }
533 d = pixGetDepth(pixs);
534 if (d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
535 return (PIX *)ERROR_PTR("pixs not {2,4,8,16,32} bpp", procName, NULL);
536
537 /* Remove colormap; clone if possible; result is either 8 or 32 bpp */
538 if ((pixt = pixConvertTo8Or32(pixs, L_CLONE, 0)) == NULL)
539 return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
540
541 d = pixGetDepth(pixt);
542 if (d == 8)
543 pixd = pixScaleGrayLI(pixt, scalex, scaley);
544 else /* d == 32 */
545 pixd = pixScaleColorLI(pixt, scalex, scaley);
546
547 pixDestroy(&pixt);
548 pixCopyInputFormat(pixd, pixs);
549 return pixd;
550}
551
552
574PIX *
576 l_float32 scalex,
577 l_float32 scaley)
578{
579l_int32 ws, hs, wpls, wd, hd, wpld;
580l_uint32 *datas, *datad;
581l_float32 maxscale;
582PIX *pixd;
583
584 PROCNAME("pixScaleColorLI");
585
586 if (!pixs || (pixGetDepth(pixs) != 32))
587 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
588 maxscale = L_MAX(scalex, scaley);
589 if (maxscale < 0.7) {
590 L_WARNING("scaling factors < 0.7; do regular scaling\n", procName);
591 return pixScaleGeneral(pixs, scalex, scaley, 0.0, 0);
592 }
593
594 /* Do fast special cases if possible */
595 if (scalex == 1.0 && scaley == 1.0)
596 return pixCopy(NULL, pixs);
597 if (scalex == 2.0 && scaley == 2.0)
598 return pixScaleColor2xLI(pixs);
599 if (scalex == 4.0 && scaley == 4.0)
600 return pixScaleColor4xLI(pixs);
601
602 /* General case */
603 pixGetDimensions(pixs, &ws, &hs, NULL);
604 datas = pixGetData(pixs);
605 wpls = pixGetWpl(pixs);
606 wd = (l_int32)(scalex * (l_float32)ws + 0.5);
607 hd = (l_int32)(scaley * (l_float32)hs + 0.5);
608 if ((pixd = pixCreate(wd, hd, 32)) == NULL)
609 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
610 pixCopyResolution(pixd, pixs);
611 pixScaleResolution(pixd, scalex, scaley);
612 datad = pixGetData(pixd);
613 wpld = pixGetWpl(pixd);
614 scaleColorLILow(datad, wd, hd, wpld, datas, ws, hs, wpls);
615 if (pixGetSpp(pixs) == 4)
616 pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley);
617
618 pixCopyInputFormat(pixd, pixs);
619 return pixd;
620}
621
622
638PIX *
640{
641l_int32 ws, hs, wpls, wpld;
642l_uint32 *datas, *datad;
643PIX *pixd;
644
645 PROCNAME("pixScaleColor2xLI");
646
647 if (!pixs || (pixGetDepth(pixs) != 32))
648 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
649
650 pixGetDimensions(pixs, &ws, &hs, NULL);
651 datas = pixGetData(pixs);
652 wpls = pixGetWpl(pixs);
653 if ((pixd = pixCreate(2 * ws, 2 * hs, 32)) == NULL)
654 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
655 pixCopyResolution(pixd, pixs);
656 pixScaleResolution(pixd, 2.0, 2.0);
657 datad = pixGetData(pixd);
658 wpld = pixGetWpl(pixd);
659 scaleColor2xLILow(datad, wpld, datas, ws, hs, wpls);
660 if (pixGetSpp(pixs) == 4)
661 pixScaleAndTransferAlpha(pixd, pixs, 2.0, 2.0);
662
663 pixCopyInputFormat(pixd, pixs);
664 return pixd;
665}
666
667
685PIX *
687{
688PIX *pixr, *pixg, *pixb;
689PIX *pixrs, *pixgs, *pixbs;
690PIX *pixd;
691
692 PROCNAME("pixScaleColor4xLI");
693
694 if (!pixs || (pixGetDepth(pixs) != 32))
695 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
696
697 pixr = pixGetRGBComponent(pixs, COLOR_RED);
698 pixrs = pixScaleGray4xLI(pixr);
699 pixDestroy(&pixr);
700 pixg = pixGetRGBComponent(pixs, COLOR_GREEN);
701 pixgs = pixScaleGray4xLI(pixg);
702 pixDestroy(&pixg);
703 pixb = pixGetRGBComponent(pixs, COLOR_BLUE);
704 pixbs = pixScaleGray4xLI(pixb);
705 pixDestroy(&pixb);
706
707 if ((pixd = pixCreateRGBImage(pixrs, pixgs, pixbs)) == NULL) {
708 L_ERROR("pixd not made\n", procName);
709 } else {
710 if (pixGetSpp(pixs) == 4)
711 pixScaleAndTransferAlpha(pixd, pixs, 4.0, 4.0);
712 pixCopyInputFormat(pixd, pixs);
713 }
714
715 pixDestroy(&pixrs);
716 pixDestroy(&pixgs);
717 pixDestroy(&pixbs);
718 return pixd;
719}
720
721
779PIX *
781 l_float32 scalex,
782 l_float32 scaley)
783{
784l_int32 ws, hs, wpls, wd, hd, wpld;
785l_uint32 *datas, *datad;
786l_float32 maxscale;
787PIX *pixd;
788
789 PROCNAME("pixScaleGrayLI");
790
791 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
792 return (PIX *)ERROR_PTR("pixs undefined, cmapped or not 8 bpp",
793 procName, NULL);
794 maxscale = L_MAX(scalex, scaley);
795 if (maxscale < 0.7) {
796 L_WARNING("scaling factors < 0.7; do regular scaling\n", procName);
797 return pixScaleGeneral(pixs, scalex, scaley, 0.0, 0);
798 }
799
800 /* Do fast special cases if possible */
801 if (scalex == 1.0 && scaley == 1.0)
802 return pixCopy(NULL, pixs);
803 if (scalex == 2.0 && scaley == 2.0)
804 return pixScaleGray2xLI(pixs);
805 if (scalex == 4.0 && scaley == 4.0)
806 return pixScaleGray4xLI(pixs);
807
808 /* General case */
809 pixGetDimensions(pixs, &ws, &hs, NULL);
810 datas = pixGetData(pixs);
811 wpls = pixGetWpl(pixs);
812 wd = (l_int32)(scalex * (l_float32)ws + 0.5);
813 hd = (l_int32)(scaley * (l_float32)hs + 0.5);
814 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
815 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
816 pixCopyText(pixd, pixs);
817 pixCopyResolution(pixd, pixs);
818 pixCopyInputFormat(pixd, pixs);
819 pixScaleResolution(pixd, scalex, scaley);
820 datad = pixGetData(pixd);
821 wpld = pixGetWpl(pixd);
822 scaleGrayLILow(datad, wd, hd, wpld, datas, ws, hs, wpls);
823 return pixd;
824}
825
826
840PIX *
842{
843l_int32 ws, hs, wpls, wpld;
844l_uint32 *datas, *datad;
845PIX *pixd;
846
847 PROCNAME("pixScaleGray2xLI");
848
849 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
850 return (PIX *)ERROR_PTR("pixs undefined, cmapped or not 8 bpp",
851 procName, NULL);
852
853 pixGetDimensions(pixs, &ws, &hs, NULL);
854 datas = pixGetData(pixs);
855 wpls = pixGetWpl(pixs);
856 if ((pixd = pixCreate(2 * ws, 2 * hs, 8)) == NULL)
857 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
858 pixCopyResolution(pixd, pixs);
859 pixCopyInputFormat(pixd, pixs);
860 pixScaleResolution(pixd, 2.0, 2.0);
861 datad = pixGetData(pixd);
862 wpld = pixGetWpl(pixd);
863 scaleGray2xLILow(datad, wpld, datas, ws, hs, wpls);
864 return pixd;
865}
866
867
881PIX *
883{
884l_int32 ws, hs, wpls, wpld;
885l_uint32 *datas, *datad;
886PIX *pixd;
887
888 PROCNAME("pixScaleGray4xLI");
889
890 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
891 return (PIX *)ERROR_PTR("pixs undefined, cmapped or not 8 bpp",
892 procName, NULL);
893
894 pixGetDimensions(pixs, &ws, &hs, NULL);
895 datas = pixGetData(pixs);
896 wpls = pixGetWpl(pixs);
897 if ((pixd = pixCreate(4 * ws, 4 * hs, 8)) == NULL)
898 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
899 pixCopyResolution(pixd, pixs);
900 pixCopyInputFormat(pixd, pixs);
901 pixScaleResolution(pixd, 4.0, 4.0);
902 datad = pixGetData(pixd);
903 wpld = pixGetWpl(pixd);
904 scaleGray4xLILow(datad, wpld, datas, ws, hs, wpls);
905 return pixd;
906}
907
908
909/*------------------------------------------------------------------*
910 * Scale 2x followed by binarization *
911 *------------------------------------------------------------------*/
926PIX *
928 l_int32 thresh)
929{
930l_int32 i, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
931l_uint32 *datas, *datad, *lines, *lined, *lineb;
932PIX *pixd;
933
934 PROCNAME("pixScaleGray2xLIThresh");
935
936 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
937 return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
938 procName, NULL);
939 if (thresh < 0 || thresh > 256)
940 return (PIX *)ERROR_PTR("thresh must be in [0, ... 256]",
941 procName, NULL);
942
943 pixGetDimensions(pixs, &ws, &hs, NULL);
944 wd = 2 * ws;
945 hd = 2 * hs;
946 hsm = hs - 1;
947 datas = pixGetData(pixs);
948 wpls = pixGetWpl(pixs);
949
950 /* Make line buffer for 2 lines of virtual intermediate image */
951 wplb = (wd + 3) / 4;
952 if ((lineb = (l_uint32 *)LEPT_CALLOC(2 * wplb, sizeof(l_uint32))) == NULL)
953 return (PIX *)ERROR_PTR("lineb not made", procName, NULL);
954
955 /* Make dest binary image */
956 if ((pixd = pixCreate(wd, hd, 1)) == NULL) {
957 LEPT_FREE(lineb);
958 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
959 }
960 pixCopyInputFormat(pixd, pixs);
961 pixCopyResolution(pixd, pixs);
962 pixScaleResolution(pixd, 2.0, 2.0);
963 wpld = pixGetWpl(pixd);
964 datad = pixGetData(pixd);
965
966 /* Do all but last src line */
967 for (i = 0; i < hsm; i++) {
968 lines = datas + i * wpls;
969 lined = datad + 2 * i * wpld; /* do 2 dest lines at a time */
970 scaleGray2xLILineLow(lineb, wplb, lines, ws, wpls, 0);
971 thresholdToBinaryLineLow(lined, wd, lineb, 8, thresh);
972 thresholdToBinaryLineLow(lined + wpld, wd, lineb + wplb, 8, thresh);
973 }
974
975 /* Do last src line */
976 lines = datas + hsm * wpls;
977 lined = datad + 2 * hsm * wpld;
978 scaleGray2xLILineLow(lineb, wplb, lines, ws, wpls, 1);
979 thresholdToBinaryLineLow(lined, wd, lineb, 8, thresh);
980 thresholdToBinaryLineLow(lined + wpld, wd, lineb + wplb, 8, thresh);
981
982 LEPT_FREE(lineb);
983 return pixd;
984}
985
986
1005PIX *
1007{
1008l_int32 i, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
1009l_uint32 *datas, *datad;
1010l_uint32 *lined;
1011l_uint32 *lineb = NULL; /* 2 intermediate buffer lines */
1012l_uint32 *linebp = NULL; /* 1 intermediate buffer line */
1013l_uint32 *bufs = NULL; /* 2 source buffer lines */
1014PIX *pixd = NULL;
1015
1016 PROCNAME("pixScaleGray2xLIDither");
1017
1018 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
1019 return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
1020 procName, NULL);
1021
1022 pixGetDimensions(pixs, &ws, &hs, NULL);
1023 wd = 2 * ws;
1024 hd = 2 * hs;
1025 hsm = hs - 1;
1026 datas = pixGetData(pixs);
1027 wpls = pixGetWpl(pixs);
1028
1029 /* Make line buffers for 2 lines of src image */
1030 if ((bufs = (l_uint32 *)LEPT_CALLOC(2 * wpls, sizeof(l_uint32))) == NULL)
1031 return (PIX *)ERROR_PTR("bufs not made", procName, NULL);
1032
1033 /* Make line buffer for 2 lines of virtual intermediate image */
1034 wplb = (wd + 3) / 4;
1035 if ((lineb = (l_uint32 *)LEPT_CALLOC(2 * wplb, sizeof(l_uint32))) == NULL) {
1036 L_ERROR("lineb not made\n", procName);
1037 goto cleanup;
1038 }
1039
1040 /* Make line buffer for 1 line of virtual intermediate image */
1041 if ((linebp = (l_uint32 *)LEPT_CALLOC(wplb, sizeof(l_uint32))) == NULL) {
1042 L_ERROR("linebp not made\n", procName);
1043 goto cleanup;
1044 }
1045
1046 /* Make dest binary image */
1047 if ((pixd = pixCreate(wd, hd, 1)) == NULL) {
1048 L_ERROR("pixd not made\n", procName);
1049 goto cleanup;
1050 }
1051 pixCopyInputFormat(pixd, pixs);
1052 pixCopyResolution(pixd, pixs);
1053 pixScaleResolution(pixd, 2.0, 2.0);
1054 wpld = pixGetWpl(pixd);
1055 datad = pixGetData(pixd);
1056
1057 /* Start with the first src and the first dest line */
1058 memcpy(bufs, datas, 4 * wpls); /* first src line */
1059 memcpy(bufs + wpls, datas + wpls, 4 * wpls); /* 2nd src line */
1060 scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 2 i lines */
1061 lined = datad;
1062 ditherToBinaryLineLow(lined, wd, lineb, lineb + wplb,
1064 /* 1st d line */
1065
1066 /* Do all but last src line */
1067 for (i = 1; i < hsm; i++) {
1068 memcpy(bufs, datas + i * wpls, 4 * wpls); /* i-th src line */
1069 memcpy(bufs + wpls, datas + (i + 1) * wpls, 4 * wpls);
1070 memcpy(linebp, lineb + wplb, 4 * wplb);
1071 scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 2 i lines */
1072 lined = datad + 2 * i * wpld;
1073 ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb,
1075 /* odd dest line */
1076 ditherToBinaryLineLow(lined, wd, lineb, lineb + wplb,
1078 /* even dest line */
1079 }
1080
1081 /* Do the last src line and the last 3 dest lines */
1082 memcpy(bufs, datas + hsm * wpls, 4 * wpls); /* hsm-th src line */
1083 memcpy(linebp, lineb + wplb, 4 * wplb); /* 1 i line */
1084 scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 1); /* 2 i lines */
1085 ditherToBinaryLineLow(lined + wpld, wd, linebp, lineb,
1087 /* odd dest line */
1088 ditherToBinaryLineLow(lined + 2 * wpld, wd, lineb, lineb + wplb,
1090 /* even dest line */
1091 ditherToBinaryLineLow(lined + 3 * wpld, wd, lineb + wplb, NULL,
1093 /* last dest line */
1094
1095cleanup:
1096 LEPT_FREE(bufs);
1097 LEPT_FREE(lineb);
1098 LEPT_FREE(linebp);
1099 return pixd;
1100}
1101
1102
1103/*------------------------------------------------------------------*
1104 * Scale 4x followed by binarization *
1105 *------------------------------------------------------------------*/
1124PIX *
1126 l_int32 thresh)
1127{
1128l_int32 i, j, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
1129l_uint32 *datas, *datad, *lines, *lined, *lineb;
1130PIX *pixd;
1131
1132 PROCNAME("pixScaleGray4xLIThresh");
1133
1134 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
1135 return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
1136 procName, NULL);
1137 if (thresh < 0 || thresh > 256)
1138 return (PIX *)ERROR_PTR("thresh must be in [0, ... 256]",
1139 procName, NULL);
1140
1141 pixGetDimensions(pixs, &ws, &hs, NULL);
1142 wd = 4 * ws;
1143 hd = 4 * hs;
1144 hsm = hs - 1;
1145 datas = pixGetData(pixs);
1146 wpls = pixGetWpl(pixs);
1147
1148 /* Make line buffer for 4 lines of virtual intermediate image */
1149 wplb = (wd + 3) / 4;
1150 if ((lineb = (l_uint32 *)LEPT_CALLOC(4 * wplb, sizeof(l_uint32))) == NULL)
1151 return (PIX *)ERROR_PTR("lineb not made", procName, NULL);
1152
1153 /* Make dest binary image */
1154 if ((pixd = pixCreate(wd, hd, 1)) == NULL) {
1155 LEPT_FREE(lineb);
1156 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1157 }
1158 pixCopyInputFormat(pixd, pixs);
1159 pixCopyResolution(pixd, pixs);
1160 pixScaleResolution(pixd, 4.0, 4.0);
1161 wpld = pixGetWpl(pixd);
1162 datad = pixGetData(pixd);
1163
1164 /* Do all but last src line */
1165 for (i = 0; i < hsm; i++) {
1166 lines = datas + i * wpls;
1167 lined = datad + 4 * i * wpld; /* do 4 dest lines at a time */
1168 scaleGray4xLILineLow(lineb, wplb, lines, ws, wpls, 0);
1169 for (j = 0; j < 4; j++) {
1170 thresholdToBinaryLineLow(lined + j * wpld, wd,
1171 lineb + j * wplb, 8, thresh);
1172 }
1173 }
1174
1175 /* Do last src line */
1176 lines = datas + hsm * wpls;
1177 lined = datad + 4 * hsm * wpld;
1178 scaleGray4xLILineLow(lineb, wplb, lines, ws, wpls, 1);
1179 for (j = 0; j < 4; j++) {
1180 thresholdToBinaryLineLow(lined + j * wpld, wd,
1181 lineb + j * wplb, 8, thresh);
1182 }
1183
1184 LEPT_FREE(lineb);
1185 return pixd;
1186}
1187
1188
1212PIX *
1214{
1215l_int32 i, j, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
1216l_uint32 *datas, *datad;
1217l_uint32 *lined;
1218l_uint32 *lineb = NULL; /* 4 intermediate buffer lines */
1219l_uint32 *linebp = NULL; /* 1 intermediate buffer line */
1220l_uint32 *bufs = NULL; /* 2 source buffer lines */
1221PIX *pixd = NULL;
1222
1223 PROCNAME("pixScaleGray4xLIDither");
1224
1225 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
1226 return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
1227 procName, NULL);
1228
1229 pixGetDimensions(pixs, &ws, &hs, NULL);
1230 wd = 4 * ws;
1231 hd = 4 * hs;
1232 hsm = hs - 1;
1233 datas = pixGetData(pixs);
1234 wpls = pixGetWpl(pixs);
1235
1236 /* Make line buffers for 2 lines of src image */
1237 if ((bufs = (l_uint32 *)LEPT_CALLOC(2 * wpls, sizeof(l_uint32))) == NULL)
1238 return (PIX *)ERROR_PTR("bufs not made", procName, NULL);
1239
1240 /* Make line buffer for 4 lines of virtual intermediate image */
1241 wplb = (wd + 3) / 4;
1242 if ((lineb = (l_uint32 *)LEPT_CALLOC(4 * wplb, sizeof(l_uint32))) == NULL) {
1243 L_ERROR("lineb not made\n", procName);
1244 goto cleanup;
1245 }
1246
1247 /* Make line buffer for 1 line of virtual intermediate image */
1248 if ((linebp = (l_uint32 *)LEPT_CALLOC(wplb, sizeof(l_uint32))) == NULL) {
1249 L_ERROR("linebp not made\n", procName);
1250 goto cleanup;
1251 }
1252
1253 /* Make dest binary image */
1254 if ((pixd = pixCreate(wd, hd, 1)) == NULL) {
1255 L_ERROR("pixd not made\n", procName);
1256 goto cleanup;
1257 }
1258 pixCopyInputFormat(pixd, pixs);
1259 pixCopyResolution(pixd, pixs);
1260 pixScaleResolution(pixd, 4.0, 4.0);
1261 wpld = pixGetWpl(pixd);
1262 datad = pixGetData(pixd);
1263
1264 /* Start with the first src and the first 3 dest lines */
1265 memcpy(bufs, datas, 4 * wpls); /* first src line */
1266 memcpy(bufs + wpls, datas + wpls, 4 * wpls); /* 2nd src line */
1267 scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 4 b lines */
1268 lined = datad;
1269 for (j = 0; j < 3; j++) { /* first 3 d lines of Q */
1270 ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb,
1271 lineb + (j + 1) * wplb,
1273 }
1274
1275 /* Do all but last src line */
1276 for (i = 1; i < hsm; i++) {
1277 memcpy(bufs, datas + i * wpls, 4 * wpls); /* i-th src line */
1278 memcpy(bufs + wpls, datas + (i + 1) * wpls, 4 * wpls);
1279 memcpy(linebp, lineb + 3 * wplb, 4 * wplb);
1280 scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 4 b lines */
1281 lined = datad + 4 * i * wpld;
1282 ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb,
1284 /* 4th dest line of Q */
1285 for (j = 0; j < 3; j++) { /* next 3 d lines of Quad */
1286 ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb,
1287 lineb + (j + 1) * wplb,
1289 }
1290 }
1291
1292 /* Do the last src line and the last 5 dest lines */
1293 memcpy(bufs, datas + hsm * wpls, 4 * wpls); /* hsm-th src line */
1294 memcpy(linebp, lineb + 3 * wplb, 4 * wplb); /* 1 b line */
1295 scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 1); /* 4 b lines */
1296 lined = datad + 4 * hsm * wpld;
1297 ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb,
1299 /* 4th dest line of Q */
1300 for (j = 0; j < 3; j++) { /* next 3 d lines of Quad */
1301 ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb,
1302 lineb + (j + 1) * wplb,
1304 }
1305 /* And finally, the last dest line */
1306 ditherToBinaryLineLow(lined + 3 * wpld, wd, lineb + 3 * wplb, NULL,
1308
1309cleanup:
1310 LEPT_FREE(bufs);
1311 LEPT_FREE(lineb);
1312 LEPT_FREE(linebp);
1313 return pixd;
1314}
1315
1316
1317/*------------------------------------------------------------------*
1318 * Scaling by closest pixel sampling *
1319 *------------------------------------------------------------------*/
1337PIX *
1339 l_float32 scalex,
1340 l_float32 scaley)
1341{
1342l_int32 ws, hs, d, wpls, wd, hd, wpld;
1343l_uint32 *datas, *datad;
1344PIX *pixd;
1345
1346 PROCNAME("pixScaleBySampling");
1347
1348 if (!pixs)
1349 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1350 if (scalex <= 0.0 || scaley <= 0.0)
1351 return (PIX *)ERROR_PTR("scale factor <= 0", procName, NULL);
1352 if (scalex == 1.0 && scaley == 1.0)
1353 return pixCopy(NULL, pixs);
1354 if ((d = pixGetDepth(pixs)) == 1)
1355 return pixScaleBinary(pixs, scalex, scaley);
1356
1357 pixGetDimensions(pixs, &ws, &hs, NULL);
1358 datas = pixGetData(pixs);
1359 wpls = pixGetWpl(pixs);
1360 wd = (l_int32)(scalex * (l_float32)ws + 0.5);
1361 hd = (l_int32)(scaley * (l_float32)hs + 0.5);
1362 if ((pixd = pixCreate(wd, hd, d)) == NULL)
1363 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1364 pixCopyResolution(pixd, pixs);
1365 pixScaleResolution(pixd, scalex, scaley);
1366 pixCopyColormap(pixd, pixs);
1367 pixCopyText(pixd, pixs);
1368 pixCopyInputFormat(pixd, pixs);
1369 pixCopySpp(pixd, pixs);
1370 datad = pixGetData(pixd);
1371 wpld = pixGetWpl(pixd);
1372 scaleBySamplingLow(datad, wd, hd, wpld, datas, ws, hs, d, wpls);
1373 if (d == 32 && pixGetSpp(pixs) == 4)
1374 pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley);
1375
1376 return pixd;
1377}
1378
1379
1399PIX *
1401 l_int32 wd,
1402 l_int32 hd)
1403{
1404l_int32 w, h;
1405l_float32 scalex, scaley;
1406
1407 PROCNAME("pixScaleBySamplingToSize");
1408
1409 if (!pixs)
1410 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1411 if (wd <= 0 && hd <= 0)
1412 return (PIX *)ERROR_PTR("neither wd nor hd > 0", procName, NULL);
1413
1414 pixGetDimensions(pixs, &w, &h, NULL);
1415 if (wd <= 0) {
1416 scaley = (l_float32)hd / (l_float32)h;
1417 scalex = scaley;
1418 } else if (hd <= 0) {
1419 scalex = (l_float32)wd / (l_float32)w;
1420 scaley = scalex;
1421 } else {
1422 scalex = (l_float32)wd / (l_float32)w;
1423 scaley = (l_float32)hd / (l_float32)h;
1424 }
1425
1426 return pixScaleBySampling(pixs, scalex, scaley);
1427}
1428
1429
1443PIX *
1445 l_int32 factor)
1446{
1447l_float32 scale;
1448
1449 PROCNAME("pixScaleByIntSampling");
1450
1451 if (!pixs)
1452 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1453 if (factor <= 1) {
1454 if (factor < 1)
1455 L_ERROR("factor must be >= 1; returning a copy\n", procName);
1456 return pixCopy(NULL, pixs);
1457 }
1458
1459 scale = 1. / (l_float32)factor;
1460 return pixScaleBySampling(pixs, scale, scale);
1461}
1462
1463
1464/*------------------------------------------------------------------*
1465 * Fast integer factor subsampling RGB to gray *
1466 *------------------------------------------------------------------*/
1485PIX *
1487 l_int32 factor,
1488 l_int32 color)
1489{
1490l_int32 byteval, shift;
1491l_int32 i, j, ws, hs, wd, hd, wpls, wpld;
1492l_uint32 *datas, *words, *datad, *lined;
1493l_float32 scale;
1494PIX *pixd;
1495
1496 PROCNAME("pixScaleRGBToGrayFast");
1497
1498 if (!pixs)
1499 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1500 if (pixGetDepth(pixs) != 32)
1501 return (PIX *)ERROR_PTR("depth not 32 bpp", procName, NULL);
1502 if (factor < 1)
1503 return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
1504
1505 if (color == COLOR_RED)
1506 shift = L_RED_SHIFT;
1507 else if (color == COLOR_GREEN)
1508 shift = L_GREEN_SHIFT;
1509 else if (color == COLOR_BLUE)
1510 shift = L_BLUE_SHIFT;
1511 else
1512 return (PIX *)ERROR_PTR("invalid color", procName, NULL);
1513
1514 pixGetDimensions(pixs, &ws, &hs, NULL);
1515 datas = pixGetData(pixs);
1516 wpls = pixGetWpl(pixs);
1517
1518 wd = ws / factor;
1519 hd = hs / factor;
1520 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1521 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1522 pixCopyResolution(pixd, pixs);
1523 pixCopyInputFormat(pixd, pixs);
1524 scale = 1. / (l_float32) factor;
1525 pixScaleResolution(pixd, scale, scale);
1526 datad = pixGetData(pixd);
1527 wpld = pixGetWpl(pixd);
1528
1529 for (i = 0; i < hd; i++) {
1530 words = datas + i * factor * wpls;
1531 lined = datad + i * wpld;
1532 for (j = 0; j < wd; j++, words += factor) {
1533 byteval = ((*words) >> shift) & 0xff;
1534 SET_DATA_BYTE(lined, j, byteval);
1535 }
1536 }
1537
1538 return pixd;
1539}
1540
1541
1560PIX *
1562 l_int32 factor,
1563 l_int32 thresh)
1564{
1565l_int32 byteval;
1566l_int32 i, j, ws, hs, wd, hd, wpls, wpld;
1567l_uint32 *datas, *words, *datad, *lined;
1568l_float32 scale;
1569PIX *pixd;
1570
1571 PROCNAME("pixScaleRGBToBinaryFast");
1572
1573 if (!pixs)
1574 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1575 if (factor < 1)
1576 return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
1577 if (pixGetDepth(pixs) != 32)
1578 return (PIX *)ERROR_PTR("depth not 32 bpp", procName, NULL);
1579
1580 pixGetDimensions(pixs, &ws, &hs, NULL);
1581 datas = pixGetData(pixs);
1582 wpls = pixGetWpl(pixs);
1583
1584 wd = ws / factor;
1585 hd = hs / factor;
1586 if ((pixd = pixCreate(wd, hd, 1)) == NULL)
1587 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1588 pixCopyResolution(pixd, pixs);
1589 pixCopyInputFormat(pixd, pixs);
1590 scale = 1. / (l_float32) factor;
1591 pixScaleResolution(pixd, scale, scale);
1592 datad = pixGetData(pixd);
1593 wpld = pixGetWpl(pixd);
1594
1595 for (i = 0; i < hd; i++) {
1596 words = datas + i * factor * wpls;
1597 lined = datad + i * wpld;
1598 for (j = 0; j < wd; j++, words += factor) {
1599 byteval = ((*words) >> L_GREEN_SHIFT) & 0xff;
1600 if (byteval < thresh)
1601 SET_DATA_BIT(lined, j);
1602 }
1603 }
1604
1605 return pixd;
1606}
1607
1608
1626PIX *
1628 l_int32 factor,
1629 l_int32 thresh)
1630{
1631l_int32 byteval;
1632l_int32 i, j, ws, hs, wd, hd, wpls, wpld, sj;
1633l_uint32 *datas, *datad, *lines, *lined;
1634l_float32 scale;
1635PIX *pixd;
1636
1637 PROCNAME("pixScaleGrayToBinaryFast");
1638
1639 if (!pixs)
1640 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1641 if (factor < 1)
1642 return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
1643 if (pixGetDepth(pixs) != 8)
1644 return (PIX *)ERROR_PTR("depth not 8 bpp", procName, NULL);
1645
1646 pixGetDimensions(pixs, &ws, &hs, NULL);
1647 datas = pixGetData(pixs);
1648 wpls = pixGetWpl(pixs);
1649
1650 wd = ws / factor;
1651 hd = hs / factor;
1652 if ((pixd = pixCreate(wd, hd, 1)) == NULL)
1653 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1654 pixCopyResolution(pixd, pixs);
1655 pixCopyInputFormat(pixd, pixs);
1656 scale = 1. / (l_float32) factor;
1657 pixScaleResolution(pixd, scale, scale);
1658 datad = pixGetData(pixd);
1659 wpld = pixGetWpl(pixd);
1660
1661 for (i = 0; i < hd; i++) {
1662 lines = datas + i * factor * wpls;
1663 lined = datad + i * wpld;
1664 for (j = 0, sj = 0; j < wd; j++, sj += factor) {
1665 byteval = GET_DATA_BYTE(lines, sj);
1666 if (byteval < thresh)
1667 SET_DATA_BIT(lined, j);
1668 }
1669 }
1670
1671 return pixd;
1672}
1673
1674
1675/*------------------------------------------------------------------*
1676 * Downscaling with (antialias) smoothing *
1677 *------------------------------------------------------------------*/
1708PIX *
1710 l_float32 scalex,
1711 l_float32 scaley)
1712{
1713l_int32 ws, hs, d, wd, hd, wpls, wpld, isize;
1714l_uint32 val;
1715l_uint32 *datas, *datad;
1716l_float32 minscale, size;
1717PIX *pixs, *pixd;
1718
1719 PROCNAME("pixScaleSmooth");
1720
1721 if (!pix)
1722 return (PIX *)ERROR_PTR("pix not defined", procName, NULL);
1723 if (scalex >= 0.7 || scaley >= 0.7) {
1724 L_WARNING("scaling factor not < 0.7; do regular scaling\n", procName);
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", procName, 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", procName, 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.0 / 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", procName, 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", procName, 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 PROCNAME("pixScaleSmoothToSize");
1803
1804 if (!pixs)
1805 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1806 if (wd <= 0 && hd <= 0)
1807 return (PIX *)ERROR_PTR("neither wd nor hd > 0", procName, NULL);
1808
1809 pixGetDimensions(pixs, &w, &h, NULL);
1810 if (wd <= 0) {
1811 scaley = (l_float32)hd / (l_float32)h;
1812 scalex = scaley;
1813 } else if (hd <= 0) {
1814 scalex = (l_float32)wd / (l_float32)w;
1815 scaley = scalex;
1816 } else {
1817 scalex = (l_float32)wd / (l_float32)w;
1818 scaley = (l_float32)hd / (l_float32)h;
1819 }
1820
1821 return pixScaleSmooth(pixs, scalex, scaley);
1822}
1823
1824
1832PIX *
1834 l_float32 rwt,
1835 l_float32 gwt,
1836 l_float32 bwt)
1837{
1838l_int32 wd, hd, wpls, wpld;
1839l_uint32 *datas, *datad;
1840PIX *pixd;
1841
1842 PROCNAME("pixScaleRGBToGray2");
1843
1844 if (!pixs)
1845 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1846 if (pixGetDepth(pixs) != 32)
1847 return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
1848 if (rwt + gwt + bwt < 0.98 || rwt + gwt + bwt > 1.02)
1849 return (PIX *)ERROR_PTR("sum of wts should be 1.0", procName, NULL);
1850
1851 wd = pixGetWidth(pixs) / 2;
1852 hd = pixGetHeight(pixs) / 2;
1853 wpls = pixGetWpl(pixs);
1854 datas = pixGetData(pixs);
1855 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1856 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1857 pixCopyResolution(pixd, pixs);
1858 pixCopyInputFormat(pixd, pixs);
1859 pixScaleResolution(pixd, 0.5, 0.5);
1860 wpld = pixGetWpl(pixd);
1861 datad = pixGetData(pixd);
1862 scaleRGBToGray2Low(datad, wd, hd, wpld, datas, wpls, rwt, gwt, bwt);
1863 return pixd;
1864}
1865
1866
1867/*------------------------------------------------------------------*
1868 * Downscaling with (antialias) area mapping *
1869 *------------------------------------------------------------------*/
1913PIX *
1915 l_float32 scalex,
1916 l_float32 scaley)
1917{
1918l_int32 ws, hs, d, wd, hd, wpls, wpld;
1919l_uint32 *datas, *datad;
1920l_float32 maxscale, minscale;
1921PIX *pixs, *pixd, *pix1, *pix2, *pix3;
1922
1923 PROCNAME("pixScaleAreaMap");
1924
1925 if (!pix)
1926 return (PIX *)ERROR_PTR("pix not defined", procName, NULL);
1927 d = pixGetDepth(pix);
1928 if (d != 2 && d != 4 && d != 8 && d != 32)
1929 return (PIX *)ERROR_PTR("pix not 2, 4, 8 or 32 bpp", procName, NULL);
1930
1931 minscale = L_MIN(scalex, scaley);
1932 if (minscale < 0.02) { /* too small for area mapping */
1933 L_WARNING("tiny scaling factor; using pixScaleSmooth()\n", procName);
1934 return pixScaleSmooth(pix, scalex, scaley);
1935 }
1936
1937 maxscale = L_MAX(scalex, scaley);
1938 if (maxscale >= 0.7) { /* too large for area mapping */
1939 L_WARNING("scaling factor >= 0.7; do regular scaling\n", procName);
1940 return pixScaleGeneral(pix, scalex, scaley, 0.0, 0);
1941 }
1942
1943 /* Special cases: 2x, 4x, 8x, 16x reduction */
1944 if (scalex == 0.5 && scaley == 0.5)
1945 return pixScaleAreaMap2(pix);
1946 if (scalex == 0.25 && scaley == 0.25) {
1947 pix1 = pixScaleAreaMap2(pix);
1948 pixd = pixScaleAreaMap2(pix1);
1949 pixDestroy(&pix1);
1950 return pixd;
1951 }
1952 if (scalex == 0.125 && scaley == 0.125) {
1953 pix1 = pixScaleAreaMap2(pix);
1954 pix2 = pixScaleAreaMap2(pix1);
1955 pixd = pixScaleAreaMap2(pix2);
1956 pixDestroy(&pix1);
1957 pixDestroy(&pix2);
1958 return pixd;
1959 }
1960 if (scalex == 0.0625 && scaley == 0.0625) {
1961 pix1 = pixScaleAreaMap2(pix);
1962 pix2 = pixScaleAreaMap2(pix1);
1963 pix3 = pixScaleAreaMap2(pix2);
1964 pixd = pixScaleAreaMap2(pix3);
1965 pixDestroy(&pix1);
1966 pixDestroy(&pix2);
1967 pixDestroy(&pix3);
1968 return pixd;
1969 }
1970
1971#if 0 /* Not enabled because it breaks too many tests that rely on exact
1972 * pixel matches. */
1973 /* Special case where it is significantly faster to downscale first
1974 * by 2x, with relatively little degradation in image quality. */
1975 if (scalex > 0.35 && scalex < 0.5) {
1976 pix1 = pixScaleAreaMap2(pix);
1977 pixd = pixScaleAreaMap(pix1, 2.0 * scalex, 2.0 * scaley);
1978 pixDestroy(&pix1);
1979 return pixd;
1980 }
1981#endif
1982
1983 /* Remove colormap if necessary.
1984 * If 2 bpp or 4 bpp gray, convert to 8 bpp */
1985 if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
1986 L_WARNING("pix has colormap; removing\n", procName);
1988 d = pixGetDepth(pixs);
1989 } else if (d == 2 || d == 4) {
1990 pixs = pixConvertTo8(pix, FALSE);
1991 d = 8;
1992 } else {
1993 pixs = pixClone(pix);
1994 }
1995
1996 pixGetDimensions(pixs, &ws, &hs, NULL);
1997 datas = pixGetData(pixs);
1998 wpls = pixGetWpl(pixs);
1999 wd = (l_int32)(scalex * (l_float32)ws + 0.5);
2000 hd = (l_int32)(scaley * (l_float32)hs + 0.5);
2001 if (wd < 1 || hd < 1) {
2002 pixDestroy(&pixs);
2003 return (PIX *)ERROR_PTR("pixd too small", procName, NULL);
2004 }
2005 if ((pixd = pixCreate(wd, hd, d)) == NULL) {
2006 pixDestroy(&pixs);
2007 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2008 }
2009 pixCopyInputFormat(pixd, pixs);
2010 pixCopyResolution(pixd, pixs);
2011 pixScaleResolution(pixd, scalex, scaley);
2012 datad = pixGetData(pixd);
2013 wpld = pixGetWpl(pixd);
2014 if (d == 8) {
2015 scaleGrayAreaMapLow(datad, wd, hd, wpld, datas, ws, hs, wpls);
2016 } else { /* RGB, d == 32 */
2017 scaleColorAreaMapLow(datad, wd, hd, wpld, datas, ws, hs, wpls);
2018 if (pixGetSpp(pixs) == 4)
2019 pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley);
2020 }
2021
2022 pixDestroy(&pixs);
2023 return pixd;
2024}
2025
2026
2046PIX *
2048{
2049l_int32 wd, hd, d, wpls, wpld;
2050l_uint32 *datas, *datad;
2051PIX *pixs, *pixd;
2052
2053 PROCNAME("pixScaleAreaMap2");
2054
2055 if (!pix)
2056 return (PIX *)ERROR_PTR("pix not defined", procName, NULL);
2057 d = pixGetDepth(pix);
2058 if (d != 2 && d != 4 && d != 8 && d != 32)
2059 return (PIX *)ERROR_PTR("pix not 2, 4, 8 or 32 bpp", procName, NULL);
2060
2061 /* Remove colormap if necessary.
2062 * If 2 bpp or 4 bpp gray, convert to 8 bpp */
2063 if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
2064 L_WARNING("pix has colormap; removing\n", procName);
2066 d = pixGetDepth(pixs);
2067 } else if (d == 2 || d == 4) {
2068 pixs = pixConvertTo8(pix, FALSE);
2069 d = 8;
2070 } else {
2071 pixs = pixClone(pix);
2072 }
2073
2074 wd = pixGetWidth(pixs) / 2;
2075 hd = pixGetHeight(pixs) / 2;
2076 datas = pixGetData(pixs);
2077 wpls = pixGetWpl(pixs);
2078 pixd = pixCreate(wd, hd, d);
2079 datad = pixGetData(pixd);
2080 wpld = pixGetWpl(pixd);
2081 pixCopyInputFormat(pixd, pixs);
2082 pixCopyResolution(pixd, pixs);
2083 pixScaleResolution(pixd, 0.5, 0.5);
2084 scaleAreaMapLow2(datad, wd, hd, wpld, datas, d, wpls);
2085 if (pixGetSpp(pixs) == 4)
2086 pixScaleAndTransferAlpha(pixd, pixs, 0.5, 0.5);
2087 pixDestroy(&pixs);
2088 return pixd;
2089}
2090
2091
2111PIX *
2113 l_int32 wd,
2114 l_int32 hd)
2115{
2116l_int32 w, h;
2117l_float32 scalex, scaley;
2118
2119 PROCNAME("pixScaleAreaMapToSize");
2120
2121 if (!pixs)
2122 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2123 if (wd <= 0 && hd <= 0)
2124 return (PIX *)ERROR_PTR("neither wd nor hd > 0", procName, NULL);
2125
2126 pixGetDimensions(pixs, &w, &h, NULL);
2127 if (wd <= 0) {
2128 scaley = (l_float32)hd / (l_float32)h;
2129 scalex = scaley;
2130 } else if (hd <= 0) {
2131 scalex = (l_float32)wd / (l_float32)w;
2132 scaley = scalex;
2133 } else {
2134 scalex = (l_float32)wd / (l_float32)w;
2135 scaley = (l_float32)hd / (l_float32)h;
2136 }
2137
2138 return pixScaleAreaMap(pixs, scalex, scaley);
2139}
2140
2141
2142/*------------------------------------------------------------------*
2143 * Binary scaling by closest pixel sampling *
2144 *------------------------------------------------------------------*/
2160PIX *
2162 l_float32 scalex,
2163 l_float32 scaley)
2164{
2165l_int32 ws, hs, wpls, wd, hd, wpld;
2166l_uint32 *datas, *datad;
2167PIX *pixd;
2168
2169 PROCNAME("pixScaleBinary");
2170
2171 if (!pixs)
2172 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2173 if (pixGetDepth(pixs) != 1)
2174 return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, NULL);
2175 if (scalex <= 0.0 || scaley <= 0.0)
2176 return (PIX *)ERROR_PTR("scale factor <= 0", procName, NULL);
2177 if (scalex == 1.0 && scaley == 1.0)
2178 return pixCopy(NULL, pixs);
2179
2180 pixGetDimensions(pixs, &ws, &hs, NULL);
2181 datas = pixGetData(pixs);
2182 wpls = pixGetWpl(pixs);
2183 wd = (l_int32)(scalex * (l_float32)ws + 0.5);
2184 hd = (l_int32)(scaley * (l_float32)hs + 0.5);
2185 if ((pixd = pixCreate(wd, hd, 1)) == NULL)
2186 return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2187 pixCopyColormap(pixd, pixs);
2188 pixCopyText(pixd, pixs);
2189 pixCopyInputFormat(pixd, pixs);
2190 pixCopyResolution(pixd, pixs);
2191 pixScaleResolution(pixd, scalex, scaley);
2192 datad = pixGetData(pixd);
2193 wpld = pixGetWpl(pixd);
2194 scaleBinaryLow(datad, wd, hd, wpld, datas, ws, hs, wpls);
2195 return pixd;
2196}
2197
2198
2199/* ================================================================ *
2200 * Low level static functions *
2201 * ================================================================ */
2202
2203/*------------------------------------------------------------------*
2204 * General linear interpolated color scaling *
2205 *------------------------------------------------------------------*/
2218static void
2219scaleColorLILow(l_uint32 *datad,
2220 l_int32 wd,
2221 l_int32 hd,
2222 l_int32 wpld,
2223 l_uint32 *datas,
2224 l_int32 ws,
2225 l_int32 hs,
2226 l_int32 wpls)
2227{
2228l_int32 i, j, wm2, hm2;
2229l_int32 xpm, ypm; /* location in src image, to 1/16 of a pixel */
2230l_int32 xp, yp, xf, yf; /* src pixel and pixel fraction coordinates */
2231l_uint32 v00r, v01r, v10r, v11r, v00g, v01g, v10g, v11g;
2232l_uint32 v00b, v01b, v10b, v11b, area00, area01, area10, area11;
2233l_uint32 pixels1, pixels2, pixels3, pixels4, pixel;
2234l_uint32 *lines, *lined;
2235l_float32 scx, scy;
2236
2237 /* (scx, scy) are scaling factors that are applied to the
2238 * dest coords to get the corresponding src coords.
2239 * We need them because we iterate over dest pixels
2240 * and must find the corresponding set of src pixels. */
2241 scx = 16. * (l_float32)ws / (l_float32)wd;
2242 scy = 16. * (l_float32)hs / (l_float32)hd;
2243 wm2 = ws - 2;
2244 hm2 = hs - 2;
2245
2246 /* Iterate over the destination pixels */
2247 for (i = 0; i < hd; i++) {
2248 ypm = (l_int32)(scy * (l_float32)i);
2249 yp = ypm >> 4;
2250 yf = ypm & 0x0f;
2251 lined = datad + i * wpld;
2252 lines = datas + yp * wpls;
2253 for (j = 0; j < wd; j++) {
2254 xpm = (l_int32)(scx * (l_float32)j);
2255 xp = xpm >> 4;
2256 xf = xpm & 0x0f;
2257
2258 /* Do bilinear interpolation. This is a simple
2259 * generalization of the calculation in scaleGrayLILow().
2260 * Without this, we could simply subsample:
2261 * *(lined + j) = *(lines + xp);
2262 * which is faster but gives lousy results! */
2263 pixels1 = *(lines + xp);
2264
2265 if (xp > wm2 || yp > hm2) {
2266 if (yp > hm2 && xp <= wm2) { /* pixels near bottom */
2267 pixels2 = *(lines + xp + 1);
2268 pixels3 = pixels1;
2269 pixels4 = pixels2;
2270 } else if (xp > wm2 && yp <= hm2) { /* pixels near rt side */
2271 pixels2 = pixels1;
2272 pixels3 = *(lines + wpls + xp);
2273 pixels4 = pixels3;
2274 } else { /* pixels at LR corner */
2275 pixels4 = pixels3 = pixels2 = pixels1;
2276 }
2277 } else {
2278 pixels2 = *(lines + xp + 1);
2279 pixels3 = *(lines + wpls + xp);
2280 pixels4 = *(lines + wpls + xp + 1);
2281 }
2282
2283 area00 = (16 - xf) * (16 - yf);
2284 area10 = xf * (16 - yf);
2285 area01 = (16 - xf) * yf;
2286 area11 = xf * yf;
2287 v00r = area00 * ((pixels1 >> L_RED_SHIFT) & 0xff);
2288 v00g = area00 * ((pixels1 >> L_GREEN_SHIFT) & 0xff);
2289 v00b = area00 * ((pixels1 >> L_BLUE_SHIFT) & 0xff);
2290 v10r = area10 * ((pixels2 >> L_RED_SHIFT) & 0xff);
2291 v10g = area10 * ((pixels2 >> L_GREEN_SHIFT) & 0xff);
2292 v10b = area10 * ((pixels2 >> L_BLUE_SHIFT) & 0xff);
2293 v01r = area01 * ((pixels3 >> L_RED_SHIFT) & 0xff);
2294 v01g = area01 * ((pixels3 >> L_GREEN_SHIFT) & 0xff);
2295 v01b = area01 * ((pixels3 >> L_BLUE_SHIFT) & 0xff);
2296 v11r = area11 * ((pixels4 >> L_RED_SHIFT) & 0xff);
2297 v11g = area11 * ((pixels4 >> L_GREEN_SHIFT) & 0xff);
2298 v11b = area11 * ((pixels4 >> L_BLUE_SHIFT) & 0xff);
2299 pixel = (((v00r + v10r + v01r + v11r + 128) << 16) & 0xff000000) |
2300 (((v00g + v10g + v01g + v11g + 128) << 8) & 0x00ff0000) |
2301 ((v00b + v10b + v01b + v11b + 128) & 0x0000ff00);
2302 *(lined + j) = pixel;
2303 }
2304 }
2305}
2306
2307
2308/*------------------------------------------------------------------*
2309 * General linear interpolated gray scaling *
2310 *------------------------------------------------------------------*/
2323static void
2324scaleGrayLILow(l_uint32 *datad,
2325 l_int32 wd,
2326 l_int32 hd,
2327 l_int32 wpld,
2328 l_uint32 *datas,
2329 l_int32 ws,
2330 l_int32 hs,
2331 l_int32 wpls)
2332{
2333l_int32 i, j, wm2, hm2;
2334l_int32 xpm, ypm; /* location in src image, to 1/16 of a pixel */
2335l_int32 xp, yp, xf, yf; /* src pixel and pixel fraction coordinates */
2336l_int32 v00, v01, v10, v11, v00_val, v01_val, v10_val, v11_val;
2337l_uint8 val;
2338l_uint32 *lines, *lined;
2339l_float32 scx, scy;
2340
2341 /* (scx, scy) are scaling factors that are applied to the
2342 * dest coords to get the corresponding src coords.
2343 * We need them because we iterate over dest pixels
2344 * and must find the corresponding set of src pixels. */
2345 scx = 16. * (l_float32)ws / (l_float32)wd;
2346 scy = 16. * (l_float32)hs / (l_float32)hd;
2347 wm2 = ws - 2;
2348 hm2 = hs - 2;
2349
2350 /* Iterate over the destination pixels */
2351 for (i = 0; i < hd; i++) {
2352 ypm = (l_int32)(scy * (l_float32)i);
2353 yp = ypm >> 4;
2354 yf = ypm & 0x0f;
2355 lined = datad + i * wpld;
2356 lines = datas + yp * wpls;
2357 for (j = 0; j < wd; j++) {
2358 xpm = (l_int32)(scx * (l_float32)j);
2359 xp = xpm >> 4;
2360 xf = xpm & 0x0f;
2361
2362 /* Do bilinear interpolation. Without this, we could
2363 * simply subsample:
2364 * SET_DATA_BYTE(lined, j, GET_DATA_BYTE(lines, xp));
2365 * which is faster but gives lousy results! */
2366 v00_val = GET_DATA_BYTE(lines, xp);
2367 if (xp > wm2 || yp > hm2) {
2368 if (yp > hm2 && xp <= wm2) { /* pixels near bottom */
2369 v01_val = v00_val;
2370 v10_val = GET_DATA_BYTE(lines, xp + 1);
2371 v11_val = v10_val;
2372 } else if (xp > wm2 && yp <= hm2) { /* pixels near rt side */
2373 v01_val = GET_DATA_BYTE(lines + wpls, xp);
2374 v10_val = v00_val;
2375 v11_val = v01_val;
2376 } else { /* pixels at LR corner */
2377 v10_val = v01_val = v11_val = v00_val;
2378 }
2379 } else {
2380 v10_val = GET_DATA_BYTE(lines, xp + 1);
2381 v01_val = GET_DATA_BYTE(lines + wpls, xp);
2382 v11_val = GET_DATA_BYTE(lines + wpls, xp + 1);
2383 }
2384
2385 v00 = (16 - xf) * (16 - yf) * v00_val;
2386 v10 = xf * (16 - yf) * v10_val;
2387 v01 = (16 - xf) * yf * v01_val;
2388 v11 = xf * yf * v11_val;
2389
2390 val = (l_uint8)((v00 + v01 + v10 + v11 + 128) / 256);
2391 SET_DATA_BYTE(lined, j, val);
2392 }
2393 }
2394}
2395
2396
2397/*------------------------------------------------------------------*
2398 * 2x linear interpolated color scaling *
2399 *------------------------------------------------------------------*/
2440static void
2441scaleColor2xLILow(l_uint32 *datad,
2442 l_int32 wpld,
2443 l_uint32 *datas,
2444 l_int32 ws,
2445 l_int32 hs,
2446 l_int32 wpls)
2447{
2448l_int32 i, hsm;
2449l_uint32 *lines, *lined;
2450
2451 hsm = hs - 1;
2452
2453 /* We're taking 2 src and 2 dest lines at a time,
2454 * and for each src line, we're computing 2 dest lines.
2455 * Call these 2 dest lines: destline1 and destline2.
2456 * The first src line is used for destline 1.
2457 * On all but the last src line, both src lines are
2458 * used in the linear interpolation for destline2.
2459 * On the last src line, both destline1 and destline2
2460 * are computed using only that src line (because there
2461 * isn't a lower src line). */
2462
2463 /* iterate over all but the last src line */
2464 for (i = 0; i < hsm; i++) {
2465 lines = datas + i * wpls;
2466 lined = datad + 2 * i * wpld;
2467 scaleColor2xLILineLow(lined, wpld, lines, ws, wpls, 0);
2468 }
2469
2470 /* last src line */
2471 lines = datas + hsm * wpls;
2472 lined = datad + 2 * hsm * wpld;
2473 scaleColor2xLILineLow(lined, wpld, lines, ws, wpls, 1);
2474}
2475
2476
2488static void
2490 l_int32 wpld,
2491 l_uint32 *lines,
2492 l_int32 ws,
2493 l_int32 wpls,
2494 l_int32 lastlineflag)
2495{
2496l_int32 j, jd, wsm;
2497l_uint32 rval1, rval2, rval3, rval4, gval1, gval2, gval3, gval4;
2498l_uint32 bval1, bval2, bval3, bval4;
2499l_uint32 pixels1, pixels2, pixels3, pixels4, pixel;
2500l_uint32 *linesp, *linedp;
2501
2502 wsm = ws - 1;
2503
2504 if (lastlineflag == 0) {
2505 linesp = lines + wpls;
2506 linedp = lined + wpld;
2507 pixels1 = *lines;
2508 pixels3 = *linesp;
2509
2510 /* initialize with v(2) and v(4) */
2511 rval2 = pixels1 >> 24;
2512 gval2 = (pixels1 >> 16) & 0xff;
2513 bval2 = (pixels1 >> 8) & 0xff;
2514 rval4 = pixels3 >> 24;
2515 gval4 = (pixels3 >> 16) & 0xff;
2516 bval4 = (pixels3 >> 8) & 0xff;
2517
2518 for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
2519 /* shift in previous src values */
2520 rval1 = rval2;
2521 gval1 = gval2;
2522 bval1 = bval2;
2523 rval3 = rval4;
2524 gval3 = gval4;
2525 bval3 = bval4;
2526 /* get new src values */
2527 pixels2 = *(lines + j + 1);
2528 pixels4 = *(linesp + j + 1);
2529 rval2 = pixels2 >> 24;
2530 gval2 = (pixels2 >> 16) & 0xff;
2531 bval2 = (pixels2 >> 8) & 0xff;
2532 rval4 = pixels4 >> 24;
2533 gval4 = (pixels4 >> 16) & 0xff;
2534 bval4 = (pixels4 >> 8) & 0xff;
2535 /* save dest values */
2536 pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
2537 *(lined + jd) = pixel; /* pix 1 */
2538 pixel = ((((rval1 + rval2) << 23) & 0xff000000) |
2539 (((gval1 + gval2) << 15) & 0x00ff0000) |
2540 (((bval1 + bval2) << 7) & 0x0000ff00));
2541 *(lined + jd + 1) = pixel; /* pix 2 */
2542 pixel = ((((rval1 + rval3) << 23) & 0xff000000) |
2543 (((gval1 + gval3) << 15) & 0x00ff0000) |
2544 (((bval1 + bval3) << 7) & 0x0000ff00));
2545 *(linedp + jd) = pixel; /* pix 3 */
2546 pixel = ((((rval1 + rval2 + rval3 + rval4) << 22) & 0xff000000) |
2547 (((gval1 + gval2 + gval3 + gval4) << 14) & 0x00ff0000) |
2548 (((bval1 + bval2 + bval3 + bval4) << 6) & 0x0000ff00));
2549 *(linedp + jd + 1) = pixel; /* pix 4 */
2550 }
2551 /* last src pixel on line */
2552 rval1 = rval2;
2553 gval1 = gval2;
2554 bval1 = bval2;
2555 rval3 = rval4;
2556 gval3 = gval4;
2557 bval3 = bval4;
2558 pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
2559 *(lined + 2 * wsm) = pixel; /* pix 1 */
2560 *(lined + 2 * wsm + 1) = pixel; /* pix 2 */
2561 pixel = ((((rval1 + rval3) << 23) & 0xff000000) |
2562 (((gval1 + gval3) << 15) & 0x00ff0000) |
2563 (((bval1 + bval3) << 7) & 0x0000ff00));
2564 *(linedp + 2 * wsm) = pixel; /* pix 3 */
2565 *(linedp + 2 * wsm + 1) = pixel; /* pix 4 */
2566 } else { /* last row of src pixels: lastlineflag == 1 */
2567 linedp = lined + wpld;
2568 pixels2 = *lines;
2569 rval2 = pixels2 >> 24;
2570 gval2 = (pixels2 >> 16) & 0xff;
2571 bval2 = (pixels2 >> 8) & 0xff;
2572 for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
2573 rval1 = rval2;
2574 gval1 = gval2;
2575 bval1 = bval2;
2576 pixels2 = *(lines + j + 1);
2577 rval2 = pixels2 >> 24;
2578 gval2 = (pixels2 >> 16) & 0xff;
2579 bval2 = (pixels2 >> 8) & 0xff;
2580 pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
2581 *(lined + jd) = pixel; /* pix 1 */
2582 *(linedp + jd) = pixel; /* pix 2 */
2583 pixel = ((((rval1 + rval2) << 23) & 0xff000000) |
2584 (((gval1 + gval2) << 15) & 0x00ff0000) |
2585 (((bval1 + bval2) << 7) & 0x0000ff00));
2586 *(lined + jd + 1) = pixel; /* pix 3 */
2587 *(linedp + jd + 1) = pixel; /* pix 4 */
2588 }
2589 rval1 = rval2;
2590 gval1 = gval2;
2591 bval1 = bval2;
2592 pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
2593 *(lined + 2 * wsm) = pixel; /* pix 1 */
2594 *(lined + 2 * wsm + 1) = pixel; /* pix 2 */
2595 *(linedp + 2 * wsm) = pixel; /* pix 3 */
2596 *(linedp + 2 * wsm + 1) = pixel; /* pix 4 */
2597 }
2598}
2599
2600
2601/*------------------------------------------------------------------*
2602 * 2x linear interpolated gray scaling *
2603 *------------------------------------------------------------------*/
2642static void
2643scaleGray2xLILow(l_uint32 *datad,
2644 l_int32 wpld,
2645 l_uint32 *datas,
2646 l_int32 ws,
2647 l_int32 hs,
2648 l_int32 wpls)
2649{
2650l_int32 i, hsm;
2651l_uint32 *lines, *lined;
2652
2653 hsm = hs - 1;
2654
2655 /* We're taking 2 src and 2 dest lines at a time,
2656 * and for each src line, we're computing 2 dest lines.
2657 * Call these 2 dest lines: destline1 and destline2.
2658 * The first src line is used for destline 1.
2659 * On all but the last src line, both src lines are
2660 * used in the linear interpolation for destline2.
2661 * On the last src line, both destline1 and destline2
2662 * are computed using only that src line (because there
2663 * isn't a lower src line). */
2664
2665 /* iterate over all but the last src line */
2666 for (i = 0; i < hsm; i++) {
2667 lines = datas + i * wpls;
2668 lined = datad + 2 * i * wpld;
2669 scaleGray2xLILineLow(lined, wpld, lines, ws, wpls, 0);
2670 }
2671
2672 /* last src line */
2673 lines = datas + hsm * wpls;
2674 lined = datad + 2 * hsm * wpld;
2675 scaleGray2xLILineLow(lined, wpld, lines, ws, wpls, 1);
2676}
2677
2678
2690static void
2691scaleGray2xLILineLow(l_uint32 *lined,
2692 l_int32 wpld,
2693 l_uint32 *lines,
2694 l_int32 ws,
2695 l_int32 wpls,
2696 l_int32 lastlineflag)
2697{
2698l_int32 j, jd, wsm, w;
2699l_uint32 sval1, sval2, sval3, sval4;
2700l_uint32 *linesp, *linedp;
2701l_uint32 words, wordsp, wordd, worddp;
2702
2703 wsm = ws - 1;
2704
2705 if (lastlineflag == 0) {
2706 linesp = lines + wpls;
2707 linedp = lined + wpld;
2708
2709 /* Unroll the loop 4x and work on full words */
2710 words = lines[0];
2711 wordsp = linesp[0];
2712 sval2 = (words >> 24) & 0xff;
2713 sval4 = (wordsp >> 24) & 0xff;
2714 for (j = 0, jd = 0, w = 0; j + 3 < wsm; j += 4, jd += 8, w++) {
2715 /* At the top of the loop,
2716 * words == lines[w], wordsp == linesp[w]
2717 * and the top bytes of those have been loaded into
2718 * sval2 and sval4. */
2719 sval1 = sval2;
2720 sval2 = (words >> 16) & 0xff;
2721 sval3 = sval4;
2722 sval4 = (wordsp >> 16) & 0xff;
2723 wordd = (sval1 << 24) | (((sval1 + sval2) >> 1) << 16);
2724 worddp = (((sval1 + sval3) >> 1) << 24) |
2725 (((sval1 + sval2 + sval3 + sval4) >> 2) << 16);
2726
2727 sval1 = sval2;
2728 sval2 = (words >> 8) & 0xff;
2729 sval3 = sval4;
2730 sval4 = (wordsp >> 8) & 0xff;
2731 wordd |= (sval1 << 8) | ((sval1 + sval2) >> 1);
2732 worddp |= (((sval1 + sval3) >> 1) << 8) |
2733 ((sval1 + sval2 + sval3 + sval4) >> 2);
2734 lined[w * 2] = wordd;
2735 linedp[w * 2] = worddp;
2736
2737 sval1 = sval2;
2738 sval2 = words & 0xff;
2739 sval3 = sval4;
2740 sval4 = wordsp & 0xff;
2741 wordd = (sval1 << 24) | /* pix 1 */
2742 (((sval1 + sval2) >> 1) << 16); /* pix 2 */
2743 worddp = (((sval1 + sval3) >> 1) << 24) | /* pix 3 */
2744 (((sval1 + sval2 + sval3 + sval4) >> 2) << 16); /* pix 4 */
2745
2746 /* Load the next word as we need its first byte */
2747 words = lines[w + 1];
2748 wordsp = linesp[w + 1];
2749 sval1 = sval2;
2750 sval2 = (words >> 24) & 0xff;
2751 sval3 = sval4;
2752 sval4 = (wordsp >> 24) & 0xff;
2753 wordd |= (sval1 << 8) | /* pix 1 */
2754 ((sval1 + sval2) >> 1); /* pix 2 */
2755 worddp |= (((sval1 + sval3) >> 1) << 8) | /* pix 3 */
2756 ((sval1 + sval2 + sval3 + sval4) >> 2); /* pix 4 */
2757 lined[w * 2 + 1] = wordd;
2758 linedp[w * 2 + 1] = worddp;
2759 }
2760
2761 /* Finish up the last word */
2762 for (; j < wsm; j++, jd += 2) {
2763 sval1 = sval2;
2764 sval3 = sval4;
2765 sval2 = GET_DATA_BYTE(lines, j + 1);
2766 sval4 = GET_DATA_BYTE(linesp, j + 1);
2767 SET_DATA_BYTE(lined, jd, sval1); /* pix 1 */
2768 SET_DATA_BYTE(lined, jd + 1, (sval1 + sval2) / 2); /* pix 2 */
2769 SET_DATA_BYTE(linedp, jd, (sval1 + sval3) / 2); /* pix 3 */
2770 SET_DATA_BYTE(linedp, jd + 1,
2771 (sval1 + sval2 + sval3 + sval4) / 4); /* pix 4 */
2772 }
2773 sval1 = sval2;
2774 sval3 = sval4;
2775 SET_DATA_BYTE(lined, 2 * wsm, sval1); /* pix 1 */
2776 SET_DATA_BYTE(lined, 2 * wsm + 1, sval1); /* pix 2 */
2777 SET_DATA_BYTE(linedp, 2 * wsm, (sval1 + sval3) / 2); /* pix 3 */
2778 SET_DATA_BYTE(linedp, 2 * wsm + 1, (sval1 + sval3) / 2); /* pix 4 */
2779
2780#if DEBUG_UNROLLING
2781#define CHECK_BYTE(a, b, c) if (GET_DATA_BYTE(a, b) != c) {\
2782 lept_stderr("Error: mismatch at %d, %d vs %d\n", \
2783 j, GET_DATA_BYTE(a, b), c); }
2784
2785 sval2 = GET_DATA_BYTE(lines, 0);
2786 sval4 = GET_DATA_BYTE(linesp, 0);
2787 for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
2788 sval1 = sval2;
2789 sval3 = sval4;
2790 sval2 = GET_DATA_BYTE(lines, j + 1);
2791 sval4 = GET_DATA_BYTE(linesp, j + 1);
2792 CHECK_BYTE(lined, jd, sval1); /* pix 1 */
2793 CHECK_BYTE(lined, jd + 1, (sval1 + sval2) / 2); /* pix 2 */
2794 CHECK_BYTE(linedp, jd, (sval1 + sval3) / 2); /* pix 3 */
2795 CHECK_BYTE(linedp, jd + 1,
2796 (sval1 + sval2 + sval3 + sval4) / 4); /* pix 4 */
2797 }
2798 sval1 = sval2;
2799 sval3 = sval4;
2800 CHECK_BYTE(lined, 2 * wsm, sval1); /* pix 1 */
2801 CHECK_BYTE(lined, 2 * wsm + 1, sval1); /* pix 2 */
2802 CHECK_BYTE(linedp, 2 * wsm, (sval1 + sval3) / 2); /* pix 3 */
2803 CHECK_BYTE(linedp, 2 * wsm + 1, (sval1 + sval3) / 2); /* pix 4 */
2804#undef CHECK_BYTE
2805#endif
2806 } else { /* last row of src pixels: lastlineflag == 1 */
2807 linedp = lined + wpld;
2808 sval2 = GET_DATA_BYTE(lines, 0);
2809 for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
2810 sval1 = sval2;
2811 sval2 = GET_DATA_BYTE(lines, j + 1);
2812 SET_DATA_BYTE(lined, jd, sval1); /* pix 1 */
2813 SET_DATA_BYTE(linedp, jd, sval1); /* pix 3 */
2814 SET_DATA_BYTE(lined, jd + 1, (sval1 + sval2) / 2); /* pix 2 */
2815 SET_DATA_BYTE(linedp, jd + 1, (sval1 + sval2) / 2); /* pix 4 */
2816 }
2817 sval1 = sval2;
2818 SET_DATA_BYTE(lined, 2 * wsm, sval1); /* pix 1 */
2819 SET_DATA_BYTE(lined, 2 * wsm + 1, sval1); /* pix 2 */
2820 SET_DATA_BYTE(linedp, 2 * wsm, sval1); /* pix 3 */
2821 SET_DATA_BYTE(linedp, 2 * wsm + 1, sval1); /* pix 4 */
2822 }
2823}
2824
2825
2826/*------------------------------------------------------------------*
2827 * 4x linear interpolated gray scaling *
2828 *------------------------------------------------------------------*/
2883static void
2884scaleGray4xLILow(l_uint32 *datad,
2885 l_int32 wpld,
2886 l_uint32 *datas,
2887 l_int32 ws,
2888 l_int32 hs,
2889 l_int32 wpls)
2890{
2891l_int32 i, hsm;
2892l_uint32 *lines, *lined;
2893
2894 hsm = hs - 1;
2895
2896 /* We're taking 2 src and 4 dest lines at a time,
2897 * and for each src line, we're computing 4 dest lines.
2898 * Call these 4 dest lines: destline1 - destline4.
2899 * The first src line is used for destline 1.
2900 * Two src lines are used for all other dest lines,
2901 * except for the last 4 dest lines, which are computed
2902 * using only the last src line. */
2903
2904 /* iterate over all but the last src line */
2905 for (i = 0; i < hsm; i++) {
2906 lines = datas + i * wpls;
2907 lined = datad + 4 * i * wpld;
2908 scaleGray4xLILineLow(lined, wpld, lines, ws, wpls, 0);
2909 }
2910
2911 /* last src line */
2912 lines = datas + hsm * wpls;
2913 lined = datad + 4 * hsm * wpld;
2914 scaleGray4xLILineLow(lined, wpld, lines, ws, wpls, 1);
2915}
2916
2917
2929static void
2930scaleGray4xLILineLow(l_uint32 *lined,
2931 l_int32 wpld,
2932 l_uint32 *lines,
2933 l_int32 ws,
2934 l_int32 wpls,
2935 l_int32 lastlineflag)
2936{
2937l_int32 j, jd, wsm, wsm4;
2938l_int32 s1, s2, s3, s4, s1t, s2t, s3t, s4t;
2939l_uint32 *linesp, *linedp1, *linedp2, *linedp3;
2940
2941 wsm = ws - 1;
2942 wsm4 = 4 * wsm;
2943
2944 if (lastlineflag == 0) {
2945 linesp = lines + wpls;
2946 linedp1 = lined + wpld;
2947 linedp2 = lined + 2 * wpld;
2948 linedp3 = lined + 3 * wpld;
2949 s2 = GET_DATA_BYTE(lines, 0);
2950 s4 = GET_DATA_BYTE(linesp, 0);
2951 for (j = 0, jd = 0; j < wsm; j++, jd += 4) {
2952 s1 = s2;
2953 s3 = s4;
2954 s2 = GET_DATA_BYTE(lines, j + 1);
2955 s4 = GET_DATA_BYTE(linesp, j + 1);
2956 s1t = 3 * s1;
2957 s2t = 3 * s2;
2958 s3t = 3 * s3;
2959 s4t = 3 * s4;
2960 SET_DATA_BYTE(lined, jd, s1); /* d1 */
2961 SET_DATA_BYTE(lined, jd + 1, (s1t + s2) / 4); /* d2 */
2962 SET_DATA_BYTE(lined, jd + 2, (s1 + s2) / 2); /* d3 */
2963 SET_DATA_BYTE(lined, jd + 3, (s1 + s2t) / 4); /* d4 */
2964 SET_DATA_BYTE(linedp1, jd, (s1t + s3) / 4); /* d5 */
2965 SET_DATA_BYTE(linedp1, jd + 1, (9*s1 + s2t + s3t + s4) / 16); /*d6*/
2966 SET_DATA_BYTE(linedp1, jd + 2, (s1t + s2t + s3 + s4) / 8); /* d7 */
2967 SET_DATA_BYTE(linedp1, jd + 3, (s1t + 9*s2 + s3 + s4t) / 16);/*d8*/
2968 SET_DATA_BYTE(linedp2, jd, (s1 + s3) / 2); /* d9 */
2969 SET_DATA_BYTE(linedp2, jd + 1, (s1t + s2 + s3t + s4) / 8);/* d10 */
2970 SET_DATA_BYTE(linedp2, jd + 2, (s1 + s2 + s3 + s4) / 4); /* d11 */
2971 SET_DATA_BYTE(linedp2, jd + 3, (s1 + s2t + s3 + s4t) / 8);/* d12 */
2972 SET_DATA_BYTE(linedp3, jd, (s1 + s3t) / 4); /* d13 */
2973 SET_DATA_BYTE(linedp3, jd + 1, (s1t + s2 + 9*s3 + s4t) / 16);/*d14*/
2974 SET_DATA_BYTE(linedp3, jd + 2, (s1 + s2 + s3t + s4t) / 8); /* d15 */
2975 SET_DATA_BYTE(linedp3, jd + 3, (s1 + s2t + s3t + 9*s4) / 16);/*d16*/
2976 }
2977 s1 = s2;
2978 s3 = s4;
2979 s1t = 3 * s1;
2980 s3t = 3 * s3;
2981 SET_DATA_BYTE(lined, wsm4, s1); /* d1 */
2982 SET_DATA_BYTE(lined, wsm4 + 1, s1); /* d2 */
2983 SET_DATA_BYTE(lined, wsm4 + 2, s1); /* d3 */
2984 SET_DATA_BYTE(lined, wsm4 + 3, s1); /* d4 */
2985 SET_DATA_BYTE(linedp1, wsm4, (s1t + s3) / 4); /* d5 */
2986 SET_DATA_BYTE(linedp1, wsm4 + 1, (s1t + s3) / 4); /* d6 */
2987 SET_DATA_BYTE(linedp1, wsm4 + 2, (s1t + s3) / 4); /* d7 */
2988 SET_DATA_BYTE(linedp1, wsm4 + 3, (s1t + s3) / 4); /* d8 */
2989 SET_DATA_BYTE(linedp2, wsm4, (s1 + s3) / 2); /* d9 */
2990 SET_DATA_BYTE(linedp2, wsm4 + 1, (s1 + s3) / 2); /* d10 */
2991 SET_DATA_BYTE(linedp2, wsm4 + 2, (s1 + s3) / 2); /* d11 */
2992 SET_DATA_BYTE(linedp2, wsm4 + 3, (s1 + s3) / 2); /* d12 */
2993 SET_DATA_BYTE(linedp3, wsm4, (s1 + s3t) / 4); /* d13 */
2994 SET_DATA_BYTE(linedp3, wsm4 + 1, (s1 + s3t) / 4); /* d14 */
2995 SET_DATA_BYTE(linedp3, wsm4 + 2, (s1 + s3t) / 4); /* d15 */
2996 SET_DATA_BYTE(linedp3, wsm4 + 3, (s1 + s3t) / 4); /* d16 */
2997 } else { /* last row of src pixels: lastlineflag == 1 */
2998 linedp1 = lined + wpld;
2999 linedp2 = lined + 2 * wpld;
3000 linedp3 = lined + 3 * wpld;
3001 s2 = GET_DATA_BYTE(lines, 0);
3002 for (j = 0, jd = 0; j < wsm; j++, jd += 4) {
3003 s1 = s2;
3004 s2 = GET_DATA_BYTE(lines, j + 1);
3005 s1t = 3 * s1;
3006 s2t = 3 * s2;
3007 SET_DATA_BYTE(lined, jd, s1); /* d1 */
3008 SET_DATA_BYTE(lined, jd + 1, (s1t + s2) / 4 ); /* d2 */
3009 SET_DATA_BYTE(lined, jd + 2, (s1 + s2) / 2 ); /* d3 */
3010 SET_DATA_BYTE(lined, jd + 3, (s1 + s2t) / 4 ); /* d4 */
3011 SET_DATA_BYTE(linedp1, jd, s1); /* d5 */
3012 SET_DATA_BYTE(linedp1, jd + 1, (s1t + s2) / 4 ); /* d6 */
3013 SET_DATA_BYTE(linedp1, jd + 2, (s1 + s2) / 2 ); /* d7 */
3014 SET_DATA_BYTE(linedp1, jd + 3, (s1 + s2t) / 4 ); /* d8 */
3015 SET_DATA_BYTE(linedp2, jd, s1); /* d9 */
3016 SET_DATA_BYTE(linedp2, jd + 1, (s1t + s2) / 4 ); /* d10 */
3017 SET_DATA_BYTE(linedp2, jd + 2, (s1 + s2) / 2 ); /* d11 */
3018 SET_DATA_BYTE(linedp2, jd + 3, (s1 + s2t) / 4 ); /* d12 */
3019 SET_DATA_BYTE(linedp3, jd, s1); /* d13 */
3020 SET_DATA_BYTE(linedp3, jd + 1, (s1t + s2) / 4 ); /* d14 */
3021 SET_DATA_BYTE(linedp3, jd + 2, (s1 + s2) / 2 ); /* d15 */
3022 SET_DATA_BYTE(linedp3, jd + 3, (s1 + s2t) / 4 ); /* d16 */
3023 }
3024 s1 = s2;
3025 SET_DATA_BYTE(lined, wsm4, s1); /* d1 */
3026 SET_DATA_BYTE(lined, wsm4 + 1, s1); /* d2 */
3027 SET_DATA_BYTE(lined, wsm4 + 2, s1); /* d3 */
3028 SET_DATA_BYTE(lined, wsm4 + 3, s1); /* d4 */
3029 SET_DATA_BYTE(linedp1, wsm4, s1); /* d5 */
3030 SET_DATA_BYTE(linedp1, wsm4 + 1, s1); /* d6 */
3031 SET_DATA_BYTE(linedp1, wsm4 + 2, s1); /* d7 */
3032 SET_DATA_BYTE(linedp1, wsm4 + 3, s1); /* d8 */
3033 SET_DATA_BYTE(linedp2, wsm4, s1); /* d9 */
3034 SET_DATA_BYTE(linedp2, wsm4 + 1, s1); /* d10 */
3035 SET_DATA_BYTE(linedp2, wsm4 + 2, s1); /* d11 */
3036 SET_DATA_BYTE(linedp2, wsm4 + 3, s1); /* d12 */
3037 SET_DATA_BYTE(linedp3, wsm4, s1); /* d13 */
3038 SET_DATA_BYTE(linedp3, wsm4 + 1, s1); /* d14 */
3039 SET_DATA_BYTE(linedp3, wsm4 + 2, s1); /* d15 */
3040 SET_DATA_BYTE(linedp3, wsm4 + 3, s1); /* d16 */
3041 }
3042}
3043
3044
3045/*------------------------------------------------------------------*
3046 * Grayscale and color scaling by closest pixel sampling *
3047 *------------------------------------------------------------------*/
3063static l_int32
3064scaleBySamplingLow(l_uint32 *datad,
3065 l_int32 wd,
3066 l_int32 hd,
3067 l_int32 wpld,
3068 l_uint32 *datas,
3069 l_int32 ws,
3070 l_int32 hs,
3071 l_int32 d,
3072 l_int32 wpls)
3073{
3074l_int32 i, j;
3075l_int32 xs, prevxs, sval;
3076l_int32 *srow, *scol;
3077l_uint32 csval;
3078l_uint32 *lines, *prevlines, *lined, *prevlined;
3079l_float32 wratio, hratio;
3080
3081 PROCNAME("scaleBySamplingLow");
3082
3083 if (d != 2 && d != 4 && d !=8 && d != 16 && d != 32)
3084 return ERROR_INT("pixel depth not supported", procName, 1);
3085
3086 /* Clear dest */
3087 memset(datad, 0, 4LL * hd * wpld);
3088
3089 /* the source row corresponding to dest row i ==> srow[i]
3090 * the source col corresponding to dest col j ==> scol[j] */
3091 if ((srow = (l_int32 *)LEPT_CALLOC(hd, sizeof(l_int32))) == NULL)
3092 return ERROR_INT("srow not made", procName, 1);
3093 if ((scol = (l_int32 *)LEPT_CALLOC(wd, sizeof(l_int32))) == NULL) {
3094 LEPT_FREE(srow);
3095 return ERROR_INT("scol not made", procName, 1);
3096 }
3097
3098 wratio = (l_float32)ws / (l_float32)wd;
3099 hratio = (l_float32)hs / (l_float32)hd;
3100 for (i = 0; i < hd; i++)
3101 srow[i] = L_MIN((l_int32)(hratio * i + 0.5), hs - 1);
3102 for (j = 0; j < wd; j++)
3103 scol[j] = L_MIN((l_int32)(wratio * j + 0.5), ws - 1);
3104
3105 prevlines = NULL;
3106 for (i = 0; i < hd; i++) {
3107 lines = datas + srow[i] * wpls;
3108 lined = datad + i * wpld;
3109 if (lines != prevlines) { /* make dest from new source row */
3110 prevxs = -1;
3111 sval = 0;
3112 csval = 0;
3113 if (d == 2) {
3114 for (j = 0; j < wd; j++) {
3115 xs = scol[j];
3116 if (xs != prevxs) { /* get dest pix from source col */
3117 sval = GET_DATA_DIBIT(lines, xs);
3118 SET_DATA_DIBIT(lined, j, sval);
3119 prevxs = xs;
3120 } else { /* copy prev dest pix */
3121 SET_DATA_DIBIT(lined, j, sval);
3122 }
3123 }
3124 } else if (d == 4) {
3125 for (j = 0; j < wd; j++) {
3126 xs = scol[j];
3127 if (xs != prevxs) { /* get dest pix from source col */
3128 sval = GET_DATA_QBIT(lines, xs);
3129 SET_DATA_QBIT(lined, j, sval);
3130 prevxs = xs;
3131 } else { /* copy prev dest pix */
3132 SET_DATA_QBIT(lined, j, sval);
3133 }
3134 }
3135 } else if (d == 8) {
3136 for (j = 0; j < wd; j++) {
3137 xs = scol[j];
3138 if (xs != prevxs) { /* get dest pix from source col */
3139 sval = GET_DATA_BYTE(lines, xs);
3140 SET_DATA_BYTE(lined, j, sval);
3141 prevxs = xs;
3142 } else { /* copy prev dest pix */
3143 SET_DATA_BYTE(lined, j, sval);
3144 }
3145 }
3146 } else if (d == 16) {
3147 for (j = 0; j < wd; j++) {
3148 xs = scol[j];
3149 if (xs != prevxs) { /* get dest pix from source col */
3150 sval = GET_DATA_TWO_BYTES(lines, xs);
3151 SET_DATA_TWO_BYTES(lined, j, sval);
3152 prevxs = xs;
3153 } else { /* copy prev dest pix */
3154 SET_DATA_TWO_BYTES(lined, j, sval);
3155 }
3156 }
3157 } else { /* d == 32 */
3158 for (j = 0; j < wd; j++) {
3159 xs = scol[j];
3160 if (xs != prevxs) { /* get dest pix from source col */
3161 csval = lines[xs];
3162 lined[j] = csval;
3163 prevxs = xs;
3164 } else { /* copy prev dest pix */
3165 lined[j] = csval;
3166 }
3167 }
3168 }
3169 } else { /* lines == prevlines; copy prev dest row */
3170 prevlined = lined - wpld;
3171 memcpy(lined, prevlined, 4 * wpld);
3172 }
3173 prevlines = lines;
3174 }
3175
3176 LEPT_FREE(srow);
3177 LEPT_FREE(scol);
3178 return 0;
3179}
3180
3181
3182/*------------------------------------------------------------------*
3183 * Color and grayscale downsampling with (antialias) smoothing *
3184 *------------------------------------------------------------------*/
3196static l_int32
3197scaleSmoothLow(l_uint32 *datad,
3198 l_int32 wd,
3199 l_int32 hd,
3200 l_int32 wpld,
3201 l_uint32 *datas,
3202 l_int32 ws,
3203 l_int32 hs,
3204 l_int32 d,
3205 l_int32 wpls,
3206 l_int32 size)
3207{
3208l_int32 i, j, m, n, xstart;
3209l_int32 val, rval, gval, bval;
3210l_int32 *srow, *scol;
3211l_uint32 *lines, *lined, *line, *ppixel;
3212l_uint32 pixel;
3213l_float32 wratio, hratio, norm;
3214
3215 PROCNAME("scaleSmoothLow");
3216
3217 /* Clear dest */
3218 memset(datad, 0, 4LL * wpld * hd);
3219
3220 /* Each dest pixel at (j,i) is computed as the average
3221 of size^2 corresponding src pixels.
3222 We store the UL corner location of the square of
3223 src pixels that correspond to dest pixel (j,i).
3224 The are labeled by the arrays srow[i] and scol[j]. */
3225 if ((srow = (l_int32 *)LEPT_CALLOC(hd, sizeof(l_int32))) == NULL)
3226 return ERROR_INT("srow not made", procName, 1);
3227 if ((scol = (l_int32 *)LEPT_CALLOC(wd, sizeof(l_int32))) == NULL) {
3228 LEPT_FREE(srow);
3229 return ERROR_INT("scol not made", procName, 1);
3230 }
3231
3232 norm = 1. / (l_float32)(size * size);
3233 wratio = (l_float32)ws / (l_float32)wd;
3234 hratio = (l_float32)hs / (l_float32)hd;
3235 for (i = 0; i < hd; i++)
3236 srow[i] = L_MIN((l_int32)(hratio * i), hs - size);
3237 for (j = 0; j < wd; j++)
3238 scol[j] = L_MIN((l_int32)(wratio * j), ws - size);
3239
3240 /* For each dest pixel, compute average */
3241 if (d == 8) {
3242 for (i = 0; i < hd; i++) {
3243 lines = datas + srow[i] * wpls;
3244 lined = datad + i * wpld;
3245 for (j = 0; j < wd; j++) {
3246 xstart = scol[j];
3247 val = 0;
3248 for (m = 0; m < size; m++) {
3249 line = lines + m * wpls;
3250 for (n = 0; n < size; n++) {
3251 val += GET_DATA_BYTE(line, xstart + n);
3252 }
3253 }
3254 val = (l_int32)((l_float32)val * norm);
3255 SET_DATA_BYTE(lined, j, val);
3256 }
3257 }
3258 } else { /* d == 32 */
3259 for (i = 0; i < hd; i++) {
3260 lines = datas + srow[i] * wpls;
3261 lined = datad + i * wpld;
3262 for (j = 0; j < wd; j++) {
3263 xstart = scol[j];
3264 rval = gval = bval = 0;
3265 for (m = 0; m < size; m++) {
3266 ppixel = lines + m * wpls + xstart;
3267 for (n = 0; n < size; n++) {
3268 pixel = *(ppixel + n);
3269 rval += (pixel >> L_RED_SHIFT) & 0xff;
3270 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3271 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3272 }
3273 }
3274 rval = (l_int32)((l_float32)rval * norm);
3275 gval = (l_int32)((l_float32)gval * norm);
3276 bval = (l_int32)((l_float32)bval * norm);
3277 composeRGBPixel(rval, gval, bval, lined + j);
3278 }
3279 }
3280 }
3281
3282 LEPT_FREE(srow);
3283 LEPT_FREE(scol);
3284 return 0;
3285}
3286
3287
3297static void
3298scaleRGBToGray2Low(l_uint32 *datad,
3299 l_int32 wd,
3300 l_int32 hd,
3301 l_int32 wpld,
3302 l_uint32 *datas,
3303 l_int32 wpls,
3304 l_float32 rwt,
3305 l_float32 gwt,
3306 l_float32 bwt)
3307{
3308l_int32 i, j, val, rval, gval, bval;
3309l_uint32 *lines, *lined;
3310l_uint32 pixel;
3311
3312 rwt *= 0.25;
3313 gwt *= 0.25;
3314 bwt *= 0.25;
3315 for (i = 0; i < hd; i++) {
3316 lines = datas + 2 * i * wpls;
3317 lined = datad + i * wpld;
3318 for (j = 0; j < wd; j++) {
3319 /* Sum each of the color components from 4 src pixels */
3320 pixel = *(lines + 2 * j);
3321 rval = (pixel >> L_RED_SHIFT) & 0xff;
3322 gval = (pixel >> L_GREEN_SHIFT) & 0xff;
3323 bval = (pixel >> L_BLUE_SHIFT) & 0xff;
3324 pixel = *(lines + 2 * j + 1);
3325 rval += (pixel >> L_RED_SHIFT) & 0xff;
3326 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3327 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3328 pixel = *(lines + wpls + 2 * j);
3329 rval += (pixel >> L_RED_SHIFT) & 0xff;
3330 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3331 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3332 pixel = *(lines + wpls + 2 * j + 1);
3333 rval += (pixel >> L_RED_SHIFT) & 0xff;
3334 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3335 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3336 /* Generate the dest byte as a weighted sum of the averages */
3337 val = (l_int32)(rwt * rval + gwt * gval + bwt * bval);
3338 SET_DATA_BYTE(lined, j, val);
3339 }
3340 }
3341}
3342
3343
3344/*------------------------------------------------------------------*
3345 * General area mapped gray scaling *
3346 *------------------------------------------------------------------*/
3362static void
3363scaleColorAreaMapLow(l_uint32 *datad,
3364 l_int32 wd,
3365 l_int32 hd,
3366 l_int32 wpld,
3367 l_uint32 *datas,
3368 l_int32 ws,
3369 l_int32 hs,
3370 l_int32 wpls)
3371{
3372l_int32 i, j, k, m, wm2, hm2;
3373l_int32 area00, area10, area01, area11, areal, arear, areat, areab;
3374l_int32 xu, yu; /* UL corner in src image, to 1/16 of a pixel */
3375l_int32 xl, yl; /* LR corner in src image, to 1/16 of a pixel */
3376l_int32 xup, yup, xuf, yuf; /* UL src pixel: integer and fraction */
3377l_int32 xlp, ylp, xlf, ylf; /* LR src pixel: integer and fraction */
3378l_int32 delx, dely, area;
3379l_int32 v00r, v00g, v00b; /* contrib. from UL src pixel */
3380l_int32 v01r, v01g, v01b; /* contrib. from LL src pixel */
3381l_int32 v10r, v10g, v10b; /* contrib from UR src pixel */
3382l_int32 v11r, v11g, v11b; /* contrib from LR src pixel */
3383l_int32 vinr, ving, vinb; /* contrib from all full interior src pixels */
3384l_int32 vmidr, vmidg, vmidb; /* contrib from side parts */
3385l_int32 rval, gval, bval;
3386l_uint32 pixel00, pixel10, pixel01, pixel11, pixel;
3387l_uint32 *lines, *lined;
3388l_float32 scx, scy;
3389
3390 /* (scx, scy) are scaling factors that are applied to the
3391 * dest coords to get the corresponding src coords.
3392 * We need them because we iterate over dest pixels
3393 * and must find the corresponding set of src pixels. */
3394 scx = 16. * (l_float32)ws / (l_float32)wd;
3395 scy = 16. * (l_float32)hs / (l_float32)hd;
3396 wm2 = ws - 2;
3397 hm2 = hs - 2;
3398
3399 /* Iterate over the destination pixels */
3400 for (i = 0; i < hd; i++) {
3401 yu = (l_int32)(scy * i);
3402 yl = (l_int32)(scy * (i + 1.0));
3403 yup = yu >> 4;
3404 yuf = yu & 0x0f;
3405 ylp = yl >> 4;
3406 ylf = yl & 0x0f;
3407 dely = ylp - yup;
3408 lined = datad + i * wpld;
3409 lines = datas + yup * wpls;
3410 for (j = 0; j < wd; j++) {
3411 xu = (l_int32)(scx * j);
3412 xl = (l_int32)(scx * (j + 1.0));
3413 xup = xu >> 4;
3414 xuf = xu & 0x0f;
3415 xlp = xl >> 4;
3416 xlf = xl & 0x0f;
3417 delx = xlp - xup;
3418
3419 /* If near the edge, just use a src pixel value */
3420 if (xlp > wm2 || ylp > hm2) {
3421 *(lined + j) = *(lines + xup);
3422 continue;
3423 }
3424
3425 /* Area summed over, in subpixels. This varies
3426 * due to the quantization, so we can't simply take
3427 * the area to be a constant: area = scx * scy. */
3428 area = ((16 - xuf) + 16 * (delx - 1) + xlf) *
3429 ((16 - yuf) + 16 * (dely - 1) + ylf);
3430
3431 /* Do area map summation */
3432 pixel00 = *(lines + xup);
3433 pixel10 = *(lines + xlp);
3434 pixel01 = *(lines + dely * wpls + xup);
3435 pixel11 = *(lines + dely * wpls + xlp);
3436 area00 = (16 - xuf) * (16 - yuf);
3437 area10 = xlf * (16 - yuf);
3438 area01 = (16 - xuf) * ylf;
3439 area11 = xlf * ylf;
3440 v00r = area00 * ((pixel00 >> L_RED_SHIFT) & 0xff);
3441 v00g = area00 * ((pixel00 >> L_GREEN_SHIFT) & 0xff);
3442 v00b = area00 * ((pixel00 >> L_BLUE_SHIFT) & 0xff);
3443 v10r = area10 * ((pixel10 >> L_RED_SHIFT) & 0xff);
3444 v10g = area10 * ((pixel10 >> L_GREEN_SHIFT) & 0xff);
3445 v10b = area10 * ((pixel10 >> L_BLUE_SHIFT) & 0xff);
3446 v01r = area01 * ((pixel01 >> L_RED_SHIFT) & 0xff);
3447 v01g = area01 * ((pixel01 >> L_GREEN_SHIFT) & 0xff);
3448 v01b = area01 * ((pixel01 >> L_BLUE_SHIFT) & 0xff);
3449 v11r = area11 * ((pixel11 >> L_RED_SHIFT) & 0xff);
3450 v11g = area11 * ((pixel11 >> L_GREEN_SHIFT) & 0xff);
3451 v11b = area11 * ((pixel11 >> L_BLUE_SHIFT) & 0xff);
3452 vinr = ving = vinb = 0;
3453 for (k = 1; k < dely; k++) { /* for full src pixels */
3454 for (m = 1; m < delx; m++) {
3455 pixel = *(lines + k * wpls + xup + m);
3456 vinr += 256 * ((pixel >> L_RED_SHIFT) & 0xff);
3457 ving += 256 * ((pixel >> L_GREEN_SHIFT) & 0xff);
3458 vinb += 256 * ((pixel >> L_BLUE_SHIFT) & 0xff);
3459 }
3460 }
3461 vmidr = vmidg = vmidb = 0;
3462 areal = (16 - xuf) * 16;
3463 arear = xlf * 16;
3464 areat = 16 * (16 - yuf);
3465 areab = 16 * ylf;
3466 for (k = 1; k < dely; k++) { /* for left side */
3467 pixel = *(lines + k * wpls + xup);
3468 vmidr += areal * ((pixel >> L_RED_SHIFT) & 0xff);
3469 vmidg += areal * ((pixel >> L_GREEN_SHIFT) & 0xff);
3470 vmidb += areal * ((pixel >> L_BLUE_SHIFT) & 0xff);
3471 }
3472 for (k = 1; k < dely; k++) { /* for right side */
3473 pixel = *(lines + k * wpls + xlp);
3474 vmidr += arear * ((pixel >> L_RED_SHIFT) & 0xff);
3475 vmidg += arear * ((pixel >> L_GREEN_SHIFT) & 0xff);
3476 vmidb += arear * ((pixel >> L_BLUE_SHIFT) & 0xff);
3477 }
3478 for (m = 1; m < delx; m++) { /* for top side */
3479 pixel = *(lines + xup + m);
3480 vmidr += areat * ((pixel >> L_RED_SHIFT) & 0xff);
3481 vmidg += areat * ((pixel >> L_GREEN_SHIFT) & 0xff);
3482 vmidb += areat * ((pixel >> L_BLUE_SHIFT) & 0xff);
3483 }
3484 for (m = 1; m < delx; m++) { /* for bottom side */
3485 pixel = *(lines + dely * wpls + xup + m);
3486 vmidr += areab * ((pixel >> L_RED_SHIFT) & 0xff);
3487 vmidg += areab * ((pixel >> L_GREEN_SHIFT) & 0xff);
3488 vmidb += areab * ((pixel >> L_BLUE_SHIFT) & 0xff);
3489 }
3490
3491 /* Sum all the contributions */
3492 rval = (v00r + v01r + v10r + v11r + vinr + vmidr + 128) / area;
3493 gval = (v00g + v01g + v10g + v11g + ving + vmidg + 128) / area;
3494 bval = (v00b + v01b + v10b + v11b + vinb + vmidb + 128) / area;
3495#if DEBUG_OVERFLOW
3496 if (rval > 255) lept_stderr("rval ovfl: %d\n", rval);
3497 if (gval > 255) lept_stderr("gval ovfl: %d\n", gval);
3498 if (bval > 255) lept_stderr("bval ovfl: %d\n", bval);
3499#endif /* DEBUG_OVERFLOW */
3500 composeRGBPixel(rval, gval, bval, lined + j);
3501 }
3502 }
3503}
3504
3505
3520static void
3521scaleGrayAreaMapLow(l_uint32 *datad,
3522 l_int32 wd,
3523 l_int32 hd,
3524 l_int32 wpld,
3525 l_uint32 *datas,
3526 l_int32 ws,
3527 l_int32 hs,
3528 l_int32 wpls)
3529{
3530l_int32 i, j, k, m, wm2, hm2;
3531l_int32 xu, yu; /* UL corner in src image, to 1/16 of a pixel */
3532l_int32 xl, yl; /* LR corner in src image, to 1/16 of a pixel */
3533l_int32 xup, yup, xuf, yuf; /* UL src pixel: integer and fraction */
3534l_int32 xlp, ylp, xlf, ylf; /* LR src pixel: integer and fraction */
3535l_int32 delx, dely, area;
3536l_int32 v00; /* contrib. from UL src pixel */
3537l_int32 v01; /* contrib. from LL src pixel */
3538l_int32 v10; /* contrib from UR src pixel */
3539l_int32 v11; /* contrib from LR src pixel */
3540l_int32 vin; /* contrib from all full interior src pixels */
3541l_int32 vmid; /* contrib from side parts that are full in 1 direction */
3542l_int32 val;
3543l_uint32 *lines, *lined;
3544l_float32 scx, scy;
3545
3546 /* (scx, scy) are scaling factors that are applied to the
3547 * dest coords to get the corresponding src coords.
3548 * We need them because we iterate over dest pixels
3549 * and must find the corresponding set of src pixels. */
3550 scx = 16. * (l_float32)ws / (l_float32)wd;
3551 scy = 16. * (l_float32)hs / (l_float32)hd;
3552 wm2 = ws - 2;
3553 hm2 = hs - 2;
3554
3555 /* Iterate over the destination pixels */
3556 for (i = 0; i < hd; i++) {
3557 yu = (l_int32)(scy * i);
3558 yl = (l_int32)(scy * (i + 1.0));
3559 yup = yu >> 4;
3560 yuf = yu & 0x0f;
3561 ylp = yl >> 4;
3562 ylf = yl & 0x0f;
3563 dely = ylp - yup;
3564 lined = datad + i * wpld;
3565 lines = datas + yup * wpls;
3566 for (j = 0; j < wd; j++) {
3567 xu = (l_int32)(scx * j);
3568 xl = (l_int32)(scx * (j + 1.0));
3569 xup = xu >> 4;
3570 xuf = xu & 0x0f;
3571 xlp = xl >> 4;
3572 xlf = xl & 0x0f;
3573 delx = xlp - xup;
3574
3575 /* If near the edge, just use a src pixel value */
3576 if (xlp > wm2 || ylp > hm2) {
3577 SET_DATA_BYTE(lined, j, GET_DATA_BYTE(lines, xup));
3578 continue;
3579 }
3580
3581 /* Area summed over, in subpixels. This varies
3582 * due to the quantization, so we can't simply take
3583 * the area to be a constant: area = scx * scy. */
3584 area = ((16 - xuf) + 16 * (delx - 1) + xlf) *
3585 ((16 - yuf) + 16 * (dely - 1) + ylf);
3586
3587 /* Do area map summation */
3588 v00 = (16 - xuf) * (16 - yuf) * GET_DATA_BYTE(lines, xup);
3589 v10 = xlf * (16 - yuf) * GET_DATA_BYTE(lines, xlp);
3590 v01 = (16 - xuf) * ylf * GET_DATA_BYTE(lines + dely * wpls, xup);
3591 v11 = xlf * ylf * GET_DATA_BYTE(lines + dely * wpls, xlp);
3592 for (vin = 0, k = 1; k < dely; k++) { /* for full src pixels */
3593 for (m = 1; m < delx; m++) {
3594 vin += 256 * GET_DATA_BYTE(lines + k * wpls, xup + m);
3595 }
3596 }
3597 for (vmid = 0, k = 1; k < dely; k++) /* for left side */
3598 vmid += (16 - xuf) * 16 * GET_DATA_BYTE(lines + k * wpls, xup);
3599 for (k = 1; k < dely; k++) /* for right side */
3600 vmid += xlf * 16 * GET_DATA_BYTE(lines + k * wpls, xlp);
3601 for (m = 1; m < delx; m++) /* for top side */
3602 vmid += 16 * (16 - yuf) * GET_DATA_BYTE(lines, xup + m);
3603 for (m = 1; m < delx; m++) /* for bottom side */
3604 vmid += 16 * ylf * GET_DATA_BYTE(lines + dely * wpls, xup + m);
3605 val = (v00 + v01 + v10 + v11 + vin + vmid + 128) / area;
3606#if DEBUG_OVERFLOW
3607 if (val > 255) lept_stderr("val overflow: %d\n", val);
3608#endif /* DEBUG_OVERFLOW */
3609 SET_DATA_BYTE(lined, j, val);
3610 }
3611 }
3612}
3613
3614
3615/*------------------------------------------------------------------*
3616 * 2x area mapped downscaling *
3617 *------------------------------------------------------------------*/
3627static void
3628scaleAreaMapLow2(l_uint32 *datad,
3629 l_int32 wd,
3630 l_int32 hd,
3631 l_int32 wpld,
3632 l_uint32 *datas,
3633 l_int32 d,
3634 l_int32 wpls)
3635{
3636l_int32 i, j, val, rval, gval, bval;
3637l_uint32 *lines, *lined;
3638l_uint32 pixel;
3639
3640 if (d == 8) {
3641 for (i = 0; i < hd; i++) {
3642 lines = datas + 2 * i * wpls;
3643 lined = datad + i * wpld;
3644 for (j = 0; j < wd; j++) {
3645 /* Average each dest pixel using 4 src pixels */
3646 val = GET_DATA_BYTE(lines, 2 * j);
3647 val += GET_DATA_BYTE(lines, 2 * j + 1);
3648 val += GET_DATA_BYTE(lines + wpls, 2 * j);
3649 val += GET_DATA_BYTE(lines + wpls, 2 * j + 1);
3650 val >>= 2;
3651 SET_DATA_BYTE(lined, j, val);
3652 }
3653 }
3654 } else { /* d == 32 */
3655 for (i = 0; i < hd; i++) {
3656 lines = datas + 2 * i * wpls;
3657 lined = datad + i * wpld;
3658 for (j = 0; j < wd; j++) {
3659 /* Average each of the color components from 4 src pixels */
3660 pixel = *(lines + 2 * j);
3661 rval = (pixel >> L_RED_SHIFT) & 0xff;
3662 gval = (pixel >> L_GREEN_SHIFT) & 0xff;
3663 bval = (pixel >> L_BLUE_SHIFT) & 0xff;
3664 pixel = *(lines + 2 * j + 1);
3665 rval += (pixel >> L_RED_SHIFT) & 0xff;
3666 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3667 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3668 pixel = *(lines + wpls + 2 * j);
3669 rval += (pixel >> L_RED_SHIFT) & 0xff;
3670 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3671 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3672 pixel = *(lines + wpls + 2 * j + 1);
3673 rval += (pixel >> L_RED_SHIFT) & 0xff;
3674 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3675 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3676 composeRGBPixel(rval >> 2, gval >> 2, bval >> 2, &pixel);
3677 *(lined + j) = pixel;
3678 }
3679 }
3680 }
3681}
3682
3683
3684/*------------------------------------------------------------------*
3685 * Binary scaling by closest pixel sampling *
3686 *------------------------------------------------------------------*/
3687/*
3688 * \brief scaleBinaryLow()
3689 *
3690 * <pre>
3691 * Notes:
3692 * (1) The dest must be cleared prior to this operation,
3693 * and we clear it here in the low-level code.
3694 * (2) We reuse dest pixels and dest pixel rows whenever
3695 * possible for upscaling; downscaling is done by
3696 * strict subsampling.
3697 * </pre>
3698 */
3699static l_int32
3700scaleBinaryLow(l_uint32 *datad,
3701 l_int32 wd,
3702 l_int32 hd,
3703 l_int32 wpld,
3704 l_uint32 *datas,
3705 l_int32 ws,
3706 l_int32 hs,
3707 l_int32 wpls)
3708{
3709l_int32 i, j;
3710l_int32 xs, prevxs, sval;
3711l_int32 *srow, *scol;
3712l_uint32 *lines, *prevlines, *lined, *prevlined;
3713l_float32 wratio, hratio;
3714
3715 PROCNAME("scaleBinaryLow");
3716
3717 /* Clear dest */
3718 memset(datad, 0, 4LL * hd * wpld);
3719
3720 /* The source row corresponding to dest row i ==> srow[i]
3721 * The source col corresponding to dest col j ==> scol[j] */
3722 if ((srow = (l_int32 *)LEPT_CALLOC(hd, sizeof(l_int32))) == NULL)
3723 return ERROR_INT("srow not made", procName, 1);
3724 if ((scol = (l_int32 *)LEPT_CALLOC(wd, sizeof(l_int32))) == NULL) {
3725 LEPT_FREE(srow);
3726 return ERROR_INT("scol not made", procName, 1);
3727 }
3728
3729 wratio = (l_float32)ws / (l_float32)wd;
3730 hratio = (l_float32)hs / (l_float32)hd;
3731 for (i = 0; i < hd; i++)
3732 srow[i] = L_MIN((l_int32)(hratio * i + 0.5), hs - 1);
3733 for (j = 0; j < wd; j++)
3734 scol[j] = L_MIN((l_int32)(wratio * j + 0.5), ws - 1);
3735
3736 prevlines = NULL;
3737 prevxs = -1;
3738 sval = 0;
3739 for (i = 0; i < hd; i++) {
3740 lines = datas + srow[i] * wpls;
3741 lined = datad + i * wpld;
3742 if (lines != prevlines) { /* make dest from new source row */
3743 for (j = 0; j < wd; j++) {
3744 xs = scol[j];
3745 if (xs != prevxs) { /* get dest pix from source col */
3746 if ((sval = GET_DATA_BIT(lines, xs)))
3747 SET_DATA_BIT(lined, j);
3748 prevxs = xs;
3749 } else { /* copy prev dest pix, if set */
3750 if (sval)
3751 SET_DATA_BIT(lined, j);
3752 }
3753 }
3754 } else { /* lines == prevlines; copy prev dest row */
3755 prevlined = lined - wpld;
3756 memcpy(lined, prevlined, 4 * wpld);
3757 }
3758 prevlines = lines;
3759 }
3760
3761 LEPT_FREE(srow);
3762 LEPT_FREE(scol);
3763 return 0;
3764}
#define GET_DATA_QBIT(pdata, n)
Definition: arrayaccess.h:164
#define GET_DATA_TWO_BYTES(pdata, n)
Definition: arrayaccess.h:212
#define SET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:127
#define SET_DATA_DIBIT(pdata, n, val)
Definition: arrayaccess.h:149
#define SET_DATA_TWO_BYTES(pdata, n, val)
Definition: arrayaccess.h:222
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:188
#define GET_DATA_DIBIT(pdata, n)
Definition: arrayaccess.h:145
#define SET_DATA_BYTE(pdata, n, val)
Definition: arrayaccess.h:198
#define GET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:123
#define SET_DATA_QBIT(pdata, n, val)
Definition: arrayaccess.h:168
PIX * pixUnsharpMasking(PIX *pixs, l_int32 halfwidth, l_float32 fract)
pixUnsharpMasking()
Definition: enhance.c:1001
void ditherToBinaryLineLow(l_uint32 *lined, l_int32 w, l_uint32 *bufs1, l_uint32 *bufs2, l_int32 lowerclip, l_int32 upperclip, l_int32 lastlineflag)
ditherToBinaryLineLow()
Definition: grayquant.c:326
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:621
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1113
l_ok pixCopySpp(PIX *pixd, const PIX *pixs)
pixCopySpp()
Definition: pix1.c:1236
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:593
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
l_ok pixCopyColormap(PIX *pixd, const PIX *pixs)
pixCopyColormap()
Definition: pix1.c:816
PIX * pixCopy(PIX *pixd, const PIX *pixs)
pixCopy()
Definition: pix1.c:705
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1763
l_ok pixSetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 val)
pixSetPixel()
Definition: pix2.c:263
l_ok pixGetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 *pval)
pixGetPixel()
Definition: pix2.c:190
l_ok composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2751
PIX * pixGetRGBComponent(PIX *pixs, l_int32 comp)
pixGetRGBComponent()
Definition: pix2.c:2479
PIX * pixCreateRGBImage(PIX *pixr, PIX *pixg, PIX *pixb)
pixCreateRGBImage()
Definition: pix2.c:2423
@ COLOR_BLUE
Definition: pix.h:206
@ COLOR_RED
Definition: pix.h:204
@ COLOR_GREEN
Definition: pix.h:205
@ DEFAULT_CLIP_LOWER_1
Definition: pix.h:935
@ DEFAULT_CLIP_UPPER_1
Definition: pix.h:936
@ REMOVE_CMAP_BASED_ON_SRC
Definition: pix.h:260
@ L_CLONE
Definition: pix.h:713
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3133
PIX * pixConvertTo8Or32(PIX *pixs, l_int32 copyflag, l_int32 warnflag)
pixConvertTo8Or32()
Definition: pixconv.c:3492
PIX * pixRemoveColormap(PIX *pixs, l_int32 type)
pixRemoveColormap()
Definition: pixconv.c:328
PIX * pixScaleGray4xLIDither(PIX *pixs)
pixScaleGray4xLIDither()
Definition: scale1.c:1213
PIX * pixScaleLI(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleLI()
Definition: scale1.c:516
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)
scaleBySamplingLow()
Definition: scale1.c:3064
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:3628
PIX * pixScaleAreaMap2(PIX *pix)
pixScaleAreaMap2()
Definition: scale1.c:2047
PIX * pixScaleGrayToBinaryFast(PIX *pixs, l_int32 factor, l_int32 thresh)
pixScaleGrayToBinaryFast()
Definition: scale1.c:1627
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:2930
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:2691
PIX * pixScaleColor4xLI(PIX *pixs)
pixScaleColor4xLI()
Definition: scale1.c:686
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:3363
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:2324
PIX * pixScaleBinary(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleBinary()
Definition: scale1.c:2161
PIX * pixScaleGray2xLIThresh(PIX *pixs, l_int32 thresh)
pixScaleGray2xLIThresh()
Definition: scale1.c:927
PIX * pixScaleByIntSampling(PIX *pixs, l_int32 factor)
pixScaleByIntSampling()
Definition: scale1.c:1444
PIX * pixScaleGray2xLI(PIX *pixs)
pixScaleGray2xLI()
Definition: scale1.c:841
PIX * pixScaleSmooth(PIX *pix, l_float32 scalex, l_float32 scaley)
pixScaleSmooth()
Definition: scale1.c:1709
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:2219
PIX * pixScaleColor2xLI(PIX *pixs)
pixScaleColor2xLI()
Definition: scale1.c:639
PIX * pixScaleGray2xLIDither(PIX *pixs)
pixScaleGray2xLIDither()
Definition: scale1.c:1006
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:3197
PIX * pixScaleGray4xLIThresh(PIX *pixs, l_int32 thresh)
pixScaleGray4xLIThresh()
Definition: scale1.c:1125
PIX * pixScaleGray4xLI(PIX *pixs)
pixScaleGray4xLI()
Definition: scale1.c:882
PIX * pixScaleBySamplingToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleBySamplingToSize()
Definition: scale1.c:1400
PIX * pixScaleBySampling(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleBySampling()
Definition: scale1.c:1338
PIX * pixScaleColorLI(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleColorLI()
Definition: scale1.c:575
PIX * pixScale(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScale()
Definition: scale1.c:250
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:2441
PIX * pixScaleToSizeRel(PIX *pixs, l_int32 delw, l_int32 delh)
pixScaleToSizeRel()
Definition: scale1.c:280
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:2884
PIX * pixScaleRGBToGray2(PIX *pixs, l_float32 rwt, l_float32 gwt, l_float32 bwt)
pixScaleRGBToGray2()
Definition: scale1.c:1833
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:1561
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:3298
PIX * pixScaleRGBToGrayFast(PIX *pixs, l_int32 factor, l_int32 color)
pixScaleRGBToGrayFast()
Definition: scale1.c:1486
PIX * pixScaleToResolution(PIX *pixs, l_float32 target, l_float32 assumed, l_float32 *pscalefact)
pixScaleToResolution()
Definition: scale1.c:363
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:2643
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:3521
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:2112
PIX * pixScaleGrayLI(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleGrayLI()
Definition: scale1.c:780
PIX * pixScaleGeneral(PIX *pixs, l_float32 scalex, l_float32 scaley, l_float32 sharpfract, l_int32 sharpwidth)
pixScaleGeneral()
Definition: scale1.c:423
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:2489
PIX * pixScaleAreaMap(PIX *pix, l_float32 scalex, l_float32 scaley)
pixScaleAreaMap()
Definition: scale1.c:1914
l_ok pixScaleAndTransferAlpha(PIX *pixd, PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleAndTransferAlpha()
Definition: scale2.c:1364
Definition: pix.h:139
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306