Leptonica  1.77.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 
105 #include <string.h>
106 #include <math.h> /* required for sin and tan */
107 #include "allheaders.h"
108 
109 static void rotateAMColorLow(l_uint32 *datad, l_int32 w, l_int32 h,
110  l_int32 wpld, l_uint32 *datas, l_int32 wpls,
111  l_float32 angle, l_uint32 colorval);
112 static void rotateAMGrayLow(l_uint32 *datad, l_int32 w, l_int32 h,
113  l_int32 wpld, l_uint32 *datas, l_int32 wpls,
114  l_float32 angle, l_uint8 grayval);
115 static void rotateAMColorCornerLow(l_uint32 *datad, l_int32 w, l_int32 h,
116  l_int32 wpld, l_uint32 *datas,
117  l_int32 wpls, l_float32 angle,
118  l_uint32 colorval);
119 static void rotateAMGrayCornerLow(l_uint32 *datad, l_int32 w, l_int32 h,
120  l_int32 wpld, l_uint32 *datas, l_int32 wpls,
121  l_float32 angle, l_uint8 grayval);
122 
123 static void rotateAMColorFastLow(l_uint32 *datad, l_int32 w, l_int32 h,
124  l_int32 wpld, l_uint32 *datas, l_int32 wpls,
125  l_float32 angle, l_uint32 colorval);
126 
127 static const l_float32 MIN_ANGLE_TO_ROTATE = 0.001; /* radians; ~0.06 deg */
128 
129 
130 /*------------------------------------------------------------------*
131  * Rotation about the center *
132  *------------------------------------------------------------------*/
148 PIX *
150  l_float32 angle,
151  l_int32 incolor)
152 {
153 l_int32 d;
154 l_uint32 fillval;
155 PIX *pixt1, *pixt2, *pixd;
156 
157  PROCNAME("pixRotateAM");
158 
159  if (!pixs)
160  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
161  if (pixGetDepth(pixs) == 1)
162  return (PIX *)ERROR_PTR("pixs is 1 bpp", procName, NULL);
163 
164  if (L_ABS(angle) < MIN_ANGLE_TO_ROTATE)
165  return pixClone(pixs);
166 
167  /* Remove cmap if it exists, and unpack to 8 bpp if necessary */
169  d = pixGetDepth(pixt1);
170  if (d < 8)
171  pixt2 = pixConvertTo8(pixt1, FALSE);
172  else
173  pixt2 = pixClone(pixt1);
174  d = pixGetDepth(pixt2);
175 
176  /* Compute actual incoming color */
177  fillval = 0;
178  if (incolor == L_BRING_IN_WHITE) {
179  if (d == 8)
180  fillval = 255;
181  else /* d == 32 */
182  fillval = 0xffffff00;
183  }
184 
185  if (d == 8)
186  pixd = pixRotateAMGray(pixt2, angle, fillval);
187  else /* d == 32 */
188  pixd = pixRotateAMColor(pixt2, angle, fillval);
189 
190  pixDestroy(&pixt1);
191  pixDestroy(&pixt2);
192  return pixd;
193 }
194 
195 
211 PIX *
213  l_float32 angle,
214  l_uint32 colorval)
215 {
216 l_int32 w, h, wpls, wpld;
217 l_uint32 *datas, *datad;
218 PIX *pix1, *pix2, *pixd;
219 
220  PROCNAME("pixRotateAMColor");
221 
222  if (!pixs)
223  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
224  if (pixGetDepth(pixs) != 32)
225  return (PIX *)ERROR_PTR("pixs must be 32 bpp", procName, NULL);
226 
227  if (L_ABS(angle) < MIN_ANGLE_TO_ROTATE)
228  return pixClone(pixs);
229 
230  pixGetDimensions(pixs, &w, &h, NULL);
231  datas = pixGetData(pixs);
232  wpls = pixGetWpl(pixs);
233  pixd = pixCreateTemplate(pixs);
234  datad = pixGetData(pixd);
235  wpld = pixGetWpl(pixd);
236 
237  rotateAMColorLow(datad, w, h, wpld, datas, wpls, angle, colorval);
238  if (pixGetSpp(pixs) == 4) {
239  pix1 = pixGetRGBComponent(pixs, L_ALPHA_CHANNEL);
240  pix2 = pixRotateAMGray(pix1, angle, 255); /* bring in opaque */
241  pixSetRGBComponent(pixd, pix2, L_ALPHA_CHANNEL);
242  pixDestroy(&pix1);
243  pixDestroy(&pix2);
244  }
245 
246  return pixd;
247 }
248 
249 
265 PIX *
267  l_float32 angle,
268  l_uint8 grayval)
269 {
270 l_int32 w, h, wpls, wpld;
271 l_uint32 *datas, *datad;
272 PIX *pixd;
273 
274  PROCNAME("pixRotateAMGray");
275 
276  if (!pixs)
277  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
278  if (pixGetDepth(pixs) != 8)
279  return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL);
280 
281  if (L_ABS(angle) < MIN_ANGLE_TO_ROTATE)
282  return pixClone(pixs);
283 
284  pixGetDimensions(pixs, &w, &h, NULL);
285  datas = pixGetData(pixs);
286  wpls = pixGetWpl(pixs);
287  pixd = pixCreateTemplate(pixs);
288  datad = pixGetData(pixd);
289  wpld = pixGetWpl(pixd);
290 
291  rotateAMGrayLow(datad, w, h, wpld, datas, wpls, angle, grayval);
292 
293  return pixd;
294 }
295 
296 
297 static void
298 rotateAMColorLow(l_uint32 *datad,
299  l_int32 w,
300  l_int32 h,
301  l_int32 wpld,
302  l_uint32 *datas,
303  l_int32 wpls,
304  l_float32 angle,
305  l_uint32 colorval)
306 {
307 l_int32 i, j, xcen, ycen, wm2, hm2;
308 l_int32 xdif, ydif, xpm, ypm, xp, yp, xf, yf;
309 l_int32 rval, gval, bval;
310 l_uint32 word00, word01, word10, word11;
311 l_uint32 *lines, *lined;
312 l_float32 sina, cosa;
313 
314  xcen = w / 2;
315  wm2 = w - 2;
316  ycen = h / 2;
317  hm2 = h - 2;
318  sina = 16. * sin(angle);
319  cosa = 16. * cos(angle);
320 
321  for (i = 0; i < h; i++) {
322  ydif = ycen - i;
323  lined = datad + i * wpld;
324  for (j = 0; j < w; j++) {
325  xdif = xcen - j;
326  xpm = (l_int32)(-xdif * cosa - ydif * sina);
327  ypm = (l_int32)(-ydif * cosa + xdif * sina);
328  xp = xcen + (xpm >> 4);
329  yp = ycen + (ypm >> 4);
330  xf = xpm & 0x0f;
331  yf = ypm & 0x0f;
332 
333  /* if off the edge, write input colorval */
334  if (xp < 0 || yp < 0 || xp > wm2 || yp > hm2) {
335  *(lined + j) = colorval;
336  continue;
337  }
338 
339  lines = datas + yp * wpls;
340 
341  /* do area weighting. Without this, we would
342  * simply do:
343  * *(lined + j) = *(lines + xp);
344  * which is faster but gives lousy results!
345  */
346  word00 = *(lines + xp);
347  word10 = *(lines + xp + 1);
348  word01 = *(lines + wpls + xp);
349  word11 = *(lines + wpls + xp + 1);
350  rval = ((16 - xf) * (16 - yf) * ((word00 >> L_RED_SHIFT) & 0xff) +
351  xf * (16 - yf) * ((word10 >> L_RED_SHIFT) & 0xff) +
352  (16 - xf) * yf * ((word01 >> L_RED_SHIFT) & 0xff) +
353  xf * yf * ((word11 >> L_RED_SHIFT) & 0xff) + 128) / 256;
354  gval = ((16 - xf) * (16 - yf) * ((word00 >> L_GREEN_SHIFT) & 0xff) +
355  xf * (16 - yf) * ((word10 >> L_GREEN_SHIFT) & 0xff) +
356  (16 - xf) * yf * ((word01 >> L_GREEN_SHIFT) & 0xff) +
357  xf * yf * ((word11 >> L_GREEN_SHIFT) & 0xff) + 128) / 256;
358  bval = ((16 - xf) * (16 - yf) * ((word00 >> L_BLUE_SHIFT) & 0xff) +
359  xf * (16 - yf) * ((word10 >> L_BLUE_SHIFT) & 0xff) +
360  (16 - xf) * yf * ((word01 >> L_BLUE_SHIFT) & 0xff) +
361  xf * yf * ((word11 >> L_BLUE_SHIFT) & 0xff) + 128) / 256;
362  composeRGBPixel(rval, gval, bval, lined + j);
363  }
364  }
365 }
366 
367 
368 static void
369 rotateAMGrayLow(l_uint32 *datad,
370  l_int32 w,
371  l_int32 h,
372  l_int32 wpld,
373  l_uint32 *datas,
374  l_int32 wpls,
375  l_float32 angle,
376  l_uint8 grayval)
377 {
378 l_int32 i, j, xcen, ycen, wm2, hm2;
379 l_int32 xdif, ydif, xpm, ypm, xp, yp, xf, yf;
380 l_int32 v00, v01, v10, v11;
381 l_uint8 val;
382 l_uint32 *lines, *lined;
383 l_float32 sina, cosa;
384 
385  xcen = w / 2;
386  wm2 = w - 2;
387  ycen = h / 2;
388  hm2 = h - 2;
389  sina = 16. * sin(angle);
390  cosa = 16. * cos(angle);
391 
392  for (i = 0; i < h; i++) {
393  ydif = ycen - i;
394  lined = datad + i * wpld;
395  for (j = 0; j < w; j++) {
396  xdif = xcen - j;
397  xpm = (l_int32)(-xdif * cosa - ydif * sina);
398  ypm = (l_int32)(-ydif * cosa + xdif * sina);
399  xp = xcen + (xpm >> 4);
400  yp = ycen + (ypm >> 4);
401  xf = xpm & 0x0f;
402  yf = ypm & 0x0f;
403 
404  /* if off the edge, write input grayval */
405  if (xp < 0 || yp < 0 || xp > wm2 || yp > hm2) {
406  SET_DATA_BYTE(lined, j, grayval);
407  continue;
408  }
409 
410  lines = datas + yp * wpls;
411 
412  /* do area weighting. Without this, we would
413  * simply do:
414  * SET_DATA_BYTE(lined, j, GET_DATA_BYTE(lines, xp));
415  * which is faster but gives lousy results!
416  */
417  v00 = (16 - xf) * (16 - yf) * GET_DATA_BYTE(lines, xp);
418  v10 = xf * (16 - yf) * GET_DATA_BYTE(lines, xp + 1);
419  v01 = (16 - xf) * yf * GET_DATA_BYTE(lines + wpls, xp);
420  v11 = xf * yf * GET_DATA_BYTE(lines + wpls, xp + 1);
421  val = (l_uint8)((v00 + v01 + v10 + v11 + 128) / 256);
422  SET_DATA_BYTE(lined, j, val);
423  }
424  }
425 }
426 
427 
428 /*------------------------------------------------------------------*
429  * Rotation about the UL corner *
430  *------------------------------------------------------------------*/
446 PIX *
448  l_float32 angle,
449  l_int32 incolor)
450 {
451 l_int32 d;
452 l_uint32 fillval;
453 PIX *pixt1, *pixt2, *pixd;
454 
455  PROCNAME("pixRotateAMCorner");
456 
457  if (!pixs)
458  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
459 
460  if (L_ABS(angle) < MIN_ANGLE_TO_ROTATE)
461  return pixClone(pixs);
462 
463  /* Remove cmap if it exists, and unpack to 8 bpp if necessary */
465  d = pixGetDepth(pixt1);
466  if (d < 8)
467  pixt2 = pixConvertTo8(pixt1, FALSE);
468  else
469  pixt2 = pixClone(pixt1);
470  d = pixGetDepth(pixt2);
471 
472  /* Compute actual incoming color */
473  fillval = 0;
474  if (incolor == L_BRING_IN_WHITE) {
475  if (d == 8)
476  fillval = 255;
477  else /* d == 32 */
478  fillval = 0xffffff00;
479  }
480 
481  if (d == 8)
482  pixd = pixRotateAMGrayCorner(pixt2, angle, fillval);
483  else /* d == 32 */
484  pixd = pixRotateAMColorCorner(pixt2, angle, fillval);
485 
486  pixDestroy(&pixt1);
487  pixDestroy(&pixt2);
488  return pixd;
489 }
490 
491 
507 PIX *
509  l_float32 angle,
510  l_uint32 fillval)
511 {
512 l_int32 w, h, wpls, wpld;
513 l_uint32 *datas, *datad;
514 PIX *pix1, *pix2, *pixd;
515 
516  PROCNAME("pixRotateAMColorCorner");
517 
518  if (!pixs)
519  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
520  if (pixGetDepth(pixs) != 32)
521  return (PIX *)ERROR_PTR("pixs must be 32 bpp", procName, NULL);
522 
523  if (L_ABS(angle) < MIN_ANGLE_TO_ROTATE)
524  return pixClone(pixs);
525 
526  pixGetDimensions(pixs, &w, &h, NULL);
527  datas = pixGetData(pixs);
528  wpls = pixGetWpl(pixs);
529  pixd = pixCreateTemplate(pixs);
530  datad = pixGetData(pixd);
531  wpld = pixGetWpl(pixd);
532 
533  rotateAMColorCornerLow(datad, w, h, wpld, datas, wpls, angle, fillval);
534  if (pixGetSpp(pixs) == 4) {
535  pix1 = pixGetRGBComponent(pixs, L_ALPHA_CHANNEL);
536  pix2 = pixRotateAMGrayCorner(pix1, angle, 255); /* bring in opaque */
537  pixSetRGBComponent(pixd, pix2, L_ALPHA_CHANNEL);
538  pixDestroy(&pix1);
539  pixDestroy(&pix2);
540  }
541 
542  return pixd;
543 }
544 
545 
561 PIX *
563  l_float32 angle,
564  l_uint8 grayval)
565 {
566 l_int32 w, h, wpls, wpld;
567 l_uint32 *datas, *datad;
568 PIX *pixd;
569 
570  PROCNAME("pixRotateAMGrayCorner");
571 
572  if (!pixs)
573  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
574  if (pixGetDepth(pixs) != 8)
575  return (PIX *)ERROR_PTR("pixs must be 8 bpp", procName, NULL);
576 
577  if (L_ABS(angle) < MIN_ANGLE_TO_ROTATE)
578  return pixClone(pixs);
579 
580  pixGetDimensions(pixs, &w, &h, NULL);
581  datas = pixGetData(pixs);
582  wpls = pixGetWpl(pixs);
583  pixd = pixCreateTemplate(pixs);
584  datad = pixGetData(pixd);
585  wpld = pixGetWpl(pixd);
586 
587  rotateAMGrayCornerLow(datad, w, h, wpld, datas, wpls, angle, grayval);
588 
589  return pixd;
590 }
591 
592 
593 static void
594 rotateAMColorCornerLow(l_uint32 *datad,
595  l_int32 w,
596  l_int32 h,
597  l_int32 wpld,
598  l_uint32 *datas,
599  l_int32 wpls,
600  l_float32 angle,
601  l_uint32 colorval)
602 {
603 l_int32 i, j, wm2, hm2;
604 l_int32 xpm, ypm, xp, yp, xf, yf;
605 l_int32 rval, gval, bval;
606 l_uint32 word00, word01, word10, word11;
607 l_uint32 *lines, *lined;
608 l_float32 sina, cosa;
609 
610  wm2 = w - 2;
611  hm2 = h - 2;
612  sina = 16. * sin(angle);
613  cosa = 16. * cos(angle);
614 
615  for (i = 0; i < h; i++) {
616  lined = datad + i * wpld;
617  for (j = 0; j < w; j++) {
618  xpm = (l_int32)(j * cosa + i * sina);
619  ypm = (l_int32)(i * cosa - j * sina);
620  xp = xpm >> 4;
621  yp = ypm >> 4;
622  xf = xpm & 0x0f;
623  yf = ypm & 0x0f;
624 
625  /* if off the edge, write input colorval */
626  if (xp < 0 || yp < 0 || xp > wm2 || yp > hm2) {
627  *(lined + j) = colorval;
628  continue;
629  }
630 
631  lines = datas + yp * wpls;
632 
633  /* do area weighting. Without this, we would
634  * simply do:
635  * *(lined + j) = *(lines + xp);
636  * which is faster but gives lousy results!
637  */
638  word00 = *(lines + xp);
639  word10 = *(lines + xp + 1);
640  word01 = *(lines + wpls + xp);
641  word11 = *(lines + wpls + xp + 1);
642  rval = ((16 - xf) * (16 - yf) * ((word00 >> L_RED_SHIFT) & 0xff) +
643  xf * (16 - yf) * ((word10 >> L_RED_SHIFT) & 0xff) +
644  (16 - xf) * yf * ((word01 >> L_RED_SHIFT) & 0xff) +
645  xf * yf * ((word11 >> L_RED_SHIFT) & 0xff) + 128) / 256;
646  gval = ((16 - xf) * (16 - yf) * ((word00 >> L_GREEN_SHIFT) & 0xff) +
647  xf * (16 - yf) * ((word10 >> L_GREEN_SHIFT) & 0xff) +
648  (16 - xf) * yf * ((word01 >> L_GREEN_SHIFT) & 0xff) +
649  xf * yf * ((word11 >> L_GREEN_SHIFT) & 0xff) + 128) / 256;
650  bval = ((16 - xf) * (16 - yf) * ((word00 >> L_BLUE_SHIFT) & 0xff) +
651  xf * (16 - yf) * ((word10 >> L_BLUE_SHIFT) & 0xff) +
652  (16 - xf) * yf * ((word01 >> L_BLUE_SHIFT) & 0xff) +
653  xf * yf * ((word11 >> L_BLUE_SHIFT) & 0xff) + 128) / 256;
654  composeRGBPixel(rval, gval, bval, lined + j);
655  }
656  }
657 }
658 
659 
660 static void
661 rotateAMGrayCornerLow(l_uint32 *datad,
662  l_int32 w,
663  l_int32 h,
664  l_int32 wpld,
665  l_uint32 *datas,
666  l_int32 wpls,
667  l_float32 angle,
668  l_uint8 grayval)
669 {
670 l_int32 i, j, wm2, hm2;
671 l_int32 xpm, ypm, xp, yp, xf, yf;
672 l_int32 v00, v01, v10, v11;
673 l_uint8 val;
674 l_uint32 *lines, *lined;
675 l_float32 sina, cosa;
676 
677  wm2 = w - 2;
678  hm2 = h - 2;
679  sina = 16. * sin(angle);
680  cosa = 16. * cos(angle);
681 
682  for (i = 0; i < h; i++) {
683  lined = datad + i * wpld;
684  for (j = 0; j < w; j++) {
685  xpm = (l_int32)(j * cosa + i * sina);
686  ypm = (l_int32)(i * cosa - j * sina);
687  xp = xpm >> 4;
688  yp = ypm >> 4;
689  xf = xpm & 0x0f;
690  yf = ypm & 0x0f;
691 
692  /* if off the edge, write input grayval */
693  if (xp < 0 || yp < 0 || xp > wm2 || yp > hm2) {
694  SET_DATA_BYTE(lined, j, grayval);
695  continue;
696  }
697 
698  lines = datas + yp * wpls;
699 
700  /* do area weighting. Without this, we would
701  * simply do:
702  * SET_DATA_BYTE(lined, j, GET_DATA_BYTE(lines, xp));
703  * which is faster but gives lousy results!
704  */
705  v00 = (16 - xf) * (16 - yf) * GET_DATA_BYTE(lines, xp);
706  v10 = xf * (16 - yf) * GET_DATA_BYTE(lines, xp + 1);
707  v01 = (16 - xf) * yf * GET_DATA_BYTE(lines + wpls, xp);
708  v11 = xf * yf * GET_DATA_BYTE(lines + wpls, xp + 1);
709  val = (l_uint8)((v00 + v01 + v10 + v11 + 128) / 256);
710  SET_DATA_BYTE(lined, j, val);
711  }
712  }
713 }
714 
715 
716 /*------------------------------------------------------------------*
717  * Fast RGB color rotation about center *
718  *------------------------------------------------------------------*/
740 PIX *
742  l_float32 angle,
743  l_uint32 colorval)
744 {
745 l_int32 w, h, wpls, wpld;
746 l_uint32 *datas, *datad;
747 PIX *pixd;
748 
749  PROCNAME("pixRotateAMColorFast");
750 
751  if (!pixs)
752  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
753  if (pixGetDepth(pixs) != 32)
754  return (PIX *)ERROR_PTR("pixs must be 32 bpp", procName, NULL);
755 
756  if (L_ABS(angle) < MIN_ANGLE_TO_ROTATE)
757  return pixClone(pixs);
758 
759  pixGetDimensions(pixs, &w, &h, NULL);
760  datas = pixGetData(pixs);
761  wpls = pixGetWpl(pixs);
762  pixd = pixCreateTemplate(pixs);
763  datad = pixGetData(pixd);
764  wpld = pixGetWpl(pixd);
765 
766  rotateAMColorFastLow(datad, w, h, wpld, datas, wpls, angle, colorval);
767  return pixd;
768 }
769 
770 
839 static void
840 rotateAMColorFastLow(l_uint32 *datad,
841  l_int32 w,
842  l_int32 h,
843  l_int32 wpld,
844  l_uint32 *datas,
845  l_int32 wpls,
846  l_float32 angle,
847  l_uint32 colorval)
848 {
849 l_int32 i, j, xcen, ycen, wm2, hm2;
850 l_int32 xdif, ydif, xpm, ypm, xp, yp, xf, yf;
851 l_uint32 word1, word2, word3, word4, red, blue, green;
852 l_uint32 *pword, *lines, *lined;
853 l_float32 sina, cosa;
854 
855  xcen = w / 2;
856  wm2 = w - 2;
857  ycen = h / 2;
858  hm2 = h - 2;
859  sina = 4. * sin(angle);
860  cosa = 4. * cos(angle);
861 
862  for (i = 0; i < h; i++) {
863  ydif = ycen - i;
864  lined = datad + i * wpld;
865  for (j = 0; j < w; j++) {
866  xdif = xcen - j;
867  xpm = (l_int32)(-xdif * cosa - ydif * sina);
868  ypm = (l_int32)(-ydif * cosa + xdif * sina);
869  xp = xcen + (xpm >> 2);
870  yp = ycen + (ypm >> 2);
871  xf = xpm & 0x03;
872  yf = ypm & 0x03;
873 
874  /* if off the edge, write input grayval */
875  if (xp < 0 || yp < 0 || xp > wm2 || yp > hm2) {
876  *(lined + j) = colorval;
877  continue;
878  }
879 
880  lines = datas + yp * wpls;
881  pword = lines + xp;
882 
883  switch (xf + 4 * yf)
884  {
885  case 0:
886  *(lined + j) = *pword;
887  break;
888  case 1:
889  word1 = *pword;
890  word2 = *(pword + 1);
891  red = 3 * (word1 >> 24) + (word2 >> 24);
892  green = 3 * ((word1 >> 16) & 0xff) +
893  ((word2 >> 16) & 0xff);
894  blue = 3 * ((word1 >> 8) & 0xff) +
895  ((word2 >> 8) & 0xff);
896  *(lined + j) = ((red << 22) & 0xff000000) |
897  ((green << 14) & 0x00ff0000) |
898  ((blue << 6) & 0x0000ff00);
899  break;
900  case 2:
901  word1 = *pword;
902  word2 = *(pword + 1);
903  red = (word1 >> 24) + (word2 >> 24);
904  green = ((word1 >> 16) & 0xff) + ((word2 >> 16) & 0xff);
905  blue = ((word1 >> 8) & 0xff) + ((word2 >> 8) & 0xff);
906  *(lined + j) = ((red << 23) & 0xff000000) |
907  ((green << 15) & 0x00ff0000) |
908  ((blue << 7) & 0x0000ff00);
909  break;
910  case 3:
911  word1 = *pword;
912  word2 = *(pword + 1);
913  red = (word1 >> 24) + 3 * (word2 >> 24);
914  green = ((word1 >> 16) & 0xff) +
915  3 * ((word2 >> 16) & 0xff);
916  blue = ((word1 >> 8) & 0xff) +
917  3 * ((word2 >> 8) & 0xff);
918  *(lined + j) = ((red << 22) & 0xff000000) |
919  ((green << 14) & 0x00ff0000) |
920  ((blue << 6) & 0x0000ff00);
921  break;
922  case 4:
923  word1 = *pword;
924  word3 = *(pword + wpls);
925  red = 3 * (word1 >> 24) + (word3 >> 24);
926  green = 3 * ((word1 >> 16) & 0xff) +
927  ((word3 >> 16) & 0xff);
928  blue = 3 * ((word1 >> 8) & 0xff) +
929  ((word3 >> 8) & 0xff);
930  *(lined + j) = ((red << 22) & 0xff000000) |
931  ((green << 14) & 0x00ff0000) |
932  ((blue << 6) & 0x0000ff00);
933  break;
934  case 5:
935  word1 = *pword;
936  word2 = *(pword + 1);
937  word3 = *(pword + wpls);
938  word4 = *(pword + wpls + 1);
939  red = 9 * (word1 >> 24) + 3 * (word2 >> 24) +
940  3 * (word3 >> 24) + (word4 >> 24);
941  green = 9 * ((word1 >> 16) & 0xff) +
942  3 * ((word2 >> 16) & 0xff) +
943  3 * ((word3 >> 16) & 0xff) +
944  ((word4 >> 16) & 0xff);
945  blue = 9 * ((word1 >> 8) & 0xff) +
946  3 * ((word2 >> 8) & 0xff) +
947  3 * ((word3 >> 8) & 0xff) +
948  ((word4 >> 8) & 0xff);
949  *(lined + j) = ((red << 20) & 0xff000000) |
950  ((green << 12) & 0x00ff0000) |
951  ((blue << 4) & 0x0000ff00);
952  break;
953  case 6:
954  word1 = *pword;
955  word2 = *(pword + 1);
956  word3 = *(pword + wpls);
957  word4 = *(pword + wpls + 1);
958  red = 3 * (word1 >> 24) + 3 * (word2 >> 24) +
959  (word3 >> 24) + (word4 >> 24);
960  green = 3 * ((word1 >> 16) & 0xff) +
961  3 * ((word2 >> 16) & 0xff) +
962  ((word3 >> 16) & 0xff) +
963  ((word4 >> 16) & 0xff);
964  blue = 3 * ((word1 >> 8) & 0xff) +
965  3 * ((word2 >> 8) & 0xff) +
966  ((word3 >> 8) & 0xff) +
967  ((word4 >> 8) & 0xff);
968  *(lined + j) = ((red << 21) & 0xff000000) |
969  ((green << 13) & 0x00ff0000) |
970  ((blue << 5) & 0x0000ff00);
971  break;
972  case 7:
973  word1 = *pword;
974  word2 = *(pword + 1);
975  word3 = *(pword + wpls);
976  word4 = *(pword + wpls + 1);
977  red = 3 * (word1 >> 24) + 9 * (word2 >> 24) +
978  (word3 >> 24) + 3 * (word4 >> 24);
979  green = 3 * ((word1 >> 16) & 0xff) +
980  9 * ((word2 >> 16) & 0xff) +
981  ((word3 >> 16) & 0xff) +
982  3 * ((word4 >> 16) & 0xff);
983  blue = 3 * ((word1 >> 8) & 0xff) +
984  9 * ((word2 >> 8) & 0xff) +
985  ((word3 >> 8) & 0xff) +
986  3 * ((word4 >> 8) & 0xff);
987  *(lined + j) = ((red << 20) & 0xff000000) |
988  ((green << 12) & 0x00ff0000) |
989  ((blue << 4) & 0x0000ff00);
990  break;
991  case 8:
992  word1 = *pword;
993  word3 = *(pword + wpls);
994  red = (word1 >> 24) + (word3 >> 24);
995  green = ((word1 >> 16) & 0xff) + ((word3 >> 16) & 0xff);
996  blue = ((word1 >> 8) & 0xff) + ((word3 >> 8) & 0xff);
997  *(lined + j) = ((red << 23) & 0xff000000) |
998  ((green << 15) & 0x00ff0000) |
999  ((blue << 7) & 0x0000ff00);
1000  break;
1001  case 9:
1002  word1 = *pword;
1003  word2 = *(pword + 1);
1004  word3 = *(pword + wpls);
1005  word4 = *(pword + wpls + 1);
1006  red = 3 * (word1 >> 24) + (word2 >> 24) +
1007  3 * (word3 >> 24) + (word4 >> 24);
1008  green = 3 * ((word1 >> 16) & 0xff) + ((word2 >> 16) & 0xff) +
1009  3 * ((word3 >> 16) & 0xff) + ((word4 >> 16) & 0xff);
1010  blue = 3 * ((word1 >> 8) & 0xff) + ((word2 >> 8) & 0xff) +
1011  3 * ((word3 >> 8) & 0xff) + ((word4 >> 8) & 0xff);
1012  *(lined + j) = ((red << 21) & 0xff000000) |
1013  ((green << 13) & 0x00ff0000) |
1014  ((blue << 5) & 0x0000ff00);
1015  break;
1016  case 10:
1017  word1 = *pword;
1018  word2 = *(pword + 1);
1019  word3 = *(pword + wpls);
1020  word4 = *(pword + wpls + 1);
1021  red = (word1 >> 24) + (word2 >> 24) +
1022  (word3 >> 24) + (word4 >> 24);
1023  green = ((word1 >> 16) & 0xff) + ((word2 >> 16) & 0xff) +
1024  ((word3 >> 16) & 0xff) + ((word4 >> 16) & 0xff);
1025  blue = ((word1 >> 8) & 0xff) + ((word2 >> 8) & 0xff) +
1026  ((word3 >> 8) & 0xff) + ((word4 >> 8) & 0xff);
1027  *(lined + j) = ((red << 22) & 0xff000000) |
1028  ((green << 14) & 0x00ff0000) |
1029  ((blue << 6) & 0x0000ff00);
1030  break;
1031  case 11:
1032  word1 = *pword;
1033  word2 = *(pword + 1);
1034  word3 = *(pword + wpls);
1035  word4 = *(pword + wpls + 1);
1036  red = (word1 >> 24) + 3 * (word2 >> 24) +
1037  (word3 >> 24) + 3 * (word4 >> 24);
1038  green = ((word1 >> 16) & 0xff) + 3 * ((word2 >> 16) & 0xff) +
1039  ((word3 >> 16) & 0xff) + 3 * ((word4 >> 16) & 0xff);
1040  blue = ((word1 >> 8) & 0xff) + 3 * ((word2 >> 8) & 0xff) +
1041  ((word3 >> 8) & 0xff) + 3 * ((word4 >> 8) & 0xff);
1042  *(lined + j) = ((red << 21) & 0xff000000) |
1043  ((green << 13) & 0x00ff0000) |
1044  ((blue << 5) & 0x0000ff00);
1045  break;
1046  case 12:
1047  word1 = *pword;
1048  word3 = *(pword + wpls);
1049  red = (word1 >> 24) + 3 * (word3 >> 24);
1050  green = ((word1 >> 16) & 0xff) +
1051  3 * ((word3 >> 16) & 0xff);
1052  blue = ((word1 >> 8) & 0xff) +
1053  3 * ((word3 >> 8) & 0xff);
1054  *(lined + j) = ((red << 22) & 0xff000000) |
1055  ((green << 14) & 0x00ff0000) |
1056  ((blue << 6) & 0x0000ff00);
1057  break;
1058  case 13:
1059  word1 = *pword;
1060  word2 = *(pword + 1);
1061  word3 = *(pword + wpls);
1062  word4 = *(pword + wpls + 1);
1063  red = 3 * (word1 >> 24) + (word2 >> 24) +
1064  9 * (word3 >> 24) + 3 * (word4 >> 24);
1065  green = 3 * ((word1 >> 16) & 0xff) + ((word2 >> 16) & 0xff) +
1066  9 * ((word3 >> 16) & 0xff) + 3 * ((word4 >> 16) & 0xff);
1067  blue = 3 *((word1 >> 8) & 0xff) + ((word2 >> 8) & 0xff) +
1068  9 * ((word3 >> 8) & 0xff) + 3 * ((word4 >> 8) & 0xff);
1069  *(lined + j) = ((red << 20) & 0xff000000) |
1070  ((green << 12) & 0x00ff0000) |
1071  ((blue << 4) & 0x0000ff00);
1072  break;
1073  case 14:
1074  word1 = *pword;
1075  word2 = *(pword + 1);
1076  word3 = *(pword + wpls);
1077  word4 = *(pword + wpls + 1);
1078  red = (word1 >> 24) + (word2 >> 24) +
1079  3 * (word3 >> 24) + 3 * (word4 >> 24);
1080  green = ((word1 >> 16) & 0xff) +((word2 >> 16) & 0xff) +
1081  3 * ((word3 >> 16) & 0xff) + 3 * ((word4 >> 16) & 0xff);
1082  blue = ((word1 >> 8) & 0xff) + ((word2 >> 8) & 0xff) +
1083  3 * ((word3 >> 8) & 0xff) + 3 * ((word4 >> 8) & 0xff);
1084  *(lined + j) = ((red << 21) & 0xff000000) |
1085  ((green << 13) & 0x00ff0000) |
1086  ((blue << 5) & 0x0000ff00);
1087  break;
1088  case 15:
1089  word1 = *pword;
1090  word2 = *(pword + 1);
1091  word3 = *(pword + wpls);
1092  word4 = *(pword + wpls + 1);
1093  red = (word1 >> 24) + 3 * (word2 >> 24) +
1094  3 * (word3 >> 24) + 9 * (word4 >> 24);
1095  green = ((word1 >> 16) & 0xff) + 3 * ((word2 >> 16) & 0xff) +
1096  3 * ((word3 >> 16) & 0xff) + 9 * ((word4 >> 16) & 0xff);
1097  blue = ((word1 >> 8) & 0xff) + 3 * ((word2 >> 8) & 0xff) +
1098  3 * ((word3 >> 8) & 0xff) + 9 * ((word4 >> 8) & 0xff);
1099  *(lined + j) = ((red << 20) & 0xff000000) |
1100  ((green << 12) & 0x00ff0000) |
1101  ((blue << 4) & 0x0000ff00);
1102  break;
1103  default:
1104  fprintf(stderr, "shouldn't get here\n");
1105  break;
1106  }
1107  }
1108  }
1109 }
PIX * pixRemoveColormap(PIX *pixs, l_int32 type)
pixRemoveColormap()
Definition: pixconv.c:322
l_ok pixSetRGBComponent(PIX *pixd, PIX *pixs, l_int32 comp)
pixSetRGBComponent()
Definition: pix2.c:2463
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:840
PIX * pixConvertTo8(PIX *pixs, l_int32 cmapflag)
pixConvertTo8()
Definition: pixconv.c:3041
l_uint32 * pixGetData(PIX *pix)
pixGetData()
Definition: pix1.c:1624
PIX * pixCreateTemplate(PIX *pixs)
pixCreateTemplate()
Definition: pix1.c:367
PIX * pixGetRGBComponent(PIX *pixs, l_int32 comp)
pixGetRGBComponent()
Definition: pix2.c:2404
PIX * pixRotateAMColor(PIX *pixs, l_float32 angle, l_uint32 colorval)
pixRotateAMColor()
Definition: rotateam.c:212
#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:515
PIX * pixRotateAMGrayCorner(PIX *pixs, l_float32 angle, l_uint8 grayval)
pixRotateAMGrayCorner()
Definition: rotateam.c:562
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:543
PIX * pixRotateAMCorner(PIX *pixs, l_float32 angle, l_int32 incolor)
pixRotateAMCorner()
Definition: rotateam.c:447
PIX * pixRotateAM(PIX *pixs, l_float32 angle, l_int32 incolor)
pixRotateAM()
Definition: rotateam.c:149
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1065
PIX * pixRotateAMGray(PIX *pixs, l_float32 angle, l_uint8 grayval)
pixRotateAMGray()
Definition: rotateam.c:266
PIX * pixRotateAMColorFast(PIX *pixs, l_float32 angle, l_uint32 colorval)
pixRotateAMColorFast()
Definition: rotateam.c:741
Definition: pix.h:134
l_ok composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2671
PIX * pixRotateAMColorCorner(PIX *pixs, l_float32 angle, l_uint32 fillval)
pixRotateAMColorCorner()
Definition: rotateam.c:508