I am trying to build an app that loads n number of images and transform them radially around a center and show the result in image control. I am able to load two image by defining each of their locations and transform them by using this code:
private void button1_Click(object sender, RoutedEventArgs e)
{
BitmapImage src = new BitmapImage();
src.BeginInit();
src.UriSource = new Uri(#"Location\Car\Car89.png", UriKind.Absolute);
src.CacheOption = BitmapCacheOption.OnLoad;
src.EndInit();
double deg = 90;
double rad = deg / 180.0 * Math.PI;
//get the bounds of the rotated image
double w = Math.Abs(Math.Cos(-rad) * src.PixelWidth) + Math.Abs(Math.Sin(-rad) * src.PixelHeight);
double h = Math.Abs(Math.Sin(-rad) * src.PixelWidth) + Math.Abs(Math.Cos(-rad) * src.PixelHeight);
BitmapImage src2 = new BitmapImage();
src2.BeginInit();
src2.UriSource = new Uri(#"Location\Car\Car269.png", UriKind.Absolute);
src2.CacheOption = BitmapCacheOption.OnLoad;
src2.EndInit();
double w2 = Math.Abs(Math.Cos(rad) * src2.PixelWidth) + Math.Abs(Math.Sin(rad) * src2.PixelHeight);
double h2 = Math.Abs(Math.Sin(rad) * src2.PixelWidth) + Math.Abs(Math.Cos(rad) * src2.PixelHeight);
Double radius = 50;
//Size sz = new Size(w + w2 + radius * 2, h + h2 + radius * 2);
double c1X = Math.Abs(Math.Sin(rad)) * (radius + src.PixelHeight / 2.0);
double c1Y = Math.Abs(Math.Cos(rad)) * (radius + src.PixelHeight / 2.0);
Size sz = new Size((w / 2 + c1X) * 2.0, (h / 2 + c1Y) * 2.0);
DrawingVisual dv = new DrawingVisual();
RenderOptions.SetBitmapScalingMode(dv, BitmapScalingMode.Fant);
RenderTargetBitmap rtb = null;
using (DrawingContext dc = dv.RenderOpen())
{
dc.DrawRectangle(Brushes.Black, null, new Rect(0, 0, (int)sz.Width, (int)sz.Height));
dc.DrawEllipse(Brushes.White, null, new Point(sz.Width / 2.0, sz.Height / 2.0), radius, radius);
//translate to first center
dc.PushTransform(new TranslateTransform(sz.Width / 2.0 - c1X, sz.Height / 2.0 - c1Y));
//rotate
dc.PushTransform(new RotateTransform(-deg));
//draw
dc.DrawImage(src, new Rect(-src.PixelWidth / 2.0, -src.PixelHeight / 2.0, src.PixelWidth, src.PixelHeight));
dc.Pop();
dc.Pop();
dc.PushTransform(new TranslateTransform(sz.Width / 2.0 + c1X, sz.Height / 2.0 - c1Y));
dc.PushTransform(new RotateTransform(deg));
dc.DrawImage(src2, new Rect(-src2.PixelWidth / 2.0, -src2.PixelHeight / 2.0, src2.PixelWidth, src2.PixelHeight));
dc.Pop();
dc.Pop();
}
rtb = new RenderTargetBitmap((int)sz.Width, (int)sz.Height, 96, 96, PixelFormats.Pbgra32);
RenderOptions.SetBitmapScalingMode(rtb, BitmapScalingMode.Fant);
rtb.Render(dv);
this.image1.Source = rtb;
}
But I wasn't able to make it load n number of images automatically named for example Car0.png, Car1.png,..., CarN.png
How can I achieve this?
Sincerely,
Samuel Farid
Related
I have this little code to use AddArc() method in a label, but when I execute the code the label disappears. I believe it is the numbers I have used, I followed instructions from the Windows documentation and it had these parameters there too.
GraphicsPath gp = new GraphicsPath();
Rectangle rec = new Rectangle(20, 20, 50, 100);
gp.AddArc(rec, 0 , 180);
label2.Region = new Region(gp);
label2.Invalidate();
I used another code to make the correct way or curve in a text
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
var center = new Point(Width / 2, Height / 2);
var radius = Math.Min(Width, Height) / 3;
var text = "Hello";//txtUp.Text;
var font = new Font(FontFamily.GenericSansSerif, 24, FontStyle.Bold);
for (var i = 0; i < text.Length; ++i)
{
var c = new String(text[i], 1);
var size = e.Graphics.MeasureString(c, font);
var charRadius = radius + size.Height;
var angle = (((float)i / text.Length) - 2);
var x = (int)(center.X + Math.Cos(angle) * charRadius);
var y = (int)(center.Y + Math.Sin(angle) * charRadius);
e.Graphics.TranslateTransform(x, y);
e.Graphics.RotateTransform((float)(90 + 360 * angle / (2 * Math.PI)));
e.Graphics.DrawString(c, font, Brushes.Red, 0, 0);
e.Graphics.ResetTransform();
e.Graphics.DrawArc(new Pen(Brushes.Transparent, 2.0f), center.X - radius, center.Y - radius, radius * 2, radius * 2, 0, 360);
}
}
but it wont show in front of a panel is it possible.
This is what it looks like:
Is it possible to move that text in front of the green circle?
How to I rotate an image without it showing like this?
Here's my Rotation Method:
public static Bitmap RotateImageN(Bitmap bmp, float angle)
{
Bitmap rotatedImage = new Bitmap(bmp.Width, bmp.Height);
using (Graphics g = Graphics.FromImage(rotatedImage))
{
// Set the rotation point to the center in the matrix
g.TranslateTransform(bmp.Width / 2, bmp.Height / 2);
// Rotate
g.RotateTransform(angle);
// Restore rotation point in the matrix
g.TranslateTransform(-bmp.Width / 2, -bmp.Height / 2);
// Draw the image on the bitmap
g.DrawImage(bmp, new Point(0, 0));
}
return rotatedImage;
}
Edit: After trying Loocid's Code
Your rotatedImage Bitmap needs to be big enough to accommodate the rotated image.
Say you rotated your original image by 30° you need to get the size of the bounding box like so:
Using some basic trig:
x = L*cos(30 * π / 180) + w*cos(60 * π / 180)
y = L*sin(30 * π / 180) + w*sin(60 * π / 180)
Therefore change the start of your code to:
var x = bmp.Width * Math.Cos(angle * Math.PI / 180) + bmp.Height * Math.Cos((90-angle) * Math.PI / 180)
var y = bmp.Width * Math.Sin(angle * Math.PI / 180) + bmp.Height * Math.Sin((90-angle) * Math.PI / 180)
Bitmap rotatedImage = new Bitmap(x, y);
The issue occurs in the rotating is related to the bounding box. It is clipping the edge because of the image you provided does not fit into the area that you have given.
I also faced this issue. So I tried a solution from here.
Adding the code that works for me.
public static Bitmap RotateImageN(Bitmap bitmap, float angle)
{
Matrix matrix = new Matrix();
matrix.Translate(bitmap.Width / -2, bitmap.Height / -2, MatrixOrder.Append);
matrix.RotateAt(angle, new System.Drawing.Point(0, 0), MatrixOrder.Append);
using (GraphicsPath graphicsPath = new GraphicsPath())
{
graphicsPath.AddPolygon(new System.Drawing.Point[] { new System.Drawing.Point(0, 0), new System.Drawing.Point(bitmap.Width, 0), new System.Drawing.Point(0, bitmap.Height) });
graphicsPath.Transform(matrix);
System.Drawing.PointF[] points = graphicsPath.PathPoints;
Rectangle rectangle = boundingBox(bitmap, matrix);
Bitmap resultBitmap = new Bitmap(rectangle.Width, rectangle.Height);
using (Graphics gDest = Graphics.FromImage(resultBitmap))
{
Matrix mDest = new Matrix();
mDest.Translate(resultBitmap.Width / 2, resultBitmap.Height / 2, MatrixOrder.Append);
gDest.Transform = mDest;
gDest.DrawImage(bitmap, points);
return resultBitmap;
}
}
}
private static Rectangle boundingBox(Image image, Matrix matrix)
{
GraphicsUnit graphicsUnit = new GraphicsUnit();
Rectangle boundingRectangle = Rectangle.Round(image.GetBounds(ref graphicsUnit));
Point topLeft = new Point(boundingRectangle.Left, boundingRectangle.Top);
Point topRight = new Point(boundingRectangle.Right, boundingRectangle.Top);
Point bottomRight = new Point(boundingRectangle.Right, boundingRectangle.Bottom);
Point bottomLeft = new Point(boundingRectangle.Left, boundingRectangle.Bottom);
Point[] points = new Point[] { topLeft, topRight, bottomRight, bottomLeft };
GraphicsPath graphicsPath = new GraphicsPath(points, new byte[] { (byte)PathPointType.Start, (byte)PathPointType.Line, (byte)PathPointType.Line, (byte)PathPointType.Line });
graphicsPath.Transform(matrix);
return Rectangle.Round(graphicsPath.GetBounds());
}
I want to draw ellipse excluding cross inside of it. I have a suspision that I need to use opacity mask. Here is how I am trying to do it.
Color grey = Color.FromArgb(128, Colors.Gray.R, Colors.Gray.G, Colors.Gray.B);
double radius = Math.Min(ActualWidth, ActualHeight) / 2;
Brush ellipse_brush = new SolidColorBrush(grey);
CombinedGeometry cg = new CombinedGeometry();
Drawing maskDrawing = new GeometryDrawing(Brushes.Lime, null, cg);
DrawingBrush mask = new DrawingBrush(maskDrawing);
dc.PushOpacityMask(mask);
dc.DrawEllipse(ellipse_brush, new Pen(ellipse_brush, 0), new Point(radius, radius), radius, radius);
dc.Pop();
Thing is that I don't understand how to create CombinedGeometry for ellipse and two lines. Or maybe I am on the wrong path?
You do not need an opacity mask in conjunction with a CombinedGeometry.
Create the cross outline geometry from a GeometryGroup with two lines and an appropriate Pen, then combine it Xor with an EllipseGeometry and draw the result:
var radius = Math.Min(ActualWidth, ActualHeight) / 2;
var crossSize = 0.8 * radius;
var crossThickness = 0.3 * radius;
var centerPoint = new Point(radius, radius);
var ellipseGeometry = new EllipseGeometry(centerPoint, radius, radius);
var crossGeometry = new GeometryGroup();
crossGeometry.Children.Add(new LineGeometry(
new Point(centerPoint.X - crossSize / 2, centerPoint.Y - crossSize / 2),
new Point(centerPoint.X + crossSize / 2, centerPoint.Y + crossSize / 2)));
crossGeometry.Children.Add(new LineGeometry(
new Point(centerPoint.X - crossSize / 2, centerPoint.Y + crossSize / 2),
new Point(centerPoint.X + crossSize / 2, centerPoint.Y - crossSize / 2)));
var crossPen = new Pen
{
Thickness = crossThickness,
StartLineCap = PenLineCap.Round,
EndLineCap = PenLineCap.Round
};
var crossOutlineGeometry = crossGeometry.GetWidenedPathGeometry(crossPen);
var combinedGeometry = new CombinedGeometry(GeometryCombineMode.Xor,
ellipseGeometry, crossOutlineGeometry);
dc.DrawGeometry(Brushes.Gray, null, combinedGeometry);
Instantiating the form.
public TwoDPlot()
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true);
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US", true);
InitializeComponent();
DrawCircle();
}
Method to draw the circle.
private void DrawCircle()
{
var radius = 0.5 * ClientRectangle.Width;
var height = ClientRectangle.Height - 0.1 * ClientRectangle.Height;
var width = ClientRectangle.Width - 0.1 * ClientRectangle.Width;
var scaledRadius = width > height ? radius * (height / radius) : radius * (width / radius);
var xlocation = ClientRectangle.Width / 2.0 - scaledRadius * 0.5;
var ylocation = ClientRectangle.Height / 2.0 - scaledRadius * 0.5;
m_Graphics = CreateGraphics();
m_Graphics?.Clear(DefaultBackColor);
m_Graphics?.DrawEllipse(new Pen(Color.Red), new Rectangle((int)xlocation, (int)ylocation, (int)scaledRadius, (int)scaledRadius));
m_Graphics.Dispose();
}
On instance, it shows empty form and upon re-sizing it shows the circle. I expect to show during the first instance.
This is the direct correction:
private void TwoDPlot_Paint(object sender, PaintEventArgs e)
{
DrawCircle(e.Graphics);
}
private void DrawCircle(Graphics m_Graphics)
{
var radius = 0.5 * ClientRectangle.Width;
var height = ClientRectangle.Height - 0.1 * ClientRectangle.Height;
var width = ClientRectangle.Width - 0.1 * ClientRectangle.Width;
var scaledRadius = width > height ? radius * (height / radius) : radius * (width / radius);
var xlocation = ClientRectangle.Width / 2.0 - scaledRadius * 0.5;
var ylocation = ClientRectangle.Height / 2.0 - scaledRadius * 0.5;
m_Graphics.Clear(DefaultBackColor);
m_Graphics.DrawEllipse(new Pen(Color.Red), new Rectangle((int)xlocation, (int)ylocation, (int)scaledRadius, (int)scaledRadius));
}
Note that to be more flexible you will want to move the variables maybe to class level variables or to parameters to the DrawCircle function..
When you have done that and changed the variables values you can trigger the Paint event by calling TwoDPlot.Invalidate().
The system will also call it whenever it needs to, e.g. upon many resize, maximize and other events..
I have animated gif and I'm using a class to parse the images(frames) from it.
The class is:
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Collections.Generic;
using System.IO;
public class AnimatedGif
{
private List<AnimatedGifFrame> mImages = new List<AnimatedGifFrame>();
public AnimatedGif(string path)
{
Image img = Image.FromFile(path);
int frames = img.GetFrameCount(FrameDimension.Time);
if (frames <= 1) throw new ArgumentException("Image not animated");
byte[] times = img.GetPropertyItem(0x5100).Value;
int frame = 0;
for (; ; )
{
int dur = BitConverter.ToInt32(times, 4 * frame);
mImages.Add(new AnimatedGifFrame(new Bitmap(img), dur));
if (++frame >= frames) break;
img.SelectActiveFrame(FrameDimension.Time, frame);
}
img.Dispose();
}
public List<AnimatedGifFrame> Images { get { return mImages; } }
}
public class AnimatedGifFrame
{
private int mDuration;
private Image mImage;
internal AnimatedGifFrame(Image img, int duration)
{
mImage = img; mDuration = duration;
}
public Image Image { get { return mImage; } }
public int Duration { get { return mDuration; } }
}
Now in form1 I loop over the frames in this case 4 and I want to rotate the animation by any degree. Now its rotating each 45 or 90 degrees. I want to add more frames(images) to the animation so if I set the rotation to 31 or to 10 degrees so I will see the animation rotating in 10 degrees.
This is the code in Form1 which is not working good. I'm using a function for the rotation which I didn't test yet if its any working.
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 AnimatedGifEditor
{
public partial class Form1 : Form
{
Image myImage;
AnimatedGif myGif;
Bitmap bitmap;
public Form1()
{
InitializeComponent();
myImage = Image.FromFile(#"D:\fananimation.gif");
myGif = new AnimatedGif(#"D:\fananimation.gif");
for (int i = 0; i < myGif.Images.Count; i++)
{
pictureBox1.Image = myGif.Images[3].Image;
bitmap = new Bitmap(pictureBox1.Image);
rotateImage(bitmap, 76);
pictureBox1.Image = bitmap;
}
}
private void Form1_Load(object sender, EventArgs e)
{
}
private Bitmap RotateImg(Bitmap bmp, float angle, Color bkColor)
{
int w = bmp.Width;
int h = bmp.Height;
bmp.PixelFormat pf = default(bmp.PixelFormat);
if (bkColor == Color.Transparent)
{
pf = bmp.Format32bppArgb;
}
else
{
pf = bmp.PixelFormat;
}
Bitmap tempImg = new Bitmap(w, h, pf);
Graphics g = Graphics.FromImage(tempImg);
g.Clear(bkColor);
g.DrawImageUnscaled(bmp, 1, 1);
g.Dispose();
GraphicsPath path = new GraphicsPath();
path.AddRectangle(new RectangleF(0f, 0f, w, h));
Matrix mtrx = new Matrix();
//Using System.Drawing.Drawing2D.Matrix class
mtrx.Rotate(angle);
RectangleF rct = path.GetBounds(mtrx);
Bitmap newImg = new Bitmap(Convert.ToInt32(rct.Width), Convert.ToInt32(rct.Height), pf);
g = Graphics.FromImage(newImg);
g.Clear(bkColor);
g.TranslateTransform(-rct.X, -rct.Y);
g.RotateTransform(angle);
g.InterpolationMode = InterpolationMode.HighQualityBilinear;
g.DrawImageUnscaled(tempImg, 0, 0);
g.Dispose();
tempImg.Dispose();
return newImg;
}
}
}
The animated gif I'm using for the test can be found here:
I didn't understand what's your problem but I think that your code could be improved. I think that you don't need to use directly the Matrix class. There are some functions that does this work for you. Infact the only things you need are: set the point of the rotation as the center, rotate the graphics and draw on it, using some functions by the Graphics class.
So to rotate an image you can use this simple code:
private Bitmap RotateImage(Bitmap bmp, float angle) {
Bitmap rotatedImage = new Bitmap(bmp.Width, bmp.Height);
rotatedImage.SetResolution(bmp.HorizontalResolution, bmp.VerticalResolution);
using (Graphics g = Graphics.FromImage(rotatedImage)) {
// Set the rotation point to the center in the matrix
g.TranslateTransform(bmp.Width / 2, bmp.Height / 2);
// Rotate
g.RotateTransform(angle);
// Restore rotation point in the matrix
g.TranslateTransform(- bmp.Width / 2, - bmp.Height / 2);
// Draw the image on the bitmap
g.DrawImage(bmp, new Point(0, 0));
}
return rotatedImage;
}
Based on the previous answers I created this code that doesn't cut the image (the other examples were not working for me)
private Bitmap RotateImage(Bitmap bmp, float angle)
{
float height = bmp.Height;
float width = bmp.Width;
int hypotenuse = System.Convert.ToInt32(System.Math.Floor(Math.Sqrt(height * height + width * width)));
Bitmap rotatedImage = new Bitmap(hypotenuse, hypotenuse);
using (Graphics g = Graphics.FromImage(rotatedImage))
{
g.TranslateTransform((float)rotatedImage.Width / 2, (float)rotatedImage.Height / 2); //set the rotation point as the center into the matrix
g.RotateTransform(angle); //rotate
g.TranslateTransform(-(float)rotatedImage.Width / 2, -(float)rotatedImage.Height / 2); //restore rotation point into the matrix
g.DrawImage(bmp, (hypotenuse - width) / 2, (hypotenuse - height) / 2, width, height);
}
return rotatedImage;
}
I tried the answer of #Omar myself and realized, that the original image gets cut at the sides ... i've rewritten it so it resizes the image to the new sizes:
private static Bitmap RotateImage(Bitmap bmp, float angle)
{
float alpha = angle;
//edit: negative angle +360
while(alpha <0) alpha +=360;
float gamma = 90;
float beta = 180 - angle - gamma;
float c1 = bmp.Height;
float a1 = (float)(c1 * Math.Sin(alpha * Math.PI / 180) / Math.Sin(gamma * Math.PI / 180));
float b1 = (float)(c1 * Math.Sin(beta * Math.PI / 180) / Math.Sin(gamma * Math.PI / 180));
float c2 = bmp.Width;
float a2 = (float)(c2 * Math.Sin(alpha * Math.PI / 180) / Math.Sin(gamma * Math.PI / 180));
float b2 = (float)(c2 * Math.Sin(beta * Math.PI / 180) / Math.Sin(gamma * Math.PI / 180));
int width = Convert.ToInt32(b2 + a1);
int height = Convert.ToInt32(b1 + a2);
Bitmap rotatedImage = new Bitmap(width, height);
using (Graphics g = Graphics.FromImage(rotatedImage))
{
g.TranslateTransform(rotatedImage.Width / 2, rotatedImage.Height / 2); //set the rotation point as the center into the matrix
g.RotateTransform(angle); //rotate
g.TranslateTransform(-rotatedImage.Width / 2, -rotatedImage.Height / 2); //restore rotation point into the matrix
g.DrawImage(bmp, new Point((width - bmp.Width) / 2, (height - bmp.Height) / 2)); //draw the image on the new bitmap
}
return rotatedImage;
}
Have you tried RotateFlip?
public partial class Form1 : Form
{
Image myImage;
AnimatedGif myGif;
Bitmap bitmap;
public Form1()
{
InitializeComponent();
myImage = Image.FromFile(#"D:\fananimation.gif");
bitmap = new Bitmap(myImage);
bitmap.RotateFlip(System.Drawing.RotateFlipType.Rotate90FlipNone);
this.pictureBox1.Image = bitmap;
}
}
Source
I was using this function in VB:
Public Function RotateImage(ByRef image As Image, ByVal angle As Single) As Drawing.Bitmap
If image Is Nothing Then
Throw New ArgumentNullException("image")
End If
Dim pi2 As Single = Math.PI / 2.0
Dim oldWidth As Single = image.Width
Dim oldHeight As Single = image.Height
Dim theta As Single = angle * Math.PI / 180.0
Dim locked_theta As Single = theta
If locked_theta < 0.0 Then locked_theta += 2 * Math.PI
Dim newWidth, newHeight As Single
Dim nWidth, nHeight As Integer
Dim adjacentTop, oppositeTop As Single
Dim adjacentBottom, oppositeBottom As Single
If (locked_theta >= 0.0 And locked_theta < pi2) Or _
(locked_theta >= Math.PI And locked_theta < (Math.PI + pi2)) Then
adjacentTop = Math.Abs(Math.Cos(locked_theta)) * oldWidth
oppositeTop = Math.Abs(Math.Sin(locked_theta)) * oldWidth
adjacentBottom = Math.Abs(Math.Cos(locked_theta)) * oldHeight
oppositeBottom = Math.Abs(Math.Sin(locked_theta)) * oldHeight
Else
adjacentTop = Math.Abs(Math.Sin(locked_theta)) * oldHeight
oppositeTop = Math.Abs(Math.Cos(locked_theta)) * oldHeight
adjacentBottom = Math.Abs(Math.Sin(locked_theta)) * oldWidth
oppositeBottom = Math.Abs(Math.Cos(locked_theta)) * oldWidth
End If
newWidth = adjacentTop + oppositeBottom
newHeight = adjacentBottom + oppositeTop
nWidth = Int(Math.Ceiling(newWidth))
nHeight = Int(Math.Ceiling(newHeight))
Dim rotatedBmp As New Drawing.Bitmap(nWidth, nHeight)
Dim g As Graphics = Graphics.FromImage(rotatedBmp)
Dim points(2) As Point
If (locked_theta >= 0.0 And locked_theta < pi2) Then
points(0) = New Point(Int(oppositeBottom), 0)
points(1) = New Point(nWidth, Int(oppositeTop))
points(2) = New Point(0, Int(adjacentBottom))
ElseIf locked_theta >= pi2 And locked_theta < Math.PI Then
points(0) = New Point(nWidth, Int(oppositeTop))
points(1) = New Point(Int(adjacentTop), nHeight)
points(2) = New Point(Int(oppositeBottom), 0)
ElseIf locked_theta >= Math.PI And locked_theta < (Math.PI + pi2) Then
points(0) = New Point(Int(adjacentTop), nHeight)
points(1) = New Point(0, Int(adjacentBottom))
points(2) = New Point(nWidth, Int(oppositeTop))
Else
points(0) = New Point(0, Int(adjacentBottom))
points(1) = New Point(Int(oppositeBottom), 0)
points(2) = New Point(Int(adjacentTop), nHeight)
End If
g.DrawImage(image, points)
g.Dispose()
image.Dispose()
Return rotatedBmp
End Function
I checked the answers and they all have at least one of the following problems:
Cropping/incorrect centering
Unnecessary margin
Errors with some angle ranges
Unnecessarily complicated calculations/code
This solution can handle any angle (positive, negative, over 360° etc.). There is no cropping or excessive margins. No memory leaks either.
public Bitmap RotateBitmap(Bitmap bmp, float angle)
{
double radianAngle = angle / 180.0 * Math.PI;
double cosA = Math.Abs(Math.Cos(radianAngle));
double sinA = Math.Abs(Math.Sin(radianAngle));
int newWidth = (int)(cosA * bmp.Width + sinA * bmp.Height);
int newHeight = (int)(cosA * bmp.Height + sinA * bmp.Width);
var rotatedBitmap = new Bitmap(newWidth, newHeight);
rotatedBitmap.SetResolution(bmp.HorizontalResolution, bmp.VerticalResolution);
using (Graphics g = Graphics.FromImage(rotatedBitmap))
{
g.TranslateTransform(rotatedBitmap.Width / 2, rotatedBitmap.Height / 2);
g.RotateTransform(angle);
g.TranslateTransform(-bmp.Width / 2, -bmp.Height / 2);
g.DrawImage(bmp, new Point(0, 0));
}
bmp.Dispose();//Remove if you want to keep oryginal bitmap
return rotatedBitmap;
}
Depending on Timo's code, i made some improvements, with improvement, negative angles (up to -360) can be give as a parameter succesfully
private static Bitmap RotateImage(Bitmap bmp, float angle)
{
float alpha = angle;
//edit: negative angle +360
while (alpha < 0) alpha += 360;
float gamma = 90;
float beta = 180 - angle - gamma;
float c1 = bmp.Height;
float a1 = Math.Abs((float)(c1 * Math.Sin(alpha * Math.PI / 180)));
float b1 = Math.Abs((float)(c1 * Math.Sin(beta * Math.PI / 180)));
float c2 = bmp.Width;
float a2 = Math.Abs((float)(c2 * Math.Sin(alpha * Math.PI / 180)));
float b2 = Math.Abs((float)(c2 * Math.Sin(beta * Math.PI / 180)));
int width = Convert.ToInt32(b2 + a1);
int height = Convert.ToInt32(b1 + a2);
Bitmap rotatedImage = new Bitmap(width, height);
using (Graphics g = Graphics.FromImage(rotatedImage))
{
g.TranslateTransform(rotatedImage.Width / 2, rotatedImage.Height / 2); //set the rotation point as the center into the matrix
g.RotateTransform(angle); //rotate
g.TranslateTransform(-rotatedImage.Width / 2, -rotatedImage.Height / 2); //restore rotation point into the matrix
g.DrawImage(bmp, new Point((width - bmp.Width) / 2, (height - bmp.Height) / 2)); //draw the image on the new bitmap
}
return rotatedImage;
}