Leptonica  1.73
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 
113 #include <string.h>
114 #include "allheaders.h"
115 
116 static void scaleColorLILow(l_uint32 *datad, l_int32 wd, l_int32 hd,
117  l_int32 wpld, l_uint32 *datas, l_int32 ws,
118  l_int32 hs, l_int32 wpls);
119 static void scaleGrayLILow(l_uint32 *datad, l_int32 wd, l_int32 hd,
120  l_int32 wpld, l_uint32 *datas, l_int32 ws,
121  l_int32 hs, l_int32 wpls);
122 static void scaleColor2xLILow(l_uint32 *datad, l_int32 wpld, l_uint32 *datas,
123  l_int32 ws, l_int32 hs, l_int32 wpls);
124 static void scaleColor2xLILineLow(l_uint32 *lined, l_int32 wpld,
125  l_uint32 *lines, l_int32 ws, l_int32 wpls,
126  l_int32 lastlineflag);
127 static void scaleGray2xLILow(l_uint32 *datad, l_int32 wpld, l_uint32 *datas,
128  l_int32 ws, l_int32 hs, l_int32 wpls);
129 static void scaleGray2xLILineLow(l_uint32 *lined, l_int32 wpld,
130  l_uint32 *lines, l_int32 ws, l_int32 wpls,
131  l_int32 lastlineflag);
132 static void scaleGray4xLILow(l_uint32 *datad, l_int32 wpld, l_uint32 *datas,
133  l_int32 ws, l_int32 hs, l_int32 wpls);
134 static void scaleGray4xLILineLow(l_uint32 *lined, l_int32 wpld,
135  l_uint32 *lines, l_int32 ws, l_int32 wpls,
136  l_int32 lastlineflag);
137 static l_int32 scaleBySamplingLow(l_uint32 *datad, l_int32 wd, l_int32 hd,
138  l_int32 wpld, l_uint32 *datas, l_int32 ws,
139  l_int32 hs, l_int32 d, l_int32 wpls);
140 static l_int32 scaleSmoothLow(l_uint32 *datad, l_int32 wd, l_int32 hd,
141  l_int32 wpld, l_uint32 *datas, l_int32 ws,
142  l_int32 hs, l_int32 d, l_int32 wpls,
143  l_int32 size);
144 static void scaleRGBToGray2Low(l_uint32 *datad, l_int32 wd, l_int32 hd,
145  l_int32 wpld, l_uint32 *datas, l_int32 wpls,
146  l_float32 rwt, l_float32 gwt, l_float32 bwt);
147 static void scaleColorAreaMapLow(l_uint32 *datad, l_int32 wd, l_int32 hd,
148  l_int32 wpld, l_uint32 *datas, l_int32 ws,
149  l_int32 hs, l_int32 wpls);
150 static void scaleGrayAreaMapLow(l_uint32 *datad, l_int32 wd, l_int32 hd,
151  l_int32 wpld, l_uint32 *datas, l_int32 ws,
152  l_int32 hs, l_int32 wpls);
153 static void scaleAreaMapLow2(l_uint32 *datad, l_int32 wd, l_int32 hd,
154  l_int32 wpld, l_uint32 *datas, l_int32 d,
155  l_int32 wpls);
156 static l_int32 scaleBinaryLow(l_uint32 *datad, l_int32 wd, l_int32 hd,
157  l_int32 wpld, l_uint32 *datas, l_int32 ws,
158  l_int32 hs, l_int32 wpls);
159 
160 #ifndef NO_CONSOLE_IO
161 #define DEBUG_OVERFLOW 0
162 #define DEBUG_UNROLLING 0
163 #endif /* ~NO_CONSOLE_IO */
164 
165 
166 /*------------------------------------------------------------------*
167  * Top level scaling dispatcher *
168  *------------------------------------------------------------------*/
242 PIX *
243 pixScale(PIX *pixs,
244  l_float32 scalex,
245  l_float32 scaley)
246 {
247 l_int32 sharpwidth;
248 l_float32 maxscale, sharpfract;
249 
250  PROCNAME("pixScale");
251 
252  if (!pixs)
253  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
254 
255  /* Reduce the default sharpening factors by 2 if maxscale < 0.7 */
256  maxscale = L_MAX(scalex, scaley);
257  sharpfract = (maxscale < 0.7) ? 0.2 : 0.4;
258  sharpwidth = (maxscale < 0.7) ? 1 : 2;
259 
260  return pixScaleGeneral(pixs, scalex, scaley, sharpfract, sharpwidth);
261 }
262 
263 
272 PIX *
274  l_int32 delw,
275  l_int32 delh)
276 {
277 l_int32 w, h, wd, hd;
278 
279  PROCNAME("pixScaleToSizeRel");
280 
281  if (!pixs)
282  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
283 
284  if (delw == 0 && delh == 0)
285  return pixCopy(NULL, pixs);
286 
287  pixGetDimensions(pixs, &w, &h, NULL);
288  wd = w + delw;
289  hd = h + delh;
290  if (wd <= 0 || hd <= 0)
291  return (PIX *)ERROR_PTR("pix dimension reduced to 0", procName, NULL);
292 
293  return pixScaleToSize(pixs, wd, hd);
294 }
295 
296 
315 PIX *
317  l_int32 wd,
318  l_int32 hd)
319 {
320 l_int32 w, h;
321 l_float32 scalex, scaley;
322 
323  PROCNAME("pixScaleToSize");
324 
325  if (!pixs)
326  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
327  if (wd <= 0 && hd <= 0)
328  return (PIX *)ERROR_PTR("neither wd nor hd > 0", procName, NULL);
329 
330  pixGetDimensions(pixs, &w, &h, NULL);
331  if (wd <= 0) {
332  scaley = (l_float32)hd / (l_float32)h;
333  scalex = scaley;
334  } else if (hd <= 0) {
335  scalex = (l_float32)wd / (l_float32)w;
336  scaley = scalex;
337  } else {
338  scalex = (l_float32)wd / (l_float32)w;
339  scaley = (l_float32)hd / (l_float32)h;
340  }
341 
342  return pixScale(pixs, scalex, scaley);
343 }
344 
345 
373 PIX *
375  l_float32 scalex,
376  l_float32 scaley,
377  l_float32 sharpfract,
378  l_int32 sharpwidth)
379 {
380 l_int32 d;
381 l_float32 maxscale;
382 PIX *pixt, *pixt2, *pixd;
383 
384  PROCNAME("pixScaleGeneral");
385 
386  if (!pixs)
387  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
388  d = pixGetDepth(pixs);
389  if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
390  return (PIX *)ERROR_PTR("pixs not {1,2,4,8,16,32} bpp", procName, NULL);
391  if (scalex <= 0.0 || scaley <= 0.0)
392  return (PIX *)ERROR_PTR("scale factor <= 0", procName, NULL);
393  if (scalex == 1.0 && scaley == 1.0)
394  return pixCopy(NULL, pixs);
395 
396  if (d == 1)
397  return pixScaleBinary(pixs, scalex, scaley);
398 
399  /* Remove colormap; clone if possible; result is either 8 or 32 bpp */
400  if ((pixt = pixConvertTo8Or32(pixs, L_CLONE, 0)) == NULL)
401  return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
402 
403  /* Scale (up or down) */
404  d = pixGetDepth(pixt);
405  maxscale = L_MAX(scalex, scaley);
406  if (maxscale < 0.7) { /* area mapping for anti-aliasing */
407  pixt2 = pixScaleAreaMap(pixt, scalex, scaley);
408  if (maxscale > 0.2 && sharpfract > 0.0 && sharpwidth > 0)
409  pixd = pixUnsharpMasking(pixt2, sharpwidth, sharpfract);
410  else
411  pixd = pixClone(pixt2);
412  } else { /* use linear interpolation */
413  if (d == 8)
414  pixt2 = pixScaleGrayLI(pixt, scalex, scaley);
415  else /* d == 32 */
416  pixt2 = pixScaleColorLI(pixt, scalex, scaley);
417  if (maxscale < 1.4 && sharpfract > 0.0 && sharpwidth > 0)
418  pixd = pixUnsharpMasking(pixt2, sharpwidth, sharpfract);
419  else
420  pixd = pixClone(pixt2);
421  }
422 
423  pixDestroy(&pixt);
424  pixDestroy(&pixt2);
425  pixCopyText(pixd, pixs);
426  pixCopyInputFormat(pixd, pixs);
427  return pixd;
428 }
429 
430 
431 /*------------------------------------------------------------------*
432  * Scaling by linear interpolation *
433  *------------------------------------------------------------------*/
457 PIX *
459  l_float32 scalex,
460  l_float32 scaley)
461 {
462 l_int32 d;
463 l_float32 maxscale;
464 PIX *pixt, *pixd;
465 
466  PROCNAME("pixScaleLI");
467 
468  if (!pixs || (pixGetDepth(pixs) == 1))
469  return (PIX *)ERROR_PTR("pixs not defined or 1 bpp", procName, NULL);
470  maxscale = L_MAX(scalex, scaley);
471  if (maxscale < 0.7) {
472  L_WARNING("scaling factors < 0.7; do regular scaling\n", procName);
473  return pixScaleGeneral(pixs, scalex, scaley, 0.0, 0);
474  }
475  d = pixGetDepth(pixs);
476  if (d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
477  return (PIX *)ERROR_PTR("pixs not {2,4,8,16,32} bpp", procName, NULL);
478 
479  /* Remove colormap; clone if possible; result is either 8 or 32 bpp */
480  if ((pixt = pixConvertTo8Or32(pixs, L_CLONE, 0)) == NULL)
481  return (PIX *)ERROR_PTR("pixt not made", procName, NULL);
482 
483  d = pixGetDepth(pixt);
484  if (d == 8)
485  pixd = pixScaleGrayLI(pixt, scalex, scaley);
486  else /* d == 32 */
487  pixd = pixScaleColorLI(pixt, scalex, scaley);
488 
489  pixDestroy(&pixt);
490  pixCopyInputFormat(pixd, pixs);
491  return pixd;
492 }
493 
494 
518 PIX *
520  l_float32 scalex,
521  l_float32 scaley)
522 {
523 l_int32 ws, hs, wpls, wd, hd, wpld;
524 l_uint32 *datas, *datad;
525 l_float32 maxscale;
526 PIX *pixd;
527 
528  PROCNAME("pixScaleColorLI");
529 
530  if (!pixs || (pixGetDepth(pixs) != 32))
531  return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
532  maxscale = L_MAX(scalex, scaley);
533  if (maxscale < 0.7) {
534  L_WARNING("scaling factors < 0.7; do regular scaling\n", procName);
535  return pixScaleGeneral(pixs, scalex, scaley, 0.0, 0);
536  }
537 
538  /* Do fast special cases if possible */
539  if (scalex == 1.0 && scaley == 1.0)
540  return pixCopy(NULL, pixs);
541  if (scalex == 2.0 && scaley == 2.0)
542  return pixScaleColor2xLI(pixs);
543  if (scalex == 4.0 && scaley == 4.0)
544  return pixScaleColor4xLI(pixs);
545 
546  /* General case */
547  pixGetDimensions(pixs, &ws, &hs, NULL);
548  datas = pixGetData(pixs);
549  wpls = pixGetWpl(pixs);
550  wd = (l_int32)(scalex * (l_float32)ws + 0.5);
551  hd = (l_int32)(scaley * (l_float32)hs + 0.5);
552  if ((pixd = pixCreate(wd, hd, 32)) == NULL)
553  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
554  pixCopyResolution(pixd, pixs);
555  pixScaleResolution(pixd, scalex, scaley);
556  datad = pixGetData(pixd);
557  wpld = pixGetWpl(pixd);
558  scaleColorLILow(datad, wd, hd, wpld, datas, ws, hs, wpls);
559  if (pixGetSpp(pixs) == 4)
560  pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley);
561 
562  pixCopyInputFormat(pixd, pixs);
563  return pixd;
564 }
565 
566 
584 PIX *
586 {
587 l_int32 ws, hs, wpls, wpld;
588 l_uint32 *datas, *datad;
589 PIX *pixd;
590 
591  PROCNAME("pixScaleColor2xLI");
592 
593  if (!pixs || (pixGetDepth(pixs) != 32))
594  return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
595 
596  pixGetDimensions(pixs, &ws, &hs, NULL);
597  datas = pixGetData(pixs);
598  wpls = pixGetWpl(pixs);
599  if ((pixd = pixCreate(2 * ws, 2 * hs, 32)) == NULL)
600  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
601  pixCopyResolution(pixd, pixs);
602  pixScaleResolution(pixd, 2.0, 2.0);
603  datad = pixGetData(pixd);
604  wpld = pixGetWpl(pixd);
605  scaleColor2xLILow(datad, wpld, datas, ws, hs, wpls);
606  if (pixGetSpp(pixs) == 4)
607  pixScaleAndTransferAlpha(pixd, pixs, 2.0, 2.0);
608 
609  pixCopyInputFormat(pixd, pixs);
610  return pixd;
611 }
612 
613 
633 PIX *
635 {
636 PIX *pixr, *pixg, *pixb;
637 PIX *pixrs, *pixgs, *pixbs;
638 PIX *pixd;
639 
640  PROCNAME("pixScaleColor4xLI");
641 
642  if (!pixs || (pixGetDepth(pixs) != 32))
643  return (PIX *)ERROR_PTR("pixs undefined or not 32 bpp", procName, NULL);
644 
645  pixr = pixGetRGBComponent(pixs, COLOR_RED);
646  pixrs = pixScaleGray4xLI(pixr);
647  pixDestroy(&pixr);
648  pixg = pixGetRGBComponent(pixs, COLOR_GREEN);
649  pixgs = pixScaleGray4xLI(pixg);
650  pixDestroy(&pixg);
651  pixb = pixGetRGBComponent(pixs, COLOR_BLUE);
652  pixbs = pixScaleGray4xLI(pixb);
653  pixDestroy(&pixb);
654 
655  if ((pixd = pixCreateRGBImage(pixrs, pixgs, pixbs)) == NULL) {
656  L_ERROR("pixd not made\n", procName);
657  } else {
658  if (pixGetSpp(pixs) == 4)
659  pixScaleAndTransferAlpha(pixd, pixs, 4.0, 4.0);
660  pixCopyInputFormat(pixd, pixs);
661  }
662 
663  pixDestroy(&pixrs);
664  pixDestroy(&pixgs);
665  pixDestroy(&pixbs);
666  return pixd;
667 }
668 
669 
737 PIX *
739  l_float32 scalex,
740  l_float32 scaley)
741 {
742 l_int32 ws, hs, wpls, wd, hd, wpld;
743 l_uint32 *datas, *datad;
744 l_float32 maxscale;
745 PIX *pixd;
746 
747  PROCNAME("pixScaleGrayLI");
748 
749  if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
750  return (PIX *)ERROR_PTR("pixs undefined, cmapped or not 8 bpp",
751  procName, NULL);
752  maxscale = L_MAX(scalex, scaley);
753  if (maxscale < 0.7) {
754  L_WARNING("scaling factors < 0.7; do regular scaling\n", procName);
755  return pixScaleGeneral(pixs, scalex, scaley, 0.0, 0);
756  }
757 
758  /* Do fast special cases if possible */
759  if (scalex == 1.0 && scaley == 1.0)
760  return pixCopy(NULL, pixs);
761  if (scalex == 2.0 && scaley == 2.0)
762  return pixScaleGray2xLI(pixs);
763  if (scalex == 4.0 && scaley == 4.0)
764  return pixScaleGray4xLI(pixs);
765 
766  /* General case */
767  pixGetDimensions(pixs, &ws, &hs, NULL);
768  datas = pixGetData(pixs);
769  wpls = pixGetWpl(pixs);
770  wd = (l_int32)(scalex * (l_float32)ws + 0.5);
771  hd = (l_int32)(scaley * (l_float32)hs + 0.5);
772  if ((pixd = pixCreate(wd, hd, 8)) == NULL)
773  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
774  pixCopyText(pixd, pixs);
775  pixCopyResolution(pixd, pixs);
776  pixCopyInputFormat(pixd, pixs);
777  pixScaleResolution(pixd, scalex, scaley);
778  datad = pixGetData(pixd);
779  wpld = pixGetWpl(pixd);
780  scaleGrayLILow(datad, wd, hd, wpld, datas, ws, hs, wpls);
781  return pixd;
782 }
783 
784 
800 PIX *
802 {
803 l_int32 ws, hs, wpls, wpld;
804 l_uint32 *datas, *datad;
805 PIX *pixd;
806 
807  PROCNAME("pixScaleGray2xLI");
808 
809  if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
810  return (PIX *)ERROR_PTR("pixs undefined, cmapped or not 8 bpp",
811  procName, NULL);
812 
813  pixGetDimensions(pixs, &ws, &hs, NULL);
814  datas = pixGetData(pixs);
815  wpls = pixGetWpl(pixs);
816  if ((pixd = pixCreate(2 * ws, 2 * hs, 8)) == NULL)
817  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
818  pixCopyResolution(pixd, pixs);
819  pixCopyInputFormat(pixd, pixs);
820  pixScaleResolution(pixd, 2.0, 2.0);
821  datad = pixGetData(pixd);
822  wpld = pixGetWpl(pixd);
823  scaleGray2xLILow(datad, wpld, datas, ws, hs, wpls);
824  return pixd;
825 }
826 
827 
843 PIX *
845 {
846 l_int32 ws, hs, wpls, wpld;
847 l_uint32 *datas, *datad;
848 PIX *pixd;
849 
850  PROCNAME("pixScaleGray4xLI");
851 
852  if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
853  return (PIX *)ERROR_PTR("pixs undefined, cmapped or not 8 bpp",
854  procName, NULL);
855 
856  pixGetDimensions(pixs, &ws, &hs, NULL);
857  datas = pixGetData(pixs);
858  wpls = pixGetWpl(pixs);
859  if ((pixd = pixCreate(4 * ws, 4 * hs, 8)) == NULL)
860  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
861  pixCopyResolution(pixd, pixs);
862  pixCopyInputFormat(pixd, pixs);
863  pixScaleResolution(pixd, 4.0, 4.0);
864  datad = pixGetData(pixd);
865  wpld = pixGetWpl(pixd);
866  scaleGray4xLILow(datad, wpld, datas, ws, hs, wpls);
867  return pixd;
868 }
869 
870 
871 /*------------------------------------------------------------------*
872  * Scale 2x followed by binarization *
873  *------------------------------------------------------------------*/
888 PIX *
890  l_int32 thresh)
891 {
892 l_int32 i, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
893 l_uint32 *datas, *datad, *lines, *lined, *lineb;
894 PIX *pixd;
895 
896  PROCNAME("pixScaleGray2xLIThresh");
897 
898  if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
899  return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
900  procName, NULL);
901  if (thresh < 0 || thresh > 256)
902  return (PIX *)ERROR_PTR("thresh must be in [0, ... 256]",
903  procName, NULL);
904 
905  pixGetDimensions(pixs, &ws, &hs, NULL);
906  wd = 2 * ws;
907  hd = 2 * hs;
908  hsm = hs - 1;
909  datas = pixGetData(pixs);
910  wpls = pixGetWpl(pixs);
911 
912  /* Make line buffer for 2 lines of virtual intermediate image */
913  wplb = (wd + 3) / 4;
914  if ((lineb = (l_uint32 *)LEPT_CALLOC(2 * wplb, sizeof(l_uint32))) == NULL)
915  return (PIX *)ERROR_PTR("lineb not made", procName, NULL);
916 
917  /* Make dest binary image */
918  if ((pixd = pixCreate(wd, hd, 1)) == NULL) {
919  LEPT_FREE(lineb);
920  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
921  }
922  pixCopyInputFormat(pixd, pixs);
923  pixCopyResolution(pixd, pixs);
924  pixScaleResolution(pixd, 2.0, 2.0);
925  wpld = pixGetWpl(pixd);
926  datad = pixGetData(pixd);
927 
928  /* Do all but last src line */
929  for (i = 0; i < hsm; i++) {
930  lines = datas + i * wpls;
931  lined = datad + 2 * i * wpld; /* do 2 dest lines at a time */
932  scaleGray2xLILineLow(lineb, wplb, lines, ws, wpls, 0);
933  thresholdToBinaryLineLow(lined, wd, lineb, 8, thresh);
934  thresholdToBinaryLineLow(lined + wpld, wd, lineb + wplb, 8, thresh);
935  }
936 
937  /* Do last src line */
938  lines = datas + hsm * wpls;
939  lined = datad + 2 * hsm * wpld;
940  scaleGray2xLILineLow(lineb, wplb, lines, ws, wpls, 1);
941  thresholdToBinaryLineLow(lined, wd, lineb, 8, thresh);
942  thresholdToBinaryLineLow(lined + wpld, wd, lineb + wplb, 8, thresh);
943 
944  LEPT_FREE(lineb);
945  return pixd;
946 }
947 
948 
967 PIX *
969 {
970 l_int32 i, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
971 l_uint32 *datas, *datad;
972 l_uint32 *lined;
973 l_uint32 *lineb = NULL; /* 2 intermediate buffer lines */
974 l_uint32 *linebp = NULL; /* 1 intermediate buffer line */
975 l_uint32 *bufs = NULL; /* 2 source buffer lines */
976 PIX *pixd = NULL;
977 
978  PROCNAME("pixScaleGray2xLIDither");
979 
980  if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
981  return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
982  procName, NULL);
983 
984  pixGetDimensions(pixs, &ws, &hs, NULL);
985  wd = 2 * ws;
986  hd = 2 * hs;
987  hsm = hs - 1;
988  datas = pixGetData(pixs);
989  wpls = pixGetWpl(pixs);
990 
991  /* Make line buffers for 2 lines of src image */
992  if ((bufs = (l_uint32 *)LEPT_CALLOC(2 * wpls, sizeof(l_uint32))) == NULL)
993  return (PIX *)ERROR_PTR("bufs not made", procName, NULL);
994 
995  /* Make line buffer for 2 lines of virtual intermediate image */
996  wplb = (wd + 3) / 4;
997  if ((lineb = (l_uint32 *)LEPT_CALLOC(2 * wplb, sizeof(l_uint32))) == NULL) {
998  L_ERROR("lineb not made\n", procName);
999  goto cleanup;
1000  }
1001 
1002  /* Make line buffer for 1 line of virtual intermediate image */
1003  if ((linebp = (l_uint32 *)LEPT_CALLOC(wplb, sizeof(l_uint32))) == NULL) {
1004  L_ERROR("linebp not made\n", procName);
1005  goto cleanup;
1006  }
1007 
1008  /* Make dest binary image */
1009  if ((pixd = pixCreate(wd, hd, 1)) == NULL) {
1010  L_ERROR("pixd not made\n", procName);
1011  goto cleanup;
1012  }
1013  pixCopyInputFormat(pixd, pixs);
1014  pixCopyResolution(pixd, pixs);
1015  pixScaleResolution(pixd, 2.0, 2.0);
1016  wpld = pixGetWpl(pixd);
1017  datad = pixGetData(pixd);
1018 
1019  /* Start with the first src and the first dest line */
1020  memcpy(bufs, datas, 4 * wpls); /* first src line */
1021  memcpy(bufs + wpls, datas + wpls, 4 * wpls); /* 2nd src line */
1022  scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 2 i lines */
1023  lined = datad;
1024  ditherToBinaryLineLow(lined, wd, lineb, lineb + wplb,
1026  /* 1st d line */
1027 
1028  /* Do all but last src line */
1029  for (i = 1; i < hsm; i++) {
1030  memcpy(bufs, datas + i * wpls, 4 * wpls); /* i-th src line */
1031  memcpy(bufs + wpls, datas + (i + 1) * wpls, 4 * wpls);
1032  memcpy(linebp, lineb + wplb, 4 * wplb);
1033  scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 2 i lines */
1034  lined = datad + 2 * i * wpld;
1035  ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb,
1037  /* odd dest line */
1038  ditherToBinaryLineLow(lined, wd, lineb, lineb + wplb,
1040  /* even dest line */
1041  }
1042 
1043  /* Do the last src line and the last 3 dest lines */
1044  memcpy(bufs, datas + hsm * wpls, 4 * wpls); /* hsm-th src line */
1045  memcpy(linebp, lineb + wplb, 4 * wplb); /* 1 i line */
1046  scaleGray2xLILineLow(lineb, wplb, bufs, ws, wpls, 1); /* 2 i lines */
1047  ditherToBinaryLineLow(lined + wpld, wd, linebp, lineb,
1049  /* odd dest line */
1050  ditherToBinaryLineLow(lined + 2 * wpld, wd, lineb, lineb + wplb,
1052  /* even dest line */
1053  ditherToBinaryLineLow(lined + 3 * wpld, wd, lineb + wplb, NULL,
1055  /* last dest line */
1056 
1057 cleanup:
1058  LEPT_FREE(bufs);
1059  LEPT_FREE(lineb);
1060  LEPT_FREE(linebp);
1061  return pixd;
1062 }
1063 
1064 
1065 /*------------------------------------------------------------------*
1066  * Scale 4x followed by binarization *
1067  *------------------------------------------------------------------*/
1086 PIX *
1088  l_int32 thresh)
1089 {
1090 l_int32 i, j, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
1091 l_uint32 *datas, *datad, *lines, *lined, *lineb;
1092 PIX *pixd;
1093 
1094  PROCNAME("pixScaleGray4xLIThresh");
1095 
1096  if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
1097  return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
1098  procName, NULL);
1099  if (thresh < 0 || thresh > 256)
1100  return (PIX *)ERROR_PTR("thresh must be in [0, ... 256]",
1101  procName, NULL);
1102 
1103  pixGetDimensions(pixs, &ws, &hs, NULL);
1104  wd = 4 * ws;
1105  hd = 4 * hs;
1106  hsm = hs - 1;
1107  datas = pixGetData(pixs);
1108  wpls = pixGetWpl(pixs);
1109 
1110  /* Make line buffer for 4 lines of virtual intermediate image */
1111  wplb = (wd + 3) / 4;
1112  if ((lineb = (l_uint32 *)LEPT_CALLOC(4 * wplb, sizeof(l_uint32))) == NULL)
1113  return (PIX *)ERROR_PTR("lineb not made", procName, NULL);
1114 
1115  /* Make dest binary image */
1116  if ((pixd = pixCreate(wd, hd, 1)) == NULL) {
1117  LEPT_FREE(lineb);
1118  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1119  }
1120  pixCopyInputFormat(pixd, pixs);
1121  pixCopyResolution(pixd, pixs);
1122  pixScaleResolution(pixd, 4.0, 4.0);
1123  wpld = pixGetWpl(pixd);
1124  datad = pixGetData(pixd);
1125 
1126  /* Do all but last src line */
1127  for (i = 0; i < hsm; i++) {
1128  lines = datas + i * wpls;
1129  lined = datad + 4 * i * wpld; /* do 4 dest lines at a time */
1130  scaleGray4xLILineLow(lineb, wplb, lines, ws, wpls, 0);
1131  for (j = 0; j < 4; j++) {
1132  thresholdToBinaryLineLow(lined + j * wpld, wd,
1133  lineb + j * wplb, 8, thresh);
1134  }
1135  }
1136 
1137  /* Do last src line */
1138  lines = datas + hsm * wpls;
1139  lined = datad + 4 * hsm * wpld;
1140  scaleGray4xLILineLow(lineb, wplb, lines, ws, wpls, 1);
1141  for (j = 0; j < 4; j++) {
1142  thresholdToBinaryLineLow(lined + j * wpld, wd,
1143  lineb + j * wplb, 8, thresh);
1144  }
1145 
1146  LEPT_FREE(lineb);
1147  return pixd;
1148 }
1149 
1150 
1174 PIX *
1176 {
1177 l_int32 i, j, ws, hs, hsm, wd, hd, wpls, wplb, wpld;
1178 l_uint32 *datas, *datad;
1179 l_uint32 *lined;
1180 l_uint32 *lineb = NULL; /* 4 intermediate buffer lines */
1181 l_uint32 *linebp = NULL; /* 1 intermediate buffer line */
1182 l_uint32 *bufs = NULL; /* 2 source buffer lines */
1183 PIX *pixd = NULL;
1184 
1185  PROCNAME("pixScaleGray4xLIDither");
1186 
1187  if (!pixs || pixGetDepth(pixs) != 8 || pixGetColormap(pixs))
1188  return (PIX *)ERROR_PTR("pixs undefined, not 8 bpp, or cmapped",
1189  procName, NULL);
1190 
1191  pixGetDimensions(pixs, &ws, &hs, NULL);
1192  wd = 4 * ws;
1193  hd = 4 * hs;
1194  hsm = hs - 1;
1195  datas = pixGetData(pixs);
1196  wpls = pixGetWpl(pixs);
1197 
1198  /* Make line buffers for 2 lines of src image */
1199  if ((bufs = (l_uint32 *)LEPT_CALLOC(2 * wpls, sizeof(l_uint32))) == NULL)
1200  return (PIX *)ERROR_PTR("bufs not made", procName, NULL);
1201 
1202  /* Make line buffer for 4 lines of virtual intermediate image */
1203  wplb = (wd + 3) / 4;
1204  if ((lineb = (l_uint32 *)LEPT_CALLOC(4 * wplb, sizeof(l_uint32))) == NULL) {
1205  L_ERROR("lineb not made\n", procName);
1206  goto cleanup;
1207  }
1208 
1209  /* Make line buffer for 1 line of virtual intermediate image */
1210  if ((linebp = (l_uint32 *)LEPT_CALLOC(wplb, sizeof(l_uint32))) == NULL) {
1211  L_ERROR("linebp not made\n", procName);
1212  goto cleanup;
1213  }
1214 
1215  /* Make dest binary image */
1216  if ((pixd = pixCreate(wd, hd, 1)) == NULL) {
1217  L_ERROR("pixd not made\n", procName);
1218  goto cleanup;
1219  }
1220  pixCopyInputFormat(pixd, pixs);
1221  pixCopyResolution(pixd, pixs);
1222  pixScaleResolution(pixd, 4.0, 4.0);
1223  wpld = pixGetWpl(pixd);
1224  datad = pixGetData(pixd);
1225 
1226  /* Start with the first src and the first 3 dest lines */
1227  memcpy(bufs, datas, 4 * wpls); /* first src line */
1228  memcpy(bufs + wpls, datas + wpls, 4 * wpls); /* 2nd src line */
1229  scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 4 b lines */
1230  lined = datad;
1231  for (j = 0; j < 3; j++) { /* first 3 d lines of Q */
1232  ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb,
1233  lineb + (j + 1) * wplb,
1235  }
1236 
1237  /* Do all but last src line */
1238  for (i = 1; i < hsm; i++) {
1239  memcpy(bufs, datas + i * wpls, 4 * wpls); /* i-th src line */
1240  memcpy(bufs + wpls, datas + (i + 1) * wpls, 4 * wpls);
1241  memcpy(linebp, lineb + 3 * wplb, 4 * wplb);
1242  scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 0); /* 4 b lines */
1243  lined = datad + 4 * i * wpld;
1244  ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb,
1246  /* 4th dest line of Q */
1247  for (j = 0; j < 3; j++) { /* next 3 d lines of Quad */
1248  ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb,
1249  lineb + (j + 1) * wplb,
1251  }
1252  }
1253 
1254  /* Do the last src line and the last 5 dest lines */
1255  memcpy(bufs, datas + hsm * wpls, 4 * wpls); /* hsm-th src line */
1256  memcpy(linebp, lineb + 3 * wplb, 4 * wplb); /* 1 b line */
1257  scaleGray4xLILineLow(lineb, wplb, bufs, ws, wpls, 1); /* 4 b lines */
1258  lined = datad + 4 * hsm * wpld;
1259  ditherToBinaryLineLow(lined - wpld, wd, linebp, lineb,
1261  /* 4th dest line of Q */
1262  for (j = 0; j < 3; j++) { /* next 3 d lines of Quad */
1263  ditherToBinaryLineLow(lined + j * wpld, wd, lineb + j * wplb,
1264  lineb + (j + 1) * wplb,
1266  }
1267  /* And finally, the last dest line */
1268  ditherToBinaryLineLow(lined + 3 * wpld, wd, lineb + 3 * wplb, NULL,
1270 
1271 cleanup:
1272  LEPT_FREE(bufs);
1273  LEPT_FREE(lineb);
1274  LEPT_FREE(linebp);
1275  return pixd;
1276 }
1277 
1278 
1279 /*------------------------------------------------------------------*
1280  * Scaling by closest pixel sampling *
1281  *------------------------------------------------------------------*/
1297 PIX *
1299  l_float32 scalex,
1300  l_float32 scaley)
1301 {
1302 l_int32 ws, hs, d, wpls, wd, hd, wpld;
1303 l_uint32 *datas, *datad;
1304 PIX *pixd;
1305 
1306  PROCNAME("pixScaleBySampling");
1307 
1308  if (!pixs)
1309  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1310  if (scalex <= 0.0 || scaley <= 0.0)
1311  return (PIX *)ERROR_PTR("scale factor <= 0", procName, NULL);
1312  if (scalex == 1.0 && scaley == 1.0)
1313  return pixCopy(NULL, pixs);
1314  if ((d = pixGetDepth(pixs)) == 1)
1315  return pixScaleBinary(pixs, scalex, scaley);
1316 
1317  pixGetDimensions(pixs, &ws, &hs, NULL);
1318  datas = pixGetData(pixs);
1319  wpls = pixGetWpl(pixs);
1320  wd = (l_int32)(scalex * (l_float32)ws + 0.5);
1321  hd = (l_int32)(scaley * (l_float32)hs + 0.5);
1322  if ((pixd = pixCreate(wd, hd, d)) == NULL)
1323  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1324  pixCopyResolution(pixd, pixs);
1325  pixScaleResolution(pixd, scalex, scaley);
1326  pixCopyColormap(pixd, pixs);
1327  pixCopyText(pixd, pixs);
1328  pixCopyInputFormat(pixd, pixs);
1329  pixCopySpp(pixd, pixs);
1330  datad = pixGetData(pixd);
1331  wpld = pixGetWpl(pixd);
1332  scaleBySamplingLow(datad, wd, hd, wpld, datas, ws, hs, d, wpls);
1333  if (d == 32 && pixGetSpp(pixs) == 4)
1334  pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley);
1335 
1336  return pixd;
1337 }
1338 
1339 
1359 PIX *
1361  l_int32 wd,
1362  l_int32 hd)
1363 {
1364 l_int32 w, h;
1365 l_float32 scalex, scaley;
1366 
1367  PROCNAME("pixScaleBySamplingToSize");
1368 
1369  if (!pixs)
1370  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1371  if (wd <= 0 && hd <= 0)
1372  return (PIX *)ERROR_PTR("neither wd nor hd > 0", procName, NULL);
1373 
1374  pixGetDimensions(pixs, &w, &h, NULL);
1375  if (wd <= 0) {
1376  scaley = (l_float32)hd / (l_float32)h;
1377  scalex = scaley;
1378  } else if (hd <= 0) {
1379  scalex = (l_float32)wd / (l_float32)w;
1380  scaley = scalex;
1381  } else {
1382  scalex = (l_float32)wd / (l_float32)w;
1383  scaley = (l_float32)hd / (l_float32)h;
1384  }
1385 
1386  return pixScaleBySampling(pixs, scalex, scaley);
1387 }
1388 
1389 
1404 PIX *
1406  l_int32 factor)
1407 {
1408 l_float32 scale;
1409 
1410  PROCNAME("pixScaleByIntSampling");
1411 
1412  if (!pixs)
1413  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1414  if (factor <= 1) {
1415  if (factor < 1)
1416  L_ERROR("factor must be >= 1; returning a copy\n", procName);
1417  return pixCopy(NULL, pixs);
1418  }
1419 
1420  scale = 1. / (l_float32)factor;
1421  return pixScaleBySampling(pixs, scale, scale);
1422 }
1423 
1424 
1425 /*------------------------------------------------------------------*
1426  * Fast integer factor subsampling RGB to gray *
1427  *------------------------------------------------------------------*/
1446 PIX *
1448  l_int32 factor,
1449  l_int32 color)
1450 {
1451 l_int32 byteval, shift;
1452 l_int32 i, j, ws, hs, wd, hd, wpls, wpld;
1453 l_uint32 *datas, *words, *datad, *lined;
1454 l_float32 scale;
1455 PIX *pixd;
1456 
1457  PROCNAME("pixScaleRGBToGrayFast");
1458 
1459  if (!pixs)
1460  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1461  if (pixGetDepth(pixs) != 32)
1462  return (PIX *)ERROR_PTR("depth not 32 bpp", procName, NULL);
1463  if (factor < 1)
1464  return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
1465 
1466  if (color == COLOR_RED)
1467  shift = L_RED_SHIFT;
1468  else if (color == COLOR_GREEN)
1469  shift = L_GREEN_SHIFT;
1470  else if (color == COLOR_BLUE)
1471  shift = L_BLUE_SHIFT;
1472  else
1473  return (PIX *)ERROR_PTR("invalid color", procName, NULL);
1474 
1475  pixGetDimensions(pixs, &ws, &hs, NULL);
1476  datas = pixGetData(pixs);
1477  wpls = pixGetWpl(pixs);
1478 
1479  wd = ws / factor;
1480  hd = hs / factor;
1481  if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1482  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1483  pixCopyResolution(pixd, pixs);
1484  pixCopyInputFormat(pixd, pixs);
1485  scale = 1. / (l_float32) factor;
1486  pixScaleResolution(pixd, scale, scale);
1487  datad = pixGetData(pixd);
1488  wpld = pixGetWpl(pixd);
1489 
1490  for (i = 0; i < hd; i++) {
1491  words = datas + i * factor * wpls;
1492  lined = datad + i * wpld;
1493  for (j = 0; j < wd; j++, words += factor) {
1494  byteval = ((*words) >> shift) & 0xff;
1495  SET_DATA_BYTE(lined, j, byteval);
1496  }
1497  }
1498 
1499  return pixd;
1500 }
1501 
1502 
1521 PIX *
1523  l_int32 factor,
1524  l_int32 thresh)
1525 {
1526 l_int32 byteval;
1527 l_int32 i, j, ws, hs, wd, hd, wpls, wpld;
1528 l_uint32 *datas, *words, *datad, *lined;
1529 l_float32 scale;
1530 PIX *pixd;
1531 
1532  PROCNAME("pixScaleRGBToBinaryFast");
1533 
1534  if (!pixs)
1535  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1536  if (factor < 1)
1537  return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
1538  if (pixGetDepth(pixs) != 32)
1539  return (PIX *)ERROR_PTR("depth not 32 bpp", procName, NULL);
1540 
1541  pixGetDimensions(pixs, &ws, &hs, NULL);
1542  datas = pixGetData(pixs);
1543  wpls = pixGetWpl(pixs);
1544 
1545  wd = ws / factor;
1546  hd = hs / factor;
1547  if ((pixd = pixCreate(wd, hd, 1)) == NULL)
1548  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1549  pixCopyResolution(pixd, pixs);
1550  pixCopyInputFormat(pixd, pixs);
1551  scale = 1. / (l_float32) factor;
1552  pixScaleResolution(pixd, scale, scale);
1553  datad = pixGetData(pixd);
1554  wpld = pixGetWpl(pixd);
1555 
1556  for (i = 0; i < hd; i++) {
1557  words = datas + i * factor * wpls;
1558  lined = datad + i * wpld;
1559  for (j = 0; j < wd; j++, words += factor) {
1560  byteval = ((*words) >> L_GREEN_SHIFT) & 0xff;
1561  if (byteval < thresh)
1562  SET_DATA_BIT(lined, j);
1563  }
1564  }
1565 
1566  return pixd;
1567 }
1568 
1569 
1587 PIX *
1589  l_int32 factor,
1590  l_int32 thresh)
1591 {
1592 l_int32 byteval;
1593 l_int32 i, j, ws, hs, wd, hd, wpls, wpld, sj;
1594 l_uint32 *datas, *datad, *lines, *lined;
1595 l_float32 scale;
1596 PIX *pixd;
1597 
1598  PROCNAME("pixScaleGrayToBinaryFast");
1599 
1600  if (!pixs)
1601  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1602  if (factor < 1)
1603  return (PIX *)ERROR_PTR("factor must be >= 1", procName, NULL);
1604  if (pixGetDepth(pixs) != 8)
1605  return (PIX *)ERROR_PTR("depth not 8 bpp", procName, NULL);
1606 
1607  pixGetDimensions(pixs, &ws, &hs, NULL);
1608  datas = pixGetData(pixs);
1609  wpls = pixGetWpl(pixs);
1610 
1611  wd = ws / factor;
1612  hd = hs / factor;
1613  if ((pixd = pixCreate(wd, hd, 1)) == NULL)
1614  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1615  pixCopyResolution(pixd, pixs);
1616  pixCopyInputFormat(pixd, pixs);
1617  scale = 1. / (l_float32) factor;
1618  pixScaleResolution(pixd, scale, scale);
1619  datad = pixGetData(pixd);
1620  wpld = pixGetWpl(pixd);
1621 
1622  for (i = 0; i < hd; i++) {
1623  lines = datas + i * factor * wpls;
1624  lined = datad + i * wpld;
1625  for (j = 0, sj = 0; j < wd; j++, sj += factor) {
1626  byteval = GET_DATA_BYTE(lines, sj);
1627  if (byteval < thresh)
1628  SET_DATA_BIT(lined, j);
1629  }
1630  }
1631 
1632  return pixd;
1633 }
1634 
1635 
1636 /*------------------------------------------------------------------*
1637  * Downscaling with (antialias) smoothing *
1638  *------------------------------------------------------------------*/
1670 PIX *
1672  l_float32 scalex,
1673  l_float32 scaley)
1674 {
1675 l_int32 ws, hs, d, wd, hd, wpls, wpld, isize;
1676 l_uint32 *datas, *datad;
1677 l_float32 minscale, size;
1678 PIX *pixs, *pixd;
1679 
1680  PROCNAME("pixScaleSmooth");
1681 
1682  if (!pix)
1683  return (PIX *)ERROR_PTR("pix not defined", procName, NULL);
1684  if (scalex >= 0.7 || scaley >= 0.7) {
1685  L_WARNING("scaling factor not < 0.7; do regular scaling\n", procName);
1686  return pixScaleGeneral(pix, scalex, scaley, 0.0, 0);
1687  }
1688 
1689  /* Remove colormap if necessary.
1690  * If 2 bpp or 4 bpp gray, convert to 8 bpp */
1691  d = pixGetDepth(pix);
1692  if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
1693  L_WARNING("pix has colormap; removing\n", procName);
1695  d = pixGetDepth(pixs);
1696  } else if (d == 2 || d == 4) {
1697  pixs = pixConvertTo8(pix, FALSE);
1698  d = 8;
1699  } else {
1700  pixs = pixClone(pix);
1701  }
1702 
1703  if (d != 8 && d != 32) { /* d == 1 or d == 16 */
1704  L_WARNING("depth not 8 or 32 bpp; do regular scaling\n", procName);
1705  pixDestroy(&pixs);
1706  return pixScaleGeneral(pix, scalex, scaley, 0.0, 0);
1707  }
1708 
1709  /* If 1.42 < 1/minscale < 2.5, use isize = 2
1710  * If 2.5 =< 1/minscale < 3.5, use isize = 3, etc.
1711  * Under no conditions use isize < 2 */
1712  minscale = L_MIN(scalex, scaley);
1713  size = 1.0 / minscale; /* ideal filter full width */
1714  isize = L_MAX(2, (l_int32)(size + 0.5));
1715 
1716  pixGetDimensions(pixs, &ws, &hs, NULL);
1717  if ((ws < isize) || (hs < isize)) {
1718  pixDestroy(&pixs);
1719  return (PIX *)ERROR_PTR("pixs too small", procName, NULL);
1720  }
1721  datas = pixGetData(pixs);
1722  wpls = pixGetWpl(pixs);
1723  wd = (l_int32)(scalex * (l_float32)ws + 0.5);
1724  hd = (l_int32)(scaley * (l_float32)hs + 0.5);
1725  if (wd < 1 || hd < 1) {
1726  pixDestroy(&pixs);
1727  return (PIX *)ERROR_PTR("pixd too small", procName, NULL);
1728  }
1729  if ((pixd = pixCreate(wd, hd, d)) == NULL) {
1730  pixDestroy(&pixs);
1731  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1732  }
1733  pixCopyResolution(pixd, pixs);
1734  pixCopyInputFormat(pixd, pixs);
1735  pixScaleResolution(pixd, scalex, scaley);
1736  datad = pixGetData(pixd);
1737  wpld = pixGetWpl(pixd);
1738  scaleSmoothLow(datad, wd, hd, wpld, datas, ws, hs, d, wpls, isize);
1739  if (d == 32 && pixGetSpp(pixs) == 4)
1740  pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley);
1741 
1742  pixDestroy(&pixs);
1743  return pixd;
1744 }
1745 
1746 
1766 PIX *
1768  l_int32 wd,
1769  l_int32 hd)
1770 {
1771 l_int32 w, h;
1772 l_float32 scalex, scaley;
1773 
1774  PROCNAME("pixScaleSmoothToSize");
1775 
1776  if (!pixs)
1777  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1778  if (wd <= 0 && hd <= 0)
1779  return (PIX *)ERROR_PTR("neither wd nor hd > 0", procName, NULL);
1780 
1781  pixGetDimensions(pixs, &w, &h, NULL);
1782  if (wd <= 0) {
1783  scaley = (l_float32)hd / (l_float32)h;
1784  scalex = scaley;
1785  } else if (hd <= 0) {
1786  scalex = (l_float32)wd / (l_float32)w;
1787  scaley = scalex;
1788  } else {
1789  scalex = (l_float32)wd / (l_float32)w;
1790  scaley = (l_float32)hd / (l_float32)h;
1791  }
1792 
1793  return pixScaleSmooth(pixs, scalex, scaley);
1794 }
1795 
1796 
1804 PIX *
1806  l_float32 rwt,
1807  l_float32 gwt,
1808  l_float32 bwt)
1809 {
1810 l_int32 wd, hd, wpls, wpld;
1811 l_uint32 *datas, *datad;
1812 PIX *pixd;
1813 
1814  PROCNAME("pixScaleRGBToGray2");
1815 
1816  if (!pixs)
1817  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1818  if (pixGetDepth(pixs) != 32)
1819  return (PIX *)ERROR_PTR("pixs not 32 bpp", procName, NULL);
1820  if (rwt + gwt + bwt < 0.98 || rwt + gwt + bwt > 1.02)
1821  return (PIX *)ERROR_PTR("sum of wts should be 1.0", procName, NULL);
1822 
1823  wd = pixGetWidth(pixs) / 2;
1824  hd = pixGetHeight(pixs) / 2;
1825  wpls = pixGetWpl(pixs);
1826  datas = pixGetData(pixs);
1827  if ((pixd = pixCreate(wd, hd, 8)) == NULL)
1828  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1829  pixCopyResolution(pixd, pixs);
1830  pixCopyInputFormat(pixd, pixs);
1831  pixScaleResolution(pixd, 0.5, 0.5);
1832  wpld = pixGetWpl(pixd);
1833  datad = pixGetData(pixd);
1834  scaleRGBToGray2Low(datad, wd, hd, wpld, datas, wpls, rwt, gwt, bwt);
1835  return pixd;
1836 }
1837 
1838 
1839 /*------------------------------------------------------------------*
1840  * Downscaling with (antialias) area mapping *
1841  *------------------------------------------------------------------*/
1871 PIX *
1873  l_float32 scalex,
1874  l_float32 scaley)
1875 {
1876 l_int32 ws, hs, d, wd, hd, wpls, wpld;
1877 l_uint32 *datas, *datad;
1878 l_float32 maxscale;
1879 PIX *pixs, *pixd, *pixt1, *pixt2, *pixt3;
1880 
1881  PROCNAME("pixScaleAreaMap");
1882 
1883  if (!pix)
1884  return (PIX *)ERROR_PTR("pix not defined", procName, NULL);
1885  d = pixGetDepth(pix);
1886  if (d != 2 && d != 4 && d != 8 && d != 32)
1887  return (PIX *)ERROR_PTR("pix not 2, 4, 8 or 32 bpp", procName, NULL);
1888  maxscale = L_MAX(scalex, scaley);
1889  if (maxscale >= 0.7) {
1890  L_WARNING("scaling factors not < 0.7; do regular scaling\n", procName);
1891  return pixScaleGeneral(pix, scalex, scaley, 0.0, 0);
1892  }
1893 
1894  /* Special cases: 2x, 4x, 8x, 16x reduction */
1895  if (scalex == 0.5 && scaley == 0.5)
1896  return pixScaleAreaMap2(pix);
1897  if (scalex == 0.25 && scaley == 0.25) {
1898  pixt1 = pixScaleAreaMap2(pix);
1899  pixd = pixScaleAreaMap2(pixt1);
1900  pixDestroy(&pixt1);
1901  return pixd;
1902  }
1903  if (scalex == 0.125 && scaley == 0.125) {
1904  pixt1 = pixScaleAreaMap2(pix);
1905  pixt2 = pixScaleAreaMap2(pixt1);
1906  pixd = pixScaleAreaMap2(pixt2);
1907  pixDestroy(&pixt1);
1908  pixDestroy(&pixt2);
1909  return pixd;
1910  }
1911  if (scalex == 0.0625 && scaley == 0.0625) {
1912  pixt1 = pixScaleAreaMap2(pix);
1913  pixt2 = pixScaleAreaMap2(pixt1);
1914  pixt3 = pixScaleAreaMap2(pixt2);
1915  pixd = pixScaleAreaMap2(pixt3);
1916  pixDestroy(&pixt1);
1917  pixDestroy(&pixt2);
1918  pixDestroy(&pixt3);
1919  return pixd;
1920  }
1921 
1922  /* Remove colormap if necessary.
1923  * If 2 bpp or 4 bpp gray, convert to 8 bpp */
1924  if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
1925  L_WARNING("pix has colormap; removing\n", procName);
1927  d = pixGetDepth(pixs);
1928  } else if (d == 2 || d == 4) {
1929  pixs = pixConvertTo8(pix, FALSE);
1930  d = 8;
1931  } else {
1932  pixs = pixClone(pix);
1933  }
1934 
1935  pixGetDimensions(pixs, &ws, &hs, NULL);
1936  datas = pixGetData(pixs);
1937  wpls = pixGetWpl(pixs);
1938  wd = (l_int32)(scalex * (l_float32)ws + 0.5);
1939  hd = (l_int32)(scaley * (l_float32)hs + 0.5);
1940  if (wd < 1 || hd < 1) {
1941  pixDestroy(&pixs);
1942  return (PIX *)ERROR_PTR("pixd too small", procName, NULL);
1943  }
1944  if ((pixd = pixCreate(wd, hd, d)) == NULL) {
1945  pixDestroy(&pixs);
1946  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
1947  }
1948  pixCopyInputFormat(pixd, pixs);
1949  pixCopyResolution(pixd, pixs);
1950  pixScaleResolution(pixd, scalex, scaley);
1951  datad = pixGetData(pixd);
1952  wpld = pixGetWpl(pixd);
1953  if (d == 8) {
1954  scaleGrayAreaMapLow(datad, wd, hd, wpld, datas, ws, hs, wpls);
1955  } else { /* RGB, d == 32 */
1956  scaleColorAreaMapLow(datad, wd, hd, wpld, datas, ws, hs, wpls);
1957  if (pixGetSpp(pixs) == 4)
1958  pixScaleAndTransferAlpha(pixd, pixs, scalex, scaley);
1959  }
1960 
1961  pixDestroy(&pixs);
1962  return pixd;
1963 }
1964 
1965 
1991 PIX *
1993 {
1994 l_int32 wd, hd, d, wpls, wpld;
1995 l_uint32 *datas, *datad;
1996 PIX *pixs, *pixd;
1997 
1998  PROCNAME("pixScaleAreaMap2");
1999 
2000  if (!pix)
2001  return (PIX *)ERROR_PTR("pix not defined", procName, NULL);
2002  d = pixGetDepth(pix);
2003  if (d != 2 && d != 4 && d != 8 && d != 32)
2004  return (PIX *)ERROR_PTR("pix not 2, 4, 8 or 32 bpp", procName, NULL);
2005 
2006  /* Remove colormap if necessary.
2007  * If 2 bpp or 4 bpp gray, convert to 8 bpp */
2008  if ((d == 2 || d == 4 || d == 8) && pixGetColormap(pix)) {
2009  L_WARNING("pix has colormap; removing\n", procName);
2011  d = pixGetDepth(pixs);
2012  } else if (d == 2 || d == 4) {
2013  pixs = pixConvertTo8(pix, FALSE);
2014  d = 8;
2015  } else {
2016  pixs = pixClone(pix);
2017  }
2018 
2019  wd = pixGetWidth(pixs) / 2;
2020  hd = pixGetHeight(pixs) / 2;
2021  datas = pixGetData(pixs);
2022  wpls = pixGetWpl(pixs);
2023  pixd = pixCreate(wd, hd, d);
2024  datad = pixGetData(pixd);
2025  wpld = pixGetWpl(pixd);
2026  pixCopyInputFormat(pixd, pixs);
2027  pixCopyResolution(pixd, pixs);
2028  pixScaleResolution(pixd, 0.5, 0.5);
2029  scaleAreaMapLow2(datad, wd, hd, wpld, datas, d, wpls);
2030  if (pixGetSpp(pixs) == 4)
2031  pixScaleAndTransferAlpha(pixd, pixs, 0.5, 0.5);
2032  pixDestroy(&pixs);
2033  return pixd;
2034 }
2035 
2036 
2056 PIX *
2058  l_int32 wd,
2059  l_int32 hd)
2060 {
2061 l_int32 w, h;
2062 l_float32 scalex, scaley;
2063 
2064  PROCNAME("pixScaleAreaMapToSize");
2065 
2066  if (!pixs)
2067  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2068  if (wd <= 0 && hd <= 0)
2069  return (PIX *)ERROR_PTR("neither wd nor hd > 0", procName, NULL);
2070 
2071  pixGetDimensions(pixs, &w, &h, NULL);
2072  if (wd <= 0) {
2073  scaley = (l_float32)hd / (l_float32)h;
2074  scalex = scaley;
2075  } else if (hd <= 0) {
2076  scalex = (l_float32)wd / (l_float32)w;
2077  scaley = scalex;
2078  } else {
2079  scalex = (l_float32)wd / (l_float32)w;
2080  scaley = (l_float32)hd / (l_float32)h;
2081  }
2082 
2083  return pixScaleAreaMap(pixs, scalex, scaley);
2084 }
2085 
2086 
2087 /*------------------------------------------------------------------*
2088  * Binary scaling by closest pixel sampling *
2089  *------------------------------------------------------------------*/
2104 PIX *
2106  l_float32 scalex,
2107  l_float32 scaley)
2108 {
2109 l_int32 ws, hs, wpls, wd, hd, wpld;
2110 l_uint32 *datas, *datad;
2111 PIX *pixd;
2112 
2113  PROCNAME("pixScaleBinary");
2114 
2115  if (!pixs)
2116  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
2117  if (pixGetDepth(pixs) != 1)
2118  return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, NULL);
2119  if (scalex <= 0.0 || scaley <= 0.0)
2120  return (PIX *)ERROR_PTR("scale factor <= 0", procName, NULL);
2121  if (scalex == 1.0 && scaley == 1.0)
2122  return pixCopy(NULL, pixs);
2123 
2124  pixGetDimensions(pixs, &ws, &hs, NULL);
2125  datas = pixGetData(pixs);
2126  wpls = pixGetWpl(pixs);
2127  wd = (l_int32)(scalex * (l_float32)ws + 0.5);
2128  hd = (l_int32)(scaley * (l_float32)hs + 0.5);
2129  if ((pixd = pixCreate(wd, hd, 1)) == NULL)
2130  return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
2131  pixCopyColormap(pixd, pixs);
2132  pixCopyText(pixd, pixs);
2133  pixCopyInputFormat(pixd, pixs);
2134  pixCopyResolution(pixd, pixs);
2135  pixScaleResolution(pixd, scalex, scaley);
2136  datad = pixGetData(pixd);
2137  wpld = pixGetWpl(pixd);
2138  scaleBinaryLow(datad, wd, hd, wpld, datas, ws, hs, wpls);
2139  return pixd;
2140 }
2141 
2142 
2143 /* ================================================================ *
2144  * Low level static functions *
2145  * ================================================================ */
2146 
2147 /*------------------------------------------------------------------*
2148  * General linear interpolated color scaling *
2149  *------------------------------------------------------------------*/
2161 static void
2162 scaleColorLILow(l_uint32 *datad,
2163  l_int32 wd,
2164  l_int32 hd,
2165  l_int32 wpld,
2166  l_uint32 *datas,
2167  l_int32 ws,
2168  l_int32 hs,
2169  l_int32 wpls)
2170 {
2171 l_int32 i, j, wm2, hm2;
2172 l_int32 xpm, ypm; /* location in src image, to 1/16 of a pixel */
2173 l_int32 xp, yp, xf, yf; /* src pixel and pixel fraction coordinates */
2174 l_int32 v00r, v01r, v10r, v11r, v00g, v01g, v10g, v11g;
2175 l_int32 v00b, v01b, v10b, v11b, area00, area01, area10, area11;
2176 l_uint32 pixels1, pixels2, pixels3, pixels4, pixel;
2177 l_uint32 *lines, *lined;
2178 l_float32 scx, scy;
2179 
2180  /* (scx, scy) are scaling factors that are applied to the
2181  * dest coords to get the corresponding src coords.
2182  * We need them because we iterate over dest pixels
2183  * and must find the corresponding set of src pixels. */
2184  scx = 16. * (l_float32)ws / (l_float32)wd;
2185  scy = 16. * (l_float32)hs / (l_float32)hd;
2186  wm2 = ws - 2;
2187  hm2 = hs - 2;
2188 
2189  /* Iterate over the destination pixels */
2190  for (i = 0; i < hd; i++) {
2191  ypm = (l_int32)(scy * (l_float32)i);
2192  yp = ypm >> 4;
2193  yf = ypm & 0x0f;
2194  lined = datad + i * wpld;
2195  lines = datas + yp * wpls;
2196  for (j = 0; j < wd; j++) {
2197  xpm = (l_int32)(scx * (l_float32)j);
2198  xp = xpm >> 4;
2199  xf = xpm & 0x0f;
2200 
2201  /* Do bilinear interpolation. This is a simple
2202  * generalization of the calculation in scaleGrayLILow().
2203  * Without this, we could simply subsample:
2204  * *(lined + j) = *(lines + xp);
2205  * which is faster but gives lousy results! */
2206  pixels1 = *(lines + xp);
2207 
2208  if (xp > wm2 || yp > hm2) {
2209  if (yp > hm2 && xp <= wm2) { /* pixels near bottom */
2210  pixels2 = *(lines + xp + 1);
2211  pixels3 = pixels1;
2212  pixels4 = pixels2;
2213  } else if (xp > wm2 && yp <= hm2) { /* pixels near rt side */
2214  pixels2 = pixels1;
2215  pixels3 = *(lines + wpls + xp);
2216  pixels4 = pixels3;
2217  } else { /* pixels at LR corner */
2218  pixels4 = pixels3 = pixels2 = pixels1;
2219  }
2220  } else {
2221  pixels2 = *(lines + xp + 1);
2222  pixels3 = *(lines + wpls + xp);
2223  pixels4 = *(lines + wpls + xp + 1);
2224  }
2225 
2226  area00 = (16 - xf) * (16 - yf);
2227  area10 = xf * (16 - yf);
2228  area01 = (16 - xf) * yf;
2229  area11 = xf * yf;
2230  v00r = area00 * ((pixels1 >> L_RED_SHIFT) & 0xff);
2231  v00g = area00 * ((pixels1 >> L_GREEN_SHIFT) & 0xff);
2232  v00b = area00 * ((pixels1 >> L_BLUE_SHIFT) & 0xff);
2233  v10r = area10 * ((pixels2 >> L_RED_SHIFT) & 0xff);
2234  v10g = area10 * ((pixels2 >> L_GREEN_SHIFT) & 0xff);
2235  v10b = area10 * ((pixels2 >> L_BLUE_SHIFT) & 0xff);
2236  v01r = area01 * ((pixels3 >> L_RED_SHIFT) & 0xff);
2237  v01g = area01 * ((pixels3 >> L_GREEN_SHIFT) & 0xff);
2238  v01b = area01 * ((pixels3 >> L_BLUE_SHIFT) & 0xff);
2239  v11r = area11 * ((pixels4 >> L_RED_SHIFT) & 0xff);
2240  v11g = area11 * ((pixels4 >> L_GREEN_SHIFT) & 0xff);
2241  v11b = area11 * ((pixels4 >> L_BLUE_SHIFT) & 0xff);
2242  pixel = (((v00r + v10r + v01r + v11r + 128) << 16) & 0xff000000) |
2243  (((v00g + v10g + v01g + v11g + 128) << 8) & 0x00ff0000) |
2244  ((v00b + v10b + v01b + v11b + 128) & 0x0000ff00);
2245  *(lined + j) = pixel;
2246  }
2247  }
2248 }
2249 
2250 
2251 /*------------------------------------------------------------------*
2252  * General linear interpolated gray scaling *
2253  *------------------------------------------------------------------*/
2263 static void
2264 scaleGrayLILow(l_uint32 *datad,
2265  l_int32 wd,
2266  l_int32 hd,
2267  l_int32 wpld,
2268  l_uint32 *datas,
2269  l_int32 ws,
2270  l_int32 hs,
2271  l_int32 wpls)
2272 {
2273 l_int32 i, j, wm2, hm2;
2274 l_int32 xpm, ypm; /* location in src image, to 1/16 of a pixel */
2275 l_int32 xp, yp, xf, yf; /* src pixel and pixel fraction coordinates */
2276 l_int32 v00, v01, v10, v11, v00_val, v01_val, v10_val, v11_val;
2277 l_uint8 val;
2278 l_uint32 *lines, *lined;
2279 l_float32 scx, scy;
2280 
2281  /* (scx, scy) are scaling factors that are applied to the
2282  * dest coords to get the corresponding src coords.
2283  * We need them because we iterate over dest pixels
2284  * and must find the corresponding set of src pixels. */
2285  scx = 16. * (l_float32)ws / (l_float32)wd;
2286  scy = 16. * (l_float32)hs / (l_float32)hd;
2287  wm2 = ws - 2;
2288  hm2 = hs - 2;
2289 
2290  /* Iterate over the destination pixels */
2291  for (i = 0; i < hd; i++) {
2292  ypm = (l_int32)(scy * (l_float32)i);
2293  yp = ypm >> 4;
2294  yf = ypm & 0x0f;
2295  lined = datad + i * wpld;
2296  lines = datas + yp * wpls;
2297  for (j = 0; j < wd; j++) {
2298  xpm = (l_int32)(scx * (l_float32)j);
2299  xp = xpm >> 4;
2300  xf = xpm & 0x0f;
2301 
2302  /* Do bilinear interpolation. Without this, we could
2303  * simply subsample:
2304  * SET_DATA_BYTE(lined, j, GET_DATA_BYTE(lines, xp));
2305  * which is faster but gives lousy results! */
2306  v00_val = GET_DATA_BYTE(lines, xp);
2307  if (xp > wm2 || yp > hm2) {
2308  if (yp > hm2 && xp <= wm2) { /* pixels near bottom */
2309  v01_val = v00_val;
2310  v10_val = GET_DATA_BYTE(lines, xp + 1);
2311  v11_val = v10_val;
2312  } else if (xp > wm2 && yp <= hm2) { /* pixels near rt side */
2313  v01_val = GET_DATA_BYTE(lines + wpls, xp);
2314  v10_val = v00_val;
2315  v11_val = v01_val;
2316  } else { /* pixels at LR corner */
2317  v10_val = v01_val = v11_val = v00_val;
2318  }
2319  } else {
2320  v10_val = GET_DATA_BYTE(lines, xp + 1);
2321  v01_val = GET_DATA_BYTE(lines + wpls, xp);
2322  v11_val = GET_DATA_BYTE(lines + wpls, xp + 1);
2323  }
2324 
2325  v00 = (16 - xf) * (16 - yf) * v00_val;
2326  v10 = xf * (16 - yf) * v10_val;
2327  v01 = (16 - xf) * yf * v01_val;
2328  v11 = xf * yf * v11_val;
2329 
2330  val = (l_uint8)((v00 + v01 + v10 + v11 + 128) / 256);
2331  SET_DATA_BYTE(lined, j, val);
2332  }
2333  }
2334 }
2335 
2336 
2337 /*------------------------------------------------------------------*
2338  * 2x linear interpolated color scaling *
2339  *------------------------------------------------------------------*/
2379 static void
2380 scaleColor2xLILow(l_uint32 *datad,
2381  l_int32 wpld,
2382  l_uint32 *datas,
2383  l_int32 ws,
2384  l_int32 hs,
2385  l_int32 wpls)
2386 {
2387 l_int32 i, hsm;
2388 l_uint32 *lines, *lined;
2389 
2390  hsm = hs - 1;
2391 
2392  /* We're taking 2 src and 2 dest lines at a time,
2393  * and for each src line, we're computing 2 dest lines.
2394  * Call these 2 dest lines: destline1 and destline2.
2395  * The first src line is used for destline 1.
2396  * On all but the last src line, both src lines are
2397  * used in the linear interpolation for destline2.
2398  * On the last src line, both destline1 and destline2
2399  * are computed using only that src line (because there
2400  * isn't a lower src line). */
2401 
2402  /* iterate over all but the last src line */
2403  for (i = 0; i < hsm; i++) {
2404  lines = datas + i * wpls;
2405  lined = datad + 2 * i * wpld;
2406  scaleColor2xLILineLow(lined, wpld, lines, ws, wpls, 0);
2407  }
2408 
2409  /* last src line */
2410  lines = datas + hsm * wpls;
2411  lined = datad + 2 * hsm * wpld;
2412  scaleColor2xLILineLow(lined, wpld, lines, ws, wpls, 1);
2413 }
2414 
2415 
2427 static void
2428 scaleColor2xLILineLow(l_uint32 *lined,
2429  l_int32 wpld,
2430  l_uint32 *lines,
2431  l_int32 ws,
2432  l_int32 wpls,
2433  l_int32 lastlineflag)
2434 {
2435 l_int32 j, jd, wsm;
2436 l_int32 rval1, rval2, rval3, rval4, gval1, gval2, gval3, gval4;
2437 l_int32 bval1, bval2, bval3, bval4;
2438 l_uint32 pixels1, pixels2, pixels3, pixels4, pixel;
2439 l_uint32 *linesp, *linedp;
2440 
2441  wsm = ws - 1;
2442 
2443  if (lastlineflag == 0) {
2444  linesp = lines + wpls;
2445  linedp = lined + wpld;
2446  pixels1 = *lines;
2447  pixels3 = *linesp;
2448 
2449  /* initialize with v(2) and v(4) */
2450  rval2 = pixels1 >> 24;
2451  gval2 = (pixels1 >> 16) & 0xff;
2452  bval2 = (pixels1 >> 8) & 0xff;
2453  rval4 = pixels3 >> 24;
2454  gval4 = (pixels3 >> 16) & 0xff;
2455  bval4 = (pixels3 >> 8) & 0xff;
2456 
2457  for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
2458  /* shift in previous src values */
2459  rval1 = rval2;
2460  gval1 = gval2;
2461  bval1 = bval2;
2462  rval3 = rval4;
2463  gval3 = gval4;
2464  bval3 = bval4;
2465  /* get new src values */
2466  pixels2 = *(lines + j + 1);
2467  pixels4 = *(linesp + j + 1);
2468  rval2 = pixels2 >> 24;
2469  gval2 = (pixels2 >> 16) & 0xff;
2470  bval2 = (pixels2 >> 8) & 0xff;
2471  rval4 = pixels4 >> 24;
2472  gval4 = (pixels4 >> 16) & 0xff;
2473  bval4 = (pixels4 >> 8) & 0xff;
2474  /* save dest values */
2475  pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
2476  *(lined + jd) = pixel; /* pix 1 */
2477  pixel = ((((rval1 + rval2) << 23) & 0xff000000) |
2478  (((gval1 + gval2) << 15) & 0x00ff0000) |
2479  (((bval1 + bval2) << 7) & 0x0000ff00));
2480  *(lined + jd + 1) = pixel; /* pix 2 */
2481  pixel = ((((rval1 + rval3) << 23) & 0xff000000) |
2482  (((gval1 + gval3) << 15) & 0x00ff0000) |
2483  (((bval1 + bval3) << 7) & 0x0000ff00));
2484  *(linedp + jd) = pixel; /* pix 3 */
2485  pixel = ((((rval1 + rval2 + rval3 + rval4) << 22) & 0xff000000) |
2486  (((gval1 + gval2 + gval3 + gval4) << 14) & 0x00ff0000) |
2487  (((bval1 + bval2 + bval3 + bval4) << 6) & 0x0000ff00));
2488  *(linedp + jd + 1) = pixel; /* pix 4 */
2489  }
2490  /* last src pixel on line */
2491  rval1 = rval2;
2492  gval1 = gval2;
2493  bval1 = bval2;
2494  rval3 = rval4;
2495  gval3 = gval4;
2496  bval3 = bval4;
2497  pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
2498  *(lined + 2 * wsm) = pixel; /* pix 1 */
2499  *(lined + 2 * wsm + 1) = pixel; /* pix 2 */
2500  pixel = ((((rval1 + rval3) << 23) & 0xff000000) |
2501  (((gval1 + gval3) << 15) & 0x00ff0000) |
2502  (((bval1 + bval3) << 7) & 0x0000ff00));
2503  *(linedp + 2 * wsm) = pixel; /* pix 3 */
2504  *(linedp + 2 * wsm + 1) = pixel; /* pix 4 */
2505  } else { /* last row of src pixels: lastlineflag == 1 */
2506  linedp = lined + wpld;
2507  pixels2 = *lines;
2508  rval2 = pixels2 >> 24;
2509  gval2 = (pixels2 >> 16) & 0xff;
2510  bval2 = (pixels2 >> 8) & 0xff;
2511  for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
2512  rval1 = rval2;
2513  gval1 = gval2;
2514  bval1 = bval2;
2515  pixels2 = *(lines + j + 1);
2516  rval2 = pixels2 >> 24;
2517  gval2 = (pixels2 >> 16) & 0xff;
2518  bval2 = (pixels2 >> 8) & 0xff;
2519  pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
2520  *(lined + jd) = pixel; /* pix 1 */
2521  *(linedp + jd) = pixel; /* pix 2 */
2522  pixel = ((((rval1 + rval2) << 23) & 0xff000000) |
2523  (((gval1 + gval2) << 15) & 0x00ff0000) |
2524  (((bval1 + bval2) << 7) & 0x0000ff00));
2525  *(lined + jd + 1) = pixel; /* pix 3 */
2526  *(linedp + jd + 1) = pixel; /* pix 4 */
2527  }
2528  rval1 = rval2;
2529  gval1 = gval2;
2530  bval1 = bval2;
2531  pixel = (rval1 << 24 | gval1 << 16 | bval1 << 8);
2532  *(lined + 2 * wsm) = pixel; /* pix 1 */
2533  *(lined + 2 * wsm + 1) = pixel; /* pix 2 */
2534  *(linedp + 2 * wsm) = pixel; /* pix 3 */
2535  *(linedp + 2 * wsm + 1) = pixel; /* pix 4 */
2536  }
2537 }
2538 
2539 
2540 /*------------------------------------------------------------------*
2541  * 2x linear interpolated gray scaling *
2542  *------------------------------------------------------------------*/
2578 static void
2579 scaleGray2xLILow(l_uint32 *datad,
2580  l_int32 wpld,
2581  l_uint32 *datas,
2582  l_int32 ws,
2583  l_int32 hs,
2584  l_int32 wpls)
2585 {
2586 l_int32 i, hsm;
2587 l_uint32 *lines, *lined;
2588 
2589  hsm = hs - 1;
2590 
2591  /* We're taking 2 src and 2 dest lines at a time,
2592  * and for each src line, we're computing 2 dest lines.
2593  * Call these 2 dest lines: destline1 and destline2.
2594  * The first src line is used for destline 1.
2595  * On all but the last src line, both src lines are
2596  * used in the linear interpolation for destline2.
2597  * On the last src line, both destline1 and destline2
2598  * are computed using only that src line (because there
2599  * isn't a lower src line). */
2600 
2601  /* iterate over all but the last src line */
2602  for (i = 0; i < hsm; i++) {
2603  lines = datas + i * wpls;
2604  lined = datad + 2 * i * wpld;
2605  scaleGray2xLILineLow(lined, wpld, lines, ws, wpls, 0);
2606  }
2607 
2608  /* last src line */
2609  lines = datas + hsm * wpls;
2610  lined = datad + 2 * hsm * wpld;
2611  scaleGray2xLILineLow(lined, wpld, lines, ws, wpls, 1);
2612 }
2613 
2614 
2626 static void
2627 scaleGray2xLILineLow(l_uint32 *lined,
2628  l_int32 wpld,
2629  l_uint32 *lines,
2630  l_int32 ws,
2631  l_int32 wpls,
2632  l_int32 lastlineflag)
2633 {
2634 l_int32 j, jd, wsm, w;
2635 l_int32 sval1, sval2, sval3, sval4;
2636 l_uint32 *linesp, *linedp;
2637 l_uint32 words, wordsp, wordd, worddp;
2638 
2639  wsm = ws - 1;
2640 
2641  if (lastlineflag == 0) {
2642  linesp = lines + wpls;
2643  linedp = lined + wpld;
2644 
2645  /* Unroll the loop 4x and work on full words */
2646  words = lines[0];
2647  wordsp = linesp[0];
2648  sval2 = (words >> 24) & 0xff;
2649  sval4 = (wordsp >> 24) & 0xff;
2650  for (j = 0, jd = 0, w = 0; j + 3 < wsm; j += 4, jd += 8, w++) {
2651  /* At the top of the loop,
2652  * words == lines[w], wordsp == linesp[w]
2653  * and the top bytes of those have been loaded into
2654  * sval2 and sval4. */
2655  sval1 = sval2;
2656  sval2 = (words >> 16) & 0xff;
2657  sval3 = sval4;
2658  sval4 = (wordsp >> 16) & 0xff;
2659  wordd = (sval1 << 24) | (((sval1 + sval2) >> 1) << 16);
2660  worddp = (((sval1 + sval3) >> 1) << 24) |
2661  (((sval1 + sval2 + sval3 + sval4) >> 2) << 16);
2662 
2663  sval1 = sval2;
2664  sval2 = (words >> 8) & 0xff;
2665  sval3 = sval4;
2666  sval4 = (wordsp >> 8) & 0xff;
2667  wordd |= (sval1 << 8) | ((sval1 + sval2) >> 1);
2668  worddp |= (((sval1 + sval3) >> 1) << 8) |
2669  ((sval1 + sval2 + sval3 + sval4) >> 2);
2670  lined[w * 2] = wordd;
2671  linedp[w * 2] = worddp;
2672 
2673  sval1 = sval2;
2674  sval2 = words & 0xff;
2675  sval3 = sval4;
2676  sval4 = wordsp & 0xff;
2677  wordd = (sval1 << 24) | /* pix 1 */
2678  (((sval1 + sval2) >> 1) << 16); /* pix 2 */
2679  worddp = (((sval1 + sval3) >> 1) << 24) | /* pix 3 */
2680  (((sval1 + sval2 + sval3 + sval4) >> 2) << 16); /* pix 4 */
2681 
2682  /* Load the next word as we need its first byte */
2683  words = lines[w + 1];
2684  wordsp = linesp[w + 1];
2685  sval1 = sval2;
2686  sval2 = (words >> 24) & 0xff;
2687  sval3 = sval4;
2688  sval4 = (wordsp >> 24) & 0xff;
2689  wordd |= (sval1 << 8) | /* pix 1 */
2690  ((sval1 + sval2) >> 1); /* pix 2 */
2691  worddp |= (((sval1 + sval3) >> 1) << 8) | /* pix 3 */
2692  ((sval1 + sval2 + sval3 + sval4) >> 2); /* pix 4 */
2693  lined[w * 2 + 1] = wordd;
2694  linedp[w * 2 + 1] = worddp;
2695  }
2696 
2697  /* Finish up the last word */
2698  for (; j < wsm; j++, jd += 2) {
2699  sval1 = sval2;
2700  sval3 = sval4;
2701  sval2 = GET_DATA_BYTE(lines, j + 1);
2702  sval4 = GET_DATA_BYTE(linesp, j + 1);
2703  SET_DATA_BYTE(lined, jd, sval1); /* pix 1 */
2704  SET_DATA_BYTE(lined, jd + 1, (sval1 + sval2) / 2); /* pix 2 */
2705  SET_DATA_BYTE(linedp, jd, (sval1 + sval3) / 2); /* pix 3 */
2706  SET_DATA_BYTE(linedp, jd + 1,
2707  (sval1 + sval2 + sval3 + sval4) / 4); /* pix 4 */
2708  }
2709  sval1 = sval2;
2710  sval3 = sval4;
2711  SET_DATA_BYTE(lined, 2 * wsm, sval1); /* pix 1 */
2712  SET_DATA_BYTE(lined, 2 * wsm + 1, sval1); /* pix 2 */
2713  SET_DATA_BYTE(linedp, 2 * wsm, (sval1 + sval3) / 2); /* pix 3 */
2714  SET_DATA_BYTE(linedp, 2 * wsm + 1, (sval1 + sval3) / 2); /* pix 4 */
2715 
2716 #if DEBUG_UNROLLING
2717 #define CHECK_BYTE(a, b, c) if (GET_DATA_BYTE(a, b) != c) {\
2718  fprintf(stderr, "Error: mismatch at %d, %d vs %d\n", \
2719  j, GET_DATA_BYTE(a, b), c); }
2720 
2721  sval2 = GET_DATA_BYTE(lines, 0);
2722  sval4 = GET_DATA_BYTE(linesp, 0);
2723  for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
2724  sval1 = sval2;
2725  sval3 = sval4;
2726  sval2 = GET_DATA_BYTE(lines, j + 1);
2727  sval4 = GET_DATA_BYTE(linesp, j + 1);
2728  CHECK_BYTE(lined, jd, sval1); /* pix 1 */
2729  CHECK_BYTE(lined, jd + 1, (sval1 + sval2) / 2); /* pix 2 */
2730  CHECK_BYTE(linedp, jd, (sval1 + sval3) / 2); /* pix 3 */
2731  CHECK_BYTE(linedp, jd + 1,
2732  (sval1 + sval2 + sval3 + sval4) / 4); /* pix 4 */
2733  }
2734  sval1 = sval2;
2735  sval3 = sval4;
2736  CHECK_BYTE(lined, 2 * wsm, sval1); /* pix 1 */
2737  CHECK_BYTE(lined, 2 * wsm + 1, sval1); /* pix 2 */
2738  CHECK_BYTE(linedp, 2 * wsm, (sval1 + sval3) / 2); /* pix 3 */
2739  CHECK_BYTE(linedp, 2 * wsm + 1, (sval1 + sval3) / 2); /* pix 4 */
2740 #undef CHECK_BYTE
2741 #endif
2742  } else { /* last row of src pixels: lastlineflag == 1 */
2743  linedp = lined + wpld;
2744  sval2 = GET_DATA_BYTE(lines, 0);
2745  for (j = 0, jd = 0; j < wsm; j++, jd += 2) {
2746  sval1 = sval2;
2747  sval2 = GET_DATA_BYTE(lines, j + 1);
2748  SET_DATA_BYTE(lined, jd, sval1); /* pix 1 */
2749  SET_DATA_BYTE(linedp, jd, sval1); /* pix 3 */
2750  SET_DATA_BYTE(lined, jd + 1, (sval1 + sval2) / 2); /* pix 2 */
2751  SET_DATA_BYTE(linedp, jd + 1, (sval1 + sval2) / 2); /* pix 4 */
2752  }
2753  sval1 = sval2;
2754  SET_DATA_BYTE(lined, 2 * wsm, sval1); /* pix 1 */
2755  SET_DATA_BYTE(lined, 2 * wsm + 1, sval1); /* pix 2 */
2756  SET_DATA_BYTE(linedp, 2 * wsm, sval1); /* pix 3 */
2757  SET_DATA_BYTE(linedp, 2 * wsm + 1, sval1); /* pix 4 */
2758  }
2759 }
2760 
2761 
2762 /*------------------------------------------------------------------*
2763  * 4x linear interpolated gray scaling *
2764  *------------------------------------------------------------------*/
2816 static void
2817 scaleGray4xLILow(l_uint32 *datad,
2818  l_int32 wpld,
2819  l_uint32 *datas,
2820  l_int32 ws,
2821  l_int32 hs,
2822  l_int32 wpls)
2823 {
2824 l_int32 i, hsm;
2825 l_uint32 *lines, *lined;
2826 
2827  hsm = hs - 1;
2828 
2829  /* We're taking 2 src and 4 dest lines at a time,
2830  * and for each src line, we're computing 4 dest lines.
2831  * Call these 4 dest lines: destline1 - destline4.
2832  * The first src line is used for destline 1.
2833  * Two src lines are used for all other dest lines,
2834  * except for the last 4 dest lines, which are computed
2835  * using only the last src line. */
2836 
2837  /* iterate over all but the last src line */
2838  for (i = 0; i < hsm; i++) {
2839  lines = datas + i * wpls;
2840  lined = datad + 4 * i * wpld;
2841  scaleGray4xLILineLow(lined, wpld, lines, ws, wpls, 0);
2842  }
2843 
2844  /* last src line */
2845  lines = datas + hsm * wpls;
2846  lined = datad + 4 * hsm * wpld;
2847  scaleGray4xLILineLow(lined, wpld, lines, ws, wpls, 1);
2848 }
2849 
2850 
2862 static void
2863 scaleGray4xLILineLow(l_uint32 *lined,
2864  l_int32 wpld,
2865  l_uint32 *lines,
2866  l_int32 ws,
2867  l_int32 wpls,
2868  l_int32 lastlineflag)
2869 {
2870 l_int32 j, jd, wsm, wsm4;
2871 l_int32 s1, s2, s3, s4, s1t, s2t, s3t, s4t;
2872 l_uint32 *linesp, *linedp1, *linedp2, *linedp3;
2873 
2874  wsm = ws - 1;
2875  wsm4 = 4 * wsm;
2876 
2877  if (lastlineflag == 0) {
2878  linesp = lines + wpls;
2879  linedp1 = lined + wpld;
2880  linedp2 = lined + 2 * wpld;
2881  linedp3 = lined + 3 * wpld;
2882  s2 = GET_DATA_BYTE(lines, 0);
2883  s4 = GET_DATA_BYTE(linesp, 0);
2884  for (j = 0, jd = 0; j < wsm; j++, jd += 4) {
2885  s1 = s2;
2886  s3 = s4;
2887  s2 = GET_DATA_BYTE(lines, j + 1);
2888  s4 = GET_DATA_BYTE(linesp, j + 1);
2889  s1t = 3 * s1;
2890  s2t = 3 * s2;
2891  s3t = 3 * s3;
2892  s4t = 3 * s4;
2893  SET_DATA_BYTE(lined, jd, s1); /* d1 */
2894  SET_DATA_BYTE(lined, jd + 1, (s1t + s2) / 4); /* d2 */
2895  SET_DATA_BYTE(lined, jd + 2, (s1 + s2) / 2); /* d3 */
2896  SET_DATA_BYTE(lined, jd + 3, (s1 + s2t) / 4); /* d4 */
2897  SET_DATA_BYTE(linedp1, jd, (s1t + s3) / 4); /* d5 */
2898  SET_DATA_BYTE(linedp1, jd + 1, (9*s1 + s2t + s3t + s4) / 16); /*d6*/
2899  SET_DATA_BYTE(linedp1, jd + 2, (s1t + s2t + s3 + s4) / 8); /* d7 */
2900  SET_DATA_BYTE(linedp1, jd + 3, (s1t + 9*s2 + s3 + s4t) / 16);/*d8*/
2901  SET_DATA_BYTE(linedp2, jd, (s1 + s3) / 2); /* d9 */
2902  SET_DATA_BYTE(linedp2, jd + 1, (s1t + s2 + s3t + s4) / 8);/* d10 */
2903  SET_DATA_BYTE(linedp2, jd + 2, (s1 + s2 + s3 + s4) / 4); /* d11 */
2904  SET_DATA_BYTE(linedp2, jd + 3, (s1 + s2t + s3 + s4t) / 8);/* d12 */
2905  SET_DATA_BYTE(linedp3, jd, (s1 + s3t) / 4); /* d13 */
2906  SET_DATA_BYTE(linedp3, jd + 1, (s1t + s2 + 9*s3 + s4t) / 16);/*d14*/
2907  SET_DATA_BYTE(linedp3, jd + 2, (s1 + s2 + s3t + s4t) / 8); /* d15 */
2908  SET_DATA_BYTE(linedp3, jd + 3, (s1 + s2t + s3t + 9*s4) / 16);/*d16*/
2909  }
2910  s1 = s2;
2911  s3 = s4;
2912  s1t = 3 * s1;
2913  s3t = 3 * s3;
2914  SET_DATA_BYTE(lined, wsm4, s1); /* d1 */
2915  SET_DATA_BYTE(lined, wsm4 + 1, s1); /* d2 */
2916  SET_DATA_BYTE(lined, wsm4 + 2, s1); /* d3 */
2917  SET_DATA_BYTE(lined, wsm4 + 3, s1); /* d4 */
2918  SET_DATA_BYTE(linedp1, wsm4, (s1t + s3) / 4); /* d5 */
2919  SET_DATA_BYTE(linedp1, wsm4 + 1, (s1t + s3) / 4); /* d6 */
2920  SET_DATA_BYTE(linedp1, wsm4 + 2, (s1t + s3) / 4); /* d7 */
2921  SET_DATA_BYTE(linedp1, wsm4 + 3, (s1t + s3) / 4); /* d8 */
2922  SET_DATA_BYTE(linedp2, wsm4, (s1 + s3) / 2); /* d9 */
2923  SET_DATA_BYTE(linedp2, wsm4 + 1, (s1 + s3) / 2); /* d10 */
2924  SET_DATA_BYTE(linedp2, wsm4 + 2, (s1 + s3) / 2); /* d11 */
2925  SET_DATA_BYTE(linedp2, wsm4 + 3, (s1 + s3) / 2); /* d12 */
2926  SET_DATA_BYTE(linedp3, wsm4, (s1 + s3t) / 4); /* d13 */
2927  SET_DATA_BYTE(linedp3, wsm4 + 1, (s1 + s3t) / 4); /* d14 */
2928  SET_DATA_BYTE(linedp3, wsm4 + 2, (s1 + s3t) / 4); /* d15 */
2929  SET_DATA_BYTE(linedp3, wsm4 + 3, (s1 + s3t) / 4); /* d16 */
2930  } else { /* last row of src pixels: lastlineflag == 1 */
2931  linedp1 = lined + wpld;
2932  linedp2 = lined + 2 * wpld;
2933  linedp3 = lined + 3 * wpld;
2934  s2 = GET_DATA_BYTE(lines, 0);
2935  for (j = 0, jd = 0; j < wsm; j++, jd += 4) {
2936  s1 = s2;
2937  s2 = GET_DATA_BYTE(lines, j + 1);
2938  s1t = 3 * s1;
2939  s2t = 3 * s2;
2940  SET_DATA_BYTE(lined, jd, s1); /* d1 */
2941  SET_DATA_BYTE(lined, jd + 1, (s1t + s2) / 4 ); /* d2 */
2942  SET_DATA_BYTE(lined, jd + 2, (s1 + s2) / 2 ); /* d3 */
2943  SET_DATA_BYTE(lined, jd + 3, (s1 + s2t) / 4 ); /* d4 */
2944  SET_DATA_BYTE(linedp1, jd, s1); /* d5 */
2945  SET_DATA_BYTE(linedp1, jd + 1, (s1t + s2) / 4 ); /* d6 */
2946  SET_DATA_BYTE(linedp1, jd + 2, (s1 + s2) / 2 ); /* d7 */
2947  SET_DATA_BYTE(linedp1, jd + 3, (s1 + s2t) / 4 ); /* d8 */
2948  SET_DATA_BYTE(linedp2, jd, s1); /* d9 */
2949  SET_DATA_BYTE(linedp2, jd + 1, (s1t + s2) / 4 ); /* d10 */
2950  SET_DATA_BYTE(linedp2, jd + 2, (s1 + s2) / 2 ); /* d11 */
2951  SET_DATA_BYTE(linedp2, jd + 3, (s1 + s2t) / 4 ); /* d12 */
2952  SET_DATA_BYTE(linedp3, jd, s1); /* d13 */
2953  SET_DATA_BYTE(linedp3, jd + 1, (s1t + s2) / 4 ); /* d14 */
2954  SET_DATA_BYTE(linedp3, jd + 2, (s1 + s2) / 2 ); /* d15 */
2955  SET_DATA_BYTE(linedp3, jd + 3, (s1 + s2t) / 4 ); /* d16 */
2956  }
2957  s1 = s2;
2958  SET_DATA_BYTE(lined, wsm4, s1); /* d1 */
2959  SET_DATA_BYTE(lined, wsm4 + 1, s1); /* d2 */
2960  SET_DATA_BYTE(lined, wsm4 + 2, s1); /* d3 */
2961  SET_DATA_BYTE(lined, wsm4 + 3, s1); /* d4 */
2962  SET_DATA_BYTE(linedp1, wsm4, s1); /* d5 */
2963  SET_DATA_BYTE(linedp1, wsm4 + 1, s1); /* d6 */
2964  SET_DATA_BYTE(linedp1, wsm4 + 2, s1); /* d7 */
2965  SET_DATA_BYTE(linedp1, wsm4 + 3, s1); /* d8 */
2966  SET_DATA_BYTE(linedp2, wsm4, s1); /* d9 */
2967  SET_DATA_BYTE(linedp2, wsm4 + 1, s1); /* d10 */
2968  SET_DATA_BYTE(linedp2, wsm4 + 2, s1); /* d11 */
2969  SET_DATA_BYTE(linedp2, wsm4 + 3, s1); /* d12 */
2970  SET_DATA_BYTE(linedp3, wsm4, s1); /* d13 */
2971  SET_DATA_BYTE(linedp3, wsm4 + 1, s1); /* d14 */
2972  SET_DATA_BYTE(linedp3, wsm4 + 2, s1); /* d15 */
2973  SET_DATA_BYTE(linedp3, wsm4 + 3, s1); /* d16 */
2974  }
2975 }
2976 
2977 
2978 /*------------------------------------------------------------------*
2979  * Grayscale and color scaling by closest pixel sampling *
2980  *------------------------------------------------------------------*/
2994 static l_int32
2995 scaleBySamplingLow(l_uint32 *datad,
2996  l_int32 wd,
2997  l_int32 hd,
2998  l_int32 wpld,
2999  l_uint32 *datas,
3000  l_int32 ws,
3001  l_int32 hs,
3002  l_int32 d,
3003  l_int32 wpls)
3004 {
3005 l_int32 i, j, bpld;
3006 l_int32 xs, prevxs, sval;
3007 l_int32 *srow, *scol;
3008 l_uint32 csval;
3009 l_uint32 *lines, *prevlines, *lined, *prevlined;
3010 l_float32 wratio, hratio;
3011 
3012  PROCNAME("scaleBySamplingLow");
3013 
3014  if (d != 2 && d != 4 && d !=8 && d != 16 && d != 32)
3015  return ERROR_INT("pixel depth not supported", procName, 1);
3016 
3017  /* clear dest */
3018  bpld = 4 * wpld;
3019  memset((char *)datad, 0, hd * bpld);
3020 
3021  /* the source row corresponding to dest row i ==> srow[i]
3022  * the source col corresponding to dest col j ==> scol[j] */
3023  if ((srow = (l_int32 *)LEPT_CALLOC(hd, sizeof(l_int32))) == NULL)
3024  return ERROR_INT("srow not made", procName, 1);
3025  if ((scol = (l_int32 *)LEPT_CALLOC(wd, sizeof(l_int32))) == NULL) {
3026  LEPT_FREE(srow);
3027  return ERROR_INT("scol not made", procName, 1);
3028  }
3029 
3030  wratio = (l_float32)ws / (l_float32)wd;
3031  hratio = (l_float32)hs / (l_float32)hd;
3032  for (i = 0; i < hd; i++)
3033  srow[i] = L_MIN((l_int32)(hratio * i + 0.5), hs - 1);
3034  for (j = 0; j < wd; j++)
3035  scol[j] = L_MIN((l_int32)(wratio * j + 0.5), ws - 1);
3036 
3037  prevlines = NULL;
3038  for (i = 0; i < hd; i++) {
3039  lines = datas + srow[i] * wpls;
3040  lined = datad + i * wpld;
3041  if (lines != prevlines) { /* make dest from new source row */
3042  prevxs = -1;
3043  sval = 0;
3044  csval = 0;
3045  if (d == 2) {
3046  for (j = 0; j < wd; j++) {
3047  xs = scol[j];
3048  if (xs != prevxs) { /* get dest pix from source col */
3049  sval = GET_DATA_DIBIT(lines, xs);
3050  SET_DATA_DIBIT(lined, j, sval);
3051  prevxs = xs;
3052  } else { /* copy prev dest pix */
3053  SET_DATA_DIBIT(lined, j, sval);
3054  }
3055  }
3056  } else if (d == 4) {
3057  for (j = 0; j < wd; j++) {
3058  xs = scol[j];
3059  if (xs != prevxs) { /* get dest pix from source col */
3060  sval = GET_DATA_QBIT(lines, xs);
3061  SET_DATA_QBIT(lined, j, sval);
3062  prevxs = xs;
3063  } else { /* copy prev dest pix */
3064  SET_DATA_QBIT(lined, j, sval);
3065  }
3066  }
3067  } else if (d == 8) {
3068  for (j = 0; j < wd; j++) {
3069  xs = scol[j];
3070  if (xs != prevxs) { /* get dest pix from source col */
3071  sval = GET_DATA_BYTE(lines, xs);
3072  SET_DATA_BYTE(lined, j, sval);
3073  prevxs = xs;
3074  } else { /* copy prev dest pix */
3075  SET_DATA_BYTE(lined, j, sval);
3076  }
3077  }
3078  } else if (d == 16) {
3079  for (j = 0; j < wd; j++) {
3080  xs = scol[j];
3081  if (xs != prevxs) { /* get dest pix from source col */
3082  sval = GET_DATA_TWO_BYTES(lines, xs);
3083  SET_DATA_TWO_BYTES(lined, j, sval);
3084  prevxs = xs;
3085  } else { /* copy prev dest pix */
3086  SET_DATA_TWO_BYTES(lined, j, sval);
3087  }
3088  }
3089  } else { /* d == 32 */
3090  for (j = 0; j < wd; j++) {
3091  xs = scol[j];
3092  if (xs != prevxs) { /* get dest pix from source col */
3093  csval = lines[xs];
3094  lined[j] = csval;
3095  prevxs = xs;
3096  } else { /* copy prev dest pix */
3097  lined[j] = csval;
3098  }
3099  }
3100  }
3101  } else { /* lines == prevlines; copy prev dest row */
3102  prevlined = lined - wpld;
3103  memcpy((char *)lined, (char *)prevlined, bpld);
3104  }
3105  prevlines = lines;
3106  }
3107 
3108  LEPT_FREE(srow);
3109  LEPT_FREE(scol);
3110  return 0;
3111 }
3112 
3113 
3114 /*------------------------------------------------------------------*
3115  * Color and grayscale downsampling with (antialias) smoothing *
3116  *------------------------------------------------------------------*/
3126 static l_int32
3127 scaleSmoothLow(l_uint32 *datad,
3128  l_int32 wd,
3129  l_int32 hd,
3130  l_int32 wpld,
3131  l_uint32 *datas,
3132  l_int32 ws,
3133  l_int32 hs,
3134  l_int32 d,
3135  l_int32 wpls,
3136  l_int32 size)
3137 {
3138 l_int32 i, j, m, n, xstart;
3139 l_int32 val, rval, gval, bval;
3140 l_int32 *srow, *scol;
3141 l_uint32 *lines, *lined, *line, *ppixel;
3142 l_uint32 pixel;
3143 l_float32 wratio, hratio, norm;
3144 
3145  PROCNAME("scaleSmoothLow");
3146 
3147  /* Clear dest */
3148  memset((char *)datad, 0, 4 * wpld * hd);
3149 
3150  /* Each dest pixel at (j,i) is computed as the average
3151  of size^2 corresponding src pixels.
3152  We store the UL corner location of the square of
3153  src pixels that correspond to dest pixel (j,i).
3154  The are labeled by the arrays srow[i] and scol[j]. */
3155  if ((srow = (l_int32 *)LEPT_CALLOC(hd, sizeof(l_int32))) == NULL)
3156  return ERROR_INT("srow not made", procName, 1);
3157  if ((scol = (l_int32 *)LEPT_CALLOC(wd, sizeof(l_int32))) == NULL) {
3158  LEPT_FREE(srow);
3159  return ERROR_INT("scol not made", procName, 1);
3160  }
3161 
3162  norm = 1. / (l_float32)(size * size);
3163  wratio = (l_float32)ws / (l_float32)wd;
3164  hratio = (l_float32)hs / (l_float32)hd;
3165  for (i = 0; i < hd; i++)
3166  srow[i] = L_MIN((l_int32)(hratio * i), hs - size);
3167  for (j = 0; j < wd; j++)
3168  scol[j] = L_MIN((l_int32)(wratio * j), ws - size);
3169 
3170  /* For each dest pixel, compute average */
3171  if (d == 8) {
3172  for (i = 0; i < hd; i++) {
3173  lines = datas + srow[i] * wpls;
3174  lined = datad + i * wpld;
3175  for (j = 0; j < wd; j++) {
3176  xstart = scol[j];
3177  val = 0;
3178  for (m = 0; m < size; m++) {
3179  line = lines + m * wpls;
3180  for (n = 0; n < size; n++) {
3181  val += GET_DATA_BYTE(line, xstart + n);
3182  }
3183  }
3184  val = (l_int32)((l_float32)val * norm);
3185  SET_DATA_BYTE(lined, j, val);
3186  }
3187  }
3188  } else { /* d == 32 */
3189  for (i = 0; i < hd; i++) {
3190  lines = datas + srow[i] * wpls;
3191  lined = datad + i * wpld;
3192  for (j = 0; j < wd; j++) {
3193  xstart = scol[j];
3194  rval = gval = bval = 0;
3195  for (m = 0; m < size; m++) {
3196  ppixel = lines + m * wpls + xstart;
3197  for (n = 0; n < size; n++) {
3198  pixel = *(ppixel + n);
3199  rval += (pixel >> L_RED_SHIFT) & 0xff;
3200  gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3201  bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3202  }
3203  }
3204  rval = (l_int32)((l_float32)rval * norm);
3205  gval = (l_int32)((l_float32)gval * norm);
3206  bval = (l_int32)((l_float32)bval * norm);
3207  *(lined + j) = rval << L_RED_SHIFT |
3208  gval << L_GREEN_SHIFT |
3209  bval << L_BLUE_SHIFT;
3210  }
3211  }
3212  }
3213 
3214  LEPT_FREE(srow);
3215  LEPT_FREE(scol);
3216  return 0;
3217 }
3218 
3219 
3227 static void
3228 scaleRGBToGray2Low(l_uint32 *datad,
3229  l_int32 wd,
3230  l_int32 hd,
3231  l_int32 wpld,
3232  l_uint32 *datas,
3233  l_int32 wpls,
3234  l_float32 rwt,
3235  l_float32 gwt,
3236  l_float32 bwt)
3237 {
3238 l_int32 i, j, val, rval, gval, bval;
3239 l_uint32 *lines, *lined;
3240 l_uint32 pixel;
3241 
3242  rwt *= 0.25;
3243  gwt *= 0.25;
3244  bwt *= 0.25;
3245  for (i = 0; i < hd; i++) {
3246  lines = datas + 2 * i * wpls;
3247  lined = datad + i * wpld;
3248  for (j = 0; j < wd; j++) {
3249  /* Sum each of the color components from 4 src pixels */
3250  pixel = *(lines + 2 * j);
3251  rval = (pixel >> L_RED_SHIFT) & 0xff;
3252  gval = (pixel >> L_GREEN_SHIFT) & 0xff;
3253  bval = (pixel >> L_BLUE_SHIFT) & 0xff;
3254  pixel = *(lines + 2 * j + 1);
3255  rval += (pixel >> L_RED_SHIFT) & 0xff;
3256  gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3257  bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3258  pixel = *(lines + wpls + 2 * j);
3259  rval += (pixel >> L_RED_SHIFT) & 0xff;
3260  gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3261  bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3262  pixel = *(lines + wpls + 2 * j + 1);
3263  rval += (pixel >> L_RED_SHIFT) & 0xff;
3264  gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3265  bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3266  /* Generate the dest byte as a weighted sum of the averages */
3267  val = (l_int32)(rwt * rval + gwt * gval + bwt * bval);
3268  SET_DATA_BYTE(lined, j, val);
3269  }
3270  }
3271 }
3272 
3273 
3274 /*------------------------------------------------------------------*
3275  * General area mapped gray scaling *
3276  *------------------------------------------------------------------*/
3289 static void
3290 scaleColorAreaMapLow(l_uint32 *datad,
3291  l_int32 wd,
3292  l_int32 hd,
3293  l_int32 wpld,
3294  l_uint32 *datas,
3295  l_int32 ws,
3296  l_int32 hs,
3297  l_int32 wpls)
3298 {
3299 l_int32 i, j, k, m, wm2, hm2;
3300 l_int32 area00, area10, area01, area11, areal, arear, areat, areab;
3301 l_int32 xu, yu; /* UL corner in src image, to 1/16 of a pixel */
3302 l_int32 xl, yl; /* LR corner in src image, to 1/16 of a pixel */
3303 l_int32 xup, yup, xuf, yuf; /* UL src pixel: integer and fraction */
3304 l_int32 xlp, ylp, xlf, ylf; /* LR src pixel: integer and fraction */
3305 l_int32 delx, dely, area;
3306 l_int32 v00r, v00g, v00b; /* contrib. from UL src pixel */
3307 l_int32 v01r, v01g, v01b; /* contrib. from LL src pixel */
3308 l_int32 v10r, v10g, v10b; /* contrib from UR src pixel */
3309 l_int32 v11r, v11g, v11b; /* contrib from LR src pixel */
3310 l_int32 vinr, ving, vinb; /* contrib from all full interior src pixels */
3311 l_int32 vmidr, vmidg, vmidb; /* contrib from side parts */
3312 l_int32 rval, gval, bval;
3313 l_uint32 pixel00, pixel10, pixel01, pixel11, pixel;
3314 l_uint32 *lines, *lined;
3315 l_float32 scx, scy;
3316 
3317  /* (scx, scy) are scaling factors that are applied to the
3318  * dest coords to get the corresponding src coords.
3319  * We need them because we iterate over dest pixels
3320  * and must find the corresponding set of src pixels. */
3321  scx = 16. * (l_float32)ws / (l_float32)wd;
3322  scy = 16. * (l_float32)hs / (l_float32)hd;
3323  wm2 = ws - 2;
3324  hm2 = hs - 2;
3325 
3326  /* Iterate over the destination pixels */
3327  for (i = 0; i < hd; i++) {
3328  yu = (l_int32)(scy * i);
3329  yl = (l_int32)(scy * (i + 1.0));
3330  yup = yu >> 4;
3331  yuf = yu & 0x0f;
3332  ylp = yl >> 4;
3333  ylf = yl & 0x0f;
3334  dely = ylp - yup;
3335  lined = datad + i * wpld;
3336  lines = datas + yup * wpls;
3337  for (j = 0; j < wd; j++) {
3338  xu = (l_int32)(scx * j);
3339  xl = (l_int32)(scx * (j + 1.0));
3340  xup = xu >> 4;
3341  xuf = xu & 0x0f;
3342  xlp = xl >> 4;
3343  xlf = xl & 0x0f;
3344  delx = xlp - xup;
3345 
3346  /* If near the edge, just use a src pixel value */
3347  if (xlp > wm2 || ylp > hm2) {
3348  *(lined + j) = *(lines + xup);
3349  continue;
3350  }
3351 
3352  /* Area summed over, in subpixels. This varies
3353  * due to the quantization, so we can't simply take
3354  * the area to be a constant: area = scx * scy. */
3355  area = ((16 - xuf) + 16 * (delx - 1) + xlf) *
3356  ((16 - yuf) + 16 * (dely - 1) + ylf);
3357 
3358  /* Do area map summation */
3359  pixel00 = *(lines + xup);
3360  pixel10 = *(lines + xlp);
3361  pixel01 = *(lines + dely * wpls + xup);
3362  pixel11 = *(lines + dely * wpls + xlp);
3363  area00 = (16 - xuf) * (16 - yuf);
3364  area10 = xlf * (16 - yuf);
3365  area01 = (16 - xuf) * ylf;
3366  area11 = xlf * ylf;
3367  v00r = area00 * ((pixel00 >> L_RED_SHIFT) & 0xff);
3368  v00g = area00 * ((pixel00 >> L_GREEN_SHIFT) & 0xff);
3369  v00b = area00 * ((pixel00 >> L_BLUE_SHIFT) & 0xff);
3370  v10r = area10 * ((pixel10 >> L_RED_SHIFT) & 0xff);
3371  v10g = area10 * ((pixel10 >> L_GREEN_SHIFT) & 0xff);
3372  v10b = area10 * ((pixel10 >> L_BLUE_SHIFT) & 0xff);
3373  v01r = area01 * ((pixel01 >> L_RED_SHIFT) & 0xff);
3374  v01g = area01 * ((pixel01 >> L_GREEN_SHIFT) & 0xff);
3375  v01b = area01 * ((pixel01 >> L_BLUE_SHIFT) & 0xff);
3376  v11r = area11 * ((pixel11 >> L_RED_SHIFT) & 0xff);
3377  v11g = area11 * ((pixel11 >> L_GREEN_SHIFT) & 0xff);
3378  v11b = area11 * ((pixel11 >> L_BLUE_SHIFT) & 0xff);
3379  vinr = ving = vinb = 0;
3380  for (k = 1; k < dely; k++) { /* for full src pixels */
3381  for (m = 1; m < delx; m++) {
3382  pixel = *(lines + k * wpls + xup + m);
3383  vinr += 256 * ((pixel >> L_RED_SHIFT) & 0xff);
3384  ving += 256 * ((pixel >> L_GREEN_SHIFT) & 0xff);
3385  vinb += 256 * ((pixel >> L_BLUE_SHIFT) & 0xff);
3386  }
3387  }
3388  vmidr = vmidg = vmidb = 0;
3389  areal = (16 - xuf) * 16;
3390  arear = xlf * 16;
3391  areat = 16 * (16 - yuf);
3392  areab = 16 * ylf;
3393  for (k = 1; k < dely; k++) { /* for left side */
3394  pixel = *(lines + k * wpls + xup);
3395  vmidr += areal * ((pixel >> L_RED_SHIFT) & 0xff);
3396  vmidg += areal * ((pixel >> L_GREEN_SHIFT) & 0xff);
3397  vmidb += areal * ((pixel >> L_BLUE_SHIFT) & 0xff);
3398  }
3399  for (k = 1; k < dely; k++) { /* for right side */
3400  pixel = *(lines + k * wpls + xlp);
3401  vmidr += arear * ((pixel >> L_RED_SHIFT) & 0xff);
3402  vmidg += arear * ((pixel >> L_GREEN_SHIFT) & 0xff);
3403  vmidb += arear * ((pixel >> L_BLUE_SHIFT) & 0xff);
3404  }
3405  for (m = 1; m < delx; m++) { /* for top side */
3406  pixel = *(lines + xup + m);
3407  vmidr += areat * ((pixel >> L_RED_SHIFT) & 0xff);
3408  vmidg += areat * ((pixel >> L_GREEN_SHIFT) & 0xff);
3409  vmidb += areat * ((pixel >> L_BLUE_SHIFT) & 0xff);
3410  }
3411  for (m = 1; m < delx; m++) { /* for bottom side */
3412  pixel = *(lines + dely * wpls + xup + m);
3413  vmidr += areab * ((pixel >> L_RED_SHIFT) & 0xff);
3414  vmidg += areab * ((pixel >> L_GREEN_SHIFT) & 0xff);
3415  vmidb += areab * ((pixel >> L_BLUE_SHIFT) & 0xff);
3416  }
3417 
3418  /* Sum all the contributions */
3419  rval = (v00r + v01r + v10r + v11r + vinr + vmidr + 128) / area;
3420  gval = (v00g + v01g + v10g + v11g + ving + vmidg + 128) / area;
3421  bval = (v00b + v01b + v10b + v11b + vinb + vmidb + 128) / area;
3422 #if DEBUG_OVERFLOW
3423  if (rval > 255) fprintf(stderr, "rval ovfl: %d\n", rval);
3424  if (gval > 255) fprintf(stderr, "gval ovfl: %d\n", gval);
3425  if (bval > 255) fprintf(stderr, "bval ovfl: %d\n", bval);
3426 #endif /* DEBUG_OVERFLOW */
3427  composeRGBPixel(rval, gval, bval, lined + j);
3428  }
3429  }
3430 }
3431 
3432 
3444 static void
3445 scaleGrayAreaMapLow(l_uint32 *datad,
3446  l_int32 wd,
3447  l_int32 hd,
3448  l_int32 wpld,
3449  l_uint32 *datas,
3450  l_int32 ws,
3451  l_int32 hs,
3452  l_int32 wpls)
3453 {
3454 l_int32 i, j, k, m, wm2, hm2;
3455 l_int32 xu, yu; /* UL corner in src image, to 1/16 of a pixel */
3456 l_int32 xl, yl; /* LR corner in src image, to 1/16 of a pixel */
3457 l_int32 xup, yup, xuf, yuf; /* UL src pixel: integer and fraction */
3458 l_int32 xlp, ylp, xlf, ylf; /* LR src pixel: integer and fraction */
3459 l_int32 delx, dely, area;
3460 l_int32 v00; /* contrib. from UL src pixel */
3461 l_int32 v01; /* contrib. from LL src pixel */
3462 l_int32 v10; /* contrib from UR src pixel */
3463 l_int32 v11; /* contrib from LR src pixel */
3464 l_int32 vin; /* contrib from all full interior src pixels */
3465 l_int32 vmid; /* contrib from side parts that are full in 1 direction */
3466 l_int32 val;
3467 l_uint32 *lines, *lined;
3468 l_float32 scx, scy;
3469 
3470  /* (scx, scy) are scaling factors that are applied to the
3471  * dest coords to get the corresponding src coords.
3472  * We need them because we iterate over dest pixels
3473  * and must find the corresponding set of src pixels. */
3474  scx = 16. * (l_float32)ws / (l_float32)wd;
3475  scy = 16. * (l_float32)hs / (l_float32)hd;
3476  wm2 = ws - 2;
3477  hm2 = hs - 2;
3478 
3479  /* Iterate over the destination pixels */
3480  for (i = 0; i < hd; i++) {
3481  yu = (l_int32)(scy * i);
3482  yl = (l_int32)(scy * (i + 1.0));
3483  yup = yu >> 4;
3484  yuf = yu & 0x0f;
3485  ylp = yl >> 4;
3486  ylf = yl & 0x0f;
3487  dely = ylp - yup;
3488  lined = datad + i * wpld;
3489  lines = datas + yup * wpls;
3490  for (j = 0; j < wd; j++) {
3491  xu = (l_int32)(scx * j);
3492  xl = (l_int32)(scx * (j + 1.0));
3493  xup = xu >> 4;
3494  xuf = xu & 0x0f;
3495  xlp = xl >> 4;
3496  xlf = xl & 0x0f;
3497  delx = xlp - xup;
3498 
3499  /* If near the edge, just use a src pixel value */
3500  if (xlp > wm2 || ylp > hm2) {
3501  SET_DATA_BYTE(lined, j, GET_DATA_BYTE(lines, xup));
3502  continue;
3503  }
3504 
3505  /* Area summed over, in subpixels. This varies
3506  * due to the quantization, so we can't simply take
3507  * the area to be a constant: area = scx * scy. */
3508  area = ((16 - xuf) + 16 * (delx - 1) + xlf) *
3509  ((16 - yuf) + 16 * (dely - 1) + ylf);
3510 
3511  /* Do area map summation */
3512  v00 = (16 - xuf) * (16 - yuf) * GET_DATA_BYTE(lines, xup);
3513  v10 = xlf * (16 - yuf) * GET_DATA_BYTE(lines, xlp);
3514  v01 = (16 - xuf) * ylf * GET_DATA_BYTE(lines + dely * wpls, xup);
3515  v11 = xlf * ylf * GET_DATA_BYTE(lines + dely * wpls, xlp);
3516  for (vin = 0, k = 1; k < dely; k++) { /* for full src pixels */
3517  for (m = 1; m < delx; m++) {
3518  vin += 256 * GET_DATA_BYTE(lines + k * wpls, xup + m);
3519  }
3520  }
3521  for (vmid = 0, k = 1; k < dely; k++) /* for left side */
3522  vmid += (16 - xuf) * 16 * GET_DATA_BYTE(lines + k * wpls, xup);
3523  for (k = 1; k < dely; k++) /* for right side */
3524  vmid += xlf * 16 * GET_DATA_BYTE(lines + k * wpls, xlp);
3525  for (m = 1; m < delx; m++) /* for top side */
3526  vmid += 16 * (16 - yuf) * GET_DATA_BYTE(lines, xup + m);
3527  for (m = 1; m < delx; m++) /* for bottom side */
3528  vmid += 16 * ylf * GET_DATA_BYTE(lines + dely * wpls, xup + m);
3529  val = (v00 + v01 + v10 + v11 + vin + vmid + 128) / area;
3530 #if DEBUG_OVERFLOW
3531  if (val > 255) fprintf(stderr, "val overflow: %d\n", val);
3532 #endif /* DEBUG_OVERFLOW */
3533  SET_DATA_BYTE(lined, j, val);
3534  }
3535  }
3536 }
3537 
3538 
3539 /*------------------------------------------------------------------*
3540  * 2x area mapped downscaling *
3541  *------------------------------------------------------------------*/
3549 static void
3550 scaleAreaMapLow2(l_uint32 *datad,
3551  l_int32 wd,
3552  l_int32 hd,
3553  l_int32 wpld,
3554  l_uint32 *datas,
3555  l_int32 d,
3556  l_int32 wpls)
3557 {
3558 l_int32 i, j, val, rval, gval, bval;
3559 l_uint32 *lines, *lined;
3560 l_uint32 pixel;
3561 
3562  if (d == 8) {
3563  for (i = 0; i < hd; i++) {
3564  lines = datas + 2 * i * wpls;
3565  lined = datad + i * wpld;
3566  for (j = 0; j < wd; j++) {
3567  /* Average each dest pixel using 4 src pixels */
3568  val = GET_DATA_BYTE(lines, 2 * j);
3569  val += GET_DATA_BYTE(lines, 2 * j + 1);
3570  val += GET_DATA_BYTE(lines + wpls, 2 * j);
3571  val += GET_DATA_BYTE(lines + wpls, 2 * j + 1);
3572  val >>= 2;
3573  SET_DATA_BYTE(lined, j, val);
3574  }
3575  }
3576  } else { /* d == 32 */
3577  for (i = 0; i < hd; i++) {
3578  lines = datas + 2 * i * wpls;
3579  lined = datad + i * wpld;
3580  for (j = 0; j < wd; j++) {
3581  /* Average each of the color components from 4 src pixels */
3582  pixel = *(lines + 2 * j);
3583  rval = (pixel >> L_RED_SHIFT) & 0xff;
3584  gval = (pixel >> L_GREEN_SHIFT) & 0xff;
3585  bval = (pixel >> L_BLUE_SHIFT) & 0xff;
3586  pixel = *(lines + 2 * j + 1);
3587  rval += (pixel >> L_RED_SHIFT) & 0xff;
3588  gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3589  bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3590  pixel = *(lines + wpls + 2 * j);
3591  rval += (pixel >> L_RED_SHIFT) & 0xff;
3592  gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3593  bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3594  pixel = *(lines + wpls + 2 * j + 1);
3595  rval += (pixel >> L_RED_SHIFT) & 0xff;
3596  gval += (pixel >> L_GREEN_SHIFT) & 0xff;
3597  bval += (pixel >> L_BLUE_SHIFT) & 0xff;
3598  composeRGBPixel(rval >> 2, gval >> 2, bval >> 2, &pixel);
3599  *(lined + j) = pixel;
3600  }
3601  }
3602  }
3603 }
3604 
3605 
3606 /*------------------------------------------------------------------*
3607  * Binary scaling by closest pixel sampling *
3608  *------------------------------------------------------------------*/
3609 /*
3610  * scaleBinaryLow()
3611  *
3612  * Notes:
3613  * (1) The dest must be cleared prior to this operation,
3614  * and we clear it here in the low-level code.
3615  * (2) We reuse dest pixels and dest pixel rows whenever
3616  * possible for upscaling; downscaling is done by
3617  * strict subsampling.
3618  */
3619 static l_int32
3620 scaleBinaryLow(l_uint32 *datad,
3621  l_int32 wd,
3622  l_int32 hd,
3623  l_int32 wpld,
3624  l_uint32 *datas,
3625  l_int32 ws,
3626  l_int32 hs,
3627  l_int32 wpls)
3628 {
3629 l_int32 i, j, bpld;
3630 l_int32 xs, prevxs, sval;
3631 l_int32 *srow, *scol;
3632 l_uint32 *lines, *prevlines, *lined, *prevlined;
3633 l_float32 wratio, hratio;
3634 
3635  PROCNAME("scaleBinaryLow");
3636 
3637  /* clear dest */
3638  bpld = 4 * wpld;
3639  memset((char *)datad, 0, hd * bpld);
3640 
3641  /* The source row corresponding to dest row i ==> srow[i]
3642  * The source col corresponding to dest col j ==> scol[j] */
3643  if ((srow = (l_int32 *)LEPT_CALLOC(hd, sizeof(l_int32))) == NULL)
3644  return ERROR_INT("srow not made", procName, 1);
3645  if ((scol = (l_int32 *)LEPT_CALLOC(wd, sizeof(l_int32))) == NULL) {
3646  LEPT_FREE(srow);
3647  return ERROR_INT("scol not made", procName, 1);
3648  }
3649 
3650  wratio = (l_float32)ws / (l_float32)wd;
3651  hratio = (l_float32)hs / (l_float32)hd;
3652  for (i = 0; i < hd; i++)
3653  srow[i] = L_MIN((l_int32)(hratio * i + 0.5), hs - 1);
3654  for (j = 0; j < wd; j++)
3655  scol[j] = L_MIN((l_int32)(wratio * j + 0.5), ws - 1);
3656 
3657  prevlines = NULL;
3658  prevxs = -1;
3659  sval = 0;
3660  for (i = 0; i < hd; i++) {
3661  lines = datas + srow[i] * wpls;
3662  lined = datad + i * wpld;
3663  if (lines != prevlines) { /* make dest from new source row */
3664  for (j = 0; j < wd; j++) {
3665  xs = scol[j];
3666  if (xs != prevxs) { /* get dest pix from source col */
3667  if ((sval = GET_DATA_BIT(lines, xs)))
3668  SET_DATA_BIT(lined, j);
3669  prevxs = xs;
3670  } else { /* copy prev dest pix, if set */
3671  if (sval)
3672  SET_DATA_BIT(lined, j);
3673  }
3674  }
3675  } else { /* lines == prevlines; copy prev dest row */
3676  prevlined = lined - wpld;
3677  memcpy((char *)lined, (char *)prevlined, bpld);
3678  }
3679  prevlines = lines;
3680  }
3681 
3682  LEPT_FREE(srow);
3683  LEPT_FREE(scol);
3684  return 0;
3685 }
3686 
PIX * pixScaleRGBToGray2(PIX *pixs, l_float32 rwt, l_float32 gwt, l_float32 bwt)
pixScaleRGBToGray2()
Definition: scale1.c:1805
PIX * pixScaleColor2xLI(PIX *pixs)
pixScaleColor2xLI()
Definition: scale1.c:585
l_int32 pixCopyColormap(PIX *pixd, PIX *pixs)
pixCopyColormap()
Definition: pix1.c:735
PIX * pixRemoveColormap(PIX *pixs, l_int32 type)
pixRemoveColormap()
Definition: pixconv.c:322
PIX * pixScaleColor4xLI(PIX *pixs)
pixScaleColor4xLI()
Definition: scale1.c:634
PIX * pixScaleToSizeRel(PIX *pixs, l_int32 delw, l_int32 delh)
pixScaleToSizeRel()
Definition: scale1.c:273
PIX * pixScaleGray2xLIDither(PIX *pixs)
pixScaleGray2xLIDither()
Definition: scale1.c:968
PIX * pixScaleRGBToGrayFast(PIX *pixs, l_int32 factor, l_int32 color)
pixScaleRGBToGrayFast()
Definition: scale1.c:1447
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:3228
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:2264
PIX * pixScaleGray4xLIThresh(PIX *pixs, l_int32 thresh)
pixScaleGray4xLIThresh()
Definition: scale1.c:1087
PIX * pixScaleGrayToBinaryFast(PIX *pixs, l_int32 factor, l_int32 thresh)
pixScaleGrayToBinaryFast()
Definition: scale1.c:1588
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3041
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:374
PIX * pixScaleGray2xLIThresh(PIX *pixs, l_int32 thresh)
pixScaleGray2xLIThresh()
Definition: scale1.c:889
PIX * pixScaleAreaMap(PIX *pix, l_float32 scalex, l_float32 scaley)
pixScaleAreaMap()
Definition: scale1.c:1872
PIX * pixScaleColorLI(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleColorLI()
Definition: scale1.c:519
#define SET_DATA_QBIT(pdata, n, val)
Definition: arrayaccess.h:162
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1602
PIX * pixScaleBySampling(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleBySampling()
Definition: scale1.c:1298
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:2162
#define GET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:117
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:3127
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:2995
PIX * pixGetRGBComponent(PIX *pixs, l_int32 comp)
pixGetRGBComponent()
Definition: pix2.c:2392
#define SET_DATA_DIBIT(pdata, n, val)
Definition: arrayaccess.h:143
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:2428
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:2380
l_int32 pixCopySpp(PIX *pixd, PIX *pixs)
pixCopySpp()
Definition: pix1.c:1172
PIX * pixScaleBinary(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleBinary()
Definition: scale1.c:2105
#define SET_DATA_BYTE(pdata, n, val)
Definition: arrayaccess.h:192
#define GET_DATA_QBIT(pdata, n)
Definition: arrayaccess.h:158
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:2817
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:182
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:2336
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:2863
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:517
PIX * pixScaleToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleToSize()
Definition: scale1.c:316
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:545
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:3445
PIX * pixScaleLI(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleLI()
Definition: scale1.c:458
PIX * pixScaleAreaMapToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleAreaMapToSize()
Definition: scale1.c:2057
PIX * pixScaleByIntSampling(PIX *pixs, l_int32 factor)
pixScaleByIntSampling()
Definition: scale1.c:1405
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:3290
PIX * pixScaleAreaMap2(PIX *pix)
pixScaleAreaMap2()
Definition: scale1.c:1992
PIX * pixScaleGrayLI(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleGrayLI()
Definition: scale1.c:738
l_int32 pixScaleAndTransferAlpha(PIX *pixd, PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScaleAndTransferAlpha()
Definition: scale2.c:1357
PIX * pixScaleGray2xLI(PIX *pixs)
pixScaleGray2xLI()
Definition: scale1.c:801
#define GET_DATA_TWO_BYTES(pdata, n)
Definition: arrayaccess.h:206
#define GET_DATA_DIBIT(pdata, n)
Definition: arrayaccess.h:139
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:2579
PIX * pixScaleSmoothToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleSmoothToSize()
Definition: scale1.c:1767
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:3550
PIX * pixScaleBySamplingToSize(PIX *pixs, l_int32 wd, l_int32 hd)
pixScaleBySamplingToSize()
Definition: scale1.c:1360
PIX * pixUnsharpMasking(PIX *pixs, l_int32 halfwidth, l_float32 fract)
pixUnsharpMasking()
Definition: enhance.c:901
l_int32 composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2659
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:2627
Definition: pix.h:134
Definition: pix.h:706
PIX * pixCopy(PIX *pixd, PIX *pixs)
pixCopy()
Definition: pix1.c:630
Definition: pix.h:201
l_int32 pixGetDimensions(PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1052
PIX * pixScaleRGBToBinaryFast(PIX *pixs, l_int32 factor, l_int32 thresh)
pixScaleRGBToBinaryFast()
Definition: scale1.c:1522
PIX * pixScaleGray4xLIDither(PIX *pixs)
pixScaleGray4xLIDither()
Definition: scale1.c:1175
PIX * pixScaleSmooth(PIX *pix, l_float32 scalex, l_float32 scaley)
pixScaleSmooth()
Definition: scale1.c:1671
PIX * pixScale(PIX *pixs, l_float32 scalex, l_float32 scaley)
pixScale()
Definition: scale1.c:243
#define SET_DATA_TWO_BYTES(pdata, n, val)
Definition: arrayaccess.h:216
PIX * pixConvertTo8Or32(PIX *pixs, l_int32 copyflag, l_int32 warnflag)
pixConvertTo8Or32()
Definition: pixconv.c:3393
#define SET_DATA_BIT(pdata, n)
Definition: arrayaccess.h:121
PIX * pixScaleGray4xLI(PIX *pixs)
pixScaleGray4xLI()
Definition: scale1.c:844