如何在 skiasharp xamarin 表单中调用 PaintSurface 两次

How to call PaintSurface twice in skiasharp xamarin forms

我正在做一个项目,我可以在其中更改图像的滤镜。我正在使用 skiasharp 来更改图像的过滤器。它类似于 CamScanner 应用程序。但是,当我先将滤镜更改为灰度,然后变亮,然后是棕褐色,然后再次变回灰度时,我点击保存,我得到了棕褐色的图像。我知道最后生成的数据是棕褐色的,因此它正在保存该数据。但如果我想更改超过 3 次,它就不起作用了。请帮帮我。这是我的代码。

  <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
                 BackgroundColor="Black"
                 x:Class="JC.EditPage">
        <ContentPage.Content>

            <StackLayout Padding="10,10,10,10" Orientation="Vertical">


                <Image x:Name="imageView" HeightRequest="450"
                       HorizontalOptions="FillAndExpand"
                       VerticalOptions="CenterAndExpand" IsVisible="True"/>

                <StackLayout x:Name="canvasStackView" IsVisible="False">
                    <skia:SKCanvasView HeightRequest="450" PaintSurface="OnCanvasViewPaintSurface" VerticalOptions="CenterAndExpand" HorizontalOptions="FillAndExpand"/>
                </StackLayout>

                <StackLayout x:Name="canvasLightenStackView" IsVisible="False">
                    <skia:SKCanvasView HeightRequest="450" PaintSurface="OnCanvasViewPaintSurfaceLighten" VerticalOptions="CenterAndExpand" HorizontalOptions="FillAndExpand"/>
                </StackLayout>

                <StackLayout x:Name="canvasSepiaStackView" IsVisible="False">
                    <skia:SKCanvasView HeightRequest="450" PaintSurface="OnCanvasViewPaintSurfaceSepia" VerticalOptions="CenterAndExpand" HorizontalOptions="FillAndExpand"/>
                </StackLayout>

      <ScrollView Orientation="Horizontal" HorizontalScrollBarVisibility="Never">
                    <StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand" VerticalOptions="EndAndExpand" x:Name="filterStack" IsVisible="True">
                        <StackLayout WidthRequest="100" HeightRequest="70" BackgroundColor="White">
                            <Label Text="Original" FontFamily="Bold" Font="14" TextColor="Black" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"/>
                            <StackLayout.GestureRecognizers>
                                <TapGestureRecognizer Tapped="Original_Tapped">
                                </TapGestureRecognizer>
                            </StackLayout.GestureRecognizers>
                        </StackLayout>

                        <StackLayout WidthRequest="100" HeightRequest="70" BackgroundColor="White" >
                            <Label Text="Grayscale" FontFamily="Bold" Font="14" TextColor="Black" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"/>
                            <StackLayout.GestureRecognizers>
                                <TapGestureRecognizer Tapped="Grayscale_Tapped">
                                </TapGestureRecognizer>
                            </StackLayout.GestureRecognizers>
                        </StackLayout>

                        <StackLayout WidthRequest="100" HeightRequest="70" BackgroundColor="White">
                            <Label Text="Lighten" FontFamily="Bold" Font="14" TextColor="Black" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"/>
                            <StackLayout.GestureRecognizers>
                                <TapGestureRecognizer Tapped="Lighten_Tapped">
                                </TapGestureRecognizer>
                            </StackLayout.GestureRecognizers>
                        </StackLayout>

                        <StackLayout WidthRequest="100" HeightRequest="70" BackgroundColor="White" >
                            <Label Text="Sepia" FontFamily="Bold" Font="14" TextColor="Black" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"/>
                            <StackLayout.GestureRecognizers>
                                <TapGestureRecognizer Tapped="Speia_Tapped">
                                </TapGestureRecognizer>
                            </StackLayout.GestureRecognizers>
                        </StackLayout>
                    </StackLayout>
                </ScrollView>

                <StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand" VerticalOptions="EndAndExpand" BackgroundColor="White">
                    <Image Source="goback.png" HorizontalOptions="StartAndExpand">
                        <Image.GestureRecognizers>
                            <TapGestureRecognizer Tapped="goback_Tapped"/>
                        </Image.GestureRecognizers>
                    </Image>

                    <Image Source="tick.png" HorizontalOptions="EndAndExpand">
                        <Image.GestureRecognizers>
                            <TapGestureRecognizer Tapped="Save_Tapped"/>
                        </Image.GestureRecognizers>
                    </Image>
                </StackLayout>
            </StackLayout>
        </ContentPage.Content>
    </ContentPage>

