/* rotate.c - image rotation * * Raster graphics library * * Copyright (c) 2000-2003 Alfredo K. Kojima * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301, USA. */ #include #include #include #include #include #include "wraster.h" #include #ifndef PI #define PI 3.14159265358979323846 #endif static RImage *rotateImage(RImage * image, float angle); RImage *RRotateImage(RImage * image, float angle) { RImage *img; int nwidth, nheight; int x, y; int bpp = image->format == RRGBAFormat ? 4 : 3; angle = ((int)angle % 360) + (angle - (int)angle); if (angle == 0.0) { return RCloneImage(image); } else if (angle == 90.0) { nwidth = image->height; nheight = image->width; img = RCreateImage(nwidth, nheight, True); if (!img) { return NULL; } if (bpp == 3) { unsigned char *optr, *nptr; unsigned offs; offs = nwidth * 4; optr = image->data; nptr = img->data; for (x = 0; x < nwidth; x++) { nptr = img->data + x * 4; for (y = nheight; y; y--) { nptr[0] = *optr++; nptr[1] = *optr++; nptr[2] = *optr++; nptr[3] = 255; nptr += offs; } } } else { unsigned *optr, *nptr; unsigned *p; optr = (unsigned *)image->data; p = (unsigned *)img->data; for (x = 0; x < nwidth; x++) { nptr = p++; for (y = nheight; y; y--) { *nptr = *optr++; nptr += nwidth; } } } } else if (angle == 180.0) { nwidth = image->width; nheight = image->height; img = RCreateImage(nwidth, nheight, True); if (!img) { return NULL; } if (bpp == 3) { unsigned char *optr, *nptr; optr = image->data; nptr = img->data + nwidth * nheight * 4 - 4; for (y = 0; y < nheight; y++) { for (x = 0; x < nwidth; x++) { nptr[0] = optr[0]; nptr[1] = optr[1]; nptr[2] = optr[2]; nptr[3] = 255; optr += 3; nptr -= 4; } } } else { unsigned *optr, *nptr; optr = (unsigned *)image->data; nptr = (unsigned *)img->data + nwidth * nheight - 1; for (y = nheight * nwidth - 1; y >= 0; y--) { *nptr = *optr; optr++; nptr--; } } } else if (angle == 270.0) { nwidth = image->height; nheight = image->width; img = RCreateImage(nwidth, nheight, True); if (!img) { return NULL; } if (bpp == 3) { unsigned char *optr, *nptr; unsigned offs; offs = nwidth * 4; optr = image->data; nptr = img->data; for (x = 0; x < nwidth; x++) { nptr = img->data + x * 4; for (y = nheight; y; y--) { nptr[0] = *optr++; nptr[1] = *optr++; nptr[2] = *optr++; nptr[3] = 255; nptr += offs; } } } else { unsigned *optr, *nptr; unsigned *p; optr = (unsigned *)image->data; p = (unsigned *)img->data + nwidth * nheight; for (x = 0; x < nwidth; x++) { nptr = p--; for (y = nheight; y; y--) { *nptr = *optr++; nptr -= nwidth; } } } } else { img = rotateImage(image, angle); } return img; } /* * Image rotation through Bresenham's line algorithm: * * If a square must be rotate by angle a, like in: * _______ * | B | * | /4\ | * | /3 8\| * | /2 7 /| * |A1 6 / | A_______B * | \5 / a| <--- |1 2 3 4| * |__C/_)_| |5 6 7 8| * C------- * * for each point P1 in the line from C to A * for each point P2 in the perpendicular line starting at P1 * get pixel from the source and plot at P2 * increment pixel location from source * */ static void copyLine(int x1, int y1, int x2, int y2, int nwidth, int format, unsigned char *dst, unsigned char **src) { unsigned char *s = *src; int dx, dy; int xi, yi; int offset; int dpr, dpru, p; dx = abs(x2 - x1); dy = abs(y2 - y1); if (x1 > x2) xi = -1; else xi = 1; if (y1 > y2) yi = -1; else yi = 1; if (dx >= dy) { dpr = dy << 1; dpru = dpr - (dx << 1); p = dpr - dx; while (dx-- >= 0) { /* fetch and draw the pixel */ offset = (x1 + y1 * nwidth) << 2; dst[offset++] = *s++; dst[offset++] = *s++; dst[offset++] = *s++; if (format == RRGBAFormat) dst[offset++] = *s++; else dst[offset++] = 255; /* calc next step */ if (p > 0) { x1 += xi; y1 += yi; p += dpru; } else { x1 += xi; p += dpr; } } } else { dpr = dx << 1; dpru = dpr - (dy << 1); p = dpr - dy; while (dy-- >= 0) { /* fetch and draw the pixel */ offset = (x1 + y1 * nwidth) << 2; dst[offset++] = *s++; dst[offset++] = *s++; dst[offset++] = *s++; if (format == RRGBAFormat) dst[offset++] = *s++; else dst[offset++] = 255; /* calc next step */ if (p > 0) { x1 += xi; y1 += yi; p += dpru; } else { y1 += yi; p += dpr; } } } *src = s; } static RImage *rotateImage(RImage * image, float angle) { RImage *img; int nwidth, nheight; int x1, y1; int x2, y2; int dx, dy; int xi, yi; int xx, yy; unsigned char *src, *dst; int dpr, dpru, p; /* only 180o for now */ if (angle > 180.0) angle -= 180.0; angle = (angle * PI) / 180.0; nwidth = ceil(abs(cos(angle) * image->width)) + ceil(abs(cos(PI / 2 - angle) * image->width)); nheight = ceil(abs(sin(angle) * image->height)) + ceil(abs(cos(PI / 2 - angle) * image->height)); img = RCreateImage(nwidth, nheight, True); if (!img) return NULL; src = image->data; dst = img->data; x1 = floor(abs(cos(PI / 2 - angle) * image->width)); y1 = 0; x2 = 0; y2 = floor(abs(sin(PI / 2 - angle) * image->width)); xx = floor(abs(cos(angle) * image->height)) - 1; yy = nheight - 1; printf("%ix%i, %i %i %i %i %i\n", nwidth, nheight, x1, y1, x2, y2, (int)((angle * 180.0) / PI)); dx = abs(x2 - x1); dy = abs(y2 - y1); if (x1 > x2) xi = -1; else xi = 1; if (y1 > y2) yi = -1; else yi = 1; if (dx >= dy) { dpr = dy << 1; dpru = dpr - (dx << 1); p = dpr - dx; while (dx-- >= 0) { copyLine(x1, y1, xx, yy, nwidth, image->format, dst, &src); /* calc next step */ if (p > 0) { x1 += xi; y1 += yi; xx += xi; yy += yi; p += dpru; } else { x1 += xi; xx += xi; p += dpr; } } } else { puts("NOT IMPLEMTENED"); return img; dpr = dx << 1; dpru = dpr - (dy << 1); p = dpr - dy; while (dy-- >= 0) { xx = abs(x1 * sin(angle * PI / 180.0)); yy = abs(y1 * cos(angle * PI / 180.0)); copyLine(x1, y1, xx, yy, nwidth, image->format, dst, &src); /* calc next step */ if (p > 0) { x1 += xi; y1 += yi; p += dpru; } else { y1 += yi; p += dpr; } } } return img; }