I have done some searching and i can not find any function thats doing what i whant it todo.
I have a image file of a scanned document with text, but the document is
If I've understood your question correctly, you essentially want to work out the new size of an image once rotated, and how to position the rotated image in it's new bitmap.
The diagram hopefully helps make clear the solution. Here is a bit of pseudo code:
sinVal = abs(sin(angle))
cosVal = abs(cos(angle))
newImgWidth = sinVal * oldImgHeight + cosVal * oldImgWidth
newImgHeight = sinVal * oldImgWidth + cosVal * oldImgHeight
originX = 0
originY = sinVal * oldImgWidth
You want to make the new image from the newImgWidth and newImgHeight, and then perform a rotation around the origin (originX, originY) and then render the image to this point. This will fall over if the angle (in degrees) isn't between -90 and 0 degrees (depicted). If it is between 0 and 90 degrees, then you just change the origin:
originX = sinVal * oldImgHeight
originY = 0
If it is in the range 90 degrees to 270 degrees (-90 degrees) then it is a little tricker (see example code below).
Your code re-written (briefly tested) - it is slightly dodgy but seems to work:
public static Bitmap RotateImg(Bitmap bmp, float angle, Color bkColor)
{
angle = angle % 360;
if (angle > 180)
angle -= 360;
System.Drawing.Imaging.PixelFormat pf = default(System.Drawing.Imaging.PixelFormat);
if (bkColor == Color.Transparent)
{
pf = System.Drawing.Imaging.PixelFormat.Format32bppArgb;
}
else
{
pf = bmp.PixelFormat;
}
float sin = (float)Math.Abs(Math.Sin(angle * Math.PI / 180.0)); // this function takes radians
float cos = (float)Math.Abs(Math.Cos(angle * Math.PI / 180.0)); // this one too
float newImgWidth = sin * bmp.Height + cos * bmp.Width;
float newImgHeight = sin * bmp.Width + cos * bmp.Height;
float originX = 0f;
float originY = 0f;
if (angle > 0)
{
if (angle <= 90)
originX = sin * bmp.Height;
else
{
originX = newImgWidth;
originY = newImgHeight - sin * bmp.Width;
}
}
else
{
if (angle >= -90)
originY = sin * bmp.Width;
else
{
originX = newImgWidth - sin * bmp.Height;
originY = newImgHeight;
}
}
Bitmap newImg = new Bitmap((int)newImgWidth, (int)newImgHeight, pf);
Graphics g = Graphics.FromImage(newImg);
g.Clear(bkColor);
g.TranslateTransform(originX, originY); // offset the origin to our calculated values
g.RotateTransform(angle); // set up rotate
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
g.DrawImageUnscaled(bmp, 0, 0); // draw the image at 0, 0
g.Dispose();
return newImg;
}
Note the Degrees to Radians Conversion (180 Degrees == Pi Radians) for the trig functions
Edit: big issue was negative sin values, and me getting width/height confused when calculating origin x/y - this should work fine now (tested)
Edit: modified code to handle any angle
This is strictly a comment to the nice answer by VisualMelon above, But I'm not allowed to add comments...
There are two tiny bugs in the code
a) The first check after the modulus should either be split into two, or changed to e.g.
if (180<Math.Abs(angle)) angle -= 360*Math.Sign(angle);
Otherwise angles between -360 and -180 will fail, as only +180 to +360 were handled
b) Just after the newImg assignment, a resolution assignment is missing, e.g.
newImg.SetResolution(bmp.HorizontalResolution, bmp.VerticalResolution);
If omitted the image will be scaled if the source is not 96 dpi.
....And splitting sticks, the intermediate calculations of dimensions and offsets ought to be kept in double, and only reduced to float last