Difficulty in implementing image cropping

Oliver 21 Reputation points
2022-09-03T09:06:32.713+00:00

Dear Community!

I have difficulties implementing this guide: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/bitmaps/cropping.

While testing i found out, that this GUide uses special libraries for the TouchTracking since installing the TouchTracking nuget Package friom Indrej Kunc does not work too in the example. I then tried to copy the custom TOuchTracking, TouchEffect etc. files from the example into my project but then not touch gesture at all worked. How can i now implement image Cropping like this?

I also tried it with https://github.com/INHack20/ImageCropper.Forms but after installing the nuget package i cannot add ,,Stormlion.ImageCropper.Droid.Platform.Init();" to the Android main act5ivity since the name Stormlion does not exist in the current context.

What am i doing wrong? How can i fix this?

namespace DoggoApp.Droid  
{  
    [Activity(Label = "DoggoApp", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize )]  
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity  
    {  
        const int RequestLocationId = 0;  
        readonly string[] LocationPermissions =  
        {  
            Manifest.Permission.AccessCoarseLocation,  
            Manifest.Permission.AccessFineLocation,  
            Manifest.Permission.AccessBackgroundLocation  
        };  
        protected override void OnCreate(Bundle savedInstanceState)  
        {  
            base.OnCreate(savedInstanceState);  
  
            CachedImageRenderer.Init(true);  
            Stormlion.ImageCropper.Droid.Platform.Init();  
  
            global::Xamarin.Forms.Forms.Init(this, bundle);  
            NControl.Droid.NControlViewRenderer.Init();  
            Xamarin.Essentials.Platform.Init(this, savedInstanceState);  
            global::Xamarin.Forms.Forms.Init(this, savedInstanceState);  
            Xamarin.FormsMaps.Init(this, savedInstanceState);  
  
              
            LoadApplication(new App());  
        }  
        public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)  
        {  
            Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);  
            base.OnRequestPermissionsResult(requestCode, permissions, grantResults);  
  
  
            if (requestCode == RequestLocationId)  
            {  
                if ((grantResults.Length == 1) && (grantResults[0] == (int)Permission.Granted))  
                    return;  
                else  
                    return;  
            }  
            else  
            {  
                Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);  
                base.OnRequestPermissionsResult(requestCode, permissions, grantResults);  
            }  
        }  
        
        protected override void OnStart()  
        {  
            base.OnStart();  
  
            if ((int)Build.VERSION.SdkInt >= 23)  
            {  
                if (CheckSelfPermission(Manifest.Permission.AccessFineLocation) != Permission.Granted)  
                {  
                    RequestPermissions(LocationPermissions, RequestLocationId);  
                }  
                if (CheckSelfPermission(Manifest.Permission.AccessCoarseLocation) != Permission.Granted)  
                {  
                    RequestPermissions(LocationPermissions, RequestLocationId);  
                }  
                if (CheckSelfPermission(Manifest.Permission.AccessBackgroundLocation) != Permission.Granted)  
                {  
                    RequestPermissions(LocationPermissions, RequestLocationId);  
                }  
                else  
                {  
                    // Permissions already granted - display a message.  
                }  
            }  
        }         

}

using System;  
using System.Collections.Generic;  
using NGraphics;  
using SkiaSharp;  
using SkiaSharp.Views.Forms;  
using TouchTracking;  
using TouchTracking.Forms;  
  
namespace SkiaSharpFormsDemos.Bitmaps  
{  
    class PhotoCropperCanvasView : SKCanvasView  
    {  
        const int CORNER = 50;      // pixel length of cropper corner  
        const int RADIUS = 100;     // pixel radius of touch hit-test  
  
        SKBitmap bitmap;  
        CroppingRectangle croppingRect;  
        SKMatrix inverseBitmapMatrix;  
  
        // Touch tracking   
        TouchEffect touchEffect = new TouchEffect();  
        struct TouchPoint  
        {  
            public int CornerIndex { set; get; }  
            public SKPoint Offset { set; get; }  
        }  
  
        Dictionary<long, TouchPoint> touchPoints = new Dictionary<long, TouchPoint>();  
  
        // Drawing objects  
        SKPaint cornerStroke = new SKPaint  
        {  
            Style = SKPaintStyle.Stroke,  
            Color = SKColors.White,  
            StrokeWidth = 10  
        };  
  
        SKPaint edgeStroke = new SKPaint  
        {  
            Style = SKPaintStyle.Stroke,  
            Color = SKColors.White,  
            StrokeWidth = 2  
        };  
  
        public PhotoCropperCanvasView(SKBitmap bitmap, float? aspectRatio = null)  
        {  
            this.bitmap = bitmap;  
  
            SKRect bitmapRect = new SKRect(0, 0, bitmap.Width, bitmap.Height);  
            croppingRect = new CroppingRectangle(bitmapRect, aspectRatio);  
  
            touchEffect.TouchAction += OnTouchEffectTouchAction;  
        }  
  
        public SKBitmap CroppedBitmap  
        {  
            get  
            {  
                SKRect cropRect = croppingRect.Rect;  
                SKBitmap croppedBitmap = new SKBitmap((int)cropRect.Width,   
                                                      (int)cropRect.Height);  
                SKRect dest = new SKRect(0, 0, cropRect.Width, cropRect.Height);  
                SKRect source = new SKRect(cropRect.Left, cropRect.Top,   
                                           cropRect.Right, cropRect.Bottom);  
  
                using (SKCanvas canvas = new SKCanvas(croppedBitmap))  
                {  
                    canvas.DrawBitmap(bitmap, source, dest);  
                }  
  
                return croppedBitmap;  
            }  
        }  
  
