/// <summary> /// Run a basic Anti-Aliasing Algorithm on the specified image. /// </summary> /// <param name="o">The image to Anti-Alias.</param> /// <returns>The Anti-Aliased Image.</returns> public static Image AntiAlias(Image i) { Image o = new Image(i.Width, i.Height); for (uint y = 0; y < i.Height; y++) { for (uint x = 0; x < i.Width; x++) { uint R = 0, G = 0, B = 0; byte divBy = 0; Pixel p = i.GetPixel(x, y); R += p.R; G += p.G; B += p.B; divBy++; p = i.GetPixel(x - 1, y - 1); if (!p.Empty) { R += p.R; G += p.G; B += p.B; divBy++; } p = i.GetPixel(x, y - 1); if (!p.Empty) { R += p.R; G += p.G; B += p.B; divBy++; } p = i.GetPixel(x + 1, y - 1); if (!p.Empty) { R += p.R; G += p.G; B += p.B; divBy++; } p = i.GetPixel(x - 1, y); if (!p.Empty) { R += p.R; G += p.G; B += p.B; divBy++; } p = i.GetPixel(x + 1, y); if (!p.Empty) { R += p.R; G += p.G; B += p.B; divBy++; } p = i.GetPixel(x - 1, y + 1); if (!p.Empty) { R += p.R; G += p.G; B += p.B; divBy++; } p = i.GetPixel(x, y + 1); if (!p.Empty) { R += p.R; G += p.G; B += p.B; divBy++; } p = i.GetPixel(x + 1, y + 1); if (!p.Empty) { R += p.R; G += p.G; B += p.B; divBy++; } o.SetPixel(x, y, new Pixel(((byte)(R / divBy)), ((byte)(G / divBy)), ((byte)(B / divBy)), 255)); } } i.Dispose(); return(o); }
private static Image ResizeBicubic(Image i, Vec2 outSize) { Image o = new Image(outSize.X, outSize.Y); int height = i.Height, width = i.Width, newHeight = o.Height, newWidth = o.Width, ymax = height - 1, xmax = width - 1, ox1, oy1, ox2, oy2; double xFactor = (double)width / newWidth, yFactor = (double)height / newHeight, ox, oy, dx, dy, k1, k2, r, g, b, a, x8, a2, b2, c2, d2, xm1, xp1, xp2; for (int y = 0; y < newHeight; y++) { oy = (double)y * yFactor - 0.5f; oy1 = (int)oy; dy = oy - (double)oy1; for (int x = 0; x < newWidth; x++) { ox = (double)x * xFactor - 0.5f; ox1 = (int)ox; dx = ox - (double)ox1; r = g = b = a = 0; for (int n = -1; n < 3; n++) { x8 = dy - (double)n; if (x8 > 2.0) { k1 = 0.0; } else { xm1 = x8 - 1.0; xp1 = x8 + 1.0; xp2 = x8 + 2.0; a2 = (xp2 <= 0.0) ? 0.0 : xp2 * xp2 * xp2; b2 = (xp1 <= 0.0) ? 0.0 : xp1 * xp1 * xp1; c2 = (x8 <= 0.0) ? 0.0 : x8 * x8 * x8; d2 = (xm1 <= 0.0) ? 0.0 : xm1 * xm1 * xm1; k1 = (0.16666666666666666667 * (a2 - (4.0 * b2) + (6.0 * c2) - (4.0 * d2))); } oy2 = oy1 + n; if (oy2 < 0) { oy2 = 0; } if (oy2 > ymax) { oy2 = ymax; } for (int m = -1; m < 3; m++) { x8 = (double)m - dx; if (x8 > 2.0) { k2 = 0.0; } else { xm1 = x8 - 1.0; xp1 = x8 + 1.0; xp2 = x8 + 2.0; a2 = (xp2 <= 0.0) ? 0.0 : xp2 * xp2 * xp2; b2 = (xp1 <= 0.0) ? 0.0 : xp1 * xp1 * xp1; c2 = (x8 <= 0.0) ? 0.0 : x8 * x8 * x8; d2 = (xm1 <= 0.0) ? 0.0 : xm1 * xm1 * xm1; k2 = k1 * (0.16666666666666666667 * (a2 - (4.0 * b2) + (6.0 * c2) - (4.0 * d2))); } ox2 = ox1 + m; if (ox2 < 0) { ox2 = 0; } if (ox2 > xmax) { ox2 = xmax; } Pixel srcPixel = i.GetPixel((uint)ox2, (uint)oy2); r += k2 * srcPixel.R; g += k2 * srcPixel.G; b += k2 * srcPixel.B; a += k2 * srcPixel.A; } } o.SetPixel((uint)x, (uint)y, new Pixel((byte)r, (byte)g, (byte)b, (byte)a)); } } return(o); }
/// <summary> /// Draw a triangle's outline. /// </summary> /// <param name="p1">The first point of the triangle.</param> /// <param name="p2">The second point of the triangle.</param> /// <param name="p3">The third point of the triangle.</param> /// <param name="color">The color to draw in.</param> public void DrawTriangleOutline(Vec2 p1, Vec2 p2, Vec2 p3, Pixel color) { DrawLines(new Vec2[] { p1, p2, p3, p1 }, color); }
/// <summary> /// Implements a flood fill algorithm. /// </summary> /// <param name="startPoint">The point to start filling from.</param> /// <param name="sColor">The color to search for.</param> /// <param name="dColor">The color to change it to.</param> public void FloodFill(Vec2 startPoint, Pixel sColor, Pixel dColor) { int x = startPoint.X; int y = startPoint.Y; if ((GetPixel((uint)x, (uint)y).Empty) || GetPixel((uint)x, (uint)y) == sColor) { SetPixel((uint)x, (uint)y, dColor); } Stack <Vec2> q = new Stack <Vec2>(); Visiteds = new bool[(Height + 1) * (Width + 1)]; #region Setup Start of queue Pixel p; Vec2 v; p = GetPixel((uint)x + 1, (uint)y); if ((p.Empty || p == sColor) && p != dColor) { v = new Vec2(x + 1, y); q.Push(v); Visiteds[((y * Width) + x + 1)] = true; SetPixel((uint)x + 1, (uint)y, dColor); } p = GetPixel((uint)x, (uint)y + 1); if ((p.Empty || p == sColor) && p != dColor) { v = new Vec2(x, y + 1); q.Push(v); Visiteds[(((y + 1) * Width) + x)] = true; SetPixel((uint)x, (uint)y + 1, dColor); } p = GetPixel((uint)x - 1, (uint)y); if ((p.Empty || p == sColor) && p != dColor) { v = new Vec2(x - 1, y); q.Push(v); Visiteds[((y * Width) + x - 1)] = true; SetPixel((uint)(x - 1), (uint)y, dColor); } p = GetPixel((uint)x, (uint)y - 1); if ((p.Empty || p == sColor) && p != dColor) { v = new Vec2(x, y - 1); q.Push(v); Visiteds[(((y - 1) * Width) + x)] = true; SetPixel((uint)x, (uint)(y - 1), dColor); } #endregion while (q.Count > 0) { v = q.Pop(); x = v.X; y = v.Y; #region Check p = GetPixel((uint)x + 1, (uint)y); if (p != dColor && (p.Empty || p == sColor)) { v = new Vec2(x + 1, y); if (x >= 0 && !(Visited(y, x + 1))) { q.Push(v); Visiteds[((y * Width) + x + 1)] = true; SetPixel((uint)x + 1, (uint)y, dColor); } } p = GetPixel((uint)x, (uint)y + 1); if (p != dColor && (p.Empty || p == sColor)) { v = new Vec2(x, y + 1); if (x >= 0 && !(Visited(y + 1, x))) { q.Push(v); Visiteds[(((y + 1) * Width) + x)] = true; SetPixel((uint)x, (uint)y + 1, dColor); } } p = GetPixel((uint)x - 1, (uint)y); if (p != dColor && (p.Empty || p == sColor)) { v = new Vec2(x - 1, y); if (x >= 0 && !(Visited(y, x - 1))) { q.Push(v); Visiteds[((y * Width) + x - 1)] = true; SetPixel((uint)x - 1, (uint)y, dColor); } } p = GetPixel((uint)x, (uint)y - 1); if (p != dColor && (p.Empty || p == sColor)) { v = new Vec2(x, y - 1); if (!(Visited(y - 1, x))) { q.Push(v); Visiteds[(((y - 1) * Width) + x)] = true; SetPixel((uint)x, (uint)y - 1, dColor); } } #endregion } // And finally empty the visiteds array. Visiteds = new bool[0]; }
/// <summary> /// Draws a triangle and fills it in. /// </summary> /// <param name="p1">The first point of the triangle.</param> /// <param name="p2">The second point of the triangle.</param> /// <param name="p3">The third point of the triangle.</param> /// <param name="color">The color to draw in.</param> public void DrawTriangle(Vec2 p1, Vec2 p2, Vec2 p3, Pixel color) { int l; // The farthest left int r; int t; int b; #region Organize points if (p1.Y > p2.Y && p1.Y > p3.Y) { t = p1.Y; if (p2.Y < p3.Y) { b = p2.Y; } else { b = p3.Y; } } else if (p2.Y > p1.Y && p2.Y > p3.Y) { t = p2.Y; if (p1.Y < p3.Y) { b = p1.Y; } else { b = p3.Y; } } else // This means p3 is the highest point { t = p3.Y; if (p1.Y < p2.Y) { b = p1.Y; } else { b = p2.Y; } } // Now organize in the width direction. if (p1.X > p3.X && p1.X > p2.X) { l = p1.X; if (p2.X < p3.X) { r = p2.X; } else { r = p3.X; } } else if (p2.X > p3.X && p2.X > p1.X) { l = p2.X; if (p1.X < p3.X) { r = p1.X; } else { r = p3.X; } } else { l = p3.X; if (p2.X < p1.X) { r = p2.X; } else { r = p1.X; } } #endregion int h; int w; if (t - b + 1 > 0) { h = t - b + 1; } else { h = b - t + 1; } if (l - r + 1 > 0) { w = l - r + 1; } else { w = r - l + 1; } Image i = new Image(w, h); // Get the location of the points within the image. Vec2 p4 = new Vec2(p1.X - r, p1.Y - b); Vec2 p5 = new Vec2(p2.X - r, p2.Y - b); Vec2 p6 = new Vec2(p3.X - r, p3.Y - b); #if DebugDraw Pixel p9 = new Pixel(); p9.B = 200; i.DrawLine(p4, p5, p9); i.DrawLine(p5, p6, p9); i.DrawLine(p6, p4, p9); #else i.DrawLine(p4, p5, color); i.DrawLine(p5, p6, color); i.DrawLine(p6, p4, color); #endif Vec2 center = (p4 + p5 + p6) / 3; i.FloodFill(center, new Pixel(true), color); /* * * NOTE TO SELF: Draw a line from each corner to the middle of the opposite line, * so as to fill in the holes that this flood fill method might leave, * when dealing with small angles. Some acute triangles have this problem. * */ Vec2 m1 = (p4 + p5) / 2; Vec2 m2 = (p5 + p6) / 2; Vec2 m3 = (p4 + p6) / 2; #if DebugDraw Pixel p50 = new Pixel(); p50.B = 200; i.DrawLine(p4, p5, p50); i.DrawLine(p5, p6, p50); i.DrawLine(p6, p4, p50); #else i.DrawLine(p6, m1, color); i.DrawLine(p4, m2, color); i.DrawLine(p5, m3, color); #endif Vec2 v = new Vec2(r, b); DrawImage(v, i); }
/// <summary> /// Draws a triangle with the specified fill color, and the specified border color. /// </summary> /// <param name="p1">The first point.</param> /// <param name="p2">The second point.</param> /// <param name="p3">The third point.</param> /// <param name="FillColor">The color to fill the triangle with.</param> /// <param name="BorderColor">The color to draw the border of the triangle.</param> public void DrawTriangle(Vec2 p1, Vec2 p2, Vec2 p3, Pixel FillColor, Pixel BorderColor) { DrawTriangle(p1, p2, p3, FillColor); DrawTriangleOutline(p1, p2, p3, BorderColor); }
/// <summary> /// Draws a quadrilateral with the specified points. /// </summary> /// <param name="p1">The first point.</param> /// <param name="p2">The second point.</param> /// <param name="p3">The third point.</param> /// <param name="p4">The fourth point.</param> /// <param name="color">The color to draw in.</param> public void DrawQuad(Vec2 p1, Vec2 p2, Vec2 p3, Vec2 p4, Pixel color) { DrawPolygon(new Vec2[] { p1, p2, p3, p4 }, color); }
/// <summary> /// Draws a polygon with the specified points. /// </summary> /// <param name="points">The points of the polygon.</param> /// <param name="color">The color to draw in.</param> public void DrawPolygon(Vec2[] points, Pixel color) { Vec2[] contour = points; List <Vec2> result = new List <Vec2>(); int cnt = 0; #region Process { #warning TODO: Change these back to floats when their implemented fully. double EPSILON = 0.0000000001f; int n = contour.Length; if (n < 3) { throw new Exception("Not enough Verticies!"); } int[] V = new int[n]; int Area; { int n2 = contour.Length; double A = 0.0f; for (int p = n2 - 1, q = 0; q < n2; p = q++) { A += contour[p].X * contour[q].Y - contour[q].X * contour[p].Y; } Area = (Int32)(A * 0.5f); } if (0.0f < Area) { for (int v = 0; v < n; v++) { V[v] = v; } } else { for (int v = 0; v < n; v++) { V[v] = (n - 1) - v; } } int nv = n; int count = 2 * nv; for (int m = 0, v = nv - 1; nv > 2;) { if (0 >= (count--)) { throw new Exception("Invalid polygon!"); } int u = v; if (nv <= u) { u = 0; } v = u + 1; if (nv <= v) { v = 0; } int w = v + 1; if (nv <= w) { w = 0; } bool Snip; { int p; double Ax, Ay, Bx, By, Cx, Cy, Px, Py; Ax = contour[V[u]].X; Ay = contour[V[u]].Y; Bx = contour[V[v]].X; By = contour[V[v]].Y; Cx = contour[V[w]].X; Cy = contour[V[w]].Y; if (EPSILON > (((Bx - Ax) * (Cy - Ay)) - ((By - Ay) * (Cx - Ax)))) { Snip = false; } for (p = 0; p < nv; p++) { if ((p == u) || (p == v) || (p == w)) { continue; } Px = contour[V[p]].X; Py = contour[V[p]].Y; bool InsideTriangle; { double ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy; double cCROSSap, bCROSScp, aCROSSbp; ax = Cx - Bx; ay = Cy - By; bx = Ax - Cx; by = Ay - Cy; cx = Bx - Ax; cy = By - Ay; apx = Px - Ax; apy = Py - Ay; bpx = Px - Bx; bpy = Py - By; cpx = Px - Cx; cpy = Py - Cy; aCROSSbp = ax * bpy - ay * bpx; cCROSSap = cx * apy - cy * apx; bCROSScp = bx * cpy - by * cpx; InsideTriangle = ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f)); } if (InsideTriangle) { Snip = false; } } Snip = true; } if (Snip) { int a, b, c, s, t; a = V[u]; b = V[v]; c = V[w]; result.Add(contour[a]); result.Add(contour[b]); result.Add(contour[c]); m++; for (s = v, t = v + 1; t < nv; s++, t++) { V[s] = V[t]; } nv--; count = 2 * nv; } } } #endregion while (cnt < (result.Count / 3)) { DrawTriangle(result[(cnt * 3)], result[(cnt * 3) + 1], result[(cnt * 3) + 2], color); cnt++; } }
/// <summary> /// Draws a quadrilateral with the specified points. /// </summary> /// <param name="p1">The first point.</param> /// <param name="p2">The second point.</param> /// <param name="p3">The third point.</param> /// <param name="p4">The fourth point.</param> /// <param name="FillColor">The color to fill in the rectangle with.</param> /// <param name="BorderColor">The color to draw the border in.</param> public void DrawQuad(Vec2 p1, Vec2 p2, Vec2 p3, Vec2 p4, Pixel FillColor, Pixel BorderColor) { DrawPolygon(new Vec2[] { p1, p2, p3, p4 }, FillColor); DrawPolygonOutline(new Vec2[] { p1, p2, p3, p4 }, BorderColor); }
/// <summary> /// Draws an eliptical arc. /// </summary> /// <param name="CenterPoint">The center-point of the elipse to use.</param> /// <param name="height">The height of the elipse to use.</param> /// <param name="width">The width of the elipse to use.</param> /// <param name="startAngle">The angle to start drawing at.</param> /// <param name="endAngle">The angle to stop drawing at.</param> /// <param name="color">The color to draw in.</param> public void DrawElipticalArc(Vec2 CenterPoint, int height, int width, int startAngle, int endAngle, Pixel color) { double angle = (((startAngle <= endAngle) ? startAngle : endAngle) * (Math.PI / 180)); double range = (((endAngle > startAngle) ? endAngle : startAngle) * (Math.PI / 180)); double x = (width * Math.Cos(angle)); double y = (height * Math.Sin(angle)); do { SetPixel((uint)((int)(CenterPoint.X + x + 0.5)), (uint)((int)(CenterPoint.Y - y + 0.5)), color); angle += 0.001; x = (width * Math.Cos(angle)); y = (height * Math.Sin(angle)); }while (angle <= range); }
/// <summary> /// Draws an elipse outline. /// </summary> /// <param name="CenterPoint">The center of the elipse</param> /// <param name="height">The height of the elipse.</param> /// <param name="width">The width of the elipse.</param> /// <param name="color">The color to draw in.</param> public void DrawElipseOutline(Vec2 CenterPoint, int height, int width, Pixel color) { DrawElipticalArc(CenterPoint, height, width, 0, 360, color); }
/// <summary> /// Draws and fills an elipse. /// </summary> /// <param name="CenterPoint">The center of the elipse</param> /// <param name="height">The height of the elipse.</param> /// <param name="width">The width of the elipse.</param> /// <param name="fillColor">The color to fill in.</param> /// <param name="borderColor">The color to draw the border in.</param> public void DrawElipse(Vec2 CenterPoint, int height, int width, Pixel fillColor, Pixel borderColor) { DrawElipse(CenterPoint, height, width, fillColor); DrawElipseOutline(CenterPoint, height, width, borderColor); }
public void DrawString(Vec2 loc, String s, FontSupport.Font f, int stringHeight, FontSupport.FontStyle flags, Pixel color) { FontSupport.FontManager.Instance.DrawText(this, null, null, s, f, loc, color); }