Clear operation on Canvas with Image Bitmap

Hello friends, I able to place the image as bitmap on the canvas and able to make annotation on it. When comes to clear operation, it clears all the annotation and also the image which is not what I expected.

I expected if clicked on clear button, it clears all the annotation and keep a clean image bitmap on the canvas.

Is there a way to only clear the annotation (keeps the image) and shows a clean image bitmap on the canvas?

Your help/suggestions would be much appreciated!

Cheers!

Answers

  • seanydaseanyda GBMember ✭✭✭✭✭

    Yeah sure, But you'll need to show some code.

    I did something like this on the OnCanvasViewPaintSurface method

    if (!hasDrawnCanvas || senderCanvas.ClassId == "UndoPressed")
                    {
                        if (savedBitmap != null)
                        {
                            canvas.Clear();
                            canvas.DrawBitmap(savedBitmap, 0, 0);
                        }
                        else
                        {
                            savedBitmap = SKBitmap.Decode(DependencyService.Get<IMediaService>().ResizeImage(mediaFile, canvasView.CanvasSize.Width, canvasView.CanvasSize.Height));
                            canvas.DrawBitmap(savedBitmap, 0, 0);
                        }
                        canvasView.ClassId = null;
                        hasDrawnCanvas = true;
                    }
    
  • ericawxwericawxw Member ✭✭

    Thank you for your reply. @seanyda

    This is my code for the clear button function. I know there is something wrong with my code, I deleted the path but I didn't render it.

    void OnClearButtonClicked(object sender, EventArgs args)
            {
                completedPaths.Clear();
                inProgressPaths.Clear();            
                UpdateBitmap();
                canvasView.InvalidateSurface();
            }
    

    And here's the code to update the bitmap.

    void UpdateBitmap()
            {
                using (saveBitmapCanvas = new SKCanvas(saveBitmap))
                {                
                    //saveBitmapCanvas.Clear();
    
                    foreach (SKPath path in completedPaths)
                    {
                        saveBitmapCanvas.DrawPath(path, paint);
                    }
    
                    foreach (SKPath path in inProgressPaths.Values)
                    {
                        saveBitmapCanvas.DrawPath(path, paint);
                    }
                }
    
                canvasView.InvalidateSurface();
            }
    
  • ericawxwericawxw Member ✭✭

    @seanyda said:
    Yeah sure, But you'll need to show some code.

    I did something like this on the OnCanvasViewPaintSurface method

    if (!hasDrawnCanvas || senderCanvas.ClassId == "UndoPressed")
                    {
                        if (savedBitmap != null)
                        {
                            canvas.Clear();
                            canvas.DrawBitmap(savedBitmap, 0, 0);
                        }
                        else
                        {
                          savedBitmap = SKBitmap.Decode(DependencyService.Get<IMediaService>().ResizeImage(mediaFile, canvasView.CanvasSize.Width, canvasView.CanvasSize.Height));
                            canvas.DrawBitmap(savedBitmap, 0, 0);
                        }
                        canvasView.ClassId = null;
                        hasDrawnCanvas = true;
                    }
    

    I was wondering, are you having two canvas view (senderCanvas and canvasView)? How does it work?
    Thank you.

  • seanydaseanyda GBMember ✭✭✭✭✭

    @ericawxw said:

    @seanyda said:
    Yeah sure, But you'll need to show some code.

    I did something like this on the OnCanvasViewPaintSurface method

    if (!hasDrawnCanvas || senderCanvas.ClassId == "UndoPressed")
                    {
                        if (savedBitmap != null)
                        {
                            canvas.Clear();
                            canvas.DrawBitmap(savedBitmap, 0, 0);
                        }
                        else
                        {
                            savedBitmap = SKBitmap.Decode(DependencyService.Get<IMediaService>().ResizeImage(mediaFile, canvasView.CanvasSize.Width, canvasView.CanvasSize.Height));
                            canvas.DrawBitmap(savedBitmap, 0, 0);
                        }
                        canvasView.ClassId = null;
                        hasDrawnCanvas = true;
                    }
    

    I was wondering, are you having two canvas view (senderCanvas and canvasView)? How does it work?
    Thank you.

    try
                {
                    SKCanvas canvas = args.Surface.Canvas;
                    SKCanvasView senderCanvas = (SKCanvasView)sender;   
    

    The sender is the SKCanvasView which contains the SKCanvas.

  • ericawxwericawxw Member ✭✭

    @seanyda can you please tell me how you implemented the flow of the clear operation process? I am not quite get it. Or do you have some example code that you can show me? Thank you in advance.

  • puneetmahalipuneetmahali Member ✭✭
    edited August 2018

    Hello Guys,

    I want to load the Indoor Map Image dynamically with use of UrhoSharp & Texture.

    Question- Is it possible to use Bitmap also in UrhoSharp?

    Because Texture not loads the image properly. And also which Shape I need to use in Texture for load the Indoor Map Image in a 3D view. I am using Sphere form.

    Below is my code-

        public IndoorMapPage(ApplicationOptions options) : base(options)
        {
            UnhandledException += Application_UnhandledException;
        }
    
        public IndoorMapPage(IntPtr handle) : base(handle)
        {
            UnhandledException += Application_UnhandledException;
        }
    
        protected IndoorMapPage(UrhoObjectFlag emptyFlag) : base(emptyFlag)
        {
            UnhandledException += Application_UnhandledException;
        }
    
        private void Application_UnhandledException(object sender, Urho.UnhandledExceptionEventArgs e)
        {
            e.Handled = true;
        }
    
        protected override void Start()
        {
            base.Start();
            CreateScene();
            SetupViewport();
        }
    
        async void CreateScene()
        {
    
            _scene = new Scene();
            _octree = _scene.CreateComponent<Octree>();
    
            _plotNode = _scene.CreateChild();
            var baseNode = _plotNode.CreateChild().CreateChild();
            var plane = baseNode.CreateComponent<StaticModel>();
            plane.Model = CoreAssets.Models.Sphere;
    
            var cameraNode = _scene.CreateChild();
            _camera = cameraNode.CreateComponent<Camera>();
            cameraNode.Position = new Vector3(10, 15, 10) / 1.75f;
            cameraNode.Rotation = new Quaternion(-0.121f, 0.878f, -0.305f, -0.35f);
    
            Node lightNode = cameraNode.CreateChild();
            var light = lightNode.CreateComponent<Light>();
            light.LightType = LightType.Directional;
            light.Range = 50;
            light.Brightness = 1f;
            light.Color = Color.White;
            light.CastShadows = false;
            light.ShadowCascade = new CascadeParameters(10.0f, 50.00f, 200.0f, 0.0f,0.8f);
            lightNode.SetDirection(new Vector3(1f, -0.25f, 1.0f));
    
            int size = 3;
            baseNode.Scale = new Vector3(size * 1.5f, 1, size * 1.5f);
    
           var imageStream = await new HttpClient().GetStreamAsync("http://www.ferienwohnung-hoedingen.de/bilder/anfahrt01.png");
    
            var ms = new MemoryStream();
            imageStream.CopyTo(ms);
    
            var image = new Image();
            var isLoaded = image.Load(new MemoryBuffer(ms.ToArray()));
            if (!isLoaded)
            {
                throw new Exception("This image cannot be load");
            }
    
            Texture2D texture = new Texture2D();
            texture.SetNumLevels(1);
            texture.SetSize(image.Width, image.Height, Urho.Graphics.RGBAFormat, TextureUsage.Dynamic); //or Static
            texture.SetData(0, 0, 0, image.Width, image.Height, image.DataBytes);
            var isTextureLoaded = texture.Load(new MemoryBuffer(ms));
    
            if (!isTextureLoaded)
            {
                throw new Exception("This texture cannot be load");
            }
    
            var material = new Material();
            material.SetTexture(TextureUnit.Diffuse, texture);
            material.SetTechnique(0, CoreAssets.Techniques.Diff, 0, 0);
            material.CullMode = CullMode.Cw;
            plane.SetMaterial(material);
    
            try
            {
                await _plotNode.RunActionsAsync(new EaseBackOut(new RotateBy(2f, 0, 360, 0)));
            }
            catch (OperationCanceledException) { }
        }
    
    
        void SetupViewport()
        {
            var renderer = Renderer;
            var vp = new Viewport(Context, _scene, _camera, null);
            renderer.SetViewport(0, vp);
    
        }
    
        protected override void OnUpdate(float timeStep)
        {
            base.OnUpdate(timeStep);
        }
    
    }
    
  • ericawxwericawxw Member ✭✭
    edited September 2018

    Hi @seanyda, I have tried your code, however, the annotation doesn't show on the image when I am drawing. When I save the image, the image bitmap doesn't save and only save a black screen with the annotation. It does show the image on canvas, but when I am drawing, the red ink doesn't show on the image.

    This is the saved image: I tried undo and clear button on my app, and it works. But it doesn't save the annotation with image as well as the red ink doesn't show on my app when I am drawing

    I expected to save the image like this:

    This is my code:

    public Annotation(Stream stream)
            {
                InitializeComponent();
    
                using (SKImage image = SKImage.FromBitmap(SKBitmap.Decode(stream)))
                {
                    SKData data = image.Encode();
                    mediaFile = data.ToArray();
                    saveBitmap = SKBitmap.Decode(mediaFile);
                    canvasView.InvalidateSurface();
                }
            }
    
    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
            {
                SKImageInfo info = args.Info;
                SKSurface surface = args.Surface;
                SKCanvas canvas = surface.Canvas;
                SKCanvasView senderCanvas = (SKCanvasView)sender;
    
                if (!hasDrawnCanvas || senderCanvas.ClassId == "UndoPressed")
                {
                    if (saveBitmap != null)
                    {
                        canvas.Clear();
                        canvas.DrawBitmap(saveBitmap, info.Rect);
                    }
                    else
                    {
                        saveBitmap = SKBitmap.Decode(mediaFile);
                        canvas.DrawBitmap(saveBitmap, info.Rect);
                    }
                    canvasView.ClassId = null;
                    hasDrawnCanvas = true;
                }
            }
    
    void OnClearButtonClicked(object sender, EventArgs args)
            {
                if (completedPaths.Count > 0)
                {
                    for (var i = 0; i < completedPaths.Count; i++)
                    {
                        completedPaths.RemoveAt(i);
                    }
    
                    UpdateBitmap();
                    canvasView.InvalidateSurface();
                }
                else if (completedPaths.Count == 0)
                {
                    UpdateBitmap();
                    canvasView.InvalidateSurface();
                }
    
    
                if (inProgressPaths.Values.Count != 0)
                {
                    for (var i = 0; i < inProgressPaths.Keys.Count; i++)
                    {
                        inProgressPaths.Remove(i);
                    }
    
                    UpdateBitmap();
                    canvasView.InvalidateSurface();
                }
            }
    
    void OnUndoButtonClicked(object sender, EventArgs args)
            {
                undoClickCount = 1;
    
                if (completedPaths.Count > 0)
                {
                    completedPaths.RemoveAt(completedPaths.Count - undoClickCount);
                    UpdateBitmap();
                    canvasView.InvalidateSurface();
                } else if (completedPaths.Count == 0)
                {
                    UpdateBitmap();
                    canvasView.InvalidateSurface();
                } 
    
    
                if (inProgressPaths.Values.Count != 0)
                {
                    inProgressPaths.Remove(inProgressPaths.Keys.Count - undoClickCount);
                    UpdateBitmap();
                    canvasView.InvalidateSurface();
                }    
            }
    

    Any help would be appreciated!
    Hope to get from you soon.
    Thank you in advance.

  • seanydaseanyda GBMember ✭✭✭✭✭

    Where is your save method? What you display to the user on the OnCanvasViewPaintSurface is completely different to when you're saving your final canvas.

  • ericawxwericawxw Member ✭✭

    @seanyda said:
    Where is your save method? What you display to the user on the OnCanvasViewPaintSurface is completely different to when you're saving your final canvas.

    This is my save method.

    async void OnSaveButtonClicked(object sender, EventArgs args)
            {
                using (SKImage image = SKImage.FromBitmap(saveBitmap))
                {
                    SKData data = image.Encode();
                    DateTime dt = DateTime.Now;
                    string filename = string.Format("FingerPaint-{0:D4}{1:D2}{2:D2}-{3:D2}{4:D2}{5:D2}{6:D3}.png",
                                                    dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, dt.Millisecond);
    
                    IPhotoLibrary photoLibrary = DependencyService.Get<IPhotoLibrary>();
                    bool result = await photoLibrary.SavePhotoAsync(data.ToArray(), "FingerPaint", filename);
    
                    if (!result)
                    {
                        await DisplayAlert("FingerPaint", "Artwork could not be saved. Sorry!", "OK");
                    }
                    else
                    {
                        await DisplayAlert("FingerPaint", "Annotation saved!", "OK");
                    }
                }
            }
    
  • seanydaseanyda GBMember ✭✭✭✭✭

    @ericawxw said:

    @seanyda said:
    Where is your save method? What you display to the user on the OnCanvasViewPaintSurface is completely different to when you're saving your final canvas.

    This is my save method.

    async void OnSaveButtonClicked(object sender, EventArgs args)
            {
                using (SKImage image = SKImage.FromBitmap(saveBitmap))
                {
                    SKData data = image.Encode();
                    DateTime dt = DateTime.Now;
                    string filename = string.Format("FingerPaint-{0:D4}{1:D2}{2:D2}-{3:D2}{4:D2}{5:D2}{6:D3}.png",
                                                    dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, dt.Millisecond);
    
                    IPhotoLibrary photoLibrary = DependencyService.Get<IPhotoLibrary>();
                    bool result = await photoLibrary.SavePhotoAsync(data.ToArray(), "FingerPaint", filename);
    
                    if (!result)
                    {
                        await DisplayAlert("FingerPaint", "Artwork could not be saved. Sorry!", "OK");
                    }
                    else
                    {
                        await DisplayAlert("FingerPaint", "Annotation saved!", "OK");
                    }
                }
            }
    

    Thats your issue. You're not drawing the annotations on the Canvas.

    Here is a cut down version of my Save.

    async void OnSaveClicked(object sender, EventArgs e)
            {
                try
                {
                    DependencyService.Get<ISettingsManager>().HideHardwareButtons(false);
                    SKImageInfo info = new SKImageInfo(rotate90 ? (int)canvasView.CanvasSize.Height : (int)canvasView.CanvasSize.Width, rotate90 ? (int)canvasView.CanvasSize.Width : (int)canvasView.CanvasSize.Height, SKImageInfo.PlatformColorType, SKAlphaType.Premul);
                    var newSurface = SKSurface.Create(info);
                    var canvas = newSurface.Canvas;
    
                    canvas.DrawBitmap(savedBitmap, 0, 0);
    
                    foreach (var path in completedPolylines) canvas.DrawPath(path.Path, paint);
    
                    foreach (var path in inProgressPolylines.Values) canvas.DrawPath(path.Path, paint);
    
                    canvas.Flush();
    
                    var snap = newSurface.Snapshot();
                    var jpgImage = snap.Encode(SKEncodedImageFormat.Jpeg, 80);
    
                    // DISPOSE OF ALL OBJECTS HERE
                }
                catch(Exception ex) {
                    Crashes.TrackError(ex);
                }
            }
    
  • ericawxwericawxw Member ✭✭

    Thank you, @seanyda
    I will give it a try!

  • ericawxwericawxw Member ✭✭
    edited September 2018

    @seanyda said:

    @ericawxw said:

    @seanyda said:
    Where is your save method? What you display to the user on the OnCanvasViewPaintSurface is completely different to when you're saving your final canvas.

    This is my save method.

    async void OnSaveButtonClicked(object sender, EventArgs args)
            {
                using (SKImage image = SKImage.FromBitmap(saveBitmap))
                {
                    SKData data = image.Encode();
                    DateTime dt = DateTime.Now;
                    string filename = string.Format("FingerPaint-{0:D4}{1:D2}{2:D2}-{3:D2}{4:D2}{5:D2}{6:D3}.png",
                                                    dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, dt.Millisecond);
    
                    IPhotoLibrary photoLibrary = DependencyService.Get<IPhotoLibrary>();
                    bool result = await photoLibrary.SavePhotoAsync(data.ToArray(), "FingerPaint", filename);
    
                    if (!result)
                    {
                        await DisplayAlert("FingerPaint", "Artwork could not be saved. Sorry!", "OK");
                    }
                    else
                    {
                        await DisplayAlert("FingerPaint", "Annotation saved!", "OK");
                    }
                }
            }
    

    Thats your issue. You're not drawing the annotations on the Canvas.

    Here is a cut down version of my Save.

    async void OnSaveClicked(object sender, EventArgs e)
            {
              try
              {
                    DependencyService.Get<ISettingsManager>().HideHardwareButtons(false);
                    SKImageInfo info = new SKImageInfo(rotate90 ? (int)canvasView.CanvasSize.Height : (int)canvasView.CanvasSize.Width, rotate90 ? (int)canvasView.CanvasSize.Width : (int)canvasView.CanvasSize.Height, SKImageInfo.PlatformColorType, SKAlphaType.Premul);
                  var newSurface = SKSurface.Create(info);
                  var canvas = newSurface.Canvas;
    
                    canvas.DrawBitmap(savedBitmap, 0, 0);
    
                  foreach (var path in completedPolylines) canvas.DrawPath(path.Path, paint);
    
                  foreach (var path in inProgressPolylines.Values) canvas.DrawPath(path.Path, paint);
    
                  canvas.Flush();
    
                  var snap = newSurface.Snapshot();
                  var jpgImage = snap.Encode(SKEncodedImageFormat.Jpeg, 80);
    
                  // DISPOSE OF ALL OBJECTS HERE
              }
              catch(Exception ex) {
                  Crashes.TrackError(ex);
              }
            }
    

    Problem occurs ><
    the annotation doesn't show on the image when I am drawing. It does show the image on canvas, but when I am drawing, the red ink doesn't show on the image.

    The problem this time is the annotation doesn't show on the image while I am drawing, the save function works fine.

  • seanydaseanyda GBMember ✭✭✭✭✭

    @ericawxw said:

    @seanyda said:

    @ericawxw said:

    @seanyda said:
    Where is your save method? What you display to the user on the OnCanvasViewPaintSurface is completely different to when you're saving your final canvas.

    This is my save method.

    async void OnSaveButtonClicked(object sender, EventArgs args)
            {
                using (SKImage image = SKImage.FromBitmap(saveBitmap))
                {
                    SKData data = image.Encode();
                    DateTime dt = DateTime.Now;
                    string filename = string.Format("FingerPaint-{0:D4}{1:D2}{2:D2}-{3:D2}{4:D2}{5:D2}{6:D3}.png",
                                                    dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, dt.Millisecond);
    
                    IPhotoLibrary photoLibrary = DependencyService.Get<IPhotoLibrary>();
                    bool result = await photoLibrary.SavePhotoAsync(data.ToArray(), "FingerPaint", filename);
    
                    if (!result)
                    {
                        await DisplayAlert("FingerPaint", "Artwork could not be saved. Sorry!", "OK");
                    }
                    else
                    {
                        await DisplayAlert("FingerPaint", "Annotation saved!", "OK");
                    }
                }
            }
    

    Thats your issue. You're not drawing the annotations on the Canvas.

    Here is a cut down version of my Save.

    async void OnSaveClicked(object sender, EventArgs e)
            {
                try
                {
                    DependencyService.Get<ISettingsManager>().HideHardwareButtons(false);
                    SKImageInfo info = new SKImageInfo(rotate90 ? (int)canvasView.CanvasSize.Height : (int)canvasView.CanvasSize.Width, rotate90 ? (int)canvasView.CanvasSize.Width : (int)canvasView.CanvasSize.Height, SKImageInfo.PlatformColorType, SKAlphaType.Premul);
                    var newSurface = SKSurface.Create(info);
                    var canvas = newSurface.Canvas;
    
                    canvas.DrawBitmap(savedBitmap, 0, 0);
    
                    foreach (var path in completedPolylines) canvas.DrawPath(path.Path, paint);
    
                    foreach (var path in inProgressPolylines.Values) canvas.DrawPath(path.Path, paint);
    
                    canvas.Flush();
    
                    var snap = newSurface.Snapshot();
                    var jpgImage = snap.Encode(SKEncodedImageFormat.Jpeg, 80);
    
                    // DISPOSE OF ALL OBJECTS HERE
                }
                catch(Exception ex) {
                    Crashes.TrackError(ex);
                }
            }
    

    Problem occurs ><
    the annotation doesn't show on the image when I am drawing. It does show the image on canvas, but when I am drawing, the red ink doesn't show on the image.

    The problem this time is the annotation doesn't show on the image while I am drawing, the save function works fine.

    Does completedPolylines list have values? That will draw the annotations on for you.

  • ericawxwericawxw Member ✭✭
    edited September 2018

    @seanyda said:

    @ericawxw said:

    @seanyda said:

    @ericawxw said:

    @seanyda said:
    Where is your save method? What you display to the user on the OnCanvasViewPaintSurface is completely different to when you're saving your final canvas.

    This is my save method.

    async void OnSaveButtonClicked(object sender, EventArgs args)
            {
                using (SKImage image = SKImage.FromBitmap(saveBitmap))
                {
                    SKData data = image.Encode();
                    DateTime dt = DateTime.Now;
                    string filename = string.Format("FingerPaint-{0:D4}{1:D2}{2:D2}-{3:D2}{4:D2}{5:D2}{6:D3}.png",
                                                    dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, dt.Millisecond);
    
                    IPhotoLibrary photoLibrary = DependencyService.Get<IPhotoLibrary>();
                    bool result = await photoLibrary.SavePhotoAsync(data.ToArray(), "FingerPaint", filename);
    
                    if (!result)
                    {
                        await DisplayAlert("FingerPaint", "Artwork could not be saved. Sorry!", "OK");
                    }
                    else
                    {
                        await DisplayAlert("FingerPaint", "Annotation saved!", "OK");
                    }
                }
            }
    

    Thats your issue. You're not drawing the annotations on the Canvas.

    Here is a cut down version of my Save.

    async void OnSaveClicked(object sender, EventArgs e)
            {
              try
              {
                    DependencyService.Get<ISettingsManager>().HideHardwareButtons(false);
                    SKImageInfo info = new SKImageInfo(rotate90 ? (int)canvasView.CanvasSize.Height : (int)canvasView.CanvasSize.Width, rotate90 ? (int)canvasView.CanvasSize.Width : (int)canvasView.CanvasSize.Height, SKImageInfo.PlatformColorType, SKAlphaType.Premul);
                  var newSurface = SKSurface.Create(info);
                  var canvas = newSurface.Canvas;
    
                    canvas.DrawBitmap(savedBitmap, 0, 0);
    
                  foreach (var path in completedPolylines) canvas.DrawPath(path.Path, paint);
    
                  foreach (var path in inProgressPolylines.Values) canvas.DrawPath(path.Path, paint);
    
                  canvas.Flush();
    
                  var snap = newSurface.Snapshot();
                  var jpgImage = snap.Encode(SKEncodedImageFormat.Jpeg, 80);
    
                  // DISPOSE OF ALL OBJECTS HERE
              }
              catch(Exception ex) {
                  Crashes.TrackError(ex);
              }
            }
    

    Problem occurs ><
    the annotation doesn't show on the image when I am drawing. It does show the image on canvas, but when I am drawing, the red ink doesn't show on the image.

    The problem this time is the annotation doesn't show on the image while I am drawing, the save function works fine.

    Does completedPolylines list have values? That will draw the annotations on for you.

    Yes, I debugged it and the completedPolylines does contain values. Do you have any ideas why is this happened? Thank you.

  • sunshinesunshine Member ✭✭

    @ericawxw Hi, I just came across this thread as I am performing the same operation in my app.

    The undo works fine when I don't have image on canvas but when I have image on canvas and draw on it and undo the operation, it doesn't do anything. It remove the value from list, but path drawn on image isn't removed. May I know how u achieved this? It will be very helpful, if you can guide on this. Thanks

Sign In or Register to comment.