diff --git a/Source/WriteableBitmapEx.Uwp/WriteableBitmapEx.Uwp.csproj b/Source/WriteableBitmapEx.Uwp/WriteableBitmapEx.Uwp.csproj
index c6d982a..66a89ef 100644
--- a/Source/WriteableBitmapEx.Uwp/WriteableBitmapEx.Uwp.csproj
+++ b/Source/WriteableBitmapEx.Uwp/WriteableBitmapEx.Uwp.csproj
@@ -129,11 +129,14 @@
Properties\GlobalAssemblyInfo.cs
-
- BitmapContext.cs
-
-
- BitmapFactory.cs
+
+ BitmapContext.cs
+
+
+ BitmapContextExtensions.cs
+
+
+ BitmapFactory.cs
WriteableBitmapAntialiasingExtensions.cs
diff --git a/Source/WriteableBitmapEx.WinRT/WriteableBitmapEx.WinRT.csproj b/Source/WriteableBitmapEx.WinRT/WriteableBitmapEx.WinRT.csproj
index 1276308..0782f1e 100644
--- a/Source/WriteableBitmapEx.WinRT/WriteableBitmapEx.WinRT.csproj
+++ b/Source/WriteableBitmapEx.WinRT/WriteableBitmapEx.WinRT.csproj
@@ -127,11 +127,14 @@
Properties\GlobalAssemblyInfo.cs
-
- BitmapContext.cs
-
-
- BitmapFactory.cs
+
+ BitmapContext.cs
+
+
+ BitmapContextExtensions.cs
+
+
+ BitmapFactory.cs
WriteableBitmapAntialiasingExtensions.cs
diff --git a/Source/WriteableBitmapEx.Wpf/WriteableBitmapEx.Wpf.csproj b/Source/WriteableBitmapEx.Wpf/WriteableBitmapEx.Wpf.csproj
index 93e738d..cc3d46b 100644
--- a/Source/WriteableBitmapEx.Wpf/WriteableBitmapEx.Wpf.csproj
+++ b/Source/WriteableBitmapEx.Wpf/WriteableBitmapEx.Wpf.csproj
@@ -47,8 +47,9 @@
-
-
+
+
+
diff --git a/Source/WriteableBitmapEx/BitmapContextExtensions.cs b/Source/WriteableBitmapEx/BitmapContextExtensions.cs
new file mode 100644
index 0000000..cb7d58a
--- /dev/null
+++ b/Source/WriteableBitmapEx/BitmapContextExtensions.cs
@@ -0,0 +1,853 @@
+#region Header
+//
+// Project: WriteableBitmapEx - WriteableBitmap extensions
+// Description: Collection of extension methods for the BitmapContext class.
+//
+// Changed by: $Author$
+// Changed on: $Date$
+// Changed in: $Revision$
+// Project: $URL$
+// Id: $Id$
+//
+//
+// Copyright © 2009-2015 Rene Schulte and WriteableBitmapEx Contributors
+//
+// This code is open source. Please read the License.txt for details. No worries, we won't sue you! ;)
+//
+#endregion
+
+using System;
+
+#if NETFX_CORE
+using Windows.Foundation;
+using Windows.UI;
+
+namespace Windows.UI.Xaml.Media.Imaging
+#else
+namespace System.Windows.Media.Imaging
+#endif
+{
+ ///
+ /// Collection of extension methods for the BitmapContext class.
+ ///
+ public
+#if WPF
+ unsafe
+#endif
+ static partial class BitmapContextExtensions
+ {
+ #region Line Drawing Methods
+
+ ///
+ /// Draws an anti-aliased line with a desired stroke thickness
+ /// The BitmapContext containing the pixels.
+ /// The x-coordinate of the start point.
+ /// The y-coordinate of the start point.
+ /// The x-coordinate of the end point.
+ /// The y-coordinate of the end point.
+ /// The color for the line.
+ /// The stroke thickness of the line.
+ ///
+ public static void DrawLineAa(this BitmapContext context, int x1, int y1, int x2, int y2, int color, int strokeThickness, Rect? clipRect = null)
+ {
+ WriteableBitmapExtensions.AAWidthLine(context.Width, context.Height, context, x1, y1, x2, y2, strokeThickness, color, clipRect);
+ }
+
+ ///
+ /// Draws an anti-aliased line with a desired stroke thickness
+ /// The BitmapContext containing the pixels.
+ /// The x-coordinate of the start point.
+ /// The y-coordinate of the start point.
+ /// The x-coordinate of the end point.
+ /// The y-coordinate of the end point.
+ /// The color for the line.
+ /// The stroke thickness of the line.
+ ///
+ public static void DrawLineAa(this BitmapContext context, int x1, int y1, int x2, int y2, Color color, int strokeThickness, Rect? clipRect = null)
+ {
+ var col = WriteableBitmapExtensions.ConvertColor(color);
+ WriteableBitmapExtensions.AAWidthLine(context.Width, context.Height, context, x1, y1, x2, y2, strokeThickness, col, clipRect);
+ }
+
+ ///
+ /// Draws an anti-aliased line
+ /// The BitmapContext containing the pixels.
+ /// The x-coordinate of the start point.
+ /// The y-coordinate of the start point.
+ /// The x-coordinate of the end point.
+ /// The y-coordinate of the end point.
+ /// The color for the line.
+ ///
+ public static void DrawLineAa(this BitmapContext context, int x1, int y1, int x2, int y2, int color, Rect? clipRect = null)
+ {
+ WriteableBitmapExtensions.DrawLineAa(context, context.Width, context.Height, x1, y1, x2, y2, color, clipRect);
+ }
+
+ ///
+ /// Draws an anti-aliased line
+ /// The BitmapContext containing the pixels.
+ /// The x-coordinate of the start point.
+ /// The y-coordinate of the start point.
+ /// The x-coordinate of the end point.
+ /// The y-coordinate of the end point.
+ /// The color for the line.
+ ///
+ public static void DrawLineAa(this BitmapContext context, int x1, int y1, int x2, int y2, Color color, Rect? clipRect = null)
+ {
+ var col = WriteableBitmapExtensions.ConvertColor(color);
+ WriteableBitmapExtensions.DrawLineAa(context, context.Width, context.Height, x1, y1, x2, y2, col, clipRect);
+ }
+
+ ///
+ /// Draws a line with the specified color.
+ ///
+ /// The BitmapContext.
+ /// The x-coordinate of the start point.
+ /// The y-coordinate of the start point.
+ /// The x-coordinate of the end point.
+ /// The y-coordinate of the end point.
+ /// The color for the line.
+ /// The region in the image to restrict drawing to.
+ public static void DrawLine(this BitmapContext context, int x1, int y1, int x2, int y2, int color, Rect? clipRect = null)
+ {
+ WriteableBitmapExtensions.DrawLine(context, context.Width, context.Height, x1, y1, x2, y2, color, clipRect);
+ }
+
+ ///
+ /// Draws a line with the specified color.
+ ///
+ /// The BitmapContext.
+ /// The x-coordinate of the start point.
+ /// The y-coordinate of the start point.
+ /// The x-coordinate of the end point.
+ /// The y-coordinate of the end point.
+ /// The color for the line.
+ /// The region in the image to restrict drawing to.
+ public static void DrawLine(this BitmapContext context, int x1, int y1, int x2, int y2, Color color, Rect? clipRect = null)
+ {
+ var col = WriteableBitmapExtensions.ConvertColor(color);
+ WriteableBitmapExtensions.DrawLine(context, context.Width, context.Height, x1, y1, x2, y2, col, clipRect);
+ }
+
+ #endregion
+
+ #region Shape Drawing Methods
+
+ ///
+ /// Draws a rectangle.
+ /// x2 has to be greater than x1 and y2 has to be greater than y1.
+ ///
+ /// The BitmapContext.
+ /// The x-coordinate of the bounding rectangle's left side.
+ /// The y-coordinate of the bounding rectangle's top side.
+ /// The x-coordinate of the bounding rectangle's right side.
+ /// The y-coordinate of the bounding rectangle's bottom side.
+ /// The color.
+ public static void DrawRectangle(this BitmapContext context, int x1, int y1, int x2, int y2, int color)
+ {
+ // Use refs for faster access (really important!) speeds up a lot!
+ var w = context.Width;
+ var h = context.Height;
+
+ // Check boundaries
+ if ((x1 < 0 && x2 < 0) || (y1 < 0 && y2 < 0)
+ || (x1 >= w && x2 >= w) || (y1 >= h && y2 >= h))
+ {
+ return;
+ }
+
+ // Clamp boundaries
+ if (x1 < 0) { x1 = 0; }
+ if (y1 < 0) { y1 = 0; }
+ if (x2 < 0) { x2 = 0; }
+ if (y2 < 0) { y2 = 0; }
+ if (x1 >= w) { x1 = w - 1; }
+ if (y1 >= h) { y1 = h - 1; }
+ if (x2 >= w) { x2 = w - 1; }
+ if (y2 >= h) { y2 = h - 1; }
+
+ WriteableBitmapExtensions.DrawLine(context, w, h, x1, y1, x2, y1, color);
+ WriteableBitmapExtensions.DrawLine(context, w, h, x2, y1, x2, y2, color);
+ WriteableBitmapExtensions.DrawLine(context, w, h, x2, y2, x1, y2, color);
+ WriteableBitmapExtensions.DrawLine(context, w, h, x1, y2, x1, y1, color);
+ }
+
+ ///
+ /// Draws a rectangle.
+ /// x2 has to be greater than x1 and y2 has to be greater than y1.
+ ///
+ /// The BitmapContext.
+ /// The x-coordinate of the bounding rectangle's left side.
+ /// The y-coordinate of the bounding rectangle's top side.
+ /// The x-coordinate of the bounding rectangle's right side.
+ /// The y-coordinate of the bounding rectangle's bottom side.
+ /// The color.
+ public static void DrawRectangle(this BitmapContext context, int x1, int y1, int x2, int y2, Color color)
+ {
+ var col = WriteableBitmapExtensions.ConvertColor(color);
+ context.DrawRectangle(x1, y1, x2, y2, col);
+ }
+
+ ///
+ /// Draws an ellipse.
+ /// x2 has to be greater than x1 and y2 has to be greater than y1.
+ ///
+ /// The BitmapContext.
+ /// The x-coordinate of the bounding rectangle's left side.
+ /// The y-coordinate of the bounding rectangle's top side.
+ /// The x-coordinate of the bounding rectangle's right side.
+ /// The y-coordinate of the bounding rectangle's bottom side.
+ /// The color.
+ public static void DrawEllipse(this BitmapContext context, int x1, int y1, int x2, int y2, int color)
+ {
+ // Calc center and radius
+ int xr = (x2 - x1) >> 1;
+ int yr = (y2 - y1) >> 1;
+ int xc = x1 + xr;
+ int yc = y1 + yr;
+ context.DrawEllipseCentered(xc, yc, xr, yr, color);
+ }
+
+ ///
+ /// Draws an ellipse.
+ /// x2 has to be greater than x1 and y2 has to be greater than y1.
+ ///
+ /// The BitmapContext.
+ /// The x-coordinate of the bounding rectangle's left side.
+ /// The y-coordinate of the bounding rectangle's top side.
+ /// The x-coordinate of the bounding rectangle's right side.
+ /// The y-coordinate of the bounding rectangle's bottom side.
+ /// The color.
+ public static void DrawEllipse(this BitmapContext context, int x1, int y1, int x2, int y2, Color color)
+ {
+ var col = WriteableBitmapExtensions.ConvertColor(color);
+ context.DrawEllipse(x1, y1, x2, y2, col);
+ }
+
+ ///
+ /// A Fast Bresenham Type Algorithm For Drawing Ellipses http://homepage.smc.edu/kennedy_john/belipse.pdf
+ /// Uses a different parameter representation than DrawEllipse().
+ ///
+ /// The BitmapContext.
+ /// The x-coordinate of the ellipses center.
+ /// The y-coordinate of the ellipses center.
+ /// The radius of the ellipse in x-direction.
+ /// The radius of the ellipse in y-direction.
+ /// The color for the line.
+ public static void DrawEllipseCentered(this BitmapContext context, int xc, int yc, int xr, int yr, int color)
+ {
+ // Use refs for faster access (really important!) speeds up a lot!
+ var pixels = context.Pixels;
+ var w = context.Width;
+ var h = context.Height;
+
+ // Avoid endless loop
+ if (xr < 1 || yr < 1)
+ {
+ return;
+ }
+
+ // Init vars
+ int uh, lh, uy, ly, lx, rx;
+ int x = xr;
+ int y = 0;
+ int xrSqTwo = (xr * xr) << 1;
+ int yrSqTwo = (yr * yr) << 1;
+ int xChg = yr * yr * (1 - (xr << 1));
+ int yChg = xr * xr;
+ int err = 0;
+ int xStopping = yrSqTwo * xr;
+ int yStopping = 0;
+
+ // Draw first set of points counter clockwise where tangent line slope > -1.
+ while (xStopping > yStopping)
+ {
+ // Draw 4 quadrant points at once
+ uy = yc + y; // Upper half
+ ly = yc - y; // Lower half
+ if (uy < 0) uy = 0; // Clip
+ if (uy >= h) uy = h - 1; // ...
+ if (ly < 0) ly = 0;
+ if (ly >= h) ly = h - 1;
+ uh = uy * w; // Upper half
+ lh = ly * w; // Lower half
+
+ rx = xc + x;
+ lx = xc - x;
+ if (rx < 0) rx = 0; // Clip
+ if (rx >= w) rx = w - 1; // ...
+ if (lx < 0) lx = 0;
+ if (lx >= w) lx = w - 1;
+
+ // Draw line
+ if (uy >= 0 && uy < h)
+ {
+ pixels[rx + uh] = color; // Quadrant I (Actually an octant)
+ pixels[lx + uh] = color; // Quadrant II
+ }
+ if (ly >= 0 && ly < h)
+ {
+ pixels[rx + lh] = color; // Quadrant IV
+ pixels[lx + lh] = color; // Quadrant III
+ }
+
+ y++;
+ yStopping += xrSqTwo;
+ err += yChg;
+ yChg += xrSqTwo;
+ if ((xChg + (err << 1)) > 0)
+ {
+ x--;
+ xStopping -= yrSqTwo;
+ err += xChg;
+ xChg += yrSqTwo;
+ }
+ }
+
+ // ReInit vars
+ x = 0;
+ y = yr;
+ uy = yc + y; // Upper half
+ ly = yc - y; // Lower half
+ if (uy < 0) uy = 0; // Clip
+ if (uy >= h) uy = h - 1; // ...
+ if (ly < 0) ly = 0;
+ if (ly >= h) ly = h - 1;
+ uh = uy * w; // Upper half
+ lh = ly * w; // Lower half
+ xChg = yr * yr;
+ yChg = xr * xr * (1 - (yr << 1));
+ err = 0;
+ xStopping = 0;
+ yStopping = xrSqTwo * yr;
+
+ // Draw second set of points clockwise where tangent line slope < -1.
+ while (xStopping < yStopping)
+ {
+ // Draw 4 quadrant points at once
+ rx = xc + x;
+ lx = xc - x;
+ if (rx < 0) rx = 0; // Clip
+ if (rx >= w) rx = w - 1; // ...
+ if (lx < 0) lx = 0;
+ if (lx >= w) lx = w - 1;
+
+ // Draw line
+ if (uy >= 0 && uy < h)
+ {
+ pixels[rx + uh] = color; // Quadrant I (Actually an octant)
+ pixels[lx + uh] = color; // Quadrant II
+ }
+ if (ly >= 0 && ly < h)
+ {
+ pixels[rx + lh] = color; // Quadrant IV
+ pixels[lx + lh] = color; // Quadrant III
+ }
+
+ x++;
+ xStopping += yrSqTwo;
+ err += xChg;
+ xChg += yrSqTwo;
+ if ((yChg + (err << 1)) > 0)
+ {
+ y--;
+ uy = yc + y; // Upper half
+ ly = yc - y; // Lower half
+ if (uy < 0) uy = 0; // Clip
+ if (uy >= h) uy = h - 1; // ...
+ if (ly < 0) ly = 0;
+ if (ly >= h) ly = h - 1;
+ uh = uy * w; // Upper half
+ lh = ly * w; // Lower half
+ yStopping -= xrSqTwo;
+ err += yChg;
+ yChg += xrSqTwo;
+ }
+ }
+ }
+
+ ///
+ /// A Fast Bresenham Type Algorithm For Drawing Ellipses http://homepage.smc.edu/kennedy_john/belipse.pdf
+ /// Uses a different parameter representation than DrawEllipse().
+ ///
+ /// The BitmapContext.
+ /// The x-coordinate of the ellipses center.
+ /// The y-coordinate of the ellipses center.
+ /// The radius of the ellipse in x-direction.
+ /// The radius of the ellipse in y-direction.
+ /// The color for the line.
+ }
+
+ #endregion
+
+ #region Fill Methods
+
+ ///
+ /// Fills a rectangle.
+ ///
+ /// The BitmapContext.
+ /// The x-coordinate of the bounding rectangle's left side.
+ /// The y-coordinate of the bounding rectangle's top side.
+ /// The x-coordinate of the bounding rectangle's right side.
+ /// The y-coordinate of the bounding rectangle's bottom side.
+ /// The color.
+ /// True if alpha blending should be performed or false if not.
+ public static void FillRectangle(this BitmapContext context, int x1, int y1, int x2, int y2, int color, bool doAlphaBlend = false)
+ {
+ // Use refs for faster access (really important!) speeds up a lot!
+ var w = context.Width;
+ var h = context.Height;
+
+ int sa = ((color >> 24) & 0xff);
+ int sr = ((color >> 16) & 0xff);
+ int sg = ((color >> 8) & 0xff);
+ int sb = ((color) & 0xff);
+
+ bool noBlending = !doAlphaBlend || sa == 255;
+
+ var pixels = context.Pixels;
+
+ // Check boundaries
+ if ((x1 < 0 && x2 < 0) || (y1 < 0 && y2 < 0)
+ || (x1 >= w && x2 >= w) || (y1 >= h && y2 >= h))
+ {
+ return;
+ }
+
+ // Clamp boundaries
+ if (x1 < 0) { x1 = 0; }
+ if (y1 < 0) { y1 = 0; }
+ if (x2 < 0) { x2 = 0; }
+ if (y2 < 0) { y2 = 0; }
+ if (x1 > w) { x1 = w; }
+ if (y1 > h) { y1 = h; }
+ if (x2 > w) { x2 = w; }
+ if (y2 > h) { y2 = h; }
+
+ //swap values
+ if (y1 > y2)
+ {
+ y2 -= y1;
+ y1 += y2;
+ y2 = (y1 - y2);
+ }
+
+ // Fill first line
+ var startY = y1 * w;
+ var startYPlusX1 = startY + x1;
+ var endOffset = startY + x2;
+ for (var idx = startYPlusX1; idx < endOffset; idx++)
+ {
+ pixels[idx] = noBlending ? color : AlphaBlendColors(pixels[idx], sa, sr, sg, sb);
+ }
+
+ // Copy first line
+ var len = (x2 - x1);
+ for (var y = y1 + 1; y < y2; y++)
+ {
+ var offset = y * w + x1;
+ for (var i = 0; i < len; i++)
+ {
+ pixels[offset + i] = noBlending ? color : AlphaBlendColors(pixels[offset + i], sa, sr, sg, sb);
+ }
+ }
+ }
+
+ ///
+ /// Fills a rectangle.
+ ///
+ /// The BitmapContext.
+ /// The x-coordinate of the bounding rectangle's left side.
+ /// The y-coordinate of the bounding rectangle's top side.
+ /// The x-coordinate of the bounding rectangle's right side.
+ /// The y-coordinate of the bounding rectangle's bottom side.
+ /// The color.
+ /// True if alpha blending should be performed or false if not.
+ public static void FillRectangle(this BitmapContext context, int x1, int y1, int x2, int y2, Color color, bool doAlphaBlend = false)
+ {
+ var col = WriteableBitmapExtensions.ConvertColor(color);
+ context.FillRectangle(x1, y1, x2, y2, col, doAlphaBlend);
+ }
+
+ ///
+ /// Fills an ellipse.
+ ///
+ /// The BitmapContext.
+ /// The x-coordinate of the bounding rectangle's left side.
+ /// The y-coordinate of the bounding rectangle's top side.
+ /// The x-coordinate of the bounding rectangle's right side.
+ /// The y-coordinate of the bounding rectangle's bottom side.
+ /// The color.
+ /// True if alpha blending should be performed or false if not.
+ public static void FillEllipse(this BitmapContext context, int x1, int y1, int x2, int y2, int color, bool doAlphaBlend = false)
+ {
+ // Calc center and radius
+ int xr = (x2 - x1) >> 1;
+ int yr = (y2 - y1) >> 1;
+ int xc = x1 + xr;
+ int yc = y1 + yr;
+ context.FillEllipseCentered(xc, yc, xr, yr, color, doAlphaBlend);
+ }
+
+ ///
+ /// A Fast Bresenham Type Algorithm For Drawing filled ellipses
+ /// Uses a different parameter representation than FillEllipse()
+ ///
+ /// The BitmapContext.
+ /// The x-coordinate of the ellipses center.
+ /// The y-coordinate of the ellipses center.
+ /// The radius of the ellipse in x-direction.
+ /// The radius of the ellipse in y-direction.
+ /// The color.
+ /// True if alpha blending should be performed or false if not.
+ public static void FillEllipseCentered(this BitmapContext context, int xc, int yc, int xr, int yr, int color, bool doAlphaBlend = false)
+ {
+ // Use refs for faster access (really important!) speeds up a lot!
+ var pixels = context.Pixels;
+ int w = context.Width;
+ int h = context.Height;
+
+ // Avoid endless loop
+ if (xr < 1 || yr < 1)
+ {
+ return;
+ }
+
+ // Skip completly outside objects
+ if (xc - xr >= w || xc + xr < 0 || yc - yr >= h || yc + yr < 0)
+ {
+ return;
+ }
+
+ // Init vars
+ int uh, lh, uy, ly, lx, rx;
+ int x = xr;
+ int y = 0;
+ int xrSqTwo = (xr * xr) << 1;
+ int yrSqTwo = (yr * yr) << 1;
+ int xChg = yr * yr * (1 - (xr << 1));
+ int yChg = xr * xr;
+ int err = 0;
+ int xStopping = yrSqTwo * xr;
+ int yStopping = 0;
+
+ int sa = ((color >> 24) & 0xff);
+ int sr = ((color >> 16) & 0xff);
+ int sg = ((color >> 8) & 0xff);
+ int sb = ((color) & 0xff);
+
+ bool noBlending = !doAlphaBlend || sa == 255;
+
+ // Draw first set of points counter clockwise where tangent line slope > -1.
+ while (xStopping >= yStopping)
+ {
+ // Draw 4 quadrant points at once
+ // Upper half
+ uy = yc + y;
+ // Lower half
+ ly = yc - y;
+
+ // Clip
+ if (uy < 0) uy = 0;
+ if (uy >= h) uy = h - 1;
+ if (ly < 0) ly = 0;
+ if (ly >= h) ly = h - 1;
+
+ // Upper half
+ uh = uy * w;
+ // Lower half
+ lh = ly * w;
+
+ rx = xc + x;
+ lx = xc - x;
+
+ // Clip
+ if (rx < 0) rx = 0;
+ if (rx >= w) rx = w - 1;
+ if (lx < 0) lx = 0;
+ if (lx >= w) lx = w - 1;
+
+ // Draw line
+ if (uy >= 0 && uy < h)
+ {
+ // Draw horizontal line in upper half
+ for (var i = lx; i <= rx; i++)
+ {
+ pixels[i + uh] = noBlending ? color : AlphaBlendColors(pixels[i + uh], sa, sr, sg, sb);
+ }
+ }
+ if (ly >= 0 && ly < h && ly != uy) // Don't overdraw horizontl lines if uy == ly
+ {
+ // Draw horizontal line in lower half
+ for (var i = lx; i <= rx; i++)
+ {
+ pixels[i + lh] = noBlending ? color : AlphaBlendColors(pixels[i + lh], sa, sr, sg, sb);
+ }
+ }
+
+ y++;
+ yStopping += xrSqTwo;
+ err += yChg;
+ yChg += xrSqTwo;
+ if ((xChg + (err << 1)) > 0)
+ {
+ x--;
+ xStopping -= yrSqTwo;
+ err += xChg;
+ xChg += yrSqTwo;
+ }
+ }
+
+ // ReInit vars
+ x = 0;
+ y = yr;
+
+ // Upper half
+ uy = yc + y;
+ // Lower half
+ ly = yc - y;
+
+ // Clip
+ if (uy < 0) uy = 0;
+ if (uy >= h) uy = h - 1;
+ if (ly < 0) ly = 0;
+ if (ly >= h) ly = h - 1;
+
+ // Upper half
+ uh = uy * w;
+ // Lower half
+ lh = ly * w;
+
+ xChg = yr * yr;
+ yChg = xr * xr * (1 - (yr << 1));
+ err = 0;
+ xStopping = 0;
+ yStopping = xrSqTwo * yr;
+
+ // Draw second set of points clockwise where tangent line slope < -1.
+ while (xStopping <= yStopping)
+ {
+ // Draw 4 quadrant points at once
+ rx = xc + x;
+ lx = xc - x;
+
+ // Clip
+ if (rx < 0) rx = 0;
+ if (rx >= w) rx = w - 1;
+ if (lx < 0) lx = 0;
+ if (lx >= w) lx = w - 1;
+
+ // Draw line
+ if (uy >= 0 && uy < h)
+ {
+ // Draw horizontal line in upper half
+ for (var i = lx; i <= rx; i++)
+ {
+ pixels[i + uh] = noBlending ? color : AlphaBlendColors(pixels[i + uh], sa, sr, sg, sb);
+ }
+ }
+ if (ly >= 0 && ly < h && ly != uy) // Don't overdraw horizontl lines if uy == ly
+ {
+ // Draw horizontal line in lower half
+ for (var i = lx; i <= rx; i++)
+ {
+ pixels[i + lh] = noBlending ? color : AlphaBlendColors(pixels[i + lh], sa, sr, sg, sb);
+ }
+ }
+
+ x++;
+ xStopping += yrSqTwo;
+ err += xChg;
+ xChg += yrSqTwo;
+ if ((yChg + (err << 1)) > 0)
+ {
+ y--;
+ // Upper half
+ uy = yc + y;
+ // Lower half
+ ly = yc - y;
+
+ // Clip
+ if (uy < 0) uy = 0;
+ if (uy >= h) uy = h - 1;
+ if (ly < 0) ly = 0;
+ if (ly >= h) ly = h - 1;
+
+ // Upper half
+ uh = uy * w;
+ // Lower half
+ lh = ly * w;
+ yStopping -= xrSqTwo;
+ err += yChg;
+ yChg += xrSqTwo;
+ }
+ }
+ }
+
+ ///
+ /// A Fast Bresenham Type Algorithm For Drawing filled ellipses
+ /// Uses a different parameter representation than FillEllipse()
+ ///
+ /// The BitmapContext.
+ /// The x-coordinate of the ellipses center.
+ /// The y-coordinate of the ellipses center.
+ /// The radius of the ellipse in x-direction.
+ /// The radius of the ellipse in y-direction.
+ /// The color.
+ /// True if alpha blending should be performed or false if not.
+ public static void FillEllipseCentered(this BitmapContext context, int xc, int yc, int xr, int yr, Color color, bool doAlphaBlend = false)
+ {
+ var col = WriteableBitmapExtensions.ConvertColor(color);
+ context.FillEllipseCentered(xc, yc, xr, yr, col, doAlphaBlend);
+ }
+
+ #endregion
+
+ #region Common Methods
+
+ ///
+ /// Alpha blends the specified source color with the destination color.
+ ///
+ /// The destination color.
+ /// The source alpha value.
+ /// The source red value.
+ /// The source green value.
+ /// The source blue value.
+ /// The alpha blended color.
+ private static int AlphaBlendColors(int pixel, int sa, int sr, int sg, int sb)
+ {
+ // Alpha blend
+ int destPixel = pixel;
+ int da = ((destPixel >> 24) & 0xff);
+ int dr = ((destPixel >> 16) & 0xff);
+ int dg = ((destPixel >> 8) & 0xff);
+ int db = ((destPixel) & 0xff);
+
+ destPixel = ((sa + (((da * (255 - sa)) * 0x8081) >> 23)) << 24) |
+ ((sr + (((dr * (255 - sa)) * 0x8081) >> 23)) << 16) |
+ ((sg + (((dg * (255 - sa)) * 0x8081) >> 23)) << 8) |
+ ((sb + (((db * (255 - sa)) * 0x8081) >> 23)));
+
+ return destPixel;
+ }
+
+ ///
+ /// Copies the specified region from the source BitmapContext to the destination BitmapContext.
+ ///
+ /// The destination context.
+ /// The rectangle in the destination that should be filled with the source content.
+ /// The source context.
+ /// The rectangle in the source that should be copied.
+ /// The width of the source bitmap.
+ public static void Blit(this BitmapContext destContext, Rect destRect, BitmapContext srcContext, Rect sourceRect, int sourceWidth)
+ {
+ // Simple parameter validation
+ int dw = (int)destRect.Width;
+ int dh = (int)destRect.Height;
+ int sw = (int)sourceRect.Width;
+ int sh = (int)sourceRect.Height;
+ int dpw = destContext.Width;
+ int dph = destContext.Height;
+
+ // Calculate actual widths to copy
+ dw = Math.Min(dw, dpw - (int)destRect.X);
+ dh = Math.Min(dh, dph - (int)destRect.Y);
+ sw = Math.Min(sw, sourceWidth - (int)sourceRect.X);
+ sh = Math.Min(sh, srcContext.Length / sourceWidth - (int)sourceRect.Y);
+
+ // Check if nothing to do
+ if (sw <= 0 || sh <= 0 || dw <= 0 || dh <= 0) return;
+
+ // If width or height is different, use scaling
+ if (sw != dw || sh != dh)
+ {
+ WriteableBitmapExtensions.BlitScaled(destContext, dpw, dph, destRect, srcContext, sourceRect, sourceWidth);
+ return;
+ }
+
+ // Calculate start index in source and destination
+ int xs0 = (int)sourceRect.X;
+ int ys0 = (int)sourceRect.Y;
+ int xd0 = (int)destRect.X;
+ int yd0 = (int)destRect.Y;
+
+ var srcPixels = srcContext.Pixels;
+ var destPixels = destContext.Pixels;
+ int sd = sourceWidth;
+ int dd = dpw;
+
+ // Copy identical sized regions
+ for (int y = 0; y < dh; y++)
+ {
+ int srcIdx = ((ys0 + y) * sd) + xs0;
+ int destIdx = ((yd0 + y) * dd) + xd0;
+
+ for (int x = 0; x < dw; x++)
+ {
+ destPixels[destIdx + x] = srcPixels[srcIdx + x];
+ }
+ }
+ }
+
+ ///
+ /// Copies the specified region from the source BitmapContext to the destination BitmapContext.
+ ///
+ /// The destination context.
+ /// The position in the destination context where the source should be copied to.
+ /// The source context.
+ /// The rectangle in the source that should be copied.
+ /// The width of the source bitmap.
+ public static void Blit(this BitmapContext destContext, Point destPosition, BitmapContext srcContext, Rect sourceRect, int sourceWidth)
+ {
+ Rect destRect = new Rect(destPosition, new Size(sourceRect.Width, sourceRect.Height));
+ destContext.Blit(destRect, srcContext, sourceRect, sourceWidth);
+ }
+
+ #region Transform Methods
+
+ ///
+ /// Flips (mirrors) the BitmapContext.
+ ///
+ /// The BitmapContext.
+ /// The flip mode.
+ /// A new BitmapContext containing the flipped image data.
+ public static BitmapContext Flip(this BitmapContext context, FlipMode flipMode)
+ {
+ // Use refs for faster access (really important!) speeds up a lot!
+ var w = context.Width;
+ var h = context.Height;
+ var p = context.Pixels;
+ var result = new int[p.Length];
+ var i = 0;
+
+ if (flipMode == FlipMode.Horizontal)
+ {
+ for (var y = h - 1; y >= 0; y--)
+ {
+ for (var x = 0; x < w; x++)
+ {
+ var srcInd = y * w + x;
+ result[i] = p[srcInd];
+ i++;
+ }
+ }
+ }
+ else if (flipMode == FlipMode.Vertical)
+ {
+ for (var y = 0; y < h; y++)
+ {
+ for (var x = w - 1; x >= 0; x--)
+ {
+ var srcInd = y * w + x;
+ result[i] = p[srcInd];
+ i++;
+ }
+ }
+ }
+
+ return new BitmapContext(result, w, h, context.Format);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Source/WriteableBitmapEx/WriteableBitmapEx.csproj b/Source/WriteableBitmapEx/WriteableBitmapEx.csproj
index a9d64b6..a8888bd 100644
--- a/Source/WriteableBitmapEx/WriteableBitmapEx.csproj
+++ b/Source/WriteableBitmapEx/WriteableBitmapEx.csproj
@@ -70,7 +70,8 @@
Properties\GlobalAssemblyInfo.cs
-
+
+