How to rotate image in c#? - c#

I have an image I display on my website. Which is written in c#. I want to give my user the ability to click on a button which rotates the image. This will rotate the actual image on the server so next time it is displayed it is displayed the correct way.
Similar to how facebook has image rotation?

Do you really need to rotate the image on the server? Why not just store a property with the image which stores the rotation value like 90, 180, 270... and apply this every time image is retrieved and update/save the property value once user rotates the image
see this tutorial for how to rotate an image or google it you will find a lot of samples

//Create Image element
Image rotated270 = new Image();
rotated270.Width = 150;
//Create source
BitmapImage bi = new BitmapImage();
//BitmapImage properties must be in a BeginInit/EndInit block
bi.BeginInit();
bi.UriSource = new Uri(#"pack://application:,,/sampleImages/watermelon.jpg");
//Set image rotation
bi.Rotation = Rotation.Rotate270;
bi.EndInit();
//set image source
rotated270.Source = bi;

public static Image RotateImage(Image image, Size size, float angle)
{
if (image == null)
{
throw new ArgumentNullException("image");
}
if (size.Width < 1 || size.Height < 1)
{
throw new ArgumentException("size must be larger than zero.");
}
Bitmap tempImage = new Bitmap(size.Width, size.Height);
using (Graphics tempGraphics = Graphics.FromImage(tempImage))
{
PointF center = new PointF((float)size.Width / 2F, (float)size.Height / 2F);
tempGraphics.TranslateTransform(center.X, center.Y, MatrixOrder.Prepend);
tempGraphics.RotateTransform(angle != 180F ? angle : 182F/*at 180 exact angle the rotate make a small shift of image I don't know why!*/);
tempGraphics.TranslateTransform(-center.X, -center.Y, MatrixOrder.Prepend);
tempGraphics.DrawImage(image, new PointF());
}
return tempImage;
}

Related

Rotate Image in Win2D

I'm trying to rotate image but couldn't get expected result.
I've tried with WIn2D but couldn't make image as expected.
My tried Code
public async void Rotate(string originalImagepath, Rect originalImageRect, float degrees)
{
int height = (int)Math.Sqrt(originalImageRect.Width * originalImageRect.Width + originalImageRect.Height * originalImageRect.Height);
CanvasDevice device = CanvasDevice.GetSharedDevice();
CanvasRenderTarget webCardImage = null;
CanvasBitmap bitmap = null;
var logicalDpi = DisplayInformation.GetForCurrentView().LogicalDpi;
Vector2 endpoint = new Vector2((float)originalImageRect.Width / 2, (float)originalImageRect.Height / 2);
try
{
webCardImage = new CanvasRenderTarget(device, height, height, logicalDpi);
using (var ds = webCardImage.CreateDrawingSession())
{
ds.Clear(Colors.Transparent);
using (FileStream imageStream = new FileStream(originalImagepath, FileMode.Open))
{
IRandomAccessStream fileStream = imageStream.AsRandomAccessStream();
bitmap = await CanvasBitmap.LoadAsync(device, fileStream);
}
ICanvasImage image = new Transform2DEffect
{
Source = bitmap,
TransformMatrix = Matrix3x2.CreateRotation(degrees, endpoint),
};
var sourceRect = image.GetBounds(ds);
ds.DrawImage(image, new Rect(originalImageRect.X, originalImageRect.Y, originalImageRect.Width, originalImageRect.Height), sourceRect, 1, CanvasImageInterpolation.HighQualityCubic);
}
}
catch (Exception ex)
{
}
//Save Image Code here
}
Expected Output:
My generated Image:
NB: Rect originalImageRect refers main image rect which i want to rotate.
When this happens, it means that after your image is rotated, the size of the target rendering rectangle (may be height or width) is smaller than the size of the rotated image, resulting in compression of the image.
I analyzed your code, you tried to create a square with the originalImageRect diagonal length as the side length, to ensure that the image will not exceed the rendering range when rotating around the center.
This is good, but there are some deviations when rendering.
The image is in the upper left corner of CanvasRenderTarget by default. If no displacement is performed, the center point is on the upper left when rotating, which means it will still exceed the rendering range.
You can try this:
double height = Math.Sqrt(originalImageRect.Width * originalImageRect.Width + originalImageRect.Height * originalImageRect.Height);
float y = (float)((height - originalImageRect.Height) / 2.0f);
float x = (float)((height - originalImageRect.Width) / 2.0f);
Vector2 endpoint = new Vector2((float)height / 2, (float)height / 2);
try
{
webCardImage = new CanvasRenderTarget(MyCanvas, (float)height, (float)height, logicalDpi);
using (var ds = webCardImage.CreateDrawingSession())
{
// init CanvasBitmap
ICanvasImage image = new Transform2DEffect
{
Source = bitmap,
TransformMatrix = Matrix3x2.CreateTranslation(new Vector2(x,y))
* Matrix3x2.CreateRotation(degrees,endpoint)
};
var sourceRect = image.GetBounds(ds);
ds.DrawImage(image);
}
}
catch (Exception ex)
{
}
We first shift the image, move it to the center of the canvas, and then rotate it around the center of the canvas, so that we can achieve our goal.
In addition, when using the DrawImage() method, there is no need to additionally define Rect for rendering constraints.
Thanks.

Scaling and rotating images in C# results in ghosted edges

I'm using C# to scale and rotate an image with a transparent background, then using JavaScript to add it to a Google Maps API map, but once it's scaled and rotated, the edges of the image get blurred, and it becomes hard to see, especially over water.
Here is my original 300x300 image:
And here is an example of one of the output images at 100x100 (SizeInt = 100):
Before you get confused as to the background colour, the image is projected onto a map where the water is a similar colour to the image.
You can see some slight ghosting around the edges of the image.
Once it's scaled down further (to it's required scale):
It's almost unnoticeable...
I'm still relatively new to C#, but I've tried loading SVGs directly onto the map with JavaScript (icon: "some/SVG/file.svg"), but that causes serious performance problems, as there are up to 1,000 icons on the map at any given time, making the map unusable when using SVG files, so I have to use image files.
The images need to be sharp and not blurred around the edges. Here is the code used to generate the images, forgive any sloppy code, I'm still somewhat new to C#:
Here is the code used to scale the image:
The image needs to be rotated in a full circle (rounded to 5 degrees), hence the loop from 0 to 361.
private void BuildIcons(string dir)
{
int SizeInt = 30;
// Get the content path
var ContentPath = dir;
// Get the original image
Bitmap OriginalImage = new Bitmap(ContentPath + "base.png");
#region Resize image
// New size
Size size = new Size(SizeInt, SizeInt);
// New height/width temp vars
int newWidth;
int newHeight;
// Aspect ratio preservation
int originalWidth = OriginalImage.Width;
int originalHeight = OriginalImage.Height;
float percentWidth = (float)size.Width / (float)originalWidth;
float percentHeight = (float)size.Height / (float)originalHeight;
float percent = percentHeight < percentWidth ? percentHeight : percentWidth;
newWidth = (int)(originalWidth * percent);
newHeight = (int)(originalHeight * percent);
// Generate the new image
Image ResizedImage = new Bitmap(newWidth, newHeight);
using (Graphics graphicsHandle = Graphics.FromImage(ResizedImage))
{
graphicsHandle.SmoothingMode = SmoothingMode.HighQuality;
graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphicsHandle.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphicsHandle.DrawImage(OriginalImage, 0, 0, newWidth, newHeight);
}
#endregion
int maxside = SizeInt;
#region Image rotation
// Generate images
for (int i = 0; i < 361; i += 5)
{
// New empty bitmap to hold rotated images
Bitmap ReturnBitmap = new Bitmap(maxside, maxside);
// Graphics object from the empty bitmap
// Normal
Graphics Gfx = Graphics.FromImage(ReturnBitmap);
Gfx.SmoothingMode = SmoothingMode.HighQuality;
Gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
Gfx.PixelOffsetMode = PixelOffsetMode.HighQuality;
// Move rotation point to center of image
Gfx.TranslateTransform(
(float)ResizedImage.Width / 2,
(float)ResizedImage.Height / 2
);
// Rotate
Gfx.RotateTransform(i);
// Move image back
Gfx.TranslateTransform(
-(float)ResizedImage.Width / 2,
-(float)ResizedImage.Height / 2
);
// draw original in image onto graphics object
Gfx.DrawImage(ResizedImage, new Point(0, 0));
// Save the image
ReturnBitmap.Save(ContentPath + i.ToString() + ".png");
// Clean up
ReturnBitmap.Dispose();
Gfx.Dispose();
}
#endregion
// Clean up
ResizedImage.Dispose();
OriginalImage.Dispose();
}
Any suggestions?

