围绕中心C#旋转图像

时间:2014-12-11 19:59:01

标签: c# rotation picturebox

尝试在图片框中旋转图片时出现小错误。 一切正常。但是在旋转时,它并不能完美地围绕中心旋转。它稍微偏离(不太明显)但有点烦人。这是我的代码:

private readonly Bitmap _origPowerKnob = Properties.Resources.PowerKnob;

//CODE WHERE ROTATE METHOD IS CALLED//

using (Bitmap b = new Bitmap(_origPowerKnob))
                {
                    Bitmap newBmp = RotateImage(b, _powerAngle);
                    PowerKnob.BackgroundImage = newBmp;
                }

private Bitmap RotateImage(Bitmap b, float angle)
        {
            //Create a new empty bitmap to hold rotated image.
            Bitmap returnBitmap = new Bitmap(b.Width, b.Height);
            //Make a graphics object from the empty bitmap.
            Graphics g = Graphics.FromImage(returnBitmap);
            //move rotation point to center of image.
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.TranslateTransform((float) b.Width / 2, (float)b.Height / 2);
            //Rotate.        
            g.RotateTransform(angle);
            //Move image back.
            g.TranslateTransform(-(float)b.Width / 2, -(float)b.Height / 2);
            //Draw passed in image onto graphics object.
            g.DrawImage(b, new Point(0, 0));
            return returnBitmap;
        }

图片展示了我的意思:

No rotating yet.

180 rotation.

它没有完美旋转。这个问题有方法解决吗?我没有为我的图片框属性设置的东西?我已经尝试了很多。

感谢。

3 个答案:

答案 0 :(得分:3)

我找到了一个从中心获取旋转图像的解决方案

[我的测试条件]

我正在测试这个以下考虑因素,如果它适合你的确定:3

1.-我使用的源图像是一个完美的正方形[LxL],取自png文件,无论是正方形的大小,只需要是LxL; //(宽度==高度)=真;

2.-我正在旋转的png源图像文件是透明和方形的,我是从插图画家那里得到的

3.-我测试了大小为417x417,520x520和1024x1024的文件

[我可以分享的代码]

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace YourNamespace
{
    public static class TheClassinWhichYouWantToPlaceTheFunction
    {
        public static Bitmap RotateImageN(Bitmap b, float angle)
        {
            //Create a new empty bitmap to hold rotated image.
            Bitmap returnBitmap = new Bitmap(b.Width, b.Height);
            //Make a graphics object from the empty bitmap.
            Graphics g = Graphics.FromImage(returnBitmap);
            //move rotation point to center of image.
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
            g.TranslateTransform((float)b.Width / 2, (float)b.Height / 2);
            //Rotate.        
            g.RotateTransform(angle);
            //Move image back.
            g.TranslateTransform(-(float)b.Width / 2, -(float)b.Height / 2);
            //Draw passed in image onto graphics object.
            //Found ERROR 1: Many people do g.DwarImage(b,0,0); The problem is that you re giving just the position
            //Found ERROR 2: Many people do g.DrawImage(b, new Point(0,0)); The size still not present hehe :3

            g.DrawImage(b, 0,0,b.Width, b.Height);  //My Final Solution :3
            return returnBitmap;
        }
   }
}

我只是给该函数命名为“RotateImageN”,因为这是我尝试过的第五种解决方案:3我希望能提供帮助

抱歉我的英语和/或语法呵呵:3

答案 1 :(得分:0)

这是一个简单的测试表格可以帮助你的地方。

获取此代码并将其放入新的WinForms项目的Form1.cs文件中。

