Browse Source

Add Bitmap Blending Mode API

pull/5683/head
Jumar Macato 5 years ago
parent
commit
88fef2fdd5
No known key found for this signature in database GPG Key ID: B19884DAC3A5BF3F
  1. 2
      src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs
  2. 5
      src/Avalonia.Visuals/ApiCompatBaseline.txt
  3. 57
      src/Avalonia.Visuals/Media/Imaging/BitmapBlendingMode.cs
  4. 3
      src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs
  5. 6
      src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs
  6. 28
      src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs
  7. 5
      src/Skia/Avalonia.Skia/DrawingContextImpl.cs
  8. 33
      src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs
  9. 36
      src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs

2
src/Avalonia.Headless/HeadlessPlatformRenderInterface.cs

@ -393,7 +393,7 @@ namespace Avalonia.Headless
{
}
public void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default)
public void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default, BitmapBlendingMode bitmapBlendingMode = BitmapBlendingMode.SourceOver)
{
}

5
src/Avalonia.Visuals/ApiCompatBaseline.txt

@ -1,6 +1,9 @@
Compat issues with assembly Avalonia.Visuals:
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IDrawingContextImpl.DrawBitmap(Avalonia.Utilities.IRef<Avalonia.Platform.IBitmapImpl>, System.Double, Avalonia.Rect, Avalonia.Rect, Avalonia.Visuals.Media.Imaging.BitmapInterpolationMode)' is present in the contract but not in the implementation.
MembersMustExist : Member 'public void Avalonia.Platform.IDrawingContextImpl.DrawBitmap(Avalonia.Utilities.IRef<Avalonia.Platform.IBitmapImpl>, System.Double, Avalonia.Rect, Avalonia.Rect, Avalonia.Visuals.Media.Imaging.BitmapInterpolationMode)' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IDrawingContextImpl.DrawBitmap(Avalonia.Utilities.IRef<Avalonia.Platform.IBitmapImpl>, System.Double, Avalonia.Rect, Avalonia.Rect, Avalonia.Visuals.Media.Imaging.BitmapInterpolationMode, Avalonia.Visuals.Media.Imaging.BitmapBlendingMode)' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.Double Avalonia.Platform.IGeometryImpl.ContourLength' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.Double Avalonia.Platform.IGeometryImpl.ContourLength.get()' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Platform.IGeometryImpl.TryGetPointAndTangentAtDistance(System.Double, Avalonia.Point, Avalonia.Point)' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Platform.IGeometryImpl.TryGetPointAtDistance(System.Double, Avalonia.Point)' is present in the implementation but not in the contract.
Total Issues: 4
Total Issues: 7

57
src/Avalonia.Visuals/Media/Imaging/BitmapBlendingMode.cs

@ -0,0 +1,57 @@
namespace Avalonia.Visuals.Media.Imaging
{
/// <summary>
/// Controls the way the bitmaps are drawn together.
/// </summary>
public enum BitmapBlendingMode
{
/// <summary>
/// Source is placed over the destination.
/// </summary>
SourceOver,
/// <summary>
/// Only the source will be present.
/// </summary>
Source,
/// <summary>
/// Only the destination will be present.
/// </summary>
Destination,
/// <summary>
/// Destination is placed over the source.
/// </summary>
DestinationOver,
/// <summary>
/// The source that overlaps the destination, replaces the destination.
/// </summary>
SourceIn,
/// <summary>
/// Destination which overlaps the source, replaces the source.
/// </summary>
DestinationIn,
/// <summary>
/// Source is placed, where it falls outside of the destination.
/// </summary>
SourceOut,
/// <summary>
/// Destination is placed, where it falls outside of the source.
/// </summary>
DestinationOut,
/// <summary>
/// Source which overlaps the destination, replaces the destination.
/// </summary>
SourceAtop,
/// <summary>
/// Destination which overlaps the source replaces the source.
/// </summary>
DestinationAtop,
/// <summary>
/// The non-overlapping regions of source and destination are combined.
/// </summary>
Xor,
/// <summary>
/// Display the sum of the source image and destination image.
/// </summary>
Plus,
}
}

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

