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