英文:
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:
<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>
答案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;
}
}
}
我认为结果符合预期:
希望我的回答有意义。
英文:
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.
<ContentPage.Resources>
<ResourceDictionary>
<toolkit:ByteArrayToImageSourceConverter x:Key="ByteArrayToImageSourceConverter" />
</ResourceDictionary>
</ContentPage.Resources>
<VerticalStackLayout>
<skia:SKCanvasView x:Name="mycanvas" PaintSurface="SKCanvasView_PaintSurface" />
<Button Text="click me to crop" Clicked="myButton_Clicked"></Button>
<Image x:Name="displayImage" BackgroundColor="Pink" Source="{Binding Image, Converter={StaticResource ByteArrayToImageSourceConverter}}" />
</VerticalStackLayout>
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(),"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;
}
}
}
And the result I think it works as expected:
Hope my answer makes sense.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论