Apoorv
Apoorv

Reputation: 2043

Clipping Using Rectangle Geometry in WinRT application

I was previosuly using WriteableBitmapEX library for cropping images whereever my mouse moves. It seems to be a bit slow.

I want to crop the image at any random pixels and I want to asssign that cropped region to another image control .

My problem is when I am using the clip property , I am only getting the clipped region left and the whole image is going. I want the image completely to be in the background but the cropped region should be assigned to the image control .

Here's the code .

 private void Image1_Tapped(object sender, TappedRoutedEventArgs e)
        {
            int CropArea = 50;
            int PointShift = CropArea / 2;
            var _rect = new RectangleGeometry();
            Point pt;
            pt = e.GetPosition(Image1);

            _rect.Rect = new Rect(pt.X - PointShift, pt.Y - PointShift, 100, 100);
            Image1.Clip = _rect;
            MagnifyTip.Image1.Source=Image1.clip; //This is what I want to do . Its not happenning. 
        }


<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Image x:Name="Image1" Stretch="Uniform" HorizontalAlignment="Center" VerticalAlignment="Center" Tapped="Image1_Tapped" >
            <Image.Source >
                <BitmapImage UriSource="Assets/Jellyfish.png" />
            </Image.Source>
        </Image>
    </Grid>

Any better solutions are welcomed becuase I have to keep on moving my finger around the image and get the updated pixel by pixel cropped image in my imagebox in my user control

Upvotes: 1

Views: 1079

Answers (2)

Bilal Bashir
Bilal Bashir

Reputation: 1493

Well you don't want to clip the image you want in the background, you want two separate image controls and only clip the image you are magnifying, here is how I would do it using a Canvas and two image controls.

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Canvas HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Name="canvas">
        <Image Canvas.ZIndex="0"  x:Name="Image1" ImageOpened="Image1_Opened" Stretch="Uniform" HorizontalAlignment="Center" VerticalAlignment="Center" Tapped="Image1_Tapped" >
            <Image.Source>
                <BitmapImage UriSource="Assets/JellyFish.png" />
            </Image.Source>
        </Image>
        <Image Canvas.ZIndex="1" x:Name="MagnifyTip" Visibility="Collapsed">
            <Image.Source >
                <BitmapImage UriSource="Assets/JellyFish.png" />
            </Image.Source>
        </Image>
    </Canvas>
</Grid>

Once your background image is loaded you want to set the sizes for images in the canvas.

    double _scaleX = 5;
    double _scaleY = 5;
    double _croppedImageWidth = 100;
    double _croppedImageHeight = 100;

    private void Image1_Opened(object sender, RoutedEventArgs e)
    {
        this.Image1.MaxHeight = this.canvas.ActualHeight;
        this.Image1.MaxWidth = this.canvas.ActualWidth;
        this.MagnifyTip.MaxHeight = this.canvas.ActualHeight;
        this.MagnifyTip.MaxWidth = this.canvas.ActualWidth;
        this.MagnifyTip.RenderTransform = new ScaleTransform() 
        { 
            ScaleX = _scaleX,
            ScaleY = _scaleY
        };
    }

Then you can set the location and scale of your magnified image in Image1_Tapped handler.

    private void Image1_Tapped(object sender, TappedRoutedEventArgs e)
    {
        Point pt = e.GetPosition(this.canvas);
        this.MagnifyTip.Clip = new RectangleGeometry()
        {
            Rect = new Rect()
            {
                X = pt.X, 
                Y = pt.Y, 
                Width = _croppedImageWidth / _scaleX,
                Height = _croppedImageHeight / _scaleY
            }
        };
        Canvas.SetLeft(this.MagnifyTip, -pt.X * (_scaleX - 1));
        Canvas.SetTop(this.MagnifyTip, -pt.Y * (_scaleY - 1));

        this.MagnifyTip.Visibility = Visibility.Visible;
    }

The important points are

  • Use Canvas Left, Top and ZIndex properties to overlay the magnified image over the background image.
  • Calculate clip size and location for magnified image based off of the click point and size of your scale.
  • Use ScaleTransform to magnify the image.

Upvotes: 1

Filip Skakun
Filip Skakun

Reputation: 31724

A few things to note for cropping

  1. Use a RectangleGeometry for the Clip property of your image (you already do that)
  2. When adjusting the crop geometry - use its Transform property rather than creating a new geometry every time you want to recrop.
  3. Updating a WriteableBitmap is fairly slow, so you might be able to do that once in a while - e.g. when you commit the crop rectangle, but not in real time like on each PointerMove event.
  4. If you want real time updates you can either
    • Use another Image element with another RectangleGeometry Clip with a transform being a scaled version of the original transform. You could also use a copy of the original transform and scale the entire Image instead.
    • Use DirectX to render transformed output in a SwapChainPanel.
  5. For the final high resolution output you can use any method since processing speed is less of a factor
    • You could use RenderTargetBitmap.RenderAsync() to render your cropped image at screen resolution. You might need to wrap the clipped image in another element like a Grid.
    • You can use WriteableBitmap to do the processing - I believe the WriteableBitmapEx project on CodePlex has methods for rotating and cropping. This is CPU based though.
    • You can use DirectX, but that could be an overkill.
    • You can use WIC with BitmapDecoder, though that has limited rotation capabilities: How to resize Image in C# WinRT/winmd?

Upvotes: 0

Related Questions