Question

How I can Crop / Clip images in WinRT. I have an image filled completely in a windows 8 window. I need to clip / crop the image from center and i need to display the two image section into two separate grids. How I can do the same through windows 8. Is it possible to implement this without using WritableBitmapEx. If no, how to do the same through WritableBitmapEx.

Was it helpful?

Solution

There are many ways to do it actually, each with some pros and cons.

  • WriteableBitmapEx seems like a popular solution. I have a similar implementation in WinRT XAML Toolkit. Both are essentially copying blocks of pixels from a full image bitmap. It might not be the fastest way, but if you'd want to get an out of the box solution - it is one that is easy to use. You need to copy the pixels, so you are not optimizing for memory use at the time of the operation and so might run out of memory on very large images quicker. You can recrop easily though end save the results to an image file if you want.
  • The BitmapDecoder solution Jan recommended is one I often use as it is part of the platform, written in native code and possibly highly optimized and you don't copy the pixels, but if you want to recrop - you'll need to decode the image again.
  • Xyroid's suggestion with Clip geometry is a quick display-only solution. You don't actually modify the bitmap in memory - you simply display a region of it on the screen. You need then to keep the entire image in memory and if you want to save it - you still need to update the bitmap to save it - by using either one of the first two solutions or maybe use RenderTargetBitmap.Render() if screen resolution is enough for you. It should be very quick though to update the crop region displayed on the screen for quick preview.
  • Another one is with a Rectangle filled with an ImageBrush where you can apply a Transform and specify the Rectangle size to control cropping. It is fairly similar to the Clip solution only instead of clipping an image and in this case you actually have to use the Tramsform (which you can also do on a Clip - RectangleGeometry). For quick updates - using a Transform might actually be a bit faster than updating the geometry and also supports scaling and rotations.

OTHER TIPS

You can use the Bitmapdecoder and the BitmapTransform classes. This example is very good for cropping. You should also read this tutorial for clipping. Basically you implement a function like this (taken from the example):

async public static Task<ImageSource> GetCroppedBitmapAsync(StorageFile originalImgFile, Point startPoint, Size corpSize, double scale) 
{ 


if (double.IsNaN(scale) || double.IsInfinity(scale)) 
{ 
    scale = 1; 
} 


// Convert start point and size to integer. 
uint startPointX = (uint)Math.Floor(startPoint.X * scale); 
uint startPointY = (uint)Math.Floor(startPoint.Y * scale); 
uint height = (uint)Math.Floor(corpSize.Height * scale); 
uint width = (uint)Math.Floor(corpSize.Width * scale); 


using (IRandomAccessStream stream = await originalImgFile.OpenReadAsync()) 
{ 


    // Create a decoder from the stream. With the decoder, we can get  
    // the properties of the image. 
    BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream); 

    // The scaledSize of original image. 
    uint scaledWidth = (uint)Math.Floor(decoder.PixelWidth * scale); 
    uint scaledHeight = (uint)Math.Floor(decoder.PixelHeight * scale); 



    // Refine the start point and the size.  
    if (startPointX + width > scaledWidth) 
    { 
        startPointX = scaledWidth - width; 
    } 


    if (startPointY + height > scaledHeight) 
    { 
        startPointY = scaledHeight - height; 
    } 


    // Create cropping BitmapTransform and define the bounds. 
    BitmapTransform transform = new BitmapTransform(); 
    BitmapBounds bounds = new BitmapBounds(); 
    bounds.X = startPointX; 
    bounds.Y = startPointY; 
    bounds.Height = height; 
    bounds.Width = width; 
    transform.Bounds = bounds; 


    transform.ScaledWidth = scaledWidth; 
    transform.ScaledHeight = scaledHeight; 

    // Get the cropped pixels within the bounds of transform. 
    PixelDataProvider pix = await decoder.GetPixelDataAsync( 
        BitmapPixelFormat.Bgra8, 
        BitmapAlphaMode.Straight, 
        transform, 
        ExifOrientationMode.IgnoreExifOrientation, 
        ColorManagementMode.ColorManageToSRgb); 
    byte[] pixels = pix.DetachPixelData(); 


    // Stream the bytes into a WriteableBitmap 
    WriteableBitmap cropBmp = new WriteableBitmap((int)width, (int)height); 
    Stream pixStream = cropBmp.PixelBuffer.AsStream(); 
    pixStream.Write(pixels, 0, (int)(width * height * 4)); 


    return cropBmp; 
} 


} 

XAML static way, if my screen size is 1366x768 & I want to clip center 400x300 image then I would do this.

<Image Source="Assets/img100.png" Stretch="Fill">
    <Image.Clip>
        <RectangleGeometry Rect="483,234,400,300" />
    </Image.Clip>
</Image>

Dynamic way. It will make center clipping for all resolution, though height & width is fixed.

double _Height = 300, _Width = 400;
img.Clip = new RectangleGeometry 
{
    Rect = new Rect((Window.Current.Bounds.Width - _Width) / 2, (Window.Current.Bounds.Height - _Height) / 2, _Width, _Height)
};

Don't forget to checkout...

How to resize Image in C# WinRT/winmd?

Crop image with rectangle

Crop image with dynamic rectangle coordinate

Cropping tool after file picker (like the one after you take a picture)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top