Reputation: 31
I am doing a project wherein I can change the filter of the image. I am using skiasharp to change the filter of the image. It is like that of CamScanner Application. But when I change the filter to grayscale first and then Lighten and then Sepia and then again back to grayscale I hit save I get Sepia's Image. I understand that the last data being generated is that of sepia's hence it is saving that data. But if I want to change more than 3 times it is not working. Please help me out. Here is my coding.
<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>
and here is my XAML.CS file for that -
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;
}
and this is my save command.
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
Upvotes: 1
Views: 2022
Reputation: 2299
I hope I got it right, you are using several SKCanvasViews and depending on what "mode" the user chooses in your app, you activate the corresponding surface?
I wouldn't recommend that. Even though it ~kinda~ works, it might become confusing very fast.
My approach to your problem would be to rewrite the view in the following way:
Create an enum containing the names of your filters and another entry for "none", e.g.
public enum Filters
{
None = 0,
Grayscale = 1,
Lighten = 2,
Sepia = 4
}
Then create a property of the type of this enum in your page.
Filters currentFilter = Filters.None;
Now instead of copying your render code 4 times, you could change the main PaintSurface method to something like:
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;
}
So when tapping your SetFilterButton all you need to do is setting the customFilter Property of your page to the corresponding filter and calling
canvasView.InvalidateSurface();
so the surface will be redrawn and then saving the image.
Upvotes: 2