Rotating image around center C#

假装没事ソ 提交于 2019-12-24 11:22:31

问题


I have a small error when trying to rotate an image within a picture box. It all works. But when rotating, it doesn't rotate perfectly around the center. It's slightly off (not very noticeable) but kinda annoying. Here is my code:

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;
        }

Pictures showing what I mean:

It doesn't rotate perfectly. Is there a solution to this? Something I haven't set for my picturebox properties? I've tried alot.

Thanks.


回答1:


I found a solution to get the rotated image from it's center

[My Testing Conditions]

I'm testing this with the next considerations, if it works for you its ok :3

1.-The source image i used is a perfect square[LxL], taked from a png file, size of the square no matter, just needs to be LxL; //(Width == Height) = true;

2.- The png source image file that i am rotating is transparent and square shaped, i got it from illustrator

3.- I tested files of size 417x417, and 520x520, and 1024x1024

[The code i can share to you]

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;
        }
   }
}

I just gived the name "RotateImageN" to the function, because is the 5th solution I have tried :3 i Hope to be helpful

Sorry for my english and/or grammar hehe :3




回答2:


This is where a simple test form would have helped you a lot.

Take this code and put it in a new WinForms project's Form1.cs file.

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;
        }
    }
}

Observe as the two crosses rotate about their center just fine. The left one being a bitmap that is rotated with your method, the right one being redrawn every frame. That is, there is nothing wrong with your rotation code but it's possible there's something wrong with your source bitmap or your display container.




回答3:


When you use transparent png with just a portion of the image filled with color for example - the code will rotate transform only the portion of the png that has data in it...

I tried to get a dot in the top center of a png to rotate around the center of the image (500x500 px) and it just recognizes the part that was colored, so it turned into a bounce effect.

I tried with a fully colored 500x500 px image too, and that worked normally..

Hope it helps a little!



来源:https://stackoverflow.com/questions/27431345/rotating-image-around-center-c-sharp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!