How to rotate source of image and not image itself in C#/XAML(WPF 8.1)?

I'm working on a painting app for windows phone 8.1 and I'm stuck. I have a working space (bitmap) that I'm able to rotate and a stamp control with which I can stamp drawed Elements. The stamp control consists of a rectangle and an image inside this rectangle. If the working space is on 0 or 180 degrees there is no problem for me to visualize the stamped elements inside the image. The problem appears if the working space is rotated by 90 or 270 degrees. Than if I rotate the image by the degrees of the working space the width and height of the image is obviously postponed.
public void SetSourceImageStamp(ImageSource imageSource)
{
var currentPocketPaintApplication = PocketPaintApplication.GetInstance();
RotateTransform rt = new RotateTransform();
rt.Angle = currentPocketPaintApplication.angularDegreeOfWorkingSpaceRotation;
image.RenderTransformOrigin = new Point(0.5, 0.5);
if (currentPocketPaintApplication.angularDegreeOfWorkingSpaceRotation == 90 || currentPocketPaintApplication.angularDegreeOfWorkingSpaceRotation == 270)
{
image.Height = RectangleToDraw.Width;
image.Width = RectangleToDraw.Height;
image.HorizontalAlignment = HorizontalAlignment.Center;
image.VerticalAlignment = VerticalAlignment.Center;
}
image.RenderTransform = rt;
image.Source = imageSource;
}
So I have the following question, is there a possibility to rotate only the source of the image and not the whole image itself?

