From 7013033a1b75920f718e5fdbc423056e5ad9ef66 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Thu, 23 Feb 2017 06:17:19 +0300 Subject: [PATCH 1/4] Added `Bitmap(PixelFormat format, IntPtr data, int width, int height, int stride)` constructor --- .../Avalonia.Controls.csproj | 1 - .../Platform/Surfaces/ILockedFramebuffer.cs | 1 + .../Platform/Surfaces/PixelFormat.cs | 15 --- src/Avalonia.Visuals/Avalonia.Visuals.csproj | 1 + src/Avalonia.Visuals/Media/Imaging/Bitmap.cs | 14 +++ .../Platform/IPlatformRenderInterface.cs | 12 ++ src/Avalonia.Visuals/Platform/PixelFormat.cs | 9 ++ src/Gtk/Avalonia.Cairo/CairoPlatform.cs | 5 + .../Avalonia.Skia/FramebufferRenderTarget.cs | 17 +-- .../Avalonia.Skia/PlatformRenderInterface.cs | 10 ++ src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs | 13 +++ .../Avalonia.Direct2D1/Direct2D1Platform.cs | 5 + .../Media/Imaging/WicBitmapImpl.cs | 25 ++++ .../SwapChainRenderTarget.cs | 1 + .../Interop/UnmanagedMethods.cs | 3 + .../Avalonia.Win32/WindowFramebuffer.cs | 2 +- .../InputElement_HitTesting.cs | 5 + .../Avalonia.RenderTests.projitems | 1 + .../Avalonia.RenderTests/Media/BitmapTests.cs | 108 ++++++++++++++++++ .../VisualTree/MockRenderInterface.cs | 5 + ...ouldBeUsableAsBitmap_Bgra8888.expected.png | Bin 0 -> 800 bytes ...ShouldBeUsableAsBitmap_Rgb565.expected.png | Bin 0 -> 786 bytes ...ouldBeUsableAsBitmap_Rgba8888.expected.png | Bin 0 -> 800 bytes 23 files changed, 221 insertions(+), 32 deletions(-) delete mode 100644 src/Avalonia.Controls/Platform/Surfaces/PixelFormat.cs create mode 100644 src/Avalonia.Visuals/Platform/PixelFormat.cs create mode 100644 tests/Avalonia.RenderTests/Media/BitmapTests.cs create mode 100644 tests/TestFiles/Skia/Media/Bitmap/FramebufferRenderResultsShouldBeUsableAsBitmap_Bgra8888.expected.png create mode 100644 tests/TestFiles/Skia/Media/Bitmap/FramebufferRenderResultsShouldBeUsableAsBitmap_Rgb565.expected.png create mode 100644 tests/TestFiles/Skia/Media/Bitmap/FramebufferRenderResultsShouldBeUsableAsBitmap_Rgba8888.expected.png diff --git a/src/Avalonia.Controls/Avalonia.Controls.csproj b/src/Avalonia.Controls/Avalonia.Controls.csproj index 6119103e6d..cb1e421470 100644 --- a/src/Avalonia.Controls/Avalonia.Controls.csproj +++ b/src/Avalonia.Controls/Avalonia.Controls.csproj @@ -60,7 +60,6 @@ - diff --git a/src/Avalonia.Controls/Platform/Surfaces/ILockedFramebuffer.cs b/src/Avalonia.Controls/Platform/Surfaces/ILockedFramebuffer.cs index d6402d170d..b62060b029 100644 --- a/src/Avalonia.Controls/Platform/Surfaces/ILockedFramebuffer.cs +++ b/src/Avalonia.Controls/Platform/Surfaces/ILockedFramebuffer.cs @@ -1,4 +1,5 @@ using System; +using Avalonia.Platform; namespace Avalonia.Controls.Platform.Surfaces { diff --git a/src/Avalonia.Controls/Platform/Surfaces/PixelFormat.cs b/src/Avalonia.Controls/Platform/Surfaces/PixelFormat.cs deleted file mode 100644 index c9f8eabe97..0000000000 --- a/src/Avalonia.Controls/Platform/Surfaces/PixelFormat.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Avalonia.Controls.Platform.Surfaces -{ - public enum PixelFormat - { - Rgb565, - Rgba8888, - Bgra8888 - } -} diff --git a/src/Avalonia.Visuals/Avalonia.Visuals.csproj b/src/Avalonia.Visuals/Avalonia.Visuals.csproj index a0ed19d2b4..1ba4e730d9 100644 --- a/src/Avalonia.Visuals/Avalonia.Visuals.csproj +++ b/src/Avalonia.Visuals/Avalonia.Visuals.csproj @@ -103,6 +103,7 @@ + diff --git a/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs b/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs index 1800110e68..c9f7e0f7ac 100644 --- a/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs +++ b/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs @@ -41,6 +41,20 @@ namespace Avalonia.Media.Imaging PlatformImpl = impl; } + /// + /// Initializes a new instance of the class. + /// + /// Pixel format + /// Pointer to source bytes + /// Bitmap width + /// Bitmap height + /// Bytes per row + public Bitmap(PixelFormat format, IntPtr data, int width, int height, int stride) + { + PlatformImpl = AvaloniaLocator.Current.GetService() + .LoadBitmap(format, data, width, height, stride); + } + /// /// Gets the width of the bitmap, in pixels. /// diff --git a/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs b/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs index cdec0a07a1..7dc97b022e 100644 --- a/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs +++ b/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs @@ -1,6 +1,7 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. +using System; using System.Collections.Generic; using System.IO; using Avalonia.Media; @@ -68,5 +69,16 @@ namespace Avalonia.Platform /// The stream to read the bitmap from. /// An . IBitmapImpl LoadBitmap(Stream stream); + + /// + /// Loads a bitmap implementation from a pixels in memory.. + /// + /// Pixel format + /// Pointer to source bytes + /// Bitmap width + /// Bitmap height + /// Bytes per row + /// An . + IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, int width, int height, int stride); } } diff --git a/src/Avalonia.Visuals/Platform/PixelFormat.cs b/src/Avalonia.Visuals/Platform/PixelFormat.cs new file mode 100644 index 0000000000..526303ebb1 --- /dev/null +++ b/src/Avalonia.Visuals/Platform/PixelFormat.cs @@ -0,0 +1,9 @@ +namespace Avalonia.Platform +{ + public enum PixelFormat + { + Rgb565, + Rgba8888, + Bgra8888 + } +} diff --git a/src/Gtk/Avalonia.Cairo/CairoPlatform.cs b/src/Gtk/Avalonia.Cairo/CairoPlatform.cs index e6c493320f..b47827cb02 100644 --- a/src/Gtk/Avalonia.Cairo/CairoPlatform.cs +++ b/src/Gtk/Avalonia.Cairo/CairoPlatform.cs @@ -91,5 +91,10 @@ namespace Avalonia.Cairo Gtk.Application.Init(); return new Gtk.Invisible().CreatePangoContext(); } + + public IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, int width, int height, int stride) + { + throw new NotSupportedException("No proper control over pixel format with Cairo, use Skia backend instead"); + } } } diff --git a/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs b/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs index b273d6209f..b2b5a0653f 100644 --- a/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs +++ b/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs @@ -22,19 +22,6 @@ namespace Avalonia.Skia //Nothing to do here, since we don't own framebuffer } - - SKColorType TranslatePixelFormat(PixelFormat fmt) - { - if(fmt == PixelFormat.Rgb565) - return SKColorType.Rgb565; - if(fmt == PixelFormat.Bgra8888) - return SKColorType.Bgra8888; - if (fmt == PixelFormat.Rgba8888) - return SKColorType.Rgba8888; - throw new ArgumentException("Unknown pixel format: " + fmt); - } - - class PixelFormatShim : IDisposable { private readonly SKImageInfo _nfo; @@ -73,8 +60,8 @@ namespace Avalonia.Skia { var fb = _surface.Lock(); PixelFormatShim shim = null; - SKImageInfo framebuffer = new SKImageInfo(fb.Width, fb.Height, TranslatePixelFormat(fb.Format), - SKAlphaType.Opaque); + SKImageInfo framebuffer = new SKImageInfo(fb.Width, fb.Height, fb.Format.ToSkColorType(), + SKAlphaType.Premul); var surface = SKSurface.Create(framebuffer, fb.Address, fb.RowBytes) ?? (shim = new PixelFormatShim(framebuffer, fb.Address, fb.RowBytes)) .CreateSurface(); diff --git a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs index f0735bb0df..1b898f0f48 100644 --- a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs +++ b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs @@ -52,6 +52,16 @@ namespace Avalonia.Skia } } + public IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, int width, int height, int stride) + { + using (var tmp = new SKBitmap()) + { + tmp.InstallPixels(new SKImageInfo(width, height, format.ToSkColorType(), SKAlphaType.Premul) + , data, stride); + return new BitmapImpl(tmp.Copy()); + } + } + public IRenderer CreateRenderer(IRenderRoot root, IRenderLoop renderLoop) { return new Renderer(root, renderLoop); diff --git a/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs b/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs index 0d0ab380c5..7540caacfe 100644 --- a/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs +++ b/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs @@ -1,4 +1,6 @@ +using System; using Avalonia.Media; +using Avalonia.Platform; using SkiaSharp; @@ -44,6 +46,17 @@ namespace Avalonia.Skia return new SKColor(c.R, c.G, c.B, c.A); } + public static SKColorType ToSkColorType(this PixelFormat fmt) + { + if (fmt == PixelFormat.Rgb565) + return SKColorType.Rgb565; + if (fmt == PixelFormat.Bgra8888) + return SKColorType.Bgra8888; + if (fmt == PixelFormat.Rgba8888) + return SKColorType.Rgba8888; + throw new ArgumentException("Unknown pixel format: " + fmt); + } + public static SKShaderTileMode ToSKShaderTileMode(this Media.GradientSpreadMethod m) { switch (m) diff --git a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs index 34595fecc8..913e76f48e 100644 --- a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs +++ b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs @@ -133,5 +133,10 @@ namespace Avalonia.Direct2D1 { return new WicBitmapImpl(s_imagingFactory, stream); } + + public IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, int width, int height, int stride) + { + return new WicBitmapImpl(s_imagingFactory, format, data, width, height, stride); + } } } diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs index f17c516edd..4082bf6850 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs @@ -4,6 +4,9 @@ using System; using System.IO; using Avalonia.Platform; +using Avalonia.Win32.Interop; +using PixelFormat = SharpDX.WIC.PixelFormat; +using APixelFormat = Avalonia.Platform.PixelFormat; using SharpDX.WIC; namespace Avalonia.Direct2D1.Media @@ -64,6 +67,28 @@ namespace Avalonia.Direct2D1.Media BitmapCreateCacheOption.CacheOnLoad); } + public WicBitmapImpl(ImagingFactory factory, Platform.PixelFormat format, IntPtr data, int width, int height, int stride) + { + Guid fmt; + if (format == APixelFormat.Rgb565) + fmt = PixelFormat.Format16bppBGR565; + else if (format == APixelFormat.Bgra8888) + fmt = PixelFormat.Format32bppPBGRA; + else if (format == APixelFormat.Rgba8888) + fmt = PixelFormat.Format32bppPRGBA; + else throw new ArgumentException("Unknown pixel format"); + + WicImpl = new Bitmap(factory, width, height, fmt, BitmapCreateCacheOption.CacheOnDemand); + using (var l = WicImpl.Lock(BitmapLockFlags.Write)) + { + for (var row = 0; row < height; row++) + { + UnmanagedMethods.CopyMemory(new IntPtr(l.Data.DataPointer.ToInt64() + row * l.Stride), + new IntPtr(data.ToInt64() + row * stride), (uint) l.Data.Pitch); + } + } + } + /// /// Gets the width of the bitmap, in pixels. /// diff --git a/src/Windows/Avalonia.Direct2D1/SwapChainRenderTarget.cs b/src/Windows/Avalonia.Direct2D1/SwapChainRenderTarget.cs index 8362305b9f..119715b5fc 100644 --- a/src/Windows/Avalonia.Direct2D1/SwapChainRenderTarget.cs +++ b/src/Windows/Avalonia.Direct2D1/SwapChainRenderTarget.cs @@ -9,6 +9,7 @@ using Avalonia.Win32.Interop; using SharpDX; using SharpDX.Direct2D1; using SharpDX.DXGI; +using PixelFormat = SharpDX.Direct2D1.PixelFormat; using AlphaMode = SharpDX.Direct2D1.AlphaMode; using Device = SharpDX.Direct2D1.Device; using Factory = SharpDX.Direct2D1.Factory; diff --git a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs index 65a9f96b71..fe04d2c011 100644 --- a/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs +++ b/src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs @@ -909,6 +909,9 @@ namespace Avalonia.Win32.Interop uint dwMaximumSizeLow, string lpName); + [DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)] + public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count); + public enum MONITOR { MONITOR_DEFAULTTONULL = 0x00000000, diff --git a/src/Windows/Avalonia.Win32/WindowFramebuffer.cs b/src/Windows/Avalonia.Win32/WindowFramebuffer.cs index b00348d97d..4cae5af237 100644 --- a/src/Windows/Avalonia.Win32/WindowFramebuffer.cs +++ b/src/Windows/Avalonia.Win32/WindowFramebuffer.cs @@ -2,7 +2,7 @@ using System.Runtime.InteropServices; using Avalonia.Controls.Platform.Surfaces; using Avalonia.Win32.Interop; -using PixelFormat = Avalonia.Controls.Platform.Surfaces.PixelFormat; +using PixelFormat = Avalonia.Platform.PixelFormat; namespace Avalonia.Win32 { diff --git a/tests/Avalonia.Input.UnitTests/InputElement_HitTesting.cs b/tests/Avalonia.Input.UnitTests/InputElement_HitTesting.cs index e00d504124..b0a57f6f4a 100644 --- a/tests/Avalonia.Input.UnitTests/InputElement_HitTesting.cs +++ b/tests/Avalonia.Input.UnitTests/InputElement_HitTesting.cs @@ -365,6 +365,11 @@ namespace Avalonia.Input.UnitTests throw new NotImplementedException(); } + public IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, int width, int height, int stride) + { + throw new NotImplementedException(); + } + class MockStreamGeometry : Avalonia.Platform.IStreamGeometryImpl { private MockStreamGeometryContext _impl = new MockStreamGeometryContext(); diff --git a/tests/Avalonia.RenderTests/Avalonia.RenderTests.projitems b/tests/Avalonia.RenderTests/Avalonia.RenderTests.projitems index ad3b182bdf..e26ac81dda 100644 --- a/tests/Avalonia.RenderTests/Avalonia.RenderTests.projitems +++ b/tests/Avalonia.RenderTests/Avalonia.RenderTests.projitems @@ -10,6 +10,7 @@ + diff --git a/tests/Avalonia.RenderTests/Media/BitmapTests.cs b/tests/Avalonia.RenderTests/Media/BitmapTests.cs new file mode 100644 index 0000000000..e7bd1054d4 --- /dev/null +++ b/tests/Avalonia.RenderTests/Media/BitmapTests.cs @@ -0,0 +1,108 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using System.IO; +using System.Runtime.InteropServices; +using Avalonia.Controls; +using Avalonia.Controls.Platform.Surfaces; +using Avalonia.Controls.Shapes; +using Avalonia.Layout; +using Avalonia.Media; +using Avalonia.Media.Imaging; +using Avalonia.Platform; +using Xunit; + +#if AVALONIA_CAIRO +namespace Avalonia.Cairo.RenderTests.Media +#elif AVALONIA_SKIA +namespace Avalonia.Skia.RenderTests +#else +namespace Avalonia.Direct2D1.RenderTests.Media +#endif +{ + public class BitmapTests : TestBase + { + public BitmapTests() + : base(@"Media\Bitmap") + { + Directory.CreateDirectory(OutputPath); + } + + class Framebuffer : ILockedFramebuffer, IFramebufferPlatformSurface + { + public Framebuffer(PixelFormat fmt, int width, int height) + { + Format = fmt; + var bpp = fmt == PixelFormat.Rgb565 ? 2 : 4; + Width = width; + Height = height; + RowBytes = bpp * width; + Address = Marshal.AllocHGlobal(Height * RowBytes); + } + + public IntPtr Address { get; } + + public Size Dpi { get; } = new Size(96, 96); + + public PixelFormat Format { get; } + + public int Height { get; } + + public int RowBytes { get; } + + public int Width { get; } + + public void Dispose() + { + //no-op + } + + public ILockedFramebuffer Lock() + { + return this; + } + + public void Deallocate() => Marshal.FreeHGlobal(Address); + } + + +#if AVALONIA_SKIA + [Theory] +#else + [Theory(Skip = "Framebuffer not supported")] +#endif + [InlineData(PixelFormat.Rgba8888), InlineData(PixelFormat.Bgra8888), InlineData(PixelFormat.Rgb565)] + public void FramebufferRenderResultsShouldBeUsableAsBitmap(PixelFormat fmt) + { + var testName = nameof(FramebufferRenderResultsShouldBeUsableAsBitmap) + "_" + fmt; + var fb = new Framebuffer(fmt, 80, 80); + var r = Avalonia.AvaloniaLocator.Current.GetService(); + using (var target = r.CreateRenderTarget(new object[] { fb })) + using (var ctx = target.CreateDrawingContext()) + { + ctx.PushOpacity(0.8); + ctx.FillRectangle(Brushes.Chartreuse, new Rect(0, 0, 20, 100)); + ctx.FillRectangle(Brushes.Crimson, new Rect(20, 0, 20, 100)); + ctx.FillRectangle(Brushes.Gold, new Rect(40, 0, 20, 100)); + } + + var bmp = new Bitmap(fmt, fb.Address, fb.Width, fb.Height, fb.RowBytes); + fb.Deallocate(); + using (var rtb = new RenderTargetBitmap(100, 100)) + { + using (var ctx = rtb.CreateDrawingContext()) + { + ctx.FillRectangle(Brushes.Blue, new Rect(0, 0, 100, 100)); + ctx.FillRectangle(Brushes.Pink, new Rect(0, 20, 100, 10)); + + var rc = new Rect(0, 0, 60, 60); + ctx.DrawImage(bmp, 1, rc, rc); + } + rtb.Save(System.IO.Path.Combine(OutputPath, testName + ".out.png")); + } + CompareImages(testName); + + } + } +} diff --git a/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs b/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs index ac31b3852b..7345826829 100644 --- a/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs +++ b/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs @@ -45,6 +45,11 @@ namespace Avalonia.Visuals.UnitTests.VisualTree throw new NotImplementedException(); } + public IBitmapImpl LoadBitmap(PixelFormat format, IntPtr data, int width, int height, int stride) + { + throw new NotImplementedException(); + } + class MockStreamGeometry : IStreamGeometryImpl { private MockStreamGeometryContext _impl = new MockStreamGeometryContext(); diff --git a/tests/TestFiles/Skia/Media/Bitmap/FramebufferRenderResultsShouldBeUsableAsBitmap_Bgra8888.expected.png b/tests/TestFiles/Skia/Media/Bitmap/FramebufferRenderResultsShouldBeUsableAsBitmap_Bgra8888.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..19686464c546d3f56a55e15fc4df8bc574ecf13e GIT binary patch literal 800 zcmeAS@N?(olHy`uVBq!ia0vp^DIm0?E|u$lp4Sznk+pCI zt8&hw6|IZJx}ppYsSSFePk-;<{yg#k=k4>?e|`Nut9(N0JB8DC9H;GU)+uI> ze8#uwjBLtG>k~#GiPBBIAg^g;9psn|@-5J#JsUblxX|hXn_`Q3mNMsM`qKH18@E56 ndHCa*hZWCgD4b?9|371-;u7va=|XQ{s%G$X^>bP0l+XkKg^yP@ literal 0 HcmV?d00001 diff --git a/tests/TestFiles/Skia/Media/Bitmap/FramebufferRenderResultsShouldBeUsableAsBitmap_Rgb565.expected.png b/tests/TestFiles/Skia/Media/Bitmap/FramebufferRenderResultsShouldBeUsableAsBitmap_Rgb565.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..f3d20008a1bde3d523b8be3c2dc29af79b52303f GIT binary patch literal 786 zcmeAS@N?(olHy`uVBq!ia0vp^DIm_*Z1E)2cG}@ZrO^~MPgl128YzTqBOD= zu3%NpSu{k1j{g3hz18}JQTc?_cM7NPI8NKytW(S$`HXMV8QGMXK#BYB6l%hUjCbf5 z@>(+IW%|o_YA=nTHk63T%ok=2_BESn~aE`Pr+P_hqe@Y6hlb22WQ%mvv4F FO#n8jN}B)x literal 0 HcmV?d00001 diff --git a/tests/TestFiles/Skia/Media/Bitmap/FramebufferRenderResultsShouldBeUsableAsBitmap_Rgba8888.expected.png b/tests/TestFiles/Skia/Media/Bitmap/FramebufferRenderResultsShouldBeUsableAsBitmap_Rgba8888.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..19686464c546d3f56a55e15fc4df8bc574ecf13e GIT binary patch literal 800 zcmeAS@N?(olHy`uVBq!ia0vp^DIm0?E|u$lp4Sznk+pCI zt8&hw6|IZJx}ppYsSSFePk-;<{yg#k=k4>?e|`Nut9(N0JB8DC9H;GU)+uI> ze8#uwjBLtG>k~#GiPBBIAg^g;9psn|@-5J#JsUblxX|hXn_`Q3mNMsM`qKH18@E56 ndHCa*hZWCgD4b?9|371-;u7va=|XQ{s%G$X^>bP0l+XkKg^yP@ literal 0 HcmV?d00001 From 90a491554990b8c0a2c26f4a2fffdc6605223682 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Thu, 23 Feb 2017 06:18:00 +0300 Subject: [PATCH 2/4] Implemented WritableBitmap --- .../Avalonia.Controls.csproj | 1 - .../Surfaces/IFramebufferPlatformSurface.cs | 1 + src/Avalonia.Visuals/Avalonia.Visuals.csproj | 3 ++ .../Media/Imaging/WritableBitmap.cs | 22 ++++++++ .../Platform}/ILockedFramebuffer.cs | 3 +- .../Platform/IPlatformRenderInterface.cs | 9 ++++ .../Platform/IWritableBitmapImpl.cs | 16 ++++++ src/Gtk/Avalonia.Cairo/CairoPlatform.cs | 5 ++ src/Gtk/Avalonia.Gtk/FramebufferManager.cs | 1 + src/Gtk/Avalonia.Gtk3/FramebufferManager.cs | 1 + src/Skia/Avalonia.Skia/BitmapImpl.cs | 45 +++++++++++++++-- .../Avalonia.Skia/PlatformRenderInterface.cs | 5 ++ src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs | 11 ++++ .../Avalonia.Direct2D1.csproj | 1 + .../Avalonia.Direct2D1/Direct2D1Platform.cs | 6 +++ .../Media/Imaging/WicBitmapImpl.cs | 25 +++++----- .../Media/Imaging/WritableWicBitmapImpl.cs | 47 ++++++++++++++++++ .../Avalonia.Direct2D1/PrimitiveExtensions.cs | 11 ++++ .../Avalonia.Win32/FramebufferManager.cs | 1 + .../Avalonia.Win32/WindowFramebuffer.cs | 1 + .../InputElement_HitTesting.cs | 5 ++ .../Avalonia.RenderTests/Media/BitmapTests.cs | 33 +++++++++++- .../VisualTree/MockRenderInterface.cs | 5 ++ ...BitmapShouldBeUsable_Bgra8888.expected.png | Bin 0 -> 147998 bytes ...BitmapShouldBeUsable_Rgba8888.expected.png | Bin 0 -> 90938 bytes ...BitmapShouldBeUsable_Bgra8888.expected.png | Bin 0 -> 147998 bytes ...BitmapShouldBeUsable_Rgba8888.expected.png | Bin 0 -> 90938 bytes 27 files changed, 237 insertions(+), 21 deletions(-) create mode 100644 src/Avalonia.Visuals/Media/Imaging/WritableBitmap.cs rename src/{Avalonia.Controls/Platform/Surfaces => Avalonia.Visuals/Platform}/ILockedFramebuffer.cs (91%) create mode 100644 src/Avalonia.Visuals/Platform/IWritableBitmapImpl.cs create mode 100644 src/Windows/Avalonia.Direct2D1/Media/Imaging/WritableWicBitmapImpl.cs create mode 100644 tests/TestFiles/Direct2D1/Media/Bitmap/WritableBitmapShouldBeUsable_Bgra8888.expected.png create mode 100644 tests/TestFiles/Direct2D1/Media/Bitmap/WritableBitmapShouldBeUsable_Rgba8888.expected.png create mode 100644 tests/TestFiles/Skia/Media/Bitmap/WritableBitmapShouldBeUsable_Bgra8888.expected.png create mode 100644 tests/TestFiles/Skia/Media/Bitmap/WritableBitmapShouldBeUsable_Rgba8888.expected.png diff --git a/src/Avalonia.Controls/Avalonia.Controls.csproj b/src/Avalonia.Controls/Avalonia.Controls.csproj index cb1e421470..f12f07070e 100644 --- a/src/Avalonia.Controls/Avalonia.Controls.csproj +++ b/src/Avalonia.Controls/Avalonia.Controls.csproj @@ -59,7 +59,6 @@ - diff --git a/src/Avalonia.Controls/Platform/Surfaces/IFramebufferPlatformSurface.cs b/src/Avalonia.Controls/Platform/Surfaces/IFramebufferPlatformSurface.cs index 84988e912f..4dc96a074d 100644 --- a/src/Avalonia.Controls/Platform/Surfaces/IFramebufferPlatformSurface.cs +++ b/src/Avalonia.Controls/Platform/Surfaces/IFramebufferPlatformSurface.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Avalonia.Platform; namespace Avalonia.Controls.Platform.Surfaces { diff --git a/src/Avalonia.Visuals/Avalonia.Visuals.csproj b/src/Avalonia.Visuals/Avalonia.Visuals.csproj index 1ba4e730d9..812e9d48ad 100644 --- a/src/Avalonia.Visuals/Avalonia.Visuals.csproj +++ b/src/Avalonia.Visuals/Avalonia.Visuals.csproj @@ -69,6 +69,7 @@ + @@ -102,7 +103,9 @@ + + diff --git a/src/Avalonia.Visuals/Media/Imaging/WritableBitmap.cs b/src/Avalonia.Visuals/Media/Imaging/WritableBitmap.cs new file mode 100644 index 0000000000..5c5b516ddd --- /dev/null +++ b/src/Avalonia.Visuals/Media/Imaging/WritableBitmap.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Avalonia.Platform; + +namespace Avalonia.Media.Imaging +{ + /// + /// Holds a writable bitmap image. + /// + public class WritableBitmap : Bitmap + { + public WritableBitmap(int width, int height, PixelFormat? format = null) + : base(AvaloniaLocator.Current.GetService().CreateWritableBitmap(width, height, format)) + { + } + + public ILockedFramebuffer Lock() => ((IWritableBitmapImpl) PlatformImpl).Lock(); + } +} diff --git a/src/Avalonia.Controls/Platform/Surfaces/ILockedFramebuffer.cs b/src/Avalonia.Visuals/Platform/ILockedFramebuffer.cs similarity index 91% rename from src/Avalonia.Controls/Platform/Surfaces/ILockedFramebuffer.cs rename to src/Avalonia.Visuals/Platform/ILockedFramebuffer.cs index b62060b029..92ec2877ab 100644 --- a/src/Avalonia.Controls/Platform/Surfaces/ILockedFramebuffer.cs +++ b/src/Avalonia.Visuals/Platform/ILockedFramebuffer.cs @@ -1,7 +1,6 @@ using System; -using Avalonia.Platform; -namespace Avalonia.Controls.Platform.Surfaces +namespace Avalonia.Platform { public interface ILockedFramebuffer : IDisposable { diff --git a/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs b/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs index 7dc97b022e..ef58d52b4f 100644 --- a/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs +++ b/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs @@ -56,6 +56,15 @@ namespace Avalonia.Platform /// An . IRenderTargetBitmapImpl CreateRenderTargetBitmap(int width, int height); + /// + /// Creates a writable bitmap implementation. + /// + /// The width of the bitmap. + /// The height of the bitmap. + /// Pixel format (optional). + /// An . + IWritableBitmapImpl CreateWritableBitmap(int width, int height, PixelFormat? format = null); + /// /// Loads a bitmap implementation from a file.. /// diff --git a/src/Avalonia.Visuals/Platform/IWritableBitmapImpl.cs b/src/Avalonia.Visuals/Platform/IWritableBitmapImpl.cs new file mode 100644 index 0000000000..b736c11dab --- /dev/null +++ b/src/Avalonia.Visuals/Platform/IWritableBitmapImpl.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Avalonia.Platform +{ + /// + /// Defines the platform-specific interface for a . + /// + public interface IWritableBitmapImpl : IBitmapImpl + { + ILockedFramebuffer Lock(); + } +} diff --git a/src/Gtk/Avalonia.Cairo/CairoPlatform.cs b/src/Gtk/Avalonia.Cairo/CairoPlatform.cs index b47827cb02..9cf16312e9 100644 --- a/src/Gtk/Avalonia.Cairo/CairoPlatform.cs +++ b/src/Gtk/Avalonia.Cairo/CairoPlatform.cs @@ -96,5 +96,10 @@ namespace Avalonia.Cairo { throw new NotSupportedException("No proper control over pixel format with Cairo, use Skia backend instead"); } + + public IWritableBitmapImpl CreateWritableBitmap(int width, int height, PixelFormat? fmt) + { + throw new NotSupportedException("No proper support with Cairo, use Skia backend instead"); + } } } diff --git a/src/Gtk/Avalonia.Gtk/FramebufferManager.cs b/src/Gtk/Avalonia.Gtk/FramebufferManager.cs index 0c9ed44274..5ec49fb91f 100644 --- a/src/Gtk/Avalonia.Gtk/FramebufferManager.cs +++ b/src/Gtk/Avalonia.Gtk/FramebufferManager.cs @@ -1,5 +1,6 @@ using System; using Avalonia.Controls.Platform.Surfaces; +using Avalonia.Platform; namespace Avalonia.Gtk { diff --git a/src/Gtk/Avalonia.Gtk3/FramebufferManager.cs b/src/Gtk/Avalonia.Gtk3/FramebufferManager.cs index e52f0efb81..41e174bce4 100644 --- a/src/Gtk/Avalonia.Gtk3/FramebufferManager.cs +++ b/src/Gtk/Avalonia.Gtk3/FramebufferManager.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Avalonia.Controls.Platform.Surfaces; +using Avalonia.Platform; namespace Avalonia.Gtk3 { diff --git a/src/Skia/Avalonia.Skia/BitmapImpl.cs b/src/Skia/Avalonia.Skia/BitmapImpl.cs index 7d99156a1d..b564734a47 100644 --- a/src/Skia/Avalonia.Skia/BitmapImpl.cs +++ b/src/Skia/Avalonia.Skia/BitmapImpl.cs @@ -9,7 +9,7 @@ using SkiaSharp; namespace Avalonia.Skia { - class BitmapImpl : IRenderTargetBitmapImpl + class BitmapImpl : IRenderTargetBitmapImpl, IWritableBitmapImpl { public SKBitmap Bitmap { get; private set; } @@ -20,11 +20,11 @@ namespace Avalonia.Skia PixelWidth = bm.Width; } - public BitmapImpl(int width, int height) + public BitmapImpl(int width, int height, PixelFormat? fmt = null) { PixelHeight = height; PixelWidth = width; - var colorType = SKImageInfo.PlatformColorType; + var colorType = fmt?.ToSkColorType() ?? SKImageInfo.PlatformColorType; var runtime = AvaloniaLocator.Current?.GetService()?.GetRuntimeInfo(); if (runtime?.IsDesktop == true && runtime?.OperatingSystem == OperatingSystemType.Linux) colorType = SKColorType.Bgra8888; @@ -38,10 +38,21 @@ namespace Avalonia.Skia public void Save(string fileName) { + #if DESKTOP + if(Bitmap.ColorType != SKColorType.Bgra8888) + { + using (var tmp = new BitmapImpl(Bitmap.Copy(SKColorType.Bgra8888))) + tmp.Save(fileName); + return; + } + IntPtr length; using (var sdb = new System.Drawing.Bitmap(PixelWidth, PixelHeight, Bitmap.RowBytes, - System.Drawing.Imaging.PixelFormat.Format32bppArgb, Bitmap.GetPixels(out length))) + + System.Drawing.Imaging.PixelFormat.Format32bppArgb, + + Bitmap.GetPixels(out length))) sdb.Save(fileName); #else //SkiaSharp doesn't expose image encoders yet @@ -96,5 +107,31 @@ namespace Avalonia.Skia data.SaveTo(stream); } } + + class BitmapFramebuffer : ILockedFramebuffer + { + private SKBitmap _bmp; + + public BitmapFramebuffer(SKBitmap bmp) + { + _bmp = bmp; + _bmp.LockPixels(); + } + + public void Dispose() + { + _bmp.UnlockPixels(); + _bmp = null; + } + + public IntPtr Address => _bmp.GetPixels(); + public int Width => _bmp.Width; + public int Height => _bmp.Height; + public int RowBytes => _bmp.RowBytes; + public Size Dpi { get; } = new Size(96, 96); + public PixelFormat Format => _bmp.ColorType.ToPixelFormat(); + } + + public ILockedFramebuffer Lock() => new BitmapFramebuffer(Bitmap); } } diff --git a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs index 1b898f0f48..72f8d08d44 100644 --- a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs +++ b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs @@ -84,5 +84,10 @@ namespace Avalonia.Skia throw new Exception("Skia backend currently only supports framebuffer render target"); return new FramebufferRenderTarget(fb); } + + public IWritableBitmapImpl CreateWritableBitmap(int width, int height, PixelFormat? format = null) + { + return new BitmapImpl(width, height, format); + } } } diff --git a/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs b/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs index 7540caacfe..8591f9218a 100644 --- a/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs +++ b/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs @@ -57,6 +57,17 @@ namespace Avalonia.Skia throw new ArgumentException("Unknown pixel format: " + fmt); } + public static PixelFormat ToPixelFormat(this SKColorType fmt) + { + if (fmt == SKColorType.Rgb565) + return PixelFormat.Rgb565; + if (fmt == SKColorType.Bgra8888) + return PixelFormat.Bgra8888; + if (fmt == SKColorType.Rgba8888) + return PixelFormat.Rgba8888; + throw new ArgumentException("Unknown pixel format: " + fmt); + } + public static SKShaderTileMode ToSKShaderTileMode(this Media.GradientSpreadMethod m) { switch (m) diff --git a/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj b/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj index a055a337eb..ba117d72e9 100644 --- a/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj +++ b/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj @@ -70,6 +70,7 @@ + diff --git a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs index 913e76f48e..d5b0f22090 100644 --- a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs +++ b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs @@ -10,6 +10,7 @@ using Avalonia.Media; using Avalonia.Platform; using Avalonia.Controls; using Avalonia.Controls.Platform.Surfaces; +using Avalonia.Direct2D1.Media.Imaging; using Avalonia.Rendering; namespace Avalonia @@ -119,6 +120,11 @@ namespace Avalonia.Direct2D1 return new RenderTargetBitmapImpl(s_imagingFactory, s_d2D1Device.Factory, width, height); } + public IWritableBitmapImpl CreateWritableBitmap(int width, int height, PixelFormat? format = null) + { + return new WritableWicBitmapImpl(s_imagingFactory, width, height, format); + } + public IStreamGeometryImpl CreateStreamGeometry() { return new StreamGeometryImpl(); diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs index 4082bf6850..2dd7acd9f9 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs @@ -56,29 +56,26 @@ namespace Avalonia.Direct2D1.Media /// The WIC imaging factory to use. /// The width of the bitmap. /// The height of the bitmap. - public WicBitmapImpl(ImagingFactory factory, int width, int height) + /// Pixel format + public WicBitmapImpl(ImagingFactory factory, int width, int height, APixelFormat? pixelFormat = null) { + if (!pixelFormat.HasValue) + pixelFormat = APixelFormat.Rgba8888; + _factory = factory; + PixelFormat = pixelFormat; WicImpl = new Bitmap( factory, width, height, - PixelFormat.Format32bppPBGRA, + pixelFormat.Value.ToWic(), BitmapCreateCacheOption.CacheOnLoad); } public WicBitmapImpl(ImagingFactory factory, Platform.PixelFormat format, IntPtr data, int width, int height, int stride) { - Guid fmt; - if (format == APixelFormat.Rgb565) - fmt = PixelFormat.Format16bppBGR565; - else if (format == APixelFormat.Bgra8888) - fmt = PixelFormat.Format32bppPBGRA; - else if (format == APixelFormat.Rgba8888) - fmt = PixelFormat.Format32bppPRGBA; - else throw new ArgumentException("Unknown pixel format"); - - WicImpl = new Bitmap(factory, width, height, fmt, BitmapCreateCacheOption.CacheOnDemand); + WicImpl = new Bitmap(factory, width, height, format.ToWic(), BitmapCreateCacheOption.CacheOnDemand); + PixelFormat = format; using (var l = WicImpl.Lock(BitmapLockFlags.Write)) { for (var row = 0; row < height; row++) @@ -89,6 +86,8 @@ namespace Avalonia.Direct2D1.Media } } + protected APixelFormat? PixelFormat { get; } + /// /// Gets the width of the bitmap, in pixels. /// @@ -120,7 +119,7 @@ namespace Avalonia.Direct2D1.Media if (_direct2D == null) { FormatConverter converter = new FormatConverter(_factory); - converter.Initialize(WicImpl, PixelFormat.Format32bppPBGRA); + converter.Initialize(WicImpl, SharpDX.WIC.PixelFormat.Format32bppPBGRA); _direct2D = SharpDX.Direct2D1.Bitmap.FromWicBitmap(renderTarget, converter); } diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WritableWicBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WritableWicBitmapImpl.cs new file mode 100644 index 0000000000..06eb26b407 --- /dev/null +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WritableWicBitmapImpl.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Avalonia.Platform; +using SharpDX.WIC; +using PixelFormat = Avalonia.Platform.PixelFormat; + +namespace Avalonia.Direct2D1.Media.Imaging +{ + class WritableWicBitmapImpl : WicBitmapImpl, IWritableBitmapImpl + { + public WritableWicBitmapImpl(ImagingFactory factory, int width, int height, PixelFormat? pixelFormat) + : base(factory, width, height, pixelFormat) + { + } + + class LockedBitmap : ILockedFramebuffer + { + private readonly BitmapLock _lock; + private readonly PixelFormat _format; + + public LockedBitmap(BitmapLock l, PixelFormat format) + { + _lock = l; + _format = format; + } + + + public void Dispose() + { + _lock.Dispose(); + } + + public IntPtr Address => _lock.Data.DataPointer; + public int Width => _lock.Size.Width; + public int Height => _lock.Size.Height; + public int RowBytes => _lock.Stride; + public Size Dpi { get; } = new Size(96, 96); + public PixelFormat Format => _format; + + } + + public ILockedFramebuffer Lock() => new LockedBitmap(WicImpl.Lock(BitmapLockFlags.Write), PixelFormat.Value); + } +} diff --git a/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs b/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs index 87be89d10c..118b6deb97 100644 --- a/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs +++ b/src/Windows/Avalonia.Direct2D1/PrimitiveExtensions.cs @@ -88,6 +88,17 @@ namespace Avalonia.Direct2D1 return CapStyle.Triangle; } + public static Guid ToWic(this Platform.PixelFormat format) + { + if (format == Platform.PixelFormat.Rgb565) + return SharpDX.WIC.PixelFormat.Format16bppBGR565; + if (format == Platform.PixelFormat.Bgra8888) + return SharpDX.WIC.PixelFormat.Format32bppPBGRA; + if (format == Platform.PixelFormat.Rgba8888) + return SharpDX.WIC.PixelFormat.Format32bppPRGBA; + throw new ArgumentException("Unknown pixel format"); + } + /// /// Converts a pen to a Direct2D stroke style. /// diff --git a/src/Windows/Avalonia.Win32/FramebufferManager.cs b/src/Windows/Avalonia.Win32/FramebufferManager.cs index ecd05f41b4..f0a6430918 100644 --- a/src/Windows/Avalonia.Win32/FramebufferManager.cs +++ b/src/Windows/Avalonia.Win32/FramebufferManager.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Avalonia.Controls.Platform.Surfaces; +using Avalonia.Platform; using Avalonia.Win32.Interop; namespace Avalonia.Win32 diff --git a/src/Windows/Avalonia.Win32/WindowFramebuffer.cs b/src/Windows/Avalonia.Win32/WindowFramebuffer.cs index 4cae5af237..fe4fe5c668 100644 --- a/src/Windows/Avalonia.Win32/WindowFramebuffer.cs +++ b/src/Windows/Avalonia.Win32/WindowFramebuffer.cs @@ -1,6 +1,7 @@ using System; using System.Runtime.InteropServices; using Avalonia.Controls.Platform.Surfaces; +using Avalonia.Platform; using Avalonia.Win32.Interop; using PixelFormat = Avalonia.Platform.PixelFormat; diff --git a/tests/Avalonia.Input.UnitTests/InputElement_HitTesting.cs b/tests/Avalonia.Input.UnitTests/InputElement_HitTesting.cs index b0a57f6f4a..a70130990a 100644 --- a/tests/Avalonia.Input.UnitTests/InputElement_HitTesting.cs +++ b/tests/Avalonia.Input.UnitTests/InputElement_HitTesting.cs @@ -370,6 +370,11 @@ namespace Avalonia.Input.UnitTests throw new NotImplementedException(); } + public IWritableBitmapImpl CreateWritableBitmap(int width, int height, PixelFormat? fmt) + { + throw new NotImplementedException(); + } + class MockStreamGeometry : Avalonia.Platform.IStreamGeometryImpl { private MockStreamGeometryContext _impl = new MockStreamGeometryContext(); diff --git a/tests/Avalonia.RenderTests/Media/BitmapTests.cs b/tests/Avalonia.RenderTests/Media/BitmapTests.cs index e7bd1054d4..1fd5d1eda6 100644 --- a/tests/Avalonia.RenderTests/Media/BitmapTests.cs +++ b/tests/Avalonia.RenderTests/Media/BitmapTests.cs @@ -102,7 +102,38 @@ namespace Avalonia.Direct2D1.RenderTests.Media rtb.Save(System.IO.Path.Combine(OutputPath, testName + ".out.png")); } CompareImages(testName); - + } + +#if AVALONIA_CAIRO + //wontfix +#else + [Theory] +#endif + [InlineData(PixelFormat.Bgra8888), InlineData(PixelFormat.Rgba8888)] + public void WritableBitmapShouldBeUsable(PixelFormat fmt) + { + var writableBitmap = new WritableBitmap(256, 256, fmt); + + var data = new int[256 * 256]; + for (int y = 0; y < 256; y++) + for (int x = 0; x < 256; x++) + data[y * 256 + x] =(int)((uint)(x + (y << 8)) | 0xFF000000u); + + + using (var l = writableBitmap.Lock()) + { + for(var r = 0; r<256; r++) + { + Marshal.Copy(data, r * 256, new IntPtr(l.Address.ToInt64() + r * l.RowBytes), 256); + } + } + + + var name = nameof(WritableBitmapShouldBeUsable) + "_" + fmt; + + writableBitmap.Save(System.IO.Path.Combine(OutputPath, name + ".out.png")); + CompareImages(name); + } } } diff --git a/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs b/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs index 7345826829..303736be9c 100644 --- a/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs +++ b/tests/Avalonia.Visuals.UnitTests/VisualTree/MockRenderInterface.cs @@ -50,6 +50,11 @@ namespace Avalonia.Visuals.UnitTests.VisualTree throw new NotImplementedException(); } + public IWritableBitmapImpl CreateWritableBitmap(int width, int height, PixelFormat? fmt) + { + throw new NotImplementedException(); + } + class MockStreamGeometry : IStreamGeometryImpl { private MockStreamGeometryContext _impl = new MockStreamGeometryContext(); diff --git a/tests/TestFiles/Direct2D1/Media/Bitmap/WritableBitmapShouldBeUsable_Bgra8888.expected.png b/tests/TestFiles/Direct2D1/Media/Bitmap/WritableBitmapShouldBeUsable_Bgra8888.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..ef77cbe0f2f6e30364fe5c47b901de0fd76961a4 GIT binary patch literal 147998 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