这是我的 XAML.CS 文件 -

  private async void Grayscale_Tapped(object sender, EventArgs e)
    {
        DependencyService.Get<IProgressInterface>().ShowLoader("Please wait...");



        adjust = false;
        canvasEditStackView.IsVisible = false;
        canvasSepiaStackView.IsVisible = false;
        canvasLightenStackView.IsVisible = false;
        imageView.IsVisible = false;
        canvasStackView.IsVisible = true;
        filterStack.IsVisible = true;
        original = false;

        byte[] tempArray = await StorageHelper.LoadImage(image, path);

       canvasView = new SKCanvasView();
       canvasView.PaintSurface += OnCanvasViewPaintSurface;

        using (Stream stream = new MemoryStream(tempArray))
        {
            if (stream != null)
            {
                libraryBitmap = SKBitmap.Decode(stream);
                canvasView.InvalidateSurface();
            }
        }
        DependencyService.Get<IProgressInterface>().DismissLoader();
    }

    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        Console.WriteLine("Hits");
        DependencyService.Get<IProgressInterface>().ShowLoader("Please wait...");

        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();

        using (SKPaint paint = new SKPaint())
        {

            paint.ColorFilter =
                SKColorFilter.CreateColorMatrix(new float[]
                {
                0.21f, 0.72f, 0.07f, 0, 0,
                0.21f, 0.72f, 0.07f, 0, 0,
                0.21f, 0.72f, 0.07f, 0, 0,
                0,     0,     0,     1, 0
                });

            canvas.DrawBitmap(libraryBitmap, info.Rect, BitmapStretch.Uniform, paint: paint);
            DependencyService.Get<IProgressInterface>().DismissLoader();
        }
        var snap = surface.Snapshot();
        SKData data = snap.Encode();
        saveData = data;

    }

    private async void Lighten_Tapped(object sender, EventArgs e)
    {
        DependencyService.Get<IProgressInterface>().ShowLoader("Please wait...");


        adjust = false;
        imageView.IsVisible = false;
        canvasEditStackView.IsVisible = false;
        canvasStackView.IsVisible = false;
        canvasSepiaStackView.IsVisible = false;
        canvasLightenStackView.IsVisible = true;
        filterStack.IsVisible = true;
        original = false;

        byte[] tempArray = await StorageHelper.LoadImage(image, path);

        canvasView = new SKCanvasView();
        canvasView.PaintSurface += OnCanvasViewPaintSurfaceLighten;

        using (Stream stream = new MemoryStream(tempArray))
        {
            if (stream != null)
            {
                libraryBitmap = SKBitmap.Decode(stream);
                canvasView.InvalidateSurface();
            }
        }
        DependencyService.Get<IProgressInterface>().DismissLoader();

    }

    void OnCanvasViewPaintSurfaceLighten(object sender, SKPaintSurfaceEventArgs args)
    {
        DependencyService.Get<IProgressInterface>().ShowLoader("Please wait...");
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();

        using (SKPaint paint = new SKPaint())
        {
            paint.ColorFilter =
                SKColorFilter.CreateColorMatrix(new float[]
                {
                0.75f, 0.25f, 0.25f, 0, 0,
                0.25f, 0.75f, 0.25f, 0, 0,
                0.25f, 0.25f, 0.75f, 0, 0,
                0, 0, 0, 1, 0
                });
            canvas.DrawBitmap(libraryBitmap, info.Rect, BitmapStretch.Uniform, paint: paint);
            DependencyService.Get<IProgressInterface>().DismissLoader();
        }
        var snap = surface.Snapshot();
        SKData data = snap.Encode();
        saveData = data;

    }

    public async void Speia_Tapped(object sender, EventArgs e)
    {

        DependencyService.Get<IProgressInterface>().ShowLoader("Please wait...");



        adjust = false;
        imageView.IsVisible = false;
        canvasEditStackView.IsVisible = false;
        canvasStackView.IsVisible = false;
        canvasLightenStackView.IsVisible = false;
        canvasSepiaStackView.IsVisible = true;
        filterStack.IsVisible = true;
        original = false;

        byte[] tempArray = await StorageHelper.LoadImage(image, path);

        canvasView = new SKCanvasView();
        canvasView.PaintSurface += OnCanvasViewPaintSurfaceSepia;

        using (Stream stream = new MemoryStream(tempArray))
        {
            if (stream != null)
            {
                libraryBitmap = SKBitmap.Decode(stream);
                canvasView.InvalidateSurface();

            }
        }
        DependencyService.Get<IProgressInterface>().DismissLoader();
    }

    void OnCanvasViewPaintSurfaceSepia(object sender, SKPaintSurfaceEventArgs args)
    {
        DependencyService.Get<IProgressInterface>().ShowLoader("Please wait...");
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();
        using (SKPaint paint = new SKPaint())
        {
            paint.ColorFilter =
                SKColorFilter.CreateColorMatrix(new float[]
                {
                  1, 0,   0, 0, 0,
                  0, 1,   0, 0, 0,
                  0, 0, 0.8f, 0, 0,
                  0, 0,   0, 1, 0
                });
            canvas.DrawBitmap(libraryBitmap, info.Rect, BitmapStretch.Uniform, paint: paint);
            DependencyService.Get<IProgressInterface>().DismissLoader();
        }
        var snap = surface.Snapshot();
        SKData data = snap.Encode();
        saveData = data;
    }

