1

I have managed to obtain the x,y,height,width of the area that I need to crop from the drawing on the inkCanvas. but I am not able to find the right solution to crop that area and save it as an image.

Edit: here is the whole story: I developed a drawing application a year ago for windows phone 8.1 Silverlight. using this example

http://bsubramanyamraju.blogspot.com/2014/03/windows-phone-ink-supportsignature.html

Now I am trying to make the same thing with some different functionalities for widows universal. I am developing it from scratch because now inking is available in win10 plus I can't use the old code as it contains InkPresenter which is only available for Silverlight applications.

Here is the code that I used for cropping the area last time (this is not my own code, I got it online)

static WriteableBitmap CropImage(WriteableBitmap source,
                                                           int xOffset, int yOffset,
                                                           int width, int height)
    {
        // Get the width of the source image
        var sourceWidth = source.PixelWidth;

        // Get the resultant image as WriteableBitmap with specified size
        var result = new WriteableBitmap(width, height);

        // Create the array of bytes
        for (var x = 0; x <= height - 1; x++)
        {
            var sourceIndex = xOffset + (yOffset + x) * sourceWidth;
            var destinationIndex = x * width;

            Array.Copy(source.Pixels, sourceIndex, result.Pixels, destinationIndex, width);
        }
        return result;
    }

But now it says

'WriteableBitmap' does not contain a definition for 'Pixels' 

at source.Pixels and source.Pixels and I don't know how to fix it.

I posted this question hoping that there must be a direct way to crop the InkCanvas area as it is a part of win10 now.

Edit 2 @Jay the width and height that I am passing in parameters is the width and height of the area that I want to crop with respect to the x and y. I tried debugging to check the value of decoder.PixelWidth and height. it is always same as the width and height I am providing in the params.

so now if xoffset =185 and yoffset=100 and the height and width in the params is 50 and 60. the decoder.PixelWidth and decoder.PixelHeight will also be the same as params. this is what the if condition looks like

if (pixelWidth > decoder.PixelWidth - xOffset || pixelHeight > decoder.PixelHeight - yOffset)

if (60> 60 - 185 || 50> 50- 100)

if (60> -125 || 50> -50)

therefore this condition is always true. where am I going wrong?

hope I didn't make any typos in this edit.

saira
  • 23
  • 5

1 Answers1

0

As you've known, the InkCanvas in UWP is different from what in Windows Phone 8.1 Silverlight. For how to use InkCanvas in UWP, please see Pen and stylus interactions in UWP apps.

To crop inkCanvas drawing from a particular area, we can store ink strokes with using IInkStrokeContainer.SaveAsync method first and then crop the image with BitmapTransform class. For example:

public static async System.Threading.Tasks.Task<WriteableBitmap> CropImageAsync(InkCanvas source, int xOffset, int yOffset, int pixelWidth, int pixelHeight)
{
    if (source.InkPresenter.StrokeContainer.GetStrokes().Count > 0)
    {
        using (var memStream = new InMemoryRandomAccessStream())
        {
            await source.InkPresenter.StrokeContainer.SaveAsync(memStream);

            BitmapDecoder decoder = await BitmapDecoder.CreateAsync(memStream);

            //pixelWidth and pixelHeight must less than the available pixel width and height
            if (pixelWidth > decoder.PixelWidth - xOffset || pixelHeight > decoder.PixelHeight - yOffset)
            {
                return null;
            }

            BitmapTransform transform = new BitmapTransform();
            BitmapBounds bounds = new BitmapBounds();
            bounds.X = (uint)xOffset;
            bounds.Y = (uint)yOffset;
            bounds.Width = (uint)pixelWidth;
            bounds.Height = (uint)pixelHeight;
            transform.Bounds = bounds;

            // Get the cropped pixels within the bounds of transform.
            PixelDataProvider pix = await decoder.GetPixelDataAsync(
                BitmapPixelFormat.Bgra8, // WriteableBitmap uses BGRA format
                BitmapAlphaMode.Straight,
                transform,
                ExifOrientationMode.IgnoreExifOrientation,
                ColorManagementMode.DoNotColorManage);

            byte[] pixels = pix.DetachPixelData();

            var cropBmp = new WriteableBitmap(pixelWidth, pixelHeight);

            // Stream the bytes into a WriteableBitmap
            using (Stream stream = cropBmp.PixelBuffer.AsStream())
            {
                await stream.WriteAsync(pixels, 0, pixels.Length);
            }

            return cropBmp;
        }
    }
    else
    {
        return null;
    }
}
Jay Zuo
  • 15,653
  • 2
  • 25
  • 49
  • It always goes inside this condition and returns null `if (pixelWidth > decoder.PixelWidth - xOffset || pixelHeight > decoder.PixelHeight - yOffset) { return null; }` – saira Jul 28 '16 at 19:55
  • @saira The size of the saved ink strokes is not the same as the size of the InkCanvas, you may need to make sure the crop area is less than the drawing area. You can use `decoder.PixelWidth` and `decoder.PixelHeight` to see the size of the saved ink strokes. – Jay Zuo Jul 29 '16 at 01:25
  • @saira How you set the `xoffset` and `yoffset`? The size of the saved ink strokes is as same as the area user drew and is not the size of the InkCanvas. So the `xoffset` and `yoffset` can't be set according to the InkCanvas. For example, if we want to crop whole ink strokes, we need to set `xoffset` and `yoffset` to `0`. – Jay Zuo Aug 01 '16 at 07:23