Image cropping in C#

I'am using PictureBox for displaying images. My images are direct from scanner so the resolutions are up to 4000*4000... Because my display area is a lot smaller I have to display the image with pictureBox1.SizeMode = PictureBoxSizeMode.Zoom; to preserve aspect ratio.
After that the image is in the middle of the screen.
How can I find the distance between the left side of the image control and the REAL left side of an actual image (see image bellow).
Is there any solution?
Btw. displaying the image on the left side of the screen would do the trick too.
var imageHeight = pictureBox1.Image.Height;
var imageWidth = pictureBox1.Image.Width;
var userSelection = rect.Rect;
var display = pictureBox1.DisplayRectangle;
var xFactor = (float)userSelection.Width / display.Width;
var yFactor = (float)userSelection.Height / display.Height;
var realCropSizeWidth = xFactor * imageWidth;
var realCropSizeHight = yFactor * imageHeight;
var realCropX = imageWidth / display.Width;
realCropX *= userSelection.X;
var realCropY = imageHeight / display.Height;
realCropY *= userSelection.Y;
var realCropRectangle = new Rectangle(realCropX, realCropY, (int)realCropSizeWidth,
(int)realCropSizeHight);
var image = CropImage(pictureBox1.Image, realCropRectangle);
pictureBox1.Image = image;
public Image CropImage(Image source, Rectangle rectangle)
{
var target = new Bitmap(rectangle.Width, rectangle.Height);
using (var g = Graphics.FromImage(target))
{
g.DrawImage(source, new Rectangle(0, 0, target.Width, target.Height),
rectangle,
GraphicsUnit.Pixel);
}
return target;
}
As far as I know there is no direct way of getting what you want, but some simple maths would suffice:
You know the aspect ratio of your original image which is preserved and you know the aspect ratio of your picturebox in which you are showing it. Based on that you can figure out which dimension (height or width) the image fits exactly. Once you know that you can obtain the scaling factor of the image and therefore you can calculate the other dimension of the shown image.
As the image will be centered on the dimension that is not fitted exactly to the picturebox, its straighforward to get the distance you are looking for.

Rotating an image - readonly

I found code to rotate an image. My problem is that when I save it, the image is already opened, and in use by me (As, I opened it to rotate it).
How can I avoid this?
public static void RotateImage(string filePath, float angle)
{
//create a new empty bitmap to hold rotated image
using (var img = Image.FromFile(filePath))
{
using(var 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(angle);
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 Point(0, 0));
//dispose of our Graphics object
}
img.Save(filePath);
}
edit: Updated code as per Anthony's advice.
edit:
Just some FYI, this was accomplished in a couple of lines...
public static void RotateImage(string filePath, float angle)
{
//create a new empty bitmap to hold rotated image
byte[] byt = System.IO.File.ReadAllBytes(filePath);
var ms = new System.IO.MemoryStream(byt);
using (Image img = Image.FromStream(ms))
{
RotateFlipType r = angle == 90 ? RotateFlipType.Rotate90FlipNone : RotateFlipType.Rotate270FlipNone;
img.RotateFlip(r);
img.Save(filePath);
}
}
Using your existing code you can do the following:
byte[] byt = System.IO.File.ReadAllBytes(filepath);
System.IO.MemoryStream ms = new System.IO.MemoryStream(byt);
Image img = Image.FromStream(ms);
That will not have the file locked when you go to save it.

Categories