这是我的保存命令。

 if (original == true)
            {
                var editPref = DependencyService.Get<IUserPreferences>();
                editPref.SaveString("edit", "false");

                await Navigation.PushModalAsync(new desiredLocationStoragePage(path));
            }
            else
            {
                var editPref = DependencyService.Get<IUserPreferences>();
                editPref.SaveString("edit", "true");
                string saveName = fileName;
                using (var stream = File.OpenWrite(saveName))
                {
                    saveData.SaveTo(stream);
                }
                await Navigation.PushModalAsync(new desiredLocationStoragePage(fileName));

            }



   please help me out guys I am quite stuck after this phase

我希望我没弄错,您正在使用多个 SKCanvasView,并且根据 "mode" 用户在您的应用中选择的内容,您激活了相应的表面?

我不推荐这样做。尽管它 ~kinda~ 有效,但它可能很快就会变得混乱。

我解决你的问题的方法是按以下方式重写视图:

创建一个包含过滤器名称的枚举和 "none" 的另一个条目,例如

public enum Filters
{
    None = 0,
    Grayscale = 1,
    Lighten = 2,
    Sepia = 4
} 

然后在您的页面中创建此枚举类型的 属性。

Filters currentFilter = Filters.None;

现在,您可以将主要的 PaintSurface 方法更改为如下内容,而不是将渲染代码复制 4 次:

void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
    Console.WriteLine("Hits");
    DependencyService.Get<IProgressInterface>().ShowLoader("Please wait...");

    SKImageInfo info = args.Info;
    SKSurface surface = args.Surface;
    SKCanvas canvas = surface.Canvas;

    canvas.Clear();



    using (SKPaint paint = new SKPaint())
    {
        // check if currentFilter is set to Filters.None
        if( (currentFilter & Filters.None) == Filters.None )
        {
            paint.ColorFilter =
                SKColorFilter.CreateColorMatrix(new float[]
                {
                    0.21f, 0.72f, 0.07f, 0, 0,
                    0.21f, 0.72f, 0.07f, 0, 0,
                    0.21f, 0.72f, 0.07f, 0, 0,
                    0,     0,     0,     1, 0
                });
        }
        // check if currentFilter is set to Filters.Lighten
        else if ( (currentFilter & Filters.Lighten) == Filters.Lighten)
        {
            paint.ColorFilter =
                SKColorFilter.CreateColorMatrix(new float[]
                {
                    0.75f, 0.25f, 0.25f, 0, 0,
                    0.25f, 0.75f, 0.25f, 0, 0,
                    0.25f, 0.25f, 0.75f, 0, 0,
                    0, 0, 0, 1, 0
            });
        }

        /*
            ... proceed with other filters accordingly ....
        */

        canvas.DrawBitmap(libraryBitmap, info.Rect, BitmapStretch.Uniform, paint: paint);
        DependencyService.Get<IProgressInterface>().DismissLoader();
    }
    var snap = surface.Snapshot();
    SKData data = snap.Encode();
    saveData = data;

}

因此,当点击您的 SetFilterButton 时,您需要做的就是将页面的 customFilter 属性 设置为相应的过滤器并调用

canvasView.InvalidateSurface();

因此表面将被重绘然后保存图像。