abLWPX=qYNVfNwr2-fI4s#FMl37KibUq4 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 PesP+$lT{tXC+>d$Igp>~ literal 0 HcmV?d00001 diff --git a/tests/TestFiles/Skia/Media/Bitmap/WritableBitmapShouldBeUsable_Bgra8888.expected.png b/tests/TestFiles/Skia/Media/Bitmap/WritableBitmapShouldBeUsable_Bgra8888.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..ef77cbe0f2f6e30364fe5c47b901de0fd76961a4 GIT binary patch literal 147998 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

abLWPX=qYNVfNwr2-fI4s#FMl37KibUq4 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 PesP+$lT{tXC+>d$Igp>~ literal 0 HcmV?d00001 From 67a82d04624d6b67e3f34251ebe8f6ba3237b4c6 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Thu, 23 Feb 2017 06:21:53 +0300 Subject: [PATCH 3/4] Reverted WIC default pixel format --- src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs index 2dd7acd9f9..1554296c0f 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs @@ -60,7 +60,7 @@ namespace Avalonia.Direct2D1.Media public WicBitmapImpl(ImagingFactory factory, int width, int height, APixelFormat? pixelFormat = null) { if (!pixelFormat.HasValue) - pixelFormat = APixelFormat.Rgba8888; + pixelFormat = APixelFormat.Bgra8888; _factory = factory; PixelFormat = pixelFormat; From 131fa44fa139d2590011d9e94bc5696287be59bb Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Thu, 23 Feb 2017 15:04:59 +0300 Subject: [PATCH 4/4] Fixed namespaces --- .../Platform/SkiaPlatform/AndroidFramebuffer.cs | 2 +- src/iOS/Avalonia.iOS/EmulatedFramebuffer.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs index 55e729f5a2..64dbeb89cc 100644 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs @@ -2,7 +2,7 @@ using System; using System.Runtime.InteropServices; using Android.Runtime; using Android.Views; -using Avalonia.Controls.Platform.Surfaces; +using Avalonia.Platform; namespace Avalonia.Android.Platform.SkiaPlatform { diff --git a/src/iOS/Avalonia.iOS/EmulatedFramebuffer.cs b/src/iOS/Avalonia.iOS/EmulatedFramebuffer.cs index 1baed80ed7..f3fc90a2ab 100644 --- a/src/iOS/Avalonia.iOS/EmulatedFramebuffer.cs +++ b/src/iOS/Avalonia.iOS/EmulatedFramebuffer.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; -using Avalonia.Controls.Platform.Surfaces; +using Avalonia.Platform; using CoreGraphics; using UIKit;