using Newtonsoft.Json.Linq;
using ryCommon.sType;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.TrayNotify;

namespace ryCommon
{
    /// <summary>
    /// 图片相关API
    /// </summary>
    public static class RyImage
    {
        #region 内部方法
        private static EncoderParameters GetEncoderParameters(long quality=100L)
        {
            System.Drawing.Imaging.Encoder myEncoder;
            EncoderParameter myEncoderParameter;
            EncoderParameters myEncoderParameters;

            myEncoder = System.Drawing.Imaging.Encoder.Quality;
            myEncoderParameters = new EncoderParameters(1);
            // Save the bitmap as a JPEG file with quality level 100.
            myEncoderParameter = new EncoderParameter(myEncoder, quality);
            myEncoderParameters.Param[0] = myEncoderParameter;
            return myEncoderParameters;
        }
        private static ImageCodecInfo GetEncoderInfo(String mimeType)
        {
            int j;
            ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();
            for (j = 0; j < encoders.Length; ++j)
            {
                if (encoders[j].MimeType == mimeType)
                    return encoders[j];
            }
            return null;
        }
        private static ImageCodecInfo GetEncoderInfo(ryCommon.Pram.ImageType type)
        {
            #region 图片格式
            ImageCodecInfo myImageCodecInfo;
            string type_str = "image/jpeg";
            switch (type)
            {
                case Pram.ImageType.Bmp:
                    type_str = "image/bmp";
                    break;
                case Pram.ImageType.Jpeg:
                    type_str = "image/jpeg";
                    break;
                case Pram.ImageType.Gif:
                    type_str = "image/gif";
                    break;
                case Pram.ImageType.Tiff:
                    type_str = "image/tiff";
                    break;
                case Pram.ImageType.Png:
                    type_str = "image/png";
                    break;
            }
            myImageCodecInfo = GetEncoderInfo(type_str);
            #endregion
            return myImageCodecInfo;
        }
        #endregion
        /// <summary>
        /// 检测文件真实扩展名
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static FileExtension CheckImgFile(string fileName)
        {
            FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
            System.IO.BinaryReader br = new System.IO.BinaryReader(fs);
            string fileType = string.Empty;
            FileExtension extension;
            try
            {
                byte data = br.ReadByte();
                fileType += data.ToString();
                data = br.ReadByte();
                fileType += data.ToString();
                try
                {
                    extension = (FileExtension)Enum.Parse(typeof(FileExtension), fileType);
                }
                catch
                {

                    extension = FileExtension.VALIDFILE;
                }
            }
            catch
            {
                extension = FileExtension.VALIDFILE;
            }
            finally
            {
                if (fs != null)
                {
                    fs.Close();
                    br.Close();
                }
            }
            return extension;
        }
        /// <summary>
        /// 检测文件真实扩展名
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static FileExtension CheckImgFile(byte[] bytes)
        {
            string fileType = string.Empty;
            FileExtension extension;
            try
            {
                if (bytes.Length <= 2) { return FileExtension.VALIDFILE; }
                byte data = bytes[0];
                fileType += data.ToString();
                data = bytes[1];
                fileType += data.ToString();
                try
                {
                    extension = (FileExtension)Enum.Parse(typeof(FileExtension), fileType);
                }
                catch
                {

                    extension = FileExtension.VALIDFILE;
                }
            }
            catch
            {
                extension = FileExtension.VALIDFILE;
            }
            finally
            {
            }
            return extension;
        }
        /// <summary>
        /// 从文件或Url中加载图片,使用本方法，不会导致图片文件被占用。(如果是webp格式,需要引入OpenXmlPowerTools)
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public static Image LoadPic(string url)
        {
            if (url.IndexOfEx("http") == 0)
            {
                Image image = null;
                try
                {
                    WebRequest webreq = WebRequest.Create(url);
                    WebResponse webres = webreq.GetResponse();
                    byte[] ResponseByte = null;
                    using (MemoryStream _stream = new MemoryStream())
                    {
                        webres.GetResponseStream().CopyTo(_stream, 1024);
                        //获取Byte
                        ResponseByte = _stream.ToArray();
                        var ext = CheckImgFile(ResponseByte);
                        if (ext == FileExtension.WebP)
                        {
                            using (WebP webP = new WebP())
                            {
                                image = webP.Decode(ResponseByte);
                            }
                        }
                        else
                        {
                            image = Image.FromStream(_stream);
                        }
                    }
                }
                catch { }
                return image;
            }
            else
            {
                if (!System.IO.File.Exists(url))
                { return null; }
                try
                {
                    var ext= CheckImgFile(url);
                    FileStream fs = new FileStream(url, FileMode.Open, FileAccess.Read);
                    //把文件读取到字节数组 
                    byte[] data = new byte[fs.Length];
                    fs.Read(data, 0, data.Length);
                    fs.Close();
                    //实例化一个内存流--->把从文件流中读取的内容[字节数组]放到内存流中去 
                    MemoryStream ms = new MemoryStream(data);
                    if(ext== FileExtension.WebP)
                    {
                        using (WebP webP = new WebP())
                        {
                           return webP.Decode(data);
                        }
                    }
                    //设置图片框 pictureBox1中的图片 
                    return Image.FromStream(ms);
                }
                catch(Exception) 
                { return null; }
            }
        }
        #region SaveHighQualityImage 方法合集
        /// <summary>
        /// 保存高质量不失真照片
        /// </summary>
        /// <param name="m"></param>
        /// <param name="path"></param>
        /// <param name="type"></param>
        public static void SaveHighQualityImage(this Bitmap m, string path, ryCommon.Pram.ImageType type)
        {
            SaveHighQualityImage(m, path, type, 100);
        }
        /// <summary>
        /// 保存高质量不失真照片
        /// </summary>
        /// <param name="m"></param>
        /// <param name="path"></param>
        /// <param name="type"></param>
        /// <param name="quality">图片质量,0~100</param>
        public static void SaveHighQualityImage(this Bitmap m, string path, ryCommon.Pram.ImageType type,int quality)
        {
            m.Save(path, GetEncoderInfo(type), GetEncoderParameters(quality));
        }
        /// <summary>
        /// 保存高质量不失真照片
        /// </summary>
        /// <param name="m"></param>
        /// <param name="ms"></param>
        /// <param name="type"></param>
        public static void SaveHighQualityImage(this Bitmap m, MemoryStream ms, ryCommon.Pram.ImageType type)
        {
            SaveHighQualityImage(m,ms,type, 100);
        }
        /// <summary>
        /// 保存高质量不失真照片
        /// </summary>
        /// <param name="m"></param>
        /// <param name="ms"></param>
        /// <param name="type"></param>
        /// <param name="quality">图片质量,0~100</param>
        public static void SaveHighQualityImage(this Bitmap m, MemoryStream ms, ryCommon.Pram.ImageType type, int quality)
        {
            m.Save(ms, GetEncoderInfo(type), GetEncoderParameters(quality));
        }
        /// <summary>
        /// 保存高质量不失真照片
        /// </summary>
        /// <param name="m"></param>
        /// <param name="path"></param>
        /// <param name="type"></param>
        public static void SaveHighQualityImage(this Image m, string path, ryCommon.Pram.ImageType type)
        {
            SaveHighQualityImage(m,path, type, 100);
        }
        /// <summary>
        /// 保存高质量不失真照片
        /// </summary>
        /// <param name="m"></param>
        /// <param name="path"></param>
        /// <param name="type"></param>
        /// <param name="quality">图片质量,0~100</param>
        public static void SaveHighQualityImage(this Image m, string path, ryCommon.Pram.ImageType type, int quality)
        {
            if(!System.IO.Directory.Exists(System.IO.Path.GetDirectoryName(path)))
            {
                RyFiles.CreateDirectory(System.IO.Path.GetDirectoryName(path));
            }
            m.Save(path, GetEncoderInfo(type), GetEncoderParameters(quality));
        }
        /// <summary>
        /// 保存高质量不失真照片
        /// </summary>
        /// <param name="m"></param>
        /// <param name="path"></param>
        public static bool SaveHighQualityImage(this Bitmap m, string path)
        {
            return SaveHighQualityImage((Image)m, path);
        }
        /// <summary>
        /// 保存高质量不失真照片
        /// </summary>
        /// <param name="m"></param>
        /// <param name="path"></param>
        public static bool SaveHighQualityImage(this Image m, string path)
        {
            if (!System.IO.Directory.Exists(System.IO.Path.GetDirectoryName(path)))
            {
                RyFiles.CreateDirectory(System.IO.Path.GetDirectoryName(path));
            }
            ryCommon.Pram.ImageType type = Pram.ImageType.Png;
            var ext = System.IO.Path.GetExtension(path).ToLower();
            switch (ext)
            {
                case ".png":
                    m.Save(path, GetEncoderInfo(type), GetEncoderParameters());
                    break;
                case ".jpg":
                    type = Pram.ImageType.Jpeg;
                    m.Save(path, GetEncoderInfo(type), GetEncoderParameters());
                    break;
                case ".bmp":
                    type = Pram.ImageType.Bmp;
                    m.Save(path, GetEncoderInfo(type), GetEncoderParameters());
                    break;
                case ".gif":
                    type = Pram.ImageType.Gif;
                    m.Save(path, GetEncoderInfo(type), GetEncoderParameters());
                    break;
                case ".tif":
                    type = Pram.ImageType.Tiff;
                    m.Save(path, GetEncoderInfo(type), GetEncoderParameters());
                    break;
                default:
                    return false;
            }
            return true;
        }
        #region 图片旋转函数
        /// <summary>
        /// 以逆时针为方向对图像进行旋转
        /// </summary>
        /// <param name="b">位图流</param>
        /// <param name="angle">旋转角度[0,360](前台给的)</param>
        /// <returns></returns>
        public static Bitmap Rotate(this Bitmap b, int angle)
        {
            angle %= 360;
            //弧度转换
            double radian = angle * Math.PI / 180.0;
            double cos = Math.Cos(radian);
            double sin = Math.Sin(radian);
            //原图的宽和高
            int w = b.Width;
            int h = b.Height;
            int W = (int)(Math.Max(Math.Abs(w * cos - h * sin), Math.Abs(w * cos + h * sin)));
            int H = (int)(Math.Max(Math.Abs(w * sin - h * cos), Math.Abs(w * sin + h * cos)));
            //目标位图
            Bitmap dsImage = new Bitmap(W, H);
            System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(dsImage);
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear;
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            //计算偏移量
            Point Offset = new Point((W - w) / 2, (H - h) / 2);
            //构造图像显示区域：让图像的中心与窗口的中心点一致
            Rectangle rect = new Rectangle(Offset.X, Offset.Y, w, h);
            Point center = new Point(rect.X + rect.Width / 2, rect.Y + rect.Height / 2);
            g.TranslateTransform(center.X, center.Y);
            g.RotateTransform(360 - angle);
            //恢复图像在水平和垂直方向的平移
            g.TranslateTransform(-center.X, -center.Y);
            g.DrawImage(b, rect);
            //重至绘图的所有变换
            g.ResetTransform();
            g.Save();
            g.Dispose();
            //dsImage.Save("yuancd.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
            return dsImage;
        }
    #endregion 图片旋转函数
        /// <summary>
        /// 是否包括透明像素
        /// </summary>
        /// <param name="i"></param>
        /// <returns></returns>
        /// <exception cref="Exception">操作失败</exception>
        public static bool HasTransparentPixel(this System.Drawing.Image i)
        {
            using (Bitmap bitmap = new Bitmap(i))
            {
                for (int x = 0; x < bitmap.Width; x++)
                {
                    for (int y = 0; y < bitmap.Height; y++)
                    {
                        if (bitmap.GetPixel(x, y).A < 255)
                        {
                            return true;
                        }
                    }
                }
            }

            return false;
        }
        /// <summary>
        /// 矩形边界
        /// </summary>
        /// <param name="bounds"></param>
        /// <param name="rect"></param>
        /// <returns></returns>
        private static Size ScaleRectangleToFitBounds(Size bounds, Size rect)
        {
            if (rect.Width < bounds.Width && rect.Height < bounds.Height)
            {
                return rect;
            }

            if (bounds.Width == 0 || bounds.Height == 0)
            {
                return new Size(0, 0);
            }

            double scaleFactorWidth = (double)rect.Width / bounds.Width;
            double scaleFactorHeight = (double)rect.Height / bounds.Height;

            double scaleFactor = Math.Max(scaleFactorWidth, scaleFactorHeight);
            return new Size()
            {
                Width = (int)(rect.Width / scaleFactor),
                Height = (int)(rect.Height / scaleFactor)
            };
        }
        /// <summary>
        /// 计算水印位置
        /// </summary>
        /// <param name="watermarkPosition"></param>
        /// <param name="imageSize"></param>
        /// <param name="watermarkSize"></param>
        /// <returns></returns>
        private static Point CalculateWatermarkPosition(WatermarkPosition watermarkPosition, Size imageSize, Size watermarkSize)
        {
            Point position = new Point();
            switch (watermarkPosition)
            {
                case WatermarkPosition.TopLeftCorner:
                    position.X = 0;
                    position.Y = 0;
                    break;
                case WatermarkPosition.TopCenter:
                    position.X = (imageSize.Width / 2) - (watermarkSize.Width / 2);
                    position.Y = 0;
                    break;
                case WatermarkPosition.TopRightCorner:
                    position.X = imageSize.Width - watermarkSize.Width;
                    position.Y = 0;
                    break;
                case WatermarkPosition.CenterLeft:
                    position.X = 0;
                    position.Y = (imageSize.Height / 2) - (watermarkSize.Height / 2);
                    break;
                case WatermarkPosition.Center:
                    position.X = (imageSize.Width / 2) - (watermarkSize.Width / 2);
                    position.Y = (imageSize.Height / 2) - (watermarkSize.Height / 2);
                    break;
                case WatermarkPosition.CenterRight:
                    position.X = imageSize.Width - watermarkSize.Width;
                    position.Y = (imageSize.Height / 2) - (watermarkSize.Height / 2);
                    break;
                case WatermarkPosition.BottomLeftCorner:
                    position.X = 0;
                    position.Y = imageSize.Height - watermarkSize.Height;
                    break;
                case WatermarkPosition.BottomCenter:
                    position.X = (imageSize.Width / 2) - (watermarkSize.Width / 2);
                    position.Y = imageSize.Height - watermarkSize.Height;
                    break;
                case WatermarkPosition.BottomRightCorner:
                    position.X = imageSize.Width - watermarkSize.Width;
                    position.Y = imageSize.Height - watermarkSize.Height;
                    break;
            }
            return position;
        }
        /// <summary>
        /// 写入水印
        /// </summary>
        /// <param name="image">原图</param>
        /// <param name="wmImg">水印图片</param>
        /// <param name="Position">水印位置</param>
        /// <param name="opacity">不透明度(0~1),越小越透明</param>
        /// <returns></returns>
        public static Bitmap DrawWatermark(this Image image, Bitmap wmImg, WatermarkPosition Position, float opacity)
        {
            return DrawWatermark(image, wmImg, new List<WatermarkPosition>() { Position }, 0,0, opacity);
        }
        /// <summary>
        /// 写入水印
        /// </summary>
        /// <param name="image">原图</param>
        /// <param name="wmImg">水印图片</param>
        /// <param name="Position">水印位置</param>
        /// <param name="offset_x">x坐标偏移</param>
        /// <param name="offset_y">y坐标偏移</param>
        /// <param name="opacity">不透明度(0~1),越小越透明</param>
        /// <returns></returns>
        public static Bitmap DrawWatermark(this Image image, Bitmap wmImg, WatermarkPosition Position, int offset_x, int offset_y, float opacity)
        {
            return DrawWatermark(image, wmImg, new List<WatermarkPosition>() { Position }, offset_x, offset_y, opacity);
        }
        /// <summary>
        /// 写入水印
        /// </summary>
        /// <param name="image">原图</param>
        /// <param name="wmImg">水印图片</param>
        /// <param name="PositionList">水印位置</param>
        /// <param name="offset_x">x坐标偏移</param>
        /// <param name="offset_y">y坐标偏移</param>
        /// <param name="opacity">不透明度(0~1),越小越透明</param>
        /// <returns></returns>
        public static Bitmap DrawWatermark(this Image image, Bitmap wmImg, List<WatermarkPosition> PositionList,int offset_x, int offset_y, float opacity)
        {
            Bitmap bm1 = new Bitmap(image); //克隆原图，它也是我们的返回值
            using (Graphics g = Graphics.FromImage(bm1))
            {
                Size calculatedWatermarkSize = ScaleRectangleToFitBounds(bm1.Size, wmImg.Size);

                if (calculatedWatermarkSize.Width == 0 || calculatedWatermarkSize.Height == 0)
                {
                    return bm1;
                }
                Bitmap scaledWatermarkBitmap =
                    new Bitmap(calculatedWatermarkSize.Width, calculatedWatermarkSize.Height);
                using (Graphics watermarkGraphics = Graphics.FromImage(scaledWatermarkBitmap))
                {
                    ColorMatrix opacityMatrix = new ColorMatrix
                    {
                        Matrix33 = opacity
                    };
                    ImageAttributes attrs = new ImageAttributes();
                    attrs.SetColorMatrix(opacityMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
                    watermarkGraphics.DrawImage(wmImg,
                        new Rectangle(0, 0, scaledWatermarkBitmap.Width, scaledWatermarkBitmap.Height),
                        0, 0, wmImg.Width, wmImg.Height,
                        GraphicsUnit.Pixel, attrs);
                    attrs.Dispose();
                }

                foreach (var position in PositionList)
                {
                    if(position== WatermarkPosition.FullScreenTile)
                    {
                        //g.RotateTransform(-45);
                        //scaledWatermarkBitmap=scaledWatermarkBitmap.Rotate(45);
                        var space = 100;
                        var start_y = ((scaledWatermarkBitmap.Width - scaledWatermarkBitmap.Height) / Math.Sqrt(2)) + (Math.Sqrt(2) * scaledWatermarkBitmap.Height)- scaledWatermarkBitmap.Size.Height;
                        for (int i_y = start_y.ToInt()-50+offset_y; i_y < image.Size.Height*2; i_y += scaledWatermarkBitmap.Height + space)
                        {
                            for (int i_x = offset_x; i_x < image.Size.Width; i_x += scaledWatermarkBitmap.Width + space)
                            {
                                var bottomleft_x = i_x;
                                var bottomleft_y = i_y+ scaledWatermarkBitmap.Size.Height;
                                var bottomright_x = i_x  +(scaledWatermarkBitmap.Size.Width / Math.Sqrt(2));//水印右上角x坐标
                                var bottomright_y = bottomleft_y - (scaledWatermarkBitmap.Size.Width / Math.Sqrt(2));//水印右上角y坐标
                                if (bottomright_x> image.Size.Width){ continue; }
                                if (bottomright_y< 0){ continue; }
                                if(bottomright_y > image.Size.Height) {
                                    continue; 
                                }
                                if (bottomleft_y > image.Size.Height) {
                                    continue; 
                                }
                                //if ((xx* Math.Sqrt(2))< scaledWatermarkBitmap.Size.Width) { continue; }
                                g.TranslateTransform(bottomleft_x, bottomleft_y);
                                g.RotateTransform(-45);
                                //if (i_x+ scaledWatermarkBitmap.Width> image.Size.Width) { continue; }
                                //if (i_y + scaledWatermarkBitmap.Height > image.Size.Height) { continue; }
                                g.DrawImage(scaledWatermarkBitmap,
                                 new Rectangle(new Point(0,0), scaledWatermarkBitmap.Size),
                                  0, 0, scaledWatermarkBitmap.Width, scaledWatermarkBitmap.Height, GraphicsUnit.Pixel);
                                g.TranslateTransform(-bottomleft_x, -bottomleft_y);
                                g.RotateTransform(45);
                                ///////重置绘图平面的所有变换
                                g.ResetTransform();
                            }
                        }
                        continue;
                    }
                    Point watermarkPosition = CalculateWatermarkPosition(position,
                        image.Size, calculatedWatermarkSize);
                    watermarkPosition.Offset(offset_x, offset_y);
                    if(watermarkPosition.X<0 || watermarkPosition.Y < 0) { continue; }
                    if (watermarkPosition.X > bm1.Width- calculatedWatermarkSize.Width || watermarkPosition.Y>bm1.Height- calculatedWatermarkSize.Height) { continue; }
                    g.DrawImage(scaledWatermarkBitmap,
                        new Rectangle(watermarkPosition, calculatedWatermarkSize),
                        0, 0, calculatedWatermarkSize.Width, calculatedWatermarkSize.Height, GraphicsUnit.Pixel);
                }
                scaledWatermarkBitmap.Dispose();
            }
            return bm1;
        }
        /// <summary>
        /// 计算最大字体大小
        /// </summary>
        /// <param name="text"></param>
        /// <param name="angle"></param>
        /// <param name="fontName"></param>
        /// <param name="maxTextSize"></param>
        /// <param name="g"></param>
        /// <returns></returns>
        private static int ComputeMaxFontSize(string text, int angle, string fontName, Size maxTextSize, Graphics g)
        {
            for (int fontSize = 2; ; fontSize++)
            {
                using (Font tmpFont = new Font(fontName, fontSize, FontStyle.Bold))
                {
                    SizeF textSize = g.MeasureString(text, tmpFont);
                    SizeF rotatedTextSize = CalculateRotatedRectSize(textSize, angle);
                    if (((int)rotatedTextSize.Width > maxTextSize.Width) ||
                        ((int)rotatedTextSize.Height > maxTextSize.Height))
                    {
                        return fontSize - 1;
                    }
                }
            }
        }
        /// <summary>
        /// 计算旋转矩形大小
        /// </summary>
        /// <param name="rectSize"></param>
        /// <param name="angleDeg"></param>
        /// <returns></returns>
        private static SizeF CalculateRotatedRectSize(SizeF rectSize, double angleDeg)
        {
            double angleRad = angleDeg * Math.PI / 180;
            double width = rectSize.Height * Math.Abs(Math.Sin(angleRad)) +
                rectSize.Width * Math.Abs(Math.Cos(angleRad));
            double height = rectSize.Height * Math.Abs(Math.Cos(angleRad)) +
                rectSize.Width * Math.Abs(Math.Sin(angleRad));
            return new SizeF((float)width, (float)height);
        }
        /// <summary>
        /// 写入水印文字
        /// </summary>
        /// <param name="image">图片</param>
        /// <param name="wmText">水印文字</param>
        /// <param name="WatermarkFont">水印字体名字</param>
        /// <param name="TextColor">字体颜色</param>
        /// <param name="TextSize">字体大小</param>
        /// <param name="TextRotatedDegree">旋转角度</param>
        /// <param name="PositionList">水印位置</param>
        /// <param name="x">x坐标偏移</param>
        /// <param name="y">y坐标偏移</param>
        /// <param name="opacity">不透明度(0~1),越小越透明</param>
        /// <returns></returns>
        public static Bitmap DrawWatermark(this Image image, string wmText,string WatermarkFont,Color TextColor, int TextSize, int TextRotatedDegree, List<WatermarkPosition> PositionList, int x, int y, float opacity)
        {
            Bitmap bm1 = new Bitmap(image); //克隆原图，它也是我们的返回值
            using (Graphics g = Graphics.FromImage(bm1))
            {
                g.SmoothingMode = SmoothingMode.AntiAlias;
                g.TextRenderingHint = TextRenderingHint.AntiAlias;

                string text = wmText;

                int textAngle = TextRotatedDegree;
                double sizeFactor = (double)TextSize / 100;
                Size maxTextSize = new Size(
                    (int)(bm1.Width * sizeFactor),
                    (int)(bm1.Height * sizeFactor));

                int fontSize = ComputeMaxFontSize(text, textAngle, WatermarkFont, maxTextSize, g);

                Font font = new Font(WatermarkFont, (float)fontSize, FontStyle.Bold);
                SizeF originalTextSize = g.MeasureString(text, font);
                SizeF rotatedTextSize = CalculateRotatedRectSize(originalTextSize, textAngle);

                Bitmap textBitmap = new Bitmap((int)rotatedTextSize.Width, (int)rotatedTextSize.Height,
                    PixelFormat.Format32bppArgb);
                using (Graphics textG = Graphics.FromImage(textBitmap))
                {
                    Color color = Color.FromArgb((int)(opacity * 255), TextColor);
                    SolidBrush brush = new SolidBrush(color);

                    textG.TranslateTransform(rotatedTextSize.Width / 2, rotatedTextSize.Height / 2);
                    textG.RotateTransform((float)textAngle);
                    textG.DrawString(text, font, brush, x-(originalTextSize.Width / 2),
                        y-(originalTextSize.Height / 2));
                    textG.ResetTransform();

                    brush.Dispose();
                }

                foreach (var position in PositionList)
                {
                    Point textPosition = CalculateWatermarkPosition(position,
                        bm1.Size, rotatedTextSize.ToSize());
                    g.DrawImage(textBitmap, textPosition);
                }
                textBitmap.Dispose();
                font.Dispose();
            }
            return bm1;
        }
        /// <summary>
        /// 写入水印文字
        /// </summary>
        /// <param name="image">图片</param>
        /// <param name="wmText">水印文字</param>
        /// <param name="WatermarkFont">水印字体名字</param>
        /// <param name="TextColor">字体颜色</param>
        /// <param name="TextSize">字体大小</param>
        /// <param name="TextRotatedDegree">旋转角度</param>
        /// <param name="Position">水印位置</param>
        /// <param name="x">x坐标偏移</param>
        /// <param name="y">y坐标偏移</param>
        /// <param name="opacity">不透明度(0~1),越小越透明</param>
        /// <returns></returns>
        public static Bitmap DrawWatermark(this Image image, string wmText, string WatermarkFont, Color TextColor, int TextSize, int TextRotatedDegree, WatermarkPosition Position, int x, int y, float opacity)
        {
            return DrawWatermark(image, wmText, WatermarkFont, TextColor, TextSize, TextRotatedDegree,
                new List<WatermarkPosition>() { Position }, x, y, opacity);
        }
        /// <summary>
        /// 写入水印文字
        /// </summary>
        /// <param name="image">图片</param>
        /// <param name="wmText">水印文字</param>
        /// <param name="WatermarkFont">水印字体名字</param>
        /// <param name="TextColor">字体颜色</param>
        /// <param name="TextSize">字体大小</param>
        /// <param name="TextRotatedDegree">旋转角度</param>
        /// <param name="Position">水印位置</param>
        /// <param name="opacity">不透明度(0~1),越小越透明</param>
        /// <returns></returns>
        public static Bitmap DrawWatermark(this Image image, string wmText, string WatermarkFont, Color TextColor, int TextSize, int TextRotatedDegree, WatermarkPosition Position, float opacity)
        {
            return DrawWatermark(image, wmText, WatermarkFont, TextColor, TextSize, TextRotatedDegree,
                new List<WatermarkPosition>() { Position }, 0,0, opacity);
        }
        /// <summary>
        /// 往图片右下角写入水印文字
        /// </summary>
        /// <param name="image">图片</param>
        /// <param name="wmText">水印文字</param>
        /// <param name="WatermarkFont">水印字体名字</param>
        /// <param name="TextColor">字体颜色</param>
        /// <param name="TextSize">字体大小</param>
        /// <param name="opacity">不透明度(0~1),越小越透明</param>
        /// <returns></returns>
        public static Bitmap DrawWatermark(this Image image, string wmText, string WatermarkFont, Color TextColor, int TextSize, float opacity)
        {
            return DrawWatermark(image, wmText, WatermarkFont, TextColor, TextSize, 0,
                new List<WatermarkPosition>() {  WatermarkPosition.BottomRightCorner }, 0, 0, opacity);
        }
        /// <summary>
        /// 往图片右下角写入水印文字
        /// </summary>
        /// <param name="image">图片</param>
        /// <param name="wmText">水印文字</param>
        /// <param name="WatermarkFont">水印字体名字</param>
        /// <param name="TextColor">字体颜色</param>
        /// <param name="TextSize">字体大小</param>
        /// <returns></returns>
        public static Bitmap DrawWatermark(this Image image, string wmText, string WatermarkFont, Color TextColor, int TextSize)
        {
            return DrawWatermark(image, wmText, WatermarkFont, TextColor, TextSize, 0,
                new List<WatermarkPosition>() { WatermarkPosition.BottomRightCorner }, 0, 0, 0.1f);
        }
        /// <summary>
        /// 缩放
        /// </summary>
        /// <param name="i"></param>
        /// <param name="width">宽</param>
        /// <param name="height">高</param>
        /// <param name="mode">插值算法</param>
        /// <returns>返回缩放后的图片</returns>
        /// <exception cref="NullReferenceException">Image 不能为 null</exception>
        /// <exception cref="Exception">操作失败</exception>
        public static System.Drawing.Image Zoom(this System.Drawing.Image i, int width, int height, InterpolationMode mode)
        {
            Bitmap bitmap = new Bitmap(width, height);
            using (Graphics g = Graphics.FromImage(bitmap))
            {
                g.InterpolationMode = mode;
                g.Clear(Color.Empty);
                g.DrawImage(i, new Rectangle(0, 0, width, height), new Rectangle(0, 0, i.Width, i.Height), GraphicsUnit.Pixel);
            }
            return bitmap;
        }
        /// <summary>
        /// 缩放
        /// </summary>
        /// <param name="i"></param>
        /// <param name="width">宽</param>
        /// <param name="height">高</param>
        /// <returns>返回缩放后的图片</returns>
        /// <exception cref="NullReferenceException">Image 不能为 null</exception>
        /// <exception cref="Exception">操作失败</exception>
        public static System.Drawing.Image Zoom(this System.Drawing.Image i, int width, int height)
        {
            Bitmap bitmap = new Bitmap(width, height);
            using (Graphics g = Graphics.FromImage(bitmap))
            {
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                g.Clear(Color.Empty);
                g.DrawImage(i, new Rectangle(0, 0, width, height), new Rectangle(0, 0, i.Width, i.Height), GraphicsUnit.Pixel);
            }
            return bitmap;
        }
        #endregion
        /// <summary>
        /// 根据原边长和新边长计算绘制的起始点坐标
        /// </summary>
        /// <param name="oldLength"></param>
        /// <param name="newLength"></param>
        /// <returns></returns>
        private static int GetSrc(int oldLength, int newLength)
        {
            return ((float)(oldLength - newLength) / 2).ToInt();
        }
        /// <summary>
        /// 获取缩放模式
        /// </summary>
        /// <param name="oldWidth"></param>
        /// <param name="oldHeight"></param>
        /// <param name="newWidth"></param>
        /// <param name="newHeight"></param>
        /// <param name="crop">是否裁剪图片</param>
        /// <returns></returns>
        private static ResizeMode GetMode(int oldWidth, int oldHeight, int newWidth, int newHeight, bool crop)
        {
            float oldScale = (float)oldWidth / oldHeight;
            float newScale = (float)newWidth / newHeight;
            if (crop)
            {
                return oldScale < newScale ? ResizeMode.WidthFirst : ResizeMode.HeightFirst;
            }
            else
            {
                return oldScale > newScale ? ResizeMode.WidthFirst : ResizeMode.HeightFirst;
            }
        }
        /// <summary>
        /// 裁剪或填充
        /// </summary>
        /// <param name="image"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="background">背景色</param>
        /// <param name="mode">插值算法</param>
        /// <returns></returns>
        /// <exception cref="NullReferenceException">Image 不能为 null</exception>
        /// <exception cref="Exception">操作失败</exception>
        private static System.Drawing.Image CropOrFill(this System.Drawing.Image image, int width, int height, Color background, InterpolationMode mode)
        {
            Bitmap bitmap = new Bitmap(width, height);
            using (Graphics g = Graphics.FromImage(bitmap))
            {
                g.InterpolationMode = mode;
                int srcX = GetSrc(image.Width, width);
                int srcY = GetSrc(image.Height, height);
                g.Clear(background);
                g.DrawImage(image, new Rectangle(0, 0, width, height), srcX, srcY, width, height, GraphicsUnit.Pixel);
            }
            return bitmap;
        }
        /// <summary>
        /// 裁剪
        /// </summary>
        /// <param name="i"></param>
        /// <param name="width">宽度</param>
        /// <param name="height">高度</param>
        /// <param name="interpolationMode"></param>
        /// <returns>返回裁剪后的图片</returns>
        /// <exception cref="NullReferenceException">Image 不能为 null</exception>
        /// <exception cref="ArgumentOutOfRangeException">新的图片尺寸的宽度和高度必须大于零</exception>
        /// <exception cref="Exception">操作失败</exception>
        public static System.Drawing.Image Crop(this System.Drawing.Image i, int width, int height, InterpolationMode interpolationMode)
        {
            return i.ReSize(width, height,Color.Transparent, GetMode(i.Width, i.Height, width, height, true), interpolationMode);
        }
        /// <summary>
        /// 调整宽度
        /// </summary>
        /// <param name="i"></param>
        /// <param name="width"></param>
        /// <returns></returns>
        public static Image ReSizeW(this Image i, int width)
        {
            return i.ReSize(width, (((float)width / i.Width) * i.Height).ToInt(), ResizeMode.WidthFirst);
        }
        /// <summary>
        /// 根据最大宽度调整图片尺寸
        /// </summary>
        /// <param name="i"></param>
        /// <param name="maxWidth">最大宽度</param>
        /// <returns>返回调整后的图片</returns>
        /// <exception cref="NullReferenceException">Image 不能为 null</exception>
        /// <exception cref="ArgumentOutOfRangeException">最大宽度必须大于零</exception>
        /// <exception cref="Exception">操作失败</exception>
        public static System.Drawing.Image ResizeMaxW(this System.Drawing.Image i, int maxWidth)
        {
            if (i.Width > maxWidth)
            {
                return i.ReSizeW(maxWidth);
            }
            else
            {
                return (System.Drawing.Image)i.Clone();
            }
        }
        /// <summary>
        /// 根据最大高度调整图片尺寸
        /// </summary>
        /// <param name="i"></param>
        /// <param name="maxHeight">最大高度</param>
        /// <returns>返回调整后的图片</returns>
        /// <exception cref="NullReferenceException">Image 不能为 null</exception>
        /// <exception cref="ArgumentOutOfRangeException">最大宽度必须大于零</exception>
        /// <exception cref="Exception">操作失败</exception>
        public static System.Drawing.Image ResizeMaxH(this System.Drawing.Image i, int maxHeight)
        {
            if (i.Height > maxHeight)
            {
                return i.ReSizeH(maxHeight);
            }
            else
            {
                return (System.Drawing.Image)i.Clone();
            }
        }
        /// <summary>
        /// 根据最长边调整图片尺寸
        /// </summary>
        /// <param name="i"></param>
        /// <param name="maxValue">设置最长边允许的值,当最长边大于这个值时,自动缩放</param>
        /// <returns>返回调整后的图片</returns>
        /// <exception cref="NullReferenceException">Image 不能为 null</exception>
        /// <exception cref="ArgumentOutOfRangeException">最大值必须大于零</exception>
        /// <exception cref="Exception">操作失败</exception>
        public static System.Drawing.Image ResizeMax(this System.Drawing.Image i, int maxValue)
        {
            if (i.Height > i.Width && i.Height> maxValue)
            {
                return i.ReSizeH(maxValue);
            }
            else if (i.Width > i.Height && i.Width > maxValue)
            {
                return i.ReSizeW(maxValue);
            }
            else
            {
                return (System.Drawing.Image)i.Clone();
            }
        }
        /// <summary>
        /// 调整高度
        /// </summary>
        /// <param name="i"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        public static Image ReSizeH(this Image i, int height)
        {
            return i.ReSize((((float)height / i.Height) * i.Width).ToInt(), height, ResizeMode.WidthFirst);
        }
        /// <summary>
        /// 调整图片大小
        /// </summary>
        /// <param name="i"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="resizeMode"></param>
        /// <returns></returns>
        public static Image ReSize(this Image i, int width, int height, ResizeMode resizeMode)
        {
            return ReSize(i, width, height, Color.Transparent, resizeMode);
        }
        /// <summary>
        /// 调整图片大小
        /// </summary>
        /// <param name="i"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="background"></param>
        /// <param name="resizeMode"></param>
        /// <returns></returns>
        public static Image ReSize(this Image i, int width, int height, Color background, ResizeMode resizeMode)
        {
            return ReSize(i,width,height,background,resizeMode, InterpolationMode.HighQualityBilinear);
        }
        /// <summary>
        /// 调整图片大小
        /// </summary>
        /// <param name="i"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="background"></param>
        /// <param name="resizeMode"></param>
        /// <param name="interpolationMode"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        public static Image ReSize(this Image i,int width,int height, Color background, ResizeMode resizeMode, InterpolationMode interpolationMode)
        {
            if (width <= 0 || height <= 0)
            {
                throw new ArgumentOutOfRangeException("新的图片尺寸的宽和高必须大于零");
            }
            //如果原图片和新图片尺寸一致，克隆对象返回
            if (i.Width == width && i.Height == height)
            {
                return (System.Drawing.Image)i.Clone();
            }
            if (((float)i.Width / i.Height == (float)width / height))
            {
                //如果原图片和新图片的比例相同，只缩放
                return i.Zoom(width, height);
            }
            else
            {
                Size size = new Size();
                //新宽高比
                float scale = (float)width / height;
                if (resizeMode == ResizeMode.WidthFirst)
                {
                    //等宽，计算高
                    size.Width = i.Width;
                    size.Height = (i.Width / scale).ToInt();
                }
                else
                {
                    //等高，计算宽
                    size.Height = i.Height;
                    size.Width = (i.Height * scale).ToInt();
                }
                //如果原图片和新图片的比例不同，先裁剪或填充后，再缩放
                using (System.Drawing.Image cropOrFill = i.CropOrFill(size.Width, size.Height, background, interpolationMode))
                {
                    return cropOrFill.Zoom(width, height, interpolationMode);
                }
            }
        }
        /// <summary>
        /// 转换Image为Icon
        /// </summary>
        /// <param name="image">要转换为图标的Image对象</param>
        /// <param name="nullTonull">当image为null时是否返回null。false则抛空引用异常</param>
        /// <exception cref="ArgumentNullException" />
        public static Icon ConvertToIcon(Image image, bool nullTonull = false)
        {
            if (image == null)
            {
                if (nullTonull) { return null; }
                throw new ArgumentNullException("image");
            }

            using (MemoryStream msImg = new MemoryStream()
                     , msIco = new MemoryStream())
            {
                image.Save(msImg, ImageFormat.Png);

                using (var bin = new BinaryWriter(msIco))
                {
                    //写图标头部
                    bin.Write((short)0);      //0-1保留
                    bin.Write((short)1);      //2-3文件类型。1=图标, 2=光标
                    bin.Write((short)1);      //4-5图像数量（图标可以包含多个图像）

                    bin.Write((byte)image.Width); //6图标宽度
                    bin.Write((byte)image.Height); //7图标高度
                    bin.Write((byte)0);      //8颜色数（若像素位深>=8，填0。这是显然的，达到8bpp的颜色数最少是256，byte不够表示）
                    bin.Write((byte)0);      //9保留。必须为0
                    bin.Write((short)0);      //10-11调色板
                    bin.Write((short)32);     //12-13位深
                    bin.Write((int)msImg.Length); //14-17位图数据大小
                    bin.Write(22);         //18-21位图数据起始字节

                    //写图像数据
                    bin.Write(msImg.ToArray());

                    bin.Flush();
                    bin.Seek(0, SeekOrigin.Begin);
                    return new Icon(msIco);
                }
            }
        }
    }
    /// <summary>
    /// 缩放模式
    /// </summary>
    public enum ResizeMode
    {
        /// <summary>
        /// 宽度优先(不裁剪宽)
        /// </summary>
        WidthFirst,

        /// <summary>
        /// 高度优先(不裁剪高)
        /// </summary>
        HeightFirst
    }
    /// <summary>
    /// 水印位置
    /// </summary>
    public enum WatermarkPosition
    {
        /// <summary>
        /// 左上角
        /// </summary>
        TopLeftCorner,
        /// <summary>
        /// 中上
        /// </summary>
        TopCenter,
        /// <summary>
        /// 右上角
        /// </summary>
        TopRightCorner,
        /// <summary>
        /// 左中
        /// </summary>
        CenterLeft,
        /// <summary>
        /// 居中
        /// </summary>
        Center,
        /// <summary>
        /// 右中
        /// </summary>
        CenterRight,
        /// <summary>
        /// 左下角
        /// </summary>
        BottomLeftCorner,
        /// <summary>
        /// 中下
        /// </summary>
        BottomCenter,
        /// <summary>
        /// 右下角
        /// </summary>
        BottomRightCorner,
        /// <summary>
        /// 全屏平铺
        /// </summary>
        FullScreenTile,
    }
}
