Leptonica  1.83.1
Image processing and image analysis suite
scale1.c
Go to the documentation of this file.
1 /*====================================================================*
2  - Copyright (C) 2001 Leptonica. All rights reserved.
3  -
4  - Redistribution and use in source and binary forms, with or without
5  - modification, are permitted provided that the following conditions
6  - are met:
7  - 1. Redistributions of source code must retain the above copyright
8  - notice, this list of conditions and the following disclaimer.
9  - 2. Redistributions in binary form must reproduce the above
10  - copyright notice, this list of conditions and the following
11  - disclaimer in the documentation and/or other materials
12  - provided with the distribution.
13  -
14  - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15  - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16  - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17  - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18  - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23  - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *====================================================================*/
26 
114 #ifdef HAVE_CONFIG_H
115 #include <config_auto.h>
116 #endif /* HAVE_CONFIG_H */
117 
118 #include <string.h>
119 #include "allheaders.h"
120 
121 static 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);
124 static 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);
127 static void scaleColor2xLILow(l_uint32 *datad, l_int32 wpld, l_uint32 *datas,
128  l_int32 ws, l_int32 hs, l_int32 wpls);
129 static void scaleColor2xLILineLow(l_uint32 *lined, l_int32 wpld,
130  l_uint32 *lines, l_int32 ws, l_int32 wpls,
131  l_int32 lastlineflag);
132 static void scaleGray2xLILow(l_uint32 *datad, l_int32 wpld, l_uint32 *datas,
133  l_int32 ws, l_int32 hs, l_int32 wpls);
134 static void scaleGray2xLILineLow(l_uint32 *lined, l_int32 wpld,
135  l_uint32 *lines, l_int32 ws, l_int32 wpls,
136  l_int32 lastlineflag);
137 static void scaleGray4xLILow(l_uint32 *datad, l_int32 wpld, l_uint32 *datas,
138  l_int32 ws, l_int32 hs, l_int32 wpls);
139 static void scaleGray4xLILineLow(l_uint32 *lined, l_int32 wpld,
140  l_uint32 *lines, l_int32 ws, l_int32 wpls,
141  l_int32 lastlineflag);
142 static 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);
145 static 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);
149 static 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);
152 static 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);
155 static 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);
158 static 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);
161 static 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  *------------------------------------------------------------------*/
249 PIX *
250 pixScale(PIX *pixs,
251  l_float32 scalex,
252  l_float32 scaley)
253 {
254 l_int32 sharpwidth;
255 l_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 
277 PIX *
279  l_int32 delw,
280  l_int32 delh)
281 {
282 l_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 
318 PIX *
320  l_int32 wd,
321  l_int32 hd)
322 {
323 l_int32 w, h;
324 l_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 
356 PIX *
358  l_float32 target,
359  l_float32 assumed,
360  l_float32 *pscalefact)
361 {
362 l_int32 xres;
363 l_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 
414 PIX *
416  l_float32 scalex,
417  l_float32 scaley,
418  l_float32 sharpfract,
419  l_int32 sharpwidth)
420 {
421 l_int32 d;
422 l_float32 maxscale, minscale;
423 PIX *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  *------------------------------------------------------------------*/
505 PIX *
507  l_float32 scalex,
508  l_float32 scaley)
509 {
510 l_int32 d;
511 l_float32 maxscale;
512 PIX *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 
562 PIX *
564  l_float32 scalex,
565  l_float32 scaley)
566 {
567 l_int32 ws, hs, wpls, wd, hd, wpld;
568 l_uint32 *datas, *datad;
569 l_float32 maxscale;
570 PIX *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 
624 PIX *
626 {
627 l_int32 ws, hs, wpls, wpld;
628 l_uint32 *datas, *datad;
629 PIX *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 
669 PIX *
671 {
672 PIX *pixr, *pixg, *pixb;
673 PIX *pixrs, *pixgs, *pixbs;
674 PIX *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 
761 PIX *
763  l_float32 scalex,
764  l_float32 scaley)
765 {
766 l_int32 ws, hs, wpls, wd, hd, wpld;
767 l_uint32 *datas, *datad;
768 l_float32 maxscale;
769 PIX *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 
820 PIX *
822 {
823 l_int32 ws, hs, wpls, wpld;
824 l_uint32 *datas, *datad;
825 PIX *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 
859 PIX *
861 {
862 l_int32 ws, hs, wpls, wpld;
863 l_uint32 *datas, *datad;
864 PIX *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  *------------------------------------------------------------------*/
902 PIX *
904  l_int32 thresh)
905 {
906 l_int32 i, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
907 l_uint32 *datas, *datad, *lines, *lined, *lineb;
908 PIX *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 
979 PIX *
981 {
982 l_int32 i, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
983 l_uint32 *datas, *datad;
984 l_uint32 *lined;
985 l_uint32 *lineb = NULL; /* 2 intermediate buffer lines */
986 l_uint32 *linebp = NULL; /* 1 intermediate buffer line */
987 l_uint32 *bufs = NULL; /* 2 source buffer lines */
988 PIX *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 
1067 cleanup:
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  *------------------------------------------------------------------*/
1096 PIX *
1098  l_int32 thresh)
1099 {
1100 l_int32 i, j, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
1101 l_uint32 *datas, *datad, *lines, *lined, *lineb;
1102 PIX *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 
1182 PIX *
1184 {
1185 l_int32 i, j, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
1186 l_uint32 *datas, *datad;
1187 l_uint32 *lined;
1188 l_uint32 *lineb = NULL; /* 4 intermediate buffer lines */
1189 l_uint32 *linebp = NULL; /* 1 intermediate buffer line */
1190 l_uint32 *bufs = NULL; /* 2 source buffer lines */
1191 PIX *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 
1277 cleanup:
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  *------------------------------------------------------------------*/
1305 PIX *
1307  l_float32 scalex,
1308  l_float32 scaley)
1309 {
1310 l_int32 ws, hs, d, wpls, wd, hd, wpld;
1311 l_uint32 *datas, *datad;
1312 PIX *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 
1365 PIX *
1367  l_int32 wd,
1368  l_int32 hd)
1369 {
1370 l_int32 w, h;
1371 l_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 
1407 PIX *
1409  l_int32 factor)
1410 {
1411 l_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  *------------------------------------------------------------------*/
1447 PIX *
1449  l_int32 factor,
1450  l_int32 color)
1451 {
1452 l_int32 byteval, shift;
1453 l_int32 i, j, ws, hs, wd, hd, wpls, wpld;
1454 l_uint32 *datas, *words, *datad, *lined;
1455 l_float32 scale;
1456 PIX *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 
1520 PIX *
1522  l_int32 factor,
1523  l_int32 thresh)
1524 {
1525 l_int32 byteval;
1526 l_int32 i, j, ws, hs, wd, hd, wpls, wpld;
1527 l_uint32 *datas, *words, *datad, *lined;
1528 l_float32 scale;
1529 PIX *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 
1584 PIX *
1586  l_int32 factor,
1587  l_int32 thresh)
1588 {
1589 l_int32 byteval;
1590 l_int32 i, j, ws, hs, wd, hd, wpls, wpld, sj;
1591 l_uint32 *datas, *datad, *lines, *lined;
1592 l_float32 scale;
1593 PIX *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  *------------------------------------------------------------------*/
1664 PIX *
1666  l_float32 scalex,
1667  l_float32 scaley)
1668 {
1669 l_int32 ws, hs, d, wd, hd, wpls, wpld, isize;
1670 l_uint32 val;
1671 l_uint32 *datas, *datad;
1672 l_float32 minscale, size;
1673 PIX *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 
1748 PIX *
1750  l_int32 wd,
1751  l_int32 hd)
1752 {
1753 l_int32 w, h;
1754 l_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 
1784 PIX *
1786  l_float32 rwt,
1787  l_float32 gwt,
1788  l_float32 bwt)
1789 {
1790 l_int32 wd, hd, wpls, wpld;
1791 l_uint32 *datas, *datad;
1792 PIX *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  *------------------------------------------------------------------*/
1863 PIX *
1865  l_float32 scalex,
1866  l_float32 scaley)
1867 {
1868 l_int32 ws, hs, d, wd, hd, wpls, wpld;
1869 l_uint32 *datas, *datad;
1870 l_float32 maxscale, minscale;
1871 PIX *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__);
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 
1994 PIX *
1996 {
1997 l_int32 wd, hd, d, wpls, wpld;
1998 l_uint32 *datas, *datad;
1999 PIX *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__);
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 
2057 PIX *
2059  l_int32 wd,
2060  l_int32 hd)
2061 {
2062 l_int32 w, h;
2063 l_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  *------------------------------------------------------------------*/
2104 PIX *
2106  l_float32 scalex,
2107  l_float32 scaley)
2108 {
2109 l_int32 ws, hs, wpls, wd, hd, wpld;
2110 l_uint32 *datas, *datad;
2111 PIX *pixd;
2112 
2113  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  *------------------------------------------------------------------*/
2160 static void
2161 scaleColorLILow(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 {
2170 l_int32 i, j, wm2, hm2;
2171 l_int32 xpm, ypm; /* location in src image, to 1/16 of a pixel */
2172 l_int32 xp, yp, xf, yf; /* src pixel and pixel fraction coordinates */
2173 l_uint32 v00r, v01r, v10r, v11r, v00g, v01g, v10g, v11g;
2174 l_uint32 v00b, v01b, v10b, v11b, area00, area01, area10, area11;
2175 l_uint32 pixels1, pixels2, pixels3, pixels4, pixel;
2176 l_uint32 *lines, *lined;
2177 l_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  *------------------------------------------------------------------*/
2265 static void
2266 scaleGrayLILow(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 {
2275 l_int32 i, j, wm2, hm2;
2276 l_int32 xpm, ypm; /* location in src image, to 1/16 of a pixel */
2277 l_int32 xp, yp, xf, yf; /* src pixel and pixel fraction coordinates */
2278 l_int32 v00, v01, v10, v11, v00_val, v01_val, v10_val, v11_val;
2279 l_uint8 val;
2280 l_uint32 *lines, *lined;
2281 l_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  *------------------------------------------------------------------*/
2382 static void
2383 scaleColor2xLILow(l_uint32 *datad,
2384  l_int32 wpld,
2385  l_uint32 *datas,
2386  l_int32 ws,
2387  l_int32 hs,
2388  l_int32 wpls)
2389 {
2390 l_int32 i, hsm;
2391 l_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 
2430 static void
2431 scaleColor2xLILineLow(l_uint32 *lined,
2432  l_int32 wpld,
2433  l_uint32 *lines,
2434  l_int32 ws,
2435  l_int32 wpls,
2436  l_int32 lastlineflag)
2437 {
2438 l_int32 j, jd, wsm;
2439 l_uint32 rval1, rval2, rval3, rval4, gval1, gval2, gval3, gval4;
2440 l_uint32 bval1, bval2, bval3, bval4;
2441 l_uint32 pixels1, pixels2, pixels3, pixels4, pixel;
2442 l_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  *------------------------------------------------------------------*/
2584 static void
2585 scaleGray2xLILow(l_uint32 *datad,
2586  l_int32 wpld,
2587  l_uint32 *datas,
2588  l_int32 ws,
2589  l_int32 hs,
2590  l_int32 wpls)
2591 {
2592 l_int32 i, hsm;
2593 l_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 
2632 static void
2633 scaleGray2xLILineLow(l_uint32 *lined,
2634  l_int32 wpld,
2635  l_uint32 *lines,
2636  l_int32 ws,
2637  l_int32 wpls,
2638  l_int32 lastlineflag)
2639 {
2640 l_int32 j, jd, wsm, w;
2641 l_uint32 sval1, sval2, sval3, sval4;
2642 l_uint32 *linesp, *linedp;
2643 l_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  *------------------------------------------------------------------*/
2825 static void
2826 scaleGray4xLILow(l_uint32 *datad,
2827  l_int32 wpld,
2828  l_uint32 *datas,
2829  l_int32 ws,
2830  l_int32 hs,
2831  l_int32 wpls)
2832 {
2833 l_int32 i, hsm;
2834 l_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 
2871 static void
2872 scaleGray4xLILineLow(l_uint32 *lined,
2873  l_int32 wpld,
2874  l_uint32 *lines,
2875  l_int32 ws,
2876  l_int32 wpls,
2877  l_int32 lastlineflag)
2878 {
2879 l_int32 j, jd, wsm, wsm4;
2880 l_int32 s1, s2, s3, s4, s1t, s2t, s3t, s4t;
2881 l_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  *------------------------------------------------------------------*/
3005 static l_int32
3006 scaleBySamplingLow(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 {
3016 l_int32 i, j;
3017 l_int32 xs, prevxs, sval;
3018 l_int32 *srow, *scol;
3019 l_uint32 csval;
3020 l_uint32 *lines, *prevlines, *lined, *prevlined;
3021 l_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  *------------------------------------------------------------------*/
3136 static l_int32
3137 scaleSmoothLow(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 {
3148 l_int32 i, j, m, n, xstart;
3149 l_int32 val, rval, gval, bval;
3150 l_int32 *srow, *scol;
3151 l_uint32 *lines, *lined, *line, *ppixel;
3152 l_uint32 pixel;
3153 l_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 
3235 static void
3236 scaleRGBToGray2Low(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 {
3246 l_int32 i, j, val, rval, gval, bval;
3247 l_uint32 *lines, *lined;
3248 l_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  *------------------------------------------------------------------*/
3300 static void
3301 scaleColorAreaMapLow(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 {
3310 l_int32 i, j, k, m, wm2, hm2;
3311 l_int32 area00, area10, area01, area11, areal, arear, areat, areab;
3312 l_int32 xu, yu; /* UL corner in src image, to 1/16 of a pixel */
3313 l_int32 xl, yl; /* LR corner in src image, to 1/16 of a pixel */
3314 l_int32 xup, yup, xuf, yuf; /* UL src pixel: integer and fraction */
3315 l_int32 xlp, ylp, xlf, ylf; /* LR src pixel: integer and fraction */
3316 l_int32 delx, dely, area;
3317 l_int32 v00r, v00g, v00b; /* contrib. from UL src pixel */
3318 l_int32 v01r, v01g, v01b; /* contrib. from LL src pixel */
3319 l_int32 v10r, v10g, v10b; /* contrib from UR src pixel */
3320 l_int32 v11r, v11g, v11b; /* contrib from LR src pixel */
3321 l_int32 vinr, ving, vinb; /* contrib from all full interior src pixels */
3322 l_int32 vmidr, vmidg, vmidb; /* contrib from side parts */
3323 l_int32 rval, gval, bval;
3324 l_uint32 pixel00, pixel10, pixel01, pixel11, pixel;
3325 l_uint32 *lines, *lined;
3326 l_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 
3458 static void
3459 scaleGrayAreaMapLow(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 {
3468 l_int32 i, j, k, m, wm2, hm2;
3469 l_int32 xu, yu; /* UL corner in src image, to 1/16 of a pixel */
3470 l_int32 xl, yl; /* LR corner in src image, to 1/16 of a pixel */
3471 l_int32 xup, yup, xuf, yuf; /* UL src pixel: integer and fraction */
3472 l_int32 xlp, ylp, xlf, ylf; /* LR src pixel: integer and fraction */
3473 l_int32 delx, dely, area;
3474 l_int32 v00; /* contrib. from UL src pixel */
3475 l_int32 v01; /* contrib. from LL src pixel */
3476 l_int32 v10; /* contrib from UR src pixel */
3477 l_int32 v11; /* contrib from LR src pixel */
3478 l_int32 vin; /* contrib from all full interior src pixels */
3479 l_int32 vmid; /* contrib from side parts that are full in 1 direction */
3480 l_int32 val;
3481 l_uint32 *lines, *lined;
3482 l_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  *------------------------------------------------------------------*/
3565 static void
3566 scaleAreaMapLow2(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 {
3574 l_int32 i, j, val, rval, gval, bval;
3575 l_uint32 *lines, *lined;
3576 l_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  */
3637 static l_int32
3638 scaleBinaryLow(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 {
3647 l_int32 i, j;
3648 l_int32 xs, prevxs, sval;
3649 l_int32 *srow, *scol;
3650 l_uint32 *lines, *prevlines, *lined, *prevlined;
3651 l_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)
Definition: arrayaccess.h:164
#define GET_DATA_TWO_BYTES(pdata, n)
Definition: arrayaccess.h:212
#define SET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:127
#define SET_DATA_DIBIT(pdata, n, val)
Definition: arrayaccess.h:149
#define SET_DATA_TWO_BYTES(pdata, n, val)
Definition: arrayaccess.h:222
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:188
#define GET_DATA_DIBIT(pdata, n)
Definition: arrayaccess.h:145
#define SET_DATA_BYTE(pdata, n, val)
Definition: arrayaccess.h:198
#define GET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:123
#define SET_DATA_QBIT(pdata, n, val)
Definition: arrayaccess.h:168
PIX * pixUnsharpMasking(PIX *pixs, l_int32 halfwidth, l_float32 fract)
pixUnsharpMasking()
Definition: enhance.c:979
void ditherToBinaryLineLow(l_uint32 *lined, l_int32 w, l_uint32 *bufs1, l_uint32 *bufs2, l_int32 lowerclip, l_int32 upperclip, l_int32 lastlineflag)
ditherToBinaryLineLow()
Definition: grayquant.c:322
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1642
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:608
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1074
l_ok pixCopySpp(PIX *pixd, const PIX *pixs)
pixCopySpp()
Definition: pix1.c:1187
PIX * pixCopy(PIX *pixd, const PIX *pixs)
pixCopy()
Definition: pix1.c:689
l_ok pixCopyColormap(PIX *pixd, const PIX *pixs)
pixCopyColormap()
Definition: pix1.c:795
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:582
PIX * pixGetRGBComponent(PIX *pixs, l_int32 comp)
pixGetRGBComponent()
Definition: pix2.c:2464
l_ok pixSetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 val)
pixSetPixel()
Definition: pix2.c:263
l_ok pixGetPixel(PIX *pix, l_int32 x, l_int32 y, l_uint32 *pval)
pixGetPixel()
Definition: pix2.c:192
PIX * pixCreateRGBImage(PIX *pixr, PIX *pixg, PIX *pixb)
pixCreateRGBImage()
Definition: pix2.c:2410
l_ok composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2728
@ COLOR_BLUE
Definition: pix.h:330
@ COLOR_RED
Definition: pix.h:328
@ COLOR_GREEN
Definition: pix.h:329
@ DEFAULT_CLIP_LOWER_1
Definition: pix.h:728
@ DEFAULT_CLIP_UPPER_1
Definition: pix.h:729
@ REMOVE_CMAP_BASED_ON_SRC
Definition: pix.h:384
@ L_CLONE
Definition: pix.h:506
PIX * pixConvertTo8Or32(PIX *pixs, l_int32 copyflag, l_int32 warnflag)
pixConvertTo8Or32()
Definition: pixconv.c:3400
PIX * pixRemoveColormap(PIX *pixs, l_int32 type)
pixRemoveColormap()
Definition: pixconv.c:324
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3055
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
PIX * pixScaleToResolution(PIX *pixs, l_float32 target, l_float32 assumed, l_float32 *pscalefact)
pixScaleToResolution()
Definition: scale1.c:357
PIX * pixScaleRGBToGrayFast(PIX *pixs, l_int32 factor, l_int32 color)
pixScaleRGBToGrayFast()
Definition: scale1.c:1448
PIX * pixScale(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScale()
Definition: scale1.c:250
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 * pixScaleGray4xLIThresh(PIX *pixs, l_int32 thresh)
pixScaleGray4xLIThresh()
Definition: scale1.c:1097
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 * 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
PIX * pixScaleColor2xLI(PIX *pixs)
pixScaleColor2xLI()
Definition: scale1.c:625
PIX * pixScaleRGBToGray2(PIX *pixs, l_float32 rwt, l_float32 gwt, l_float32 bwt)
pixScaleRGBToGray2()
Definition: scale1.c:1785
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 * pixScaleAreaMap(PIX *pix, l_float32 scalex, l_float32 scaley)
pixScaleAreaMap()
Definition: scale1.c:1864
PIX * pixScaleRGBToBinaryFast(PIX *pixs, l_int32 factor, l_int32 thresh)
pixScaleRGBToBinaryFast()
Definition: scale1.c:1521
PIX * pixScaleToSizeRel(PIX *pixs, l_int32 delw, l_int32 delh)
pixScaleToSizeRel()
Definition: scale1.c:278
PIX * pixScaleToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleToSize()
Definition: scale1.c:319
PIX * pixScaleLI(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleLI()
Definition: scale1.c:506
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 * pixScaleGray2xLI(PIX *pixs)
pixScaleGray2xLI()
Definition: scale1.c:821
PIX * pixScaleBinary(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleBinary()
Definition: scale1.c:2105
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 * pixScaleGrayToBinaryFast(PIX *pixs, l_int32 factor, l_int32 thresh)
pixScaleGrayToBinaryFast()
Definition: scale1.c:1585
PIX * pixScaleSmooth(PIX *pix, l_float32 scalex, l_float32 scaley)
pixScaleSmooth()
Definition: scale1.c:1665
PIX * pixScaleGray2xLIThresh(PIX *pixs, l_int32 thresh)
pixScaleGray2xLIThresh()
Definition: scale1.c:903
PIX * pixScaleAreaMap2(PIX *pix)
pixScaleAreaMap2()
Definition: scale1.c:1995
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
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 * pixScaleBySamplingToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleBySamplingToSize()
Definition: scale1.c:1366
PIX * pixScaleAreaMapToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleAreaMapToSize()
Definition: scale1.c:2058
PIX * pixScaleGray4xLI(PIX *pixs)
pixScaleGray4xLI()
Definition: scale1.c:860
PIX * pixScaleByIntSampling(PIX *pixs, l_int32 factor)
pixScaleByIntSampling()
Definition: scale1.c:1408
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
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 * pixScaleColorLI(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleColorLI()
Definition: scale1.c:563
PIX * pixScaleSmoothToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleSmoothToSize()
Definition: scale1.c:1749
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 * pixScaleGray4xLIDither(PIX *pixs)
pixScaleGray4xLIDither()
Definition: scale1.c:1183
PIX * pixScaleBySampling(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleBySampling()
Definition: scale1.c:1306
PIX * pixScaleGray2xLIDither(PIX *pixs)
pixScaleGray2xLIDither()
Definition: scale1.c:980
l_ok pixScaleAndTransferAlpha(PIX *pixd, PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleAndTransferAlpha()
Definition: scale2.c:1334
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306