#region Header // // Project: WriteableBitmapEx - WriteableBitmap extensions // Description: Collection of internal anti-aliasing helper methods for the WriteableBitmap class. // // Changed by: $Author: unknown $ // Changed on: $Date: 2015-02-24 20:36:41 +0100 (Di, 24 Feb 2015) $ // Changed in: $Revision: 112951 $ // Project: $URL: https://writeablebitmapex.svn.codeplex.com/svn/trunk/Source/WriteableBitmapEx/WriteableBitmapTransformationExtensions.cs $ // Id: $Id: WriteableBitmapTransformationExtensions.cs 112951 2015-02-24 19:36:41Z 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 using Windows.Foundation; using Windows.UI.Xaml.Media.Imaging; using Windows.UI; namespace Windows.UI.Xaml.Media.Imaging #else namespace System.Windows.Media.Imaging #endif { /// /// Collection of draw extension methods for the Silverlight WriteableBitmap class. /// internal #if !SILVERLIGHT unsafe #endif static partial class WriteableBitmapExtensions { private static readonly int[] leftEdgeX = new int[8192]; private static readonly int[] rightEdgeX = new int[8192]; private static void AAWidthLine(int width, int height, BitmapContext context, float x1, float y1, float x2, float y2, float lineWidth, Int32 color) { // Perform cohen-sutherland clipping if either point is out of the viewport if (!CohenSutherlandLineClip(new Rect(0, 0, width, height), ref x1, ref y1, ref x2, ref y2)) return; if (lineWidth <= 0) return; var buffer = context.Pixels; if (y1 > y2) { Swap(ref x1, ref x2); Swap(ref y1, ref y2); } if (x1 == x2) { x1 -= (int)lineWidth / 2; x2 += (int)lineWidth / 2; if (x1 < 0) x1 = 0; if (x2 < 0) return; if (x1 >= width) return; if (x2 >= width) x2 = width - 1; if (y1 >= height || y2 < 0) return; if (y1 < 0) y1 = 0; if (y2 >= height) y2 = height - 1; for (var x = (int)x1; x <= x2; x++) { for (var y = (int)y1; y <= y2; y++) { var a = (byte)((color & 0xff000000) >> 24); var r = (byte)((color & 0x00ff0000) >> 16); var g = (byte)((color & 0x0000ff00) >> 8); var b = (byte)((color & 0x000000ff) >> 0); byte rs, gs, bs; byte rd, gd, bd; int d; rs = r; gs = g; bs = b; d = buffer[y * width + x]; rd = (byte)((d & 0x00ff0000) >> 16); gd = (byte)((d & 0x0000ff00) >> 8); bd = (byte)((d & 0x000000ff) >> 0); rd = (byte)((rs * a + rd * (0xff - a)) >> 8); gd = (byte)((gs * a + gd * (0xff - a)) >> 8); bd = (byte)((bs * a + bd * (0xff - a)) >> 8); buffer[y * width + x] = (0xff << 24) | (rd << 16) | (gd << 8) | (bd << 0); } } return; } if (y1 == y2) { if (x1 > x2) Swap(ref x1, ref x2); y1 -= (int)lineWidth / 2; y2 += (int)lineWidth / 2; if (y1 < 0) y1 = 0; if (y2 < 0) return; if (y1 >= height) return; if (y2 >= height) x2 = height - 1; if (x1 >= width || y2 < 0) return; if (x1 < 0) x1 = 0; if (x2 >= width) x2 = width - 1; for (var x = (int)x1; x <= x2; x++) { for (var y = (int)y1; y <= y2; y++) { var a = (byte)((color & 0xff000000) >> 24); var r = (byte)((color & 0x00ff0000) >> 16); var g = (byte)((color & 0x0000ff00) >> 8); var b = (byte)((color & 0x000000ff) >> 0); Byte rs, gs, bs; Byte rd, gd, bd; Int32 d; rs = r; gs = g; bs = b; d = buffer[y * width + x]; rd = (byte)((d & 0x00ff0000) >> 16); gd = (byte)((d & 0x0000ff00) >> 8); bd = (byte)((d & 0x000000ff) >> 0); rd = (byte)((rs * a + rd * (0xff - a)) >> 8); gd = (byte)((gs * a + gd * (0xff - a)) >> 8); bd = (byte)((bs * a + bd * (0xff - a)) >> 8); buffer[y * width + x] = (0xff << 24) | (rd << 16) | (gd << 8) | (bd << 0); } } return; } y1 += 1; y2 += 1; float slope = (y2 - y1) / (x2 - x1); float islope = (x2 - x1) / (y2 - y1); float m = slope; float w = lineWidth; float dx = x2 - x1; float dy = y2 - y1; var xtot = (float)(w * dy / Math.Sqrt(dx * dx + dy * dy)); var ytot = (float)(w * dx / Math.Sqrt(dx * dx + dy * dy)); float sm = dx * dy / (dx * dx + dy * dy); // Center it. x1 += xtot / 2; y1 -= ytot / 2; x2 += xtot / 2; y2 -= ytot / 2; // // float sx = -xtot; float sy = +ytot; var ix1 = (int)x1; var iy1 = (int)y1; var ix2 = (int)x2; var iy2 = (int)y2; var ix3 = (int)(x1 + sx); var iy3 = (int)(y1 + sy); var ix4 = (int)(x2 + sx); var iy4 = (int)(y2 + sy); if (lineWidth == 2) { if (Math.Abs(dy) < Math.Abs(dx)) { if (x1 < x2) { iy3 = iy1 + 2; iy4 = iy2 + 2; } else { iy1 = iy3 + 2; iy2 = iy4 + 2; } } else { ix1 = ix3 + 2; ix2 = ix4 + 2; } } int starty = Math.Min(Math.Min(iy1, iy2), Math.Min(iy3, iy4)); int endy = Math.Max(Math.Max(iy1, iy2), Math.Max(iy3, iy4)); if (starty < 0) starty = -1; if (endy >= height) endy = height + 1; for (int y = starty + 1; y < endy - 1; y++) { leftEdgeX[y] = -1 << 16; rightEdgeX[y] = 1 << 16 - 1; } AALineQ1(width, height, context, ix1, iy1, ix2, iy2, color, sy > 0, false); AALineQ1(width, height, context, ix3, iy3, ix4, iy4, color, sy < 0, true); if (lineWidth > 1) { AALineQ1(width, height, context, ix1, iy1, ix3, iy3, color, true, sy > 0); AALineQ1(width, height, context, ix2, iy2, ix4, iy4, color, false, sy < 0); } if (x1 < x2) { if (iy2 >= 0 && iy2 < height) rightEdgeX[iy2] = Math.Min(ix2, rightEdgeX[iy2]); if (iy3 >= 0 && iy3 < height) leftEdgeX[iy3] = Math.Max(ix3, leftEdgeX[iy3]); } else { if (iy1 >= 0 && iy1 < height) rightEdgeX[iy1] = Math.Min(ix1, rightEdgeX[iy1]); if (iy4 >= 0 && iy4 < height) leftEdgeX[iy4] = Math.Max(ix4, leftEdgeX[iy4]); } //return; for (int y = starty + 1; y < endy - 1; y++) { leftEdgeX[y] = Math.Max(leftEdgeX[y], 0); rightEdgeX[y] = Math.Min(rightEdgeX[y], width - 1); for (int x = leftEdgeX[y]; x <= rightEdgeX[y]; x++) { var a = (byte)((color & 0xff000000) >> 24); var r = (byte)((color & 0x00ff0000) >> 16); var g = (byte)((color & 0x0000ff00) >> 8); var b = (byte)((color & 0x000000ff) >> 0); Byte rs, gs, bs; Byte rd, gd, bd; Int32 d; rs = r; gs = g; bs = b; d = buffer[y * width + x]; rd = (byte)((d & 0x00ff0000) >> 16); gd = (byte)((d & 0x0000ff00) >> 8); bd = (byte)((d & 0x000000ff) >> 0); rd = (byte)((rs * a + rd * (0xff - a)) >> 8); gd = (byte)((gs * a + gd * (0xff - a)) >> 8); bd = (byte)((bs * a + bd * (0xff - a)) >> 8); buffer[y * width + x] = (0xff << 24) | (rd << 16) | (gd << 8) | (bd << 0); } } } private static void Swap(ref T a, ref T b) { T t = a; a = b; b = t; } private static void AALineQ1(int width, int height, BitmapContext context, int x1, int y1, int x2, int y2, Int32 color, bool minEdge, bool leftEdge) { Byte off = 0; if (minEdge) off = 0xff; if (x1 == x2) return; if (y1 == y2) return; var buffer = context.Pixels; if (y1 > y2) { Swap(ref x1, ref x2); Swap(ref y1, ref y2); } int deltax = (x2 - x1); int deltay = (y2 - y1); if (x1 > x2) deltax = (x1 - x2); int x = x1; int y = y1; UInt16 m = 0; if (deltax > deltay) m = (ushort)(((deltay << 16) / deltax)); else m = (ushort)(((deltax << 16) / deltay)); UInt16 e = 0; var a = (byte)((color & 0xff000000) >> 24); var r = (byte)((color & 0x00ff0000) >> 16); var g = (byte)((color & 0x0000ff00) >> 8); var b = (byte)((color & 0x000000ff) >> 0); Byte rs, gs, bs; Byte rd, gd, bd; Int32 d; Byte ta = a; e = 0; if (deltax >= deltay) { while (deltax-- != 0) { if ((UInt16)(e + m) <= e) // Roll { y++; } e += m; if (x1 < x2) x++; else x--; if (y < 0 || y >= height) continue; if (leftEdge) leftEdgeX[y] = Math.Max(x + 1, leftEdgeX[y]); else rightEdgeX[y] = Math.Min(x - 1, rightEdgeX[y]); if (x < 0 || x >= width) continue; // ta = (byte)((a * (UInt16)(((((UInt16)(e >> 8))) ^ off))) >> 8); rs = r; gs = g; bs = b; d = buffer[y * width + x]; rd = (byte)((d & 0x00ff0000) >> 16); gd = (byte)((d & 0x0000ff00) >> 8); bd = (byte)((d & 0x000000ff) >> 0); rd = (byte)((rs * ta + rd * (0xff - ta)) >> 8); gd = (byte)((gs * ta + gd * (0xff - ta)) >> 8); bd = (byte)((bs * ta + bd * (0xff - ta)) >> 8); buffer[y * width + x] = (0xff << 24) | (rd << 16) | (gd << 8) | (bd << 0); // } } else { off ^= 0xff; while (--deltay != 0) { if ((UInt16)(e + m) <= e) // Roll { if (x1 < x2) x++; else x--; } e += m; y++; if (x < 0 || x >= width) continue; if (y < 0 || y >= height) continue; // ta = (byte)((a * (UInt16)(((((UInt16)(e >> 8))) ^ off))) >> 8); rs = r; gs = g; bs = b; d = buffer[y * width + x]; rd = (byte)((d & 0x00ff0000) >> 16); gd = (byte)((d & 0x0000ff00) >> 8); bd = (byte)((d & 0x000000ff) >> 0); rd = (byte)((rs * ta + rd * (0xff - ta)) >> 8); gd = (byte)((gs * ta + gd * (0xff - ta)) >> 8); bd = (byte)((bs * ta + bd * (0xff - ta)) >> 8); buffer[y * width + x] = (0xff << 24) | (rd << 16) | (gd << 8) | (bd << 0); if (leftEdge) leftEdgeX[y] = x + 1; else rightEdgeX[y] = x - 1; } } } } }