
using System;
using System.Web;
using System.Drawing.Drawing2D;
using System.Drawing;
using System.Collections.Generic;
using System.Drawing.Imaging;

using PaintDotNet;
using PaintDotNet.Base;
using PaintDotNet.Effects;
using System;
using System.Drawing;
using System.Runtime.InteropServices;

/// <summary>
/// Summary description for ImageUtility
/// </summary>
public class ImageUtility
{
	protected ImageUtility()
	{
    }
    private static object SyncLock = new object();


    public static Bitmap RotateImage(Image image, Color backgroundColor, float angle2)
    {
        if (angle2 == 0)
        {
            return new Bitmap(image); // Don't waste time rotating if there is no need
        }
        lock (SyncLock)
        {
            Surface surface = Surface.CopyFromBitmap((Bitmap)image);
            RectangleF bounds = GetRotatedPoints(angle2, image.Width, image.Height);
            Size outputSize = bounds.Size.ToSize();
            Size size = new Size(outputSize.Width + Math.Abs((int)bounds.Left), outputSize.Height);
            Surface dstSurface = new Surface(size);
            Effect effect = new RotateZoomEffect();
            double angle = angle2; 
            double dist = 0; 
            RotateZoomEffectConfigToken token = new RotateZoomEffectConfigToken(true, (float)1, (float)1.0, (float)angle, (float)1.0, new PointF(75, 75), false, true);
            token.Offset = new PointF((outputSize.Width - image.Width) / (float)100, bounds.Y / 100); // new PointF((outputSize.Width - image.Width) / (float)100, (outputSize.Height - image.Height) / (float)100.0);//new PointF(outputSize.Width - image.Width, outputSize.Height - image.Height);
            token.PreRotateZ = (float)(angle);
            token.PostRotateZ = (float)(-angle - angle2 * Math.PI / 180);
            token.Tilt = (float)Math.Asin(dist / 90);
            token.SourceAsBackground = false;
            token.Tile = false;
            token.Zoom = (float)Math.Pow(2.0, (512 - 512) / 128.0);
            RenderArgs srcArgs = new RenderArgs(surface);
            RenderArgs dstArgs = new RenderArgs(dstSurface);
            effect.Render(token, dstArgs, srcArgs, new Rectangle[] { new Rectangle(0, 0, (int)size.Width, (int)size.Height) });
            using (Bitmap bmp = dstSurface.CreateAliasedBitmap())
            {
                Bitmap bmp2 = new Bitmap(size.Width, size.Height);
                Graphics g = Graphics.FromImage(bmp2);
                g.Clear(backgroundColor);
                g.DrawImage(bmp, 0, 0);
                return bmp2;
            }            
        }
    }

    private static RectangleF GetRotatedPoints(float angle, int imageWidth, int imageHeight)
    {

        PointF[] points = new PointF[3];
        byte[] types = new byte[3];

        double radAngle = (angle * Math.PI) / 180;
        double sin = Math.Sin(radAngle);
        double cos = Math.Cos(radAngle);

        double halfWidth = imageWidth / 2;
        double halfHeight = imageHeight / 2;

        double cosWidth = cos * halfWidth;
        double cosHeight = cos * halfHeight;
        double sinWidth = sin * halfWidth;
        double sinHeight = sin * halfHeight;

        points[0] = new PointF
        (
        (float)(halfWidth - cosWidth + sinHeight),
        (float)(halfHeight - cosHeight - sinWidth)
        );

        points[1] = new PointF
        (
        (float)(halfWidth + cosWidth + sinHeight),
        (float)(halfHeight - cosHeight + sinWidth)
        );

        points[2] = new PointF
        (
        (float)(halfWidth - cosWidth - sinHeight),
        (float)(halfHeight + cosHeight - sinWidth)
        );

        types[0] = (byte)PathPointType.Start;
        types[1] = (byte)PathPointType.Line;
        types[2] = (byte)PathPointType.Line;
        //types[3] = (byte)PathPointType.Start;

        //GraphicsPath p = new GraphicsPath(points, types);
        GraphicsPath p = new GraphicsPath();
        p.AddRectangle(new Rectangle(0, 0, imageWidth, imageHeight));
        Matrix X = new Matrix();

        PointF point = new PointF(imageWidth * 0.5f, imageHeight * 0.5f);
        X.Rotate(angle); //, point); //, point)     
        p.Transform(X);
        RectangleF bounds = p.GetBounds();

        /*
        points[0] = new PointF
        (
points[0].X + Math.Abs(bounds.X),
points[0].Y + Math.Abs(bounds.Y)
        );
      */

        float currentX = 0;
        float currentY = float.MaxValue;
        /*
        PointF topLeft = points.Find (delegate (PointF match) {
            return match.X < currentX;
        });
         */
        foreach (PointF po in points)
        {
            if (po.X < currentX)
            {
                currentX = po.X;
            }
            if (po.Y < currentY)
            {
                currentY = po.Y;
            }
        }
        currentX = Math.Abs(currentX);
        currentY = -1 * currentY; // Math.Abs(currentY);

        for (int i = 0; i < points.Length; i++)
        {
            points[i].X += currentX;
            points[i].Y += currentY;
        }

        return new RectangleF(currentX,currentY, bounds.Width, bounds.Height);
    }


}
