Browse Source

Added IImage interface.

`IImage` represents a base interface for raster and vector images. `IBitmap` now implements this interface and `DrawingContext` accepts this interface in `DrawImage`.

The interface defines a `Draw` method which introduces a level of indirection for drawing the image through the image itself.

Renamed `IDrawingContextImpl.DrawImage` to `DrawBitmap` as this only handles drawing bitmap images. `Bitmap` now calls this method directly on the platform implementation.
pull/3378/head
Steven Kirk 6 years ago
parent
commit
a8e75384b7
  1. 8
      src/Avalonia.Visuals/Media/DrawingContext.cs
  2. 31
      src/Avalonia.Visuals/Media/IImage.cs
  3. 21
      src/Avalonia.Visuals/Media/Imaging/Bitmap.cs
  4. 11
      src/Avalonia.Visuals/Media/Imaging/IBitmap.cs
  5. 4
      src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs
  6. 6
      src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
  7. 4
      src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs
  8. 2
      src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs
  9. 2
      src/Avalonia.X11/X11IconLoader.cs
  10. 8
      src/Skia/Avalonia.Skia/DrawingContextImpl.cs
  11. 4
      src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
  12. 2
      src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs
  13. 2
      src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs
  14. 2
      tests/Avalonia.RenderTests/Media/BitmapTests.cs
  15. 2
      tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs

8
src/Avalonia.Visuals/Media/DrawingContext.cs

@ -74,18 +74,18 @@ namespace Avalonia.Media
public Matrix CurrentContainerTransform => _currentContainerTransform;
/// <summary>
/// Draws a bitmap image.
/// Draws an image.
/// </summary>
/// <param name="source">The bitmap image.</param>
/// <param name="source">The image.</param>
/// <param name="opacity">The opacity to draw with.</param>
/// <param name="sourceRect">The rect in the image to draw.</param>
/// <param name="destRect">The rect in the output to draw to.</param>
/// <param name="bitmapInterpolationMode">The bitmap interpolation mode.</param>
public void DrawImage(IBitmap source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode = default)
public void DrawImage(IImage source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode = default)
{
Contract.Requires<ArgumentNullException>(source != null);
PlatformImpl.DrawImage(source.PlatformImpl, opacity, sourceRect, destRect, bitmapInterpolationMode);
source.Draw(this, opacity, sourceRect, destRect, bitmapInterpolationMode);
}
/// <summary>

31
src/Avalonia.Visuals/Media/IImage.cs

@ -0,0 +1,31 @@
using Avalonia.Platform;
using Avalonia.Visuals.Media.Imaging;
namespace Avalonia.Media
{
/// <summary>
/// Represents a raster or vector image.
/// </summary>
public interface IImage
{
/// <summary>
/// Gets the size of the image, in device independent pixels.
/// </summary>
Size Size { get; }
/// <summary>
/// Draws the image to a <see cref="DrawingContext"/>.
/// </summary>
/// <param name="context">The drawing context.</param>
/// <param name="opacity">The opacity to draw with.</param>
/// <param name="sourceRect">The rect in the image to draw.</param>
/// <param name="destRect">The rect in the output to draw to.</param>
/// <param name="bitmapInterpolationMode">The bitmap interpolation mode.</param>
void Draw(
DrawingContext context,
double opacity,
Rect sourceRect,
Rect destRect,
BitmapInterpolationMode bitmapInterpolationMode);
}
}

21
src/Avalonia.Visuals/Media/Imaging/Bitmap.cs

@ -5,6 +5,7 @@ using System;
using System.IO;
using Avalonia.Platform;
using Avalonia.Utilities;
using Avalonia.Visuals.Media.Imaging;
namespace Avalonia.Media.Imaging
{
@ -94,9 +95,29 @@ namespace Avalonia.Media.Imaging
PlatformImpl.Item.Save(fileName);
}
/// <summary>
/// Saves the bitmap to a stream.
/// </summary>
/// <param name="stream">The stream.</param>
public void Save(Stream stream)
{
PlatformImpl.Item.Save(stream);
}
/// <inheritdoc/>
void IImage.Draw(
DrawingContext context,
double opacity,
Rect sourceRect,
Rect destRect,
BitmapInterpolationMode bitmapInterpolationMode)
{
context.PlatformImpl.DrawBitmap(
PlatformImpl,
opacity,
sourceRect,
destRect,
bitmapInterpolationMode);
}
}
}

11
src/Avalonia.Visuals/Media/Imaging/IBitmap.cs

