public unsafe void Rotate(Bitmap bmp, float angle)
{
int width=bmp.Width;
int height=bmp.Height;
/*
* right, down = positive
* p1------------p2
* | |
* p4------------p3
*
* p1(0,0), p2(width-1,0), p3(width-1,height-1), p4(0,height-1)
*
* In this coordinate system(left-handed coordinate system), clockwise rotation matrix (theta): (cos -sin
* sin cos)
*
*/
//Calculate new vertex
Point p1 = RotatePoint(new Point(0, 0), angle);
Point p2 = RotatePoint(new Point(width - 1, 0), angle);
Point p3 = RotatePoint(new Point(width - 1, height - 1), angle);
Point p4 = RotatePoint(new Point(0, height - 1), angle);
//Calculate new size
int dstWidth = Math.Max(Math.Abs(p3.X - p1.X) + 1, Math.Abs(p4.X - p2.X) + 1);
int dstHeight = Math.Max(Math.Abs(p3.Y - p1.X) + 1, Math.Abs(p4.Y - p2.Y) + 1);
/*
* Calculate offset between old and new coordinate system
* left-top point in new coordiante system -> (0,0)
*
*/
int offsetX = -new int[4] { p1.X, p2.X, p3.X, p4.X }.Min();
int offsetY = -new int[4] { p1.Y, p2.Y, p3.Y, p4.Y }.Min();
//create bmp
Bitmap dstBitmap = new Bitmap(dstWidth, dstHeight, PixelFormat.Format32bppArgb);
Rectangle srcRect = new Rectangle(0, 0, width, height);
Rectangle dstRect = new Rectangle(0, 0, dstWidth, dstHeight);
BitmapData srcBmpData = bmp.LockBits(srcRect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
BitmapData dstBmpData = dstBitmap.LockBits(dstRect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
//define sin and cos
double sin = Math.Sin(angle * Math.PI / 180);
double cos = Math.Cos(angle * Math.PI / 180);
int srcStride = srcBmpData.Stride;
int dstStride = dstBmpData.Stride;
//define pointer
byte* srcP = (byte*)srcBmpData.Scan0.ToPointer();
byte* dstP = (byte*)dstBmpData.Scan0.ToPointer();
Parallel.For(0,dstHeight,i=>
{
Parallel.For(0, dstWidth, j =>
{
int k = 4 * j + i * dstStride;
//Calculate corresponding point in old coordinate system
Point oldPoint = RotatePoint(new Point(j - offsetX, i - offsetY), -angle);
if (oldPoint.X >= 0 && oldPoint.X < width && oldPoint.Y >= 0 && oldPoint.Y < height)
{
dstP[k] = srcP[4 * oldPoint.X + srcStride * oldPoint.Y];
dstP[k + 1] = srcP[4 * oldPoint.X + srcStride * oldPoint.Y + 1];
dstP[k + 2] = srcP[4 * oldPoint.X + srcStride * oldPoint.Y + 2];
dstP[k + 3] = srcP[4 * oldPoint.X + srcStride * oldPoint.Y + 3];
}
else
{
dstP[k] = dstP[k + 1] = dstP[k + 2] = 0xff;
dstP[k + 3] = 0x0;
}
});
});
bmp.UnlockBits(srcBmpData);
dstBitmap.UnlockBits(dstBmpData);
bmp = (Bitmap)dstBitmap.Clone();
dstBitmap.Dispose();
width = bmp.Width;
height = bmp.Height;
}