/////////////////////////////////////////////////////////////////////////////////
// Paint.NET //
// Copyright (C) dotPDN LLC, Rick Brewster, Tom Jackson, and contributors. //
// Portions Copyright (C) Microsoft Corporation. All Rights Reserved. //
// See src/Resources/Files/License.txt for full licensing and attribution //
// details. //
// . //
/////////////////////////////////////////////////////////////////////////////////
using System;
using System.Drawing;
namespace PaintDotNet{
/// <summary>
/// Defines a way to operate on a pixel, or a region of pixels, in a binary fashion.
/// That is, it is a simple function F that takes two parameters and returns a
/// result of the form: c = F(a, b)
/// </summary>
[Serializable]
public unsafe abstract class BinaryPixelOp
: PixelOp
{
public abstract ColorBgra Apply(ColorBgra lhs, ColorBgra rhs);
public unsafe virtual void Apply(ColorBgra *dst, ColorBgra *lhs, ColorBgra *rhs, int length)
{
unsafe
{
while (length > 0)
{
*dst = Apply(*lhs, *rhs);
++dst;
++lhs;
++rhs;
--length;
}
}
}
/// <summary>
/// Provides a default implementation for performing dst = F(lhs, rhs) over some rectangle of interest.
/// </summary>
/// <param name="dst">The Surface to write pixels to.</param>
/// <param name="dstOffset">The pixel offset that defines the upper-left of the rectangle-of-interest for the dst Surface.</param>
/// <param name="lhs">The Surface to read pixels from for the lhs parameter given to the method <b>ColorBgra Apply(ColorBgra, ColorBgra)</b>b>.</param></param>
/// <param name="lhsOffset">The pixel offset that defines the upper-left of the rectangle-of-interest for the lhs Surface.</param>
/// <param name="rhs">The Surface to read pixels from for the rhs parameter given to the method <b>ColorBgra Apply(ColorBgra, ColorBgra)</b></param>
/// <param name="rhsOffset">The pixel offset that defines the upper-left of the rectangle-of-interest for the rhs Surface.</param>
/// <param name="roiSize">The size of the rectangles-of-interest for all Surfaces.</param>
public void Apply(Surface dst, Point dstOffset,
Surface lhs, Point lhsOffset,
Surface rhs, Point rhsOffset,
Size roiSize)
{
// Bounds checking only enabled in Debug builds.
#if DEBUG
// Create bounding rectangles for each Surface
Rectangle dstRect = new Rectangle(dstOffset, roiSize);
Rectangle lhsRect = new Rectangle(lhsOffset, roiSize);
Rectangle rhsRect = new Rectangle(rhsOffset, roiSize);
// Clip those rectangles to those Surface's bounding rectangles
Rectangle dstClip = Rectangle.Intersect(dstRect, dst.Bounds);
Rectangle lhsClip = Rectangle.Intersect(lhsRect, lhs.Bounds);
Rectangle rhsClip = Rectangle.Intersect(rhsRect, rhs.Bounds);
// If any of those Rectangles actually got clipped, then throw an exception
if (dstRect != dstClip)
{
throw new ArgumentOutOfRangeException("roiSize", "Destination roi out of bounds");
}
if (lhsRect != lhsClip)
{
throw new ArgumentOutOfRangeException("roiSize", "lhs roi out of bounds");
}
if (rhsRect != rhsClip)
{
throw new ArgumentOutOfRangeException("roiSize", "rhs roi out of bounds");
}
#endif
// Cache the width and height properties
int width = roiSize.Width;
int height = roiSize.Height;
// Do the work.
unsafe
{
for (int row = 0; row < height; ++row)
{
ColorBgra *dstPtr = dst.GetPointAddress(dstOffset.X, dstOffset.Y + row);
ColorBgra *lhsPtr = lhs.GetPointAddress(lhsOffset.X, lhsOffset.Y + row);
ColorBgra *rhsPtr = rhs.GetPointAddress(rhsOffset.X, rhsOffset.Y + row);
Apply(dstPtr, lhsPtr, rhsPtr, width);
}
}
}
public unsafe override void Apply(ColorBgra *dst, ColorBgra *src, int length)
{
unsafe
{
while (length > 0)
{
*dst = Apply(*dst, *src);
++dst;
++src;
--length;
}
}
}
public override void Apply(Surface dst, Point dstOffset, Surface src, Point srcOffset, int roiLength)
{
Apply(dst.GetPointAddress(dstOffset), src.GetPointAddress(srcOffset), roiLength);
}
public void Apply(Surface dst, Surface src)
{
if (dst.Size != src.Size)
{
throw new ArgumentException("dst.Size != src.Size");
}
unsafe
{
for (int y = 0; y < dst.Height; ++y)
{
ColorBgra *dstPtr = dst.GetRowAddressUnchecked(y);
ColorBgra *srcPtr = src.GetRowAddressUnchecked(y);
Apply(dstPtr, srcPtr, dst.Width);
}
}
}
public void Apply(Surface dst, Surface lhs, Surface rhs)
{
if (dst.Size != lhs.Size)
{
throw new ArgumentException("dst.Size != lhs.Size");
}
if (lhs.Size != rhs.Size)
{
throw new ArgumentException("lhs.Size != rhs.Size");
}
unsafe
{
for (int y = 0; y < dst.Height; ++y)
{
ColorBgra *dstPtr = dst.GetRowAddressUnchecked(y);
ColorBgra *lhsPtr = lhs.GetRowAddressUnchecked(y);
ColorBgra *rhsPtr = rhs.GetRowAddressUnchecked(y);
Apply(dstPtr, lhsPtr, rhsPtr, dst.Width);
}
}
}
protected BinaryPixelOp()
{
}
}
}
|