Leptonica  1.77.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 #include <string.h>
115 #include "allheaders.h"
116 
117 static void scaleColorLILow(l_uint32 *datad, l_int32 wd, l_int32 hd,
118  l_int32 wpld, l_uint32 *datas, l_int32 ws,
119  l_int32 hs, l_int32 wpls);
120 static void scaleGrayLILow(l_uint32 *datad, l_int32 wd, l_int32 hd,
121  l_int32 wpld, l_uint32 *datas, l_int32 ws,
122  l_int32 hs, l_int32 wpls);
123 static void scaleColor2xLILow(l_uint32 *datad, l_int32 wpld, l_uint32 *datas,
124  l_int32 ws, l_int32 hs, l_int32 wpls);
125 static void scaleColor2xLILineLow(l_uint32 *lined, l_int32 wpld,
126  l_uint32 *lines, l_int32 ws, l_int32 wpls,
127  l_int32 lastlineflag);
128 static void scaleGray2xLILow(l_uint32 *datad, l_int32 wpld, l_uint32 *datas,
129  l_int32 ws, l_int32 hs, l_int32 wpls);
130 static void scaleGray2xLILineLow(l_uint32 *lined, l_int32 wpld,
131  l_uint32 *lines, l_int32 ws, l_int32 wpls,
132  l_int32 lastlineflag);
133 static void scaleGray4xLILow(l_uint32 *datad, l_int32 wpld, l_uint32 *datas,
134  l_int32 ws, l_int32 hs, l_int32 wpls);
135 static void scaleGray4xLILineLow(l_uint32 *lined, l_int32 wpld,
136  l_uint32 *lines, l_int32 ws, l_int32 wpls,
137  l_int32 lastlineflag);
138 static l_int32 scaleBySamplingLow(l_uint32 *datad, l_int32 wd, l_int32 hd,
139  l_int32 wpld, l_uint32 *datas, l_int32 ws,
140  l_int32 hs, l_int32 d, l_int32 wpls);
141 static l_int32 scaleSmoothLow(l_uint32 *datad, l_int32 wd, l_int32 hd,
142  l_int32 wpld, l_uint32 *datas, l_int32 ws,
143  l_int32 hs, l_int32 d, l_int32 wpls,
144  l_int32 size);
145 static void scaleRGBToGray2Low(l_uint32 *datad, l_int32 wd, l_int32 hd,
146  l_int32 wpld, l_uint32 *datas, l_int32 wpls,
147  l_float32 rwt, l_float32 gwt, l_float32 bwt);
148 static void scaleColorAreaMapLow(l_uint32 *datad, l_int32 wd, l_int32 hd,
149  l_int32 wpld, l_uint32 *datas, l_int32 ws,
150  l_int32 hs, l_int32 wpls);
151 static void scaleGrayAreaMapLow(l_uint32 *datad, l_int32 wd, l_int32 hd,
152  l_int32 wpld, l_uint32 *datas, l_int32 ws,
153  l_int32 hs, l_int32 wpls);
154 static void scaleAreaMapLow2(l_uint32 *datad, l_int32 wd, l_int32 hd,
155  l_int32 wpld, l_uint32 *datas, l_int32 d,
156  l_int32 wpls);
157 static l_int32 scaleBinaryLow(l_uint32 *datad, l_int32 wd, l_int32 hd,
158  l_int32 wpld, l_uint32 *datas, l_int32 ws,
159  l_int32 hs, l_int32 wpls);
160 
161 #ifndef NO_CONSOLE_IO
162 #define DEBUG_OVERFLOW 0
163 #define DEBUG_UNROLLING 0
164 #endif /* ~NO_CONSOLE_IO */
165 
166 
167 /*------------------------------------------------------------------*
168  * Top level scaling dispatcher *
169  *------------------------------------------------------------------*/
243 PIX *
244 pixScale(PIX *pixs,
245  l_float32 scalex,
246  l_float32 scaley)
247 {
248 l_int32 sharpwidth;
249 l_float32 maxscale, sharpfract;
250 
251  PROCNAME("pixScale");
252 
253  if (!pixs)
254  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
255 
256  /* Reduce the default sharpening factors by 2 if maxscale < 0.7 */
257  maxscale = L_MAX(scalex, scaley);
258  sharpfract = (maxscale < 0.7) ? 0.2 : 0.4;
259  sharpwidth = (maxscale < 0.7) ? 1 : 2;
260 
261  return pixScaleGeneral(pixs, scalex, scaley, sharpfract, sharpwidth);
262 }
263 
264 
273 PIX *
275  l_int32 delw,
276  l_int32 delh)
277 {
278 l_int32 w, h, wd, hd;
279 
280  PROCNAME("pixScaleToSizeRel");
281 
282  if (!pixs)
283  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
284 
285  if (delw == 0 && delh == 0)
286  return pixCopy(NULL, pixs);
287 
288  pixGetDimensions(pixs, &w, &h, NULL);
289  wd = w + delw;
290  hd = h + delh;
291  if (wd <= 0 || hd <= 0)
292  return (PIX *)ERROR_PTR("pix dimension reduced to 0", procName, NULL);
293 
294  return pixScaleToSize(pixs, wd, hd);
295 }
296 
297 
316 PIX *
318  l_int32 wd,
319  l_int32 hd)
320 {
321 l_int32 w, h;
322 l_float32 scalex, scaley;
323 
324  PROCNAME("pixScaleToSize");
325 
326  if (!pixs)
327  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
328  if (wd <= 0 && hd <= 0)
329  return (PIX *)ERROR_PTR("neither wd nor hd > 0", procName, NULL);
330 
331  pixGetDimensions(pixs, &w, &h, NULL);
332  if (wd <= 0) {
333  scaley = (l_float32)hd / (l_float32)h;
334  scalex = scaley;
335  } else if (hd <= 0) {
336  scalex = (l_float32)wd / (l_float32)w;
337  scaley = scalex;
338  } else {
339  scalex = (l_float32)wd / (l_float32)w;
340  scaley = (l_float32)hd / (l_float32)h;
341  }
342 
343  return pixScale(pixs, scalex, scaley);
344 }
345 
346 
356 PIX *
358  l_float32 target,
359  l_float32 assumed,
360  l_float32 *pscalefact)
361 {
362 l_int32 xres;
363 l_float32 factor;
364 
365  PROCNAME("pixScaleToResolution");
366 
367  if (pscalefact) *pscalefact = 1.0;
368  if (!pixs)
369  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
370  if (target <= 0)
371  return (PIX *)ERROR_PTR("target resolution <= 0", procName, NULL);
372 
373  xres = pixGetXRes(pixs);
374  if (xres <= 0) {
375  if (assumed == 0)
376  return pixCopy(NULL, pixs);
377  xres = assumed;
378  }
379  factor = target / (l_float32)xres;
380  if (pscalefact) *pscalefact = factor;
381 
382  return pixScale(pixs, factor, factor);
383 }
384 
385 
413 PIX *
415  l_float32 scalex,
416  l_float32 scaley,
417  l_float32 sharpfract,
418  l_int32 sharpwidth)
419 {
420 l_int32 d;
421 l_float32 maxscale;
422 PIX *pixt, *pixt2, *pixd;
423 
424  PROCNAME("pixScaleGeneral");
425 
426  if (!pixs)
427  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
428  d = pixGetDepth(pixs);
429  if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
430  return (PIX *)ERROR_PTR("pixs not {1,2,4,8,16,32} bpp", procName, NULL);
431  if (scalex <= 0.0 || scaley <= 0.0)
432  return (PIX *)ERROR_PTR("scale factor <= 0", procName, NULL);
433  if (scalex == 1.0 && scaley == 1.0)
434  return pixCopy(NULL, pixs);
435 
436  if (d == 1)
437  return pixScaleBinary(pixs, scalex, scaley);
438 
439  /* Remove colormap; clone if possible; result is either 8 or 32 bpp */
440  if ((pixt = pixConvertTo8Or32(pixs, L_CLONE, 0)) == NULL)
441  return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
442 
443  /* Scale (up or down) */
444  d = pixGetDepth(pixt);
445  maxscale = L_MAX(scalex, scaley);
446  if (maxscale < 0.7) { /* area mapping for anti-aliasing */
447  pixt2 = pixScaleAreaMap(pixt, scalex, scaley);
448  if (maxscale > 0.2 && sharpfract > 0.0 && sharpwidth > 0)
449  pixd = pixUnsharpMasking(pixt2, sharpwidth, sharpfract);
450  else
451  pixd = pixClone(pixt2);
452  } else { /* use linear interpolation */
453  if (d == 8)
454  pixt2 = pixScaleGrayLI(pixt, scalex, scaley);
455  else /* d == 32 */
456  pixt2 = pixScaleColorLI(pixt, scalex, scaley);
457  if (maxscale < 1.4 && sharpfract > 0.0 && sharpwidth > 0)
458  pixd = pixUnsharpMasking(pixt2, sharpwidth, sharpfract);
459  else
460  pixd = pixClone(pixt2);
461  }
462 
463  pixDestroy(&pixt);
464  pixDestroy(&pixt2);
465  pixCopyText(pixd, pixs);
466  pixCopyInputFormat(pixd, pixs);
467  return pixd;
468 }
469 
470 
471 /*------------------------------------------------------------------*
472  * Scaling by linear interpolation *
473  *------------------------------------------------------------------*/
497 PIX *
499  l_float32 scalex,
500  l_float32 scaley)
501 {
502 l_int32 d;
503 l_float32 maxscale;
504 PIX *pixt, *pixd;
505 
506  PROCNAME("pixScaleLI");
507 
508  if (!pixs || (pixGetDepth(pixs) == 1))
509  return (PIX *)ERROR_PTR("pixs not defined or 1 bpp", procName, NULL);
510  maxscale = L_MAX(scalex, scaley);
511  if (maxscale < 0.7) {
512  L_WARNING("scaling factors < 0.7; do regular scaling\n", procName);
513  return pixScaleGeneral(pixs, scalex, scaley, 0.0, 0);
514  }
515  d = pixGetDepth(pixs);
516  if (d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
517  return (PIX *)ERROR_PTR("pixs not {2,4,8,16,32} bpp", procName, NULL);
518 
519  /* Remove colormap; clone if possible; result is either 8 or 32 bpp */
520  if ((pixt = pixConvertTo8Or32(pixs, L_CLONE, 0)) == NULL)
521  return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
522 
523  d = pixGetDepth(pixt);
524  if (d == 8)
525  pixd = pixScaleGrayLI(pixt, scalex, scaley);
526  else /* d == 32 */
527  pixd = pixScaleColorLI(pixt, scalex, scaley);
528 
529  pixDestroy(&pixt);
530  pixCopyInputFormat(pixd, pixs);
531  return pixd;
532 }
533 
534 
558 PIX *
560  l_float32 scalex,
561  l_float32 scaley)
562 {
563 l_int32 ws, hs, wpls, wd, hd, wpld;
564 l_uint32 *datas, *datad;
565 l_float32 maxscale;
566 PIX *pixd;
567 
568  PROCNAME("pixScaleColorLI");
569 
570  if (!pixs || (pixGetDepth(pixs) != 32))
571  return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
572  maxscale = L_MAX(scalex, scaley);
573  if (maxscale < 0.7) {
574  L_WARNING("scaling factors < 0.7; do regular scaling\n", procName);
575  return pixScaleGeneral(pixs, scalex, scaley, 0.0, 0);
576  }
577 
578  /* Do fast special cases if possible */
579  if (scalex == 1.0 && scaley == 1.0)
580  return pixCopy(NULL, pixs);
581  if (scalex == 2.0 && scaley == 2.0)
582  return pixScaleColor2xLI(pixs);
583  if (scalex == 4.0 && scaley == 4.0)
584  return pixScaleColor4xLI(pixs);
585 
586  /* General case */
587  pixGetDimensions(pixs, &ws, &hs, NULL);
588  datas = pixGetData(pixs);
589  wpls = pixGetWpl(pixs);
590  wd = (l_int32)(scalex * (l_float32)ws + 0.5);
591  hd = (l_int32)(scaley * (l_float32)hs + 0.5);
592  if ((pixd = pixCreate(wd, hd, 32)) == NULL)
593  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
594  pixCopyResolution(pixd, pixs);
595  pixScaleResolution(pixd, scalex, scaley);
596  datad = pixGetData(pixd);
597  wpld = pixGetWpl(pixd);
598  scaleColorLILow(datad, wd, hd, wpld, datas, ws, hs, wpls);
599  if (pixGetSpp(pixs) == 4)
600  pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley);
601 
602  pixCopyInputFormat(pixd, pixs);
603  return pixd;
604 }
605 
606 
624 PIX *
626 {
627 l_int32 ws, hs, wpls, wpld;
628 l_uint32 *datas, *datad;
629 PIX *pixd;
630 
631  PROCNAME("pixScaleColor2xLI");
632 
633  if (!pixs || (pixGetDepth(pixs) != 32))
634  return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
635 
636  pixGetDimensions(pixs, &ws, &hs, NULL);
637  datas = pixGetData(pixs);
638  wpls = pixGetWpl(pixs);
639  if ((pixd = pixCreate(2 * ws, 2 * hs, 32)) == NULL)
640  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
641  pixCopyResolution(pixd, pixs);
642  pixScaleResolution(pixd, 2.0, 2.0);
643  datad = pixGetData(pixd);
644  wpld = pixGetWpl(pixd);
645  scaleColor2xLILow(datad, wpld, datas, ws, hs, wpls);
646  if (pixGetSpp(pixs) == 4)
647  pixScaleAndTransferAlpha(pixd, pixs, 2.0, 2.0);
648 
649  pixCopyInputFormat(pixd, pixs);
650  return pixd;
651 }
652 
653 
673 PIX *
675 {
676 PIX *pixr, *pixg, *pixb;
677 PIX *pixrs, *pixgs, *pixbs;
678 PIX *pixd;
679 
680  PROCNAME("pixScaleColor4xLI");
681 
682  if (!pixs || (pixGetDepth(pixs) != 32))
683  return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
684 
685  pixr = pixGetRGBComponent(pixs, COLOR_RED);
686  pixrs = pixScaleGray4xLI(pixr);
687  pixDestroy(&pixr);
688  pixg = pixGetRGBComponent(pixs, COLOR_GREEN);
689  pixgs = pixScaleGray4xLI(pixg);
690  pixDestroy(&pixg);
691  pixb = pixGetRGBComponent(pixs, COLOR_BLUE);
692  pixbs = pixScaleGray4xLI(pixb);
693  pixDestroy(&pixb);
694 
695  if ((pixd = pixCreateRGBImage(pixrs, pixgs, pixbs)) == NULL) {
696  L_ERROR("pixd not made\n", procName);
697  } else {
698  if (pixGetSpp(pixs) == 4)
699  pixScaleAndTransferAlpha(pixd, pixs, 4.0, 4.0);
700  pixCopyInputFormat(pixd, pixs);
701  }
702 
703  pixDestroy(&pixrs);
704  pixDestroy(&pixgs);
705  pixDestroy(&pixbs);
706  return pixd;
707 }
708 
709 
777 PIX *
779  l_float32 scalex,
780  l_float32 scaley)
781 {
782 l_int32 ws, hs, wpls, wd, hd, wpld;
783 l_uint32 *datas, *datad;
784 l_float32 maxscale;
785 PIX *pixd;
786 
787  PROCNAME("pixScaleGrayLI");
788 
789  if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
790  return (PIX *)ERROR_PTR("pixs undefined, cmapped or not 8 bpp",
791  procName, NULL);
792  maxscale = L_MAX(scalex, scaley);
793  if (maxscale < 0.7) {
794  L_WARNING("scaling factors < 0.7; do regular scaling\n", procName);
795  return pixScaleGeneral(pixs, scalex, scaley, 0.0, 0);
796  }
797 
798  /* Do fast special cases if possible */
799  if (scalex == 1.0 && scaley == 1.0)
800  return pixCopy(NULL, pixs);
801  if (scalex == 2.0 && scaley == 2.0)
802  return pixScaleGray2xLI(pixs);
803  if (scalex == 4.0 && scaley == 4.0)
804  return pixScaleGray4xLI(pixs);
805 
806  /* General case */
807  pixGetDimensions(pixs, &ws, &hs, NULL);
808  datas = pixGetData(pixs);
809  wpls = pixGetWpl(pixs);
810  wd = (l_int32)(scalex * (l_float32)ws + 0.5);
811  hd = (l_int32)(scaley * (l_float32)hs + 0.5);
812  if ((pixd = pixCreate(wd, hd, 8)) == NULL)
813  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
814  pixCopyText(pixd, pixs);
815  pixCopyResolution(pixd, pixs);
816  pixCopyInputFormat(pixd, pixs);
817  pixScaleResolution(pixd, scalex, scaley);
818  datad = pixGetData(pixd);
819  wpld = pixGetWpl(pixd);
820  scaleGrayLILow(datad, wd, hd, wpld, datas, ws, hs, wpls);
821  return pixd;
822 }
823 
824 
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 
883 PIX *
885 {
886 l_int32 ws, hs, wpls, wpld;
887 l_uint32 *datas, *datad;
888 PIX *pixd;
889 
890  PROCNAME("pixScaleGray4xLI");
891 
892  if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
893  return (PIX *)ERROR_PTR("pixs undefined, cmapped or not 8 bpp",
894  procName, NULL);
895 
896  pixGetDimensions(pixs, &ws, &hs, NULL);
897  datas = pixGetData(pixs);
898  wpls = pixGetWpl(pixs);
899  if ((pixd = pixCreate(4 * ws, 4 * hs, 8)) == NULL)
900  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
901  pixCopyResolution(pixd, pixs);
902  pixCopyInputFormat(pixd, pixs);
903  pixScaleResolution(pixd, 4.0, 4.0);
904  datad = pixGetData(pixd);
905  wpld = pixGetWpl(pixd);
906  scaleGray4xLILow(datad, wpld, datas, ws, hs, wpls);
907  return pixd;
908 }
909 
910 
911 /*------------------------------------------------------------------*
912  * Scale 2x followed by binarization *
913  *------------------------------------------------------------------*/
928 PIX *
930  l_int32 thresh)
931 {
932 l_int32 i, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
933 l_uint32 *datas, *datad, *lines, *lined, *lineb;
934 PIX *pixd;
935 
936  PROCNAME("pixScaleGray2xLIThresh");
937 
938  if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
939  return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
940  procName, NULL);
941  if (thresh < 0 || thresh > 256)
942  return (PIX *)ERROR_PTR("thresh must be in [0, ... 256]",
943  procName, NULL);
944 
945  pixGetDimensions(pixs, &ws, &hs, NULL);
946  wd = 2 * ws;
947  hd = 2 * hs;
948  hsm = hs - 1;
949  datas = pixGetData(pixs);
950  wpls = pixGetWpl(pixs);
951 
952  /* Make line buffer for 2 lines of virtual intermediate image */
953  wplb = (wd + 3) / 4;
954  if ((lineb = (l_uint32 *)LEPT_CALLOC(2 * wplb, sizeof(l_uint32))) == NULL)
955  return (PIX *)ERROR_PTR("lineb not made", procName, NULL);
956 
957  /* Make dest binary image */
958  if ((pixd = pixCreate(wd, hd, 1)) == NULL) {
959  LEPT_FREE(lineb);
960  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
961  }
962  pixCopyInputFormat(pixd, pixs);
963  pixCopyResolution(pixd, pixs);
964  pixScaleResolution(pixd, 2.0, 2.0);
965  wpld = pixGetWpl(pixd);
966  datad = pixGetData(pixd);
967 
968  /* Do all but last src line */
969  for (i = 0; i < hsm; i++) {
970  lines = datas + i * wpls;
971  lined = datad + 2 * i * wpld; /* do 2 dest lines at a time */
972  scaleGray2xLILineLow(lineb, wplb, lines, ws, wpls, 0);
973  thresholdToBinaryLineLow(lined, wd, lineb, 8, thresh);
974  thresholdToBinaryLineLow(lined + wpld, wd, lineb + wplb, 8, thresh);
975  }
976 
977  /* Do last src line */
978  lines = datas + hsm * wpls;
979  lined = datad + 2 * hsm * wpld;
980  scaleGray2xLILineLow(lineb, wplb, lines, ws, wpls, 1);
981  thresholdToBinaryLineLow(lined, wd, lineb, 8, thresh);
982  thresholdToBinaryLineLow(lined + wpld, wd, lineb + wplb, 8, thresh);
983 
984  LEPT_FREE(lineb);
985  return pixd;
986 }
987 
988 
1007 PIX *
1009 {
1010 l_int32 i, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
1011 l_uint32 *datas, *datad;
1012 l_uint32 *lined;
1013 l_uint32 *lineb = NULL; /* 2 intermediate buffer lines */
1014 l_uint32 *linebp = NULL; /* 1 intermediate buffer line */
1015 l_uint32 *bufs = NULL; /* 2 source buffer lines */
1016 PIX *pixd = NULL;
1017 
1018  PROCNAME("pixScaleGray2xLIDither");
1019 
1020  if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
1021  return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
1022  procName, NULL);
1023 
1024  pixGetDimensions(pixs, &ws, &hs, NULL);
1025  wd = 2 * ws;
1026  hd = 2 * hs;
1027  hsm = hs - 1;
1028  datas = pixGetData(pixs);
1029  wpls = pixGetWpl(pixs);
1030 
1031  /* Make line buffers for 2 lines of src image */
1032  if ((bufs = (l_uint32 *)LEPT_CALLOC(2 * wpls, sizeof(l_uint32))) == NULL)
1033  return (PIX *)ERROR_PTR("bufs not made", procName, NULL);
1034 
1035  /* Make line buffer for 2 lines of virtual intermediate image */
1036  wplb = (wd + 3) / 4;
1037  if ((lineb = (l_uint32 *)LEPT_CALLOC(2 * wplb, sizeof(l_uint32))) == NULL) {
1038  L_ERROR("lineb not made\n", procName);
1039  goto cleanup;
1040  }
1041 
1042  /* Make line buffer for 1 line of virtual intermediate image */
1043  if ((linebp = (l_uint32 *)LEPT_CALLOC(wplb, sizeof(l_uint32))) == NULL) {
1044  L_ERROR("linebp not made\n", procName);
1045  goto cleanup;
1046  }
1047 
1048  /* Make dest binary image */
1049  if ((pixd = pixCreate(wd, hd, 1)) == NULL) {
1050  L_ERROR("pixd not made\n", procName);
1051  goto cleanup;
1052  }
1053  pixCopyInputFormat(pixd, pixs);
1054  pixCopyResolution(pixd, pixs);
1055  pixScaleResolution(pixd, 2.0, 2.0);
1056  wpld = pixGetWpl(pixd);
1057  datad = pixGetData(pixd);
1058 
1059  /* Start with the first src and the first dest line */
1060  memcpy(bufs, datas, 4 * wpls); /* first src line */
1061  memcpy(bufs + wpls, datas + wpls, 4 * wpls); /* 2nd src line */
1062  scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 2 i lines */
1063  lined = datad;
1064  ditherToBinaryLineLow(lined, wd, lineb, lineb + wplb,
1066  /* 1st d line */
1067 
1068  /* Do all but last src line */
1069  for (i = 1; i < hsm; i++) {
1070  memcpy(bufs, datas + i * wpls, 4 * wpls); /* i-th src line */
1071  memcpy(bufs + wpls, datas + (i + 1) * wpls, 4 * wpls);
1072  memcpy(linebp, lineb + wplb, 4 * wplb);
1073  scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 2 i lines */
1074  lined = datad + 2 * i * wpld;
1075  ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb,
1077  /* odd dest line */
1078  ditherToBinaryLineLow(lined, wd, lineb, lineb + wplb,
1080  /* even dest line */
1081  }
1082 
1083  /* Do the last src line and the last 3 dest lines */
1084  memcpy(bufs, datas + hsm * wpls, 4 * wpls); /* hsm-th src line */
1085  memcpy(linebp, lineb + wplb, 4 * wplb); /* 1 i line */
1086  scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 1); /* 2 i lines */
1087  ditherToBinaryLineLow(lined + wpld, wd, linebp, lineb,
1089  /* odd dest line */
1090  ditherToBinaryLineLow(lined + 2 * wpld, wd, lineb, lineb + wplb,
1092  /* even dest line */
1093  ditherToBinaryLineLow(lined + 3 * wpld, wd, lineb + wplb, NULL,
1095  /* last dest line */
1096 
1097 cleanup:
1098  LEPT_FREE(bufs);
1099  LEPT_FREE(lineb);
1100  LEPT_FREE(linebp);
1101  return pixd;
1102 }
1103 
1104 
1105 /*------------------------------------------------------------------*
1106  * Scale 4x followed by binarization *
1107  *------------------------------------------------------------------*/
1126 PIX *
1128  l_int32 thresh)
1129 {
1130 l_int32 i, j, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
1131 l_uint32 *datas, *datad, *lines, *lined, *lineb;
1132 PIX *pixd;
1133 
1134  PROCNAME("pixScaleGray4xLIThresh");
1135 
1136  if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
1137  return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
1138  procName, NULL);
1139  if (thresh < 0 || thresh > 256)
1140  return (PIX *)ERROR_PTR("thresh must be in [0, ... 256]",
1141  procName, NULL);
1142 
1143  pixGetDimensions(pixs, &ws, &hs, NULL);
1144  wd = 4 * ws;
1145  hd = 4 * hs;
1146  hsm = hs - 1;
1147  datas = pixGetData(pixs);
1148  wpls = pixGetWpl(pixs);
1149 
1150  /* Make line buffer for 4 lines of virtual intermediate image */
1151  wplb = (wd + 3) / 4;
1152  if ((lineb = (l_uint32 *)LEPT_CALLOC(4 * wplb, sizeof(l_uint32))) == NULL)
1153  return (PIX *)ERROR_PTR("lineb not made", procName, NULL);
1154 
1155  /* Make dest binary image */
1156  if ((pixd = pixCreate(wd, hd, 1)) == NULL) {
1157  LEPT_FREE(lineb);
1158  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1159  }
1160  pixCopyInputFormat(pixd, pixs);
1161  pixCopyResolution(pixd, pixs);
1162  pixScaleResolution(pixd, 4.0, 4.0);
1163  wpld = pixGetWpl(pixd);
1164  datad = pixGetData(pixd);
1165 
1166  /* Do all but last src line */
1167  for (i = 0; i < hsm; i++) {
1168  lines = datas + i * wpls;
1169  lined = datad + 4 * i * wpld; /* do 4 dest lines at a time */
1170  scaleGray4xLILineLow(lineb, wplb, lines, ws, wpls, 0);
1171  for (j = 0; j < 4; j++) {
1172  thresholdToBinaryLineLow(lined + j * wpld, wd,
1173  lineb + j * wplb, 8, thresh);
1174  }
1175  }
1176 
1177  /* Do last src line */
1178  lines = datas + hsm * wpls;
1179  lined = datad + 4 * hsm * wpld;
1180  scaleGray4xLILineLow(lineb, wplb, lines, ws, wpls, 1);
1181  for (j = 0; j < 4; j++) {
1182  thresholdToBinaryLineLow(lined + j * wpld, wd,
1183  lineb + j * wplb, 8, thresh);
1184  }
1185 
1186  LEPT_FREE(lineb);
1187  return pixd;
1188 }
1189 
1190 
1214 PIX *
1216 {
1217 l_int32 i, j, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
1218 l_uint32 *datas, *datad;
1219 l_uint32 *lined;
1220 l_uint32 *lineb = NULL; /* 4 intermediate buffer lines */
1221 l_uint32 *linebp = NULL; /* 1 intermediate buffer line */
1222 l_uint32 *bufs = NULL; /* 2 source buffer lines */
1223 PIX *pixd = NULL;
1224 
1225  PROCNAME("pixScaleGray4xLIDither");
1226 
1227  if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
1228  return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
1229  procName, NULL);
1230 
1231  pixGetDimensions(pixs, &ws, &hs, NULL);
1232  wd = 4 * ws;
1233  hd = 4 * hs;
1234  hsm = hs - 1;
1235  datas = pixGetData(pixs);
1236  wpls = pixGetWpl(pixs);
1237 
1238  /* Make line buffers for 2 lines of src image */
1239  if ((bufs = (l_uint32 *)LEPT_CALLOC(2 * wpls, sizeof(l_uint32))) == NULL)
1240  return (PIX *)ERROR_PTR("bufs not made", procName, NULL);
1241 
1242  /* Make line buffer for 4 lines of virtual intermediate image */
1243  wplb = (wd + 3) / 4;
1244  if ((lineb = (l_uint32 *)LEPT_CALLOC(4 * wplb, sizeof(l_uint32))) == NULL) {
1245  L_ERROR("lineb not made\n", procName);
1246  goto cleanup;
1247  }
1248 
1249  /* Make line buffer for 1 line of virtual intermediate image */
1250  if ((linebp = (l_uint32 *)LEPT_CALLOC(wplb, sizeof(l_uint32))) == NULL) {
1251  L_ERROR("linebp not made\n", procName);
1252  goto cleanup;
1253  }
1254 
1255  /* Make dest binary image */
1256  if ((pixd = pixCreate(wd, hd, 1)) == NULL) {
1257  L_ERROR("pixd not made\n", procName);
1258  goto cleanup;
1259  }
1260  pixCopyInputFormat(pixd, pixs);
1261  pixCopyResolution(pixd, pixs);
1262  pixScaleResolution(pixd, 4.0, 4.0);
1263  wpld = pixGetWpl(pixd);
1264  datad = pixGetData(pixd);
1265 
1266  /* Start with the first src and the first 3 dest lines */
1267  memcpy(bufs, datas, 4 * wpls); /* first src line */
1268  memcpy(bufs + wpls, datas + wpls, 4 * wpls); /* 2nd src line */
1269  scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 4 b lines */
1270  lined = datad;
1271  for (j = 0; j < 3; j++) { /* first 3 d lines of Q */
1272  ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb,
1273  lineb + (j + 1) * wplb,
1275  }
1276 
1277  /* Do all but last src line */
1278  for (i = 1; i < hsm; i++) {
1279  memcpy(bufs, datas + i * wpls, 4 * wpls); /* i-th src line */
1280  memcpy(bufs + wpls, datas + (i + 1) * wpls, 4 * wpls);
1281  memcpy(linebp, lineb + 3 * wplb, 4 * wplb);
1282  scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 4 b lines */
1283  lined = datad + 4 * i * wpld;
1284  ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb,
1286  /* 4th dest line of Q */
1287  for (j = 0; j < 3; j++) { /* next 3 d lines of Quad */
1288  ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb,
1289  lineb + (j + 1) * wplb,
1291  }
1292  }
1293 
1294  /* Do the last src line and the last 5 dest lines */
1295  memcpy(bufs, datas + hsm * wpls, 4 * wpls); /* hsm-th src line */
1296  memcpy(linebp, lineb + 3 * wplb, 4 * wplb); /* 1 b line */
1297  scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 1); /* 4 b lines */
1298  lined = datad + 4 * hsm * wpld;
1299  ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb,
1301  /* 4th dest line of Q */
1302  for (j = 0; j < 3; j++) { /* next 3 d lines of Quad */
1303  ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb,
1304  lineb + (j + 1) * wplb,
1306  }
1307  /* And finally, the last dest line */
1308  ditherToBinaryLineLow(lined + 3 * wpld, wd, lineb + 3 * wplb, NULL,
1310 
1311 cleanup:
1312  LEPT_FREE(bufs);
1313  LEPT_FREE(lineb);
1314  LEPT_FREE(linebp);
1315  return pixd;
1316 }
1317 
1318 
1319 /*------------------------------------------------------------------*
1320  * Scaling by closest pixel sampling *
1321  *------------------------------------------------------------------*/
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 
1444 PIX *
1446  l_int32 factor)
1447 {
1448 l_float32 scale;
1449 
1450  PROCNAME("pixScaleByIntSampling");
1451 
1452  if (!pixs)
1453  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1454  if (factor <= 1) {
1455  if (factor < 1)
1456  L_ERROR("factor must be >= 1; returning a copy\n", procName);
1457  return pixCopy(NULL, pixs);
1458  }
1459 
1460  scale = 1. / (l_float32)factor;
1461  return pixScaleBySampling(pixs, scale, scale);
1462 }
1463 
1464 
1465 /*------------------------------------------------------------------*
1466  * Fast integer factor subsampling RGB to gray *
1467  *------------------------------------------------------------------*/
1486 PIX *
1488  l_int32 factor,
1489  l_int32 color)
1490 {
1491 l_int32 byteval, shift;
1492 l_int32 i, j, ws, hs, wd, hd, wpls, wpld;
1493 l_uint32 *datas, *words, *datad, *lined;
1494 l_float32 scale;
1495 PIX *pixd;
1496 
1497  PROCNAME("pixScaleRGBToGrayFast");
1498 
1499  if (!pixs)
1500  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1501  if (pixGetDepth(pixs) != 32)
1502  return (PIX *)ERROR_PTR("depth not 32 bpp", procName, NULL);
1503  if (factor < 1)
1504  return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
1505 
1506  if (color == COLOR_RED)
1507  shift = L_RED_SHIFT;
1508  else if (color == COLOR_GREEN)
1509  shift = L_GREEN_SHIFT;
1510  else if (color == COLOR_BLUE)
1511  shift = L_BLUE_SHIFT;
1512  else
1513  return (PIX *)ERROR_PTR("invalid color", procName, NULL);
1514 
1515  pixGetDimensions(pixs, &ws, &hs, NULL);
1516  datas = pixGetData(pixs);
1517  wpls = pixGetWpl(pixs);
1518 
1519  wd = ws / factor;
1520  hd = hs / factor;
1521  if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1522  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1523  pixCopyResolution(pixd, pixs);
1524  pixCopyInputFormat(pixd, pixs);
1525  scale = 1. / (l_float32) factor;
1526  pixScaleResolution(pixd, scale, scale);
1527  datad = pixGetData(pixd);
1528  wpld = pixGetWpl(pixd);
1529 
1530  for (i = 0; i < hd; i++) {
1531  words = datas + i * factor * wpls;
1532  lined = datad + i * wpld;
1533  for (j = 0; j < wd; j++, words += factor) {
1534  byteval = ((*words) >> shift) & 0xff;
1535  SET_DATA_BYTE(lined, j, byteval);
1536  }
1537  }
1538 
1539  return pixd;
1540 }
1541 
1542 
1561 PIX *
1563  l_int32 factor,
1564  l_int32 thresh)
1565 {
1566 l_int32 byteval;
1567 l_int32 i, j, ws, hs, wd, hd, wpls, wpld;
1568 l_uint32 *datas, *words, *datad, *lined;
1569 l_float32 scale;
1570 PIX *pixd;
1571 
1572  PROCNAME("pixScaleRGBToBinaryFast");
1573 
1574  if (!pixs)
1575  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1576  if (factor < 1)
1577  return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
1578  if (pixGetDepth(pixs) != 32)
1579  return (PIX *)ERROR_PTR("depth not 32 bpp", procName, NULL);
1580 
1581  pixGetDimensions(pixs, &ws, &hs, NULL);
1582  datas = pixGetData(pixs);
1583  wpls = pixGetWpl(pixs);
1584 
1585  wd = ws / factor;
1586  hd = hs / factor;
1587  if ((pixd = pixCreate(wd, hd, 1)) == NULL)
1588  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1589  pixCopyResolution(pixd, pixs);
1590  pixCopyInputFormat(pixd, pixs);
1591  scale = 1. / (l_float32) factor;
1592  pixScaleResolution(pixd, scale, scale);
1593  datad = pixGetData(pixd);
1594  wpld = pixGetWpl(pixd);
1595 
1596  for (i = 0; i < hd; i++) {
1597  words = datas + i * factor * wpls;
1598  lined = datad + i * wpld;
1599  for (j = 0; j < wd; j++, words += factor) {
1600  byteval = ((*words) >> L_GREEN_SHIFT) & 0xff;
1601  if (byteval < thresh)
1602  SET_DATA_BIT(lined, j);
1603  }
1604  }
1605 
1606  return pixd;
1607 }
1608 
1609 
1627 PIX *
1629  l_int32 factor,
1630  l_int32 thresh)
1631 {
1632 l_int32 byteval;
1633 l_int32 i, j, ws, hs, wd, hd, wpls, wpld, sj;
1634 l_uint32 *datas, *datad, *lines, *lined;
1635 l_float32 scale;
1636 PIX *pixd;
1637 
1638  PROCNAME("pixScaleGrayToBinaryFast");
1639 
1640  if (!pixs)
1641  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1642  if (factor < 1)
1643  return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
1644  if (pixGetDepth(pixs) != 8)
1645  return (PIX *)ERROR_PTR("depth not 8 bpp", procName, NULL);
1646 
1647  pixGetDimensions(pixs, &ws, &hs, NULL);
1648  datas = pixGetData(pixs);
1649  wpls = pixGetWpl(pixs);
1650 
1651  wd = ws / factor;
1652  hd = hs / factor;
1653  if ((pixd = pixCreate(wd, hd, 1)) == NULL)
1654  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1655  pixCopyResolution(pixd, pixs);
1656  pixCopyInputFormat(pixd, pixs);
1657  scale = 1. / (l_float32) factor;
1658  pixScaleResolution(pixd, scale, scale);
1659  datad = pixGetData(pixd);
1660  wpld = pixGetWpl(pixd);
1661 
1662  for (i = 0; i < hd; i++) {
1663  lines = datas + i * factor * wpls;
1664  lined = datad + i * wpld;
1665  for (j = 0, sj = 0; j < wd; j++, sj += factor) {
1666  byteval = GET_DATA_BYTE(lines, sj);
1667  if (byteval < thresh)
1668  SET_DATA_BIT(lined, j);
1669  }
1670  }
1671 
1672  return pixd;
1673 }
1674 
1675 
1676 /*------------------------------------------------------------------*
1677  * Downscaling with (antialias) smoothing *
1678  *------------------------------------------------------------------*/
1710 PIX *
1712  l_float32 scalex,
1713  l_float32 scaley)
1714 {
1715 l_int32 ws, hs, d, wd, hd, wpls, wpld, isize;
1716 l_uint32 *datas, *datad;
1717 l_float32 minscale, size;
1718 PIX *pixs, *pixd;
1719 
1720  PROCNAME("pixScaleSmooth");
1721 
1722  if (!pix)
1723  return (PIX *)ERROR_PTR("pix not defined", procName, NULL);
1724  if (scalex >= 0.7 || scaley >= 0.7) {
1725  L_WARNING("scaling factor not < 0.7; do regular scaling\n", procName);
1726  return pixScaleGeneral(pix, scalex, scaley, 0.0, 0);
1727  }
1728 
1729  /* Remove colormap if necessary.
1730  * If 2 bpp or 4 bpp gray, convert to 8 bpp */
1731  d = pixGetDepth(pix);
1732  if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
1733  L_WARNING("pix has colormap; removing\n", procName);
1735  d = pixGetDepth(pixs);
1736  } else if (d == 2 || d == 4) {
1737  pixs = pixConvertTo8(pix, FALSE);
1738  d = 8;
1739  } else {
1740  pixs = pixClone(pix);
1741  }
1742 
1743  if (d != 8 && d != 32) { /* d == 1 or d == 16 */
1744  L_WARNING("depth not 8 or 32 bpp; do regular scaling\n", procName);
1745  pixDestroy(&pixs);
1746  return pixScaleGeneral(pix, scalex, scaley, 0.0, 0);
1747  }
1748 
1749  /* If 1.42 < 1/minscale < 2.5, use isize = 2
1750  * If 2.5 =< 1/minscale < 3.5, use isize = 3, etc.
1751  * Under no conditions use isize < 2 */
1752  minscale = L_MIN(scalex, scaley);
1753  size = 1.0 / minscale; /* ideal filter full width */
1754  isize = L_MAX(2, (l_int32)(size + 0.5));
1755 
1756  pixGetDimensions(pixs, &ws, &hs, NULL);
1757  if ((ws < isize) || (hs < isize)) {
1758  pixDestroy(&pixs);
1759  return (PIX *)ERROR_PTR("pixs too small", procName, NULL);
1760  }
1761  datas = pixGetData(pixs);
1762  wpls = pixGetWpl(pixs);
1763  wd = (l_int32)(scalex * (l_float32)ws + 0.5);
1764  hd = (l_int32)(scaley * (l_float32)hs + 0.5);
1765  if (wd < 1 || hd < 1) {
1766  pixDestroy(&pixs);
1767  return (PIX *)ERROR_PTR("pixd too small", procName, NULL);
1768  }
1769  if ((pixd = pixCreate(wd, hd, d)) == NULL) {
1770  pixDestroy(&pixs);
1771  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1772  }
1773  pixCopyResolution(pixd, pixs);
1774  pixCopyInputFormat(pixd, pixs);
1775  pixScaleResolution(pixd, scalex, scaley);
1776  datad = pixGetData(pixd);
1777  wpld = pixGetWpl(pixd);
1778  scaleSmoothLow(datad, wd, hd, wpld, datas, ws, hs, d, wpls, isize);
1779  if (d == 32 && pixGetSpp(pixs) == 4)
1780  pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley);
1781 
1782  pixDestroy(&pixs);
1783  return pixd;
1784 }
1785 
1786 
1806 PIX *
1808  l_int32 wd,
1809  l_int32 hd)
1810 {
1811 l_int32 w, h;
1812 l_float32 scalex, scaley;
1813 
1814  PROCNAME("pixScaleSmoothToSize");
1815 
1816  if (!pixs)
1817  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1818  if (wd <= 0 && hd <= 0)
1819  return (PIX *)ERROR_PTR("neither wd nor hd > 0", procName, NULL);
1820 
1821  pixGetDimensions(pixs, &w, &h, NULL);
1822  if (wd <= 0) {
1823  scaley = (l_float32)hd / (l_float32)h;
1824  scalex = scaley;
1825  } else if (hd <= 0) {
1826  scalex = (l_float32)wd / (l_float32)w;
1827  scaley = scalex;
1828  } else {
1829  scalex = (l_float32)wd / (l_float32)w;
1830  scaley = (l_float32)hd / (l_float32)h;
1831  }
1832 
1833  return pixScaleSmooth(pixs, scalex, scaley);
1834 }
1835 
1836 
1844 PIX *
1846  l_float32 rwt,
1847  l_float32 gwt,
1848  l_float32 bwt)
1849 {
1850 l_int32 wd, hd, wpls, wpld;
1851 l_uint32 *datas, *datad;
1852 PIX *pixd;
1853 
1854  PROCNAME("pixScaleRGBToGray2");
1855 
1856  if (!pixs)
1857  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1858  if (pixGetDepth(pixs) != 32)
1859  return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
1860  if (rwt + gwt + bwt < 0.98 || rwt + gwt + bwt > 1.02)
1861  return (PIX *)ERROR_PTR("sum of wts should be 1.0", procName, NULL);
1862 
1863  wd = pixGetWidth(pixs) / 2;
1864  hd = pixGetHeight(pixs) / 2;
1865  wpls = pixGetWpl(pixs);
1866  datas = pixGetData(pixs);
1867  if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1868  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1869  pixCopyResolution(pixd, pixs);
1870  pixCopyInputFormat(pixd, pixs);
1871  pixScaleResolution(pixd, 0.5, 0.5);
1872  wpld = pixGetWpl(pixd);
1873  datad = pixGetData(pixd);
1874  scaleRGBToGray2Low(datad, wd, hd, wpld, datas, wpls, rwt, gwt, bwt);
1875  return pixd;
1876 }
1877 
1878 
1879 /*------------------------------------------------------------------*
1880  * Downscaling with (antialias) area mapping *
1881  *------------------------------------------------------------------*/
1911 PIX *
1913  l_float32 scalex,
1914  l_float32 scaley)
1915 {
1916 l_int32 ws, hs, d, wd, hd, wpls, wpld;
1917 l_uint32 *datas, *datad;
1918 l_float32 maxscale;
1919 PIX *pixs, *pixd, *pixt1, *pixt2, *pixt3;
1920 
1921  PROCNAME("pixScaleAreaMap");
1922 
1923  if (!pix)
1924  return (PIX *)ERROR_PTR("pix not defined", procName, NULL);
1925  d = pixGetDepth(pix);
1926  if (d != 2 && d != 4 && d != 8 && d != 32)
1927  return (PIX *)ERROR_PTR("pix not 2, 4, 8 or 32 bpp", procName, NULL);
1928  maxscale = L_MAX(scalex, scaley);
1929  if (maxscale >= 0.7) {
1930  L_WARNING("scaling factors not < 0.7; do regular scaling\n", procName);
1931  return pixScaleGeneral(pix, scalex, scaley, 0.0, 0);
1932  }
1933 
1934  /* Special cases: 2x, 4x, 8x, 16x reduction */
1935  if (scalex == 0.5 && scaley == 0.5)
1936  return pixScaleAreaMap2(pix);
1937  if (scalex == 0.25 && scaley == 0.25) {
1938  pixt1 = pixScaleAreaMap2(pix);
1939  pixd = pixScaleAreaMap2(pixt1);
1940  pixDestroy(&pixt1);
1941  return pixd;
1942  }
1943  if (scalex == 0.125 && scaley == 0.125) {
1944  pixt1 = pixScaleAreaMap2(pix);
1945  pixt2 = pixScaleAreaMap2(pixt1);
1946  pixd = pixScaleAreaMap2(pixt2);
1947  pixDestroy(&pixt1);
1948  pixDestroy(&pixt2);
1949  return pixd;
1950  }
1951  if (scalex == 0.0625 && scaley == 0.0625) {
1952  pixt1 = pixScaleAreaMap2(pix);
1953  pixt2 = pixScaleAreaMap2(pixt1);
1954  pixt3 = pixScaleAreaMap2(pixt2);
1955  pixd = pixScaleAreaMap2(pixt3);
1956  pixDestroy(&pixt1);
1957  pixDestroy(&pixt2);
1958  pixDestroy(&pixt3);
1959  return pixd;
1960  }
1961 
1962  /* Remove colormap if necessary.
1963  * If 2 bpp or 4 bpp gray, convert to 8 bpp */
1964  if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
1965  L_WARNING("pix has colormap; removing\n", procName);
1967  d = pixGetDepth(pixs);
1968  } else if (d == 2 || d == 4) {
1969  pixs = pixConvertTo8(pix, FALSE);
1970  d = 8;
1971  } else {
1972  pixs = pixClone(pix);
1973  }
1974 
1975  pixGetDimensions(pixs, &ws, &hs, NULL);
1976  datas = pixGetData(pixs);
1977  wpls = pixGetWpl(pixs);
1978  wd = (l_int32)(scalex * (l_float32)ws + 0.5);
1979  hd = (l_int32)(scaley * (l_float32)hs + 0.5);
1980  if (wd < 1 || hd < 1) {
1981  pixDestroy(&pixs);
1982  return (PIX *)ERROR_PTR("pixd too small", procName, NULL);
1983  }
1984  if ((pixd = pixCreate(wd, hd, d)) == NULL) {
1985  pixDestroy(&pixs);
1986  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1987  }
1988  pixCopyInputFormat(pixd, pixs);
1989  pixCopyResolution(pixd, pixs);
1990  pixScaleResolution(pixd, scalex, scaley);
1991  datad = pixGetData(pixd);
1992  wpld = pixGetWpl(pixd);
1993  if (d == 8) {
1994  scaleGrayAreaMapLow(datad, wd, hd, wpld, datas, ws, hs, wpls);
1995  } else { /* RGB, d == 32 */
1996  scaleColorAreaMapLow(datad, wd, hd, wpld, datas, ws, hs, wpls);
1997  if (pixGetSpp(pixs) == 4)
1998  pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley);
1999  }
2000 
2001  pixDestroy(&pixs);
2002  return pixd;
2003 }
2004 
2005 
2031 PIX *
2033 {
2034 l_int32 wd, hd, d, wpls, wpld;
2035 l_uint32 *datas, *datad;
2036 PIX *pixs, *pixd;
2037 
2038  PROCNAME("pixScaleAreaMap2");
2039 
2040  if (!pix)
2041  return (PIX *)ERROR_PTR("pix not defined", procName, NULL);
2042  d = pixGetDepth(pix);
2043  if (d != 2 && d != 4 && d != 8 && d != 32)
2044  return (PIX *)ERROR_PTR("pix not 2, 4, 8 or 32 bpp", procName, NULL);
2045 
2046  /* Remove colormap if necessary.
2047  * If 2 bpp or 4 bpp gray, convert to 8 bpp */
2048  if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
2049  L_WARNING("pix has colormap; removing\n", procName);
2051  d = pixGetDepth(pixs);
2052  } else if (d == 2 || d == 4) {
2053  pixs = pixConvertTo8(pix, FALSE);
2054  d = 8;
2055  } else {
2056  pixs = pixClone(pix);
2057  }
2058 
2059  wd = pixGetWidth(pixs) / 2;
2060  hd = pixGetHeight(pixs) / 2;
2061  datas = pixGetData(pixs);
2062  wpls = pixGetWpl(pixs);
2063  pixd = pixCreate(wd, hd, d);
2064  datad = pixGetData(pixd);
2065  wpld = pixGetWpl(pixd);
2066  pixCopyInputFormat(pixd, pixs);
2067  pixCopyResolution(pixd, pixs);
2068  pixScaleResolution(pixd, 0.5, 0.5);
2069  scaleAreaMapLow2(datad, wd, hd, wpld, datas, d, wpls);
2070  if (pixGetSpp(pixs) == 4)
2071  pixScaleAndTransferAlpha(pixd, pixs, 0.5, 0.5);
2072  pixDestroy(&pixs);
2073  return pixd;
2074 }
2075 
2076 
2096 PIX *
2098  l_int32 wd,
2099  l_int32 hd)
2100 {
2101 l_int32 w, h;
2102 l_float32 scalex, scaley;
2103 
2104  PROCNAME("pixScaleAreaMapToSize");
2105 
2106  if (!pixs)
2107  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2108  if (wd <= 0 && hd <= 0)
2109  return (PIX *)ERROR_PTR("neither wd nor hd > 0", procName, NULL);
2110 
2111  pixGetDimensions(pixs, &w, &h, NULL);
2112  if (wd <= 0) {
2113  scaley = (l_float32)hd / (l_float32)h;
2114  scalex = scaley;
2115  } else if (hd <= 0) {
2116  scalex = (l_float32)wd / (l_float32)w;
2117  scaley = scalex;
2118  } else {
2119  scalex = (l_float32)wd / (l_float32)w;
2120  scaley = (l_float32)hd / (l_float32)h;
2121  }
2122 
2123  return pixScaleAreaMap(pixs, scalex, scaley);
2124 }
2125 
2126 
2127 /*------------------------------------------------------------------*
2128  * Binary scaling by closest pixel sampling *
2129  *------------------------------------------------------------------*/
2144 PIX *
2146  l_float32 scalex,
2147  l_float32 scaley)
2148 {
2149 l_int32 ws, hs, wpls, wd, hd, wpld;
2150 l_uint32 *datas, *datad;
2151 PIX *pixd;
2152 
2153  PROCNAME("pixScaleBinary");
2154 
2155  if (!pixs)
2156  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2157  if (pixGetDepth(pixs) != 1)
2158  return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, NULL);
2159  if (scalex <= 0.0 || scaley <= 0.0)
2160  return (PIX *)ERROR_PTR("scale factor <= 0", procName, NULL);
2161  if (scalex == 1.0 && scaley == 1.0)
2162  return pixCopy(NULL, pixs);
2163 
2164  pixGetDimensions(pixs, &ws, &hs, NULL);
2165  datas = pixGetData(pixs);
2166  wpls = pixGetWpl(pixs);
2167  wd = (l_int32)(scalex * (l_float32)ws + 0.5);
2168  hd = (l_int32)(scaley * (l_float32)hs + 0.5);
2169  if ((pixd = pixCreate(wd, hd, 1)) == NULL)
2170  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2171  pixCopyColormap(pixd, pixs);
2172  pixCopyText(pixd, pixs);
2173  pixCopyInputFormat(pixd, pixs);
2174  pixCopyResolution(pixd, pixs);
2175  pixScaleResolution(pixd, scalex, scaley);
2176  datad = pixGetData(pixd);
2177  wpld = pixGetWpl(pixd);
2178  scaleBinaryLow(datad, wd, hd, wpld, datas, ws, hs, wpls);
2179  return pixd;
2180 }
2181 
2182 
2183 /* ================================================================ *
2184  * Low level static functions *
2185  * ================================================================ */
2186 
2187 /*------------------------------------------------------------------*
2188  * General linear interpolated color scaling *
2189  *------------------------------------------------------------------*/
2201 static void
2202 scaleColorLILow(l_uint32 *datad,
2203  l_int32 wd,
2204  l_int32 hd,
2205  l_int32 wpld,
2206  l_uint32 *datas,
2207  l_int32 ws,
2208  l_int32 hs,
2209  l_int32 wpls)
2210 {
2211 l_int32 i, j, wm2, hm2;
2212 l_int32 xpm, ypm; /* location in src image, to 1/16 of a pixel */
2213 l_int32 xp, yp, xf, yf; /* src pixel and pixel fraction coordinates */
2214 l_int32 v00r, v01r, v10r, v11r, v00g, v01g, v10g, v11g;
2215 l_int32 v00b, v01b, v10b, v11b, area00, area01, area10, area11;
2216 l_uint32 pixels1, pixels2, pixels3, pixels4, pixel;
2217 l_uint32 *lines, *lined;
2218 l_float32 scx, scy;
2219 
2220  /* (scx, scy) are scaling factors that are applied to the
2221  * dest coords to get the corresponding src coords.
2222  * We need them because we iterate over dest pixels
2223  * and must find the corresponding set of src pixels. */
2224  scx = 16. * (l_float32)ws / (l_float32)wd;
2225  scy = 16. * (l_float32)hs / (l_float32)hd;
2226  wm2 = ws - 2;
2227  hm2 = hs - 2;
2228 
2229  /* Iterate over the destination pixels */
2230  for (i = 0; i < hd; i++) {
2231  ypm = (l_int32)(scy * (l_float32)i);
2232  yp = ypm >> 4;
2233  yf = ypm & 0x0f;
2234  lined = datad + i * wpld;
2235  lines = datas + yp * wpls;
2236  for (j = 0; j < wd; j++) {
2237  xpm = (l_int32)(scx * (l_float32)j);
2238  xp = xpm >> 4;
2239  xf = xpm & 0x0f;
2240 
2241  /* Do bilinear interpolation. This is a simple
2242  * generalization of the calculation in scaleGrayLILow().
2243  * Without this, we could simply subsample:
2244  * *(lined + j) = *(lines + xp);
2245  * which is faster but gives lousy results! */
2246  pixels1 = *(lines + xp);
2247 
2248  if (xp > wm2 || yp > hm2) {
2249  if (yp > hm2 && xp <= wm2) { /* pixels near bottom */
2250  pixels2 = *(lines + xp + 1);
2251  pixels3 = pixels1;
2252  pixels4 = pixels2;
2253  } else if (xp > wm2 && yp <= hm2) { /* pixels near rt side */
2254  pixels2 = pixels1;
2255  pixels3 = *(lines + wpls + xp);
2256  pixels4 = pixels3;
2257  } else { /* pixels at LR corner */
2258  pixels4 = pixels3 = pixels2 = pixels1;
2259  }
2260  } else {
2261  pixels2 = *(lines + xp + 1);
2262  pixels3 = *(lines + wpls + xp);
2263  pixels4 = *(lines + wpls + xp + 1);
2264  }
2265 
2266  area00 = (16 - xf) * (16 - yf);
2267  area10 = xf * (16 - yf);
2268  area01 = (16 - xf) * yf;
2269  area11 = xf * yf;
2270  v00r = area00 * ((pixels1 >> L_RED_SHIFT) & 0xff);
2271  v00g = area00 * ((pixels1 >> L_GREEN_SHIFT) & 0xff);
2272  v00b = area00 * ((pixels1 >> L_BLUE_SHIFT) & 0xff);
2273  v10r = area10 * ((pixels2 >> L_RED_SHIFT) & 0xff);
2274  v10g = area10 * ((pixels2 >> L_GREEN_SHIFT) & 0xff);
2275  v10b = area10 * ((pixels2 >> L_BLUE_SHIFT) & 0xff);
2276  v01r = area01 * ((pixels3 >> L_RED_SHIFT) & 0xff);
2277  v01g = area01 * ((pixels3 >> L_GREEN_SHIFT) & 0xff);
2278  v01b = area01 * ((pixels3 >> L_BLUE_SHIFT) & 0xff);
2279  v11r = area11 * ((pixels4 >> L_RED_SHIFT) & 0xff);
2280  v11g = area11 * ((pixels4 >> L_GREEN_SHIFT) & 0xff);
2281  v11b = area11 * ((pixels4 >> L_BLUE_SHIFT) & 0xff);
2282  pixel = (((v00r + v10r + v01r + v11r + 128) << 16) & 0xff000000) |
2283  (((v00g + v10g + v01g + v11g + 128) << 8) & 0x00ff0000) |
2284  ((v00b + v10b + v01b + v11b + 128) & 0x0000ff00);
2285  *(lined + j) = pixel;
2286  }
2287  }
2288 }
2289 
2290 
2291 /*------------------------------------------------------------------*
2292  * General linear interpolated gray scaling *
2293  *------------------------------------------------------------------*/
2303 static void
2304 scaleGrayLILow(l_uint32 *datad,
2305  l_int32 wd,
2306  l_int32 hd,
2307  l_int32 wpld,
2308  l_uint32 *datas,
2309  l_int32 ws,
2310  l_int32 hs,
2311  l_int32 wpls)
2312 {
2313 l_int32 i, j, wm2, hm2;
2314 l_int32 xpm, ypm; /* location in src image, to 1/16 of a pixel */
2315 l_int32 xp, yp, xf, yf; /* src pixel and pixel fraction coordinates */
2316 l_int32 v00, v01, v10, v11, v00_val, v01_val, v10_val, v11_val;
2317 l_uint8 val;
2318 l_uint32 *lines, *lined;
2319 l_float32 scx, scy;
2320 
2321  /* (scx, scy) are scaling factors that are applied to the
2322  * dest coords to get the corresponding src coords.
2323  * We need them because we iterate over dest pixels
2324  * and must find the corresponding set of src pixels. */
2325  scx = 16. * (l_float32)ws / (l_float32)wd;
2326  scy = 16. * (l_float32)hs / (l_float32)hd;
2327  wm2 = ws - 2;
2328  hm2 = hs - 2;
2329 
2330  /* Iterate over the destination pixels */
2331  for (i = 0; i < hd; i++) {
2332  ypm = (l_int32)(scy * (l_float32)i);
2333  yp = ypm >> 4;
2334  yf = ypm & 0x0f;
2335  lined = datad + i * wpld;
2336  lines = datas + yp * wpls;
2337  for (j = 0; j < wd; j++) {
2338  xpm = (l_int32)(scx * (l_float32)j);
2339  xp = xpm >> 4;
2340  xf = xpm & 0x0f;
2341 
2342  /* Do bilinear interpolation. Without this, we could
2343  * simply subsample:
2344  * SET_DATA_BYTE(lined, j, GET_DATA_BYTE(lines, xp));
2345  * which is faster but gives lousy results! */
2346  v00_val = GET_DATA_BYTE(lines, xp);
2347  if (xp > wm2 || yp > hm2) {
2348  if (yp > hm2 && xp <= wm2) { /* pixels near bottom */
2349  v01_val = v00_val;
2350  v10_val = GET_DATA_BYTE(lines, xp + 1);
2351  v11_val = v10_val;
2352  } else if (xp > wm2 && yp <= hm2) { /* pixels near rt side */
2353  v01_val = GET_DATA_BYTE(lines + wpls, xp);
2354  v10_val = v00_val;
2355  v11_val = v01_val;
2356  } else { /* pixels at LR corner */
2357  v10_val = v01_val = v11_val = v00_val;
2358  }
2359  } else {
2360  v10_val = GET_DATA_BYTE(lines, xp + 1);
2361  v01_val = GET_DATA_BYTE(lines + wpls, xp);
2362  v11_val = GET_DATA_BYTE(lines + wpls, xp + 1);
2363  }
2364 
2365  v00 = (16 - xf) * (16 - yf) * v00_val;
2366  v10 = xf * (16 - yf) * v10_val;
2367  v01 = (16 - xf) * yf * v01_val;
2368  v11 = xf * yf * v11_val;
2369 
2370  val = (l_uint8)((v00 + v01 + v10 + v11 + 128) / 256);
2371  SET_DATA_BYTE(lined, j, val);
2372  }
2373  }
2374 }
2375 
2376 
2377 /*------------------------------------------------------------------*
2378  * 2x linear interpolated color scaling *
2379  *------------------------------------------------------------------*/
2419 static void
2420 scaleColor2xLILow(l_uint32 *datad,
2421  l_int32 wpld,
2422  l_uint32 *datas,
2423  l_int32 ws,
2424  l_int32 hs,
2425  l_int32 wpls)
2426 {
2427 l_int32 i, hsm;
2428 l_uint32 *lines, *lined;
2429 
2430  hsm = hs - 1;
2431 
2432  /* We're taking 2 src and 2 dest lines at a time,
2433  * and for each src line, we're computing 2 dest lines.
2434  * Call these 2 dest lines: destline1 and destline2.
2435  * The first src line is used for destline 1.
2436  * On all but the last src line, both src lines are
2437  * used in the linear interpolation for destline2.
2438  * On the last src line, both destline1 and destline2
2439  * are computed using only that src line (because there
2440  * isn't a lower src line). */
2441 
2442  /* iterate over all but the last src line */
2443  for (i = 0; i < hsm; i++) {
2444  lines = datas + i * wpls;
2445  lined = datad + 2 * i * wpld;
2446  scaleColor2xLILineLow(lined, wpld, lines, ws, wpls, 0);
2447  }
2448 
2449  /* last src line */
2450  lines = datas + hsm * wpls;
2451  lined = datad + 2 * hsm * wpld;
2452  scaleColor2xLILineLow(lined, wpld, lines, ws, wpls, 1);
2453 }
2454 
2455 
2467 static void
2468 scaleColor2xLILineLow(l_uint32 *lined,
2469  l_int32 wpld,
2470  l_uint32 *lines,
2471  l_int32 ws,
2472  l_int32 wpls,
2473  l_int32 lastlineflag)
2474 {
2475 l_int32 j, jd, wsm;
2476 l_int32 rval1, rval2, rval3, rval4, gval1, gval2, gval3, gval4;
2477 l_int32 bval1, bval2, bval3, bval4;
2478 l_uint32 pixels1, pixels2, pixels3, pixels4, pixel;
2479 l_uint32 *linesp, *linedp;
2480 
2481  wsm = ws - 1;
2482 
2483  if (lastlineflag == 0) {
2484  linesp = lines + wpls;
2485  linedp = lined + wpld;
2486  pixels1 = *lines;
2487  pixels3 = *linesp;
2488 
2489  /* initialize with v(2) and v(4) */
2490  rval2 = pixels1 >> 24;
2491  gval2 = (pixels1 >> 16) & 0xff;
2492  bval2 = (pixels1 >> 8) & 0xff;
2493  rval4 = pixels3 >> 24;
2494  gval4 = (pixels3 >> 16) & 0xff;
2495  bval4 = (pixels3 >> 8) & 0xff;
2496 
2497  for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
2498  /* shift in previous src values */
2499  rval1 = rval2;
2500  gval1 = gval2;
2501  bval1 = bval2;
2502  rval3 = rval4;
2503  gval3 = gval4;
2504  bval3 = bval4;
2505  /* get new src values */
2506  pixels2 = *(lines + j + 1);
2507  pixels4 = *(linesp + j + 1);
2508  rval2 = pixels2 >> 24;
2509  gval2 = (pixels2 >> 16) & 0xff;
2510  bval2 = (pixels2 >> 8) & 0xff;
2511  rval4 = pixels4 >> 24;
2512  gval4 = (pixels4 >> 16) & 0xff;
2513  bval4 = (pixels4 >> 8) & 0xff;
2514  /* save dest values */
2515  pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
2516  *(lined + jd) = pixel; /* pix 1 */
2517  pixel = ((((rval1 + rval2) << 23) & 0xff000000) |
2518  (((gval1 + gval2) << 15) & 0x00ff0000) |
2519  (((bval1 + bval2) << 7) & 0x0000ff00));
2520  *(lined + jd + 1) = pixel; /* pix 2 */
2521  pixel = ((((rval1 + rval3) << 23) & 0xff000000) |
2522  (((gval1 + gval3) << 15) & 0x00ff0000) |
2523  (((bval1 + bval3) << 7) & 0x0000ff00));
2524  *(linedp + jd) = pixel; /* pix 3 */
2525  pixel = ((((rval1 + rval2 + rval3 + rval4) << 22) & 0xff000000) |
2526  (((gval1 + gval2 + gval3 + gval4) << 14) & 0x00ff0000) |
2527  (((bval1 + bval2 + bval3 + bval4) << 6) & 0x0000ff00));
2528  *(linedp + jd + 1) = pixel; /* pix 4 */
2529  }
2530  /* last src pixel on line */
2531  rval1 = rval2;
2532  gval1 = gval2;
2533  bval1 = bval2;
2534  rval3 = rval4;
2535  gval3 = gval4;
2536  bval3 = bval4;
2537  pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
2538  *(lined + 2 * wsm) = pixel; /* pix 1 */
2539  *(lined + 2 * wsm + 1) = pixel; /* pix 2 */
2540  pixel = ((((rval1 + rval3) << 23) & 0xff000000) |
2541  (((gval1 + gval3) << 15) & 0x00ff0000) |
2542  (((bval1 + bval3) << 7) & 0x0000ff00));
2543  *(linedp + 2 * wsm) = pixel; /* pix 3 */
2544  *(linedp + 2 * wsm + 1) = pixel; /* pix 4 */
2545  } else { /* last row of src pixels: lastlineflag == 1 */
2546  linedp = lined + wpld;
2547  pixels2 = *lines;
2548  rval2 = pixels2 >> 24;
2549  gval2 = (pixels2 >> 16) & 0xff;
2550  bval2 = (pixels2 >> 8) & 0xff;
2551  for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
2552  rval1 = rval2;
2553  gval1 = gval2;
2554  bval1 = bval2;
2555  pixels2 = *(lines + j + 1);
2556  rval2 = pixels2 >> 24;
2557  gval2 = (pixels2 >> 16) & 0xff;
2558  bval2 = (pixels2 >> 8) & 0xff;
2559  pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
2560  *(lined + jd) = pixel; /* pix 1 */
2561  *(linedp + jd) = pixel; /* pix 2 */
2562  pixel = ((((rval1 + rval2) << 23) & 0xff000000) |
2563  (((gval1 + gval2) << 15) & 0x00ff0000) |
2564  (((bval1 + bval2) << 7) & 0x0000ff00));
2565  *(lined + jd + 1) = pixel; /* pix 3 */
2566  *(linedp + jd + 1) = pixel; /* pix 4 */
2567  }
2568  rval1 = rval2;
2569  gval1 = gval2;
2570  bval1 = bval2;
2571  pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
2572  *(lined + 2 * wsm) = pixel; /* pix 1 */
2573  *(lined + 2 * wsm + 1) = pixel; /* pix 2 */
2574  *(linedp + 2 * wsm) = pixel; /* pix 3 */
2575  *(linedp + 2 * wsm + 1) = pixel; /* pix 4 */
2576  }
2577 }
2578 
2579 
2580 /*------------------------------------------------------------------*
2581  * 2x linear interpolated gray scaling *
2582  *------------------------------------------------------------------*/
2618 static void
2619 scaleGray2xLILow(l_uint32 *datad,
2620  l_int32 wpld,
2621  l_uint32 *datas,
2622  l_int32 ws,
2623  l_int32 hs,
2624  l_int32 wpls)
2625 {
2626 l_int32 i, hsm;
2627 l_uint32 *lines, *lined;
2628 
2629  hsm = hs - 1;
2630 
2631  /* We're taking 2 src and 2 dest lines at a time,
2632  * and for each src line, we're computing 2 dest lines.
2633  * Call these 2 dest lines: destline1 and destline2.
2634  * The first src line is used for destline 1.
2635  * On all but the last src line, both src lines are
2636  * used in the linear interpolation for destline2.
2637  * On the last src line, both destline1 and destline2
2638  * are computed using only that src line (because there
2639  * isn't a lower src line). */
2640 
2641  /* iterate over all but the last src line */
2642  for (i = 0; i < hsm; i++) {
2643  lines = datas + i * wpls;
2644  lined = datad + 2 * i * wpld;
2645  scaleGray2xLILineLow(lined, wpld, lines, ws, wpls, 0);
2646  }
2647 
2648  /* last src line */
2649  lines = datas + hsm * wpls;
2650  lined = datad + 2 * hsm * wpld;
2651  scaleGray2xLILineLow(lined, wpld, lines, ws, wpls, 1);
2652 }
2653 
2654 
2666 static void
2667 scaleGray2xLILineLow(l_uint32 *lined,
2668  l_int32 wpld,
2669  l_uint32 *lines,
2670  l_int32 ws,
2671  l_int32 wpls,
2672  l_int32 lastlineflag)
2673 {
2674 l_int32 j, jd, wsm, w;
2675 l_int32 sval1, sval2, sval3, sval4;
2676 l_uint32 *linesp, *linedp;
2677 l_uint32 words, wordsp, wordd, worddp;
2678 
2679  wsm = ws - 1;
2680 
2681  if (lastlineflag == 0) {
2682  linesp = lines + wpls;
2683  linedp = lined + wpld;
2684 
2685  /* Unroll the loop 4x and work on full words */
2686  words = lines[0];
2687  wordsp = linesp[0];
2688  sval2 = (words >> 24) & 0xff;
2689  sval4 = (wordsp >> 24) & 0xff;
2690  for (j = 0, jd = 0, w = 0; j + 3 < wsm; j += 4, jd += 8, w++) {
2691  /* At the top of the loop,
2692  * words == lines[w], wordsp == linesp[w]
2693  * and the top bytes of those have been loaded into
2694  * sval2 and sval4. */
2695  sval1 = sval2;
2696  sval2 = (words >> 16) & 0xff;
2697  sval3 = sval4;
2698  sval4 = (wordsp >> 16) & 0xff;
2699  wordd = (sval1 << 24) | (((sval1 + sval2) >> 1) << 16);
2700  worddp = (((sval1 + sval3) >> 1) << 24) |
2701  (((sval1 + sval2 + sval3 + sval4) >> 2) << 16);
2702 
2703  sval1 = sval2;
2704  sval2 = (words >> 8) & 0xff;
2705  sval3 = sval4;
2706  sval4 = (wordsp >> 8) & 0xff;
2707  wordd |= (sval1 << 8) | ((sval1 + sval2) >> 1);
2708  worddp |= (((sval1 + sval3) >> 1) << 8) |
2709  ((sval1 + sval2 + sval3 + sval4) >> 2);
2710  lined[w * 2] = wordd;
2711  linedp[w * 2] = worddp;
2712 
2713  sval1 = sval2;
2714  sval2 = words & 0xff;
2715  sval3 = sval4;
2716  sval4 = wordsp & 0xff;
2717  wordd = (sval1 << 24) | /* pix 1 */
2718  (((sval1 + sval2) >> 1) << 16); /* pix 2 */
2719  worddp = (((sval1 + sval3) >> 1) << 24) | /* pix 3 */
2720  (((sval1 + sval2 + sval3 + sval4) >> 2) << 16); /* pix 4 */
2721 
2722  /* Load the next word as we need its first byte */
2723  words = lines[w + 1];
2724  wordsp = linesp[w + 1];
2725  sval1 = sval2;
2726  sval2 = (words >> 24) & 0xff;
2727  sval3 = sval4;
2728  sval4 = (wordsp >> 24) & 0xff;
2729  wordd |= (sval1 << 8) | /* pix 1 */
2730  ((sval1 + sval2) >> 1); /* pix 2 */
2731  worddp |= (((sval1 + sval3) >> 1) << 8) | /* pix 3 */
2732  ((sval1 + sval2 + sval3 + sval4) >> 2); /* pix 4 */
2733  lined[w * 2 + 1] = wordd;
2734  linedp[w * 2 + 1] = worddp;
2735  }
2736 
2737  /* Finish up the last word */
2738  for (; j < wsm; j++, jd += 2) {
2739  sval1 = sval2;
2740  sval3 = sval4;
2741  sval2 = GET_DATA_BYTE(lines, j + 1);
2742  sval4 = GET_DATA_BYTE(linesp, j + 1);
2743  SET_DATA_BYTE(lined, jd, sval1); /* pix 1 */
2744  SET_DATA_BYTE(lined, jd + 1, (sval1 + sval2) / 2); /* pix 2 */
2745  SET_DATA_BYTE(linedp, jd, (sval1 + sval3) / 2); /* pix 3 */
2746  SET_DATA_BYTE(linedp, jd + 1,
2747  (sval1 + sval2 + sval3 + sval4) / 4); /* pix 4 */
2748  }
2749  sval1 = sval2;
2750  sval3 = sval4;
2751  SET_DATA_BYTE(lined, 2 * wsm, sval1); /* pix 1 */
2752  SET_DATA_BYTE(lined, 2 * wsm + 1, sval1); /* pix 2 */
2753  SET_DATA_BYTE(linedp, 2 * wsm, (sval1 + sval3) / 2); /* pix 3 */
2754  SET_DATA_BYTE(linedp, 2 * wsm + 1, (sval1 + sval3) / 2); /* pix 4 */
2755 
2756 #if DEBUG_UNROLLING
2757 #define CHECK_BYTE(a, b, c) if (GET_DATA_BYTE(a, b) != c) {\
2758  fprintf(stderr, "Error: mismatch at %d, %d vs %d\n", \
2759  j, GET_DATA_BYTE(a, b), c); }
2760 
2761  sval2 = GET_DATA_BYTE(lines, 0);
2762  sval4 = GET_DATA_BYTE(linesp, 0);
2763  for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
2764  sval1 = sval2;
2765  sval3 = sval4;
2766  sval2 = GET_DATA_BYTE(lines, j + 1);
2767  sval4 = GET_DATA_BYTE(linesp, j + 1);
2768  CHECK_BYTE(lined, jd, sval1); /* pix 1 */
2769  CHECK_BYTE(lined, jd + 1, (sval1 + sval2) / 2); /* pix 2 */
2770  CHECK_BYTE(linedp, jd, (sval1 + sval3) / 2); /* pix 3 */
2771  CHECK_BYTE(linedp, jd + 1,
2772  (sval1 + sval2 + sval3 + sval4) / 4); /* pix 4 */
2773  }
2774  sval1 = sval2;
2775  sval3 = sval4;
2776  CHECK_BYTE(lined, 2 * wsm, sval1); /* pix 1 */
2777  CHECK_BYTE(lined, 2 * wsm + 1, sval1); /* pix 2 */
2778  CHECK_BYTE(linedp, 2 * wsm, (sval1 + sval3) / 2); /* pix 3 */
2779  CHECK_BYTE(linedp, 2 * wsm + 1, (sval1 + sval3) / 2); /* pix 4 */
2780 #undef CHECK_BYTE
2781 #endif
2782  } else { /* last row of src pixels: lastlineflag == 1 */
2783  linedp = lined + wpld;
2784  sval2 = GET_DATA_BYTE(lines, 0);
2785  for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
2786  sval1 = sval2;
2787  sval2 = GET_DATA_BYTE(lines, j + 1);
2788  SET_DATA_BYTE(lined, jd, sval1); /* pix 1 */
2789  SET_DATA_BYTE(linedp, jd, sval1); /* pix 3 */
2790  SET_DATA_BYTE(lined, jd + 1, (sval1 + sval2) / 2); /* pix 2 */
2791  SET_DATA_BYTE(linedp, jd + 1, (sval1 + sval2) / 2); /* pix 4 */
2792  }
2793  sval1 = sval2;
2794  SET_DATA_BYTE(lined, 2 * wsm, sval1); /* pix 1 */
2795  SET_DATA_BYTE(lined, 2 * wsm + 1, sval1); /* pix 2 */
2796  SET_DATA_BYTE(linedp, 2 * wsm, sval1); /* pix 3 */
2797  SET_DATA_BYTE(linedp, 2 * wsm + 1, sval1); /* pix 4 */
2798  }
2799 }
2800 
2801 
2802 /*------------------------------------------------------------------*
2803  * 4x linear interpolated gray scaling *
2804  *------------------------------------------------------------------*/
2856 static void
2857 scaleGray4xLILow(l_uint32 *datad,
2858  l_int32 wpld,
2859  l_uint32 *datas,
2860  l_int32 ws,
2861  l_int32 hs,
2862  l_int32 wpls)
2863 {
2864 l_int32 i, hsm;
2865 l_uint32 *lines, *lined;
2866 
2867  hsm = hs - 1;
2868 
2869  /* We're taking 2 src and 4 dest lines at a time,
2870  * and for each src line, we're computing 4 dest lines.
2871  * Call these 4 dest lines: destline1 - destline4.
2872  * The first src line is used for destline 1.
2873  * Two src lines are used for all other dest lines,
2874  * except for the last 4 dest lines, which are computed
2875  * using only the last src line. */
2876 
2877  /* iterate over all but the last src line */
2878  for (i = 0; i < hsm; i++) {
2879  lines = datas + i * wpls;
2880  lined = datad + 4 * i * wpld;
2881  scaleGray4xLILineLow(lined, wpld, lines, ws, wpls, 0);
2882  }
2883 
2884  /* last src line */
2885  lines = datas + hsm * wpls;
2886  lined = datad + 4 * hsm * wpld;
2887  scaleGray4xLILineLow(lined, wpld, lines, ws, wpls, 1);
2888 }
2889 
2890 
2902 static void
2903 scaleGray4xLILineLow(l_uint32 *lined,
2904  l_int32 wpld,
2905  l_uint32 *lines,
2906  l_int32 ws,
2907  l_int32 wpls,
2908  l_int32 lastlineflag)
2909 {
2910 l_int32 j, jd, wsm, wsm4;
2911 l_int32 s1, s2, s3, s4, s1t, s2t, s3t, s4t;
2912 l_uint32 *linesp, *linedp1, *linedp2, *linedp3;
2913 
2914  wsm = ws - 1;
2915  wsm4 = 4 * wsm;
2916 
2917  if (lastlineflag == 0) {
2918  linesp = lines + wpls;
2919  linedp1 = lined + wpld;
2920  linedp2 = lined + 2 * wpld;
2921  linedp3 = lined + 3 * wpld;
2922  s2 = GET_DATA_BYTE(lines, 0);
2923  s4 = GET_DATA_BYTE(linesp, 0);
2924  for (j = 0, jd = 0; j < wsm; j++, jd += 4) {
2925  s1 = s2;
2926  s3 = s4;
2927  s2 = GET_DATA_BYTE(lines, j + 1);
2928  s4 = GET_DATA_BYTE(linesp, j + 1);
2929  s1t = 3 * s1;
2930  s2t = 3 * s2;
2931  s3t = 3 * s3;
2932  s4t = 3 * s4;
2933  SET_DATA_BYTE(lined, jd, s1); /* d1 */
2934  SET_DATA_BYTE(lined, jd + 1, (s1t + s2) / 4); /* d2 */
2935  SET_DATA_BYTE(lined, jd + 2, (s1 + s2) / 2); /* d3 */
2936  SET_DATA_BYTE(lined, jd + 3, (s1 + s2t) / 4); /* d4 */
2937  SET_DATA_BYTE(linedp1, jd, (s1t + s3) / 4); /* d5 */
2938  SET_DATA_BYTE(linedp1, jd + 1, (9*s1 + s2t + s3t + s4) / 16); /*d6*/
2939  SET_DATA_BYTE(linedp1, jd + 2, (s1t + s2t + s3 + s4) / 8); /* d7 */
2940  SET_DATA_BYTE(linedp1, jd + 3, (s1t + 9*s2 + s3 + s4t) / 16);/*d8*/
2941  SET_DATA_BYTE(linedp2, jd, (s1 + s3) / 2); /* d9 */
2942  SET_DATA_BYTE(linedp2, jd + 1, (s1t + s2 + s3t + s4) / 8);/* d10 */
2943  SET_DATA_BYTE(linedp2, jd + 2, (s1 + s2 + s3 + s4) / 4); /* d11 */
2944  SET_DATA_BYTE(linedp2, jd + 3, (s1 + s2t + s3 + s4t) / 8);/* d12 */
2945  SET_DATA_BYTE(linedp3, jd, (s1 + s3t) / 4); /* d13 */
2946  SET_DATA_BYTE(linedp3, jd + 1, (s1t + s2 + 9*s3 + s4t) / 16);/*d14*/
2947  SET_DATA_BYTE(linedp3, jd + 2, (s1 + s2 + s3t + s4t) / 8); /* d15 */
2948  SET_DATA_BYTE(linedp3, jd + 3, (s1 + s2t + s3t + 9*s4) / 16);/*d16*/
2949  }
2950  s1 = s2;
2951  s3 = s4;
2952  s1t = 3 * s1;
2953  s3t = 3 * s3;
2954  SET_DATA_BYTE(lined, wsm4, s1); /* d1 */
2955  SET_DATA_BYTE(lined, wsm4 + 1, s1); /* d2 */
2956  SET_DATA_BYTE(lined, wsm4 + 2, s1); /* d3 */
2957  SET_DATA_BYTE(lined, wsm4 + 3, s1); /* d4 */
2958  SET_DATA_BYTE(linedp1, wsm4, (s1t + s3) / 4); /* d5 */
2959  SET_DATA_BYTE(linedp1, wsm4 + 1, (s1t + s3) / 4); /* d6 */
2960  SET_DATA_BYTE(linedp1, wsm4 + 2, (s1t + s3) / 4); /* d7 */
2961  SET_DATA_BYTE(linedp1, wsm4 + 3, (s1t + s3) / 4); /* d8 */
2962  SET_DATA_BYTE(linedp2, wsm4, (s1 + s3) / 2); /* d9 */
2963  SET_DATA_BYTE(linedp2, wsm4 + 1, (s1 + s3) / 2); /* d10 */
2964  SET_DATA_BYTE(linedp2, wsm4 + 2, (s1 + s3) / 2); /* d11 */
2965  SET_DATA_BYTE(linedp2, wsm4 + 3, (s1 + s3) / 2); /* d12 */
2966  SET_DATA_BYTE(linedp3, wsm4, (s1 + s3t) / 4); /* d13 */
2967  SET_DATA_BYTE(linedp3, wsm4 + 1, (s1 + s3t) / 4); /* d14 */
2968  SET_DATA_BYTE(linedp3, wsm4 + 2, (s1 + s3t) / 4); /* d15 */
2969  SET_DATA_BYTE(linedp3, wsm4 + 3, (s1 + s3t) / 4); /* d16 */
2970  } else { /* last row of src pixels: lastlineflag == 1 */
2971  linedp1 = lined + wpld;
2972  linedp2 = lined + 2 * wpld;
2973  linedp3 = lined + 3 * wpld;
2974  s2 = GET_DATA_BYTE(lines, 0);
2975  for (j = 0, jd = 0; j < wsm; j++, jd += 4) {
2976  s1 = s2;
2977  s2 = GET_DATA_BYTE(lines, j + 1);
2978  s1t = 3 * s1;
2979  s2t = 3 * s2;
2980  SET_DATA_BYTE(lined, jd, s1); /* d1 */
2981  SET_DATA_BYTE(lined, jd + 1, (s1t + s2) / 4 ); /* d2 */
2982  SET_DATA_BYTE(lined, jd + 2, (s1 + s2) / 2 ); /* d3 */
2983  SET_DATA_BYTE(lined, jd + 3, (s1 + s2t) / 4 ); /* d4 */
2984  SET_DATA_BYTE(linedp1, jd, s1); /* d5 */
2985  SET_DATA_BYTE(linedp1, jd + 1, (s1t + s2) / 4 ); /* d6 */
2986  SET_DATA_BYTE(linedp1, jd + 2, (s1 + s2) / 2 ); /* d7 */
2987  SET_DATA_BYTE(linedp1, jd + 3, (s1 + s2t) / 4 ); /* d8 */
2988  SET_DATA_BYTE(linedp2, jd, s1); /* d9 */
2989  SET_DATA_BYTE(linedp2, jd + 1, (s1t + s2) / 4 ); /* d10 */
2990  SET_DATA_BYTE(linedp2, jd + 2, (s1 + s2) / 2 ); /* d11 */
2991  SET_DATA_BYTE(linedp2, jd + 3, (s1 + s2t) / 4 ); /* d12 */
2992  SET_DATA_BYTE(linedp3, jd, s1); /* d13 */
2993  SET_DATA_BYTE(linedp3, jd + 1, (s1t + s2) / 4 ); /* d14 */
2994  SET_DATA_BYTE(linedp3, jd + 2, (s1 + s2) / 2 ); /* d15 */
2995  SET_DATA_BYTE(linedp3, jd + 3, (s1 + s2t) / 4 ); /* d16 */
2996  }
2997  s1 = s2;
2998  SET_DATA_BYTE(lined, wsm4, s1); /* d1 */
2999  SET_DATA_BYTE(lined, wsm4 + 1, s1); /* d2 */
3000  SET_DATA_BYTE(lined, wsm4 + 2, s1); /* d3 */
3001  SET_DATA_BYTE(lined, wsm4 + 3, s1); /* d4 */
3002  SET_DATA_BYTE(linedp1, wsm4, s1); /* d5 */
3003  SET_DATA_BYTE(linedp1, wsm4 + 1, s1); /* d6 */
3004  SET_DATA_BYTE(linedp1, wsm4 + 2, s1); /* d7 */
3005  SET_DATA_BYTE(linedp1, wsm4 + 3, s1); /* d8 */
3006  SET_DATA_BYTE(linedp2, wsm4, s1); /* d9 */
3007  SET_DATA_BYTE(linedp2, wsm4 + 1, s1); /* d10 */
3008  SET_DATA_BYTE(linedp2, wsm4 + 2, s1); /* d11 */
3009  SET_DATA_BYTE(linedp2, wsm4 + 3, s1); /* d12 */
3010  SET_DATA_BYTE(linedp3, wsm4, s1); /* d13 */
3011  SET_DATA_BYTE(linedp3, wsm4 + 1, s1); /* d14 */
3012  SET_DATA_BYTE(linedp3, wsm4 + 2, s1); /* d15 */
3013  SET_DATA_BYTE(linedp3, wsm4 + 3, s1); /* d16 */
3014  }
3015 }
3016 
3017 
3018 /*------------------------------------------------------------------*
3019  * Grayscale and color scaling by closest pixel sampling *
3020  *------------------------------------------------------------------*/
3034 static l_int32
3035 scaleBySamplingLow(l_uint32 *datad,
3036  l_int32 wd,
3037  l_int32 hd,
3038  l_int32 wpld,
3039  l_uint32 *datas,
3040  l_int32 ws,
3041  l_int32 hs,
3042  l_int32 d,
3043  l_int32 wpls)
3044 {
3045 l_int32 i, j;
3046 l_int32 xs, prevxs, sval;
3047 l_int32 *srow, *scol;
3048 l_uint32 csval;
3049 l_uint32 *lines, *prevlines, *lined, *prevlined;
3050 l_float32 wratio, hratio;
3051 
3052  PROCNAME("scaleBySamplingLow");
3053 
3054  if (d != 2 && d != 4 && d !=8 && d != 16 && d != 32)
3055  return ERROR_INT("pixel depth not supported", procName, 1);
3056 
3057  /* Clear dest */
3058  memset(datad, 0, 4LL * hd * wpld);
3059 
3060  /* the source row corresponding to dest row i ==> srow[i]
3061  * the source col corresponding to dest col j ==> scol[j] */
3062  if ((srow = (l_int32 *)LEPT_CALLOC(hd, sizeof(l_int32))) == NULL)
3063  return ERROR_INT("srow not made", procName, 1);
3064  if ((scol = (l_int32 *)LEPT_CALLOC(wd, sizeof(l_int32))) == NULL) {
3065  LEPT_FREE(srow);
3066  return ERROR_INT("scol not made", procName, 1);
3067  }
3068 
3069  wratio = (l_float32)ws / (l_float32)wd;
3070  hratio = (l_float32)hs / (l_float32)hd;
3071  for (i = 0; i < hd; i++)
3072  srow[i] = L_MIN((l_int32)(hratio * i + 0.5), hs - 1);
3073  for (j = 0; j < wd; j++)
3074  scol[j] = L_MIN((l_int32)(wratio * j + 0.5), ws - 1);
3075 
3076  prevlines = NULL;
3077  for (i = 0; i < hd; i++) {
3078  lines = datas + srow[i] * wpls;
3079  lined = datad + i * wpld;
3080  if (lines != prevlines) { /* make dest from new source row */
3081  prevxs = -1;
3082  sval = 0;
3083  csval = 0;
3084  if (d == 2) {
3085  for (j = 0; j < wd; j++) {
3086  xs = scol[j];
3087  if (xs != prevxs) { /* get dest pix from source col */
3088  sval = GET_DATA_DIBIT(lines, xs);
3089  SET_DATA_DIBIT(lined, j, sval);
3090  prevxs = xs;
3091  } else { /* copy prev dest pix */
3092  SET_DATA_DIBIT(lined, j, sval);
3093  }
3094  }
3095  } else if (d == 4) {
3096  for (j = 0; j < wd; j++) {
3097  xs = scol[j];
3098  if (xs != prevxs) { /* get dest pix from source col */
3099  sval = GET_DATA_QBIT(lines, xs);
3100  SET_DATA_QBIT(lined, j, sval);
3101  prevxs = xs;
3102  } else { /* copy prev dest pix */
3103  SET_DATA_QBIT(lined, j, sval);
3104  }
3105  }
3106  } else if (d == 8) {
3107  for (j = 0; j < wd; j++) {
3108  xs = scol[j];
3109  if (xs != prevxs) { /* get dest pix from source col */
3110  sval = GET_DATA_BYTE(lines, xs);
3111  SET_DATA_BYTE(lined, j, sval);
3112  prevxs = xs;
3113  } else { /* copy prev dest pix */
3114  SET_DATA_BYTE(lined, j, sval);
3115  }
3116  }
3117  } else if (d == 16) {
3118  for (j = 0; j < wd; j++) {
3119  xs = scol[j];
3120  if (xs != prevxs) { /* get dest pix from source col */
3121  sval = GET_DATA_TWO_BYTES(lines, xs);
3122  SET_DATA_TWO_BYTES(lined, j, sval);
3123  prevxs = xs;
3124  } else { /* copy prev dest pix */
3125  SET_DATA_TWO_BYTES(lined, j, sval);
3126  }
3127  }
3128  } else { /* d == 32 */
3129  for (j = 0; j < wd; j++) {
3130  xs = scol[j];
3131  if (xs != prevxs) { /* get dest pix from source col */
3132  csval = lines[xs];
3133  lined[j] = csval;
3134  prevxs = xs;
3135  } else { /* copy prev dest pix */
3136  lined[j] = csval;
3137  }
3138  }
3139  }
3140  } else { /* lines == prevlines; copy prev dest row */
3141  prevlined = lined - wpld;
3142  memcpy(lined, prevlined, 4 * wpld);
3143  }
3144  prevlines = lines;
3145  }
3146 
3147  LEPT_FREE(srow);
3148  LEPT_FREE(scol);
3149  return 0;
3150 }
3151 
3152 
3153 /*------------------------------------------------------------------*
3154  * Color and grayscale downsampling with (antialias) smoothing *
3155  *------------------------------------------------------------------*/
3165 static l_int32
3166 scaleSmoothLow(l_uint32 *datad,
3167  l_int32 wd,
3168  l_int32 hd,
3169  l_int32 wpld,
3170  l_uint32 *datas,
3171  l_int32 ws,
3172  l_int32 hs,
3173  l_int32 d,
3174  l_int32 wpls,
3175  l_int32 size)
3176 {
3177 l_int32 i, j, m, n, xstart;
3178 l_int32 val, rval, gval, bval;
3179 l_int32 *srow, *scol;
3180 l_uint32 *lines, *lined, *line, *ppixel;
3181 l_uint32 pixel;
3182 l_float32 wratio, hratio, norm;
3183 
3184  PROCNAME("scaleSmoothLow");
3185 
3186  /* Clear dest */
3187  memset(datad, 0, 4LL * wpld * hd);
3188 
3189  /* Each dest pixel at (j,i) is computed as the average
3190  of size^2 corresponding src pixels.
3191  We store the UL corner location of the square of
3192  src pixels that correspond to dest pixel (j,i).
3193  The are labeled by the arrays srow[i] and scol[j]. */
3194  if ((srow = (l_int32 *)LEPT_CALLOC(hd, sizeof(l_int32))) == NULL)
3195  return ERROR_INT("srow not made", procName, 1);
3196  if ((scol = (l_int32 *)LEPT_CALLOC(wd, sizeof(l_int32))) == NULL) {
3197  LEPT_FREE(srow);
3198  return ERROR_INT("scol not made", procName, 1);
3199  }
3200 
3201  norm = 1. / (l_float32)(size * size);
3202  wratio = (l_float32)ws / (l_float32)wd;
3203  hratio = (l_float32)hs / (l_float32)hd;
3204  for (i = 0; i < hd; i++)
3205  srow[i] = L_MIN((l_int32)(hratio * i), hs - size);
3206  for (j = 0; j < wd; j++)
3207  scol[j] = L_MIN((l_int32)(wratio * j), ws - size);
3208 
3209  /* For each dest pixel, compute average */
3210  if (d == 8) {
3211  for (i = 0; i < hd; i++) {
3212  lines = datas + srow[i] * wpls;
3213  lined = datad + i * wpld;
3214  for (j = 0; j < wd; j++) {
3215  xstart = scol[j];
3216  val = 0;
3217  for (m = 0; m < size; m++) {
3218  line = lines + m * wpls;
3219  for (n = 0; n < size; n++) {
3220  val += GET_DATA_BYTE(line, xstart + n);
3221  }
3222  }
3223  val = (l_int32)((l_float32)val * norm);
3224  SET_DATA_BYTE(lined, j, val);
3225  }
3226  }
3227  } else { /* d == 32 */
3228  for (i = 0; i < hd; i++) {
3229  lines = datas + srow[i] * wpls;
3230  lined = datad + i * wpld;
3231  for (j = 0; j < wd; j++) {
3232  xstart = scol[j];
3233  rval = gval = bval = 0;
3234  for (m = 0; m < size; m++) {
3235  ppixel = lines + m * wpls + xstart;
3236  for (n = 0; n < size; n++) {
3237  pixel = *(ppixel + n);
3238  rval += (pixel >> L_RED_SHIFT) & 0xff;
3239  gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3240  bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3241  }
3242  }
3243  rval = (l_int32)((l_float32)rval * norm);
3244  gval = (l_int32)((l_float32)gval * norm);
3245  bval = (l_int32)((l_float32)bval * norm);
3246  composeRGBPixel(rval, gval, bval, lined + j);
3247  }
3248  }
3249  }
3250 
3251  LEPT_FREE(srow);
3252  LEPT_FREE(scol);
3253  return 0;
3254 }
3255 
3256 
3264 static void
3265 scaleRGBToGray2Low(l_uint32 *datad,
3266  l_int32 wd,
3267  l_int32 hd,
3268  l_int32 wpld,
3269  l_uint32 *datas,
3270  l_int32 wpls,
3271  l_float32 rwt,
3272  l_float32 gwt,
3273  l_float32 bwt)
3274 {
3275 l_int32 i, j, val, rval, gval, bval;
3276 l_uint32 *lines, *lined;
3277 l_uint32 pixel;
3278 
3279  rwt *= 0.25;
3280  gwt *= 0.25;
3281  bwt *= 0.25;
3282  for (i = 0; i < hd; i++) {
3283  lines = datas + 2 * i * wpls;
3284  lined = datad + i * wpld;
3285  for (j = 0; j < wd; j++) {
3286  /* Sum each of the color components from 4 src pixels */
3287  pixel = *(lines + 2 * j);
3288  rval = (pixel >> L_RED_SHIFT) & 0xff;
3289  gval = (pixel >> L_GREEN_SHIFT) & 0xff;
3290  bval = (pixel >> L_BLUE_SHIFT) & 0xff;
3291  pixel = *(lines + 2 * j + 1);
3292  rval += (pixel >> L_RED_SHIFT) & 0xff;
3293  gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3294  bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3295  pixel = *(lines + wpls + 2 * j);
3296  rval += (pixel >> L_RED_SHIFT) & 0xff;
3297  gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3298  bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3299  pixel = *(lines + wpls + 2 * j + 1);
3300  rval += (pixel >> L_RED_SHIFT) & 0xff;
3301  gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3302  bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3303  /* Generate the dest byte as a weighted sum of the averages */
3304  val = (l_int32)(rwt * rval + gwt * gval + bwt * bval);
3305  SET_DATA_BYTE(lined, j, val);
3306  }
3307  }
3308 }
3309 
3310 
3311 /*------------------------------------------------------------------*
3312  * General area mapped gray scaling *
3313  *------------------------------------------------------------------*/
3326 static void
3327 scaleColorAreaMapLow(l_uint32 *datad,
3328  l_int32 wd,
3329  l_int32 hd,
3330  l_int32 wpld,
3331  l_uint32 *datas,
3332  l_int32 ws,
3333  l_int32 hs,
3334  l_int32 wpls)
3335 {
3336 l_int32 i, j, k, m, wm2, hm2;
3337 l_int32 area00, area10, area01, area11, areal, arear, areat, areab;
3338 l_int32 xu, yu; /* UL corner in src image, to 1/16 of a pixel */
3339 l_int32 xl, yl; /* LR corner in src image, to 1/16 of a pixel */
3340 l_int32 xup, yup, xuf, yuf; /* UL src pixel: integer and fraction */
3341 l_int32 xlp, ylp, xlf, ylf; /* LR src pixel: integer and fraction */
3342 l_int32 delx, dely, area;
3343 l_int32 v00r, v00g, v00b; /* contrib. from UL src pixel */
3344 l_int32 v01r, v01g, v01b; /* contrib. from LL src pixel */
3345 l_int32 v10r, v10g, v10b; /* contrib from UR src pixel */
3346 l_int32 v11r, v11g, v11b; /* contrib from LR src pixel */
3347 l_int32 vinr, ving, vinb; /* contrib from all full interior src pixels */
3348 l_int32 vmidr, vmidg, vmidb; /* contrib from side parts */
3349 l_int32 rval, gval, bval;
3350 l_uint32 pixel00, pixel10, pixel01, pixel11, pixel;
3351 l_uint32 *lines, *lined;
3352 l_float32 scx, scy;
3353 
3354  /* (scx, scy) are scaling factors that are applied to the
3355  * dest coords to get the corresponding src coords.
3356  * We need them because we iterate over dest pixels
3357  * and must find the corresponding set of src pixels. */
3358  scx = 16. * (l_float32)ws / (l_float32)wd;
3359  scy = 16. * (l_float32)hs / (l_float32)hd;
3360  wm2 = ws - 2;
3361  hm2 = hs - 2;
3362 
3363  /* Iterate over the destination pixels */
3364  for (i = 0; i < hd; i++) {
3365  yu = (l_int32)(scy * i);
3366  yl = (l_int32)(scy * (i + 1.0));
3367  yup = yu >> 4;
3368  yuf = yu & 0x0f;
3369  ylp = yl >> 4;
3370  ylf = yl & 0x0f;
3371  dely = ylp - yup;
3372  lined = datad + i * wpld;
3373  lines = datas + yup * wpls;
3374  for (j = 0; j < wd; j++) {
3375  xu = (l_int32)(scx * j);
3376  xl = (l_int32)(scx * (j + 1.0));
3377  xup = xu >> 4;
3378  xuf = xu & 0x0f;
3379  xlp = xl >> 4;
3380  xlf = xl & 0x0f;
3381  delx = xlp - xup;
3382 
3383  /* If near the edge, just use a src pixel value */
3384  if (xlp > wm2 || ylp > hm2) {
3385  *(lined + j) = *(lines + xup);
3386  continue;
3387  }
3388 
3389  /* Area summed over, in subpixels. This varies
3390  * due to the quantization, so we can't simply take
3391  * the area to be a constant: area = scx * scy. */
3392  area = ((16 - xuf) + 16 * (delx - 1) + xlf) *
3393  ((16 - yuf) + 16 * (dely - 1) + ylf);
3394 
3395  /* Do area map summation */
3396  pixel00 = *(lines + xup);
3397  pixel10 = *(lines + xlp);
3398  pixel01 = *(lines + dely * wpls + xup);
3399  pixel11 = *(lines + dely * wpls + xlp);
3400  area00 = (16 - xuf) * (16 - yuf);
3401  area10 = xlf * (16 - yuf);
3402  area01 = (16 - xuf) * ylf;
3403  area11 = xlf * ylf;
3404  v00r = area00 * ((pixel00 >> L_RED_SHIFT) & 0xff);
3405  v00g = area00 * ((pixel00 >> L_GREEN_SHIFT) & 0xff);
3406  v00b = area00 * ((pixel00 >> L_BLUE_SHIFT) & 0xff);
3407  v10r = area10 * ((pixel10 >> L_RED_SHIFT) & 0xff);
3408  v10g = area10 * ((pixel10 >> L_GREEN_SHIFT) & 0xff);
3409  v10b = area10 * ((pixel10 >> L_BLUE_SHIFT) & 0xff);
3410  v01r = area01 * ((pixel01 >> L_RED_SHIFT) & 0xff);
3411  v01g = area01 * ((pixel01 >> L_GREEN_SHIFT) & 0xff);
3412  v01b = area01 * ((pixel01 >> L_BLUE_SHIFT) & 0xff);
3413  v11r = area11 * ((pixel11 >> L_RED_SHIFT) & 0xff);
3414  v11g = area11 * ((pixel11 >> L_GREEN_SHIFT) & 0xff);
3415  v11b = area11 * ((pixel11 >> L_BLUE_SHIFT) & 0xff);
3416  vinr = ving = vinb = 0;
3417  for (k = 1; k < dely; k++) { /* for full src pixels */
3418  for (m = 1; m < delx; m++) {
3419  pixel = *(lines + k * wpls + xup + m);
3420  vinr += 256 * ((pixel >> L_RED_SHIFT) & 0xff);
3421  ving += 256 * ((pixel >> L_GREEN_SHIFT) & 0xff);
3422  vinb += 256 * ((pixel >> L_BLUE_SHIFT) & 0xff);
3423  }
3424  }
3425  vmidr = vmidg = vmidb = 0;
3426  areal = (16 - xuf) * 16;
3427  arear = xlf * 16;
3428  areat = 16 * (16 - yuf);
3429  areab = 16 * ylf;
3430  for (k = 1; k < dely; k++) { /* for left side */
3431  pixel = *(lines + k * wpls + xup);
3432  vmidr += areal * ((pixel >> L_RED_SHIFT) & 0xff);
3433  vmidg += areal * ((pixel >> L_GREEN_SHIFT) & 0xff);
3434  vmidb += areal * ((pixel >> L_BLUE_SHIFT) & 0xff);
3435  }
3436  for (k = 1; k < dely; k++) { /* for right side */
3437  pixel = *(lines + k * wpls + xlp);
3438  vmidr += arear * ((pixel >> L_RED_SHIFT) & 0xff);
3439  vmidg += arear * ((pixel >> L_GREEN_SHIFT) & 0xff);
3440  vmidb += arear * ((pixel >> L_BLUE_SHIFT) & 0xff);
3441  }
3442  for (m = 1; m < delx; m++) { /* for top side */
3443  pixel = *(lines + xup + m);
3444  vmidr += areat * ((pixel >> L_RED_SHIFT) & 0xff);
3445  vmidg += areat * ((pixel >> L_GREEN_SHIFT) & 0xff);
3446  vmidb += areat * ((pixel >> L_BLUE_SHIFT) & 0xff);
3447  }
3448  for (m = 1; m < delx; m++) { /* for bottom side */
3449  pixel = *(lines + dely * wpls + xup + m);
3450  vmidr += areab * ((pixel >> L_RED_SHIFT) & 0xff);
3451  vmidg += areab * ((pixel >> L_GREEN_SHIFT) & 0xff);
3452  vmidb += areab * ((pixel >> L_BLUE_SHIFT) & 0xff);
3453  }
3454 
3455  /* Sum all the contributions */
3456  rval = (v00r + v01r + v10r + v11r + vinr + vmidr + 128) / area;
3457  gval = (v00g + v01g + v10g + v11g + ving + vmidg + 128) / area;
3458  bval = (v00b + v01b + v10b + v11b + vinb + vmidb + 128) / area;
3459 #if DEBUG_OVERFLOW
3460  if (rval > 255) fprintf(stderr, "rval ovfl: %d\n", rval);
3461  if (gval > 255) fprintf(stderr, "gval ovfl: %d\n", gval);
3462  if (bval > 255) fprintf(stderr, "bval ovfl: %d\n", bval);
3463 #endif /* DEBUG_OVERFLOW */
3464  composeRGBPixel(rval, gval, bval, lined + j);
3465  }
3466  }
3467 }
3468 
3469 
3481 static void
3482 scaleGrayAreaMapLow(l_uint32 *datad,
3483  l_int32 wd,
3484  l_int32 hd,
3485  l_int32 wpld,
3486  l_uint32 *datas,
3487  l_int32 ws,
3488  l_int32 hs,
3489  l_int32 wpls)
3490 {
3491 l_int32 i, j, k, m, wm2, hm2;
3492 l_int32 xu, yu; /* UL corner in src image, to 1/16 of a pixel */
3493 l_int32 xl, yl; /* LR corner in src image, to 1/16 of a pixel */
3494 l_int32 xup, yup, xuf, yuf; /* UL src pixel: integer and fraction */
3495 l_int32 xlp, ylp, xlf, ylf; /* LR src pixel: integer and fraction */
3496 l_int32 delx, dely, area;
3497 l_int32 v00; /* contrib. from UL src pixel */
3498 l_int32 v01; /* contrib. from LL src pixel */
3499 l_int32 v10; /* contrib from UR src pixel */
3500 l_int32 v11; /* contrib from LR src pixel */
3501 l_int32 vin; /* contrib from all full interior src pixels */
3502 l_int32 vmid; /* contrib from side parts that are full in 1 direction */
3503 l_int32 val;
3504 l_uint32 *lines, *lined;
3505 l_float32 scx, scy;
3506 
3507  /* (scx, scy) are scaling factors that are applied to the
3508  * dest coords to get the corresponding src coords.
3509  * We need them because we iterate over dest pixels
3510  * and must find the corresponding set of src pixels. */
3511  scx = 16. * (l_float32)ws / (l_float32)wd;
3512  scy = 16. * (l_float32)hs / (l_float32)hd;
3513  wm2 = ws - 2;
3514  hm2 = hs - 2;
3515 
3516  /* Iterate over the destination pixels */
3517  for (i = 0; i < hd; i++) {
3518  yu = (l_int32)(scy * i);
3519  yl = (l_int32)(scy * (i + 1.0));
3520  yup = yu >> 4;
3521  yuf = yu & 0x0f;
3522  ylp = yl >> 4;
3523  ylf = yl & 0x0f;
3524  dely = ylp - yup;
3525  lined = datad + i * wpld;
3526  lines = datas + yup * wpls;
3527  for (j = 0; j < wd; j++) {
3528  xu = (l_int32)(scx * j);
3529  xl = (l_int32)(scx * (j + 1.0));
3530  xup = xu >> 4;
3531  xuf = xu & 0x0f;
3532  xlp = xl >> 4;
3533  xlf = xl & 0x0f;
3534  delx = xlp - xup;
3535 
3536  /* If near the edge, just use a src pixel value */
3537  if (xlp > wm2 || ylp > hm2) {
3538  SET_DATA_BYTE(lined, j, GET_DATA_BYTE(lines, xup));
3539  continue;
3540  }
3541 
3542  /* Area summed over, in subpixels. This varies
3543  * due to the quantization, so we can't simply take
3544  * the area to be a constant: area = scx * scy. */
3545  area = ((16 - xuf) + 16 * (delx - 1) + xlf) *
3546  ((16 - yuf) + 16 * (dely - 1) + ylf);
3547 
3548  /* Do area map summation */
3549  v00 = (16 - xuf) * (16 - yuf) * GET_DATA_BYTE(lines, xup);
3550  v10 = xlf * (16 - yuf) * GET_DATA_BYTE(lines, xlp);
3551  v01 = (16 - xuf) * ylf * GET_DATA_BYTE(lines + dely * wpls, xup);
3552  v11 = xlf * ylf * GET_DATA_BYTE(lines + dely * wpls, xlp);
3553  for (vin = 0, k = 1; k < dely; k++) { /* for full src pixels */
3554  for (m = 1; m < delx; m++) {
3555  vin += 256 * GET_DATA_BYTE(lines + k * wpls, xup + m);
3556  }
3557  }
3558  for (vmid = 0, k = 1; k < dely; k++) /* for left side */
3559  vmid += (16 - xuf) * 16 * GET_DATA_BYTE(lines + k * wpls, xup);
3560  for (k = 1; k < dely; k++) /* for right side */
3561  vmid += xlf * 16 * GET_DATA_BYTE(lines + k * wpls, xlp);
3562  for (m = 1; m < delx; m++) /* for top side */
3563  vmid += 16 * (16 - yuf) * GET_DATA_BYTE(lines, xup + m);
3564  for (m = 1; m < delx; m++) /* for bottom side */
3565  vmid += 16 * ylf * GET_DATA_BYTE(lines + dely * wpls, xup + m);
3566  val = (v00 + v01 + v10 + v11 + vin + vmid + 128) / area;
3567 #if DEBUG_OVERFLOW
3568  if (val > 255) fprintf(stderr, "val overflow: %d\n", val);
3569 #endif /* DEBUG_OVERFLOW */
3570  SET_DATA_BYTE(lined, j, val);
3571  }
3572  }
3573 }
3574 
3575 
3576 /*------------------------------------------------------------------*
3577  * 2x area mapped downscaling *
3578  *------------------------------------------------------------------*/
3586 static void
3587 scaleAreaMapLow2(l_uint32 *datad,
3588  l_int32 wd,
3589  l_int32 hd,
3590  l_int32 wpld,
3591  l_uint32 *datas,
3592  l_int32 d,
3593  l_int32 wpls)
3594 {
3595 l_int32 i, j, val, rval, gval, bval;
3596 l_uint32 *lines, *lined;
3597 l_uint32 pixel;
3598 
3599  if (d == 8) {
3600  for (i = 0; i < hd; i++) {
3601  lines = datas + 2 * i * wpls;
3602  lined = datad + i * wpld;
3603  for (j = 0; j < wd; j++) {
3604  /* Average each dest pixel using 4 src pixels */
3605  val = GET_DATA_BYTE(lines, 2 * j);
3606  val += GET_DATA_BYTE(lines, 2 * j + 1);
3607  val += GET_DATA_BYTE(lines + wpls, 2 * j);
3608  val += GET_DATA_BYTE(lines + wpls, 2 * j + 1);
3609  val >>= 2;
3610  SET_DATA_BYTE(lined, j, val);
3611  }
3612  }
3613  } else { /* d == 32 */
3614  for (i = 0; i < hd; i++) {
3615  lines = datas + 2 * i * wpls;
3616  lined = datad + i * wpld;
3617  for (j = 0; j < wd; j++) {
3618  /* Average each of the color components from 4 src pixels */
3619  pixel = *(lines + 2 * j);
3620  rval = (pixel >> L_RED_SHIFT) & 0xff;
3621  gval = (pixel >> L_GREEN_SHIFT) & 0xff;
3622  bval = (pixel >> L_BLUE_SHIFT) & 0xff;
3623  pixel = *(lines + 2 * j + 1);
3624  rval += (pixel >> L_RED_SHIFT) & 0xff;
3625  gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3626  bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3627  pixel = *(lines + wpls + 2 * j);
3628  rval += (pixel >> L_RED_SHIFT) & 0xff;
3629  gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3630  bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3631  pixel = *(lines + wpls + 2 * j + 1);
3632  rval += (pixel >> L_RED_SHIFT) & 0xff;
3633  gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3634  bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3635  composeRGBPixel(rval >> 2, gval >> 2, bval >> 2, &pixel);
3636  *(lined + j) = pixel;
3637  }
3638  }
3639  }
3640 }
3641 
3642 
3643 /*------------------------------------------------------------------*
3644  * Binary scaling by closest pixel sampling *
3645  *------------------------------------------------------------------*/
3646 /*
3647  * scaleBinaryLow()
3648  *
3649  * Notes:
3650  * (1) The dest must be cleared prior to this operation,
3651  * and we clear it here in the low-level code.
3652  * (2) We reuse dest pixels and dest pixel rows whenever
3653  * possible for upscaling; downscaling is done by
3654  * strict subsampling.
3655  */
3656 static l_int32
3657 scaleBinaryLow(l_uint32 *datad,
3658  l_int32 wd,
3659  l_int32 hd,
3660  l_int32 wpld,
3661  l_uint32 *datas,
3662  l_int32 ws,
3663  l_int32 hs,
3664  l_int32 wpls)
3665 {
3666 l_int32 i, j;
3667 l_int32 xs, prevxs, sval;
3668 l_int32 *srow, *scol;
3669 l_uint32 *lines, *prevlines, *lined, *prevlined;
3670 l_float32 wratio, hratio;
3671 
3672  PROCNAME("scaleBinaryLow");
3673 
3674  /* Clear dest */
3675  memset(datad, 0, 4LL * hd * wpld);
3676 
3677  /* The source row corresponding to dest row i ==> srow[i]
3678  * The source col corresponding to dest col j ==> scol[j] */
3679  if ((srow = (l_int32 *)LEPT_CALLOC(hd, sizeof(l_int32))) == NULL)
3680  return ERROR_INT("srow not made", procName, 1);
3681  if ((scol = (l_int32 *)LEPT_CALLOC(wd, sizeof(l_int32))) == NULL) {
3682  LEPT_FREE(srow);
3683  return ERROR_INT("scol not made", procName, 1);
3684  }
3685 
3686  wratio = (l_float32)ws / (l_float32)wd;
3687  hratio = (l_float32)hs / (l_float32)hd;
3688  for (i = 0; i < hd; i++)
3689  srow[i] = L_MIN((l_int32)(hratio * i + 0.5), hs - 1);
3690  for (j = 0; j < wd; j++)
3691  scol[j] = L_MIN((l_int32)(wratio * j + 0.5), ws - 1);
3692 
3693  prevlines = NULL;
3694  prevxs = -1;
3695  sval = 0;
3696  for (i = 0; i < hd; i++) {
3697  lines = datas + srow[i] * wpls;
3698  lined = datad + i * wpld;
3699  if (lines != prevlines) { /* make dest from new source row */
3700  for (j = 0; j < wd; j++) {
3701  xs = scol[j];
3702  if (xs != prevxs) { /* get dest pix from source col */
3703  if ((sval = GET_DATA_BIT(lines, xs)))
3704  SET_DATA_BIT(lined, j);
3705  prevxs = xs;
3706  } else { /* copy prev dest pix, if set */
3707  if (sval)
3708  SET_DATA_BIT(lined, j);
3709  }
3710  }
3711  } else { /* lines == prevlines; copy prev dest row */
3712  prevlined = lined - wpld;
3713  memcpy(lined, prevlined, 4 * wpld);
3714  }
3715  prevlines = lines;
3716  }
3717 
3718  LEPT_FREE(srow);
3719  LEPT_FREE(scol);
3720  return 0;
3721 }
3722 
PIX * pixScaleRGBToGray2(PIX *pixs, l_float32 rwt, l_float32 gwt, l_float32 bwt)
pixScaleRGBToGray2()
Definition: scale1.c:1845
PIX * pixScaleColor2xLI(PIX *pixs)
pixScaleColor2xLI()
Definition: scale1.c:625
PIX * pixRemoveColormap(PIX *pixs, l_int32 type)
pixRemoveColormap()
Definition: pixconv.c:322
PIX * pixScaleColor4xLI(PIX *pixs)
pixScaleColor4xLI()
Definition: scale1.c:674
PIX * pixScaleToSizeRel(PIX *pixs, l_int32 delw, l_int32 delh)
pixScaleToSizeRel()
Definition: scale1.c:274
PIX * pixScaleGray2xLIDither(PIX *pixs)
pixScaleGray2xLIDither()
Definition: scale1.c:1008
PIX * pixScaleRGBToGrayFast(PIX *pixs, l_int32 factor, l_int32 color)
pixScaleRGBToGrayFast()
Definition: scale1.c:1487
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:3265
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:2304
PIX * pixScaleGray4xLIThresh(PIX *pixs, l_int32 thresh)
pixScaleGray4xLIThresh()
Definition: scale1.c:1127
PIX * pixScaleGrayToBinaryFast(PIX *pixs, l_int32 factor, l_int32 thresh)
pixScaleGrayToBinaryFast()
Definition: scale1.c:1628
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3041
PIX * pixScaleToResolution(PIX *pixs, l_float32 target, l_float32 assumed, l_float32 *pscalefact)
pixScaleToResolution()
Definition: scale1.c:357
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:302
PIX * pixScaleGeneral(PIX *pixs, l_float32 scalex, l_float32 scaley, l_float32 sharpfract, l_int32 sharpwidth)
pixScaleGeneral()
Definition: scale1.c:414
PIX * pixScaleGray2xLIThresh(PIX *pixs, l_int32 thresh)
pixScaleGray2xLIThresh()
Definition: scale1.c:929
PIX * pixScaleAreaMap(PIX *pix, l_float32 scalex, l_float32 scaley)
pixScaleAreaMap()
Definition: scale1.c:1912
PIX * pixScaleColorLI(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleColorLI()
Definition: scale1.c:559
#define SET_DATA_QBIT(pdata, n, val)
Definition: arrayaccess.h:168
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1624
PIX * pixScaleBySampling(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleBySampling()
Definition: scale1.c:1338
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:2202
#define GET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:123
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:3166
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:3035
PIX * pixGetRGBComponent(PIX *pixs, l_int32 comp)
pixGetRGBComponent()
Definition: pix2.c:2404
#define SET_DATA_DIBIT(pdata, n, val)
Definition: arrayaccess.h:149
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:2468
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:2420
PIX * pixScaleBinary(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleBinary()
Definition: scale1.c:2145
#define SET_DATA_BYTE(pdata, n, val)
Definition: arrayaccess.h:198
#define GET_DATA_QBIT(pdata, n)
Definition: arrayaccess.h:164
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:2857
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:188
void ditherToBinaryLineLow(l_uint32 *lined, l_int32 w, l_uint32 *bufs1, l_uint32 *bufs2, l_int32 lowerclip, l_int32 upperclip, l_int32 lastlineflag)
ditherToBinaryLineLow()
Definition: grayquant.c:322
PIX * pixCreateRGBImage(PIX *pixr, PIX *pixg, PIX *pixb)
pixCreateRGBImage()
Definition: pix2.c:2348
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:2903
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:515
PIX * pixScaleToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleToSize()
Definition: scale1.c:317
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:543
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:3482
l_ok pixCopyColormap(PIX *pixd, PIX *pixs)
pixCopyColormap()
Definition: pix1.c:745
PIX * pixScaleLI(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleLI()
Definition: scale1.c:498
PIX * pixScaleAreaMapToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleAreaMapToSize()
Definition: scale1.c:2097
PIX * pixScaleByIntSampling(PIX *pixs, l_int32 factor)
pixScaleByIntSampling()
Definition: scale1.c:1445
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:3327
PIX * pixScaleAreaMap2(PIX *pix)
pixScaleAreaMap2()
Definition: scale1.c:2032
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1065
PIX * pixScaleGrayLI(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleGrayLI()
Definition: scale1.c:778
PIX * pixScaleGray2xLI(PIX *pixs)
pixScaleGray2xLI()
Definition: scale1.c:841
#define GET_DATA_TWO_BYTES(pdata, n)
Definition: arrayaccess.h:212
#define GET_DATA_DIBIT(pdata, n)
Definition: arrayaccess.h:145
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:2619
PIX * pixScaleSmoothToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleSmoothToSize()
Definition: scale1.c:1807
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:3587
PIX * pixScaleBySamplingToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleBySamplingToSize()
Definition: scale1.c:1400
PIX * pixUnsharpMasking(PIX *pixs, l_int32 halfwidth, l_float32 fract)
pixUnsharpMasking()
Definition: enhance.c:903
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:2667
Definition: pix.h:134
Definition: pix.h:719
PIX * pixCopy(PIX *pixd, PIX *pixs)
pixCopy()
Definition: pix1.c:628
Definition: pix.h:201
PIX * pixScaleRGBToBinaryFast(PIX *pixs, l_int32 factor, l_int32 thresh)
pixScaleRGBToBinaryFast()
Definition: scale1.c:1562
PIX * pixScaleGray4xLIDither(PIX *pixs)
pixScaleGray4xLIDither()
Definition: scale1.c:1215
l_ok composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2671
l_ok pixCopySpp(PIX *pixd, const PIX *pixs)
pixCopySpp()
Definition: pix1.c:1188
PIX * pixScaleSmooth(PIX *pix, l_float32 scalex, l_float32 scaley)
pixScaleSmooth()
Definition: scale1.c:1711
l_ok pixScaleAndTransferAlpha(PIX *pixd, PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleAndTransferAlpha()
Definition: scale2.c:1358
PIX * pixScale(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScale()
Definition: scale1.c:244
#define SET_DATA_TWO_BYTES(pdata, n, val)
Definition: arrayaccess.h:222
PIX * pixConvertTo8Or32(PIX *pixs, l_int32 copyflag, l_int32 warnflag)
pixConvertTo8Or32()
Definition: pixconv.c:3393
#define SET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:127
PIX * pixScaleGray4xLI(PIX *pixs)
pixScaleGray4xLI()
Definition: scale1.c:884