@ -30,7 +30,8 @@ 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 DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default);
/// <param name="bitmapBlendMode">The bitmap blending mode.</param>
void DrawBitmap(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default, BitmapBlendingMode bitmapBlendMode = BitmapBlendingMode.SourceOver);
/// <summary>
/// Draws a bitmap image.

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

@ -112,13 +112,13 @@ namespace Avalonia.Rendering.SceneGraph
}
/// <inheritdoc/>
public void DrawBitmap(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, BitmapBlendingMode bitmapBlendingMode)
{
var next = NextDrawAs<ImageNode>();
if (next == null || !next.Item.Equals(Transform, source, opacity, sourceRect, destRect, bitmapInterpolationMode))
if (next == null || !next.Item.Equals(Transform, source, opacity, sourceRect, destRect, bitmapInterpolationMode, bitmapBlendingMode))
{
Add(new ImageNode(Transform, source, opacity, sourceRect, destRect, bitmapInterpolationMode));
Add(new ImageNode(Transform, source, opacity, sourceRect, destRect, bitmapInterpolationMode, bitmapBlendingMode));
}
else
{

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

@ -18,7 +18,7 @@ namespace Avalonia.Rendering.SceneGraph
/// <param name="sourceRect">The source rect.</param>
/// <param name="destRect">The destination rect.</param>
/// <param name="bitmapInterpolationMode">The bitmap interpolation mode.</param>
public ImageNode(Matrix transform, IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode)
public ImageNode(Matrix transform, IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode, BitmapBlendingMode bitmapBlendingMode)
: base(destRect, transform)
{
Transform = transform;
@ -27,6 +27,7 @@ namespace Avalonia.Rendering.SceneGraph
SourceRect = sourceRect;
DestRect = destRect;
BitmapInterpolationMode = bitmapInterpolationMode;
BitmapBlendingMode = bitmapBlendingMode;
SourceVersion = Source.Item.Version;
}
@ -67,6 +68,14 @@ namespace Avalonia.Rendering.SceneGraph
/// The scaling mode.
/// </value>
public BitmapInterpolationMode BitmapInterpolationMode { get; }
/// <summary>
/// The bitmap blending mode.
/// </summary>
/// <value>
/// The blending mode.
/// </value>
public BitmapBlendingMode BitmapBlendingMode { get; }
/// <summary>
/// Determines if this draw operation equals another.
@ -82,22 +91,23 @@ namespace Avalonia.Rendering.SceneGraph
/// The properties of the other draw operation are passed in as arguments to prevent
/// allocation of a not-yet-constructed draw operation object.
/// </remarks>
public bool Equals(Matrix transform, IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode)
public bool Equals(Matrix transform, IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode, BitmapBlendingMode bitmapBlendingMode)
{
return transform == Transform &&
Equals(source.Item, Source.Item) &&
source.Item.Version == SourceVersion &&
opacity == Opacity &&
sourceRect == SourceRect &&
destRect == DestRect &&
bitmapInterpolationMode == BitmapInterpolationMode;
Equals(source.Item, Source.Item) &&
source.Item.Version == SourceVersion &&
opacity == Opacity &&
sourceRect == SourceRect &&
destRect == DestRect &&
bitmapInterpolationMode == BitmapInterpolationMode &&
bitmapBlendingMode == BitmapBlendingMode;
}
/// <inheritdoc/>
public override void Render(IDrawingContextImpl context)
{
context.Transform = Transform;
context.DrawBitmap(Source, Opacity, SourceRect, DestRect, BitmapInterpolationMode);
context.DrawBitmap(Source, Opacity, SourceRect, DestRect, BitmapInterpolationMode, BitmapBlendingMode);
}
/// <inheritdoc/>

5
src/Skia/Avalonia.Skia/DrawingContextImpl.cs

@ -132,7 +132,7 @@ namespace Avalonia.Skia
}
/// <inheritdoc />
public void DrawBitmap(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, BitmapBlendingMode bitmapBlendingMode)
{
var drawableImage = (IDrawableBitmapImpl)source.Item;
var s = sourceRect.ToSKRect();
@ -145,6 +145,7 @@ namespace Avalonia.Skia
})
{
paint.FilterQuality = bitmapInterpolationMode.ToSKFilterQuality();
paint.BlendMode = bitmapBlendingMode.ToSKBlendMode();
drawableImage.Draw(this, s, d, paint);
}
@ -154,7 +155,7 @@ namespace Avalonia.Skia
public void DrawBitmap(IRef<IBitmapImpl> source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect)
{
PushOpacityMask(opacityMask, opacityMaskRect);
DrawBitmap(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, BitmapBlendingMode.SourceOver);
PopOpacityMask();
}