using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace RotateImage {
    public partial class Form1 : Form {
        private readonly Graphics gfx;
        private readonly Bitmap originalBitmap;
        private readonly Bitmap redrawnBitmap;
        private readonly Stopwatch sw;

        private Timer timer;
        public Form1() {
            InitializeComponent();
            BackColor = Color.White;

            timer = new Timer();
            timer.Interval = 16;
            timer.Enabled = true;
            timer.Tick += timer_Tick;
            sw = new Stopwatch();
            sw.Start();

            gfx = CreateGraphics();

            originalBitmap = new Bitmap(256, 256);
            redrawnBitmap = new Bitmap(256, 256);
            using (var bmpGfx = Graphics.FromImage(originalBitmap)) {
                DrawCross(bmpGfx, new Point(128, 128), 128D, 0D);
            }
        }

        private void timer_Tick(object sender, EventArgs e) {
            // Rotate a full 90 degrees every 4 seconds.
            var angle = sw.Elapsed.TotalSeconds * 22.5D;

            var newBitmap = RotateImage(originalBitmap, (float)angle);

            // Clear the result of the last draw.
            gfx.FillRectangle(Brushes.White, new Rectangle(0, 0, 256, 256));

            gfx.DrawImageUnscaled(newBitmap, 0, 0);
            gfx.DrawEllipse(Pens.Blue, new Rectangle(124, 124, 8, 8));

            using (var redrawGfx = Graphics.FromImage(redrawnBitmap)) {
                // Clear what we have, we are redrawing on the same surface.
                redrawGfx.Clear(Color.White);
                DrawCross(redrawGfx, new Point(128, 128), 128D, angle);
            }
            gfx.DrawImageUnscaled(redrawnBitmap, 256, 0);
            gfx.DrawEllipse(Pens.Blue, new Rectangle(256+124, 124, 8, 8));
        }

        private void DrawCross(Graphics drawGfx, Point center, double radius, double angle) {
            // Turn our angle from degrees to radians.
            angle *= Math.PI / 180;

            // NOTE: Using PointF to lazily "fix" rounding errors and casting (flooring) double to int. When the result of the math below is say 127.9999999...
            // then it would get rounded down to 127. There is always Math.Round, which can round to nearest whole (away from .5) integer!
            // Draw one line of our cross.
            drawGfx.DrawLine(
                Pens.Red,
                new PointF((float)(Math.Cos(angle) * radius + center.X), (float)(Math.Sin(angle) * radius + center.Y)),
                new PointF((float)(Math.Cos(angle - Math.PI) * radius + center.X), (float)(Math.Sin(angle - Math.PI) * radius + center.Y)));

            // Rotate our angle 90 degrees.
            angle += Math.PI / 2D;

            // Draw the other line of our cross.
            drawGfx.DrawLine(
                Pens.Red,
                new PointF((float)(Math.Cos(angle) * radius + center.X), (float)(Math.Sin(angle) * radius + center.Y)),
                new PointF((float)(Math.Cos(angle - Math.PI) * radius + center.X), (float)(Math.Sin(angle - Math.PI) * radius + center.Y)));
        }

        // Your method, not mine.
        private Bitmap RotateImage(Bitmap b, float angle)
        {
            //Create a new empty bitmap to hold rotated image.
            Bitmap returnBitmap = new Bitmap(b.Width, b.Height);
            //Make a graphics object from the empty bitmap.
            Graphics g = Graphics.FromImage(returnBitmap);
            //move rotation point to center of image.
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.TranslateTransform((float) b.Width / 2, (float)b.Height / 2);
            //Rotate.        
            g.RotateTransform(angle);
            //Move image back.
            g.TranslateTransform(-(float)b.Width / 2, -(float)b.Height / 2);
            //Draw passed in image onto graphics object.
            g.DrawImage(b, new Point(0, 0));
            return returnBitmap;
        }
    }
}

观察两个十字架围绕它们的中心旋转就好了。左边的一个是用你的方法旋转的位图,右边的每一帧都重绘一次。 也就是说,您的旋转代码没有任何问题,但是您的源位图或显示容器可能存在问题。

答案 2 :(得分:0)

当您使用透明的png时,例如只有一部分图像填充了颜色 - 代码将旋转只转换png中包含数据的部分......

我试图在png的顶部中心得到一个点,围绕图像的中心(500x500像素)旋转,它只识别被着色的部分,因此它变成了反弹效果。

我尝试使用全彩色的500x500像素图像,并且正常工作..

希望它有所帮助!