From a0adee3d00c480c18805a8c34f2c697e227edc8c Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sun, 29 Jan 2023 12:31:52 +0600 Subject: [PATCH] Added a ctor for populating WriteableBitmap with initial data --- .../Media/Imaging/WriteableBitmap.cs | 26 ++++++++++++++++ .../Avalonia.RenderTests/Media/BitmapTests.cs | 30 +++++++++++++------ 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/src/Avalonia.Base/Media/Imaging/WriteableBitmap.cs b/src/Avalonia.Base/Media/Imaging/WriteableBitmap.cs index a3dd88b075..868f4439c4 100644 --- a/src/Avalonia.Base/Media/Imaging/WriteableBitmap.cs +++ b/src/Avalonia.Base/Media/Imaging/WriteableBitmap.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Runtime.CompilerServices; using Avalonia.Platform; namespace Avalonia.Media.Imaging @@ -36,6 +37,31 @@ namespace Avalonia.Media.Imaging _pixelFormatMemory = pixelFormatMemory; } + /// + /// Initializes a new instance of the class with existing pixel data + /// The data is copied to the bitmap + /// + /// The pixel format. + /// The alpha format. + /// The pointer to the source bytes. + /// The size of the bitmap in device pixels. + /// The DPI of the bitmap. + /// The number of bytes per row. + public unsafe WriteableBitmap(PixelFormat format, AlphaFormat alphaFormat, IntPtr data, PixelSize size, Vector dpi, int stride) + : this(size, dpi, format, alphaFormat) + { + var minStride = (format.BitsPerPixel * size.Width + 7) / 8; + if (minStride > stride) + throw new ArgumentOutOfRangeException(nameof(stride)); + + using (var locked = Lock()) + { + for (var y = 0; y < size.Height; y++) + Unsafe.CopyBlock((locked.Address + locked.RowBytes * y).ToPointer(), + (data + y * stride).ToPointer(), (uint)minStride); + } + } + public override PixelFormat? Format => _pixelFormatMemory?.Format ?? base.Format; public ILockedFramebuffer Lock() diff --git a/tests/Avalonia.RenderTests/Media/BitmapTests.cs b/tests/Avalonia.RenderTests/Media/BitmapTests.cs index 5b85f98b70..c63a876d81 100644 --- a/tests/Avalonia.RenderTests/Media/BitmapTests.cs +++ b/tests/Avalonia.RenderTests/Media/BitmapTests.cs @@ -167,10 +167,17 @@ namespace Avalonia.Direct2D1.RenderTests.Media if (!File.Exists(Path.Combine(OutputPath, expectedName + ".expected.png"))) expectedName = Path.Combine(relativeFilesDir, "Default"); - foreach (var writable in new[] { false, true }) + var names = new[] + { + "_Writeable", + "_WriteableInitialized", + "_Normal" + }; + + foreach (var step in new[] { 0,1,2 }) { - var testName = nameof(BitmapsShouldSupportTranscoders_Lenna) + "_" + formatName + - (writable ? "_Writeable" : "_Normal"); + + var testName = nameof(BitmapsShouldSupportTranscoders_Lenna) + "_" + formatName + names[step]; var path = System.IO.Path.Combine(OutputPath, testName + ".out.png"); fixed (byte* pData = data) @@ -178,7 +185,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media Bitmap? b = null; try { - if (writable) + if (step == 0) { var bmp = new WriteableBitmap(size, new Vector(96, 96), new PixelFormat(format), alphaFormat); @@ -194,15 +201,20 @@ namespace Avalonia.Direct2D1.RenderTests.Media } b = bmp; - var copyTo = new byte[data.Length]; - fixed (byte* pCopyTo = copyTo) - b.CopyPixels(default, new IntPtr(pCopyTo), copyTo.Length, stride); - Assert.Equal(data.ToArray(), copyTo); } + else if (step == 1) + b = new WriteableBitmap(new PixelFormat(format), alphaFormat, new IntPtr(pData), + size, new Vector(96, 96), stride); else - { b = new Bitmap(new PixelFormat(format), alphaFormat, new IntPtr(pData), size, new Vector(96, 96), stride); + + if (step < 2) + { + var copyTo = new byte[data.Length]; + fixed (byte* pCopyTo = copyTo) + b.CopyPixels(default, new IntPtr(pCopyTo), copyTo.Length, stride); + Assert.Equal(data.ToArray(), copyTo); } b.Save(path);