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