C#使用GDI对一个图像Image进行任意角度旋转

83 篇文章 3 订阅
25 篇文章 1 订阅

上一篇我们对矩形进行旋转

C#使用GDI对一个矩形进行任意角度旋转-CSDN博客

基于上篇的基础上,对图片进行任意角度旋转

新建winform应用程序RotatedRectangleDemo,将默认的Form1重命名为FormRotatedImage

窗体FormRotatedImage设计如图:

找一下测试图片 云无月.jpg

将其设置为始终复制:

窗体设计器代码如下:

文件 FormRotatedImage.Designer.cs


namespace RotatedRectangleDemo
{
    partial class FormRotatedImage
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.numRotate = new System.Windows.Forms.NumericUpDown();
            this.label1 = new System.Windows.Forms.Label();
            this.btnRotate = new System.Windows.Forms.Button();
            this.pictureBox1 = new System.Windows.Forms.PictureBox();
            ((System.ComponentModel.ISupportInitialize)(this.numRotate)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
            this.SuspendLayout();
            // 
            // numRotate
            // 
            this.numRotate.DecimalPlaces = 2;
            this.numRotate.Location = new System.Drawing.Point(166, 12);
            this.numRotate.Maximum = new decimal(new int[] {
            360,
            0,
            0,
            0});
            this.numRotate.Name = "numRotate";
            this.numRotate.Size = new System.Drawing.Size(97, 21);
            this.numRotate.TabIndex = 5;
            this.numRotate.Value = new decimal(new int[] {
            30,
            0,
            0,
            0});
            // 
            // label1
            // 
            this.label1.AutoSize = true;
            this.label1.Location = new System.Drawing.Point(41, 16);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(119, 12);
            this.label1.TabIndex = 4;
            this.label1.Text = "旋转角度(0°~360°)";
            // 
            // btnRotate
            // 
            this.btnRotate.Font = new System.Drawing.Font("宋体", 13F);
            this.btnRotate.Location = new System.Drawing.Point(287, 3);
            this.btnRotate.Name = "btnRotate";
            this.btnRotate.Size = new System.Drawing.Size(75, 33);
            this.btnRotate.TabIndex = 3;
            this.btnRotate.Text = "旋转";
            this.btnRotate.UseVisualStyleBackColor = true;
            this.btnRotate.Click += new System.EventHandler(this.btnRotate_Click);
            // 
            // pictureBox1
            // 
            this.pictureBox1.Location = new System.Drawing.Point(80, 98);
            this.pictureBox1.Name = "pictureBox1";
            this.pictureBox1.Size = new System.Drawing.Size(900, 600);
            this.pictureBox1.TabIndex = 6;
            this.pictureBox1.TabStop = false;
            // 
            // FormRotatedImage
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(1085, 772);
            this.Controls.Add(this.pictureBox1);
            this.Controls.Add(this.numRotate);
            this.Controls.Add(this.label1);
            this.Controls.Add(this.btnRotate);
            this.Name = "FormRotatedImage";
            this.Text = "GDI旋转示例:图片旋转任意角度";
            this.Load += new System.EventHandler(this.FormRotatedImage_Load);
            ((System.ComponentModel.ISupportInitialize)(this.numRotate)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.NumericUpDown numRotate;
        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.Button btnRotate;
        private System.Windows.Forms.PictureBox pictureBox1;
    }
}

窗体FormRotatedImage相关图片旋转程序如下:

文件FormRotatedImage.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace RotatedRectangleDemo
{
    public partial class FormRotatedImage : Form
    {
        public FormRotatedImage()
        {
            InitializeComponent();

            /*
             * 已知一个矩形,如何绘制其绕其中心点旋转N度后的矩形区域
由于Graphics进行旋转平移等转换时的原点都是左上角,我们的要求是绕矩形中心旋转,需要三步完成 
(1)将Graphics的原点移至矩形的中点,假设坐标为(x,y) 
(2)将Graphics绕当前原点旋转N度 
(3)将Graphics沿(-x,-y)移回 
每步形成效果如下图所示。红色为原矩形,黄色为第一步,蓝色为第二步,绿色为第三步。 
————————————————

            获得图像旋转任意角度后的图像
解决上述两个问题后,再想获取图像旋转任意角度后的图像就会变得很简单了 
(1)已知一个原始图像srcImage和要旋转的角度 
(2)获取这个图像按角度旋转后的宽高(rotateRect) 
(3)根据旋转后的宽高定义Bitmap(rotateImage),定义Graphics,将Graphics按rotateImage的矩形区域中心进行旋转变换 
(4)将srcImage绘制到rotateImage中心(即两个中心点重合) 
(5)重置Graphics,完成 
————————————————
            */
        }

        /// <summary>
        /// 计算矩形绕中心任意角度旋转后所占区域矩形宽高
        /// </summary>
        /// <param name="width">原矩形的宽</param>
        /// <param name="height">原矩形高</param>
        /// <param name="angle">顺时针旋转角度</param>
        /// <returns></returns>
        public Rectangle GetRotateRectangle(int width, int height, float angle)
        {
            double radian = angle * Math.PI / 180;
            double cos = Math.Cos(radian);
            double sin = Math.Sin(radian);
            //只需要考虑到第四象限和第三象限的情况取大值(中间用绝对值就可以包括第一和第二象限)
            int newWidth = (int)(Math.Max(Math.Abs(width * cos - height * sin), Math.Abs(width * cos + height * sin)));
            int newHeight = (int)(Math.Max(Math.Abs(width * sin - height * cos), Math.Abs(width * sin + height * cos)));
            return new Rectangle(0, 0, newWidth, newHeight);
        }

        /// <summary>
        /// 获取原图像绕中心任意角度旋转后的图像
        /// </summary>
        /// <param name="rawImg"></param>
        /// <param name="angle"></param>
        /// <returns></returns>
        public Image GetRotateImage(Image srcImage, float angle)
        {
            angle = angle % 360;
            //原图的宽和高
            int srcWidth = srcImage.Width;
            int srcHeight = srcImage.Height;
            //图像旋转之后所占区域宽和高
            Rectangle rotateRec = GetRotateRectangle(srcWidth, srcHeight, angle);
            int rotateWidth = rotateRec.Width;
            int rotateHeight = rotateRec.Height;
            //目标位图
            Bitmap destImage = null;
            Graphics graphics = null;
            try
            {
                //定义画布,宽高为图像旋转后的宽高
                destImage = new Bitmap(rotateWidth, rotateHeight);
                //graphics根据destImage创建,因此其原点此时在destImage左上角
                graphics = Graphics.FromImage(destImage);
                //要让graphics围绕某矩形中心点旋转N度,分三步
                //第一步,将graphics坐标原点移到矩形中心点,假设其中点坐标(x,y)
                //第二步,graphics旋转相应的角度(沿当前原点)
                //第三步,移回(-x,-y)
                //获取画布中心点
                Point centerPoint = new Point(rotateWidth / 2, rotateHeight / 2);
                //将graphics坐标原点移到中心点
                graphics.TranslateTransform(centerPoint.X, centerPoint.Y);
                //graphics旋转相应的角度(绕当前原点)
                graphics.RotateTransform(angle);
                //恢复graphics在水平和垂直方向的平移(沿当前原点)
                graphics.TranslateTransform(-centerPoint.X, -centerPoint.Y);
                //此时已经完成了graphics的旋转

                //计算:如果要将源图像画到画布上且中心与画布中心重合,需要的偏移量
                Point Offset = new Point((rotateWidth - srcWidth) / 2, (rotateHeight - srcHeight) / 2);
                //将源图片画到rect里(rotateRec的中心)
                graphics.DrawImage(srcImage, new Rectangle(Offset.X, Offset.Y, srcWidth, srcHeight));
                //重至绘图的所有变换
                graphics.ResetTransform();
                graphics.Save();
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (graphics != null)
                    graphics.Dispose();
            }
            return destImage;
        }

        private void btnRotate_Click(object sender, EventArgs e)
        {
            Image srcImage = Image.FromFile(AppDomain.CurrentDomain.BaseDirectory + "云无月.jpg");
            pictureBox1.Image = GetRotateImage(srcImage, (float)numRotate.Value);            
        }

        private void FormRotatedImage_Load(object sender, EventArgs e)
        {
            pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
            pictureBox1.Image = Image.FromFile(AppDomain.CurrentDomain.BaseDirectory + "云无月.jpg");
        }
    }
}

运行如图:

旋转90°

旋转180°

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

斯内科

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值