@ -11,7 +11,7 @@ namespace Avalonia.Media.Imaging
/// <summary>
/// Represents a bitmap image.
/// </summary>
public interface IBitmap : IDisposable
public interface IBitmap : IImage, IDisposable
{
/// <summary>
/// Gets the dots per inch (DPI) of the image.
@ -32,15 +32,6 @@ namespace Avalonia.Media.Imaging
/// </summary>
IRef<IBitmapImpl> PlatformImpl { get; }
/// <summary>
/// Gets the size of the image, in device independent pixels.
/// </summary>
/// <remarks>
/// Note that Skia does not currently support reading the DPI of an image so this value
/// will equal <see cref="PixelSize"/> on Skia.
/// </remarks>
Size Size { get; }
/// <summary>
/// Saves the bitmap to a file.
/// </summary>

4
src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs

@ -33,7 +33,7 @@ namespace Avalonia.Platform
/// <param name="sourceRect">The rect in the image to draw.</param>
/// <param name="destRect">The rect in the output to draw to.</param>
/// <param name="bitmapInterpolationMode">The bitmap interpolation mode.</param>
void DrawImage(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default);
void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default);
/// <summary>
/// Draws a bitmap image.
@ -42,7 +42,7 @@ namespace Avalonia.Platform
/// <param name="opacityMask">The opacity mask to draw with.</param>
/// <param name="opacityMaskRect">The destination rect for the opacity mask.</param>
/// <param name="destRect">The rect in the output to draw to.</param>
void DrawImage(IRef<IBitmapImpl> source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect);
void DrawBitmap(IRef<IBitmapImpl> source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect);
/// <summary>
/// Draws a line.

6
src/Avalonia.Visuals/Rendering/DeferredRenderer.cs

@ -469,11 +469,11 @@ namespace Avalonia.Rendering
if (layer.OpacityMask == null)
{
context.DrawImage(bitmap, layer.Opacity, sourceRect, clientRect);
context.DrawBitmap(bitmap, layer.Opacity, sourceRect, clientRect);
}
else
{
context.DrawImage(bitmap, layer.OpacityMask, layer.OpacityMaskRect, sourceRect);
context.DrawBitmap(bitmap, layer.OpacityMask, layer.OpacityMaskRect, sourceRect);
}
if (layer.GeometryClip != null)
@ -485,7 +485,7 @@ namespace Avalonia.Rendering
if (_overlay != null)
{
var sourceRect = new Rect(0, 0, _overlay.Item.PixelSize.Width, _overlay.Item.PixelSize.Height);
context.DrawImage(_overlay, 0.5, sourceRect, clientRect);
context.DrawBitmap(_overlay, 0.5, sourceRect, clientRect);
}
if (DrawFps)

4
src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs

