I build a minimap for an overylay, it correctly updates images based on player location. I am attempting now to make it rotate, although the graphics function rotateTransform, rotates about the upper left corner, how can I rotate about the center?
if (ShowRadar)
{
//Center point
RadarCenter = new Vector2(this.GameWindowRect.Right - 125, this.GameWindowRect.Top + 125 + 25 - 15);
//If map exists
if (originalBitmap != null)
{
DXSprite.Begin(SpriteFlags.None);
//Transpose player posistion to map position and create the current mini map image
//player location range -4000 - 4000, bitmap range 0 - 8000
x = (int)(Math.Abs(-4000 - player_Z));
z = (int)(Math.Abs(4000 - player_X));
//minimap rec loc on bitmap with a scale of 1000x1000
mini = new Rectangle(x-500, z-500, 1000, 1000);
croppedBitmap = new Bitmap(200, 200);
croppedBitmapFinal = new Bitmap(200, 200);
//draw the crop
using (Graphics grD = Graphics.FromImage(croppedBitmap))
{
grD.DrawImage(originalBitmap, new Rectangle(0, 0, 158, 158), mini, GraphicsUnit.Pixel);
grD.Dispose();
}
//redraw crop as circle
using (Graphics grD = Graphics.FromImage(croppedBitmapFinal))
{
GraphicsPath path = new GraphicsPath();
path.AddEllipse(0, 0, croppedBitmapFinal.Width-45, croppedBitmapFinal.Height-45);
grD.SetClip(path);
//apply rotate - direction 0 to 3.15 = 0 to 180, -3.15 to 0 = 180 to 360; so multiply by (180/3.15)
grD.RotateTransform(player_D * 57);
grD.DrawImage(croppedBitmap, 0, 0);
grD.Dispose();
}
//make texture from final bitmap
using (MemoryStream s = new MemoryStream())//s is a MemoryStream
{
croppedBitmapFinal.Save(s, System.Drawing.Imaging.ImageFormat.Png);
s.Seek(0, SeekOrigin.Begin); //must do this, or error is thrown in next line
currentMinimap = Texture.FromStream(DXDevice, s);
s.Dispose();
}
//clean up and print to screen
croppedBitmapFinal.Dispose();
croppedBitmap.Dispose();
DXSprite.Draw(currentMinimap, new Vector3(0f, 0f, 0f), new Vector3(this.GameWindowRect.Right - 225, this.GameWindowRect.Top + 35, 0f), Color.White);
DXSprite.End();
currentMinimap.Dispose();
}
}
simply had to move the origin like so
if (ShowRadar)
{
//Center point
RadarCenter = new Vector2(this.GameWindowRect.Right - 125, this.GameWindowRect.Top + 125 + 25 - 15);
//If map exists
if (originalBitmap != null)
{
DXSprite.Begin(SpriteFlags.None);
//Transpose player posistion to map position and create the current mini map image
//player location range -4000 - 4000, bitmap range 0 - 8000
x = (int)(Math.Abs(-4000 - player_Z));
z = (int)(Math.Abs(4000 - player_X));
//minimap rec loc on bitmap with a scale of 1000x1000
mini = new Rectangle(x-500, z-500, 1000, 1000);
croppedBitmap = new Bitmap(200, 200);
croppedBitmapFinal = new Bitmap(200, 200);
//draw the crop
using (Graphics grD = Graphics.FromImage(croppedBitmap))
{
grD.DrawImage(originalBitmap, new Rectangle(0, 0, 158, 158), mini, GraphicsUnit.Pixel);
grD.Dispose();
}
//redraw crop as circle
using (Graphics grD = Graphics.FromImage(croppedBitmapFinal))
{
//add circle clip to graphics
GraphicsPath path = new GraphicsPath();
path.AddEllipse(0, 0, croppedBitmapFinal.Width-45, croppedBitmapFinal.Height-45);
grD.SetClip(path);
//move origin to center for rotate
float hw = (croppedBitmapFinal.Width / 2)-22.5f;
float hh = (croppedBitmapFinal.Height / 2)-22.5f;
grD.TranslateTransform(hw, hh);
//apply rotate - direction 0 to 3.15 = 0 to 180, -3.15 to 0 = 180 to 360; so multiply by (180/3.15)
grD.RotateTransform((player_D * 57)-90);
//Move origin back to original pos
grD.TranslateTransform(-hw, -hh);
//Draw to bitmap
grD.DrawImage(croppedBitmap, 0, 0);
grD.Dispose();
}
//make texture from final bitmap
using (MemoryStream s = new MemoryStream())//s is a MemoryStream
{
croppedBitmapFinal.Save(s, System.Drawing.Imaging.ImageFormat.Png);
s.Seek(0, SeekOrigin.Begin); //must do this, or error is thrown in next line
currentMinimap = Texture.FromStream(DXDevice, s);
s.Dispose();
}
//clean up and print to screen
croppedBitmapFinal.Dispose();
croppedBitmap.Dispose();
DXSprite.Draw(currentMinimap, new Vector3(0f, 0f, 0f), new Vector3(this.GameWindowRect.Right - 225, this.GameWindowRect.Top + 35, 0f), Color.White);
DXSprite.End();
currentMinimap.Dispose();
}
Related
Back here. Is there any way to improve the quality of the Arc?
I'm using e.Graphics.SmoothingMode = SmoothingMode.AntiAlias
This is the piece of code that creates the arc:
using (GraphicsPath gp = new GraphicsPath())
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
gp.Reset();
gp.AddPie(_OuterRectangle, (float)_Properties.Origin, (float)_Properties.GaugeType);
gp.Reverse();
gp.AddPie(_InnerRectangle, (float)_Properties.Origin, (float)_Properties.GaugeType);
gp.Reverse();
pArea.SetClip(gp);
using (Pen oPen = new Pen(this.ForeColor, 2f))
{
e.Graphics.DrawPath(oPen, gp);
}
e.Graphics.SetClip(ClientRectangle);
}
Thanks in advance.
EDIT:
I've did what LarsTech proposed and now the quality is perfect, but I'm not having the figure I need:
OuterRectangle: is the ClientRectangle area, that I'm manipulating it to make Width and Height the same lenght;
InnerRectangle: is 2/3ths of the ClientRectangle area, ergo, of the OuterRectangle;
Properties.Origin: is the angle where the arc starts. I have it in an enumerator as Cardinal Points, where North is 270, East is 0,
and so. In case of the figure, is SouthWest, 135 degrees;
Properties.GaugeType: is another enumerator that says if is Complete = 360, Half = 180, Quarter = 90, so with that I can determine the sweep angle. In case of the figure is ThreeQuarter, 270 degrees.
The problem:
When clipping a region of the current Graphics (Graphics.SetClip method), the resulting drawing loses quality, because the antialiasing effect generated by Graphics.SmoothingMode = SmoothingMode.AntiAlias is lost.
A possible solution is to avoid clipping the region defined by the GraphicsPath used to design the arcs (GraphicsPath.AddPie method); this, however, leaves the lines of the Pie visible, compromising the shape.
Another solution is to draw an ellipsis in the center of the arcs using the background color of the Canvas. Since the arcs are drawn using two rectangles, we can use the inner rectagle, inflate it (Rectangle.Inflate method) as needed (a fraction - Pen.Width / 2 - of the Pen size used for the ouline, usually).
This allows to delete the artifacts generated by the GraphicsPath shapes and to draw some other graphics content in the center of the shapes.
For example, using different Brushes:
LinearGradientBrush HatchBrush TextureBrush
Of course there are other methods to achieve the same result. We could draw the Arcs using the GraphicsPath.AddArc method, extract or calculate the first and last points of the Arcs and use them to draw two lines (GraphicsPath.AddLine) that will close the figures.
But, since we want to draw different graphics objects in the center of the arcs, these objects will cover the center area anyway.
How to use this code:
In a Form, add a TrackBar (named tbarSpeed, here)
Add a PictureBox (named Canvas), with Size (200, 200).
Wire up the TrackBar tbarSpeed_Scroll event and the Panel Canvas_Paint event.
using System.Drawing;
using System.Drawing.Drawing2D;
float GaugeValue = 88.0f;
float GaugeSweepAngle = 270.0f;
float GaugeStartAngle = 135.0F;
private void Canvas_Paint(object sender, PaintEventArgs e)
{
var canvas = sender as Control;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
var outerRectangle = new Rectangle(10, 10, 180, 180);
var innerRectangle = new Rectangle(30, 30, 140, 140);
var blendRectangle = new Rectangle(10, 10, 180, 160);
var innerCenter = new PointF(outerRectangle.Left + (outerRectangle.Width / 2),
outerRectangle.Top + (outerRectangle.Height / 2));
float gaugeLength = (outerRectangle.Width / 2) - 2;
using (var path = new GraphicsPath())
{
path.AddPie(outerRectangle, GaugeStartAngle, GaugeSweepAngle);
path.AddPie(innerRectangle, GaugeStartAngle, GaugeSweepAngle);
innerRectangle.Inflate(-1, -1);
using (var pen = new Pen(Color.White, 3f))
using (var backgroundbrush = new SolidBrush(canvas.BackColor))
using (var gradientBrush = new LinearGradientBrush(blendRectangle,
Color.Green, Color.Red, LinearGradientMode.ForwardDiagonal))
{
var blend = new Blend()
{
Factors = new[] { 0.0f, 0.0f, 0.1f, 0.3f, 0.7f, 1.0f },
Positions = new[] { 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f }
};
gradientBrush.Blend = blend;
e.Graphics.FillPath(gradientBrush, path);
e.Graphics.DrawPath(pen, path);
e.Graphics.FillEllipse(backgroundbrush, innerRectangle);
using (var format = new StringFormat())
{
format.Alignment = StringAlignment.Center;
format.LineAlignment = StringAlignment.Center;
innerRectangle.Location = new Point(innerRectangle.X, innerRectangle.Y + canvas.Font.Height);
e.Graphics.DrawString(GaugeValue.ToString() + "%", canvas.Font, Brushes.White, innerRectangle, format);
}
using (var mx = new Matrix())
{
mx.RotateAt(GaugeStartAngle + 90 + (GaugeValue * (GaugeSweepAngle / 100)), innerCenter);
e.Graphics.Transform = mx;
e.Graphics.DrawLine(pen, innerCenter, new PointF(innerCenter.X, innerCenter.Y - gaugeLength));
e.Graphics.ResetTransform();
}
}
}
}
private void tbarSpeed_Scroll(object sender, EventArgs e)
{
GaugeValue = tbarSpeed.Value;
Canvas.Invalidate();
}
Sample code on PasteBin
I'm dynamically creating isometric tiles from standard top-down tiles from another game. The problem, though, is that the the image resize often ends up with some amount of pixels "missing" on either side. I understand they're not really missing and the code is working properly but I don't know enough about GDI to know what settings/tutorials to search for.
I take this: and turn it into this: .
It goes from 32x32 to 48x24, which is the correct proportion. However, on the left and bottom, the grass is one pixel short of reaching the edge of the image. I don't want to fix this manually as I'll be doing this for hundreds of tiles so I'd like to find a way to fix this in the code. The issue, in the end, is that the tiles end up with tiny one-pixel gaps between them.
Is there anything I can do with GDI other than just checking each image for the edge colors and adding them manually if they're missing/transparent?
Here's the code I used to do this. The commented out parts are some of the various settings I've been messing with:
Bitmap bmp = RotateImage(new Bitmap(fileName), 45);
bmp = ResizeImage(bmp, bmp.Width, bmp.Height / 2);
private static Bitmap RotateImage(Bitmap rotateMe, float angle)
{
//First, re-center the image in a larger image that has a margin/frame
//to compensate for the rotated image's increased size
var bmp = new Bitmap(rotateMe.Width + (rotateMe.Width / 2), rotateMe.Height + (rotateMe.Height / 2));
using (Graphics g = Graphics.FromImage(bmp))
g.DrawImageUnscaled(rotateMe, (rotateMe.Width / 4), (rotateMe.Height / 4), bmp.Width, bmp.Height);
rotateMe = bmp;
//Now, actually rotate the image
Bitmap rotatedImage = new Bitmap(rotateMe.Width, rotateMe.Height);
using (Graphics g = Graphics.FromImage(rotatedImage))
{
g.TranslateTransform(rotateMe.Width / 2, rotateMe.Height / 2); //set the rotation point as the center into the matrix
g.RotateTransform(angle); //rotate
g.TranslateTransform(-rotateMe.Width / 2, -rotateMe.Height / 2); //restore rotation point into the matrix
g.DrawImage(rotateMe, new Point(0, 0)); //draw the image on the new bitmap
}
return rotatedImage;
}
private static Bitmap ResizeImage(System.Drawing.Image image, int width, int height)
{
var destRect = new Rectangle(0, 0, width, height);
var destImage = new Bitmap(width, height);
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
//graphics.CompositingMode = CompositingMode.SourceCopy;
//graphics.CompositingQuality = CompositingQuality.HighQuality;
//graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
//graphics.SmoothingMode = SmoothingMode.HighQuality;
//graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.SmoothingMode = SmoothingMode.AntiAlias;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
You might want to consider calculating the Width and Height of your rotated object.
For example:
private void button1_Click(object sender, EventArgs e)
{
var width = (int) numericUpDown2.Value;
var height = (int) numericUpDown3.Value;
var angle = (float) numericUpDown1.Value;
var size = new Size(width, height);
var result = RotatedSettings(angle, size);
textBox1.Text = String.Format("{0} x {1}", result.Width, result.Height);
}
private static Size RotatedSettings(float angle, Size size)
{
// setup corner values in array
var corners = new[]
{ new PointF(0, 0),
new PointF(size.Width, 0),
new PointF(0, size.Height),
new PointF(size.Width, size.Height)};
// rotate corners
var xc = corners.Select(p => Rotate(p, (float)angle).X);
var yc = corners.Select(p => Rotate(p, (float)angle).Y);
// find the new sizes by subtracting highest from lowest result.
var widths = xc as IList<float> ?? xc.ToList();
var newWidth = (int)Math.Abs(widths.Max() - widths.Min());
var heights = yc as IList<float> ?? yc.ToList();
var newHeight = (int)Math.Abs(heights.Max() - heights.Min());
// as we rotate the mid point we need to middle midpoint section and add the outcome to size.
var midX = ((size.Width / 2) - ((double)newWidth / 2));
var midY = ((size.Height / 2) - ((double)newHeight / 2));
return new Size(newWidth + (int)midX, newHeight + (int)midY);
}
/// <summary>
/// Rotates a point around the origin (0,0)
/// </summary>
private static PointF Rotate(PointF p, float angle)
{
// convert from angle to radians
var theta = Math.PI * angle / 180;
return new PointF(
(float)(Math.Cos(theta) * (p.X) - Math.Sin(theta) * (p.Y)),
(float)(Math.Sin(theta) * (p.X) + Math.Cos(theta) * (p.Y)));
}
I need to draw a rectangle that should be around the size 2X2 Inches when printed on a paper.
I know that i can draw a rectangle using
g.DrawRectangle(pen, 100,100, 100, 200);
This application will only be used in computers.How can i convert the inches to pixels properly so that i can get the desired dimensions when printed.
To make an image print in the right size by default, it needs to have the right combination of dpi and pixels.
Let's look at an example:
// aiming at 150dpi and 4x6 inches:
float dpi = 150;
float width = 4;
float height = 6;
using (Bitmap bmp = new Bitmap((int)(dpi * width), (int)(dpi * height)))
{
// first set the resolution
bmp.SetResolution(dpi, dpi);
// then create a suitable Graphics object:
using (Graphics G = Graphics.FromImage(bmp))
using (Pen pen = new Pen(Color.Orange))
{
pen.Alignment = System.Drawing.Drawing2D.PenAlignment.Center;
G.Clear(Color.FloralWhite);
// using pixels here:
Size sz = new System.Drawing.Size((int)dpi * 2 - 1, (int)dpi * 2 - 1);
G.DrawRectangle(pen, new Rectangle(new Point(0, 0), sz));
G.DrawRectangle(pen, new Rectangle(new Point(0, 300), sz));
G.DrawRectangle(pen, new Rectangle(new Point(0, 600), sz));
G.DrawRectangle(pen, new Rectangle(new Point(300, 0), sz));
G.DrawRectangle(pen, new Rectangle(new Point(300, 300), sz));
G.DrawRectangle(pen, new Rectangle(new Point(300, 600), sz));
// alternative code:
// we can also set the Graphics object to measure stuff in inches;
G.PageUnit = GraphicsUnit.Inch;
// or fractions of it, let's use 10th:
G.PageScale = 0.1f;
using (Pen pen2 = new Pen(Color.MediumPurple, 1f / dpi * G.PageScale))
{
// draw one rectangle offset by an inch:
G.DrawRectangle(pen2, 10f, 10f, 20f, 20f);
}
bmp.Save(#"D:\xxx.jpg", ImageFormat.Jpeg);
}
}
Note that I had to subtract 1 pixel from the drawn size as DrawRectangle overdraws by 1 pixel!
Note that the coordinates I draw at depend on the resolution! Also note how the jpeg format creates a lot of smeared colors. Pngcreates crisper results, especially once you print text..
Also note how I had to scale down the PenWidth in the alternative code!
I am attempting to create a minimap for an overlay. Currently the radar portion is working, targets rotate around the center point at the correct distance. I am having trouble printing the graphic that holds the minimap to screen. Everything other than the map prints to screen using the SlimDx.Direct3D9 library but based on my research the best way to create sub images based on player location was with graphics and this method avoids the OutOfMemory exception with cloning bitmaps and is more efficient.
if (ShowRadar)
{
//Draw background
//DrawFilledBox(this.GameWindowRect.Right - 225, this.GameWindowRect.Top + 50, 201f, 201f, Color.DarkOliveGreen, RadarTransparency);
RadarCenter = new Vector2(this.GameWindowRect.Right - 125, this.GameWindowRect.Top + 125 + 25);
if (DXTextrureMap != null)
{
//Transpose player posistion to map position and create the current mini map image
x = (int)player_X / 8;// +/- 4000 is max player range /8 = 500 = max map range
z = (int)player_Z / 8;
mini = new Rectangle(x, z, 100, 100);
Graphics g = Graphics.FromImage(originalBitmap);
g.DrawImage(originalBitmap, mini, new Rectangle((int)this.GameWindowRect.Right - 125, (int)this.GameWindowRect.Top + 125, 100, 100), System.Drawing.GraphicsUnit.Pixel);
}//the rest works as it should and displays on screen
if (RadarCenter.Length() > 0f)
{
//Display each entity in correct relational position
foreach (ENTITY entity in Entity)
{
Vector2 pointToRotate = new Vector2(entity.Pos.X, entity.Pos.Z);
Vector2 vector3 = new Vector2(player_X, player_Z);
pointToRotate = vector3 - pointToRotate;
float num30 = pointToRotate.Length() * 0.5f;
num30 = Math.Min(num30, 90f);
pointToRotate.Normalize();
pointToRotate = (Vector2)(pointToRotate * num30);
pointToRotate += RadarCenter;
pointToRotate = RotatePoint(pointToRotate, RadarCenter, player_D, true);
if (entity.Type == 0x04 && RadarPlayers)
{
DrawFilledBox(pointToRotate.X, pointToRotate.Y, 3f, 3f, Color.SkyBlue);
}
if ((entity.Type == 0x0C || entity.Type == 0x14 || entity.Type == 0x50 || entity.Type == 0x5b) && RadarAggressive)
{
DrawFilledBox(pointToRotate.X, pointToRotate.Y, 3f, 3f, Color.Red);
}
if ((entity.Type == 0x13 || entity.Type == 0x55) && RadarAnimals)
{
DrawFilledBox(pointToRotate.X, pointToRotate.Y, 3f, 3f, Color.LightGreen);
}
if ((entity.Type == 0x11 || entity.Type == 0x72 || entity.Type == 0x76) && RadarVehicles)
{
DrawFilledBox(pointToRotate.X, pointToRotate.Y, 3f, 3f, Color.HotPink);
}
}
}
//Draw radar border
DrawBoxAbs(this.GameWindowRect.Right - 225, this.GameWindowRect.Top + 50, 201f, 201f, 1f, Color.Black);
//Draw radar axis
DrawLine(this.GameWindowRect.Right - 125, this.GameWindowRect.Top + 50, this.GameWindowRect.Right - 125, this.GameWindowRect.Top + 251, 1f, Color.Black);
DrawLine(this.GameWindowRect.Right - 225, this.GameWindowRect.Top + 150, this.GameWindowRect.Right - 24, this.GameWindowRect.Top + 150, 1f, Color.Black);
//Center point
DrawFilledBox(RadarCenter.X - 1f, RadarCenter.Y - 1f, 3f, 3f, Color.White);
}
What is the correct way to print my graphic?
Makes more sense when you realize a graphic draws on the image it grabs, also had to dispose of some elements. Time to make it rotate then perhaps add headings.
if (DXTextrureMap != null)
{
DXSprite.Begin(SpriteFlags.None);
//Transpose player posistion to map position and create the current mini map image
x = (int)player_X / 4;// +/- 4000 is max player range and /4 = 1000 = max map range
z = (int)player_Z / 4;
mini = new Rectangle(x-78, z-78, 157, 157);
croppedBitmap = new Bitmap(200, 200);
using (Graphics grD = Graphics.FromImage(croppedBitmap))
{
grD.DrawImage(originalBitmap, new Rectangle(0, 0, 157, 157), mini, GraphicsUnit.Pixel);
}
//croppedBitmap = Copy(originalBitmap, mini);
using (MemoryStream s = new MemoryStream())//s is a MemoryStream
{
croppedBitmap.Save(s, System.Drawing.Imaging.ImageFormat.Png);
s.Seek(0, SeekOrigin.Begin); //must do this, or error is thrown in next line
currentMinimap = Texture.FromStream(DXDevice, s);
s.Dispose();
}
//croppedImage.Dispose();
DXSprite.Draw(currentMinimap, new Vector3(100f, 100f, 0f), new Vector3(this.GameWindowRect.Right - 125, this.GameWindowRect.Top + 135, 0f), Color.White);
DXSprite.End();
currentMinimap.Dispose();
}
I need to solve a problem by rotating an image, but I have this code to rotate the image does not rotate completely
public static Image RotateImage(Image img, float rotationAngle)
{
//create an empty Bitmap image
Bitmap bmp = new Bitmap(img.Width, img.Height);
//turn the Bitmap into a Graphics object
Graphics gfx = Graphics.FromImage(bmp);
//now we set the rotation point to the center of our image
gfx.TranslateTransform((float)bmp.Width / 2, (float)bmp.Height / 2);
//now rotate the image
gfx.RotateTransform(rotationAngle);
gfx.TranslateTransform(-(float)bmp.Width / 2, -(float)bmp.Height / 2);
//set the InterpolationMode to HighQualityBicubic so to ensure a high
//quality image once it is transformed to the specified size
gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
//now draw our new image onto the graphics object
gfx.DrawImage(img, new System.Drawing.Point(0, 0));
//dispose of our Graphics object
gfx.Dispose();
//return the image
return bmp;
}
And use this to call method. The right is rotate the image rectangle that contains, and to avoid cutting the image
Bitmap bitmap = (Bitmap)Pix.Image;
Pix.Image = (Bitmap)(RotateImage(bitmap, 20.0f));
private Bitmap RotateImageByAngle(Image oldBitmap, float angle)
{
var newBitmap = new Bitmap(oldBitmap.Width, oldBitmap.Height);
newBitmap.SetResolution(oldBitmap.HorizontalResolution, oldBitmap.VerticalResolution);
var graphics = Graphics.FromImage(newBitmap);
graphics.TranslateTransform((float)oldBitmap.Width / 2, (float)oldBitmap.Height / 2);
graphics.RotateTransform(angle);
graphics.TranslateTransform(-(float)oldBitmap.Width / 2, -(float)oldBitmap.Height / 2);
graphics.DrawImage(oldBitmap, new Point(0, 0));
return newBitmap;
}
I have used in the past the following code from this article.
http://www.switchonthecode.com/tutorials/csharp-tutorial-image-editing-rotate
Has some other solutions as well.
/// <summary>
/// Rotates the input image by theta degrees around center.
/// </summary>
public static Bitmap rotateCenter(Bitmap bmpSrc, float theta)
{
Matrix mRotate = new Matrix();
mRotate.Translate(bmpSrc.Width / -2, bmpSrc.Height / -2, MatrixOrder.Append);
mRotate.RotateAt(theta, new Point(0, 0), MatrixOrder.Append);
using (GraphicsPath gp = new GraphicsPath())
{ // transform image points by rotation matrix
gp.AddPolygon(new Point[] { new Point(0, 0), new Point(bmpSrc.Width, 0), new Point(0, bmpSrc.Height) });
gp.Transform(mRotate);
PointF[] pts = gp.PathPoints;
// create destination bitmap sized to contain rotated source image
Rectangle bbox = boundingBox(bmpSrc, mRotate);
Bitmap bmpDest = new Bitmap(bbox.Width, bbox.Height);
using (Graphics gDest = Graphics.FromImage(bmpDest))
{ // draw source into dest
Matrix mDest = new Matrix();
mDest.Translate(bmpDest.Width / 2, bmpDest.Height / 2, MatrixOrder.Append);
gDest.Transform = mDest;
gDest.DrawImage(bmpSrc, pts);
//drawAxes(gDest, Color.Red, 0, 0, 1, 100, "");
return bmpDest;
}
}
}
private static Rectangle boundingBox(Image img, Matrix matrix)
{
GraphicsUnit gu = new GraphicsUnit();
Rectangle rImg = Rectangle.Round(img.GetBounds(ref gu));
// Transform the four points of the image, to get the resized bounding box.
Point topLeft = new Point(rImg.Left, rImg.Top);
Point topRight = new Point(rImg.Right, rImg.Top);
Point bottomRight = new Point(rImg.Right, rImg.Bottom);
Point bottomLeft = new Point(rImg.Left, rImg.Bottom);
Point[] points = new Point[] { topLeft, topRight, bottomRight, bottomLeft };
GraphicsPath gp = new GraphicsPath(points,
new byte[] { (byte)PathPointType.Start, (byte)PathPointType.Line, (byte)PathPointType.Line, (byte)PathPointType.Line });
gp.Transform(matrix);
return Rectangle.Round(gp.GetBounds());
}