When decoding from SKData, it is not immediate. Rather, the data is passed to
a lazy image that is decoded when the pixels are actually needed. Thus,
passing fixed the byte[] array will result in invalid images if the array
is moved in memory or changed later on. So, we create a copy.

The other cases where the codec was use to construct a bitmap first are also
wrong. SKBitmap constructs differently to SKImage, and since SKImage is just
going to create a copy anyway, just copy the encoded data once, and pass the
data to SKImage. This way, we are all in with SKImage, and we get the expected
results.
This commit is contained in:
Matthew Leibowitz 2019-12-10 19:42:48 +02:00 коммит произвёл GitHub
Родитель 91e071bf16
Коммит ae5c43ef3b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
3 изменённых файлов: 188 добавлений и 44 удалений

Просмотреть файл

@ -188,10 +188,8 @@ namespace SkiaSharp
if (data.Length == 0)
throw new ArgumentException ("The data buffer was empty.");
fixed (byte* b = data) {
using (var skdata = SKData.Create ((IntPtr)b, data.Length)) {
return FromEncodedData (skdata);
}
using (var skdata = SKData.CreateCopy (data)) {
return FromEncodedData (skdata);
}
}
@ -202,10 +200,8 @@ namespace SkiaSharp
if (data.Length == 0)
throw new ArgumentException ("The data buffer was empty.");
fixed (byte* b = data) {
using (var skdata = SKData.Create ((IntPtr)b, data.Length)) {
return FromEncodedData (skdata);
}
using (var skdata = SKData.CreateCopy (data)) {
return FromEncodedData (skdata);
}
}
@ -214,19 +210,10 @@ namespace SkiaSharp
if (data == null)
throw new ArgumentNullException (nameof (data));
using (var codec = SKCodec.Create (data)) {
if (codec == null)
using (var skdata = SKData.Create (data)) {
if (skdata == null)
return null;
var bitmap = SKBitmap.Decode (codec, codec.Info);
if (bitmap == null)
return null;
bitmap.SetImmutable ();
return FromPixels (bitmap.PeekPixels (), delegate {
bitmap.Dispose ();
bitmap = null;
});
return FromEncodedData (skdata);
}
}
@ -235,19 +222,10 @@ namespace SkiaSharp
if (data == null)
throw new ArgumentNullException (nameof (data));
using (var codec = SKCodec.Create (data)) {
if (codec == null)
using (var skdata = SKData.Create (data)) {
if (skdata == null)
return null;
var bitmap = SKBitmap.Decode (codec, codec.Info);
if (bitmap == null)
return null;
bitmap.SetImmutable ();
return FromPixels (bitmap.PeekPixels (), delegate {
bitmap.Dispose ();
bitmap = null;
});
return FromEncodedData (skdata);
}
}
@ -256,19 +234,10 @@ namespace SkiaSharp
if (filename == null)
throw new ArgumentNullException (nameof (filename));
using (var codec = SKCodec.Create (filename)) {
if (codec == null)
using (var skdata = SKData.Create (filename)) {
if (skdata == null)
return null;
var bitmap = SKBitmap.Decode (codec, codec.Info);
if (bitmap == null)
return null;
bitmap.SetImmutable ();
return FromPixels (bitmap.PeekPixels (), delegate {
bitmap.Dispose ();
bitmap = null;
});
return FromEncodedData (skdata);
}
}

Двоичные данные
tests/Content/images/vimeo_icon_dark.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.7 KiB

Просмотреть файл

