public object Clone() { var result = new SvgTransformCollection(); foreach (var trans in this) { result.AddItem(trans.Clone() as SvgTransform); } return(result); }
/// <summary> /// Converts the given object to the type of this converter, using the specified context and culture information. /// </summary> /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.</param> /// <param name="culture">The <see cref="T:System.Globalization.CultureInfo"/> to use as the current culture.</param> /// <param name="value">The <see cref="T:System.Object"/> to convert.</param> /// <returns> /// An <see cref="T:System.Object"/> that represents the converted value. /// </returns> /// <exception cref="T:System.NotSupportedException">The conversion cannot be performed. </exception> public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { if (value is not string str) { return(base.ConvertFrom(context, culture, value)); } var transformList = new SvgTransformCollection(); var source = str.AsSpan().TrimStart(); var sourceLength = source.Length; var splitChars = SplitChars.AsSpan(); while (true) { var currentIndex = 0; var startIndex = source.IndexOf('('); var endIndex = source.IndexOf(')'); if (startIndex < 0 || endIndex <= startIndex) { break; } var transformName = source.Slice(currentIndex, startIndex - currentIndex).Trim().Trim(',').Trim(); var contents = source.Slice(startIndex + 1, endIndex - startIndex - 1).Trim(); var parts = new StringSplitEnumerator(contents, splitChars); var transformType = GetTransformType(ref transformName); switch (transformType) { case TransformType.Translate: { var count = 0; var x = default(float); var y = default(float); foreach (var part in parts) { var partValue = part.Value; if (count == 0) { x = ToFloat(ref partValue); } else if (count == 1) { y = ToFloat(ref partValue); } count++; } if (count == 0 || count > 2) { throw new FormatException("Translate transforms must be in the format 'translate(x [y])'"); } transformList.Add(count > 1 ? new SvgTranslate(x, y) : new SvgTranslate(x)); } break; case TransformType.Rotate: { int count = 0; var angle = default(float); var cx = default(float); var cy = default(float); foreach (var part in parts) { var partValue = part.Value; if (count == 0) { angle = ToFloat(ref partValue); } else if (count == 1) { cx = ToFloat(ref partValue); } else if (count == 2) { cy = ToFloat(ref partValue); } count++; } if (count != 1 && count != 3) { throw new FormatException("Rotate transforms must be in the format 'rotate(angle [cx cy])'"); } transformList.Add(count == 1 ? new SvgRotate(angle) : new SvgRotate(angle, cx, cy)); } break; case TransformType.Scale: { int count = 0; var sx = default(float); var sy = default(float); foreach (var part in parts) { var partValue = part.Value; if (count == 0) { sx = ToFloat(ref partValue); } else if (count == 1) { sy = ToFloat(ref partValue); } count++; } if (count == 0 || count > 2) { throw new FormatException("Scale transforms must be in the format 'scale(x [y])'"); } transformList.Add(count > 1 ? new SvgScale(sx, sy) : new SvgScale(sx)); } break; case TransformType.Matrix: { int count = 0; var m11 = default(float); var m12 = default(float); var m21 = default(float); var m22 = default(float); var dx = default(float); var dy = default(float); foreach (var part in parts) { var partValue = part.Value; if (count == 0) { m11 = ToFloat(ref partValue); } else if (count == 1) { m12 = ToFloat(ref partValue); } else if (count == 2) { m21 = ToFloat(ref partValue); } else if (count == 3) { m22 = ToFloat(ref partValue); } else if (count == 4) { dx = ToFloat(ref partValue); } else if (count == 5) { dy = ToFloat(ref partValue); } count++; } if (count != 6) { throw new FormatException("Matrix transforms must be in the format 'matrix(m11 m12 m21 m22 dx dy)'"); } transformList.Add(new SvgMatrix(new List <float>(6) { m11, m12, m21, m22, dx, dy })); } break; case TransformType.Shear: { int count = 0; var hx = default(float); var hy = default(float); foreach (var part in parts) { var partValue = part.Value; if (count == 0) { hx = ToFloat(ref partValue); } else if (count == 1) { hy = ToFloat(ref partValue); } count++; } if (count == 0 || count > 2) { throw new FormatException("Shear transforms must be in the format 'shear(x [y])'"); } transformList.Add(count > 1 ? new SvgShear(hx, hy) : new SvgShear(hx)); } break; case TransformType.SkewX: { int count = 0; var ax = default(float); foreach (var part in parts) { var partValue = part.Value; if (count == 0) { ax = ToFloat(ref partValue); } count++; } if (count != 1) { throw new FormatException("SkewX transforms must be in the format 'skewX(a)'"); } transformList.Add(new SvgSkew(ax, 0f)); } break; case TransformType.SkewY: { int count = 0; var ay = default(float); foreach (var part in parts) { var partValue = part.Value; if (count == 0) { ay = ToFloat(ref partValue); } count++; } if (count != 1) { throw new FormatException("SkewY transforms must be in the format 'skewY(a)'"); } transformList.Add(new SvgSkew(0f, ay)); } break; } currentIndex = endIndex; if (currentIndex + 1 > sourceLength) { break; } source = source.Slice(currentIndex + 1, sourceLength - currentIndex - 1).TrimStart(); sourceLength = source.Length; if (sourceLength <= 0) { break; } } return(transformList); }
/// <summary> /// Converts the given object to the type of this converter, using the specified context and culture information. /// </summary> /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.</param> /// <param name="culture">The <see cref="T:System.Globalization.CultureInfo"/> to use as the current culture.</param> /// <param name="value">The <see cref="T:System.Object"/> to convert.</param> /// <returns> /// An <see cref="T:System.Object"/> that represents the converted value. /// </returns> /// <exception cref="T:System.NotSupportedException">The conversion cannot be performed. </exception> public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) { if (value is string) { SvgTransformCollection transformList = new SvgTransformCollection(); string[] parts; string contents; string transformName; foreach (string transform in SvgTransformConverter.SplitTransforms((string)value)) { if (string.IsNullOrEmpty(transform)) { continue; } parts = transform.Split('(', ')'); transformName = parts[0].Trim(); contents = parts[1].Trim(); switch (transformName) { case "translate": string[] coords = contents.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); if (coords.Length == 0 || coords.Length > 2) { throw new FormatException("Translate transforms must be in the format 'translate(x [,y])'"); } float x = float.Parse(coords[0].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture); if (coords.Length > 1) { float y = float.Parse(coords[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture); transformList.Add(new SvgTranslate(x, y)); } else { transformList.Add(new SvgTranslate(x)); } break; case "rotate": string[] args = contents.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); if (args.Length != 1 && args.Length != 3) { throw new FormatException("Rotate transforms must be in the format 'rotate(angle [cx cy ])'"); } float angle = float.Parse(args[0], NumberStyles.Float, CultureInfo.InvariantCulture); if (args.Length == 1) { transformList.Add(new SvgRotate(angle)); } else { float cx = float.Parse(args[1], NumberStyles.Float, CultureInfo.InvariantCulture); float cy = float.Parse(args[2], NumberStyles.Float, CultureInfo.InvariantCulture); transformList.Add(new SvgRotate(angle, cx, cy)); } break; case "scale": string[] scales = contents.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); if (scales.Length == 0 || scales.Length > 2) { throw new FormatException("Scale transforms must be in the format 'scale(x [,y])'"); } float sx = float.Parse(scales[0].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture); if (scales.Length > 1) { float sy = float.Parse(scales[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture); transformList.Add(new SvgScale(sx, sy)); } else { transformList.Add(new SvgScale(sx)); } break; case "matrix": string[] points = contents.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); if (points.Length != 6) { throw new FormatException("Matrix transforms must be in the format 'matrix(m11, m12, m21, m22, dx, dy)'"); } List <float> mPoints = new List <float>(); foreach (string point in points) { mPoints.Add(float.Parse(point.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture)); } transformList.Add(new SvgMatrix(mPoints)); break; case "shear": string[] shears = contents.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); if (shears.Length == 0 || shears.Length > 2) { throw new FormatException("Shear transforms must be in the format 'shear(x [,y])'"); } float hx = float.Parse(shears[0].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture); if (shears.Length > 1) { float hy = float.Parse(shears[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture); transformList.Add(new SvgShear(hx, hy)); } else { transformList.Add(new SvgShear(hx)); } break; case "skewX": float ax = float.Parse(contents, NumberStyles.Float, CultureInfo.InvariantCulture); transformList.Add(new SvgSkew(ax, 0)); break; case "skewY": float ay = float.Parse(contents, NumberStyles.Float, CultureInfo.InvariantCulture); transformList.Add(new SvgSkew(0, ay)); break; } } return(transformList); } return(base.ConvertFrom(context, culture, value)); }