c# - Rotating and centering an image - c#

I have an image, which I want to rotate clockwise by a specified number of degrees. I don't want to cut anything off, so I calculate the width and height of the new image based on the specified rotation (a rotation of 45 degrees for example requires a taller and wider image.
//Calculate required size of new image
GraphicsPath path = new GraphicsPath();
path.AddRectangle(new RectangleF(0f, 0f, bmpSource.Width, bmpSource.Height));
Matrix matrix = new Matrix();
matrix.Rotate(iRotationDegrees);
RectangleF rctNewSize = path.GetBounds(matrix);
//Create new image
Bitmap bmpRotated = new Bitmap(Convert.ToInt32(rctNewSize.Width), Convert.ToInt32(rctNewSize.Height));
using (Graphics g = Graphics.FromImage(bmpRotated))
{
//Set rotation point to center of image
g.TranslateTransform(bmpRotated.Width / 2, 0);
g.RotateTransform(iRotationDegrees);
//Draw the rotated image on the bitmap
g.DrawImageUnscaled(bmpSource, 0,0);
}
With an angle of 45 degrees, when I set the TranslateTransform to bmpRotated.Width / 2, 0 the rotated image is not quite centered horizontally, and the bottom left corner is cut off a bit.
I'm missing some math here that is correctly figuring out the appropriate dx/dy values to pass to TranslateTransform.

Related

DrawEllipse: Antialiasing broken with PenAlignment.Inset

As suggested by #TaW on this previous question, I setted PenAlignment.Inset to draw the circle inside the Bitmap, but this caused another problem.
I want to draw a circle on a specified Bitmap with antialiasing.
SmoothingMode.AntiAlias
The problem is that, when I use PenAlignment.Inset, the antialiasing doesn't work correctly!
Instead, with PenAlignment.Center, it works correctly...
Any suggestion to resolve this problem?
Bitmap layer = new Bitmap(80, 80);
using (Graphics g = Graphics.FromImage(layer))
{
using (Pen p = new Pen(Color.Black, 4))
{
p.Alignment = PenAlignment.Inset;
g.SmoothingMode = SmoothingMode.AntiAlias;
g.DrawEllipse(p, new Rectangle(0, 0, layer.Width, layer.Height));
}
}
pictureBox3.Size = new Size(100, 100);
pictureBox3.Image = layer;
(Note the bugs on the left image)
Deflating the bounding rectangle by 1/2 of the pen's stroke width should solve this problem. By "deflate", I mean pull in all 4 sides towards the rectangle's center by 1/2 pen width:
float halfPenWidth = p.Width*0.5f;
g.DrawEllipse(p, new RectangleF(halfPenWidth, halfPenWidth, layer.Width - p.Width, layer.Height - p.Width));
or plugging in a hardcoded pen width of 4:
g.DrawEllipse(p, new Rectangle(2, 2, layer.Width - 4, layer.Height - 4));
Note that the full pen width must be subtracted from the rectangle's width and height in order to pull the right and bottom sides in by 1/2 pen width while keeping the rectangle centered on the same point.
Using this code with pen alignment centered, 1/2 of the stroke width will be drawn outside of the rectangle at the points where the ellipse touches the rectangle, but it will still be drawn inside the bitmap.

Image not rotating perfectly around center

So I have a picturebox with a background image of size 123x123 pixels.
Everytime the image is clicked I make it rotate by a certain angle using the function below.
//The original image to rotate.
private readonly Bitmap _origPowerKnob = Properties.Resources.PowerKnob;
//Calling the rotation function.
using (Bitmap b = new Bitmap(_origPowerKnob))
{
Bitmap newBmp = RotateImage(b, _powerAngle);
PowerKnob.BackgroundImage = newBmp;
}
//Do the rotation.
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(b.Width / 2F, b.Height / 2F);
//Rotate.
g.RotateTransform(angle);
//Move image back.
g.TranslateTransform(-b.Width / 2F, -b.Height / 2F);
//Draw passed in image onto graphics object.
g.DrawImage(b, new PointF(0,0));
return returnBitmap;
}
The problem is the image in not correctly rotating around the center. It is a little off and I can't seem to understand why. Any suggestions?

Matrix Transform of Rectangle after changing its bounds