33
src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs

@ -25,6 +25,39 @@ namespace Avalonia.Skia
}
}
public static SKBlendMode ToSKBlendMode(this BitmapBlendingMode blendingMode)
{
switch (blendingMode)
{
case BitmapBlendingMode.SourceOver:
return SKBlendMode.SrcOver;
case BitmapBlendingMode.Source:
return SKBlendMode.Src;
case BitmapBlendingMode.SourceIn:
return SKBlendMode.SrcIn;
case BitmapBlendingMode.SourceOut:
return SKBlendMode.SrcOut;
case BitmapBlendingMode.SourceAtop:
return SKBlendMode.SrcATop;
case BitmapBlendingMode.Destination:
return SKBlendMode.Dst;
case BitmapBlendingMode.DestinationIn:
return SKBlendMode.DstIn;
case BitmapBlendingMode.DestinationOut:
return SKBlendMode.DstOut;
case BitmapBlendingMode.DestinationOver:
return SKBlendMode.DstOver;
case BitmapBlendingMode.DestinationAtop:
return SKBlendMode.DstATop;
case BitmapBlendingMode.Xor:
return SKBlendMode.Xor;
case BitmapBlendingMode.Plus:
return SKBlendMode.Plus;
default:
throw new ArgumentOutOfRangeException(nameof(blendingMode), blendingMode, null);
}
}
public static SKPoint ToSKPoint(this Point p)
{
return new SKPoint((float)p.X, (float)p.Y);

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

@ -5,6 +5,7 @@ using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Rendering.SceneGraph;
using Avalonia.Utilities;
using Avalonia.Visuals.Media.Imaging;
using SharpDX;
using SharpDX.Direct2D1;
using SharpDX.Mathematics.Interop;
@ -116,12 +117,14 @@ 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 DrawBitmap(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, BitmapBlendingMode bitmapBlendingMode)
{
using (var d2d = ((BitmapImpl)source.Item).GetDirect2DBitmap(_deviceContext))
{
var interpolationMode = GetInterpolationMode(bitmapInterpolationMode);
// TODO: How to implement CompositeMode here?
_deviceContext.DrawBitmap(
d2d.Value,
destRect.ToSharpDX(),
@ -149,6 +152,35 @@ namespace Avalonia.Direct2D1.Media
}
}
public static CompositeMode GetCompositeMode(BitmapBlendingMode blendingMode)
{
switch (blendingMode)
{
case BitmapBlendingMode.SourceIn:
return CompositeMode.SourceIn;
case BitmapBlendingMode.SourceOut:
return CompositeMode.SourceOut;
case BitmapBlendingMode.SourceOver:
return CompositeMode.SourceOver;
case BitmapBlendingMode.SourceAtop:
return CompositeMode.SourceAtop;
case BitmapBlendingMode.DestinationIn:
return CompositeMode.DestinationIn;
case BitmapBlendingMode.DestinationOut:
return CompositeMode.DestinationOut;
case BitmapBlendingMode.DestinationOver:
return CompositeMode.DestinationOver;
case BitmapBlendingMode.DestinationAtop:
return CompositeMode.DestinationAtop;
case BitmapBlendingMode.Xor:
return CompositeMode.Xor;
case BitmapBlendingMode.Plus:
return CompositeMode.Plus;
default:
throw new ArgumentOutOfRangeException(nameof(blendingMode), blendingMode, null);
}
}
/// <summary>
/// Draws a bitmap image.
/// </summary>

Loading…
Cancel
Save