@ -525,6 +525,181 @@ namespace SkiaSharp.Tests
}
}
[Trait(CategoryKey, GpuCategory)]
[SkippableFact]
public void DecodingWithDataAndDrawingOnGPUCreatesCorrectImage()
{
var info = new SKImageInfo(120, 120);
var path = Path.Combine(PathToImages, "vimeo_icon_dark.png");
using (var ctx = CreateGlContext())
{
ctx.MakeCurrent();
using (var grContext = GRContext.CreateGl())
using (var surface = SKSurface.Create(grContext, true, info))
{
var canvas = surface.Canvas;
canvas.Clear(SKColors.Crimson);
using (var data = SKData.Create(path))
using (var image = SKImage.FromEncodedData(data))
{
canvas.DrawImage(image, 0, 0);
}
using (var bmp = new SKBitmap(info))
{
surface.ReadPixels(info, bmp.GetPixels(), info.RowBytes, 0, 0);
Assert.Equal(SKColors.Crimson, bmp.GetPixel(3, 3));
Assert.Equal(SKColors.Crimson, bmp.GetPixel(70, 50));
Assert.Equal(new SKColor(23, 35, 34), bmp.GetPixel(40, 40));
}
}
}
}
[Trait(CategoryKey, GpuCategory)]
[SkippableFact]
public void DecodingWithBitmapAndDrawingOnGPUCreatesCorrectImage()
{
var info = new SKImageInfo(120, 120);
var path = Path.Combine(PathToImages, "vimeo_icon_dark.png");
using (var ctx = CreateGlContext())
{
ctx.MakeCurrent();
using (var grContext = GRContext.CreateGl())
using (var surface = SKSurface.Create(grContext, true, info))
{
var canvas = surface.Canvas;
canvas.Clear(SKColors.Crimson);
using (var bitmap = SKBitmap.Decode(path))
using (var image = SKImage.FromBitmap(bitmap))
{
canvas.DrawImage(image, 0, 0);
}
using (var bmp = new SKBitmap(info))
{
surface.ReadPixels(info, bmp.GetPixels(), info.RowBytes, 0, 0);
Assert.Equal(SKColors.Crimson, bmp.GetPixel(3, 3));
Assert.Equal(SKColors.Crimson, bmp.GetPixel(70, 50));
Assert.Equal(new SKColor(23, 35, 34), bmp.GetPixel(40, 40));
}
}
}
}
[Trait(CategoryKey, GpuCategory)]
[SkippableFact]
public void DecodingWithPathAndDrawingOnGPUCreatesCorrectImage()
{
var info = new SKImageInfo(120, 120);
var path = Path.Combine(PathToImages, "vimeo_icon_dark.png");
using (var ctx = CreateGlContext())
{
ctx.MakeCurrent();
using (var grContext = GRContext.CreateGl())
using (var surface = SKSurface.Create(grContext, true, info))
{
var canvas = surface.Canvas;
canvas.Clear(SKColors.Crimson);
using (var image = SKImage.FromEncodedData(path))
{
canvas.DrawImage(image, 0, 0);
}
using (var bmp = new SKBitmap(info))
{
surface.ReadPixels(info, bmp.GetPixels(), info.RowBytes, 0, 0);
Assert.Equal(SKColors.Crimson, bmp.GetPixel(3, 3));
Assert.Equal(SKColors.Crimson, bmp.GetPixel(70, 50));
Assert.Equal(new SKColor(23, 35, 34), bmp.GetPixel(40, 40));
}
}
}
}
[SkippableFact]
public void DecodingWithDataCreatesCorrectImage()
{
var info = new SKImageInfo(120, 120);
var path = Path.Combine(PathToImages, "vimeo_icon_dark.png");
using (var bmp = new SKBitmap(info))
using (var canvas = new SKCanvas(bmp))
{
canvas.Clear(SKColors.Crimson);
using (var data = SKData.Create(path))
using (var image = SKImage.FromEncodedData(data))
{
canvas.DrawImage(image, 0, 0);
}
Assert.Equal(SKColors.Crimson, bmp.GetPixel(3, 3));
Assert.Equal(SKColors.Crimson, bmp.GetPixel(70, 50));
Assert.Equal(new SKColor(23, 35, 34), bmp.GetPixel(40, 40));
}
}
[SkippableFact]
public void DecodingWithBitmapCreatesCorrectImage()
{
var info = new SKImageInfo(120, 120);
var path = Path.Combine(PathToImages, "vimeo_icon_dark.png");
using (var bmp = new SKBitmap(info))
using (var canvas = new SKCanvas(bmp))
{
canvas.Clear(SKColors.Crimson);
using (var bitmap = SKBitmap.Decode(path))
using (var image = SKImage.FromBitmap(bitmap))
{
canvas.DrawImage(image, 0, 0);
}
Assert.Equal(SKColors.Crimson, bmp.GetPixel(3, 3));
Assert.Equal(SKColors.Crimson, bmp.GetPixel(70, 50));
Assert.Equal(new SKColor(23, 35, 34), bmp.GetPixel(40, 40));
}
}
[SkippableFact]
public void DecodingWithPathCreatesCorrectImage()
{
var info = new SKImageInfo(120, 120);
var path = Path.Combine(PathToImages, "vimeo_icon_dark.png");
using (var bmp = new SKBitmap(info))
using (var canvas = new SKCanvas(bmp))
{
canvas.Clear(SKColors.Crimson);
using (var image = SKImage.FromEncodedData(path))
{
canvas.DrawImage(image, 0, 0);
}
Assert.Equal(SKColors.Crimson, bmp.GetPixel(3, 3));
Assert.Equal(SKColors.Crimson, bmp.GetPixel(70, 50));
Assert.Equal(new SKColor(23, 35, 34), bmp.GetPixel(40, 40));
}
}
[Obsolete]
[SkippableFact]
public void EncodeWithSimpleSerializer()