Leptonica  1.83.1
Image processing and image analysis suite
rotateam.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 
27 
124 #ifdef HAVE_CONFIG_H
125 #include <config_auto.h>
126 #endif /* HAVE_CONFIG_H */
127 
128 #include <string.h>
129 #include <math.h> /* required for sin and tan */
130 #include "allheaders.h"
131 
132 static void rotateAMColorLow(l_uint32 *datad, l_int32 w, l_int32 h,
133  l_int32 wpld, l_uint32 *datas, l_int32 wpls,
134  l_float32 angle, l_uint32 colorval);
135 static void rotateAMGrayLow(l_uint32 *datad, l_int32 w, l_int32 h,
136  l_int32 wpld, l_uint32 *datas, l_int32 wpls,
137  l_float32 angle, l_uint8 grayval);
138 static void rotateAMColorCornerLow(l_uint32 *datad, l_int32 w, l_int32 h,
139  l_int32 wpld, l_uint32 *datas,
140  l_int32 wpls, l_float32 angle,
141  l_uint32 colorval);
142 static void rotateAMGrayCornerLow(l_uint32 *datad, l_int32 w, l_int32 h,
143  l_int32 wpld, l_uint32 *datas, l_int32 wpls,
144  l_float32 angle, l_uint8 grayval);
145 
146 static void rotateAMColorFastLow(l_uint32 *datad, l_int32 w, l_int32 h,
147  l_int32 wpld, l_uint32 *datas, l_int32 wpls,
148  l_float32 angle, l_uint32 colorval);
149 
150 static const l_float32 MinAngleToRotate = 0.001; /* radians; ~0.06 deg */
151 
152 
153 /*------------------------------------------------------------------*
154  * Rotation about the center *
155  *------------------------------------------------------------------*/
171 PIX *
173  l_float32 angle,
174  l_int32 incolor)
175 {
176 l_int32 d;
177 l_uint32 fillval;
178 PIX *pixt1, *pixt2, *pixd;
179 
180  if (!pixs)
181  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
182  if (pixGetDepth(pixs) == 1)
183  return (PIX *)ERROR_PTR("pixs is 1 bpp", __func__, NULL);
184 
185  if (L_ABS(angle) < MinAngleToRotate)
186  return pixClone(pixs);
187 
188  /* Remove cmap if it exists, and unpack to 8 bpp if necessary */
190  d = pixGetDepth(pixt1);
191  if (d < 8)
192  pixt2 = pixConvertTo8(pixt1, FALSE);
193  else
194  pixt2 = pixClone(pixt1);
195  d = pixGetDepth(pixt2);
196 
197  /* Compute actual incoming color */
198  fillval = 0;
199  if (incolor == L_BRING_IN_WHITE) {
200  if (d == 8)
201  fillval = 255;
202  else /* d == 32 */
203  fillval = 0xffffff00;
204  }
205 
206  if (d == 8)
207  pixd = pixRotateAMGray(pixt2, angle, fillval);
208  else /* d == 32 */
209  pixd = pixRotateAMColor(pixt2, angle, fillval);
210 
211  pixDestroy(&pixt1);
212  pixDestroy(&pixt2);
213  return pixd;
214 }
215 
216 
232 PIX *
234  l_float32 angle,
235  l_uint32 colorval)
236 {
237 l_int32 w, h, wpls, wpld;
238 l_uint32 *datas, *datad;
239 PIX *pix1, *pix2, *pixd;
240 
241  if (!pixs)
242  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
243  if (pixGetDepth(pixs) != 32)
244  return (PIX *)ERROR_PTR("pixs must be 32 bpp", __func__, NULL);
245 
246  if (L_ABS(angle) < MinAngleToRotate)
247  return pixClone(pixs);
248 
249  pixGetDimensions(pixs, &w, &h, NULL);
250  datas = pixGetData(pixs);
251  wpls = pixGetWpl(pixs);
252  pixd = pixCreateTemplate(pixs);
253  datad = pixGetData(pixd);
254  wpld = pixGetWpl(pixd);
255 
256  rotateAMColorLow(datad, w, h, wpld, datas, wpls, angle, colorval);
257  if (pixGetSpp(pixs) == 4) {
258  pix1 = pixGetRGBComponent(pixs, L_ALPHA_CHANNEL);
259  pix2 = pixRotateAMGray(pix1, angle, 255); /* bring in opaque */
260  pixSetRGBComponent(pixd, pix2, L_ALPHA_CHANNEL);
261  pixDestroy(&pix1);
262  pixDestroy(&pix2);
263  }
264 
265  return pixd;
266 }
267 
268 
284 PIX *
286  l_float32 angle,
287  l_uint8 grayval)
288 {
289 l_int32 w, h, wpls, wpld;
290 l_uint32 *datas, *datad;
291 PIX *pixd;
292 
293  if (!pixs)
294  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
295  if (pixGetDepth(pixs) != 8)
296  return (PIX *)ERROR_PTR("pixs must be 8 bpp", __func__, NULL);
297 
298  if (L_ABS(angle) < MinAngleToRotate)
299  return pixClone(pixs);
300 
301  pixGetDimensions(pixs, &w, &h, NULL);
302  datas = pixGetData(pixs);
303  wpls = pixGetWpl(pixs);
304  pixd = pixCreateTemplate(pixs);
305  datad = pixGetData(pixd);
306  wpld = pixGetWpl(pixd);
307 
308  rotateAMGrayLow(datad, w, h, wpld, datas, wpls, angle, grayval);
309 
310  return pixd;
311 }
312 
313 
314 static void
315 rotateAMColorLow(l_uint32 *datad,
316  l_int32 w,
317  l_int32 h,
318  l_int32 wpld,
319  l_uint32 *datas,
320  l_int32 wpls,
321  l_float32 angle,
322  l_uint32 colorval)
323 {
324 l_int32 i, j, xcen, ycen, wm2, hm2;
325 l_int32 xdif, ydif, xpm, ypm, xp, yp, xf, yf;
326 l_int32 rval, gval, bval;
327 l_uint32 word00, word01, word10, word11;
328 l_uint32 *lines, *lined;
329 l_float32 sina, cosa;
330 
331  xcen = w / 2;
332  wm2 = w - 2;
333  ycen = h / 2;
334  hm2 = h - 2;
335  sina = 16. * sin(angle);
336  cosa = 16. * cos(angle);
337 
338  for (i = 0; i < h; i++) {
339  ydif = ycen - i;
340  lined = datad + i * wpld;
341  for (j = 0; j < w; j++) {
342  xdif = xcen - j;
343  xpm = (l_int32)(-xdif * cosa - ydif * sina);
344  ypm = (l_int32)(-ydif * cosa + xdif * sina);
345  xp = xcen + (xpm >> 4);
346  yp = ycen + (ypm >> 4);
347  xf = xpm & 0x0f;
348  yf = ypm & 0x0f;
349 
350  /* if off the edge, write input colorval */
351  if (xp < 0 || yp < 0 || xp > wm2 || yp > hm2) {
352  *(lined + j) = colorval;
353  continue;
354  }
355 
356  lines = datas + yp * wpls;
357 
358  /* do area weighting. Without this, we would
359  * simply do:
360  * *(lined + j) = *(lines + xp);
361  * which is faster but gives lousy results!
362  */
363  word00 = *(lines + xp);
364  word10 = *(lines + xp + 1);
365  word01 = *(lines + wpls + xp);
366  word11 = *(lines + wpls + xp + 1);
367  rval = ((16 - xf) * (16 - yf) * ((word00 >> L_RED_SHIFT) & 0xff) +
368  xf * (16 - yf) * ((word10 >> L_RED_SHIFT) & 0xff) +
369  (16 - xf) * yf * ((word01 >> L_RED_SHIFT) & 0xff) +
370  xf * yf * ((word11 >> L_RED_SHIFT) & 0xff) + 128) / 256;
371  gval = ((16 - xf) * (16 - yf) * ((word00 >> L_GREEN_SHIFT) & 0xff) +
372  xf * (16 - yf) * ((word10 >> L_GREEN_SHIFT) & 0xff) +
373  (16 - xf) * yf * ((word01 >> L_GREEN_SHIFT) & 0xff) +
374  xf * yf * ((word11 >> L_GREEN_SHIFT) & 0xff) + 128) / 256;
375  bval = ((16 - xf) * (16 - yf) * ((word00 >> L_BLUE_SHIFT) & 0xff) +
376  xf * (16 - yf) * ((word10 >> L_BLUE_SHIFT) & 0xff) +
377  (16 - xf) * yf * ((word01 >> L_BLUE_SHIFT) & 0xff) +
378  xf * yf * ((word11 >> L_BLUE_SHIFT) & 0xff) + 128) / 256;
379  composeRGBPixel(rval, gval, bval, lined + j);
380  }
381  }
382 }
383 
384 
385 static void
386 rotateAMGrayLow(l_uint32 *datad,
387  l_int32 w,
388  l_int32 h,
389  l_int32 wpld,
390  l_uint32 *datas,
391  l_int32 wpls,
392  l_float32 angle,
393  l_uint8 grayval)
394 {
395 l_int32 i, j, xcen, ycen, wm2, hm2;
396 l_int32 xdif, ydif, xpm, ypm, xp, yp, xf, yf;
397 l_int32 v00, v01, v10, v11;
398 l_uint8 val;
399 l_uint32 *lines, *lined;
400 l_float32 sina, cosa;
401 
402  xcen = w / 2;
403  wm2 = w - 2;
404  ycen = h / 2;
405  hm2 = h - 2;
406  sina = 16. * sin(angle);
407  cosa = 16. * cos(angle);
408 
409  for (i = 0; i < h; i++) {
410  ydif = ycen - i;
411  lined = datad + i * wpld;
412  for (j = 0; j < w; j++) {
413  xdif = xcen - j;
414  xpm = (l_int32)(-xdif * cosa - ydif * sina);
415  ypm = (l_int32)(-ydif * cosa + xdif * sina);
416  xp = xcen + (xpm >> 4);
417  yp = ycen + (ypm >> 4);
418  xf = xpm & 0x0f;
419  yf = ypm & 0x0f;
420 
421  /* if off the edge, write input grayval */
422  if (xp < 0 || yp < 0 || xp > wm2 || yp > hm2) {
423  SET_DATA_BYTE(lined, j, grayval);
424  continue;
425  }
426 
427  lines = datas + yp * wpls;
428 
429  /* do area weighting. Without this, we would
430  * simply do:
431  * SET_DATA_BYTE(lined, j, GET_DATA_BYTE(lines, xp));
432  * which is faster but gives lousy results!
433  */
434  v00 = (16 - xf) * (16 - yf) * GET_DATA_BYTE(lines, xp);
435  v10 = xf * (16 - yf) * GET_DATA_BYTE(lines, xp + 1);
436  v01 = (16 - xf) * yf * GET_DATA_BYTE(lines + wpls, xp);
437  v11 = xf * yf * GET_DATA_BYTE(lines + wpls, xp + 1);
438  val = (l_uint8)((v00 + v01 + v10 + v11 + 128) / 256);
439  SET_DATA_BYTE(lined, j, val);
440  }
441  }
442 }
443 
444 
445 /*------------------------------------------------------------------*
446  * Rotation about the UL corner *
447  *------------------------------------------------------------------*/
463 PIX *
465  l_float32 angle,
466  l_int32 incolor)
467 {
468 l_int32 d;
469 l_uint32 fillval;
470 PIX *pixt1, *pixt2, *pixd;
471 
472  if (!pixs)
473  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
474 
475  if (L_ABS(angle) < MinAngleToRotate)
476  return pixClone(pixs);
477 
478  /* Remove cmap if it exists, and unpack to 8 bpp if necessary */
480  d = pixGetDepth(pixt1);
481  if (d < 8)
482  pixt2 = pixConvertTo8(pixt1, FALSE);
483  else
484  pixt2 = pixClone(pixt1);
485  d = pixGetDepth(pixt2);
486 
487  /* Compute actual incoming color */
488  fillval = 0;
489  if (incolor == L_BRING_IN_WHITE) {
490  if (d == 8)
491  fillval = 255;
492  else /* d == 32 */
493  fillval = 0xffffff00;
494  }
495 
496  if (d == 8)
497  pixd = pixRotateAMGrayCorner(pixt2, angle, fillval);
498  else /* d == 32 */
499  pixd = pixRotateAMColorCorner(pixt2, angle, fillval);
500 
501  pixDestroy(&pixt1);
502  pixDestroy(&pixt2);
503  return pixd;
504 }
505 
506 
522 PIX *
524  l_float32 angle,
525  l_uint32 fillval)
526 {
527 l_int32 w, h, wpls, wpld;
528 l_uint32 *datas, *datad;
529 PIX *pix1, *pix2, *pixd;
530 
531  if (!pixs)
532  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
533  if (pixGetDepth(pixs) != 32)
534  return (PIX *)ERROR_PTR("pixs must be 32 bpp", __func__, NULL);
535 
536  if (L_ABS(angle) < MinAngleToRotate)
537  return pixClone(pixs);
538 
539  pixGetDimensions(pixs, &w, &h, NULL);
540  datas = pixGetData(pixs);
541  wpls = pixGetWpl(pixs);
542  pixd = pixCreateTemplate(pixs);
543  datad = pixGetData(pixd);
544  wpld = pixGetWpl(pixd);
545 
546  rotateAMColorCornerLow(datad, w, h, wpld, datas, wpls, angle, fillval);
547  if (pixGetSpp(pixs) == 4) {
548  pix1 = pixGetRGBComponent(pixs, L_ALPHA_CHANNEL);
549  pix2 = pixRotateAMGrayCorner(pix1, angle, 255); /* bring in opaque */
550  pixSetRGBComponent(pixd, pix2, L_ALPHA_CHANNEL);
551  pixDestroy(&pix1);
552  pixDestroy(&pix2);
553  }
554 
555  return pixd;
556 }
557 
558 
574 PIX *
576  l_float32 angle,
577  l_uint8 grayval)
578 {
579 l_int32 w, h, wpls, wpld;
580 l_uint32 *datas, *datad;
581 PIX *pixd;
582 
583  if (!pixs)
584  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
585  if (pixGetDepth(pixs) != 8)
586  return (PIX *)ERROR_PTR("pixs must be 8 bpp", __func__, NULL);
587 
588  if (L_ABS(angle) < MinAngleToRotate)
589  return pixClone(pixs);
590 
591  pixGetDimensions(pixs, &w, &h, NULL);
592  datas = pixGetData(pixs);
593  wpls = pixGetWpl(pixs);
594  pixd = pixCreateTemplate(pixs);
595  datad = pixGetData(pixd);
596  wpld = pixGetWpl(pixd);
597 
598  rotateAMGrayCornerLow(datad, w, h, wpld, datas, wpls, angle, grayval);
599 
600  return pixd;
601 }
602 
603 
604 static void
605 rotateAMColorCornerLow(l_uint32 *datad,
606  l_int32 w,
607  l_int32 h,
608  l_int32 wpld,
609  l_uint32 *datas,
610  l_int32 wpls,
611  l_float32 angle,
612  l_uint32 colorval)
613 {
614 l_int32 i, j, wm2, hm2;
615 l_int32 xpm, ypm, xp, yp, xf, yf;
616 l_int32 rval, gval, bval;
617 l_uint32 word00, word01, word10, word11;
618 l_uint32 *lines, *lined;
619 l_float32 sina, cosa;
620 
621  wm2 = w - 2;
622  hm2 = h - 2;
623  sina = 16. * sin(angle);
624  cosa = 16. * cos(angle);
625 
626  for (i = 0; i < h; i++) {
627  lined = datad + i * wpld;
628  for (j = 0; j < w; j++) {
629  xpm = (l_int32)(j * cosa + i * sina);
630  ypm = (l_int32)(i * cosa - j * sina);
631  xp = xpm >> 4;
632  yp = ypm >> 4;
633  xf = xpm & 0x0f;
634  yf = ypm & 0x0f;
635 
636  /* if off the edge, write input colorval */
637  if (xp < 0 || yp < 0 || xp > wm2 || yp > hm2) {
638  *(lined + j) = colorval;
639  continue;
640  }
641 
642  lines = datas + yp * wpls;
643 
644  /* do area weighting. Without this, we would
645  * simply do:
646  * *(lined + j) = *(lines + xp);
647  * which is faster but gives lousy results!
648  */
649  word00 = *(lines + xp);
650  word10 = *(lines + xp + 1);
651  word01 = *(lines + wpls + xp);
652  word11 = *(lines + wpls + xp + 1);
653  rval = ((16 - xf) * (16 - yf) * ((word00 >> L_RED_SHIFT) & 0xff) +
654  xf * (16 - yf) * ((word10 >> L_RED_SHIFT) & 0xff) +
655  (16 - xf) * yf * ((word01 >> L_RED_SHIFT) & 0xff) +
656  xf * yf * ((word11 >> L_RED_SHIFT) & 0xff) + 128) / 256;
657  gval = ((16 - xf) * (16 - yf) * ((word00 >> L_GREEN_SHIFT) & 0xff) +
658  xf * (16 - yf) * ((word10 >> L_GREEN_SHIFT) & 0xff) +
659  (16 - xf) * yf * ((word01 >> L_GREEN_SHIFT) & 0xff) +
660  xf * yf * ((word11 >> L_GREEN_SHIFT) & 0xff) + 128) / 256;
661  bval = ((16 - xf) * (16 - yf) * ((word00 >> L_BLUE_SHIFT) & 0xff) +
662  xf * (16 - yf) * ((word10 >> L_BLUE_SHIFT) & 0xff) +
663  (16 - xf) * yf * ((word01 >> L_BLUE_SHIFT) & 0xff) +
664  xf * yf * ((word11 >> L_BLUE_SHIFT) & 0xff) + 128) / 256;
665  composeRGBPixel(rval, gval, bval, lined + j);
666  }
667  }
668 }
669 
670 
671 static void
672 rotateAMGrayCornerLow(l_uint32 *datad,
673  l_int32 w,
674  l_int32 h,
675  l_int32 wpld,
676  l_uint32 *datas,
677  l_int32 wpls,
678  l_float32 angle,
679  l_uint8 grayval)
680 {
681 l_int32 i, j, wm2, hm2;
682 l_int32 xpm, ypm, xp, yp, xf, yf;
683 l_int32 v00, v01, v10, v11;
684 l_uint8 val;
685 l_uint32 *lines, *lined;
686 l_float32 sina, cosa;
687 
688  wm2 = w - 2;
689  hm2 = h - 2;
690  sina = 16. * sin(angle);
691  cosa = 16. * cos(angle);
692 
693  for (i = 0; i < h; i++) {
694  lined = datad + i * wpld;
695  for (j = 0; j < w; j++) {
696  xpm = (l_int32)(j * cosa + i * sina);
697  ypm = (l_int32)(i * cosa - j * sina);
698  xp = xpm >> 4;
699  yp = ypm >> 4;
700  xf = xpm & 0x0f;
701  yf = ypm & 0x0f;
702 
703  /* if off the edge, write input grayval */
704  if (xp < 0 || yp < 0 || xp > wm2 || yp > hm2) {
705  SET_DATA_BYTE(lined, j, grayval);
706  continue;
707  }
708 
709  lines = datas + yp * wpls;
710 
711  /* do area weighting. Without this, we would
712  * simply do:
713  * SET_DATA_BYTE(lined, j, GET_DATA_BYTE(lines, xp));
714  * which is faster but gives lousy results!
715  */
716  v00 = (16 - xf) * (16 - yf) * GET_DATA_BYTE(lines, xp);
717  v10 = xf * (16 - yf) * GET_DATA_BYTE(lines, xp + 1);
718  v01 = (16 - xf) * yf * GET_DATA_BYTE(lines + wpls, xp);
719  v11 = xf * yf * GET_DATA_BYTE(lines + wpls, xp + 1);
720  val = (l_uint8)((v00 + v01 + v10 + v11 + 128) / 256);
721  SET_DATA_BYTE(lined, j, val);
722  }
723  }
724 }
725 
726 
727 /*------------------------------------------------------------------*
728  * Fast RGB color rotation about center *
729  *------------------------------------------------------------------*/
751 PIX *
753  l_float32 angle,
754  l_uint32 colorval)
755 {
756 l_int32 w, h, wpls, wpld;
757 l_uint32 *datas, *datad;
758 PIX *pixd;
759 
760  if (!pixs)
761  return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
762  if (pixGetDepth(pixs) != 32)
763  return (PIX *)ERROR_PTR("pixs must be 32 bpp", __func__, NULL);
764 
765  if (L_ABS(angle) < MinAngleToRotate)
766  return pixClone(pixs);
767 
768  pixGetDimensions(pixs, &w, &h, NULL);
769  datas = pixGetData(pixs);
770  wpls = pixGetWpl(pixs);
771  pixd = pixCreateTemplate(pixs);
772  datad = pixGetData(pixd);
773  wpld = pixGetWpl(pixd);
774 
775  rotateAMColorFastLow(datad, w, h, wpld, datas, wpls, angle, colorval);
776  return pixd;
777 }
778 
779 
848 static void
849 rotateAMColorFastLow(l_uint32 *datad,
850  l_int32 w,
851  l_int32 h,
852  l_int32 wpld,
853  l_uint32 *datas,
854  l_int32 wpls,
855  l_float32 angle,
856  l_uint32 colorval)
857 {
858 l_int32 i, j, xcen, ycen, wm2, hm2;
859 l_int32 xdif, ydif, xpm, ypm, xp, yp, xf, yf;
860 l_uint32 word1, word2, word3, word4, red, blue, green;
861 l_uint32 *pword, *lines, *lined;
862 l_float32 sina, cosa;
863 
864  xcen = w / 2;
865  wm2 = w - 2;
866  ycen = h / 2;
867  hm2 = h - 2;
868  sina = 4. * sin(angle);
869  cosa = 4. * cos(angle);
870 
871  for (i = 0; i < h; i++) {
872  ydif = ycen - i;
873  lined = datad + i * wpld;
874  for (j = 0; j < w; j++) {
875  xdif = xcen - j;
876  xpm = (l_int32)(-xdif * cosa - ydif * sina);
877  ypm = (l_int32)(-ydif * cosa + xdif * sina);
878  xp = xcen + (xpm >> 2);
879  yp = ycen + (ypm >> 2);
880  xf = xpm & 0x03;
881  yf = ypm & 0x03;
882 
883  /* if off the edge, write input grayval */
884  if (xp < 0 || yp < 0 || xp > wm2 || yp > hm2) {
885  *(lined + j) = colorval;
886  continue;
887  }
888 
889  lines = datas + yp * wpls;
890  pword = lines + xp;
891 
892  switch (xf + 4 * yf)
893  {
894  case 0:
895  *(lined + j) = *pword;
896  break;
897  case 1:
898  word1 = *pword;
899  word2 = *(pword + 1);
900  red = 3 * (word1 >> 24) + (word2 >> 24);
901  green = 3 * ((word1 >> 16) & 0xff) +
902  ((word2 >> 16) & 0xff);
903  blue = 3 * ((word1 >> 8) & 0xff) +
904  ((word2 >> 8) & 0xff);
905  *(lined + j) = ((red << 22) & 0xff000000) |
906  ((green << 14) & 0x00ff0000) |
907  ((blue << 6) & 0x0000ff00);
908  break;
909  case 2:
910  word1 = *pword;
911  word2 = *(pword + 1);
912  red = (word1 >> 24) + (word2 >> 24);
913  green = ((word1 >> 16) & 0xff) + ((word2 >> 16) & 0xff);
914  blue = ((word1 >> 8) & 0xff) + ((word2 >> 8) & 0xff);
915  *(lined + j) = ((red << 23) & 0xff000000) |
916  ((green << 15) & 0x00ff0000) |
917  ((blue << 7) & 0x0000ff00);
918  break;
919  case 3:
920  word1 = *pword;
921  word2 = *(pword + 1);
922  red = (word1 >> 24) + 3 * (word2 >> 24);
923  green = ((word1 >> 16) & 0xff) +
924  3 * ((word2 >> 16) & 0xff);
925  blue = ((word1 >> 8) & 0xff) +
926  3 * ((word2 >> 8) & 0xff);
927  *(lined + j) = ((red << 22) & 0xff000000) |
928  ((green << 14) & 0x00ff0000) |
929  ((blue << 6) & 0x0000ff00);
930  break;
931  case 4:
932  word1 = *pword;
933  word3 = *(pword + wpls);
934  red = 3 * (word1 >> 24) + (word3 >> 24);
935  green = 3 * ((word1 >> 16) & 0xff) +
936  ((word3 >> 16) & 0xff);
937  blue = 3 * ((word1 >> 8) & 0xff) +
938  ((word3 >> 8) & 0xff);
939  *(lined + j) = ((red << 22) & 0xff000000) |
940  ((green << 14) & 0x00ff0000) |
941  ((blue << 6) & 0x0000ff00);
942  break;
943  case 5:
944  word1 = *pword;
945  word2 = *(pword + 1);
946  word3 = *(pword + wpls);
947  word4 = *(pword + wpls + 1);
948  red = 9 * (word1 >> 24) + 3 * (word2 >> 24) +
949  3 * (word3 >> 24) + (word4 >> 24);
950  green = 9 * ((word1 >> 16) & 0xff) +
951  3 * ((word2 >> 16) & 0xff) +
952  3 * ((word3 >> 16) & 0xff) +
953  ((word4 >> 16) & 0xff);
954  blue = 9 * ((word1 >> 8) & 0xff) +
955  3 * ((word2 >> 8) & 0xff) +
956  3 * ((word3 >> 8) & 0xff) +
957  ((word4 >> 8) & 0xff);
958  *(lined + j) = ((red << 20) & 0xff000000) |
959  ((green << 12) & 0x00ff0000) |
960  ((blue << 4) & 0x0000ff00);
961  break;
962  case 6:
963  word1 = *pword;
964  word2 = *(pword + 1);
965  word3 = *(pword + wpls);
966  word4 = *(pword + wpls + 1);
967  red = 3 * (word1 >> 24) + 3 * (word2 >> 24) +
968  (word3 >> 24) + (word4 >> 24);
969  green = 3 * ((word1 >> 16) & 0xff) +
970  3 * ((word2 >> 16) & 0xff) +
971  ((word3 >> 16) & 0xff) +
972  ((word4 >> 16) & 0xff);
973  blue = 3 * ((word1 >> 8) & 0xff) +
974  3 * ((word2 >> 8) & 0xff) +
975  ((word3 >> 8) & 0xff) +
976  ((word4 >> 8) & 0xff);
977  *(lined + j) = ((red << 21) & 0xff000000) |
978  ((green << 13) & 0x00ff0000) |
979  ((blue << 5) & 0x0000ff00);
980  break;
981  case 7:
982  word1 = *pword;
983  word2 = *(pword + 1);
984  word3 = *(pword + wpls);
985  word4 = *(pword + wpls + 1);
986  red = 3 * (word1 >> 24) + 9 * (word2 >> 24) +
987  (word3 >> 24) + 3 * (word4 >> 24);
988  green = 3 * ((word1 >> 16) & 0xff) +
989  9 * ((word2 >> 16) & 0xff) +
990  ((word3 >> 16) & 0xff) +
991  3 * ((word4 >> 16) & 0xff);
992  blue = 3 * ((word1 >> 8) & 0xff) +
993  9 * ((word2 >> 8) & 0xff) +
994  ((word3 >> 8) & 0xff) +
995  3 * ((word4 >> 8) & 0xff);
996  *(lined + j) = ((red << 20) & 0xff000000) |
997  ((green << 12) & 0x00ff0000) |
998  ((blue << 4) & 0x0000ff00);
999  break;
1000  case 8:
1001  word1 = *pword;
1002  word3 = *(pword + wpls);
1003  red = (word1 >> 24) + (word3 >> 24);
1004  green = ((word1 >> 16) & 0xff) + ((word3 >> 16) & 0xff);
1005  blue = ((word1 >> 8) & 0xff) + ((word3 >> 8) & 0xff);
1006  *(lined + j) = ((red << 23) & 0xff000000) |
1007  ((green << 15) & 0x00ff0000) |
1008  ((blue << 7) & 0x0000ff00);
1009  break;
1010  case 9:
1011  word1 = *pword;
1012  word2 = *(pword + 1);
1013  word3 = *(pword + wpls);
1014  word4 = *(pword + wpls + 1);
1015  red = 3 * (word1 >> 24) + (word2 >> 24) +
1016  3 * (word3 >> 24) + (word4 >> 24);
1017  green = 3 * ((word1 >> 16) & 0xff) + ((word2 >> 16) & 0xff) +
1018  3 * ((word3 >> 16) & 0xff) + ((word4 >> 16) & 0xff);
1019  blue = 3 * ((word1 >> 8) & 0xff) + ((word2 >> 8) & 0xff) +
1020  3 * ((word3 >> 8) & 0xff) + ((word4 >> 8) & 0xff);
1021  *(lined + j) = ((red << 21) & 0xff000000) |
1022  ((green << 13) & 0x00ff0000) |
1023  ((blue << 5) & 0x0000ff00);
1024  break;
1025  case 10:
1026  word1 = *pword;
1027  word2 = *(pword + 1);
1028  word3 = *(pword + wpls);
1029  word4 = *(pword + wpls + 1);
1030  red = (word1 >> 24) + (word2 >> 24) +
1031  (word3 >> 24) + (word4 >> 24);
1032  green = ((word1 >> 16) & 0xff) + ((word2 >> 16) & 0xff) +
1033  ((word3 >> 16) & 0xff) + ((word4 >> 16) & 0xff);
1034  blue = ((word1 >> 8) & 0xff) + ((word2 >> 8) & 0xff) +
1035  ((word3 >> 8) & 0xff) + ((word4 >> 8) & 0xff);
1036  *(lined + j) = ((red << 22) & 0xff000000) |
1037  ((green << 14) & 0x00ff0000) |
1038  ((blue << 6) & 0x0000ff00);
1039  break;
1040  case 11:
1041  word1 = *pword;
1042  word2 = *(pword + 1);
1043  word3 = *(pword + wpls);
1044  word4 = *(pword + wpls + 1);
1045  red = (word1 >> 24) + 3 * (word2 >> 24) +
1046  (word3 >> 24) + 3 * (word4 >> 24);
1047  green = ((word1 >> 16) & 0xff) + 3 * ((word2 >> 16) & 0xff) +
1048  ((word3 >> 16) & 0xff) + 3 * ((word4 >> 16) & 0xff);
1049  blue = ((word1 >> 8) & 0xff) + 3 * ((word2 >> 8) & 0xff) +
1050  ((word3 >> 8) & 0xff) + 3 * ((word4 >> 8) & 0xff);
1051  *(lined + j) = ((red << 21) & 0xff000000) |
1052  ((green << 13) & 0x00ff0000) |
1053  ((blue << 5) & 0x0000ff00);
1054  break;
1055  case 12:
1056  word1 = *pword;
1057  word3 = *(pword + wpls);
1058  red = (word1 >> 24) + 3 * (word3 >> 24);
1059  green = ((word1 >> 16) & 0xff) +
1060  3 * ((word3 >> 16) & 0xff);
1061  blue = ((word1 >> 8) & 0xff) +
1062  3 * ((word3 >> 8) & 0xff);
1063  *(lined + j) = ((red << 22) & 0xff000000) |
1064  ((green << 14) & 0x00ff0000) |
1065  ((blue << 6) & 0x0000ff00);
1066  break;
1067  case 13:
1068  word1 = *pword;
1069  word2 = *(pword + 1);
1070  word3 = *(pword + wpls);
1071  word4 = *(pword + wpls + 1);
1072  red = 3 * (word1 >> 24) + (word2 >> 24) +
1073  9 * (word3 >> 24) + 3 * (word4 >> 24);
1074  green = 3 * ((word1 >> 16) & 0xff) + ((word2 >> 16) & 0xff) +
1075  9 * ((word3 >> 16) & 0xff) + 3 * ((word4 >> 16) & 0xff);
1076  blue = 3 *((word1 >> 8) & 0xff) + ((word2 >> 8) & 0xff) +
1077  9 * ((word3 >> 8) & 0xff) + 3 * ((word4 >> 8) & 0xff);
1078  *(lined + j) = ((red << 20) & 0xff000000) |
1079  ((green << 12) & 0x00ff0000) |
1080  ((blue << 4) & 0x0000ff00);
1081  break;
1082  case 14:
1083  word1 = *pword;
1084  word2 = *(pword + 1);
1085  word3 = *(pword + wpls);
1086  word4 = *(pword + wpls + 1);
1087  red = (word1 >> 24) + (word2 >> 24) +
1088  3 * (word3 >> 24) + 3 * (word4 >> 24);
1089  green = ((word1 >> 16) & 0xff) +((word2 >> 16) & 0xff) +
1090  3 * ((word3 >> 16) & 0xff) + 3 * ((word4 >> 16) & 0xff);
1091  blue = ((word1 >> 8) & 0xff) + ((word2 >> 8) & 0xff) +
1092  3 * ((word3 >> 8) & 0xff) + 3 * ((word4 >> 8) & 0xff);
1093  *(lined + j) = ((red << 21) & 0xff000000) |
1094  ((green << 13) & 0x00ff0000) |
1095  ((blue << 5) & 0x0000ff00);
1096  break;
1097  case 15:
1098  word1 = *pword;
1099  word2 = *(pword + 1);
1100  word3 = *(pword + wpls);
1101  word4 = *(pword + wpls + 1);
1102  red = (word1 >> 24) + 3 * (word2 >> 24) +
1103  3 * (word3 >> 24) + 9 * (word4 >> 24);
1104  green = ((word1 >> 16) & 0xff) + 3 * ((word2 >> 16) & 0xff) +
1105  3 * ((word3 >> 16) & 0xff) + 9 * ((word4 >> 16) & 0xff);
1106  blue = ((word1 >> 8) & 0xff) + 3 * ((word2 >> 8) & 0xff) +
1107  3 * ((word3 >> 8) & 0xff) + 9 * ((word4 >> 8) & 0xff);
1108  *(lined + j) = ((red << 20) & 0xff000000) |
1109  ((green << 12) & 0x00ff0000) |
1110  ((blue << 4) & 0x0000ff00);
1111  break;
1112  default:
1113  lept_stderr("shouldn't get here\n");
1114  break;
1115  }
1116  }
1117  }
1118 }
#define GET_DATA_BYTE(pdata, n)
Definition: arrayaccess.h:188
#define SET_DATA_BYTE(pdata, n, val)
Definition: arrayaccess.h:198
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1642
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:608
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1074
PIX * pixCreateTemplate(const PIX *pixs)
pixCreateTemplate()
Definition: pix1.c:380
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:582
PIX * pixGetRGBComponent(PIX *pixs, l_int32 comp)
pixGetRGBComponent()
Definition: pix2.c:2464
l_ok composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2728
l_ok pixSetRGBComponent(PIX *pixd, PIX *pixs, l_int32 comp)
pixSetRGBComponent()
Definition: pix2.c:2521
@ L_ALPHA_CHANNEL
Definition: pix.h:331
@ REMOVE_CMAP_BASED_ON_SRC
Definition: pix.h:384
@ L_BRING_IN_WHITE
Definition: pix.h:662
PIX * pixRemoveColormap(PIX *pixs, l_int32 type)
pixRemoveColormap()
Definition: pixconv.c:324
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3055
PIX * pixRotateAM(PIX *pixs, l_float32 angle, l_int32 incolor)
pixRotateAM()
Definition: rotateam.c:172
PIX * pixRotateAMCorner(PIX *pixs, l_float32 angle, l_int32 incolor)
pixRotateAMCorner()
Definition: rotateam.c:464
PIX * pixRotateAMGrayCorner(PIX *pixs, l_float32 angle, l_uint8 grayval)
pixRotateAMGrayCorner()
Definition: rotateam.c:575
static void rotateAMColorFastLow(l_uint32 *datad, l_int32 w, l_int32 h, l_int32 wpld, l_uint32 *datas, l_int32 wpls, l_float32 angle, l_uint32 colorval)
rotateAMColorFastLow()
Definition: rotateam.c:849
PIX * pixRotateAMColor(PIX *pixs, l_float32 angle, l_uint32 colorval)
pixRotateAMColor()
Definition: rotateam.c:233
PIX * pixRotateAMColorCorner(PIX *pixs, l_float32 angle, l_uint32 fillval)
pixRotateAMColorCorner()
Definition: rotateam.c:523
PIX * pixRotateAMGray(PIX *pixs, l_float32 angle, l_uint8 grayval)
pixRotateAMGray()
Definition: rotateam.c:285
PIX * pixRotateAMColorFast(PIX *pixs, l_float32 angle, l_uint32 colorval)
pixRotateAMColorFast()
Definition: rotateam.c:752
void lept_stderr(const char *fmt,...)
lept_stderr()
Definition: utils1.c:306