        protected override void OnParentSet()  
        {  
            base.OnParentSet();  
  
            // Attach TouchEffect to parent view  
            Parent.Effects.Add(touchEffect);  
        }  
  
        protected override void OnPaintSurface(SKPaintSurfaceEventArgs args)  
        {  
            base.OnPaintSurface(args);  
  
            SKImageInfo info = args.Info;  
            SKSurface surface = args.Surface;  
            SKCanvas canvas = surface.Canvas;  
  
            canvas.Clear(SKColors.Gray);  
  
            // Calculate rectangle for displaying bitmap   
            float scale = Math.Min((float)info.Width / bitmap.Width, (float)info.Height / bitmap.Height);  
            float x = (info.Width - scale * bitmap.Width) / 2;  
            float y = (info.Height - scale * bitmap.Height) / 2;  
            SKRect bitmapRect = new SKRect(x, y, x + scale * bitmap.Width, y + scale * bitmap.Height);  
            canvas.DrawBitmap(bitmap, bitmapRect);  
  
            // Calculate a matrix transform for displaying the cropping rectangle  
            SKMatrix bitmapScaleMatrix = SKMatrix.MakeIdentity();  
            bitmapScaleMatrix.SetScaleTranslate(scale, scale, x, y);  
  
            // Display rectangle  
            SKRect scaledCropRect = bitmapScaleMatrix.MapRect(croppingRect.Rect);  
            canvas.DrawRect(scaledCropRect, edgeStroke);  
  
            // Display heavier corners  
            using (SKPath path = new SKPath())  
            {  
                path.MoveTo(scaledCropRect.Left, scaledCropRect.Top + CORNER);  
                path.LineTo(scaledCropRect.Left, scaledCropRect.Top);  
                path.LineTo(scaledCropRect.Left + CORNER, scaledCropRect.Top);  
  
                path.MoveTo(scaledCropRect.Right - CORNER, scaledCropRect.Top);  
                path.LineTo(scaledCropRect.Right, scaledCropRect.Top);  
                path.LineTo(scaledCropRect.Right, scaledCropRect.Top + CORNER);  
  
                path.MoveTo(scaledCropRect.Right, scaledCropRect.Bottom - CORNER);  
                path.LineTo(scaledCropRect.Right, scaledCropRect.Bottom);  
                path.LineTo(scaledCropRect.Right - CORNER, scaledCropRect.Bottom);  
  
                path.MoveTo(scaledCropRect.Left + CORNER, scaledCropRect.Bottom);  
                path.LineTo(scaledCropRect.Left, scaledCropRect.Bottom);  
                path.LineTo(scaledCropRect.Left, scaledCropRect.Bottom - CORNER);  
  
                canvas.DrawPath(path, cornerStroke);  
            }  
  
            // Invert the transform for touch tracking  
            bitmapScaleMatrix.TryInvert(out inverseBitmapMatrix);  
        }  
  
        void OnTouchEffectTouchAction(object sender, TouchActionEventArgs args)  
        {  
            SKPoint pixelLocation = ConvertToPixel(args.Location);  
            SKPoint bitmapLocation = inverseBitmapMatrix.MapPoint(pixelLocation);  
  
            switch (args.Type)  
            {  
                case TouchActionType.Pressed:  
                    // Convert radius to bitmap/cropping scale  
                    float radius = inverseBitmapMatrix.ScaleX * RADIUS;  
  
                    // Find corner that the finger is touching  
                    int cornerIndex = croppingRect.HitTest(bitmapLocation, radius);  
  
                    if (cornerIndex != -1 && !touchPoints.ContainsKey(args.Id))  
                    {  
                        TouchPoint touchPoint = new TouchPoint  
                        {  
                            CornerIndex = cornerIndex,  
                            Offset = bitmapLocation - croppingRect.Corners[cornerIndex]  
                        };  
  
                        touchPoints.Add(args.Id, touchPoint);  
                    }  
                    break;  
  
                case TouchActionType.Moved:  
                    if (touchPoints.ContainsKey(args.Id))  
                    {  
                        TouchPoint touchPoint = touchPoints[args.Id];  
                        croppingRect.MoveCorner(touchPoint.CornerIndex,   
                                                bitmapLocation - touchPoint.Offset);  
                        InvalidateSurface();  
                    }  
                    break;  
                       
                case TouchActionType.Released:  
                case TouchActionType.Cancelled:  
                    if (touchPoints.ContainsKey(args.Id))  
                    {  
                        touchPoints.Remove(args.Id);  
                    }  
                    break;  
            }  
        }  
  
        SKPoint ConvertToPixel(TouchTrackingPoint pt)  
        {  
            return new SKPoint((float)(CanvasSize.Width * pt.X / Width),  
                                (float)(CanvasSize.Height * pt.Y / Height));  
        }  
    }  
}  


  
Xamarin
Xamarin
A Microsoft open-source app platform for building Android and iOS apps with .NET and C#.
5,289 questions
0 comments No comments
{count} votes

Accepted answer
  1. Leon Lu (Shanghai Wicresoft Co,.Ltd.) 67,781 Reputation points Microsoft Vendor
    2022-09-05T07:34:01.32+00:00

    Hello,

    TouchTracking since installing the TouchTracking nuget Package friom Indrej Kunc does not work too in the example

    No, it is not use TouchTracking nuget Package. This demo creates custom touch effect for different platforms.

    Firstly, you need to create a new class TouchEffect.cs in DoggoApp folder, please notice namespace is namespace TouchTracking.

    Then , you can copy this TouchEffect.cs to your DoggoApp.Droid folder. That is same for iOS and UWP

    Best Regards,

    Leon Lu


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


0 additional answers

Sort by: Most helpful