SkiaSharp绘制位图裁剪行为

huangapple go评论73阅读模式
英文:

SkiaSharp Draw Bitmap cutting behavior

问题

以下是您要翻译的部分:

"A new understanding issue arises while Experimenting with the Canvas.DrawBitmap function. I set up the Rectangle of the Source Part and of the destination via SkRect.Create(). The Problem starts here. I have set the destination Rectangle to be as large as the destination bitmap, which is larger than the source Rectangle. I have gradually enlarged the Space the sourceRectangle takes from 500 by 500 up to 1500 by 1500 with origin coordinates staying at 400 200. The Problem is, the part of the Image that gets shown after the Canvas.DrawBitmap stayed the same always. However, when I make the destination Rectangle as large and with the same coordinates as the source Rectangle i get the Part of the Image i expected to get. What is the Problem here? Do have the destination and source Rectangle have to have the same coordinates and size or is this some kind of caching issue that the displayed part always stays the same, when the destination Rect is of the same Size as the destination Bitmap?"

The Cropping logic:

[RelayCommand]
public async void UploadImage()
{
//Well i pick a photo for convenience
FileResult im = await MediaPicker.Default.PickPhotoAsync();

SKBitmap sourceMap;
using (Stream s = await im.OpenReadAsync())
{
    using (MemoryStream ms = new MemoryStream())
    {
        await s.CopyToAsync(ms);
        ms.Seek(0, SeekOrigin.Begin);
        sourceMap = SKBitmap.Decode(ms);
    }
}

SKBitmap destination = new SKBitmap(1080, 1080);
var height = sourceMap.Height; //1332
var width = sourceMap.Width; //2000
SKRect maxRect = new SKRect(0,0,width,height);
SKRect sourceRect = SKRect.Create(400, 200, 1500, 1500);
SKRect destRect = SKRect.Create(0, 0, 1080, 1080);
using (SKCanvas canvas = new SKCanvas(destination))
{
    canvas.Clear();
    canvas.DrawBitmap(sourceMap, sourceRect, destRect);
}

SKImage skImage = SKImage.FromBitmap(destination);
SKData encoded = skImage.Encode();
using (MemoryStream memory = new MemoryStream())
{
    encoded.AsStream().CopyTo(memory);
    Image = memory.ToArray();
}

}

The associated View:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
xmlns:ImageCroppingTry2="clr-namespace:ImageCroppingTry2"
x:DataType="ImageCroppingTry2:MainPageViewModel"
x:Class="ImageCroppingTry2.MainPage">

<ContentPage.Resources>
<ResourceDictionary>
<toolkit:ByteArrayToImageSourceConverter x:Key="ByteArrayToImageSourceConverter" />
</ResourceDictionary>
</ContentPage.Resources>

<VerticalStackLayout>
<Image x:Name="displayImage" Source="{Binding Image, Converter={StaticResource ByteArrayToImageSourceConverter}}" />
<Button Command="{Binding UploadImageCommand}"></Button>
</VerticalStackLayout>

</ContentPage>

英文:

A new understanding issue arises while Experimenting with the Canvas.DrawBitmap function. I set up the Rectangle of the Source Part and of the destination via SkRect.Create(). The Problem starts here. I have set the destination Rectangle to be as large as the destination bitmap, which is larger than the source Rectangle. I have gradually enlarged the Space the sourceRectangle takes from 500 by 500 up to 1500 by 1500 with origin coordinates staying at 400 200. The Problem is, the part of the Image that gets shown after the Canvas.DrawBitmap stayed the same always. However, when I make the destination Rectangle as large and with the same coordinates as the source Rectangle i get the Part of the Image i expected to get. What is the Problem here? Do have the destination and source Rectangle have to have the same coordinates and size or is this some kind of caching issue that the displayed part always stays the same, when the destination Rect is of the same Size as the destination Bitmap?

The Cropping logic:

