From 1fd692f262baa12b48abbf2f0c5e8c027e219383 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 17 Jan 2017 16:45:06 -0600 Subject: [PATCH] Change implementation to be via different classes so as to not break invariants and pixel measurements. --- .../Avalonia.Direct2D1.csproj | 4 +- .../Avalonia.Direct2D1/Direct2D1Platform.cs | 6 +- .../Media/DrawingContext.cs | 2 +- .../Media/Imaging/BitmapImpl.cs | 150 ++---------------- .../Media/Imaging/D2DBitmapImpl.cs | 57 +++++++ .../Media/Imaging/RenderTargetBitmapImpl.cs | 2 +- .../Media/Imaging/WicBitmapImpl.cs | 135 ++++++++++++++++ 7 files changed, 212 insertions(+), 144 deletions(-) create mode 100644 src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DBitmapImpl.cs create mode 100644 src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs diff --git a/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj b/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj index 9f9558ff76..8a3a100ba8 100644 --- a/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj +++ b/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj @@ -65,8 +65,10 @@ - + + + diff --git a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs index b43eef2fa9..5c135a2201 100644 --- a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs +++ b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs @@ -46,7 +46,7 @@ namespace Avalonia.Direct2D1 public IBitmapImpl CreateBitmap(int width, int height) { - return new BitmapImpl(s_imagingFactory, width, height); + return new WicBitmapImpl(s_imagingFactory, width, height); } public IFormattedTextImpl CreateFormattedText( @@ -92,12 +92,12 @@ namespace Avalonia.Direct2D1 public IBitmapImpl LoadBitmap(string fileName) { - return new BitmapImpl(s_imagingFactory, fileName); + return new WicBitmapImpl(s_imagingFactory, fileName); } public IBitmapImpl LoadBitmap(Stream stream) { - return new BitmapImpl(s_imagingFactory, stream); + return new WicBitmapImpl(s_imagingFactory, stream); } } } diff --git a/src/Windows/Avalonia.Direct2D1/Media/DrawingContext.cs b/src/Windows/Avalonia.Direct2D1/Media/DrawingContext.cs index 75a0f43d9f..0d936b7057 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/DrawingContext.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/DrawingContext.cs @@ -76,7 +76,7 @@ namespace Avalonia.Direct2D1.Media /// The rect in the output to draw to. public void DrawImage(IBitmap source, double opacity, Rect sourceRect, Rect destRect) { - BitmapImpl impl = (BitmapImpl)source.PlatformImpl; + var impl = (BitmapImpl)source.PlatformImpl; Bitmap d2d = impl.GetDirect2DBitmap(_renderTarget); _renderTarget.DrawBitmap( d2d, diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs index 13dccf7714..63596bdf54 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs @@ -1,150 +1,24 @@ -// 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; +using System.Collections.Generic; using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; using Avalonia.Platform; -using SharpDX.WIC; +using SharpDX.Direct2D1; namespace Avalonia.Direct2D1.Media { - /// - /// A Direct2D implementation of a . - /// - public class BitmapImpl : IBitmapImpl + public abstract class BitmapImpl : IBitmapImpl, IDisposable { - private readonly ImagingFactory _factory; - - private SharpDX.Direct2D1.Bitmap _direct2D; - - /// - /// Initializes a new instance of the class. - /// - /// The WIC imaging factory to use. - /// The filename of the bitmap to load. - public BitmapImpl(ImagingFactory factory, string fileName) - { - _factory = factory; - - using (BitmapDecoder decoder = new BitmapDecoder(factory, fileName, DecodeOptions.CacheOnDemand)) - { - WicImpl = new Bitmap(factory, decoder.GetFrame(0), BitmapCreateCacheOption.CacheOnDemand); - } - } - - /// - /// Initializes a new instance of the class. - /// - /// The WIC imaging factory to use. - /// The stream to read the bitmap from. - public BitmapImpl(ImagingFactory factory, Stream stream) - { - _factory = factory; - - using (BitmapDecoder decoder = new BitmapDecoder(factory, stream, DecodeOptions.CacheOnLoad)) - { - WicImpl = new Bitmap(factory, decoder.GetFrame(0), BitmapCreateCacheOption.CacheOnLoad); - } - } - - /// - /// Initializes a new instance of the class. - /// - /// The WIC imaging factory to use. - /// The width of the bitmap. - /// The height of the bitmap. - public BitmapImpl(ImagingFactory factory, int width, int height) - { - _factory = factory; - WicImpl = new Bitmap( - factory, - width, - height, - PixelFormat.Format32bppPBGRA, - BitmapCreateCacheOption.CacheOnLoad); - } - - /// - /// Initialize a new instance of the class - /// with a bitmap backed by GPU memory. - /// - /// The GPU bitmap. - /// - /// This bitmap must be either from the same render target, - /// or if the render target is a , - /// the device associated with this context, to be renderable. - /// - public BitmapImpl(SharpDX.Direct2D1.Bitmap d2DBitmap) - { - _direct2D = d2DBitmap; - } - - /// - /// Gets the width of the bitmap, in pixels. - /// - public int PixelWidth => WicImpl.Size.Width; - - /// - /// Gets the height of the bitmap, in pixels. - /// - public int PixelHeight => WicImpl.Size.Height; + public abstract Bitmap GetDirect2DBitmap(SharpDX.Direct2D1.RenderTarget target); + public abstract int PixelWidth { get; } + public abstract int PixelHeight { get; } + public abstract void Save(string fileName); + public abstract void Save(Stream stream); public virtual void Dispose() { - WicImpl.Dispose(); - _direct2D?.Dispose(); - } - - /// - /// Gets the WIC implementation of the bitmap. - /// - public Bitmap WicImpl { get; } - - /// - /// Gets a Direct2D bitmap to use on the specified render target. - /// - /// The render target. - /// The Direct2D bitmap. - public SharpDX.Direct2D1.Bitmap GetDirect2DBitmap(SharpDX.Direct2D1.RenderTarget renderTarget) - { - if (_direct2D == null) - { - FormatConverter converter = new FormatConverter(_factory); - converter.Initialize(WicImpl, PixelFormat.Format32bppPBGRA); - _direct2D = SharpDX.Direct2D1.Bitmap.FromWicBitmap(renderTarget, converter); - } - - return _direct2D; - } - - /// - /// Saves the bitmap to a file. - /// - /// The filename. - public void Save(string fileName) - { - if (Path.GetExtension(fileName) != ".png") - { - // Yeah, we need to support other formats. - throw new NotSupportedException("Use PNG, stoopid."); - } - - using (FileStream s = new FileStream(fileName, FileMode.Create)) - { - Save(s); - } - } - - public void Save(Stream stream) - { - PngBitmapEncoder encoder = new PngBitmapEncoder(_factory); - encoder.Initialize(stream); - - BitmapFrameEncode frame = new BitmapFrameEncode(encoder); - frame.Initialize(); - frame.WriteSource(WicImpl); - frame.Commit(); - encoder.Commit(); } } } diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DBitmapImpl.cs new file mode 100644 index 0000000000..5378ae3257 --- /dev/null +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DBitmapImpl.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Avalonia.Platform; +using SharpDX.Direct2D1; + +namespace Avalonia.Direct2D1.Media +{ + /// + /// A Direct2D Bitmap implementation that uses a GPU memory bitmap as its image. + /// + public class D2DBitmapImpl : BitmapImpl + { + private Bitmap _direct2D; + + /// + /// Initialize a new instance of the class + /// with a bitmap backed by GPU memory. + /// + /// The GPU bitmap. + /// + /// This bitmap must be either from the same render target, + /// or if the render target is a , + /// the device associated with this context, to be renderable. + /// + public D2DBitmapImpl(Bitmap d2DBitmap) + { + if (d2DBitmap == null) throw new ArgumentNullException(nameof(d2DBitmap)); + + _direct2D = d2DBitmap; + } + + public override Bitmap GetDirect2DBitmap(SharpDX.Direct2D1.RenderTarget target) => _direct2D; + + public override int PixelWidth => _direct2D.PixelSize.Width; + public override int PixelHeight => _direct2D.PixelSize.Height; + + public override void Save(string fileName) + { + throw new NotImplementedException(); + } + + public override void Save(Stream stream) + { + throw new NotImplementedException(); + } + + public override void Dispose() + { + base.Dispose(); + _direct2D.Dispose(); + } + } +} diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/RenderTargetBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/RenderTargetBitmapImpl.cs index eff832407e..59f3734649 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/RenderTargetBitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/RenderTargetBitmapImpl.cs @@ -10,7 +10,7 @@ using SharpDX.WIC; namespace Avalonia.Direct2D1.Media { - public class RenderTargetBitmapImpl : BitmapImpl, IRenderTargetBitmapImpl, IDisposable + public class RenderTargetBitmapImpl : WicBitmapImpl, IRenderTargetBitmapImpl { private readonly WicRenderTarget _target; diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs new file mode 100644 index 0000000000..f17c516edd --- /dev/null +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/WicBitmapImpl.cs @@ -0,0 +1,135 @@ +// 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 Avalonia.Platform; +using SharpDX.WIC; + +namespace Avalonia.Direct2D1.Media +{ + /// + /// A WIC implementation of a . + /// + public class WicBitmapImpl : BitmapImpl + { + private readonly ImagingFactory _factory; + + private SharpDX.Direct2D1.Bitmap _direct2D; + + /// + /// Initializes a new instance of the class. + /// + /// The WIC imaging factory to use. + /// The filename of the bitmap to load. + public WicBitmapImpl(ImagingFactory factory, string fileName) + { + _factory = factory; + + using (BitmapDecoder decoder = new BitmapDecoder(factory, fileName, DecodeOptions.CacheOnDemand)) + { + WicImpl = new Bitmap(factory, decoder.GetFrame(0), BitmapCreateCacheOption.CacheOnDemand); + } + } + + /// + /// Initializes a new instance of the class. + /// + /// The WIC imaging factory to use. + /// The stream to read the bitmap from. + public WicBitmapImpl(ImagingFactory factory, Stream stream) + { + _factory = factory; + + using (BitmapDecoder decoder = new BitmapDecoder(factory, stream, DecodeOptions.CacheOnLoad)) + { + WicImpl = new Bitmap(factory, decoder.GetFrame(0), BitmapCreateCacheOption.CacheOnLoad); + } + } + + /// + /// Initializes a new instance of the class. + /// + /// The WIC imaging factory to use. + /// The width of the bitmap. + /// The height of the bitmap. + public WicBitmapImpl(ImagingFactory factory, int width, int height) + { + _factory = factory; + WicImpl = new Bitmap( + factory, + width, + height, + PixelFormat.Format32bppPBGRA, + BitmapCreateCacheOption.CacheOnLoad); + } + + /// + /// Gets the width of the bitmap, in pixels. + /// + public override int PixelWidth => WicImpl.Size.Width; + + /// + /// Gets the height of the bitmap, in pixels. + /// + public override int PixelHeight => WicImpl.Size.Height; + + public override void Dispose() + { + WicImpl.Dispose(); + _direct2D?.Dispose(); + } + + /// + /// Gets the WIC implementation of the bitmap. + /// + public Bitmap WicImpl { get; } + + /// + /// Gets a Direct2D bitmap to use on the specified render target. + /// + /// The render target. + /// The Direct2D bitmap. + public override SharpDX.Direct2D1.Bitmap GetDirect2DBitmap(SharpDX.Direct2D1.RenderTarget renderTarget) + { + if (_direct2D == null) + { + FormatConverter converter = new FormatConverter(_factory); + converter.Initialize(WicImpl, PixelFormat.Format32bppPBGRA); + _direct2D = SharpDX.Direct2D1.Bitmap.FromWicBitmap(renderTarget, converter); + } + + return _direct2D; + } + + /// + /// Saves the bitmap to a file. + /// + /// The filename. + public override void Save(string fileName) + { + if (Path.GetExtension(fileName) != ".png") + { + // Yeah, we need to support other formats. + throw new NotSupportedException("Use PNG, stoopid."); + } + + using (FileStream s = new FileStream(fileName, FileMode.Create)) + { + Save(s); + } + } + + public override void Save(Stream stream) + { + PngBitmapEncoder encoder = new PngBitmapEncoder(_factory); + encoder.Initialize(stream); + + BitmapFrameEncode frame = new BitmapFrameEncode(encoder); + frame.Initialize(); + frame.WriteSource(WicImpl); + frame.Commit(); + encoder.Commit(); + } + } +}