using System; using System.Collections.Generic; using System.Globalization; using System.Text.RegularExpressions; using System.Windows.Media; namespace Html5Canvas { static class Utility { // Attempt to parse a string style; return results if successful public static bool ParseStyle(string style, out Brush brush, out string effectiveStyle) { brush = null; effectiveStyle = null; Color color; if (ParseCssColor(style, out color)) { // Create a brush and style string for it brush = new SolidColorBrush(color); if (byte.MaxValue == color.A) { // Use 6-character form effectiveStyle = string.Format("#{0:x2}{1:x2}{2:x2}", color.R, color.G, color.B); } else { // Use 8-character form effectiveStyle = string.Format("rgba({0}, {1}, {2}, {3})", color.R, color.G, color.B, color.A / ((double)byte.MaxValue)); } } else { // Unable to parse return false; } return true; } // Clones a PathGeometry because Silverlight doesn't support reuse public static PathGeometry ClonePathGeometry(PathGeometry pathGeometry) { var pathGeometryClone = new PathGeometry(); foreach (var figure in pathGeometry.Figures) { var figureClone = new PathFigure { StartPoint = figure.StartPoint, IsClosed = figure.IsClosed, IsFilled = figure.IsFilled }; foreach (var segment in figure.Segments) { var lineSegment = segment as LineSegment; var arcSegment = segment as ArcSegment; var bezierSegment = segment as BezierSegment; var quadraticBezierSegment = segment as QuadraticBezierSegment; if (null != lineSegment) { figureClone.Segments.Add(new LineSegment { Point = lineSegment.Point }); } else if (null != arcSegment) { figureClone.Segments.Add(new ArcSegment { Point = arcSegment.Point, RotationAngle = arcSegment.RotationAngle, Size = arcSegment.Size, SweepDirection = arcSegment.SweepDirection, IsLargeArc = arcSegment.IsLargeArc }); } else if (null != quadraticBezierSegment) { figureClone.Segments.Add(new QuadraticBezierSegment { Point1 = quadraticBezierSegment.Point1, Point2 = quadraticBezierSegment.Point2 }); } else if (null != bezierSegment) { figureClone.Segments.Add(new BezierSegment { Point1 = bezierSegment.Point1, Point2 = bezierSegment.Point2, Point3 = bezierSegment.Point3 }); } else { throw new NotSupportedException(); } } pathGeometryClone.Figures.Add(figureClone); } return pathGeometryClone; } // Clones a TransformGroup for use with a new Canvas public static TransformGroup CloneTransformGroup(TransformGroup transformGroup) { var transformGroupClone = new TransformGroup(); foreach (var transform in transformGroup.Children) { var translateTransform = transform as TranslateTransform; var rotateTransform = transform as RotateTransform; var scaleTransform = transform as ScaleTransform; if (null != translateTransform) { transformGroupClone.Children.Add(new TranslateTransform { X = translateTransform.X, Y = translateTransform.Y }); } else if (null != rotateTransform) { transformGroupClone.Children.Add(new RotateTransform { Angle = rotateTransform.Angle }); } else if (null != scaleTransform) { transformGroupClone.Children.Add(new ScaleTransform { ScaleX = scaleTransform.ScaleX, ScaleY = scaleTransform.ScaleY }); } else { throw new NotSupportedException(); } } return transformGroupClone; } // Clones a GradientBrush so a TranslateTransform can be applied public static Brush CloneAndMapGradientBrush(Brush brush, double x, double y) { var gradientBrush = brush as GradientBrush; if (null == gradientBrush) { return brush; } GradientBrush gradientBrushClone = null; var linearGradientBrush = gradientBrush as LinearGradientBrush; var radialGradientBrush = gradientBrush as RadialGradientBrush; if (null != linearGradientBrush) { var linearGradientBrushClone = new LinearGradientBrush(); linearGradientBrushClone.StartPoint = linearGradientBrush.StartPoint; linearGradientBrushClone.EndPoint = linearGradientBrush.EndPoint; gradientBrushClone = linearGradientBrushClone; } else if (null != radialGradientBrush) { var radialGradientBrushClone = new RadialGradientBrush(); radialGradientBrushClone.GradientOrigin = radialGradientBrush.GradientOrigin; radialGradientBrushClone.Center = radialGradientBrush.Center; radialGradientBrushClone.RadiusX = radialGradientBrush.RadiusX; radialGradientBrushClone.RadiusY = radialGradientBrush.RadiusY; gradientBrushClone = radialGradientBrushClone; } else { throw new NotSupportedException(); } foreach (var gradientStop in gradientBrush.GradientStops) { gradientBrushClone.GradientStops.Add(new GradientStop { Color = gradientStop.Color, Offset = gradientStop.Offset }); } gradientBrushClone.MappingMode = gradientBrush.MappingMode; gradientBrushClone.Transform = new TranslateTransform { X = -x, Y = -y }; return gradientBrushClone; } private static readonly Regex _hex6Regex = new Regex(@"#[0-9a-fA-F]{6}"); private static readonly Regex _hex3Regex = new Regex(@"#[0-9a-fA-F]{3}"); private static readonly Regex _rgbRegex = new Regex(@"rgb\(\s*(?\d+)\s*,\s*(?\d+)\s*,\s*(?\d+)\s*\)"); private static readonly Regex _rgbaRegex = new Regex(@"rgba\(\s*(?\d+)\s*,\s*(?\d+)\s*,\s*(?\d+)\s*,\s*(?.+)\s*\)"); // Attempt to parse a color by the various allowed forms public static bool ParseCssColor(string cssColor, out Color color) { color = Colors.Transparent; cssColor = CssColorToHex6(cssColor); var hex6Match = _hex6Regex.Match(cssColor); var hex3Match = _hex3Regex.Match(cssColor); var rgbMatch = _rgbRegex.Match(cssColor); var rgbaMatch = _rgbaRegex.Match(cssColor); if (hex6Match.Success) { color = Color.FromArgb(byte.MaxValue, byte.Parse(cssColor.Substring(1, 2), NumberStyles.AllowHexSpecifier), byte.Parse(cssColor.Substring(3, 2), NumberStyles.AllowHexSpecifier), byte.Parse(cssColor.Substring(5, 2), NumberStyles.AllowHexSpecifier)); } else if (hex3Match.Success) { color = Color.FromArgb(byte.MaxValue, (byte)(byte.Parse(cssColor.Substring(1, 1), NumberStyles.AllowHexSpecifier) << 4), (byte)(byte.Parse(cssColor.Substring(2, 1), NumberStyles.AllowHexSpecifier) << 4), (byte)(byte.Parse(cssColor.Substring(3, 1), NumberStyles.AllowHexSpecifier) << 4)); } else if (rgbMatch.Success) { color = Color.FromArgb(byte.MaxValue, byte.Parse(rgbMatch.Groups["r"].Value), byte.Parse(rgbMatch.Groups["g"].Value), byte.Parse(rgbMatch.Groups["b"].Value)); } else if (rgbaMatch.Success) { color = Color.FromArgb((byte)(byte.MaxValue * double.Parse(rgbaMatch.Groups["a"].Value)), byte.Parse(rgbaMatch.Groups["r"].Value), byte.Parse(rgbaMatch.Groups["g"].Value), byte.Parse(rgbaMatch.Groups["b"].Value)); } else { return false; } return true; } // Looks up the string color in the list of CSS color mappings private static string CssColorToHex6(string color) { color = color.ToLower(CultureInfo.InvariantCulture); return _cssColorToHex6.ContainsKey(color) ? _cssColorToHex6[color] : color; } // From http://www.w3.org/TR/css3-color/ private static Dictionary _cssColorToHex6 = new Dictionary { {"aliceblue", "#f0f8ff"}, {"antiquewhite", "#faebd7"}, {"aqua", "#00ffff"}, {"aquamarine", "#7fffd4"}, {"azure", "#f0ffff"}, {"beige", "#f5f5dc"}, {"bisque", "#ffe4c4"}, {"black", "#000000"}, {"blanchedalmond", "#ffebcd"}, {"blue", "#0000ff"}, {"blueviolet", "#8a2be2"}, {"brown", "#a52a2a"}, {"burlywood", "#deb887"}, {"cadetblue", "#5f9ea0"}, {"chartreuse", "#7fff00"}, {"chocolate", "#d2691e"}, {"coral", "#ff7f50"}, {"cornflowerblue", "#6495ed"}, {"cornsilk", "#fff8dc"}, {"crimson", "#dc143c"}, {"cyan", "#00ffff"}, {"darkblue", "#00008b"}, {"darkcyan", "#008b8b"}, {"darkgoldenrod", "#b8860b"}, {"darkgray", "#a9a9a9"}, {"darkgreen", "#006400"}, {"darkgrey", "#a9a9a9"}, {"darkkhaki", "#bdb76b"}, {"darkmagenta", "#8b008b"}, {"darkolivegreen", "#556b2f"}, {"darkorange", "#ff8c00"}, {"darkorchid", "#9932cc"}, {"darkred", "#8b0000"}, {"darksalmon", "#e9967a"}, {"darkseagreen", "#8fbc8f"}, {"darkslateblue", "#483d8b"}, {"darkslategray", "#2f4f4f"}, {"darkslategrey", "#2f4f4f"}, {"darkturquoise", "#00ced1"}, {"darkviolet", "#9400d3"}, {"deeppink", "#ff1493"}, {"deepskyblue", "#00bfff"}, {"dimgray", "#696969"}, {"dimgrey", "#696969"}, {"dodgerblue", "#1e90ff"}, {"firebrick", "#b22222"}, {"floralwhite", "#fffaf0"}, {"forestgreen", "#228b22"}, {"fuchsia", "#ff00ff"}, {"gainsboro", "#dcdcdc"}, {"ghostwhite", "#f8f8ff"}, {"gold", "#ffd700"}, {"goldenrod", "#daa520"}, {"gray", "#808080"}, {"green", "#008000"}, {"greenyellow", "#adff2f"}, {"grey", "#808080"}, {"honeydew", "#f0fff0"}, {"hotpink", "#ff69b4"}, {"indianred", "#cd5c5c"}, {"indigo", "#4b0082"}, {"ivory", "#fffff0"}, {"khaki", "#f0e68c"}, {"lavender", "#e6e6fa"}, {"lavenderblush", "#fff0f5"}, {"lawngreen", "#7cfc00"}, {"lemonchiffon", "#fffacd"}, {"lightblue", "#add8e6"}, {"lightcoral", "#f08080"}, {"lightcyan", "#e0ffff"}, {"lightgoldenrodyellow", "#fafad2"}, {"lightgray", "#d3d3d3"}, {"lightgreen", "#90ee90"}, {"lightgrey", "#d3d3d3"}, {"lightpink", "#ffb6c1"}, {"lightsalmon", "#ffa07a"}, {"lightseagreen", "#20b2aa"}, {"lightskyblue", "#87cefa"}, {"lightslategray", "#778899"}, {"lightslategrey", "#778899"}, {"lightsteelblue", "#b0c4de"}, {"lightyellow", "#ffffe0"}, {"lime", "#00ff00"}, {"limegreen", "#32cd32"}, {"linen", "#faf0e6"}, {"magenta", "#ff00ff"}, {"maroon", "#800000"}, {"mediumaquamarine", "#66cdaa"}, {"mediumblue", "#0000cd"}, {"mediumorchid", "#ba55d3"}, {"mediumpurple", "#9370db"}, {"mediumseagreen", "#3cb371"}, {"mediumslateblue", "#7b68ee"}, {"mediumspringgreen", "#00fa9a"}, {"mediumturquoise", "#48d1cc"}, {"mediumvioletred", "#c71585"}, {"midnightblue", "#191970"}, {"mintcream", "#f5fffa"}, {"mistyrose", "#ffe4e1"}, {"moccasin", "#ffe4b5"}, {"navajowhite", "#ffdead"}, {"navy", "#000080"}, {"oldlace", "#fdf5e6"}, {"olive", "#808000"}, {"olivedrab", "#6b8e23"}, {"orange", "#ffa500"}, {"orangered", "#ff4500"}, {"orchid", "#da70d6"}, {"palegoldenrod", "#eee8aa"}, {"palegreen", "#98fb98"}, {"paleturquoise", "#afeeee"}, {"palevioletred", "#db7093"}, {"papayawhip", "#ffefd5"}, {"peachpuff", "#ffdab9"}, {"peru", "#cd853f"}, {"pink", "#ffc0cb"}, {"plum", "#dda0dd"}, {"powderblue", "#b0e0e6"}, {"purple", "#800080"}, {"red", "#ff0000"}, {"rosybrown", "#bc8f8f"}, {"royalblue", "#4169e1"}, {"saddlebrown", "#8b4513"}, {"salmon", "#fa8072"}, {"sandybrown", "#f4a460"}, {"seagreen", "#2e8b57"}, {"seashell", "#fff5ee"}, {"sienna", "#a0522d"}, {"silver", "#c0c0c0"}, {"skyblue", "#87ceeb"}, {"slateblue", "#6a5acd"}, {"slategray", "#708090"}, {"slategrey", "#708090"}, {"snow", "#fffafa"}, {"springgreen", "#00ff7f"}, {"steelblue", "#4682b4"}, {"tan", "#d2b48c"}, {"teal", "#008080"}, {"thistle", "#d8bfd8"}, {"tomato", "#ff6347"}, {"turquoise", "#40e0d0"}, {"violet", "#ee82ee"}, {"wheat", "#f5deb3"}, {"white", "#ffffff"}, {"whitesmoke", "#f5f5f5"}, {"yellow", "#ffff00"}, {"yellowgreen", "#9acd32"}, }; } }