#region Header
//
// Project: WriteableBitmapEx - WriteableBitmap extensions
// Description: Collection of extension methods for the WriteableBitmap class.
//
// Changed by: $Author: unknown $
// Changed on: $Date: 2015-07-20 11:44:36 +0200 (Mo, 20 Jul 2015) $
// Changed in: $Revision: 114480 $
// Project: $URL: https://writeablebitmapex.svn.codeplex.com/svn/trunk/Source/WriteableBitmapEx/WriteableBitmapShapeExtensions.cs $
// Id: $Id: WriteableBitmapShapeExtensions.cs 114480 2015-07-20 09:44:36Z unknown $
//
//
// 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
namespace Windows.UI.Xaml.Media.Imaging
#else
namespace System.Windows.Media.Imaging
#endif
{
///
/// Collection of extension methods for the WriteableBitmap class.
///
internal
#if WPF
unsafe
#endif
static partial class WriteableBitmapExtensions
{
#region Methods
#region Draw Shapes
#region Polyline, Triangle, Quad
///
/// Draws a polyline. Add the first point also at the end of the array if the line should be closed.
///
/// The WriteableBitmap.
/// The points of the polyline in x and y pairs, therefore the array is interpreted as (x1, y1, x2, y2, ..., xn, yn).
/// The color for the line.
internal static void DrawPolyline(this WriteableBitmap bmp, int[] points, Color color)
{
var col = ConvertColor(color);
bmp.DrawPolyline(points, col);
}
///
/// Draws a polyline anti-aliased. Add the first point also at the end of the array if the line should be closed.
///
/// The WriteableBitmap.
/// The points of the polyline in x and y pairs, therefore the array is interpreted as (x1, y1, x2, y2, ..., xn, yn).
/// The color for the line.
internal static void DrawPolyline(this WriteableBitmap bmp, int[] points, int color)
{
using (var context = bmp.GetBitmapContext())
{
// Use refs for faster access (really important!) speeds up a lot!
var w = context.Width;
var h = context.Height;
var x1 = points[0];
var y1 = points[1];
for (var i = 2; i < points.Length; i += 2)
{
var x2 = points[i];
var y2 = points[i + 1];
DrawLine(context, w, h, x1, y1, x2, y2, color);
x1 = x2;
y1 = y2;
}
}
}
///
/// Draws a polyline. Add the first point also at the end of the array if the line should be closed.
///
/// The WriteableBitmap.
/// The points of the polyline in x and y pairs, therefore the array is interpreted as (x1, y1, x2, y2, ..., xn, yn).
/// The color for the line.
internal static void DrawPolylineAa(this WriteableBitmap bmp, int[] points, Color color)
{
var col = ConvertColor(color);
bmp.DrawPolylineAa(points, col);
}
///
/// Draws a polyline anti-aliased. Add the first point also at the end of the array if the line should be closed.
///
/// The WriteableBitmap.
/// The points of the polyline in x and y pairs, therefore the array is interpreted as (x1, y1, x2, y2, ..., xn, yn).
/// The color for the line.
internal static void DrawPolylineAa(this WriteableBitmap bmp, int[] points, int color)
{
using (var context = bmp.GetBitmapContext())
{
// Use refs for faster access (really important!) speeds up a lot!
var w = context.Width;
var h = context.Height;
var x1 = points[0];
var y1 = points[1];
for (var i = 2; i < points.Length; i += 2)
{
var x2 = points[i];
var y2 = points[i + 1];
DrawLineAa(context, w, h, x1, y1, x2, y2, color);
x1 = x2;
y1 = y2;
}
}
}
///
/// Draws a triangle.
///
/// The WriteableBitmap.
/// The x-coordinate of the 1st point.
/// The y-coordinate of the 1st point.
/// The x-coordinate of the 2nd point.
/// The y-coordinate of the 2nd point.
/// The x-coordinate of the 3rd point.
/// The y-coordinate of the 3rd point.
/// The color.
internal static void DrawTriangle(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, int x3, int y3, Color color)
{
var col = ConvertColor(color);
bmp.DrawTriangle(x1, y1, x2, y2, x3, y3, col);
}
///
/// Draws a triangle.
///
/// The WriteableBitmap.
/// The x-coordinate of the 1st point.
/// The y-coordinate of the 1st point.
/// The x-coordinate of the 2nd point.
/// The y-coordinate of the 2nd point.
/// The x-coordinate of the 3rd point.
/// The y-coordinate of the 3rd point.
/// The color.
internal static void DrawTriangle(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, int x3, int y3, int color)
{
using (var context = bmp.GetBitmapContext())
{
// Use refs for faster access (really important!) speeds up a lot!
int w = context.Width;
int h = context.Height;
DrawLine(context, w, h, x1, y1, x2, y2, color);
DrawLine(context, w, h, x2, y2, x3, y3, color);
DrawLine(context, w, h, x3, y3, x1, y1, color);
}
}
///
/// Draws a quad.
///
/// The WriteableBitmap.
/// The x-coordinate of the 1st point.
/// The y-coordinate of the 1st point.
/// The x-coordinate of the 2nd point.
/// The y-coordinate of the 2nd point.
/// The x-coordinate of the 3rd point.
/// The y-coordinate of the 3rd point.
/// The x-coordinate of the 4th point.
/// The y-coordinate of the 4th point.
/// The color.
internal static void DrawQuad(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, Color color)
{
var col = ConvertColor(color);
bmp.DrawQuad(x1, y1, x2, y2, x3, y3, x4, y4, col);
}
///
/// Draws a quad.
///
/// The WriteableBitmap.
/// The x-coordinate of the 1st point.
/// The y-coordinate of the 1st point.
/// The x-coordinate of the 2nd point.
/// The y-coordinate of the 2nd point.
/// The x-coordinate of the 3rd point.
/// The y-coordinate of the 3rd point.
/// The x-coordinate of the 4th point.
/// The y-coordinate of the 4th point.
/// The color.
internal static void DrawQuad(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int color)
{
using (var context = bmp.GetBitmapContext())
{
// Use refs for faster access (really important!) speeds up a lot!
int w = context.Width;
int h = context.Height;
DrawLine(context, w, h, x1, y1, x2, y2, color);
DrawLine(context, w, h, x2, y2, x3, y3, color);
DrawLine(context, w, h, x3, y3, x4, y4, color);
DrawLine(context, w, h, x4, y4, x1, y1, color);
}
}
#endregion
#region Rectangle
///
/// Draws a rectangle.
/// x2 has to be greater than x1 and y2 has to be greater than y1.
///
/// The WriteableBitmap.
/// 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.
internal static void DrawRectangle(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, Color color)
{
var col = ConvertColor(color);
bmp.DrawRectangle(x1, y1, x2, y2, col);
}
///
/// Draws a rectangle.
/// x2 has to be greater than x1 and y2 has to be greater than y1.
///
/// The WriteableBitmap.
/// 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.
internal static void DrawRectangle(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, int color)
{
using (var context = bmp.GetBitmapContext())
{
// Use refs for faster access (really important!) speeds up a lot!
var w = context.Width;
var h = context.Height;
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 - 1; }
if (y1 >= h) { y1 = h - 1; }
if (x2 >= w) { x2 = w - 1; }
if (y2 >= h) { y2 = h - 1; }
var startY = y1 * w;
var endY = y2 * w;
var offset2 = endY + x1;
var endOffset = startY + x2;
var startYPlusX1 = startY + x1;
// top and bottom horizontal scanlines
for (var x = startYPlusX1; x <= endOffset; x++)
{
pixels[x] = color; // top horizontal line
pixels[offset2] = color; // bottom horizontal line
offset2++;
}
// offset2 == endY + x2
// vertical scanlines
endOffset = startYPlusX1 + w;
offset2 -= w;
for (var y = startY + x2 + w; y <= offset2; y += w)
{
pixels[y] = color; // right vertical line
pixels[endOffset] = color; // left vertical line
endOffset += w;
}
}
}
#endregion
#region Ellipse
///
/// A Fast Bresenham Type Algorithm For Drawing Ellipses http://homepage.smc.edu/kennedy_john/belipse.pdf
/// x2 has to be greater than x1 and y2 has to be greater than y1.
///
/// The WriteableBitmap.
/// 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 for the line.
internal static void DrawEllipse(this WriteableBitmap bmp, int x1, int y1, int x2, int y2, Color color)
{
var col = ConvertColor(color);
bmp.DrawEllipse(x1, y1, x2, y2, col);
}
///
/// A Fast Bresenham Type Algorithm For Drawing Ellipses http://homepage.smc.edu/kennedy_john/belipse.pdf
/// x2 has to be greater than x1 and y2 has to be greater than y1.
///
/// The WriteableBitmap.
/// 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 for the line.
internal static void DrawEllipse(this WriteableBitmap bmp, 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;
bmp.DrawEllipseCentered(xc, yc, xr, yr, color);
}
///
/// A Fast Bresenham Type Algorithm For Drawing Ellipses http://homepage.smc.edu/kennedy_john/belipse.pdf
/// Uses a different parameter representation than DrawEllipse().
///
/// The WriteableBitmap.
/// 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.
internal static void DrawEllipseCentered(this WriteableBitmap bmp, int xc, int yc, int xr, int yr, Color color)
{
var col = ConvertColor(color);
bmp.DrawEllipseCentered(xc, yc, xr, yr, 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 WriteableBitmap.
/// 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.
internal static void DrawEllipseCentered(this WriteableBitmap bmp, int xc, int yc, int xr, int yr, int color)
{
// Use refs for faster access (really important!) speeds up a lot!
using (var context = bmp.GetBitmapContext())
{
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;
pixels[rx + uh] = color; // Quadrant I (Actually an octant)
pixels[lx + uh] = color; // Quadrant II
pixels[lx + lh] = color; // Quadrant III
pixels[rx + lh] = color; // Quadrant IV
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;
pixels[rx + uh] = color; // Quadrant I (Actually an octant)
pixels[lx + uh] = color; // Quadrant II
pixels[lx + lh] = color; // Quadrant III
pixels[rx + lh] = color; // Quadrant IV
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;
}
}
}
}
#endregion
#endregion
#endregion
}
}