@ -115,7 +115,7 @@ namespace Avalonia.Rendering.SceneGraph
}
/// <inheritdoc/>
public void DrawImage(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode)
public void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode)
{
var next = NextDrawAs<ImageNode>();
@ -130,7 +130,7 @@ namespace Avalonia.Rendering.SceneGraph
}
/// <inheritdoc/>
public void DrawImage(IRef<IBitmapImpl> source, IBrush opacityMask, Rect opacityMaskRect, Rect sourceRect)
public void DrawBitmap(IRef<IBitmapImpl> source, IBrush opacityMask, Rect opacityMaskRect, Rect sourceRect)
{
// This method is currently only used to composite layers so shouldn't be called here.
throw new NotSupportedException();

2
src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs

@ -100,7 +100,7 @@ namespace Avalonia.Rendering.SceneGraph
public override void Render(IDrawingContextImpl context)
{
context.Transform = Transform;
context.DrawImage(Source, Opacity, SourceRect, DestRect, BitmapInterpolationMode);
context.DrawBitmap(Source, Opacity, SourceRect, DestRect, BitmapInterpolationMode);
}
/// <inheritdoc/>

2
src/Avalonia.X11/X11IconLoader.cs

@ -59,7 +59,7 @@ namespace Avalonia.X11
}
using(var rt = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>().CreateRenderTarget(new[]{this}))
using (var ctx = rt.CreateDrawingContext(null))
ctx.DrawImage(bitmap.PlatformImpl, 1, new Rect(bitmap.Size),
ctx.DrawBitmap(bitmap.PlatformImpl, 1, new Rect(bitmap.Size),
new Rect(0, 0, _width, _height));
Data = new UIntPtr[_width * _height + 2];
Data[0] = new UIntPtr((uint)_width);

8
src/Skia/Avalonia.Skia/DrawingContextImpl.cs

@ -110,7 +110,7 @@ namespace Avalonia.Skia
}
/// <inheritdoc />
public void DrawImage(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode)
public void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode)
{
var drawableImage = (IDrawableBitmapImpl)source.Item;
var s = sourceRect.ToSKRect();
@ -146,10 +146,10 @@ namespace Avalonia.Skia
}
/// <inheritdoc />
public void DrawImage(IRef<IBitmapImpl> source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect)
public void DrawBitmap(IRef<IBitmapImpl> source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect)
{
PushOpacityMask(opacityMask, opacityMaskRect);
DrawImage(source, 1, new Rect(0, 0, source.Item.PixelSize.Width, source.Item.PixelSize.Height), destRect, BitmapInterpolationMode.Default);
DrawBitmap(source, 1, new Rect(0, 0, source.Item.PixelSize.Width, source.Item.PixelSize.Height), destRect, BitmapInterpolationMode.Default);
PopOpacityMask();
}
@ -437,7 +437,7 @@ namespace Avalonia.Skia
context.Clear(Colors.Transparent);
context.PushClip(calc.IntermediateClip);
context.Transform = calc.IntermediateTransform;
context.DrawImage(
context.DrawBitmap(
RefCountable.CreateUnownedNotClonable(tileBrushImage),
1,
sourceRect,

4
src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs

@ -109,7 +109,7 @@ namespace Avalonia.Direct2D1.Media
/// <param name="sourceRect">The rect in the image to draw.</param>
/// <param name="destRect">The rect in the output to draw to.</param>
/// <param name="bitmapInterpolationMode">The bitmap interpolation mode.</param>
public void DrawImage(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode)
public void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode)
{
using (var d2d = ((BitmapImpl)source.Item).GetDirect2DBitmap(_deviceContext))
{
@ -149,7 +149,7 @@ namespace Avalonia.Direct2D1.Media
/// <param name="opacityMask">The opacity mask to draw with.</param>
/// <param name="opacityMaskRect">The destination rect for the opacity mask.</param>
/// <param name="destRect">The rect in the output to draw to.</param>
public void DrawImage(IRef<IBitmapImpl> source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect)
public void DrawBitmap(IRef<IBitmapImpl> source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect)
{
using (var d2dSource = ((BitmapImpl)source.Item).GetDirect2DBitmap(_deviceContext))
using (var sourceBrush = new BitmapBrush(_deviceContext, d2dSource.Value))

2
src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs

@ -107,7 +107,7 @@ namespace Avalonia.Direct2D1.Media
context.PushClip(calc.IntermediateClip);
context.Transform = calc.IntermediateTransform;
context.DrawImage(RefCountable.CreateUnownedNotClonable(bitmap), 1, rect, rect, _bitmapInterpolationMode);
context.DrawBitmap(RefCountable.CreateUnownedNotClonable(bitmap), 1, rect, rect, _bitmapInterpolationMode);
context.PopClip();
}

2
src/Windows/Avalonia.Direct2D1/Media/Imaging/D2DRenderTargetBitmapImpl.cs

@ -58,7 +58,7 @@ namespace Avalonia.Direct2D1.Media.Imaging
{
using (var dc = wic.CreateDrawingContext(null))
{
dc.DrawImage(
dc.DrawBitmap(
RefCountable.CreateUnownedNotClonable(this),
1,
new Rect(PixelSize.ToSizeWithDpi(Dpi.X)),

2
tests/Avalonia.RenderTests/Media/BitmapTests.cs

@ -94,7 +94,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
ctx.DrawRectangle(Brushes.Pink, null, new Rect(0, 20, 100, 10));
var rc = new Rect(0, 0, 60, 60);
ctx.DrawImage(bmp.PlatformImpl, 1, rc, rc);
ctx.DrawBitmap(bmp.PlatformImpl, 1, rc, rc);
}
rtb.Save(System.IO.Path.Combine(OutputPath, testName + ".out.png"));
}

2
tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs

@ -670,7 +670,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering
var context = Mock.Get(target.RenderTarget.CreateDrawingContext(null));
var borderLayer = target.Layers[border].Bitmap;
context.Verify(x => x.DrawImage(borderLayer, 0.5, It.IsAny<Rect>(), It.IsAny<Rect>(), BitmapInterpolationMode.Default));
context.Verify(x => x.DrawBitmap(borderLayer, 0.5, It.IsAny<Rect>(), It.IsAny<Rect>(), BitmapInterpolationMode.Default));
}
[Fact]

Loading…
Cancel
Save