[RelayCommand]
    public async void UploadImage()
    {
        //Well i pick a photo for convenience 
        FileResult im = await MediaPicker.Default.PickPhotoAsync();
    
        SKBitmap sourceMap;
        using (Stream s = await im.OpenReadAsync())
        {
            using (MemoryStream ms = new MemoryStream())
            {
                await s.CopyToAsync(ms);
                ms.Seek(0, SeekOrigin.Begin);
                sourceMap = SKBitmap.Decode(ms);
            }
        }
    
        SKBitmap destination = new SKBitmap(1080, 1080);
        var height = sourceMap.Height; //1332
        var width = sourceMap.Width; //2000
        SKRect maxRect = new SKRect(0,0,width,height);
        SKRect sourceRect = SKRect.Create(400, 200, 1500, 1500);
        SKRect destRect = SKRect.Create(0, 0, 1080, 1080);
        using (SKCanvas canvas = new SKCanvas(destination))
        {
            canvas.Clear();
            canvas.DrawBitmap(sourceMap, sourceRect, destRect);
        }
    
        SKImage skImage = SKImage.FromBitmap(destination);
        SKData encoded = skImage.Encode();
        using (MemoryStream memory = new MemoryStream())
        {
            encoded.AsStream().CopyTo(memory);
            Image = memory.ToArray();
        }
    }

The associated View:

&lt;ContentPage xmlns=&quot;http://schemas.microsoft.com/dotnet/2021/maui&quot;
         xmlns:x=&quot;http://schemas.microsoft.com/winfx/2009/xaml&quot;
         xmlns:toolkit=&quot;http://schemas.microsoft.com/dotnet/2022/maui/toolkit&quot;
         xmlns:ImageCroppingTry2=&quot;clr-namespace:ImageCroppingTry2&quot;
         x:DataType=&quot;ImageCroppingTry2:MainPageViewModel&quot;
         x:Class=&quot;ImageCroppingTry2.MainPage&quot;&gt;

&lt;ContentPage.Resources&gt;
    &lt;ResourceDictionary&gt;
        &lt;toolkit:ByteArrayToImageSourceConverter x:Key=&quot;ByteArrayToImageSourceConverter&quot; /&gt;
    &lt;/ResourceDictionary&gt;
&lt;/ContentPage.Resources&gt;

&lt;VerticalStackLayout&gt;
    &lt;Image x:Name=&quot;displayImage&quot; Source=&quot;{Binding Image, Converter={StaticResource ByteArrayToImageSourceConverter}}&quot; /&gt;
    &lt;Button Command=&quot;{Binding UploadImageCommand}&quot;&gt;&lt;/Button&gt;
&lt;/VerticalStackLayout&gt;

</ContentPage>

答案1

得分: 2

我在官方演示中使用了MountainClimbers.jpg创建了一个小演示:Xamarin.Forms - SkiaSharp and Xamarin.Forms

这是我的XAML文件,在VerticalStackLayout中,我放置了一个CanvasView用于原始位图,还有一个Image控件绑定到裁剪后的图像。按钮将触发命令。

<ContentPage.Resources>
    <ResourceDictionary>
        <toolkit:ByteArrayToImageSourceConverter x:Key="ByteArrayToImageSourceConverter" />
    </ResourceDictionary>
</ContentPage.Resources>

<VerticalStackLayout>
    <skia:SKCanvasView x:Name="mycanvas" PaintSurface="SKCanvasView_PaintSurface"   />
    <Button Text="点击我进行裁剪" Clicked="myButton_Clicked"></Button>
    <Image x:Name="displayImage" BackgroundColor="Pink" Source="{Binding Image, Converter={StaticResource ByteArrayToImageSourceConverter}}" />           
</VerticalStackLayout>

对于.cs文件,将BindingContext设置为自身。我们知道这张图片的大小是360 x 480。我想在图像的中央裁剪出120 x 160的部分。

public partial class NewPage1 : ContentPage
{
public byte[] image;
public byte[] Image
{

    get
    {
        return image;
    }
    set
    {
        image = value;
        OnPropertyChanged(nameof(Image));
    }
}

SKBitmap croppedBitmap;
SKBitmap originalBitmap;

public NewPage1()
{
	InitializeComponent();
    originalBitmap = BitmapExtensions.LoadBitmapResource(GetType(),"SkiaSharpDrawBitmap75620262.Media.MountainClimbers.jpg");
	this.BindingContext = this;
    mycanvas.HeightRequest = originalBitmap.Height;
}

void SKCanvasView_PaintSurface(System.Object sender, SkiaSharp.Views.Maui.SKPaintSurfaceEventArgs e)
{

    SKImageInfo info = e.Info;
    SKSurface surface = e.Surface;
    SKCanvas canvas = surface.Canvas;
    
    canvas.DrawBitmap(originalBitmap, info.Rect, BitmapStretch.Uniform);
    
}

void myButton_Clicked(System.Object sender, System.EventArgs e)
{
    croppedBitmap = new SKBitmap(120, 160);
    SKRect dest = new SKRect(0, 0,120, 160);
    SKRect source = SKRect.Create(120, 160, 120 , 160);

    using (SKCanvas canvas = new SKCanvas(croppedBitmap))
    {
        canvas.Clear();
        canvas.DrawBitmap(originalBitmap,
                          source,dest);  // destination
    }

    SKImage skImage = SKImage.FromBitmap(croppedBitmap);
    SKData encoded = skImage.Encode();
    using (MemoryStream memory = new MemoryStream())
    {
        encoded.AsStream().CopyTo(memory);       
        Image = memory.ToArray();
        displayImage.HeightRequest = croppedBitmap.Height;
    }
}

}

