From bbaa8898e5fa26b03438ab683d0cbfe5007d4c0e Mon Sep 17 00:00:00 2001 From: Vicente Penades Date: Fri, 28 Apr 2017 21:14:13 +0200 Subject: [PATCH] Added Image drawing functions to use general porter duff modes --- src/ImageSharp.Drawing/DrawImage.cs | 50 ++++++++- .../Processors/DrawImageEffectProcessor.cs | 102 ++++++++++++++++++ 2 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 src/ImageSharp.Drawing/Processors/DrawImageEffectProcessor.cs diff --git a/src/ImageSharp.Drawing/DrawImage.cs b/src/ImageSharp.Drawing/DrawImage.cs index 6a4f49337..a7f2bf701 100644 --- a/src/ImageSharp.Drawing/DrawImage.cs +++ b/src/ImageSharp.Drawing/DrawImage.cs @@ -4,7 +4,8 @@ // namespace ImageSharp -{ +{ + using System; using Drawing.Processors; using ImageSharp.PixelFormats; @@ -52,6 +53,53 @@ namespace ImageSharp source.ApplyProcessor(new DrawImageProcessor(image, size, location, percent), source.Bounds); return source; + } + + /// + /// Draws the given image together with the current one by blending their pixels. + /// + /// The image this method extends. + /// The image to blend with the currently processing image. + /// Pixel function effect to apply on every pixel + /// The pixel format. + /// The opacity of the image image to blend. Must be between 0 and 100. + /// The size to draw the blended image. + /// The location to draw the blended image. + /// The . + public static Image DrawImage(this Image source, Image image, PixelTransformMode mode, int percent, Size size, Point location) + where TPixel : struct, IPixel + { + Func pixelFunc = mode.GetPixelFunction(); + + return DrawImage(source, image, pixelFunc, percent, size, location); + } + + /// + /// Draws the given image together with the current one by blending their pixels. + /// + /// The image this method extends. + /// The image to blend with the currently processing image. + /// Pixel function effect to apply on every pixel + /// The pixel format. + /// The opacity of the image image to blend. Must be between 0 and 100. + /// The size to draw the blended image. + /// The location to draw the blended image. + /// The . + public static Image DrawImage(this Image source, Image image, Func pixelFunc, int percent, Size size, Point location) + where TPixel : struct, IPixel + { + if (size == default(Size)) + { + size = new Size(image.Width, image.Height); + } + + if (location == default(Point)) + { + location = Point.Empty; + } + + source.ApplyProcessor(new DrawImageEffectProcessor(image, size, location, pixelFunc, percent), source.Bounds); + return source; } } } \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Processors/DrawImageEffectProcessor.cs b/src/ImageSharp.Drawing/Processors/DrawImageEffectProcessor.cs new file mode 100644 index 000000000..4b57be53e --- /dev/null +++ b/src/ImageSharp.Drawing/Processors/DrawImageEffectProcessor.cs @@ -0,0 +1,102 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Drawing.Processors +{ + using System; + using System.Numerics; + using System.Threading.Tasks; + using ImageSharp.PixelFormats; + using ImageSharp.Processing; + + /// + /// Combines two images together by blending the pixels. + /// + /// The pixel format. + internal class DrawImageEffectProcessor : ImageProcessor + where TPixel : struct, IPixel + { + /// + /// Initializes a new instance of the class. + /// + /// The image to blend with the currently processing image. + /// The size to draw the blended image. + /// The location to draw the blended image. + /// Pixel function effect to apply on every pixel + /// The opacity of the image to blend. Between 0 and 100. + public DrawImageEffectProcessor(Image image, Size size, Point location, Func pixelFunction, int alpha = 100) + { + Guard.MustBeBetweenOrEqualTo(alpha, 0, 100, nameof(alpha)); + this.Image = image; + this.PixelFunction = pixelFunction; + this.Size = size; + this.Location = location; + this.Alpha = alpha; + } + + /// + /// Gets the image to blend. + /// + public Image Image { get; private set; } + + /// + /// Gets The function effect to apply on a per pixel basis + /// + public Func PixelFunction { get; private set; } + + /// + /// Gets the alpha percentage value. + /// + public int Alpha { get; } + + /// + /// Gets the size to draw the blended image. + /// + public Size Size { get; } + + /// + /// Gets the location to draw the blended image. + /// + public Point Location { get; } + + /// + protected override void OnApply(ImageBase target, Rectangle sourceRectangle) + { + if (this.Image.Bounds.Size != this.Size) + { + // should Resize be moved to core? + this.Image = this.Image.Resize(this.Size.Width, this.Size.Height); + } + + // Align start/end positions. + Rectangle bounds = this.Image.Bounds; + int minX = Math.Max(this.Location.X, sourceRectangle.X); + int maxX = Math.Min(this.Location.X + bounds.Width, sourceRectangle.Width); + int minY = Math.Max(this.Location.Y, sourceRectangle.Y); + int maxY = Math.Min(this.Location.Y + bounds.Height, sourceRectangle.Bottom); + + float alpha = this.Alpha / 100F; + + using (PixelAccessor sourcePixels = this.Image.Lock()) + using (PixelAccessor targetPixels = target.Lock()) + { + Parallel.For( + minY, + maxY, + this.ParallelOptions, + y => + { + for (int x = minX; x < maxX; x++) + { + TPixel targetColor = targetPixels[x, y]; + TPixel sourceColor = sourcePixels[x - minX, y - minY]; + + targetPixels[x, y] = this.PixelFunction(targetColor, sourceColor, alpha); + } + }); + } + } + } +} \ No newline at end of file