Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF: Cut and save image

I'm looking for a way to rotate an image in order to cut a rectangle inside this image and save it as a separate picture.

Illustration

Edit: See accepted answer for solution.

like image 745
xsl Avatar asked Dec 09 '10 20:12

xsl


1 Answers

Update
I read your question again and this is probably closer to your problem. I didn't quite get how to use your coordinates but this method will take a BitmapImage, rotate it by an angle and save a cropped version of it from the starting X,Y values with the specified width and height. Probably not 100% like what you're trying to do but hopefully you can use the idea.

public void RotateAndSaveImage(BitmapImage sourceImage,
                               double angle,
                               int startX,
                               int startY,
                               int width,
                               int height,
                               string filePath)
{
    TransformGroup transformGroup = new TransformGroup();
    RotateTransform rotateTransform = new RotateTransform(angle);
    rotateTransform.CenterX = sourceImage.PixelWidth / 2.0;
    rotateTransform.CenterY = sourceImage.PixelHeight / 2.0;
    transformGroup.Children.Add(rotateTransform);
    TranslateTransform translateTransform = new TranslateTransform();
    translateTransform.X = -startX;
    translateTransform.Y = -startY;
    transformGroup.Children.Add(translateTransform);

    DrawingVisual vis = new DrawingVisual();
    DrawingContext cont = vis.RenderOpen();
    cont.PushTransform(transformGroup);
    cont.DrawImage(sourceImage, new Rect(new Size(sourceImage.PixelWidth, sourceImage.PixelHeight)));
    cont.Close();

    RenderTargetBitmap rtb = new RenderTargetBitmap(width, height, 96d, 96d, PixelFormats.Default);
    rtb.Render(vis);

    FileStream stream = new FileStream(filePath, FileMode.Create);
    PngBitmapEncoder encoder = new PngBitmapEncoder();
    encoder.Frames.Add(BitmapFrame.Create(rtb));
    encoder.Save(stream);
    stream.Close();
}

Thank you for your post, I had to alter the function a bit:

    private static double RadianToDegree(double angle)
    {
        return angle * (180.0 / Math.PI);
    }

    public static double GetDistanceBetweenPoints(Point p, Point q)
    {
        var a = p.X - q.X;
        var b = p.Y - q.Y;
        return Math.Sqrt(a * a + b * b);
    }

    private static double CalculateTheta(Point p1, Point p2)
    {
        var deltaX = Math.Abs(p1.Y - p2.Y);
        var deltaY = Math.Abs(p1.X - p2.X);
        var theta = RadianToDegree(Math.Atan(deltaY / deltaX));
        return (90 - theta) * -1;
    }

    public void RotateAndSaveImage(string sourceFile, List<Point> subCoords)
    {
        var bitmap = new BitmapImage();
        bitmap.BeginInit();
        bitmap.UriSource = new Uri(sourceFile);
        bitmap.EndInit();

        var p1 = subCoords[0];
        var p2 = subCoords[1];
        var p4 = subCoords[3];

        var theta = CalculateTheta(p1, p2);
        var width = GetDistanceBetweenPoints(p1, p2);
        var height = GetDistanceBetweenPoints(p1, p4);

        var transformGroup = new TransformGroup();
        var rotateTransform = new RotateTransform(theta)
        {
            CenterX = p1.X,
            CenterY = p1.Y
        };
        transformGroup.Children.Add(rotateTransform);

        var translateTransform = new TranslateTransform
        {
            X = -p1.X,
            Y = -p1.Y
        };

        transformGroup.Children.Add(translateTransform);

        var vis = new DrawingVisual();

        using (var cont = vis.RenderOpen())
        {
            cont.PushTransform(transformGroup);
            cont.DrawImage(bitmap, new Rect(
                new Size(bitmap.PixelWidth, bitmap.PixelHeight)));
        }

        var rtb = new RenderTargetBitmap((int)width, (int)height,
            96d, 96d, PixelFormats.Default);
        rtb.Render(vis);

        using (var stream = new FileStream(TargetFile, FileMode.Create))
        {
            var encoder = new JpegBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(rtb));
            encoder.Save(stream);
        }
    }

The code above works perfectly. I would have never accomplished this without your help.

like image 97
Fredrik Hedblad Avatar answered Oct 14 '22 15:10

Fredrik Hedblad