I have a shape, for example a Rectangle which has the following bounds:
X = 100
Y = 100
Width = 100
Height = 100
I apply the following rotation to this rectangle using a new Matrix:
X = 100
Y = 100
Angle = 45
var transform = new Matrix();
transform.RotateAt(angle, point);
So the new Matrix has the following value:
0.7071068, 0.7071067, -0.7071067, 0.7071068, 150, -62.13202
I use this Matrix when I draw the Rectangle with Graphic:
protected override void OnPaint(PaintEventArgs e)
{
...
e.Graphic.Transform = transform;
g.DrawRectangle(Pen, bounds.X, bounds.Y, bounds.Width, bounds.Height);
}
The problem is the following: at a certain point I need to draw the same Rectangle but shifted by a certain offset, for example (50, 50). I have stored the Matrix transform and the Rectangle bounds. If I change only the bounds (adding the offset) the new Rectangle will be drawn in a wrong position, probably due to the previous rotation point.
How I have to change the Matrix in order to draw my Rectangle in the "right" position? that is, how can I retreive the right rotation point and the old rotation angle?
Try to add translation to the matrix using MatrixOrder.Prepend.
For offset (50, 50) it'll be:
transform.Translate(50, 50, MatrixOrder.Prepend);
Or create a separate matrix for this case:
var transformWithOffset = new Matrix();
transformWithOffset.Translate(50, 50);
transformWithOffset.RotateAt(angle, point);

System.Drawing.Graphics

I have one problem relating to rotate ellipse by given Center,
Suppose I have one ellipse and what should be is to rotate that ellipse by point given by user and ellipse should be rotate around that given point.
I have tried
g.RotateTransform(…)
g.TranslateTransform(…)
Code:
Graphics g = this.GetGraphics();
g.RotateTransform((float)degreeArg); //degree to rotate object
g.DrawEllipse(Pens.Red, 300, 300, 100, 200);
this works fine but how can we give our out center to rotate ellipse....
How could it be possible please any buddy can suggest……
Thanks…….
RotateTransform always rotates about the origin. So you need to first translate your centre of rotation to the origin, then rotate, then translate it back.
Something like this:
Graphics g = this.GetGraphics();
g.TranslateTransform(300,300);
g.RotateTransform((float)degreeArg); //degree to rotate object
g.TranslateTransform(-300,-300);
g.DrawEllipse(Pens.Red, 300, 300, 100, 200);
//center of the rotation
PointF center = new PointF(...);
//angle in degrees
float angle = 45.0f;
//use a rotation matrix
using (Matrix rotate = new Matrix())
{
//used to restore g.Transform previous state
GraphicsContainer container = g.BeginContainer();
//create the rotation matrix
rotate.RotateAt(angle, center);
//add it to g.Transform
g.Transform = rotate;
//draw what you want
...
//restore g.Transform state
g.EndContainer(container);
}

Strange rotation in C# graphics

I am using OnPaint method in my class Class1 : Panel.
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics g = e.Graphics;
}
to rotate and draw rectangle I am using
Matrix m = new Matrix();
m.RotateAt(90, rotationPoint);
g.Transform = m;
g.FillRectangle(Brushes.Black, rectangle)
the problem is, that rotation isn't working as I want it to.
Red square is rotation point and it's located in the middle-top of rectangle. How to set x, y and rotation point so rotation would work properly?
After rotating at 90 degress it should look like this
red pixel is still at the same location.
Rotation point is not the point, which you want to rotate. It is point, around which graphics is rotated. So if you draw a rectangle on the top of the graphics and want to rotate it (rectangle) - then you should set rotation point as center of graphics and rotate image to 90 degrees.
Here is example, that does almost what you want:
base.OnPaint(e);
var g = e.Graphics;
var width = g.VisibleClipBounds.Width;
var height = g.VisibleClipBounds.Height;
var rotationPoint = new PointF(width / 2, height / 2); ;
// draw center point
g.FillRectangle(Brushes.Red, new RectangleF(rotationPoint.X - 5, rotationPoint.Y - 5, 10, 10));
using (var path = new GraphicsPath())
{
var rectangle = new RectangleF((width - 10) / 2, 0, 10, 10);
var m = new Matrix();
m.RotateAt(90, rotationPoint);
path.AddRectangle(rectangle);
path.Transform(m);
// draw rotated point
g.FillPath(Brushes.Black, path);
}

Categories

Resources