我认为结果符合预期:

SkiaSharp绘制位图裁剪行为

希望我的回答有意义。

英文:

I made a small demo using MountainClimbers.jpg in official demo: Xamarin.Forms - SkiaSharp and Xamarin.Forms.

This is my xaml file, in VerticalStackLayout, I put a canvasview for origin bitmap and also a Image control binds to crop image. The button will trigger the command.

&lt;ContentPage.Resources&gt;
    &lt;ResourceDictionary&gt;
        &lt;toolkit:ByteArrayToImageSourceConverter x:Key=&quot;ByteArrayToImageSourceConverter&quot; /&gt;
    &lt;/ResourceDictionary&gt;
&lt;/ContentPage.Resources&gt;

&lt;VerticalStackLayout&gt;
    &lt;skia:SKCanvasView x:Name=&quot;mycanvas&quot; PaintSurface=&quot;SKCanvasView_PaintSurface&quot;   /&gt;
    &lt;Button Text=&quot;click me to crop&quot; Clicked=&quot;myButton_Clicked&quot;&gt;&lt;/Button&gt;
    &lt;Image x:Name=&quot;displayImage&quot; BackgroundColor=&quot;Pink&quot; Source=&quot;{Binding Image, Converter={StaticResource ByteArrayToImageSourceConverter}}&quot; /&gt;           
&lt;/VerticalStackLayout&gt;

For .cs file, set BindingContext to itself. We know this image is 360 X 480. And I want to crop the 120 X 160 at the central of the image.

public partial class NewPage1 : ContentPage
{
public byte[] image;
public byte[] Image
{

    get
    {
        return image;
    }
    set
    {
        image = value;
        OnPropertyChanged(nameof(Image));
    }
}

SKBitmap croppedBitmap;
SKBitmap originalBitmap;

public NewPage1()
{
	InitializeComponent();
    originalBitmap = BitmapExtensions.LoadBitmapResource(GetType(),&quot;SkiaSharpDrawBitmap75620262.Media.MountainClimbers.jpg&quot;);
	this.BindingContext = this;
    mycanvas.HeightRequest = originalBitmap.Height;
}

void SKCanvasView_PaintSurface(System.Object sender, SkiaSharp.Views.Maui.SKPaintSurfaceEventArgs e)
{

    SKImageInfo info = e.Info;
    SKSurface surface = e.Surface;
    SKCanvas canvas = surface.Canvas;
    
    canvas.DrawBitmap(originalBitmap, info.Rect, BitmapStretch.Uniform);
    
}

void myButton_Clicked(System.Object sender, System.EventArgs e)
{
    croppedBitmap = new SKBitmap(120, 160);
    SKRect dest = new SKRect(0, 0,120, 160);
    SKRect source = SKRect.Create(120, 160, 120 , 160);

    using (SKCanvas canvas = new SKCanvas(croppedBitmap))
    {
        canvas.Clear();
        canvas.DrawBitmap(originalBitmap,
                          source,dest);  // destination
    }

    SKImage skImage = SKImage.FromBitmap(croppedBitmap);
    SKData encoded = skImage.Encode();
    using (MemoryStream memory = new MemoryStream())
    {
        encoded.AsStream().CopyTo(memory);       
        Image = memory.ToArray();
        displayImage.HeightRequest = croppedBitmap.Height;
    }
}

}

And the result I think it works as expected:

SkiaSharp绘制位图裁剪行为

Hope my answer makes sense.

huangapple
  • 本文由 发表于 2023年3月9日 17:03:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/75682406.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定