Leptonica 1.83.1
Image processing and image analysis suite
Loading...
Searching...
No Matches
scale1.c
Go to the documentation of this file.
1/*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 -
4 - Redistribution and use in source and binary forms, with or without
5 - modification, are permitted provided that the following conditions
6 - are met:
7 - 1. Redistributions of source code must retain the above copyright
8 - notice, this list of conditions and the following disclaimer.
9 - 2. Redistributions in binary form must reproduce the above
10 - copyright notice, this list of conditions and the following
11 - disclaimer in the documentation and/or other materials
12 - provided with the distribution.
13 -
14 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18 - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *====================================================================*/
26
113
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 if (!pixs)
258 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
259
260 /* Reduce the default sharpening factors by 2 if maxscale < 0.7 */
261 maxscale = L_MAX(scalex, scaley);
262 sharpfract = (maxscale < 0.7) ? 0.2 : 0.4;
263 sharpwidth = (maxscale < 0.7) ? 1 : 2;
264
265 return pixScaleGeneral(pixs, scalex, scaley, sharpfract, sharpwidth);
266}
267
268
277PIX *
279 l_int32 delw,
280 l_int32 delh)
281{
282l_int32 w, h, wd, hd;
283
284 if (!pixs)
285 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
286
287 if (delw == 0 && delh == 0)
288 return pixCopy(NULL, pixs);
289
290 pixGetDimensions(pixs, &w, &h, NULL);
291 wd = w + delw;
292 hd = h + delh;
293 if (wd <= 0 || hd <= 0)
294 return (PIX *)ERROR_PTR("pix dimension reduced to 0", __func__, NULL);
295
296 return pixScaleToSize(pixs, wd, hd);
297}
298
299
318PIX *
320 l_int32 wd,
321 l_int32 hd)
322{
323l_int32 w, h;
324l_float32 scalex, scaley;
325
326 if (!pixs)
327 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
328 if (wd <= 0 && hd <= 0)
329 return (PIX *)ERROR_PTR("neither wd nor hd > 0", __func__, NULL);
330
331 pixGetDimensions(pixs, &w, &h, NULL);
332 if (wd <= 0) {
333 scaley = (l_float32)hd / (l_float32)h;
334 scalex = scaley;
335 } else if (hd <= 0) {
336 scalex = (l_float32)wd / (l_float32)w;
337 scaley = scalex;
338 } else {
339 scalex = (l_float32)wd / (l_float32)w;
340 scaley = (l_float32)hd / (l_float32)h;
341 }
342
343 return pixScale(pixs, scalex, scaley);
344}
345
346
356PIX *
358 l_float32 target,
359 l_float32 assumed,
360 l_float32 *pscalefact)
361{
362l_int32 xres;
363l_float32 factor;
364
365 if (pscalefact) *pscalefact = 1.0;
366 if (!pixs)
367 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
368 if (target <= 0)
369 return (PIX *)ERROR_PTR("target resolution <= 0", __func__, NULL);
370
371 xres = pixGetXRes(pixs);
372 if (xres <= 0) {
373 if (assumed == 0)
374 return pixCopy(NULL, pixs);
375 xres = assumed;
376 }
377 factor = target / (l_float32)xres;
378 if (pscalefact) *pscalefact = factor;
379
380 return pixScale(pixs, factor, factor);
381}
382
383
414PIX *
416 l_float32 scalex,
417 l_float32 scaley,
418 l_float32 sharpfract,
419 l_int32 sharpwidth)
420{
421l_int32 d;
422l_float32 maxscale, minscale;
423PIX *pix1, *pix2, *pixd;
424
425 if (!pixs)
426 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
427 d = pixGetDepth(pixs);
428 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
429 return (PIX *)ERROR_PTR("pixs not {1,2,4,8,16,32} bpp", __func__, NULL);
430 if (scalex <= 0.0 || scaley <= 0.0)
431 return (PIX *)ERROR_PTR("scale factor <= 0", __func__, NULL);
432 if (scalex == 1.0 && scaley == 1.0)
433 return pixCopy(NULL, pixs);
434
435 if (d == 1)
436 return pixScaleBinary(pixs, scalex, scaley);
437
438 /* Remove colormap; clone if possible; result is either 8 or 32 bpp */
439 if ((pix1 = pixConvertTo8Or32(pixs, L_CLONE, 0)) == NULL)
440 return (PIX *)ERROR_PTR("pix1 not made", __func__, NULL);
441
442 /* Scale (up or down) */
443 d = pixGetDepth(pix1);
444 maxscale = L_MAX(scalex, scaley);
445 minscale = L_MIN(scalex, scaley);
446 if (maxscale < 0.7) { /* use low-pass filter for anti-aliasing */
447 if (minscale < 0.02) { /* whole-pixel low-pass filter */
448 pix2 = pixScaleSmooth(pix1, scalex, scaley);
449 } else { /* fractional pixel low-pass filter */
450 pix2 = pixScaleAreaMap(pix1, scalex, scaley);
451 }
452 if (maxscale > 0.2 && sharpfract > 0.0 && sharpwidth > 0) {
453 pixd = pixUnsharpMasking(pix2, sharpwidth, sharpfract);
454 } else {
455 pixd = pixClone(pix2);
456 }
457 } else { /* use linear interpolation */
458 if (d == 8) {
459 pix2 = pixScaleGrayLI(pix1, scalex, scaley);
460 } else { /* d == 32 */
461 pix2 = pixScaleColorLI(pix1, scalex, scaley);
462 }
463 if (maxscale < 1.4 && sharpfract > 0.0 && sharpwidth > 0) {
464 pixd = pixUnsharpMasking(pix2, sharpwidth, sharpfract);
465 } else {
466 pixd = pixClone(pix2);
467 }
468 }
469
470 pixDestroy(&pix1);
471 pixDestroy(&pix2);
472 pixCopyText(pixd, pixs);
473 pixCopyInputFormat(pixd, pixs);
474 return pixd;
475}
476
477
478/*------------------------------------------------------------------*
479 * Scaling by linear interpolation *
480 *------------------------------------------------------------------*/
505PIX *
507 l_float32 scalex,
508 l_float32 scaley)
509{
510l_int32 d;
511l_float32 maxscale;
512PIX *pixt, *pixd;
513
514 if (!pixs || (pixGetDepth(pixs) == 1))
515 return (PIX *)ERROR_PTR("pixs not defined or 1 bpp", __func__, NULL);
516 maxscale = L_MAX(scalex, scaley);
517 if (maxscale < 0.7) {
518 L_WARNING("scaling factors < 0.7; do regular scaling\n", __func__);
519 return pixScaleGeneral(pixs, scalex, scaley, 0.0, 0);
520 }
521 d = pixGetDepth(pixs);
522 if (d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
523 return (PIX *)ERROR_PTR("pixs not {2,4,8,16,32} bpp", __func__, NULL);
524
525 /* Remove colormap; clone if possible; result is either 8 or 32 bpp */
526 if ((pixt = pixConvertTo8Or32(pixs, L_CLONE, 0)) == NULL)
527 return (PIX *)ERROR_PTR("pixt not made", __func__, NULL);
528
529 d = pixGetDepth(pixt);
530 if (d == 8)
531 pixd = pixScaleGrayLI(pixt, scalex, scaley);
532 else /* d == 32 */
533 pixd = pixScaleColorLI(pixt, scalex, scaley);
534
535 pixDestroy(&pixt);
536 pixCopyInputFormat(pixd, pixs);
537 return pixd;
538}
539
540
562PIX *
564 l_float32 scalex,
565 l_float32 scaley)
566{
567l_int32 ws, hs, wpls, wd, hd, wpld;
568l_uint32 *datas, *datad;
569l_float32 maxscale;
570PIX *pixd;
571
572 if (!pixs || (pixGetDepth(pixs) != 32))
573 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", __func__, NULL);
574 maxscale = L_MAX(scalex, scaley);
575 if (maxscale < 0.7) {
576 L_WARNING("scaling factors < 0.7; do regular scaling\n", __func__);
577 return pixScaleGeneral(pixs, scalex, scaley, 0.0, 0);
578 }
579
580 /* Do fast special cases if possible */
581 if (scalex == 1.0 && scaley == 1.0)
582 return pixCopy(NULL, pixs);
583 if (scalex == 2.0 && scaley == 2.0)
584 return pixScaleColor2xLI(pixs);
585 if (scalex == 4.0 && scaley == 4.0)
586 return pixScaleColor4xLI(pixs);
587
588 /* General case */
589 pixGetDimensions(pixs, &ws, &hs, NULL);
590 datas = pixGetData(pixs);
591 wpls = pixGetWpl(pixs);
592 wd = (l_int32)(scalex * (l_float32)ws + 0.5);
593 hd = (l_int32)(scaley * (l_float32)hs + 0.5);
594 if ((pixd = pixCreate(wd, hd, 32)) == NULL)
595 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
596 pixCopyResolution(pixd, pixs);
597 pixScaleResolution(pixd, scalex, scaley);
598 datad = pixGetData(pixd);
599 wpld = pixGetWpl(pixd);
600 scaleColorLILow(datad, wd, hd, wpld, datas, ws, hs, wpls);
601 if (pixGetSpp(pixs) == 4)
602 pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley);
603
604 pixCopyInputFormat(pixd, pixs);
605 return pixd;
606}
607
608
624PIX *
626{
627l_int32 ws, hs, wpls, wpld;
628l_uint32 *datas, *datad;
629PIX *pixd;
630
631 if (!pixs || (pixGetDepth(pixs) != 32))
632 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", __func__, NULL);
633
634 pixGetDimensions(pixs, &ws, &hs, NULL);
635 datas = pixGetData(pixs);
636 wpls = pixGetWpl(pixs);
637 if ((pixd = pixCreate(2 * ws, 2 * hs, 32)) == NULL)
638 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
639 pixCopyResolution(pixd, pixs);
640 pixScaleResolution(pixd, 2.0, 2.0);
641 datad = pixGetData(pixd);
642 wpld = pixGetWpl(pixd);
643 scaleColor2xLILow(datad, wpld, datas, ws, hs, wpls);
644 if (pixGetSpp(pixs) == 4)
645 pixScaleAndTransferAlpha(pixd, pixs, 2.0, 2.0);
646
647 pixCopyInputFormat(pixd, pixs);
648 return pixd;
649}
650
651
669PIX *
671{
672PIX *pixr, *pixg, *pixb;
673PIX *pixrs, *pixgs, *pixbs;
674PIX *pixd;
675
676 if (!pixs || (pixGetDepth(pixs) != 32))
677 return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", __func__, NULL);
678
679 pixr = pixGetRGBComponent(pixs, COLOR_RED);
680 pixrs = pixScaleGray4xLI(pixr);
681 pixDestroy(&pixr);
682 pixg = pixGetRGBComponent(pixs, COLOR_GREEN);
683 pixgs = pixScaleGray4xLI(pixg);
684 pixDestroy(&pixg);
685 pixb = pixGetRGBComponent(pixs, COLOR_BLUE);
686 pixbs = pixScaleGray4xLI(pixb);
687 pixDestroy(&pixb);
688
689 if ((pixd = pixCreateRGBImage(pixrs, pixgs, pixbs)) == NULL) {
690 L_ERROR("pixd not made\n", __func__);
691 } else {
692 if (pixGetSpp(pixs) == 4)
693 pixScaleAndTransferAlpha(pixd, pixs, 4.0, 4.0);
694 pixCopyInputFormat(pixd, pixs);
695 }
696
697 pixDestroy(&pixrs);
698 pixDestroy(&pixgs);
699 pixDestroy(&pixbs);
700 return pixd;
701}
702
703
761PIX *
763 l_float32 scalex,
764 l_float32 scaley)
765{
766l_int32 ws, hs, wpls, wd, hd, wpld;
767l_uint32 *datas, *datad;
768l_float32 maxscale;
769PIX *pixd;
770
771 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
772 return (PIX *)ERROR_PTR("pixs undefined, cmapped or not 8 bpp",
773 __func__, NULL);
774 maxscale = L_MAX(scalex, scaley);
775 if (maxscale < 0.7) {
776 L_WARNING("scaling factors < 0.7; do regular scaling\n", __func__);
777 return pixScaleGeneral(pixs, scalex, scaley, 0.0, 0);
778 }
779
780 /* Do fast special cases if possible */
781 if (scalex == 1.0 && scaley == 1.0)
782 return pixCopy(NULL, pixs);
783 if (scalex == 2.0 && scaley == 2.0)
784 return pixScaleGray2xLI(pixs);
785 if (scalex == 4.0 && scaley == 4.0)
786 return pixScaleGray4xLI(pixs);
787
788 /* General case */
789 pixGetDimensions(pixs, &ws, &hs, NULL);
790 datas = pixGetData(pixs);
791 wpls = pixGetWpl(pixs);
792 wd = (l_int32)(scalex * (l_float32)ws + 0.5);
793 hd = (l_int32)(scaley * (l_float32)hs + 0.5);
794 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
795 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
796 pixCopyText(pixd, pixs);
797 pixCopyResolution(pixd, pixs);
798 pixCopyInputFormat(pixd, pixs);
799 pixScaleResolution(pixd, scalex, scaley);
800 datad = pixGetData(pixd);
801 wpld = pixGetWpl(pixd);
802 scaleGrayLILow(datad, wd, hd, wpld, datas, ws, hs, wpls);
803 return pixd;
804}
805
806
820PIX *
822{
823l_int32 ws, hs, wpls, wpld;
824l_uint32 *datas, *datad;
825PIX *pixd;
826
827 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
828 return (PIX *)ERROR_PTR("pixs undefined, cmapped or not 8 bpp",
829 __func__, NULL);
830
831 pixGetDimensions(pixs, &ws, &hs, NULL);
832 datas = pixGetData(pixs);
833 wpls = pixGetWpl(pixs);
834 if ((pixd = pixCreate(2 * ws, 2 * hs, 8)) == NULL)
835 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
836 pixCopyResolution(pixd, pixs);
837 pixCopyInputFormat(pixd, pixs);
838 pixScaleResolution(pixd, 2.0, 2.0);
839 datad = pixGetData(pixd);
840 wpld = pixGetWpl(pixd);
841 scaleGray2xLILow(datad, wpld, datas, ws, hs, wpls);
842 return pixd;
843}
844
845
859PIX *
861{
862l_int32 ws, hs, wpls, wpld;
863l_uint32 *datas, *datad;
864PIX *pixd;
865
866 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
867 return (PIX *)ERROR_PTR("pixs undefined, cmapped or not 8 bpp",
868 __func__, NULL);
869
870 pixGetDimensions(pixs, &ws, &hs, NULL);
871 datas = pixGetData(pixs);
872 wpls = pixGetWpl(pixs);
873 if ((pixd = pixCreate(4 * ws, 4 * hs, 8)) == NULL)
874 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
875 pixCopyResolution(pixd, pixs);
876 pixCopyInputFormat(pixd, pixs);
877 pixScaleResolution(pixd, 4.0, 4.0);
878 datad = pixGetData(pixd);
879 wpld = pixGetWpl(pixd);
880 scaleGray4xLILow(datad, wpld, datas, ws, hs, wpls);
881 return pixd;
882}
883
884
885/*------------------------------------------------------------------*
886 * Scale 2x followed by binarization *
887 *------------------------------------------------------------------*/
902PIX *
904 l_int32 thresh)
905{
906l_int32 i, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
907l_uint32 *datas, *datad, *lines, *lined, *lineb;
908PIX *pixd;
909
910 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
911 return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
912 __func__, NULL);
913 if (thresh < 0 || thresh > 256)
914 return (PIX *)ERROR_PTR("thresh must be in [0, ... 256]",
915 __func__, NULL);
916
917 pixGetDimensions(pixs, &ws, &hs, NULL);
918 wd = 2 * ws;
919 hd = 2 * hs;
920 hsm = hs - 1;
921 datas = pixGetData(pixs);
922 wpls = pixGetWpl(pixs);
923
924 /* Make line buffer for 2 lines of virtual intermediate image */
925 wplb = (wd + 3) / 4;
926 if ((lineb = (l_uint32 *)LEPT_CALLOC(2 * wplb, sizeof(l_uint32))) == NULL)
927 return (PIX *)ERROR_PTR("lineb not made", __func__, NULL);
928
929 /* Make dest binary image */
930 if ((pixd = pixCreate(wd, hd, 1)) == NULL) {
931 LEPT_FREE(lineb);
932 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
933 }
934 pixCopyInputFormat(pixd, pixs);
935 pixCopyResolution(pixd, pixs);
936 pixScaleResolution(pixd, 2.0, 2.0);
937 wpld = pixGetWpl(pixd);
938 datad = pixGetData(pixd);
939
940 /* Do all but last src line */
941 for (i = 0; i < hsm; i++) {
942 lines = datas + i * wpls;
943 lined = datad + 2 * i * wpld; /* do 2 dest lines at a time */
944 scaleGray2xLILineLow(lineb, wplb, lines, ws, wpls, 0);
945 thresholdToBinaryLineLow(lined, wd, lineb, 8, thresh);
946 thresholdToBinaryLineLow(lined + wpld, wd, lineb + wplb, 8, thresh);
947 }
948
949 /* Do last src line */
950 lines = datas + hsm * wpls;
951 lined = datad + 2 * hsm * wpld;
952 scaleGray2xLILineLow(lineb, wplb, lines, ws, wpls, 1);
953 thresholdToBinaryLineLow(lined, wd, lineb, 8, thresh);
954 thresholdToBinaryLineLow(lined + wpld, wd, lineb + wplb, 8, thresh);
955
956 LEPT_FREE(lineb);
957 return pixd;
958}
959
960
979PIX *
981{
982l_int32 i, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
983l_uint32 *datas, *datad;
984l_uint32 *lined;
985l_uint32 *lineb = NULL; /* 2 intermediate buffer lines */
986l_uint32 *linebp = NULL; /* 1 intermediate buffer line */
987l_uint32 *bufs = NULL; /* 2 source buffer lines */
988PIX *pixd = NULL;
989
990 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
991 return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
992 __func__, NULL);
993
994 pixGetDimensions(pixs, &ws, &hs, NULL);
995 wd = 2 * ws;
996 hd = 2 * hs;
997 hsm = hs - 1;
998 datas = pixGetData(pixs);
999 wpls = pixGetWpl(pixs);
1000
1001 /* Make line buffers for 2 lines of src image */
1002 if ((bufs = (l_uint32 *)LEPT_CALLOC(2 * wpls, sizeof(l_uint32))) == NULL)
1003 return (PIX *)ERROR_PTR("bufs not made", __func__, NULL);
1004
1005 /* Make line buffer for 2 lines of virtual intermediate image */
1006 wplb = (wd + 3) / 4;
1007 if ((lineb = (l_uint32 *)LEPT_CALLOC(2 * wplb, sizeof(l_uint32))) == NULL) {
1008 L_ERROR("lineb not made\n", __func__);
1009 goto cleanup;
1010 }
1011
1012 /* Make line buffer for 1 line of virtual intermediate image */
1013 if ((linebp = (l_uint32 *)LEPT_CALLOC(wplb, sizeof(l_uint32))) == NULL) {
1014 L_ERROR("linebp not made\n", __func__);
1015 goto cleanup;
1016 }
1017
1018 /* Make dest binary image */
1019 if ((pixd = pixCreate(wd, hd, 1)) == NULL) {
1020 L_ERROR("pixd not made\n", __func__);
1021 goto cleanup;
1022 }
1023 pixCopyInputFormat(pixd, pixs);
1024 pixCopyResolution(pixd, pixs);
1025 pixScaleResolution(pixd, 2.0, 2.0);
1026 wpld = pixGetWpl(pixd);
1027 datad = pixGetData(pixd);
1028
1029 /* Start with the first src and the first dest line */
1030 memcpy(bufs, datas, 4 * wpls); /* first src line */
1031 memcpy(bufs + wpls, datas + wpls, 4 * wpls); /* 2nd src line */
1032 scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 2 i lines */
1033 lined = datad;
1034 ditherToBinaryLineLow(lined, wd, lineb, lineb + wplb,
1036 /* 1st d line */
1037
1038 /* Do all but last src line */
1039 for (i = 1; i < hsm; i++) {
1040 memcpy(bufs, datas + i * wpls, 4 * wpls); /* i-th src line */
1041 memcpy(bufs + wpls, datas + (i + 1) * wpls, 4 * wpls);
1042 memcpy(linebp, lineb + wplb, 4 * wplb);
1043 scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 2 i lines */
1044 lined = datad + 2 * i * wpld;
1045 ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb,
1047 /* odd dest line */
1048 ditherToBinaryLineLow(lined, wd, lineb, lineb + wplb,
1050 /* even dest line */
1051 }
1052
1053 /* Do the last src line and the last 3 dest lines */
1054 memcpy(bufs, datas + hsm * wpls, 4 * wpls); /* hsm-th src line */
1055 memcpy(linebp, lineb + wplb, 4 * wplb); /* 1 i line */
1056 scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 1); /* 2 i lines */
1057 ditherToBinaryLineLow(lined + wpld, wd, linebp, lineb,
1059 /* odd dest line */
1060 ditherToBinaryLineLow(lined + 2 * wpld, wd, lineb, lineb + wplb,
1062 /* even dest line */
1063 ditherToBinaryLineLow(lined + 3 * wpld, wd, lineb + wplb, NULL,
1065 /* last dest line */
1066
1067cleanup:
1068 LEPT_FREE(bufs);
1069 LEPT_FREE(lineb);
1070 LEPT_FREE(linebp);
1071 return pixd;
1072}
1073
1074
1075/*------------------------------------------------------------------*
1076 * Scale 4x followed by binarization *
1077 *------------------------------------------------------------------*/
1096PIX *
1098 l_int32 thresh)
1099{
1100l_int32 i, j, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
1101l_uint32 *datas, *datad, *lines, *lined, *lineb;
1102PIX *pixd;
1103
1104 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
1105 return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
1106 __func__, NULL);
1107 if (thresh < 0 || thresh > 256)
1108 return (PIX *)ERROR_PTR("thresh must be in [0, ... 256]",
1109 __func__, NULL);
1110
1111 pixGetDimensions(pixs, &ws, &hs, NULL);
1112 wd = 4 * ws;
1113 hd = 4 * hs;
1114 hsm = hs - 1;
1115 datas = pixGetData(pixs);
1116 wpls = pixGetWpl(pixs);
1117
1118 /* Make line buffer for 4 lines of virtual intermediate image */
1119 wplb = (wd + 3) / 4;
1120 if ((lineb = (l_uint32 *)LEPT_CALLOC(4 * wplb, sizeof(l_uint32))) == NULL)
1121 return (PIX *)ERROR_PTR("lineb not made", __func__, NULL);
1122
1123 /* Make dest binary image */
1124 if ((pixd = pixCreate(wd, hd, 1)) == NULL) {
1125 LEPT_FREE(lineb);
1126 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1127 }
1128 pixCopyInputFormat(pixd, pixs);
1129 pixCopyResolution(pixd, pixs);
1130 pixScaleResolution(pixd, 4.0, 4.0);
1131 wpld = pixGetWpl(pixd);
1132 datad = pixGetData(pixd);
1133
1134 /* Do all but last src line */
1135 for (i = 0; i < hsm; i++) {
1136 lines = datas + i * wpls;
1137 lined = datad + 4 * i * wpld; /* do 4 dest lines at a time */
1138 scaleGray4xLILineLow(lineb, wplb, lines, ws, wpls, 0);
1139 for (j = 0; j < 4; j++) {
1140 thresholdToBinaryLineLow(lined + j * wpld, wd,
1141 lineb + j * wplb, 8, thresh);
1142 }
1143 }
1144
1145 /* Do last src line */
1146 lines = datas + hsm * wpls;
1147 lined = datad + 4 * hsm * wpld;
1148 scaleGray4xLILineLow(lineb, wplb, lines, ws, wpls, 1);
1149 for (j = 0; j < 4; j++) {
1150 thresholdToBinaryLineLow(lined + j * wpld, wd,
1151 lineb + j * wplb, 8, thresh);
1152 }
1153
1154 LEPT_FREE(lineb);
1155 return pixd;
1156}
1157
1158
1182PIX *
1184{
1185l_int32 i, j, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
1186l_uint32 *datas, *datad;
1187l_uint32 *lined;
1188l_uint32 *lineb = NULL; /* 4 intermediate buffer lines */
1189l_uint32 *linebp = NULL; /* 1 intermediate buffer line */
1190l_uint32 *bufs = NULL; /* 2 source buffer lines */
1191PIX *pixd = NULL;
1192
1193 if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
1194 return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
1195 __func__, NULL);
1196
1197 pixGetDimensions(pixs, &ws, &hs, NULL);
1198 wd = 4 * ws;
1199 hd = 4 * hs;
1200 hsm = hs - 1;
1201 datas = pixGetData(pixs);
1202 wpls = pixGetWpl(pixs);
1203
1204 /* Make line buffers for 2 lines of src image */
1205 if ((bufs = (l_uint32 *)LEPT_CALLOC(2 * wpls, sizeof(l_uint32))) == NULL)
1206 return (PIX *)ERROR_PTR("bufs not made", __func__, NULL);
1207
1208 /* Make line buffer for 4 lines of virtual intermediate image */
1209 wplb = (wd + 3) / 4;
1210 if ((lineb = (l_uint32 *)LEPT_CALLOC(4 * wplb, sizeof(l_uint32))) == NULL) {
1211 L_ERROR("lineb not made\n", __func__);
1212 goto cleanup;
1213 }
1214
1215 /* Make line buffer for 1 line of virtual intermediate image */
1216 if ((linebp = (l_uint32 *)LEPT_CALLOC(wplb, sizeof(l_uint32))) == NULL) {
1217 L_ERROR("linebp not made\n", __func__);
1218 goto cleanup;
1219 }
1220
1221 /* Make dest binary image */
1222 if ((pixd = pixCreate(wd, hd, 1)) == NULL) {
1223 L_ERROR("pixd not made\n", __func__);
1224 goto cleanup;
1225 }
1226 pixCopyInputFormat(pixd, pixs);
1227 pixCopyResolution(pixd, pixs);
1228 pixScaleResolution(pixd, 4.0, 4.0);
1229 wpld = pixGetWpl(pixd);
1230 datad = pixGetData(pixd);
1231
1232 /* Start with the first src and the first 3 dest lines */
1233 memcpy(bufs, datas, 4 * wpls); /* first src line */
1234 memcpy(bufs + wpls, datas + wpls, 4 * wpls); /* 2nd src line */
1235 scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 4 b lines */
1236 lined = datad;
1237 for (j = 0; j < 3; j++) { /* first 3 d lines of Q */
1238 ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb,
1239 lineb + (j + 1) * wplb,
1241 }
1242
1243 /* Do all but last src line */
1244 for (i = 1; i < hsm; i++) {
1245 memcpy(bufs, datas + i * wpls, 4 * wpls); /* i-th src line */
1246 memcpy(bufs + wpls, datas + (i + 1) * wpls, 4 * wpls);
1247 memcpy(linebp, lineb + 3 * wplb, 4 * wplb);
1248 scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 4 b lines */
1249 lined = datad + 4 * i * wpld;
1250 ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb,
1252 /* 4th dest line of Q */
1253 for (j = 0; j < 3; j++) { /* next 3 d lines of Quad */
1254 ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb,
1255 lineb + (j + 1) * wplb,
1257 }
1258 }
1259
1260 /* Do the last src line and the last 5 dest lines */
1261 memcpy(bufs, datas + hsm * wpls, 4 * wpls); /* hsm-th src line */
1262 memcpy(linebp, lineb + 3 * wplb, 4 * wplb); /* 1 b line */
1263 scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 1); /* 4 b lines */
1264 lined = datad + 4 * hsm * wpld;
1265 ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb,
1267 /* 4th dest line of Q */
1268 for (j = 0; j < 3; j++) { /* next 3 d lines of Quad */
1269 ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb,
1270 lineb + (j + 1) * wplb,
1272 }
1273 /* And finally, the last dest line */
1274 ditherToBinaryLineLow(lined + 3 * wpld, wd, lineb + 3 * wplb, NULL,
1276
1277cleanup:
1278 LEPT_FREE(bufs);
1279 LEPT_FREE(lineb);
1280 LEPT_FREE(linebp);
1281 return pixd;
1282}
1283
1284
1285/*------------------------------------------------------------------*
1286 * Scaling by closest pixel sampling *
1287 *------------------------------------------------------------------*/
1305PIX *
1307 l_float32 scalex,
1308 l_float32 scaley)
1309{
1310l_int32 ws, hs, d, wpls, wd, hd, wpld;
1311l_uint32 *datas, *datad;
1312PIX *pixd;
1313
1314 if (!pixs)
1315 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1316 if (scalex <= 0.0 || scaley <= 0.0)
1317 return (PIX *)ERROR_PTR("scale factor <= 0", __func__, NULL);
1318 if (scalex == 1.0 && scaley == 1.0)
1319 return pixCopy(NULL, pixs);
1320 if ((d = pixGetDepth(pixs)) == 1)
1321 return pixScaleBinary(pixs, scalex, scaley);
1322
1323 pixGetDimensions(pixs, &ws, &hs, NULL);
1324 datas = pixGetData(pixs);
1325 wpls = pixGetWpl(pixs);
1326 wd = (l_int32)(scalex * (l_float32)ws + 0.5);
1327 hd = (l_int32)(scaley * (l_float32)hs + 0.5);
1328 if ((pixd = pixCreate(wd, hd, d)) == NULL)
1329 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1330 pixCopyResolution(pixd, pixs);
1331 pixScaleResolution(pixd, scalex, scaley);
1332 pixCopyColormap(pixd, pixs);
1333 pixCopyText(pixd, pixs);
1334 pixCopyInputFormat(pixd, pixs);
1335 pixCopySpp(pixd, pixs);
1336 datad = pixGetData(pixd);
1337 wpld = pixGetWpl(pixd);
1338 scaleBySamplingLow(datad, wd, hd, wpld, datas, ws, hs, d, wpls);
1339 if (d == 32 && pixGetSpp(pixs) == 4)
1340 pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley);
1341
1342 return pixd;
1343}
1344
1345
1365PIX *
1367 l_int32 wd,
1368 l_int32 hd)
1369{
1370l_int32 w, h;
1371l_float32 scalex, scaley;
1372
1373 if (!pixs)
1374 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1375 if (wd <= 0 && hd <= 0)
1376 return (PIX *)ERROR_PTR("neither wd nor hd > 0", __func__, NULL);
1377
1378 pixGetDimensions(pixs, &w, &h, NULL);
1379 if (wd <= 0) {
1380 scaley = (l_float32)hd / (l_float32)h;
1381 scalex = scaley;
1382 } else if (hd <= 0) {
1383 scalex = (l_float32)wd / (l_float32)w;
1384 scaley = scalex;
1385 } else {
1386 scalex = (l_float32)wd / (l_float32)w;
1387 scaley = (l_float32)hd / (l_float32)h;
1388 }
1389
1390 return pixScaleBySampling(pixs, scalex, scaley);
1391}
1392
1393
1407PIX *
1409 l_int32 factor)
1410{
1411l_float32 scale;
1412
1413 if (!pixs)
1414 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1415 if (factor <= 1) {
1416 if (factor < 1)
1417 L_ERROR("factor must be >= 1; returning a copy\n", __func__);
1418 return pixCopy(NULL, pixs);
1419 }
1420
1421 scale = 1. / (l_float32)factor;
1422 return pixScaleBySampling(pixs, scale, scale);
1423}
1424
1425
1426/*------------------------------------------------------------------*
1427 * Fast integer factor subsampling RGB to gray *
1428 *------------------------------------------------------------------*/
1447PIX *
1449 l_int32 factor,
1450 l_int32 color)
1451{
1452l_int32 byteval, shift;
1453l_int32 i, j, ws, hs, wd, hd, wpls, wpld;
1454l_uint32 *datas, *words, *datad, *lined;
1455l_float32 scale;
1456PIX *pixd;
1457
1458 if (!pixs)
1459 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1460 if (pixGetDepth(pixs) != 32)
1461 return (PIX *)ERROR_PTR("depth not 32 bpp", __func__, NULL);
1462 if (factor < 1)
1463 return (PIX *)ERROR_PTR("factor must be >= 1", __func__, NULL);
1464
1465 if (color == COLOR_RED)
1466 shift = L_RED_SHIFT;
1467 else if (color == COLOR_GREEN)
1468 shift = L_GREEN_SHIFT;
1469 else if (color == COLOR_BLUE)
1470 shift = L_BLUE_SHIFT;
1471 else
1472 return (PIX *)ERROR_PTR("invalid color", __func__, NULL);
1473
1474 pixGetDimensions(pixs, &ws, &hs, NULL);
1475 datas = pixGetData(pixs);
1476 wpls = pixGetWpl(pixs);
1477
1478 wd = ws / factor;
1479 hd = hs / factor;
1480 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1481 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1482 pixCopyResolution(pixd, pixs);
1483 pixCopyInputFormat(pixd, pixs);
1484 scale = 1. / (l_float32) factor;
1485 pixScaleResolution(pixd, scale, scale);
1486 datad = pixGetData(pixd);
1487 wpld = pixGetWpl(pixd);
1488
1489 for (i = 0; i < hd; i++) {
1490 words = datas + i * factor * wpls;
1491 lined = datad + i * wpld;
1492 for (j = 0; j < wd; j++, words += factor) {
1493 byteval = ((*words) >> shift) & 0xff;
1494 SET_DATA_BYTE(lined, j, byteval);
1495 }
1496 }
1497
1498 return pixd;
1499}
1500
1501
1520PIX *
1522 l_int32 factor,
1523 l_int32 thresh)
1524{
1525l_int32 byteval;
1526l_int32 i, j, ws, hs, wd, hd, wpls, wpld;
1527l_uint32 *datas, *words, *datad, *lined;
1528l_float32 scale;
1529PIX *pixd;
1530
1531 if (!pixs)
1532 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1533 if (factor < 1)
1534 return (PIX *)ERROR_PTR("factor must be >= 1", __func__, NULL);
1535 if (pixGetDepth(pixs) != 32)
1536 return (PIX *)ERROR_PTR("depth not 32 bpp", __func__, NULL);
1537
1538 pixGetDimensions(pixs, &ws, &hs, NULL);
1539 datas = pixGetData(pixs);
1540 wpls = pixGetWpl(pixs);
1541
1542 wd = ws / factor;
1543 hd = hs / factor;
1544 if ((pixd = pixCreate(wd, hd, 1)) == NULL)
1545 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1546 pixCopyResolution(pixd, pixs);
1547 pixCopyInputFormat(pixd, pixs);
1548 scale = 1. / (l_float32) factor;
1549 pixScaleResolution(pixd, scale, scale);
1550 datad = pixGetData(pixd);
1551 wpld = pixGetWpl(pixd);
1552
1553 for (i = 0; i < hd; i++) {
1554 words = datas + i * factor * wpls;
1555 lined = datad + i * wpld;
1556 for (j = 0; j < wd; j++, words += factor) {
1557 byteval = ((*words) >> L_GREEN_SHIFT) & 0xff;
1558 if (byteval < thresh)
1559 SET_DATA_BIT(lined, j);
1560 }
1561 }
1562
1563 return pixd;
1564}
1565
1566
1584PIX *
1586 l_int32 factor,
1587 l_int32 thresh)
1588{
1589l_int32 byteval;
1590l_int32 i, j, ws, hs, wd, hd, wpls, wpld, sj;
1591l_uint32 *datas, *datad, *lines, *lined;
1592l_float32 scale;
1593PIX *pixd;
1594
1595 if (!pixs)
1596 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1597 if (factor < 1)
1598 return (PIX *)ERROR_PTR("factor must be >= 1", __func__, NULL);
1599 if (pixGetDepth(pixs) != 8)
1600 return (PIX *)ERROR_PTR("depth not 8 bpp", __func__, NULL);
1601
1602 pixGetDimensions(pixs, &ws, &hs, NULL);
1603 datas = pixGetData(pixs);
1604 wpls = pixGetWpl(pixs);
1605
1606 wd = ws / factor;
1607 hd = hs / factor;
1608 if ((pixd = pixCreate(wd, hd, 1)) == NULL)
1609 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1610 pixCopyResolution(pixd, pixs);
1611 pixCopyInputFormat(pixd, pixs);
1612 scale = 1. / (l_float32) factor;
1613 pixScaleResolution(pixd, scale, scale);
1614 datad = pixGetData(pixd);
1615 wpld = pixGetWpl(pixd);
1616
1617 for (i = 0; i < hd; i++) {
1618 lines = datas + i * factor * wpls;
1619 lined = datad + i * wpld;
1620 for (j = 0, sj = 0; j < wd; j++, sj += factor) {
1621 byteval = GET_DATA_BYTE(lines, sj);
1622 if (byteval < thresh)
1623 SET_DATA_BIT(lined, j);
1624 }
1625 }
1626
1627 return pixd;
1628}
1629
1630
1631/*------------------------------------------------------------------*
1632 * Downscaling with (antialias) smoothing *
1633 *------------------------------------------------------------------*/
1664PIX *
1666 l_float32 scalex,
1667 l_float32 scaley)
1668{
1669l_int32 ws, hs, d, wd, hd, wpls, wpld, isize;
1670l_uint32 val;
1671l_uint32 *datas, *datad;
1672l_float32 minscale, size;
1673PIX *pixs, *pixd;
1674
1675 if (!pix)
1676 return (PIX *)ERROR_PTR("pix not defined", __func__, NULL);
1677 if (scalex >= 0.7 || scaley >= 0.7) {
1678 L_WARNING("scaling factor not < 0.7; do regular scaling\n", __func__);
1679 return pixScaleGeneral(pix, scalex, scaley, 0.0, 0);
1680 }
1681 d = pixGetDepth(pix);
1682 if (d != 2 && d != 4 && d !=8 && d != 32)
1683 return (PIX *)ERROR_PTR("pix not 2, 4, 8 or 32 bpp", __func__, NULL);
1684
1685 /* Remove colormap; clone if possible; result is either 8 or 32 bpp */
1686 if ((pixs = pixConvertTo8Or32(pix, L_CLONE, 0)) == NULL)
1687 return (PIX *)ERROR_PTR("pixs not made", __func__, NULL);
1688 d = pixGetDepth(pixs);
1689
1690 /* If 1.42 < 1/minscale < 2.5, use isize = 2
1691 * If 2.5 =< 1/minscale < 3.5, use isize = 3, etc.
1692 * Under no conditions use isize < 2 */
1693 minscale = L_MIN(scalex, scaley);
1694 size = 1.0 / minscale; /* ideal filter full width */
1695 isize = L_MIN(10000, L_MAX(2, (l_int32)(size + 0.5)));
1696
1697 pixGetDimensions(pixs, &ws, &hs, NULL);
1698 if ((ws < isize) || (hs < isize)) {
1699 pixd = pixCreate(1, 1, d);
1700 pixGetPixel(pixs, ws / 2, hs / 2, &val);
1701 pixSetPixel(pixd, 0, 0, val);
1702 L_WARNING("ridiculously small scaling factor %f\n", __func__, minscale);
1703 pixDestroy(&pixs);
1704 return pixd;
1705 }
1706
1707 datas = pixGetData(pixs);
1708 wpls = pixGetWpl(pixs);
1709 wd = L_MAX(1, (l_int32)(scalex * (l_float32)ws + 0.5));
1710 hd = L_MAX(1, (l_int32)(scaley * (l_float32)hs + 0.5));
1711 if ((pixd = pixCreate(wd, hd, d)) == NULL) {
1712 pixDestroy(&pixs);
1713 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1714 }
1715 pixCopyResolution(pixd, pixs);
1716 pixCopyInputFormat(pixd, pixs);
1717 pixScaleResolution(pixd, scalex, scaley);
1718 datad = pixGetData(pixd);
1719 wpld = pixGetWpl(pixd);
1720 scaleSmoothLow(datad, wd, hd, wpld, datas, ws, hs, d, wpls, isize);
1721 if (d == 32 && pixGetSpp(pixs) == 4)
1722 pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley);
1723
1724 pixDestroy(&pixs);
1725 return pixd;
1726}
1727
1728
1748PIX *
1750 l_int32 wd,
1751 l_int32 hd)
1752{
1753l_int32 w, h;
1754l_float32 scalex, scaley;
1755
1756 if (!pixs)
1757 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1758 if (wd <= 0 && hd <= 0)
1759 return (PIX *)ERROR_PTR("neither wd nor hd > 0", __func__, NULL);
1760
1761 pixGetDimensions(pixs, &w, &h, NULL);
1762 if (wd <= 0) {
1763 scaley = (l_float32)hd / (l_float32)h;
1764 scalex = scaley;
1765 } else if (hd <= 0) {
1766 scalex = (l_float32)wd / (l_float32)w;
1767 scaley = scalex;
1768 } else {
1769 scalex = (l_float32)wd / (l_float32)w;
1770 scaley = (l_float32)hd / (l_float32)h;
1771 }
1772
1773 return pixScaleSmooth(pixs, scalex, scaley);
1774}
1775
1776
1784PIX *
1786 l_float32 rwt,
1787 l_float32 gwt,
1788 l_float32 bwt)
1789{
1790l_int32 wd, hd, wpls, wpld;
1791l_uint32 *datas, *datad;
1792PIX *pixd;
1793
1794 if (!pixs)
1795 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1796 if (pixGetDepth(pixs) != 32)
1797 return (PIX *)ERROR_PTR("pixs not 32 bpp", __func__, NULL);
1798 if (rwt + gwt + bwt < 0.98 || rwt + gwt + bwt > 1.02)
1799 return (PIX *)ERROR_PTR("sum of wts should be 1.0", __func__, NULL);
1800
1801 wd = pixGetWidth(pixs) / 2;
1802 hd = pixGetHeight(pixs) / 2;
1803 wpls = pixGetWpl(pixs);
1804 datas = pixGetData(pixs);
1805 if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1806 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1807 pixCopyResolution(pixd, pixs);
1808 pixCopyInputFormat(pixd, pixs);
1809 pixScaleResolution(pixd, 0.5, 0.5);
1810 wpld = pixGetWpl(pixd);
1811 datad = pixGetData(pixd);
1812 scaleRGBToGray2Low(datad, wd, hd, wpld, datas, wpls, rwt, gwt, bwt);
1813 return pixd;
1814}
1815
1816
1817/*------------------------------------------------------------------*
1818 * Downscaling with (antialias) area mapping *
1819 *------------------------------------------------------------------*/
1863PIX *
1865 l_float32 scalex,
1866 l_float32 scaley)
1867{
1868l_int32 ws, hs, d, wd, hd, wpls, wpld;
1869l_uint32 *datas, *datad;
1870l_float32 maxscale, minscale;
1871PIX *pixs, *pixd, *pix1, *pix2, *pix3;
1872
1873 if (!pix)
1874 return (PIX *)ERROR_PTR("pix not defined", __func__, NULL);
1875 d = pixGetDepth(pix);
1876 if (d != 2 && d != 4 && d != 8 && d != 32)
1877 return (PIX *)ERROR_PTR("pix not 2, 4, 8 or 32 bpp", __func__, NULL);
1878
1879 minscale = L_MIN(scalex, scaley);
1880 if (minscale < 0.02) { /* too small for area mapping */
1881 L_WARNING("tiny scaling factor; using pixScaleSmooth()\n", __func__);
1882 return pixScaleSmooth(pix, scalex, scaley);
1883 }
1884
1885 maxscale = L_MAX(scalex, scaley);
1886 if (maxscale >= 0.7) { /* too large for area mapping */
1887 L_WARNING("scaling factor >= 0.7; do regular scaling\n", __func__);
1888 return pixScaleGeneral(pix, scalex, scaley, 0.0, 0);
1889 }
1890
1891 /* Special cases: 2x, 4x, 8x, 16x reduction */
1892 if (scalex == 0.5 && scaley == 0.5)
1893 return pixScaleAreaMap2(pix);
1894 if (scalex == 0.25 && scaley == 0.25) {
1895 pix1 = pixScaleAreaMap2(pix);
1896 pixd = pixScaleAreaMap2(pix1);
1897 pixDestroy(&pix1);
1898 return pixd;
1899 }
1900 if (scalex == 0.125 && scaley == 0.125) {
1901 pix1 = pixScaleAreaMap2(pix);
1902 pix2 = pixScaleAreaMap2(pix1);
1903 pixd = pixScaleAreaMap2(pix2);
1904 pixDestroy(&pix1);
1905 pixDestroy(&pix2);
1906 return pixd;
1907 }
1908 if (scalex == 0.0625 && scaley == 0.0625) {
1909 pix1 = pixScaleAreaMap2(pix);
1910 pix2 = pixScaleAreaMap2(pix1);
1911 pix3 = pixScaleAreaMap2(pix2);
1912 pixd = pixScaleAreaMap2(pix3);
1913 pixDestroy(&pix1);
1914 pixDestroy(&pix2);
1915 pixDestroy(&pix3);
1916 return pixd;
1917 }
1918
1919#if 0 /* Not enabled because it breaks too many tests that rely on exact
1920 * pixel matches. */
1921 /* Special case where it is significantly faster to downscale first
1922 * by 2x, with relatively little degradation in image quality. */
1923 if (scalex > 0.35 && scalex < 0.5) {
1924 pix1 = pixScaleAreaMap2(pix);
1925 pixd = pixScaleAreaMap(pix1, 2.0 * scalex, 2.0 * scaley);
1926 pixDestroy(&pix1);
1927 return pixd;
1928 }
1929#endif
1930
1931 /* Remove colormap if necessary.
1932 * If 2 bpp or 4 bpp gray, convert to 8 bpp */
1933 if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
1934 L_WARNING("pix has colormap; removing\n", __func__);
1935 pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC);
1936 d = pixGetDepth(pixs);
1937 } else if (d == 2 || d == 4) {
1938 pixs = pixConvertTo8(pix, FALSE);
1939 d = 8;
1940 } else {
1941 pixs = pixClone(pix);
1942 }
1943
1944 pixGetDimensions(pixs, &ws, &hs, NULL);
1945 datas = pixGetData(pixs);
1946 wpls = pixGetWpl(pixs);
1947 wd = (l_int32)(scalex * (l_float32)ws + 0.5);
1948 hd = (l_int32)(scaley * (l_float32)hs + 0.5);
1949 if (wd < 1 || hd < 1) {
1950 pixDestroy(&pixs);
1951 return (PIX *)ERROR_PTR("pixd too small", __func__, NULL);
1952 }
1953 if ((pixd = pixCreate(wd, hd, d)) == NULL) {
1954 pixDestroy(&pixs);
1955 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
1956 }
1957 pixCopyInputFormat(pixd, pixs);
1958 pixCopyResolution(pixd, pixs);
1959 pixScaleResolution(pixd, scalex, scaley);
1960 datad = pixGetData(pixd);
1961 wpld = pixGetWpl(pixd);
1962 if (d == 8) {
1963 scaleGrayAreaMapLow(datad, wd, hd, wpld, datas, ws, hs, wpls);
1964 } else { /* RGB, d == 32 */
1965 scaleColorAreaMapLow(datad, wd, hd, wpld, datas, ws, hs, wpls);
1966 if (pixGetSpp(pixs) == 4)
1967 pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley);
1968 }
1969
1970 pixDestroy(&pixs);
1971 return pixd;
1972}
1973
1974
1994PIX *
1996{
1997l_int32 wd, hd, d, wpls, wpld;
1998l_uint32 *datas, *datad;
1999PIX *pixs, *pixd;
2000
2001 if (!pix)
2002 return (PIX *)ERROR_PTR("pix not defined", __func__, NULL);
2003 d = pixGetDepth(pix);
2004 if (d != 2 && d != 4 && d != 8 && d != 32)
2005 return (PIX *)ERROR_PTR("pix not 2, 4, 8 or 32 bpp", __func__, NULL);
2006
2007 /* Remove colormap if necessary.
2008 * If 2 bpp or 4 bpp gray, convert to 8 bpp */
2009 if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
2010 L_WARNING("pix has colormap; removing\n", __func__);
2011 pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC);
2012 d = pixGetDepth(pixs);
2013 } else if (d == 2 || d == 4) {
2014 pixs = pixConvertTo8(pix, FALSE);
2015 d = 8;
2016 } else {
2017 pixs = pixClone(pix);
2018 }
2019
2020 wd = pixGetWidth(pixs) / 2;
2021 hd = pixGetHeight(pixs) / 2;
2022 datas = pixGetData(pixs);
2023 wpls = pixGetWpl(pixs);
2024 pixd = pixCreate(wd, hd, d);
2025 datad = pixGetData(pixd);
2026 wpld = pixGetWpl(pixd);
2027 pixCopyInputFormat(pixd, pixs);
2028 pixCopyResolution(pixd, pixs);
2029 pixScaleResolution(pixd, 0.5, 0.5);
2030 scaleAreaMapLow2(datad, wd, hd, wpld, datas, d, wpls);
2031 if (pixGetSpp(pixs) == 4)
2032 pixScaleAndTransferAlpha(pixd, pixs, 0.5, 0.5);
2033 pixDestroy(&pixs);
2034 return pixd;
2035}
2036
2037
2057PIX *
2059 l_int32 wd,
2060 l_int32 hd)
2061{
2062l_int32 w, h;
2063l_float32 scalex, scaley;
2064
2065 if (!pixs)
2066 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2067 if (wd <= 0 && hd <= 0)
2068 return (PIX *)ERROR_PTR("neither wd nor hd > 0", __func__, NULL);
2069
2070 pixGetDimensions(pixs, &w, &h, NULL);
2071 if (wd <= 0) {
2072 scaley = (l_float32)hd / (l_float32)h;
2073 scalex = scaley;
2074 } else if (hd <= 0) {
2075 scalex = (l_float32)wd / (l_float32)w;
2076 scaley = scalex;
2077 } else {
2078 scalex = (l_float32)wd / (l_float32)w;
2079 scaley = (l_float32)hd / (l_float32)h;
2080 }
2081
2082 return pixScaleAreaMap(pixs, scalex, scaley);
2083}
2084
2085
2086/*------------------------------------------------------------------*
2087 * Binary scaling by closest pixel sampling *
2088 *------------------------------------------------------------------*/
2104PIX *
2106 l_float32 scalex,
2107 l_float32 scaley)
2108{
2109l_int32 ws, hs, wpls, wd, hd, wpld;
2110l_uint32 *datas, *datad;
2111PIX *pixd;
2112
2113 if (!pixs)
2114 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
2115 if (pixGetDepth(pixs) != 1)
2116 return (PIX *)ERROR_PTR("pixs must be 1 bpp", __func__, NULL);
2117 if (scalex <= 0.0 || scaley <= 0.0)
2118 return (PIX *)ERROR_PTR("scale factor <= 0", __func__, NULL);
2119 if (scalex == 1.0 && scaley == 1.0)
2120 return pixCopy(NULL, pixs);
2121
2122 pixGetDimensions(pixs, &ws, &hs, NULL);
2123 datas = pixGetData(pixs);
2124 wpls = pixGetWpl(pixs);
2125 wd = (l_int32)(scalex * (l_float32)ws + 0.5);
2126 hd = (l_int32)(scaley * (l_float32)hs + 0.5);
2127 if ((pixd = pixCreate(wd, hd, 1)) == NULL)
2128 return (PIX *)ERROR_PTR("pixd not made", __func__, NULL);
2129 pixCopyColormap(pixd, pixs);
2130 pixCopyText(pixd, pixs);
2131 pixCopyInputFormat(pixd, pixs);
2132 pixCopyResolution(pixd, pixs);
2133 pixScaleResolution(pixd, scalex, scaley);
2134 datad = pixGetData(pixd);
2135 wpld = pixGetWpl(pixd);
2136 scaleBinaryLow(datad, wd, hd, wpld, datas, ws, hs, wpls);
2137 return pixd;
2138}
2139
2140
2141/* ================================================================ *
2142 * Low level static functions *
2143 * ================================================================ */
2144
2145/*------------------------------------------------------------------*
2146 * General linear interpolated color scaling *
2147 *------------------------------------------------------------------*/
2160static void
2161scaleColorLILow(l_uint32 *datad,
2162 l_int32 wd,
2163 l_int32 hd,
2164 l_int32 wpld,
2165 l_uint32 *datas,
2166 l_int32 ws,
2167 l_int32 hs,
2168 l_int32 wpls)
2169{
2170l_int32 i, j, wm2, hm2;
2171l_int32 xpm, ypm; /* location in src image, to 1/16 of a pixel */
2172l_int32 xp, yp, xf, yf; /* src pixel and pixel fraction coordinates */
2173l_uint32 v00r, v01r, v10r, v11r, v00g, v01g, v10g, v11g;
2174l_uint32 v00b, v01b, v10b, v11b, area00, area01, area10, area11;
2175l_uint32 pixels1, pixels2, pixels3, pixels4, pixel;
2176l_uint32 *lines, *lined;
2177l_float32 scx, scy;
2178
2179 /* (scx, scy) are scaling factors that are applied to the
2180 * dest coords to get the corresponding src coords.
2181 * We need them because we iterate over dest pixels
2182 * and must find the corresponding set of src pixels. */
2183 scx = 16. * (l_float32)ws / (l_float32)wd;
2184 scy = 16. * (l_float32)hs / (l_float32)hd;
2185 wm2 = ws - 2;
2186 hm2 = hs - 2;
2187
2188 /* Iterate over the destination pixels */
2189 for (i = 0; i < hd; i++) {
2190 ypm = (l_int32)(scy * (l_float32)i);
2191 yp = ypm >> 4;
2192 yf = ypm & 0x0f;
2193 lined = datad + i * wpld;
2194 lines = datas + yp * wpls;
2195 for (j = 0; j < wd; j++) {
2196 xpm = (l_int32)(scx * (l_float32)j);
2197 xp = xpm >> 4;
2198 xf = xpm & 0x0f;
2199
2200 /* Do bilinear interpolation. This is a simple
2201 * generalization of the calculation in scaleGrayLILow().
2202 * Without this, we could simply subsample:
2203 * *(lined + j) = *(lines + xp);
2204 * which is faster but gives lousy results! */
2205 pixels1 = *(lines + xp);
2206
2207 if (xp > wm2 || yp > hm2) {
2208 if (yp > hm2 && xp <= wm2) { /* pixels near bottom */
2209 pixels2 = *(lines + xp + 1);
2210 pixels3 = pixels1;
2211 pixels4 = pixels2;
2212 } else if (xp > wm2 && yp <= hm2) { /* pixels near rt side */
2213 pixels2 = pixels1;
2214 pixels3 = *(lines + wpls + xp);
2215 pixels4 = pixels3;
2216 } else { /* pixels at LR corner */
2217 pixels4 = pixels3 = pixels2 = pixels1;
2218 }
2219 } else {
2220 pixels2 = *(lines + xp + 1);
2221 pixels3 = *(lines + wpls + xp);
2222 pixels4 = *(lines + wpls + xp + 1);
2223 }
2224
2225 area00 = (16 - xf) * (16 - yf);
2226 area10 = xf * (16 - yf);
2227 area01 = (16 - xf) * yf;
2228 area11 = xf * yf;
2229 v00r = area00 * ((pixels1 >> L_RED_SHIFT) & 0xff);
2230 v00g = area00 * ((pixels1 >> L_GREEN_SHIFT) & 0xff);
2231 v00b = area00 * ((pixels1 >> L_BLUE_SHIFT) & 0xff);
2232 v10r = area10 * ((pixels2 >> L_RED_SHIFT) & 0xff);
2233 v10g = area10 * ((pixels2 >> L_GREEN_SHIFT) & 0xff);
2234 v10b = area10 * ((pixels2 >> L_BLUE_SHIFT) & 0xff);
2235 v01r = area01 * ((pixels3 >> L_RED_SHIFT) & 0xff);
2236 v01g = area01 * ((pixels3 >> L_GREEN_SHIFT) & 0xff);
2237 v01b = area01 * ((pixels3 >> L_BLUE_SHIFT) & 0xff);
2238 v11r = area11 * ((pixels4 >> L_RED_SHIFT) & 0xff);
2239 v11g = area11 * ((pixels4 >> L_GREEN_SHIFT) & 0xff);
2240 v11b = area11 * ((pixels4 >> L_BLUE_SHIFT) & 0xff);
2241 pixel = (((v00r + v10r + v01r + v11r + 128) << 16) & 0xff000000) |
2242 (((v00g + v10g + v01g + v11g + 128) << 8) & 0x00ff0000) |
2243 ((v00b + v10b + v01b + v11b + 128) & 0x0000ff00);
2244 *(lined + j) = pixel;
2245 }
2246 }
2247}
2248
2249
2250/*------------------------------------------------------------------*
2251 * General linear interpolated gray scaling *
2252 *------------------------------------------------------------------*/
2265static void
2266scaleGrayLILow(l_uint32 *datad,
2267 l_int32 wd,
2268 l_int32 hd,
2269 l_int32 wpld,
2270 l_uint32 *datas,
2271 l_int32 ws,
2272 l_int32 hs,
2273 l_int32 wpls)
2274{
2275l_int32 i, j, wm2, hm2;
2276l_int32 xpm, ypm; /* location in src image, to 1/16 of a pixel */
2277l_int32 xp, yp, xf, yf; /* src pixel and pixel fraction coordinates */
2278l_int32 v00, v01, v10, v11, v00_val, v01_val, v10_val, v11_val;
2279l_uint8 val;
2280l_uint32 *lines, *lined;
2281l_float32 scx, scy;
2282
2283 /* (scx, scy) are scaling factors that are applied to the
2284 * dest coords to get the corresponding src coords.
2285 * We need them because we iterate over dest pixels
2286 * and must find the corresponding set of src pixels. */
2287 scx = 16. * (l_float32)ws / (l_float32)wd;
2288 scy = 16. * (l_float32)hs / (l_float32)hd;
2289 wm2 = ws - 2;
2290 hm2 = hs - 2;
2291
2292 /* Iterate over the destination pixels */
2293 for (i = 0; i < hd; i++) {
2294 ypm = (l_int32)(scy * (l_float32)i);
2295 yp = ypm >> 4;
2296 yf = ypm & 0x0f;
2297 lined = datad + i * wpld;
2298 lines = datas + yp * wpls;
2299 for (j = 0; j < wd; j++) {
2300 xpm = (l_int32)(scx * (l_float32)j);
2301 xp = xpm >> 4;
2302 xf = xpm & 0x0f;
2303
2304 /* Do bilinear interpolation. Without this, we could
2305 * simply subsample:
2306 * SET_DATA_BYTE(lined, j, GET_DATA_BYTE(lines, xp));
2307 * which is faster but gives lousy results! */
2308 v00_val = GET_DATA_BYTE(lines, xp);
2309 if (xp > wm2 || yp > hm2) {
2310 if (yp > hm2 && xp <= wm2) { /* pixels near bottom */
2311 v01_val = v00_val;
2312 v10_val = GET_DATA_BYTE(lines, xp + 1);
2313 v11_val = v10_val;
2314 } else if (xp > wm2 && yp <= hm2) { /* pixels near rt side */
2315 v01_val = GET_DATA_BYTE(lines + wpls, xp);
2316 v10_val = v00_val;
2317 v11_val = v01_val;
2318 } else { /* pixels at LR corner */
2319 v10_val = v01_val = v11_val = v00_val;
2320 }
2321 } else {
2322 v10_val = GET_DATA_BYTE(lines, xp + 1);
2323 v01_val = GET_DATA_BYTE(lines + wpls, xp);
2324 v11_val = GET_DATA_BYTE(lines + wpls, xp + 1);
2325 }
2326
2327 v00 = (16 - xf) * (16 - yf) * v00_val;
2328 v10 = xf * (16 - yf) * v10_val;
2329 v01 = (16 - xf) * yf * v01_val;
2330 v11 = xf * yf * v11_val;
2331
2332 val = (l_uint8)((v00 + v01 + v10 + v11 + 128) / 256);
2333 SET_DATA_BYTE(lined, j, val);
2334 }
2335 }
2336}
2337
2338
2339/*------------------------------------------------------------------*
2340 * 2x linear interpolated color scaling *
2341 *------------------------------------------------------------------*/
2382static void
2383scaleColor2xLILow(l_uint32 *datad,
2384 l_int32 wpld,
2385 l_uint32 *datas,
2386 l_int32 ws,
2387 l_int32 hs,
2388 l_int32 wpls)
2389{
2390l_int32 i, hsm;
2391l_uint32 *lines, *lined;
2392
2393 hsm = hs - 1;
2394
2395 /* We're taking 2 src and 2 dest lines at a time,
2396 * and for each src line, we're computing 2 dest lines.
2397 * Call these 2 dest lines: destline1 and destline2.
2398 * The first src line is used for destline 1.
2399 * On all but the last src line, both src lines are
2400 * used in the linear interpolation for destline2.
2401 * On the last src line, both destline1 and destline2
2402 * are computed using only that src line (because there
2403 * isn't a lower src line). */
2404
2405 /* iterate over all but the last src line */
2406 for (i = 0; i < hsm; i++) {
2407 lines = datas + i * wpls;
2408 lined = datad + 2 * i * wpld;
2409 scaleColor2xLILineLow(lined, wpld, lines, ws, wpls, 0);
2410 }
2411
2412 /* last src line */
2413 lines = datas + hsm * wpls;
2414 lined = datad + 2 * hsm * wpld;
2415 scaleColor2xLILineLow(lined, wpld, lines, ws, wpls, 1);
2416}
2417
2418
2430static void
2432 l_int32 wpld,
2433 l_uint32 *lines,
2434 l_int32 ws,
2435 l_int32 wpls,
2436 l_int32 lastlineflag)
2437{
2438l_int32 j, jd, wsm;
2439l_uint32 rval1, rval2, rval3, rval4, gval1, gval2, gval3, gval4;
2440l_uint32 bval1, bval2, bval3, bval4;
2441l_uint32 pixels1, pixels2, pixels3, pixels4, pixel;
2442l_uint32 *linesp, *linedp;
2443
2444 wsm = ws - 1;
2445
2446 if (lastlineflag == 0) {
2447 linesp = lines + wpls;
2448 linedp = lined + wpld;
2449 pixels1 = *lines;
2450 pixels3 = *linesp;
2451
2452 /* initialize with v(2) and v(4) */
2453 rval2 = pixels1 >> 24;
2454 gval2 = (pixels1 >> 16) & 0xff;
2455 bval2 = (pixels1 >> 8) & 0xff;
2456 rval4 = pixels3 >> 24;
2457 gval4 = (pixels3 >> 16) & 0xff;
2458 bval4 = (pixels3 >> 8) & 0xff;
2459
2460 for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
2461 /* shift in previous src values */
2462 rval1 = rval2;
2463 gval1 = gval2;
2464 bval1 = bval2;
2465 rval3 = rval4;
2466 gval3 = gval4;
2467 bval3 = bval4;
2468 /* get new src values */
2469 pixels2 = *(lines + j + 1);
2470 pixels4 = *(linesp + j + 1);
2471 rval2 = pixels2 >> 24;
2472 gval2 = (pixels2 >> 16) & 0xff;
2473 bval2 = (pixels2 >> 8) & 0xff;
2474 rval4 = pixels4 >> 24;
2475 gval4 = (pixels4 >> 16) & 0xff;
2476 bval4 = (pixels4 >> 8) & 0xff;
2477 /* save dest values */
2478 pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
2479 *(lined + jd) = pixel; /* pix 1 */
2480 pixel = ((((rval1 + rval2) << 23) & 0xff000000) |
2481 (((gval1 + gval2) << 15) & 0x00ff0000) |
2482 (((bval1 + bval2) << 7) & 0x0000ff00));
2483 *(lined + jd + 1) = pixel; /* pix 2 */
2484 pixel = ((((rval1 + rval3) << 23) & 0xff000000) |
2485 (((gval1 + gval3) << 15) & 0x00ff0000) |
2486 (((bval1 + bval3) << 7) & 0x0000ff00));
2487 *(linedp + jd) = pixel; /* pix 3 */
2488 pixel = ((((rval1 + rval2 + rval3 + rval4) << 22) & 0xff000000) |
2489 (((gval1 + gval2 + gval3 + gval4) << 14) & 0x00ff0000) |
2490 (((bval1 + bval2 + bval3 + bval4) << 6) & 0x0000ff00));
2491 *(linedp + jd + 1) = pixel; /* pix 4 */
2492 }
2493 /* last src pixel on line */
2494 rval1 = rval2;
2495 gval1 = gval2;
2496 bval1 = bval2;
2497 rval3 = rval4;
2498 gval3 = gval4;
2499 bval3 = bval4;
2500 pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
2501 *(lined + 2 * wsm) = pixel; /* pix 1 */
2502 *(lined + 2 * wsm + 1) = pixel; /* pix 2 */
2503 pixel = ((((rval1 + rval3) << 23) & 0xff000000) |
2504 (((gval1 + gval3) << 15) & 0x00ff0000) |
2505 (((bval1 + bval3) << 7) & 0x0000ff00));
2506 *(linedp + 2 * wsm) = pixel; /* pix 3 */
2507 *(linedp + 2 * wsm + 1) = pixel; /* pix 4 */
2508 } else { /* last row of src pixels: lastlineflag == 1 */
2509 linedp = lined + wpld;
2510 pixels2 = *lines;
2511 rval2 = pixels2 >> 24;
2512 gval2 = (pixels2 >> 16) & 0xff;
2513 bval2 = (pixels2 >> 8) & 0xff;
2514 for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
2515 rval1 = rval2;
2516 gval1 = gval2;
2517 bval1 = bval2;
2518 pixels2 = *(lines + j + 1);
2519 rval2 = pixels2 >> 24;
2520 gval2 = (pixels2 >> 16) & 0xff;
2521 bval2 = (pixels2 >> 8) & 0xff;
2522 pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
2523 *(lined + jd) = pixel; /* pix 1 */
2524 *(linedp + jd) = pixel; /* pix 2 */
2525 pixel = ((((rval1 + rval2) << 23) & 0xff000000) |
2526 (((gval1 + gval2) << 15) & 0x00ff0000) |
2527 (((bval1 + bval2) << 7) & 0x0000ff00));
2528 *(lined + jd + 1) = pixel; /* pix 3 */
2529 *(linedp + jd + 1) = pixel; /* pix 4 */
2530 }
2531 rval1 = rval2;
2532 gval1 = gval2;
2533 bval1 = bval2;
2534 pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
2535 *(lined + 2 * wsm) = pixel; /* pix 1 */
2536 *(lined + 2 * wsm + 1) = pixel; /* pix 2 */
2537 *(linedp + 2 * wsm) = pixel; /* pix 3 */
2538 *(linedp + 2 * wsm + 1) = pixel; /* pix 4 */
2539 }
2540}
2541
2542
2543/*------------------------------------------------------------------*
2544 * 2x linear interpolated gray scaling *
2545 *------------------------------------------------------------------*/
2584static void
2585scaleGray2xLILow(l_uint32 *datad,
2586 l_int32 wpld,
2587 l_uint32 *datas,
2588 l_int32 ws,
2589 l_int32 hs,
2590 l_int32 wpls)
2591{
2592l_int32 i, hsm;
2593l_uint32 *lines, *lined;
2594
2595 hsm = hs - 1;
2596
2597 /* We're taking 2 src and 2 dest lines at a time,
2598 * and for each src line, we're computing 2 dest lines.
2599 * Call these 2 dest lines: destline1 and destline2.
2600 * The first src line is used for destline 1.
2601 * On all but the last src line, both src lines are
2602 * used in the linear interpolation for destline2.
2603 * On the last src line, both destline1 and destline2
2604 * are computed using only that src line (because there
2605 * isn't a lower src line). */
2606
2607 /* iterate over all but the last src line */
2608 for (i = 0; i < hsm; i++) {
2609 lines = datas + i * wpls;
2610 lined = datad + 2 * i * wpld;
2611 scaleGray2xLILineLow(lined, wpld, lines, ws, wpls, 0);
2612 }
2613
2614 /* last src line */
2615 lines = datas + hsm * wpls;
2616 lined = datad + 2 * hsm * wpld;
2617 scaleGray2xLILineLow(lined, wpld, lines, ws, wpls, 1);
2618}
2619
2620
2632static void
2633scaleGray2xLILineLow(l_uint32 *lined,
2634 l_int32 wpld,
2635 l_uint32 *lines,
2636 l_int32 ws,
2637 l_int32 wpls,
2638 l_int32 lastlineflag)
2639{
2640l_int32 j, jd, wsm, w;
2641l_uint32 sval1, sval2, sval3, sval4;
2642l_uint32 *linesp, *linedp;
2643l_uint32 words, wordsp, wordd, worddp;
2644
2645 wsm = ws - 1;
2646
2647 if (lastlineflag == 0) {
2648 linesp = lines + wpls;
2649 linedp = lined + wpld;
2650
2651 /* Unroll the loop 4x and work on full words */
2652 words = lines[0];
2653 wordsp = linesp[0];
2654 sval2 = (words >> 24) & 0xff;
2655 sval4 = (wordsp >> 24) & 0xff;
2656 for (j = 0, jd = 0, w = 0; j + 3 < wsm; j += 4, jd += 8, w++) {
2657 /* At the top of the loop,
2658 * words == lines[w], wordsp == linesp[w]
2659 * and the top bytes of those have been loaded into
2660 * sval2 and sval4. */
2661 sval1 = sval2;
2662 sval2 = (words >> 16) & 0xff;
2663 sval3 = sval4;
2664 sval4 = (wordsp >> 16) & 0xff;
2665 wordd = (sval1 << 24) | (((sval1 + sval2) >> 1) << 16);
2666 worddp = (((sval1 + sval3) >> 1) << 24) |
2667 (((sval1 + sval2 + sval3 + sval4) >> 2) << 16);
2668
2669 sval1 = sval2;
2670 sval2 = (words >> 8) & 0xff;
2671 sval3 = sval4;
2672 sval4 = (wordsp >> 8) & 0xff;
2673 wordd |= (sval1 << 8) | ((sval1 + sval2) >> 1);
2674 worddp |= (((sval1 + sval3) >> 1) << 8) |
2675 ((sval1 + sval2 + sval3 + sval4) >> 2);
2676 lined[w * 2] = wordd;
2677 linedp[w * 2] = worddp;
2678
2679 sval1 = sval2;
2680 sval2 = words & 0xff;
2681 sval3 = sval4;
2682 sval4 = wordsp & 0xff;
2683 wordd = (sval1 << 24) | /* pix 1 */
2684 (((sval1 + sval2) >> 1) << 16); /* pix 2 */
2685 worddp = (((sval1 + sval3) >> 1) << 24) | /* pix 3 */
2686 (((sval1 + sval2 + sval3 + sval4) >> 2) << 16); /* pix 4 */
2687
2688 /* Load the next word as we need its first byte */
2689 words = lines[w + 1];
2690 wordsp = linesp[w + 1];
2691 sval1 = sval2;
2692 sval2 = (words >> 24) & 0xff;
2693 sval3 = sval4;
2694 sval4 = (wordsp >> 24) & 0xff;
2695 wordd |= (sval1 << 8) | /* pix 1 */
2696 ((sval1 + sval2) >> 1); /* pix 2 */
2697 worddp |= (((sval1 + sval3) >> 1) << 8) | /* pix 3 */
2698 ((sval1 + sval2 + sval3 + sval4) >> 2); /* pix 4 */
2699 lined[w * 2 + 1] = wordd;
2700 linedp[w * 2 + 1] = worddp;
2701 }
2702
2703 /* Finish up the last word */
2704 for (; j < wsm; j++, jd += 2) {
2705 sval1 = sval2;
2706 sval3 = sval4;
2707 sval2 = GET_DATA_BYTE(lines, j + 1);
2708 sval4 = GET_DATA_BYTE(linesp, j + 1);
2709 SET_DATA_BYTE(lined, jd, sval1); /* pix 1 */
2710 SET_DATA_BYTE(lined, jd + 1, (sval1 + sval2) / 2); /* pix 2 */
2711 SET_DATA_BYTE(linedp, jd, (sval1 + sval3) / 2); /* pix 3 */
2712 SET_DATA_BYTE(linedp, jd + 1,
2713 (sval1 + sval2 + sval3 + sval4) / 4); /* pix 4 */
2714 }
2715 sval1 = sval2;
2716 sval3 = sval4;
2717 SET_DATA_BYTE(lined, 2 * wsm, sval1); /* pix 1 */
2718 SET_DATA_BYTE(lined, 2 * wsm + 1, sval1); /* pix 2 */
2719 SET_DATA_BYTE(linedp, 2 * wsm, (sval1 + sval3) / 2); /* pix 3 */
2720 SET_DATA_BYTE(linedp, 2 * wsm + 1, (sval1 + sval3) / 2); /* pix 4 */
2721
2722#if DEBUG_UNROLLING
2723#define CHECK_BYTE(a, b, c) if (GET_DATA_BYTE(a, b) != c) {\
2724 lept_stderr("Error: mismatch at %d, %d vs %d\n", \
2725 j, GET_DATA_BYTE(a, b), c); }
2726
2727 sval2 = GET_DATA_BYTE(lines, 0);
2728 sval4 = GET_DATA_BYTE(linesp, 0);
2729 for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
2730 sval1 = sval2;
2731 sval3 = sval4;
2732 sval2 = GET_DATA_BYTE(lines, j + 1);
2733 sval4 = GET_DATA_BYTE(linesp, j + 1);
2734 CHECK_BYTE(lined, jd, sval1); /* pix 1 */
2735 CHECK_BYTE(lined, jd + 1, (sval1 + sval2) / 2); /* pix 2 */
2736 CHECK_BYTE(linedp, jd, (sval1 + sval3) / 2); /* pix 3 */
2737 CHECK_BYTE(linedp, jd + 1,
2738 (sval1 + sval2 + sval3 + sval4) / 4); /* pix 4 */
2739 }
2740 sval1 = sval2;
2741 sval3 = sval4;
2742 CHECK_BYTE(lined, 2 * wsm, sval1); /* pix 1 */
2743 CHECK_BYTE(lined, 2 * wsm + 1, sval1); /* pix 2 */
2744 CHECK_BYTE(linedp, 2 * wsm, (sval1 + sval3) / 2); /* pix 3 */
2745 CHECK_BYTE(linedp, 2 * wsm + 1, (sval1 + sval3) / 2); /* pix 4 */
2746#undef CHECK_BYTE
2747#endif
2748 } else { /* last row of src pixels: lastlineflag == 1 */
2749 linedp = lined + wpld;
2750 sval2 = GET_DATA_BYTE(lines, 0);
2751 for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
2752 sval1 = sval2;
2753 sval2 = GET_DATA_BYTE(lines, j + 1);
2754 SET_DATA_BYTE(lined, jd, sval1); /* pix 1 */
2755 SET_DATA_BYTE(linedp, jd, sval1); /* pix 3 */
2756 SET_DATA_BYTE(lined, jd + 1, (sval1 + sval2) / 2); /* pix 2 */
2757 SET_DATA_BYTE(linedp, jd + 1, (sval1 + sval2) / 2); /* pix 4 */
2758 }
2759 sval1 = sval2;
2760 SET_DATA_BYTE(lined, 2 * wsm, sval1); /* pix 1 */
2761 SET_DATA_BYTE(lined, 2 * wsm + 1, sval1); /* pix 2 */
2762 SET_DATA_BYTE(linedp, 2 * wsm, sval1); /* pix 3 */
2763 SET_DATA_BYTE(linedp, 2 * wsm + 1, sval1); /* pix 4 */
2764 }
2765}
2766
2767
2768/*------------------------------------------------------------------*
2769 * 4x linear interpolated gray scaling *
2770 *------------------------------------------------------------------*/
2825static void
2826scaleGray4xLILow(l_uint32 *datad,
2827 l_int32 wpld,
2828 l_uint32 *datas,
2829 l_int32 ws,
2830 l_int32 hs,
2831 l_int32 wpls)
2832{
2833l_int32 i, hsm;
2834l_uint32 *lines, *lined;
2835
2836 hsm = hs - 1;
2837
2838 /* We're taking 2 src and 4 dest lines at a time,
2839 * and for each src line, we're computing 4 dest lines.
2840 * Call these 4 dest lines: destline1 - destline4.
2841 * The first src line is used for destline 1.
2842 * Two src lines are used for all other dest lines,
2843 * except for the last 4 dest lines, which are computed
2844 * using only the last src line. */
2845
2846 /* iterate over all but the last src line */
2847 for (i = 0; i < hsm; i++) {
2848 lines = datas + i * wpls;
2849 lined = datad + 4 * i * wpld;
2850 scaleGray4xLILineLow(lined, wpld, lines, ws, wpls, 0);
2851 }
2852
2853 /* last src line */
2854 lines = datas + hsm * wpls;
2855 lined = datad + 4 * hsm * wpld;
2856 scaleGray4xLILineLow(lined, wpld, lines, ws, wpls, 1);
2857}
2858
2859
2871static void
2872scaleGray4xLILineLow(l_uint32 *lined,
2873 l_int32 wpld,
2874 l_uint32 *lines,
2875 l_int32 ws,
2876 l_int32 wpls,
2877 l_int32 lastlineflag)
2878{
2879l_int32 j, jd, wsm, wsm4;
2880l_int32 s1, s2, s3, s4, s1t, s2t, s3t, s4t;
2881l_uint32 *linesp, *linedp1, *linedp2, *linedp3;
2882
2883 wsm = ws - 1;
2884 wsm4 = 4 * wsm;
2885
2886 if (lastlineflag == 0) {
2887 linesp = lines + wpls;
2888 linedp1 = lined + wpld;
2889 linedp2 = lined + 2 * wpld;
2890 linedp3 = lined + 3 * wpld;
2891 s2 = GET_DATA_BYTE(lines, 0);
2892 s4 = GET_DATA_BYTE(linesp, 0);
2893 for (j = 0, jd = 0; j < wsm; j++, jd += 4) {
2894 s1 = s2;
2895 s3 = s4;
2896 s2 = GET_DATA_BYTE(lines, j + 1);
2897 s4 = GET_DATA_BYTE(linesp, j + 1);
2898 s1t = 3 * s1;
2899 s2t = 3 * s2;
2900 s3t = 3 * s3;
2901 s4t = 3 * s4;
2902 SET_DATA_BYTE(lined, jd, s1); /* d1 */
2903 SET_DATA_BYTE(lined, jd + 1, (s1t + s2) / 4); /* d2 */
2904 SET_DATA_BYTE(lined, jd + 2, (s1 + s2) / 2); /* d3 */
2905 SET_DATA_BYTE(lined, jd + 3, (s1 + s2t) / 4); /* d4 */
2906 SET_DATA_BYTE(linedp1, jd, (s1t + s3) / 4); /* d5 */
2907 SET_DATA_BYTE(linedp1, jd + 1, (9*s1 + s2t + s3t + s4) / 16); /*d6*/
2908 SET_DATA_BYTE(linedp1, jd + 2, (s1t + s2t + s3 + s4) / 8); /* d7 */
2909 SET_DATA_BYTE(linedp1, jd + 3, (s1t + 9*s2 + s3 + s4t) / 16);/*d8*/
2910 SET_DATA_BYTE(linedp2, jd, (s1 + s3) / 2); /* d9 */
2911 SET_DATA_BYTE(linedp2, jd + 1, (s1t + s2 + s3t + s4) / 8);/* d10 */
2912 SET_DATA_BYTE(linedp2, jd + 2, (s1 + s2 + s3 + s4) / 4); /* d11 */
2913 SET_DATA_BYTE(linedp2, jd + 3, (s1 + s2t + s3 + s4t) / 8);/* d12 */
2914 SET_DATA_BYTE(linedp3, jd, (s1 + s3t) / 4); /* d13 */
2915 SET_DATA_BYTE(linedp3, jd + 1, (s1t + s2 + 9*s3 + s4t) / 16);/*d14*/
2916 SET_DATA_BYTE(linedp3, jd + 2, (s1 + s2 + s3t + s4t) / 8); /* d15 */
2917 SET_DATA_BYTE(linedp3, jd + 3, (s1 + s2t + s3t + 9*s4) / 16);/*d16*/
2918 }
2919 s1 = s2;
2920 s3 = s4;
2921 s1t = 3 * s1;
2922 s3t = 3 * s3;
2923 SET_DATA_BYTE(lined, wsm4, s1); /* d1 */
2924 SET_DATA_BYTE(lined, wsm4 + 1, s1); /* d2 */
2925 SET_DATA_BYTE(lined, wsm4 + 2, s1); /* d3 */
2926 SET_DATA_BYTE(lined, wsm4 + 3, s1); /* d4 */
2927 SET_DATA_BYTE(linedp1, wsm4, (s1t + s3) / 4); /* d5 */
2928 SET_DATA_BYTE(linedp1, wsm4 + 1, (s1t + s3) / 4); /* d6 */
2929 SET_DATA_BYTE(linedp1, wsm4 + 2, (s1t + s3) / 4); /* d7 */
2930 SET_DATA_BYTE(linedp1, wsm4 + 3, (s1t + s3) / 4); /* d8 */
2931 SET_DATA_BYTE(linedp2, wsm4, (s1 + s3) / 2); /* d9 */
2932 SET_DATA_BYTE(linedp2, wsm4 + 1, (s1 + s3) / 2); /* d10 */
2933 SET_DATA_BYTE(linedp2, wsm4 + 2, (s1 + s3) / 2); /* d11 */
2934 SET_DATA_BYTE(linedp2, wsm4 + 3, (s1 + s3) / 2); /* d12 */
2935 SET_DATA_BYTE(linedp3, wsm4, (s1 + s3t) / 4); /* d13 */
2936 SET_DATA_BYTE(linedp3, wsm4 + 1, (s1 + s3t) / 4); /* d14 */
2937 SET_DATA_BYTE(linedp3, wsm4 + 2, (s1 + s3t) / 4); /* d15 */
2938 SET_DATA_BYTE(linedp3, wsm4 + 3, (s1 + s3t) / 4); /* d16 */
2939 } else { /* last row of src pixels: lastlineflag == 1 */
2940 linedp1 = lined + wpld;
2941 linedp2 = lined + 2 * wpld;
2942 linedp3 = lined + 3 * wpld;
2943 s2 = GET_DATA_BYTE(lines, 0);
2944 for (j = 0, jd = 0; j < wsm; j++, jd += 4) {
2945 s1 = s2;
2946 s2 = GET_DATA_BYTE(lines, j + 1);
2947 s1t = 3 * s1;
2948 s2t = 3 * s2;
2949 SET_DATA_BYTE(lined, jd, s1); /* d1 */
2950 SET_DATA_BYTE(lined, jd + 1, (s1t + s2) / 4 ); /* d2 */
2951 SET_DATA_BYTE(lined, jd + 2, (s1 + s2) / 2 ); /* d3 */
2952 SET_DATA_BYTE(lined, jd + 3, (s1 + s2t) / 4 ); /* d4 */
2953 SET_DATA_BYTE(linedp1, jd, s1); /* d5 */
2954 SET_DATA_BYTE(linedp1, jd + 1, (s1t + s2) / 4 ); /* d6 */
2955 SET_DATA_BYTE(linedp1, jd + 2, (s1 + s2) / 2 ); /* d7 */
2956 SET_DATA_BYTE(linedp1, jd + 3, (s1 + s2t) / 4 ); /* d8 */
2957 SET_DATA_BYTE(linedp2, jd, s1); /* d9 */
2958 SET_DATA_BYTE(linedp2, jd + 1, (s1t + s2) / 4 ); /* d10 */
2959 SET_DATA_BYTE(linedp2, jd + 2, (s1 + s2) / 2 ); /* d11 */
2960 SET_DATA_BYTE(linedp2, jd + 3, (s1 + s2t) / 4 ); /* d12 */
2961 SET_DATA_BYTE(linedp3, jd, s1); /* d13 */
2962 SET_DATA_BYTE(linedp3, jd + 1, (s1t + s2) / 4 ); /* d14 */
2963 SET_DATA_BYTE(linedp3, jd + 2, (s1 + s2) / 2 ); /* d15 */
2964 SET_DATA_BYTE(linedp3, jd + 3, (s1 + s2t) / 4 ); /* d16 */
2965 }
2966 s1 = s2;
2967 SET_DATA_BYTE(lined, wsm4, s1); /* d1 */
2968 SET_DATA_BYTE(lined, wsm4 + 1, s1); /* d2 */
2969 SET_DATA_BYTE(lined, wsm4 + 2, s1); /* d3 */
2970 SET_DATA_BYTE(lined, wsm4 + 3, s1); /* d4 */
2971 SET_DATA_BYTE(linedp1, wsm4, s1); /* d5 */
2972 SET_DATA_BYTE(linedp1, wsm4 + 1, s1); /* d6 */
2973 SET_DATA_BYTE(linedp1, wsm4 + 2, s1); /* d7 */
2974 SET_DATA_BYTE(linedp1, wsm4 + 3, s1); /* d8 */
2975 SET_DATA_BYTE(linedp2, wsm4, s1); /* d9 */
2976 SET_DATA_BYTE(linedp2, wsm4 + 1, s1); /* d10 */
2977 SET_DATA_BYTE(linedp2, wsm4 + 2, s1); /* d11 */
2978 SET_DATA_BYTE(linedp2, wsm4 + 3, s1); /* d12 */
2979 SET_DATA_BYTE(linedp3, wsm4, s1); /* d13 */
2980 SET_DATA_BYTE(linedp3, wsm4 + 1, s1); /* d14 */
2981 SET_DATA_BYTE(linedp3, wsm4 + 2, s1); /* d15 */
2982 SET_DATA_BYTE(linedp3, wsm4 + 3, s1); /* d16 */
2983 }
2984}
2985
2986
2987/*------------------------------------------------------------------*
2988 * Grayscale and color scaling by closest pixel sampling *
2989 *------------------------------------------------------------------*/
3005static l_int32
3006scaleBySamplingLow(l_uint32 *datad,
3007 l_int32 wd,
3008 l_int32 hd,
3009 l_int32 wpld,
3010 l_uint32 *datas,
3011 l_int32 ws,
3012 l_int32 hs,
3013 l_int32 d,
3014 l_int32 wpls)
3015{
3016l_int32 i, j;
3017l_int32 xs, prevxs, sval;
3018l_int32 *srow, *scol;
3019l_uint32 csval;
3020l_uint32 *lines, *prevlines, *lined, *prevlined;
3021l_float32 wratio, hratio;
3022
3023 if (d != 2 && d != 4 && d !=8 && d != 16 && d != 32)
3024 return ERROR_INT("pixel depth not supported", __func__, 1);
3025
3026 /* Clear dest */
3027 memset(datad, 0, 4LL * hd * wpld);
3028
3029 /* the source row corresponding to dest row i ==> srow[i]
3030 * the source col corresponding to dest col j ==> scol[j] */
3031 if ((srow = (l_int32 *)LEPT_CALLOC(hd, sizeof(l_int32))) == NULL)
3032 return ERROR_INT("srow not made", __func__, 1);
3033 if ((scol = (l_int32 *)LEPT_CALLOC(wd, sizeof(l_int32))) == NULL) {
3034 LEPT_FREE(srow);
3035 return ERROR_INT("scol not made", __func__, 1);
3036 }
3037
3038 wratio = (l_float32)ws / (l_float32)wd;
3039 hratio = (l_float32)hs / (l_float32)hd;
3040 for (i = 0; i < hd; i++)
3041 srow[i] = L_MIN((l_int32)(hratio * i + 0.5), hs - 1);
3042 for (j = 0; j < wd; j++)
3043 scol[j] = L_MIN((l_int32)(wratio * j + 0.5), ws - 1);
3044
3045 prevlines = NULL;
3046 for (i = 0; i < hd; i++) {
3047 lines = datas + srow[i] * wpls;
3048 lined = datad + i * wpld;
3049 if (lines != prevlines) { /* make dest from new source row */
3050 prevxs = -1;
3051 sval = 0;
3052 csval = 0;
3053 if (d == 2) {
3054 for (j = 0; j < wd; j++) {
3055 xs = scol[j];
3056 if (xs != prevxs) { /* get dest pix from source col */
3057 sval = GET_DATA_DIBIT(lines, xs);
3058 SET_DATA_DIBIT(lined, j, sval);
3059 prevxs = xs;
3060 } else { /* copy prev dest pix */
3061 SET_DATA_DIBIT(lined, j, sval);
3062 }
3063 }
3064 } else if (d == 4) {
3065 for (j = 0; j < wd; j++) {
3066 xs = scol[j];
3067 if (xs != prevxs) { /* get dest pix from source col */
3068 sval = GET_DATA_QBIT(lines, xs);
3069 SET_DATA_QBIT(lined, j, sval);
3070 prevxs = xs;
3071 } else { /* copy prev dest pix */
3072 SET_DATA_QBIT(lined, j, sval);
3073 }
3074 }
3075 } else if (d == 8) {
3076 for (j = 0; j < wd; j++) {
3077 xs = scol[j];
3078 if (xs != prevxs) { /* get dest pix from source col */
3079 sval = GET_DATA_BYTE(lines, xs);
3080 SET_DATA_BYTE(lined, j, sval);
3081 prevxs = xs;
3082 } else { /* copy prev dest pix */
3083 SET_DATA_BYTE(lined, j, sval);
3084 }
3085 }
3086 } else if (d == 16) {
3087 for (j = 0; j < wd; j++) {
3088 xs = scol[j];
3089 if (xs != prevxs) { /* get dest pix from source col */
3090 sval = GET_DATA_TWO_BYTES(lines, xs);
3091 SET_DATA_TWO_BYTES(lined, j, sval);
3092 prevxs = xs;
3093 } else { /* copy prev dest pix */
3094 SET_DATA_TWO_BYTES(lined, j, sval);
3095 }
3096 }
3097 } else { /* d == 32 */
3098 for (j = 0; j < wd; j++) {
3099 xs = scol[j];
3100 if (xs != prevxs) { /* get dest pix from source col */
3101 csval = lines[xs];
3102 lined[j] = csval;
3103 prevxs = xs;
3104 } else { /* copy prev dest pix */
3105 lined[j] = csval;
3106 }
3107 }
3108 }
3109 } else { /* lines == prevlines; copy prev dest row */
3110 prevlined = lined - wpld;
3111 memcpy(lined, prevlined, 4 * wpld);
3112 }
3113 prevlines = lines;
3114 }
3115
3116 LEPT_FREE(srow);
3117 LEPT_FREE(scol);
3118 return 0;
3119}
3120
3121
3122/*------------------------------------------------------------------*
3123 * Color and grayscale downsampling with (antialias) smoothing *
3124 *------------------------------------------------------------------*/
3136static l_int32
3137scaleSmoothLow(l_uint32 *datad,
3138 l_int32 wd,
3139 l_int32 hd,
3140 l_int32 wpld,
3141 l_uint32 *datas,
3142 l_int32 ws,
3143 l_int32 hs,
3144 l_int32 d,
3145 l_int32 wpls,
3146 l_int32 size)
3147{
3148l_int32 i, j, m, n, xstart;
3149l_int32 val, rval, gval, bval;
3150l_int32 *srow, *scol;
3151l_uint32 *lines, *lined, *line, *ppixel;
3152l_uint32 pixel;
3153l_float32 wratio, hratio, norm;
3154
3155 /* Clear dest */
3156 memset(datad, 0, 4LL * wpld * hd);
3157
3158 /* Each dest pixel at (j,i) is computed as the average
3159 of size^2 corresponding src pixels.
3160 We store the UL corner location of the square of
3161 src pixels that correspond to dest pixel (j,i).
3162 The are labeled by the arrays srow[i] and scol[j]. */
3163 if ((srow = (l_int32 *)LEPT_CALLOC(hd, sizeof(l_int32))) == NULL)
3164 return ERROR_INT("srow not made", __func__, 1);
3165 if ((scol = (l_int32 *)LEPT_CALLOC(wd, sizeof(l_int32))) == NULL) {
3166 LEPT_FREE(srow);
3167 return ERROR_INT("scol not made", __func__, 1);
3168 }
3169
3170 norm = 1. / (l_float32)(size * size);
3171 wratio = (l_float32)ws / (l_float32)wd;
3172 hratio = (l_float32)hs / (l_float32)hd;
3173 for (i = 0; i < hd; i++)
3174 srow[i] = L_MIN((l_int32)(hratio * i), hs - size);
3175 for (j = 0; j < wd; j++)
3176 scol[j] = L_MIN((l_int32)(wratio * j), ws - size);
3177
3178 /* For each dest pixel, compute average */
3179 if (d == 8) {
3180 for (i = 0; i < hd; i++) {
3181 lines = datas + srow[i] * wpls;
3182 lined = datad + i * wpld;
3183 for (j = 0; j < wd; j++) {
3184 xstart = scol[j];
3185 val = 0;
3186 for (m = 0; m < size; m++) {
3187 line = lines + m * wpls;
3188 for (n = 0; n < size; n++) {
3189 val += GET_DATA_BYTE(line, xstart + n);
3190 }
3191 }
3192 val = (l_int32)((l_float32)val * norm);
3193 SET_DATA_BYTE(lined, j, val);
3194 }
3195 }
3196 } else { /* d == 32 */
3197 for (i = 0; i < hd; i++) {
3198 lines = datas + srow[i] * wpls;
3199 lined = datad + i * wpld;
3200 for (j = 0; j < wd; j++) {
3201 xstart = scol[j];
3202 rval = gval = bval = 0;
3203 for (m = 0; m < size; m++) {
3204 ppixel = lines + m * wpls + xstart;
3205 for (n = 0; n < size; n++) {
3206 pixel = *(ppixel + n);
3207 rval += (pixel >> L_RED_SHIFT) & 0xff;
3208 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3209 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3210 }
3211 }
3212 rval = (l_int32)((l_float32)rval * norm);
3213 gval = (l_int32)((l_float32)gval * norm);
3214 bval = (l_int32)((l_float32)bval * norm);
3215 composeRGBPixel(rval, gval, bval, lined + j);
3216 }
3217 }
3218 }
3219
3220 LEPT_FREE(srow);
3221 LEPT_FREE(scol);
3222 return 0;
3223}
3224
3225
3235static void
3236scaleRGBToGray2Low(l_uint32 *datad,
3237 l_int32 wd,
3238 l_int32 hd,
3239 l_int32 wpld,
3240 l_uint32 *datas,
3241 l_int32 wpls,
3242 l_float32 rwt,
3243 l_float32 gwt,
3244 l_float32 bwt)
3245{
3246l_int32 i, j, val, rval, gval, bval;
3247l_uint32 *lines, *lined;
3248l_uint32 pixel;
3249
3250 rwt *= 0.25;
3251 gwt *= 0.25;
3252 bwt *= 0.25;
3253 for (i = 0; i < hd; i++) {
3254 lines = datas + 2 * i * wpls;
3255 lined = datad + i * wpld;
3256 for (j = 0; j < wd; j++) {
3257 /* Sum each of the color components from 4 src pixels */
3258 pixel = *(lines + 2 * j);
3259 rval = (pixel >> L_RED_SHIFT) & 0xff;
3260 gval = (pixel >> L_GREEN_SHIFT) & 0xff;
3261 bval = (pixel >> L_BLUE_SHIFT) & 0xff;
3262 pixel = *(lines + 2 * j + 1);
3263 rval += (pixel >> L_RED_SHIFT) & 0xff;
3264 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3265 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3266 pixel = *(lines + wpls + 2 * j);
3267 rval += (pixel >> L_RED_SHIFT) & 0xff;
3268 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3269 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3270 pixel = *(lines + wpls + 2 * j + 1);
3271 rval += (pixel >> L_RED_SHIFT) & 0xff;
3272 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3273 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3274 /* Generate the dest byte as a weighted sum of the averages */
3275 val = (l_int32)(rwt * rval + gwt * gval + bwt * bval);
3276 SET_DATA_BYTE(lined, j, val);
3277 }
3278 }
3279}
3280
3281
3282/*------------------------------------------------------------------*
3283 * General area mapped gray scaling *
3284 *------------------------------------------------------------------*/
3300static void
3301scaleColorAreaMapLow(l_uint32 *datad,
3302 l_int32 wd,
3303 l_int32 hd,
3304 l_int32 wpld,
3305 l_uint32 *datas,
3306 l_int32 ws,
3307 l_int32 hs,
3308 l_int32 wpls)
3309{
3310l_int32 i, j, k, m, wm2, hm2;
3311l_int32 area00, area10, area01, area11, areal, arear, areat, areab;
3312l_int32 xu, yu; /* UL corner in src image, to 1/16 of a pixel */
3313l_int32 xl, yl; /* LR corner in src image, to 1/16 of a pixel */
3314l_int32 xup, yup, xuf, yuf; /* UL src pixel: integer and fraction */
3315l_int32 xlp, ylp, xlf, ylf; /* LR src pixel: integer and fraction */
3316l_int32 delx, dely, area;
3317l_int32 v00r, v00g, v00b; /* contrib. from UL src pixel */
3318l_int32 v01r, v01g, v01b; /* contrib. from LL src pixel */
3319l_int32 v10r, v10g, v10b; /* contrib from UR src pixel */
3320l_int32 v11r, v11g, v11b; /* contrib from LR src pixel */
3321l_int32 vinr, ving, vinb; /* contrib from all full interior src pixels */
3322l_int32 vmidr, vmidg, vmidb; /* contrib from side parts */
3323l_int32 rval, gval, bval;
3324l_uint32 pixel00, pixel10, pixel01, pixel11, pixel;
3325l_uint32 *lines, *lined;
3326l_float32 scx, scy;
3327
3328 /* (scx, scy) are scaling factors that are applied to the
3329 * dest coords to get the corresponding src coords.
3330 * We need them because we iterate over dest pixels
3331 * and must find the corresponding set of src pixels. */
3332 scx = 16. * (l_float32)ws / (l_float32)wd;
3333 scy = 16. * (l_float32)hs / (l_float32)hd;
3334 wm2 = ws - 2;
3335 hm2 = hs - 2;
3336
3337 /* Iterate over the destination pixels */
3338 for (i = 0; i < hd; i++) {
3339 yu = (l_int32)(scy * i);
3340 yl = (l_int32)(scy * (i + 1.0));
3341 yup = yu >> 4;
3342 yuf = yu & 0x0f;
3343 ylp = yl >> 4;
3344 ylf = yl & 0x0f;
3345 dely = ylp - yup;
3346 lined = datad + i * wpld;
3347 lines = datas + yup * wpls;
3348 for (j = 0; j < wd; j++) {
3349 xu = (l_int32)(scx * j);
3350 xl = (l_int32)(scx * (j + 1.0));
3351 xup = xu >> 4;
3352 xuf = xu & 0x0f;
3353 xlp = xl >> 4;
3354 xlf = xl & 0x0f;
3355 delx = xlp - xup;
3356
3357 /* If near the edge, just use a src pixel value */
3358 if (xlp > wm2 || ylp > hm2) {
3359 *(lined + j) = *(lines + xup);
3360 continue;
3361 }
3362
3363 /* Area summed over, in subpixels. This varies
3364 * due to the quantization, so we can't simply take
3365 * the area to be a constant: area = scx * scy. */
3366 area = ((16 - xuf) + 16 * (delx - 1) + xlf) *
3367 ((16 - yuf) + 16 * (dely - 1) + ylf);
3368
3369 /* Do area map summation */
3370 pixel00 = *(lines + xup);
3371 pixel10 = *(lines + xlp);
3372 pixel01 = *(lines + dely * wpls + xup);
3373 pixel11 = *(lines + dely * wpls + xlp);
3374 area00 = (16 - xuf) * (16 - yuf);
3375 area10 = xlf * (16 - yuf);
3376 area01 = (16 - xuf) * ylf;
3377 area11 = xlf * ylf;
3378 v00r = area00 * ((pixel00 >> L_RED_SHIFT) & 0xff);
3379 v00g = area00 * ((pixel00 >> L_GREEN_SHIFT) & 0xff);
3380 v00b = area00 * ((pixel00 >> L_BLUE_SHIFT) & 0xff);
3381 v10r = area10 * ((pixel10 >> L_RED_SHIFT) & 0xff);
3382 v10g = area10 * ((pixel10 >> L_GREEN_SHIFT) & 0xff);
3383 v10b = area10 * ((pixel10 >> L_BLUE_SHIFT) & 0xff);
3384 v01r = area01 * ((pixel01 >> L_RED_SHIFT) & 0xff);
3385 v01g = area01 * ((pixel01 >> L_GREEN_SHIFT) & 0xff);
3386 v01b = area01 * ((pixel01 >> L_BLUE_SHIFT) & 0xff);
3387 v11r = area11 * ((pixel11 >> L_RED_SHIFT) & 0xff);
3388 v11g = area11 * ((pixel11 >> L_GREEN_SHIFT) & 0xff);
3389 v11b = area11 * ((pixel11 >> L_BLUE_SHIFT) & 0xff);
3390 vinr = ving = vinb = 0;
3391 for (k = 1; k < dely; k++) { /* for full src pixels */
3392 for (m = 1; m < delx; m++) {
3393 pixel = *(lines + k * wpls + xup + m);
3394 vinr += 256 * ((pixel >> L_RED_SHIFT) & 0xff);
3395 ving += 256 * ((pixel >> L_GREEN_SHIFT) & 0xff);
3396 vinb += 256 * ((pixel >> L_BLUE_SHIFT) & 0xff);
3397 }
3398 }
3399 vmidr = vmidg = vmidb = 0;
3400 areal = (16 - xuf) * 16;
3401 arear = xlf * 16;
3402 areat = 16 * (16 - yuf);
3403 areab = 16 * ylf;
3404 for (k = 1; k < dely; k++) { /* for left side */
3405 pixel = *(lines + k * wpls + xup);
3406 vmidr += areal * ((pixel >> L_RED_SHIFT) & 0xff);
3407 vmidg += areal * ((pixel >> L_GREEN_SHIFT) & 0xff);
3408 vmidb += areal * ((pixel >> L_BLUE_SHIFT) & 0xff);
3409 }
3410 for (k = 1; k < dely; k++) { /* for right side */
3411 pixel = *(lines + k * wpls + xlp);
3412 vmidr += arear * ((pixel >> L_RED_SHIFT) & 0xff);
3413 vmidg += arear * ((pixel >> L_GREEN_SHIFT) & 0xff);
3414 vmidb += arear * ((pixel >> L_BLUE_SHIFT) & 0xff);
3415 }
3416 for (m = 1; m < delx; m++) { /* for top side */
3417 pixel = *(lines + xup + m);
3418 vmidr += areat * ((pixel >> L_RED_SHIFT) & 0xff);
3419 vmidg += areat * ((pixel >> L_GREEN_SHIFT) & 0xff);
3420 vmidb += areat * ((pixel >> L_BLUE_SHIFT) & 0xff);
3421 }
3422 for (m = 1; m < delx; m++) { /* for bottom side */
3423 pixel = *(lines + dely * wpls + xup + m);
3424 vmidr += areab * ((pixel >> L_RED_SHIFT) & 0xff);
3425 vmidg += areab * ((pixel >> L_GREEN_SHIFT) & 0xff);
3426 vmidb += areab * ((pixel >> L_BLUE_SHIFT) & 0xff);
3427 }
3428
3429 /* Sum all the contributions */
3430 rval = (v00r + v01r + v10r + v11r + vinr + vmidr + 128) / area;
3431 gval = (v00g + v01g + v10g + v11g + ving + vmidg + 128) / area;
3432 bval = (v00b + v01b + v10b + v11b + vinb + vmidb + 128) / area;
3433#if DEBUG_OVERFLOW
3434 if (rval > 255) lept_stderr("rval ovfl: %d\n", rval);
3435 if (gval > 255) lept_stderr("gval ovfl: %d\n", gval);
3436 if (bval > 255) lept_stderr("bval ovfl: %d\n", bval);
3437#endif /* DEBUG_OVERFLOW */
3438 composeRGBPixel(rval, gval, bval, lined + j);
3439 }
3440 }
3441}
3442
3443
3458static void
3459scaleGrayAreaMapLow(l_uint32 *datad,
3460 l_int32 wd,
3461 l_int32 hd,
3462 l_int32 wpld,
3463 l_uint32 *datas,
3464 l_int32 ws,
3465 l_int32 hs,
3466 l_int32 wpls)
3467{
3468l_int32 i, j, k, m, wm2, hm2;
3469l_int32 xu, yu; /* UL corner in src image, to 1/16 of a pixel */
3470l_int32 xl, yl; /* LR corner in src image, to 1/16 of a pixel */
3471l_int32 xup, yup, xuf, yuf; /* UL src pixel: integer and fraction */
3472l_int32 xlp, ylp, xlf, ylf; /* LR src pixel: integer and fraction */
3473l_int32 delx, dely, area;
3474l_int32 v00; /* contrib. from UL src pixel */
3475l_int32 v01; /* contrib. from LL src pixel */
3476l_int32 v10; /* contrib from UR src pixel */
3477l_int32 v11; /* contrib from LR src pixel */
3478l_int32 vin; /* contrib from all full interior src pixels */
3479l_int32 vmid; /* contrib from side parts that are full in 1 direction */
3480l_int32 val;
3481l_uint32 *lines, *lined;
3482l_float32 scx, scy;
3483
3484 /* (scx, scy) are scaling factors that are applied to the
3485 * dest coords to get the corresponding src coords.
3486 * We need them because we iterate over dest pixels
3487 * and must find the corresponding set of src pixels. */
3488 scx = 16. * (l_float32)ws / (l_float32)wd;
3489 scy = 16. * (l_float32)hs / (l_float32)hd;
3490 wm2 = ws - 2;
3491 hm2 = hs - 2;
3492
3493 /* Iterate over the destination pixels */
3494 for (i = 0; i < hd; i++) {
3495 yu = (l_int32)(scy * i);
3496 yl = (l_int32)(scy * (i + 1.0));
3497 yup = yu >> 4;
3498 yuf = yu & 0x0f;
3499 ylp = yl >> 4;
3500 ylf = yl & 0x0f;
3501 dely = ylp - yup;
3502 lined = datad + i * wpld;
3503 lines = datas + yup * wpls;
3504 for (j = 0; j < wd; j++) {
3505 xu = (l_int32)(scx * j);
3506 xl = (l_int32)(scx * (j + 1.0));
3507 xup = xu >> 4;
3508 xuf = xu & 0x0f;
3509 xlp = xl >> 4;
3510 xlf = xl & 0x0f;
3511 delx = xlp - xup;
3512
3513 /* If near the edge, just use a src pixel value */
3514 if (xlp > wm2 || ylp > hm2) {
3515 SET_DATA_BYTE(lined, j, GET_DATA_BYTE(lines, xup));
3516 continue;
3517 }
3518
3519 /* Area summed over, in subpixels. This varies
3520 * due to the quantization, so we can't simply take
3521 * the area to be a constant: area = scx * scy. */
3522 area = ((16 - xuf) + 16 * (delx - 1) + xlf) *
3523 ((16 - yuf) + 16 * (dely - 1) + ylf);
3524
3525 /* Do area map summation */
3526 v00 = (16 - xuf) * (16 - yuf) * GET_DATA_BYTE(lines, xup);
3527 v10 = xlf * (16 - yuf) * GET_DATA_BYTE(lines, xlp);
3528 v01 = (16 - xuf) * ylf * GET_DATA_BYTE(lines + dely * wpls, xup);
3529 v11 = xlf * ylf * GET_DATA_BYTE(lines + dely * wpls, xlp);
3530 for (vin = 0, k = 1; k < dely; k++) { /* for full src pixels */
3531 for (m = 1; m < delx; m++) {
3532 vin += 256 * GET_DATA_BYTE(lines + k * wpls, xup + m);
3533 }
3534 }
3535 for (vmid = 0, k = 1; k < dely; k++) /* for left side */
3536 vmid += (16 - xuf) * 16 * GET_DATA_BYTE(lines + k * wpls, xup);
3537 for (k = 1; k < dely; k++) /* for right side */
3538 vmid += xlf * 16 * GET_DATA_BYTE(lines + k * wpls, xlp);
3539 for (m = 1; m < delx; m++) /* for top side */
3540 vmid += 16 * (16 - yuf) * GET_DATA_BYTE(lines, xup + m);
3541 for (m = 1; m < delx; m++) /* for bottom side */
3542 vmid += 16 * ylf * GET_DATA_BYTE(lines + dely * wpls, xup + m);
3543 val = (v00 + v01 + v10 + v11 + vin + vmid + 128) / area;
3544#if DEBUG_OVERFLOW
3545 if (val > 255) lept_stderr("val overflow: %d\n", val);
3546#endif /* DEBUG_OVERFLOW */
3547 SET_DATA_BYTE(lined, j, val);
3548 }
3549 }
3550}
3551
3552
3553/*------------------------------------------------------------------*
3554 * 2x area mapped downscaling *
3555 *------------------------------------------------------------------*/
3565static void
3566scaleAreaMapLow2(l_uint32 *datad,
3567 l_int32 wd,
3568 l_int32 hd,
3569 l_int32 wpld,
3570 l_uint32 *datas,
3571 l_int32 d,
3572 l_int32 wpls)
3573{
3574l_int32 i, j, val, rval, gval, bval;
3575l_uint32 *lines, *lined;
3576l_uint32 pixel;
3577
3578 if (d == 8) {
3579 for (i = 0; i < hd; i++) {
3580 lines = datas + 2 * i * wpls;
3581 lined = datad + i * wpld;
3582 for (j = 0; j < wd; j++) {
3583 /* Average each dest pixel using 4 src pixels */
3584 val = GET_DATA_BYTE(lines, 2 * j);
3585 val += GET_DATA_BYTE(lines, 2 * j + 1);
3586 val += GET_DATA_BYTE(lines + wpls, 2 * j);
3587 val += GET_DATA_BYTE(lines + wpls, 2 * j + 1);
3588 val >>= 2;
3589 SET_DATA_BYTE(lined, j, val);
3590 }
3591 }
3592 } else { /* d == 32 */
3593 for (i = 0; i < hd; i++) {
3594 lines = datas + 2 * i * wpls;
3595 lined = datad + i * wpld;
3596 for (j = 0; j < wd; j++) {
3597 /* Average each of the color components from 4 src pixels */
3598 pixel = *(lines + 2 * j);
3599 rval = (pixel >> L_RED_SHIFT) & 0xff;
3600 gval = (pixel >> L_GREEN_SHIFT) & 0xff;
3601 bval = (pixel >> L_BLUE_SHIFT) & 0xff;
3602 pixel = *(lines + 2 * j + 1);
3603 rval += (pixel >> L_RED_SHIFT) & 0xff;
3604 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3605 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3606 pixel = *(lines + wpls + 2 * j);
3607 rval += (pixel >> L_RED_SHIFT) & 0xff;
3608 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3609 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3610 pixel = *(lines + wpls + 2 * j + 1);
3611 rval += (pixel >> L_RED_SHIFT) & 0xff;
3612 gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3613 bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3614 composeRGBPixel(rval >> 2, gval >> 2, bval >> 2, &pixel);
3615 *(lined + j) = pixel;
3616 }
3617 }
3618 }
3619}
3620
3621
3622/*------------------------------------------------------------------*
3623 * Binary scaling by closest pixel sampling *
3624 *------------------------------------------------------------------*/
3625/*
3626 * \brief scaleBinaryLow()
3627 *
3628 * <pre>
3629 * Notes:
3630 * (1) The dest must be cleared prior to this operation,
3631 * and we clear it here in the low-level code.
3632 * (2) We reuse dest pixels and dest pixel rows whenever
3633 * possible for upscaling; downscaling is done by
3634 * strict subsampling.
3635 * </pre>
3636 */
3637static l_int32
3638scaleBinaryLow(l_uint32 *datad,
3639 l_int32 wd,
3640 l_int32 hd,
3641 l_int32 wpld,
3642 l_uint32 *datas,
3643 l_int32 ws,
3644 l_int32 hs,
3645 l_int32 wpls)
3646{
3647l_int32 i, j;
3648l_int32 xs, prevxs, sval;
3649l_int32 *srow, *scol;
3650l_uint32 *lines, *prevlines, *lined, *prevlined;
3651l_float32 wratio, hratio;
3652
3653 /* Clear dest */
3654 memset(datad, 0, 4LL * hd * wpld);
3655
3656 /* The source row corresponding to dest row i ==> srow[i]
3657 * The source col corresponding to dest col j ==> scol[j] */
3658 if ((srow = (l_int32 *)LEPT_CALLOC(hd, sizeof(l_int32))) == NULL)
3659 return ERROR_INT("srow not made", __func__, 1);
3660 if ((scol = (l_int32 *)LEPT_CALLOC(wd, sizeof(l_int32))) == NULL) {
3661 LEPT_FREE(srow);
3662 return ERROR_INT("scol not made", __func__, 1);
3663 }
3664
3665 wratio = (l_float32)ws / (l_float32)wd;
3666 hratio = (l_float32)hs / (l_float32)hd;
3667 for (i = 0; i < hd; i++)
3668 srow[i] = L_MIN((l_int32)(hratio * i + 0.5), hs - 1);
3669 for (j = 0; j < wd; j++)
3670 scol[j] = L_MIN((l_int32)(wratio * j + 0.5), ws - 1);
3671
3672 prevlines = NULL;
3673 prevxs = -1;
3674 sval = 0;
3675 for (i = 0; i < hd; i++) {
3676 lines = datas + srow[i] * wpls;
3677 lined = datad + i * wpld;
3678 if (lines != prevlines) { /* make dest from new source row */
3679 for (j = 0; j < wd; j++) {
3680 xs = scol[j];
3681 if (xs != prevxs) { /* get dest pix from source col */
3682 if ((sval = GET_DATA_BIT(lines, xs)))
3683 SET_DATA_BIT(lined, j);
3684 prevxs = xs;
3685 } else { /* copy prev dest pix, if set */
3686 if (sval)
3687 SET_DATA_BIT(lined, j);
3688 }
3689 }
3690 } else { /* lines == prevlines; copy prev dest row */
3691 prevlined = lined - wpld;
3692 memcpy(lined, prevlined, 4 * wpld);
3693 }
3694 prevlines = lines;
3695 }
3696
3697 LEPT_FREE(srow);
3698 LEPT_FREE(scol);
3699 return 0;
3700}
#define GET_DATA_QBIT(pdata, n)
#define GET_DATA_TWO_BYTES(pdata, n)
#define SET_DATA_BIT(pdata, n)
#define SET_DATA_DIBIT(pdata, n, val)
#define SET_DATA_TWO_BYTES(pdata, n, val)
#define GET_DATA_BYTE(pdata, n)
#define GET_DATA_DIBIT(pdata, n)
#define SET_DATA_BYTE(pdata, n, val)
#define GET_DATA_BIT(pdata, n)
#define SET_DATA_QBIT(pdata, n, val)
@ REMOVE_CMAP_BASED_ON_SRC
Definition pix.h:384
@ L_CLONE
Definition pix.h:506
struct Pix PIX
Definition pix.h:228
@ COLOR_BLUE
Definition pix.h:330
@ COLOR_RED
Definition pix.h:328
@ COLOR_GREEN
Definition pix.h:329
@ DEFAULT_CLIP_LOWER_1
Definition pix.h:728
@ DEFAULT_CLIP_UPPER_1
Definition pix.h:729
PIX * pixScaleGray4xLIDither(PIX *pixs)
pixScaleGray4xLIDither()
Definition scale1.c:1183
PIX * pixScaleLI(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleLI()
Definition scale1.c:506
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:3006
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:3566
PIX * pixScaleAreaMap2(PIX *pix)
pixScaleAreaMap2()
Definition scale1.c:1995
PIX * pixScaleGrayToBinaryFast(PIX *pixs, l_int32 factor, l_int32 thresh)
pixScaleGrayToBinaryFast()
Definition scale1.c:1585
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:2872
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:2633
PIX * pixScaleColor4xLI(PIX *pixs)
pixScaleColor4xLI()
Definition scale1.c:670
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:3301
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:2266
PIX * pixScaleBinary(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleBinary()
Definition scale1.c:2105
PIX * pixScaleGray2xLIThresh(PIX *pixs, l_int32 thresh)
pixScaleGray2xLIThresh()
Definition scale1.c:903
PIX * pixScaleByIntSampling(PIX *pixs, l_int32 factor)
pixScaleByIntSampling()
Definition scale1.c:1408
PIX * pixScaleGray2xLI(PIX *pixs)
pixScaleGray2xLI()
Definition scale1.c:821
PIX * pixScaleSmooth(PIX *pix, l_float32 scalex, l_float32 scaley)
pixScaleSmooth()
Definition scale1.c:1665
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:2161
PIX * pixScaleColor2xLI(PIX *pixs)
pixScaleColor2xLI()
Definition scale1.c:625
PIX * pixScaleGray2xLIDither(PIX *pixs)
pixScaleGray2xLIDither()
Definition scale1.c:980
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:3137
PIX * pixScaleGray4xLIThresh(PIX *pixs, l_int32 thresh)
pixScaleGray4xLIThresh()
Definition scale1.c:1097
PIX * pixScaleGray4xLI(PIX *pixs)
pixScaleGray4xLI()
Definition scale1.c:860
PIX * pixScaleBySamplingToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleBySamplingToSize()
Definition scale1.c:1366
PIX * pixScaleBySampling(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleBySampling()
Definition scale1.c:1306
PIX * pixScaleColorLI(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleColorLI()
Definition scale1.c:563
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:2383
PIX * pixScaleToSizeRel(PIX *pixs, l_int32 delw, l_int32 delh)
pixScaleToSizeRel()
Definition scale1.c:278
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:2826
PIX * pixScaleRGBToGray2(PIX *pixs, l_float32 rwt, l_float32 gwt, l_float32 bwt)
pixScaleRGBToGray2()
Definition scale1.c:1785
PIX * pixScaleSmoothToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleSmoothToSize()
Definition scale1.c:1749
PIX * pixScaleRGBToBinaryFast(PIX *pixs, l_int32 factor, l_int32 thresh)
pixScaleRGBToBinaryFast()
Definition scale1.c:1521
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:3236
PIX * pixScaleRGBToGrayFast(PIX *pixs, l_int32 factor, l_int32 color)
pixScaleRGBToGrayFast()
Definition scale1.c:1448
PIX * pixScaleToResolution(PIX *pixs, l_float32 target, l_float32 assumed, l_float32 *pscalefact)
pixScaleToResolution()
Definition scale1.c:357
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:2585
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:3459
PIX * pixScaleToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleToSize()
Definition scale1.c:319
PIX * pixScaleAreaMapToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleAreaMapToSize()
Definition scale1.c:2058
PIX * pixScaleGrayLI(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleGrayLI()
Definition scale1.c:762
PIX * pixScaleGeneral(PIX *pixs, l_float32 scalex, l_float32 scaley, l_float32 sharpfract, l_int32 sharpwidth)
pixScaleGeneral()
Definition scale1.c:415
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:2431
PIX * pixScaleAreaMap(PIX *pix, l_float32 scalex, l_float32 scaley)
pixScaleAreaMap()
Definition scale1.c:1864