/// <summary> /// Convert a given text to graphic paths /// </summary> public static (double, double) Vectorize(GraphicPathGeometry graphicPathGeometry, string text, double x, double y, Typeface typeface, double fontSize, double rotate, Matrix currentTransformationMatrix) { FormattedText formattedText = new FormattedText( text, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, typeface, fontSize, Brushes.Black, 96); Matrix fontTransformation = Matrix.Identity; fontTransformation.RotateAt(rotate, 0, formattedText.Baseline); fontTransformation.Translate(x, y - formattedText.Baseline); fontTransformation = fontTransformation * currentTransformationMatrix; var pathGeometry = formattedText.BuildGeometry(new Point(0, 0)); ConvertToGraphicGeometry(graphicPathGeometry, pathGeometry, fontTransformation); var newX = formattedText.WidthIncludingTrailingWhitespace; return(x + newX, y); }
/// <summary> /// Parse polyline /// </summary> private static GraphicPathGeometry ParsePolyline(XElement path) { XAttribute dAttr = path.Attribute("points"); GraphicPathGeometry geometry = new GraphicPathGeometry(); var pointParser = new DoubleListParser(); var points = pointParser.ParsePointList(dAttr.Value); if (points.Count > 1) { var move = new GraphicMoveSegment { StartPoint = points[0] }; geometry.Segments.Add(move); move.IsClosed = false; for (int i = 1; i < points.Count; i++) { var lineTo = new GraphicLineSegment { To = points[i] }; geometry.Segments.Add(lineTo); } } return(geometry); }
private void AddRectangle(GraphicPathGeometry geometry, double x, double y, double width, double height, Matrix ctm) { var point1 = MatrixUtilities.TransformPoint(x, y, ctm); var point2 = MatrixUtilities.TransformPoint(x + width, y + height, ctm); var move = new GraphicMoveSegment { StartPoint = point1 }; geometry.Segments.Add(move); var lineTo = new GraphicLineSegment { To = new Point(point2.X, point1.Y) }; geometry.Segments.Add(lineTo); lineTo = new GraphicLineSegment { To = new Point(point2.X, point2.Y) }; geometry.Segments.Add(lineTo); lineTo = new GraphicLineSegment { To = new Point(point1.X, point2.Y) }; geometry.Segments.Add(lineTo); move.IsClosed = true; }
public override void Execute(EpsInterpreter interpreter) { var operandStack = interpreter.OperandStack; var topOperand = operandStack.Pop(); var graphicState = interpreter.GraphicState; var ctm = graphicState.CurrentTransformationMatrix; var geometry = new GraphicPathGeometry(); switch (topOperand) { case IntegerOperand integerOperand: case RealOperand realOperand: { var height = OperandHelper.GetRealValue(topOperand); var width = operandStack.PopRealValue(); var y = operandStack.PopRealValue(); var x = operandStack.PopRealValue(); AddRectangle(geometry, x, y, width, height, ctm); break; } case ArrayOperand arrayOperand: { for (int i = 0; i < arrayOperand.Values.Count; i += 4) { var x = OperandHelper.GetRealValue(arrayOperand.Values[i].Operand); var y = OperandHelper.GetRealValue(arrayOperand.Values[i + 1].Operand); var height = OperandHelper.GetRealValue(arrayOperand.Values[i + 2].Operand); var width = OperandHelper.GetRealValue(arrayOperand.Values[i + 3].Operand); AddRectangle(geometry, x, y, width, height, ctm); } break; } case StringOperand stringOperand: { var values = HomogeneousNumberArrayDecoder.Decode(stringOperand); for (int i = 0; i < values.Count; i += 4) { var x = values[i]; var y = values[i + 1]; var height = values[i + 2]; var width = values[i + 3]; AddRectangle(geometry, x, y, width, height, ctm); } break; } } ClipHelper.SetClip(interpreter, geometry); interpreter.ResetCurrentGeometry(); }
/// <summary> /// Generate the source code for the given geometry /// </summary> public void GenerateShape(GraphicPathGeometry geometry) { outputStream.WriteLine("newpath"); bool closeLastPath = false; foreach (var segment in geometry.Segments) { switch (segment) { case GraphicMoveSegment graphicMove: { if (closeLastPath) { outputStream.WriteLine("closepath"); } var pointStr = FormatPoint(graphicMove.StartPoint); outputStream.WriteLine($"{pointStr} moveto"); closeLastPath = graphicMove.IsClosed; break; } case GraphicLineSegment graphicLineTo: { var pointStr = FormatPoint(graphicLineTo.To); outputStream.WriteLine($"{pointStr} lineto"); break; } case GraphicCubicBezierSegment graphicCubicBezier: { var point1Str = FormatPoint(graphicCubicBezier.ControlPoint1); var point2Str = FormatPoint(graphicCubicBezier.ControlPoint2); var endPointStr = FormatPoint(graphicCubicBezier.EndPoint); outputStream.WriteLine($"{point1Str} {point2Str} {endPointStr} curveto"); break; } case GraphicQuadraticBezierSegment graphicQuadraticBezier: { var pointStr = FormatPoint(graphicQuadraticBezier.ControlPoint); var endPointStr = FormatPoint(graphicQuadraticBezier.EndPoint); outputStream.WriteLine($"{pointStr} {pointStr} {endPointStr} curveto"); break; } default: break; } } if (closeLastPath) { outputStream.WriteLine("closepath"); } }
public static void SetClip(EpsInterpreter interpreter, GraphicPathGeometry geometry) { interpreter.GraphicState.ClippingPath = geometry; var graphicGroup = new GraphicGroup(); interpreter.GraphicGroup = graphicGroup; interpreter.GraphicGroup.Clip = geometry; interpreter.ReturnGraphicGroup.Childreen.Add(graphicGroup); }
/// <summary> /// Transform a path /// </summary> private GraphicPathGeometry TransformGeometry(GraphicPathGeometry geometry) { GraphicPathGeometry transformedPath = new GraphicPathGeometry(); transformedPath.FillRule = geometry.FillRule; transformedPath.Segments = TransformSegments(geometry.Segments); return(transformedPath); }
/// <summary> /// Normalizes the specified graphic path. /// </summary> private GraphicPathGeometry NormalizeGeometry(GraphicPathGeometry graphicPathGeometry) { GraphicPathGeometry normalizedGeometry = new GraphicPathGeometry(); normalizedGeometry.FillRule = graphicPathGeometry.FillRule; foreach (var pathElement in graphicPathGeometry.Segments) { switch (pathElement) { case GraphicMoveSegment graphicMove: { var normalizedMove = new GraphicMoveSegment(); normalizedGeometry.Segments.Add(normalizedMove); normalizedMove.StartPoint = NormalizePoint(graphicMove.StartPoint); normalizedMove.IsClosed = graphicMove.IsClosed; break; } case GraphicLineSegment graphicLineTo: { var normalizedLineTo = new GraphicLineSegment(); normalizedGeometry.Segments.Add(normalizedLineTo); normalizedLineTo.To = NormalizePoint(graphicLineTo.To); break; } case GraphicCubicBezierSegment graphicCubicBezier: { var normalizedCubicBezier = new GraphicCubicBezierSegment(); normalizedGeometry.Segments.Add(normalizedCubicBezier); normalizedCubicBezier.ControlPoint1 = NormalizePoint(graphicCubicBezier.ControlPoint1); normalizedCubicBezier.ControlPoint2 = NormalizePoint(graphicCubicBezier.ControlPoint2); normalizedCubicBezier.EndPoint = NormalizePoint(graphicCubicBezier.EndPoint); break; } case GraphicQuadraticBezierSegment graphicQuadraticBezier: { var normalizedQuadraticBezier = new GraphicQuadraticBezierSegment(); normalizedGeometry.Segments.Add(normalizedQuadraticBezier); normalizedQuadraticBezier.ControlPoint = NormalizePoint(graphicQuadraticBezier.ControlPoint); normalizedQuadraticBezier.EndPoint = NormalizePoint(graphicQuadraticBezier.EndPoint); break; } } } return(normalizedGeometry); }
/// <summary> /// Parse an SVG shape and return a GraphicPathGeometry /// </summary> public static GraphicPathGeometry Parse(XElement shape, Matrix currentTransformationMatrix) { GraphicPathGeometry geometry = null; switch (shape.Name.LocalName) { case "path": geometry = ParsePath(shape); break; case "polygon": geometry = ParsePolygon(shape); break; case "circle": geometry = ParseCircle(shape); break; case "ellipse": geometry = ParseEllipse(shape); break; case "rect": geometry = ParseRect(shape); break; case "line": geometry = ParseLine(shape); break; case "polyline": geometry = ParsePolyline(shape); break; } if (geometry != null) { //Matrix currentPathTransformationMatrix = currentTransformationMatrix; //var attrs = shape.Attribute("transform"); //if (attrs != null) //{ // var transformMatrix = TransformMatrixParser.GetTransformMatrix(attrs.Value); // currentPathTransformationMatrix = transformMatrix * currentPathTransformationMatrix; //} var trans = new TransformVisual(); geometry = trans.Transform(geometry, currentTransformationMatrix); } return(geometry); }
/// <summary> /// Generates a WPF geometry for a single graphic path geometry /// </summary> public static Geometry GenerateGeometry(GraphicPathGeometry graphicPathGeometry) { if (graphicPathGeometry == null) { return(null); } StreamGeometry geometry = new StreamGeometry(); geometry.FillRule = ConvertFillRule(graphicPathGeometry.FillRule); StreamGeometryContext ctx = geometry.Open(); foreach (var segment in graphicPathGeometry.Segments) { switch (segment) { case GraphicMoveSegment graphicMove: { ctx.BeginFigure(graphicMove.StartPoint, true, graphicMove.IsClosed); break; } case GraphicLineSegment graphicLineTo: { ctx.LineTo(graphicLineTo.To, true, true); break; } case GraphicCubicBezierSegment graphicCubicBezier: { ctx.BezierTo(graphicCubicBezier.ControlPoint1, graphicCubicBezier.ControlPoint2, graphicCubicBezier.EndPoint, true, true); break; } case GraphicQuadraticBezierSegment graphicQuadraticBezier: { ctx.QuadraticBezierTo(graphicQuadraticBezier.ControlPoint, graphicQuadraticBezier.EndPoint, true, true); break; } } } ctx.Close(); geometry.Freeze(); return(geometry); }
/// <summary> /// Create an ellipse path with absolute points from the definition with /// relative values (radius) /// </summary> public static GraphicPathGeometry EllipseToGeometry(Point center, double radiusX, double radiusY) { Point[] points = new Point[pointCount]; radiusX = Math.Abs(radiusX); radiusY = Math.Abs(radiusY); // Set the X coordinates double mid = radiusX * arcAsBezier; points[0].X = points[1].X = points[11].X = points[12].X = center.X + radiusX; points[2].X = points[10].X = center.X + mid; points[3].X = points[9].X = center.X; points[4].X = points[8].X = center.X - mid; points[5].X = points[6].X = points[7].X = center.X - radiusX; // Set the Y coordinates mid = radiusY * arcAsBezier; points[2].Y = points[3].Y = points[4].Y = center.Y + radiusY; points[1].Y = points[5].Y = center.Y + mid; points[0].Y = points[6].Y = points[12].Y = center.Y; points[7].Y = points[11].Y = center.Y - mid; points[8].Y = points[9].Y = points[10].Y = center.Y - radiusY; var geometry = new GraphicPathGeometry(); var move = new GraphicMoveSegment { StartPoint = points[0] }; move.IsClosed = true; geometry.Segments.Add(move); // i == 0, 3, 6, 9 for (int i = 0; i < 12; i += 3) { var bezier = new GraphicCubicBezierSegment(); geometry.Segments.Add(bezier); bezier.ControlPoint1 = points[i + 1]; bezier.ControlPoint2 = points[i + 2]; bezier.EndPoint = points[i + 3]; } return(geometry); }
/// <summary> /// Parse an SVG shape and return a GraphicPathGeometry /// </summary> public GraphicPathGeometry Parse(XElement shape, Matrix currentTransformationMatrix) { GraphicPathGeometry geometry = null; switch (shape.Name.LocalName) { case "path": geometry = ParsePath(shape); break; case "polygon": geometry = ParsePolygon(shape); break; case "circle": geometry = ParseCircle(shape); break; case "ellipse": geometry = ParseEllipse(shape); break; case "rect": geometry = ParseRect(shape); break; case "line": geometry = ParseLine(shape); break; case "polyline": geometry = ParsePolyline(shape); break; } if (geometry != null) { var trans = new TransformVisual(); geometry = trans.Transform(geometry, currentTransformationMatrix); } return(geometry); }
/// <summary> /// Parse a line /// </summary> private static GraphicPathGeometry ParseLine(XElement path) { var x1 = GetDoubleAttr(path, "x1"); var y1 = GetDoubleAttr(path, "y1"); var x2 = GetDoubleAttr(path, "x2"); var y2 = GetDoubleAttr(path, "y2"); GraphicPathGeometry geometry = new GraphicPathGeometry(); var move = new GraphicMoveSegment { StartPoint = new Point(x1, y1) }; move.IsClosed = false; geometry.Segments.Add(move); var lineTo = new GraphicLineSegment { To = new Point(x2, y2) }; geometry.Segments.Add(lineTo); return(geometry); }
/// <summary> /// Parse a line /// </summary> private GraphicPathGeometry ParseLine(XElement path) { var x1 = GetLengthPercentAttr(path, "x1", PercentBaseSelector.ViewBoxWidth); var y1 = GetLengthPercentAttr(path, "y1", PercentBaseSelector.ViewBoxHeight); var x2 = GetLengthPercentAttr(path, "x2", PercentBaseSelector.ViewBoxWidth); var y2 = GetLengthPercentAttr(path, "y2", PercentBaseSelector.ViewBoxHeight); GraphicPathGeometry geometry = new GraphicPathGeometry(); var move = new GraphicMoveSegment { StartPoint = new Point(x1, y1) }; move.IsClosed = false; geometry.Segments.Add(move); var lineTo = new GraphicLineSegment { To = new Point(x2, y2) }; geometry.Segments.Add(lineTo); return(geometry); }
private const double arcAsBezier = 0.5522847498307933984; // =( \/2 - 1)*4/3 /// <summary> /// Create a rectangle with absolute points from the rectangle /// definition with relative values (width, height) /// </summary> public static GraphicPathGeometry RectToGeometry(Rect rect, double radiusX, double radiusY) { GraphicPathGeometry geometry = new GraphicPathGeometry(); if (!DoubleUtilities.IsZero(radiusX) && !DoubleUtilities.IsZero(radiusY)) { var points = GetRectPointList(rect, radiusX, radiusY); var move = new GraphicMoveSegment { StartPoint = points[0] }; move.IsClosed = true; geometry.Segments.Add(move); var bezier = new GraphicCubicBezierSegment(); geometry.Segments.Add(bezier); bezier.ControlPoint1 = points[1]; bezier.ControlPoint2 = points[2]; bezier.EndPoint = points[3]; var lineTo = new GraphicLineSegment { To = points[4] }; geometry.Segments.Add(lineTo); bezier = new GraphicCubicBezierSegment(); geometry.Segments.Add(bezier); bezier.ControlPoint1 = points[5]; bezier.ControlPoint2 = points[6]; bezier.EndPoint = points[7]; lineTo = new GraphicLineSegment { To = points[8] }; geometry.Segments.Add(lineTo); bezier = new GraphicCubicBezierSegment(); geometry.Segments.Add(bezier); bezier.ControlPoint1 = points[9]; bezier.ControlPoint2 = points[10]; bezier.EndPoint = points[11]; lineTo = new GraphicLineSegment { To = points[12] }; geometry.Segments.Add(lineTo); bezier = new GraphicCubicBezierSegment(); geometry.Segments.Add(bezier); bezier.ControlPoint1 = points[13]; bezier.ControlPoint2 = points[14]; bezier.EndPoint = points[15]; } else { var points = GetRectPointList(rect); var move = new GraphicMoveSegment { StartPoint = points[0] }; move.IsClosed = true; geometry.Segments.Add(move); var lineTo = new GraphicLineSegment { To = points[1] }; geometry.Segments.Add(lineTo); lineTo = new GraphicLineSegment { To = points[2] }; geometry.Segments.Add(lineTo); lineTo = new GraphicLineSegment { To = points[3] }; geometry.Segments.Add(lineTo); } return(geometry); }
/// <summary> /// Generate the XAML source code for a PathGeometry /// </summary> public static void GeneratePathGeometry(StringBuilder result, GraphicPathGeometry geometry, int level) { GeneratePathGeometry(result, geometry, level, string.Empty); }
/// <summary> /// Generate the raw (pure) stream geometry for a single graphic path /// </summary> public static string GenerateStreamGeometry(GraphicPathGeometry geometry, bool includeFillRule = true) { StringBuilder result = new StringBuilder(); bool closeLastPath = false; if (includeFillRule) { switch (geometry.FillRule) { case GraphicFillRule.EvenOdd: result.Append("F0"); break; case GraphicFillRule.NoneZero: result.Append("F1"); break; } } foreach (var segment in geometry.Segments) { switch (segment) { case GraphicMoveSegment graphicMove: { if (closeLastPath) { result.Append("z "); } result.Append("M"); SourceFormatterHelper.AppendPoint(result, graphicMove.StartPoint.X, graphicMove.StartPoint.Y); closeLastPath = graphicMove.IsClosed; break; } case GraphicLineSegment graphicLineTo: { result.Append("L"); SourceFormatterHelper.AppendPoint(result, graphicLineTo.To); break; } case GraphicCubicBezierSegment graphicCubicBezier: { result.Append("C"); SourceFormatterHelper.AppendPoint(result, graphicCubicBezier.ControlPoint1); SourceFormatterHelper.AppendPoint(result, graphicCubicBezier.ControlPoint2); SourceFormatterHelper.AppendPoint(result, graphicCubicBezier.EndPoint); break; } case GraphicQuadraticBezierSegment graphicQuadraticBezier: { result.Append("Q"); SourceFormatterHelper.AppendPoint(result, graphicQuadraticBezier.ControlPoint); SourceFormatterHelper.AppendPoint(result, graphicQuadraticBezier.EndPoint); break; } default: break; } } if (closeLastPath) { result.Append("z"); } var len = result.Length; if (result[len - 1] == ' ') { result.Remove(len - 1, 1); } return(result.ToString()); }
/// <summary> /// Generate the XAML source code for a PathGeometry plus an optional xKey attribute /// </summary> private static void GeneratePathGeometry(StringBuilder result, GraphicPathGeometry geometry, int level, string xKey) { bool finalizeLastFigure = false; var indent = SourceFormatterHelper.GetTagIndent(level); var indent1 = SourceFormatterHelper.GetTagIndent(level + 1); var indent2 = SourceFormatterHelper.GetTagIndent(level + 2); var pathGeometryTag = "PathGeometry"; string fillRule = string.Empty; switch (geometry.FillRule) { case GraphicFillRule.EvenOdd: fillRule = "EvenOdd"; break; case GraphicFillRule.NoneZero: fillRule = "Nonzero"; break; } if (string.IsNullOrEmpty(xKey)) { result.AppendLine(string.Format(CultureInfo.InvariantCulture, "{0}<{1} FillRule=\"{2}\">", indent, pathGeometryTag, fillRule)); } else { var indentPathGeometryProperty = SourceFormatterHelper.GetPropertyIndent(level, pathGeometryTag); result.AppendLine(string.Format(CultureInfo.InvariantCulture, "{0}<{1} x:Key=\"{2}\"", indent, pathGeometryTag, xKey)); result.AppendLine(string.Format(CultureInfo.InvariantCulture, "{0}FillRule=\"{1}\">", indentPathGeometryProperty, fillRule)); } var pathFigureTag = "PathFigure"; foreach (var segment in geometry.Segments) { switch (segment) { case GraphicMoveSegment graphicMove: { if (finalizeLastFigure) { result.Append(indent1); result.AppendLine("</PathFigure>"); } var indentPathFigureProperty = SourceFormatterHelper.GetPropertyIndent(level + 1, pathFigureTag); result.Append(string.Format(CultureInfo.InvariantCulture, "{0}<{1} IsClosed=", indent1, pathFigureTag)); SourceFormatterHelper.AppendXamlBool(result, graphicMove.IsClosed); result.AppendLine(); result.Append(indentPathFigureProperty); result.Append("StartPoint="); SourceFormatterHelper.AppendXamlPoint(result, graphicMove.StartPoint.X, graphicMove.StartPoint.Y); result.AppendLine(">"); finalizeLastFigure = true; break; } case GraphicLineSegment graphicLineTo: { result.Append(indent2); result.Append("<LineSegment Point="); SourceFormatterHelper.AppendXamlPoint(result, graphicLineTo.To); result.AppendLine(" />"); break; } case GraphicCubicBezierSegment graphicCubicBezier: { var tag = "BezierSegment"; var indentProperty = SourceFormatterHelper.GetPropertyIndent(level + 2, tag); result.Append(string.Format(CultureInfo.InvariantCulture, "{0}<{1} Point1=", indent2, tag)); SourceFormatterHelper.AppendXamlPoint(result, graphicCubicBezier.ControlPoint1); result.AppendLine(); result.Append(indentProperty); result.Append("Point2="); SourceFormatterHelper.AppendXamlPoint(result, graphicCubicBezier.ControlPoint2); result.AppendLine(); result.Append(indentProperty); result.Append("Point3="); SourceFormatterHelper.AppendXamlPoint(result, graphicCubicBezier.EndPoint); result.AppendLine(" />"); break; } case GraphicQuadraticBezierSegment graphicQuadraticBezier: { var tag = "QuadraticBezierSegment"; var indentProperty = SourceFormatterHelper.GetPropertyIndent(level + 2, tag); result.Append(string.Format(CultureInfo.InvariantCulture, "{0}<{1} Point1=", indent2, tag)); SourceFormatterHelper.AppendXamlPoint(result, graphicQuadraticBezier.ControlPoint); result.AppendLine(); result.Append(indentProperty); result.Append("Point2="); SourceFormatterHelper.AppendXamlPoint(result, graphicQuadraticBezier.EndPoint); result.AppendLine(" />"); break; } default: break; } } if (finalizeLastFigure) { result.Append(indent1); result.AppendLine($"</{pathFigureTag}>"); } result.AppendLine($"{indent}</{pathGeometryTag}>"); }
/// <summary> /// Generates a WPF geometry for a single graphic path geometry /// </summary> public static Geometry GenerateGeometry(GraphicPathGeometry graphicPathGeometry) { if (graphicPathGeometry == null) { return(null); } PathGeometry pathGeometry = new PathGeometry(); pathGeometry.FillRule = ConvertFillRule(graphicPathGeometry.FillRule); PathFigureCollection pathFigureCollection = new PathFigureCollection(); pathGeometry.Figures = pathFigureCollection; PathSegmentCollection pathSegmentCollection = null; foreach (var segment in graphicPathGeometry.Segments) { switch (segment) { case GraphicMoveSegment graphicMove: { var pathFigure = new PathFigure(); pathFigureCollection.Add(pathFigure); pathFigure.StartPoint = graphicMove.StartPoint; pathFigure.IsClosed = graphicMove.IsClosed; pathSegmentCollection = new PathSegmentCollection(); pathFigure.Segments = pathSegmentCollection; break; } case GraphicLineSegment graphicLineTo: { LineSegment lineSegment = new LineSegment(); pathSegmentCollection.Add(lineSegment); lineSegment.Point = graphicLineTo.To; break; } case GraphicCubicBezierSegment graphicCubicBezier: { BezierSegment bezierSegment = new BezierSegment(); pathSegmentCollection.Add(bezierSegment); bezierSegment.Point1 = graphicCubicBezier.ControlPoint1; bezierSegment.Point2 = graphicCubicBezier.ControlPoint2; bezierSegment.Point3 = graphicCubicBezier.EndPoint; break; } case GraphicQuadraticBezierSegment graphicQuadraticBezier: { QuadraticBezierSegment quadraticBezierSegment = new QuadraticBezierSegment(); pathSegmentCollection.Add(quadraticBezierSegment); quadraticBezierSegment.Point1 = graphicQuadraticBezier.ControlPoint; quadraticBezierSegment.Point2 = graphicQuadraticBezier.EndPoint; break; } } } pathGeometry.Freeze(); return(pathGeometry); }
/// <summary> /// Transform a single geometry /// </summary> public GraphicPathGeometry Transform(GraphicPathGeometry geometry, Matrix transformMatrix) { this.transformMatrix = transformMatrix; return(TransformGeometry(geometry)); }
/// <summary> /// Parse a single PDF page /// </summary> public GraphicGroup Run(PdfDictionary form, CSequence sequence, GraphicsState graphicsState) { this.returnGraphicGroup = new GraphicGroup(); graphicGroup = returnGraphicGroup; graphicsStateStack = new Stack <GraphicsState>(); fontState = new FontState(); textVectorizer = new TextVectorizer(); currentGraphicsState = graphicsState; Init(form); InitColor(); Point currentPoint = new Point(0, 0); GraphicMoveSegment lastMove = null; ResetCurrentGeometry(); for (int index = 0; index < sequence.Count; index++) { var contentOperator = sequence[index] as COperator; switch (contentOperator.OpCode.OpCodeName) { // path construction operators // rectangle case OpCodeName.re: { if (currentGeometry == null) { currentGeometry = new GraphicPathGeometry(); } var x = PdfUtilities.GetDouble(contentOperator.Operands[0]); var y = PdfUtilities.GetDouble(contentOperator.Operands[1]); var width = PdfUtilities.GetDouble(contentOperator.Operands[2]); var height = PdfUtilities.GetDouble(contentOperator.Operands[3]); var point1 = MatrixUtilities.TransformPoint(x, y, currentGraphicsState.CurrentTransformationMatrix); var point2 = MatrixUtilities.TransformPoint(x + width, y + height, currentGraphicsState.CurrentTransformationMatrix); var move = new GraphicMoveSegment { StartPoint = point1 }; currentGeometry.Segments.Add(move); var lineTo = new GraphicLineSegment { To = new Point(point2.X, point1.Y) }; currentGeometry.Segments.Add(lineTo); lineTo = new GraphicLineSegment { To = new Point(point2.X, point2.Y) }; currentGeometry.Segments.Add(lineTo); lineTo = new GraphicLineSegment { To = new Point(point1.X, point2.Y) }; currentGeometry.Segments.Add(lineTo); move.IsClosed = true; lastMove = move; currentPoint = point1; break; } // move to case OpCodeName.m: { if (currentGeometry == null) { currentGeometry = new GraphicPathGeometry(); } var x = PdfUtilities.GetDouble(contentOperator.Operands[0]); var y = PdfUtilities.GetDouble(contentOperator.Operands[1]); var point = MatrixUtilities.TransformPoint(x, y, currentGraphicsState.CurrentTransformationMatrix); var move = new GraphicMoveSegment { StartPoint = point }; currentGeometry.Segments.Add(move); lastMove = move; currentPoint = point; break; } // line to case OpCodeName.l: { var x = PdfUtilities.GetDouble(contentOperator.Operands[0]); var y = PdfUtilities.GetDouble(contentOperator.Operands[1]); var point = MatrixUtilities.TransformPoint(x, y, currentGraphicsState.CurrentTransformationMatrix); var lineTo = new GraphicLineSegment { To = point }; currentGeometry.Segments.Add(lineTo); currentPoint = point; break; } // cubic bezier case OpCodeName.c: { var bezier = new GraphicCubicBezierSegment(); currentGeometry.Segments.Add(bezier); var x = PdfUtilities.GetDouble(contentOperator.Operands[0]); var y = PdfUtilities.GetDouble(contentOperator.Operands[1]); bezier.ControlPoint1 = MatrixUtilities.TransformPoint(x, y, currentGraphicsState.CurrentTransformationMatrix); x = PdfUtilities.GetDouble(contentOperator.Operands[2]); y = PdfUtilities.GetDouble(contentOperator.Operands[3]); bezier.ControlPoint2 = MatrixUtilities.TransformPoint(x, y, currentGraphicsState.CurrentTransformationMatrix); x = PdfUtilities.GetDouble(contentOperator.Operands[4]); y = PdfUtilities.GetDouble(contentOperator.Operands[5]); bezier.EndPoint = MatrixUtilities.TransformPoint(x, y, currentGraphicsState.CurrentTransformationMatrix); currentPoint = bezier.EndPoint; break; } // quadratic bezier case OpCodeName.v: { var bezier = new GraphicCubicBezierSegment(); currentGeometry.Segments.Add(bezier); bezier.ControlPoint1 = currentPoint; var x = PdfUtilities.GetDouble(contentOperator.Operands[0]); var y = PdfUtilities.GetDouble(contentOperator.Operands[1]); bezier.ControlPoint2 = MatrixUtilities.TransformPoint(x, y, currentGraphicsState.CurrentTransformationMatrix); x = PdfUtilities.GetDouble(contentOperator.Operands[2]); y = PdfUtilities.GetDouble(contentOperator.Operands[3]); bezier.EndPoint = MatrixUtilities.TransformPoint(x, y, currentGraphicsState.CurrentTransformationMatrix); currentPoint = bezier.EndPoint; break; } // quadratic bezier case OpCodeName.y: { var bezier = new GraphicCubicBezierSegment(); currentGeometry.Segments.Add(bezier); var x = PdfUtilities.GetDouble(contentOperator.Operands[0]); var y = PdfUtilities.GetDouble(contentOperator.Operands[1]); bezier.ControlPoint1 = MatrixUtilities.TransformPoint(x, y, currentGraphicsState.CurrentTransformationMatrix); x = PdfUtilities.GetDouble(contentOperator.Operands[2]); y = PdfUtilities.GetDouble(contentOperator.Operands[3]); bezier.ControlPoint2 = MatrixUtilities.TransformPoint(x, y, currentGraphicsState.CurrentTransformationMatrix); bezier.EndPoint = bezier.ControlPoint2; currentPoint = bezier.EndPoint; break; } // path painting operators // end the path without filling and stroking case OpCodeName.n: { ResetCurrentGeometry(); break; } // set clipping path case OpCodeName.W: case OpCodeName.Wx: { currentGraphicsState.ClippingPath = currentGeometry; graphicGroup = new GraphicGroup(); graphicGroup.Clip = currentGeometry; returnGraphicGroup.Children.Add(graphicGroup); break; } // close path case OpCodeName.h: lastMove.IsClosed = true; break; // close and fill the path case OpCodeName.s: { lastMove.IsClosed = true; var path = GetCurrentPathFilled(); graphicGroup.Children.Add(path); ResetCurrentGeometry(); break; } // stroke the path case OpCodeName.S: { var path = GetCurrentPathStroked(); graphicGroup.Children.Add(path); ResetCurrentGeometry(); break; } // close, fill and stroke the path case OpCodeName.b: case OpCodeName.bx: { lastMove.IsClosed = true; var path = GetCurrentPathFilledAndStroked(); graphicGroup.Children.Add(path); ResetCurrentGeometry(); break; } // fill and stroke the path case OpCodeName.B: { var path = GetCurrentPathFilledAndStroked(); currentGeometry.FillRule = GraphicFillRule.NoneZero; graphicGroup.Children.Add(path); ResetCurrentGeometry(); break; } // fill and stroke the path case OpCodeName.Bx: { var path = GetCurrentPathFilledAndStroked(); currentGeometry.FillRule = GraphicFillRule.NoneZero; currentGeometry.FillRule = GraphicFillRule.EvenOdd; graphicGroup.Children.Add(path); ResetCurrentGeometry(); break; } // fill the path case OpCodeName.F: case OpCodeName.f: { var path = GetCurrentPathFilled(); currentGeometry.FillRule = GraphicFillRule.NoneZero; graphicGroup.Children.Add(path); ResetCurrentGeometry(); break; } // fill the path case OpCodeName.fx: { var path = GetCurrentPathFilled(); currentGeometry.FillRule = GraphicFillRule.EvenOdd; graphicGroup.Children.Add(path); ResetCurrentGeometry(); break; } // set color space for stroking operations case OpCodeName.CS: { var colorSpaceName = ((CName)contentOperator.Operands[0]).Name; currentGraphicsState.StrokeColorSpace = colorSpaceManager.GetColorSpace(colorSpaceName); break; } // set color space for nonstroking operations case OpCodeName.cs: { var colorSpaceName = ((CName)contentOperator.Operands[0]).Name; currentGraphicsState.ColorSpace = colorSpaceManager.GetColorSpace(colorSpaceName); break; } // set /DeviceRGB and non-stroked color case OpCodeName.rg: { currentGraphicsState.ColorSpace = colorSpaceManager.GetColorSpace(PdfKeys.DeviceRGB); currentGraphicsState.FillBrush = currentGraphicsState.ColorSpace.GetBrushDescriptor(contentOperator.Operands, currentGraphicsState.CurrentTransformationMatrix, currentGraphicsState.FillAlpha.Current); break; } // set /DeviceCMYK and non-stroked color case OpCodeName.k: { currentGraphicsState.ColorSpace = colorSpaceManager.GetColorSpace(PdfKeys.DeviceCMYK); currentGraphicsState.FillBrush = currentGraphicsState.ColorSpace.GetBrushDescriptor(contentOperator.Operands, currentGraphicsState.CurrentTransformationMatrix, currentGraphicsState.FillAlpha.Current); break; } // set /DeviceGray and non-stroked color case OpCodeName.g: { currentGraphicsState.ColorSpace = colorSpaceManager.GetColorSpace(PdfKeys.DeviceGray); currentGraphicsState.FillBrush = currentGraphicsState.ColorSpace.GetBrushDescriptor(contentOperator.Operands, currentGraphicsState.CurrentTransformationMatrix, currentGraphicsState.FillAlpha.Current); break; } // non-stroked color case OpCodeName.sc: { currentGraphicsState.FillBrush = currentGraphicsState.ColorSpace.GetBrushDescriptor(contentOperator.Operands, currentGraphicsState.CurrentTransformationMatrix, currentGraphicsState.FillAlpha.Current); break; } // ICC based non-stroked color case OpCodeName.scn: { currentGraphicsState.FillBrush = currentGraphicsState.ColorSpace.GetBrushDescriptor(contentOperator.Operands, currentGraphicsState.CurrentTransformationMatrix, currentGraphicsState.FillAlpha.Current); break; } // ICC based stroked color case OpCodeName.SCN: { currentGraphicsState.StrokeBrush = currentGraphicsState.StrokeColorSpace.GetBrushDescriptor(contentOperator.Operands, currentGraphicsState.CurrentTransformationMatrix, currentGraphicsState.StrokeAlpha.Current); break; } // set /DeviceRGB and stroked color case OpCodeName.RG: { currentGraphicsState.StrokeColorSpace = colorSpaceManager.GetColorSpace(PdfKeys.DeviceRGB); currentGraphicsState.StrokeBrush = currentGraphicsState.StrokeColorSpace.GetBrushDescriptor(contentOperator.Operands, currentGraphicsState.CurrentTransformationMatrix, currentGraphicsState.StrokeAlpha.Current); break; } // set /DeviceGray and stroked color case OpCodeName.G: { currentGraphicsState.StrokeColorSpace = colorSpaceManager.GetColorSpace(PdfKeys.DeviceGray); currentGraphicsState.StrokeBrush = currentGraphicsState.StrokeColorSpace.GetBrushDescriptor(contentOperator.Operands, currentGraphicsState.CurrentTransformationMatrix, currentGraphicsState.StrokeAlpha.Current); break; } // set /DeviceCMYK and stroked color case OpCodeName.K: { currentGraphicsState.StrokeColorSpace = colorSpaceManager.GetColorSpace(PdfKeys.DeviceCMYK); currentGraphicsState.StrokeBrush = currentGraphicsState.StrokeColorSpace.GetBrushDescriptor(contentOperator.Operands, currentGraphicsState.CurrentTransformationMatrix, currentGraphicsState.StrokeAlpha.Current); break; } // set stroked color case OpCodeName.SC: { currentGraphicsState.StrokeBrush = currentGraphicsState.StrokeColorSpace.GetBrushDescriptor(contentOperator.Operands, currentGraphicsState.CurrentTransformationMatrix, currentGraphicsState.StrokeAlpha.Current); break; } // shading case OpCodeName.sh: { var graphicPath = new GraphicPath(); var shadingDescriptor = shadingManager.GetShading(contentOperator.Operands); graphicPath.Geometry = currentGraphicsState.ClippingPath; graphicPath.FillBrush = shadingDescriptor.GetBrush(currentGraphicsState.CurrentTransformationMatrix, currentGraphicsState.ClippingPath.Bounds, currentGraphicsState.FillAlpha.Current, currentGraphicsState.SoftMask); graphicPath.ColorPrecision = shadingDescriptor.ColorPrecision; graphicGroup.Children.Add(graphicPath); break; } // begin text case OpCodeName.BT: { fontState.TextLineMatrix = Matrix.Identity; fontState.TextMatrix = Matrix.Identity; break; } // set current font case OpCodeName.Tf: { var fontName = ((CName)contentOperator.Operands[0]).Name; fontState.FontSize = PdfUtilities.GetDouble(contentOperator.Operands[1]); fontState.FontDescriptor = fontManager.GetFont(fontName); break; } // set rendering mode case OpCodeName.Tr: { fontState.RenderingMode = PdfUtilities.GetRenderingMode(contentOperator.Operands[0]); break; } // set font transformation matrix case OpCodeName.Tm: { var matrix = PdfUtilities.GetMatrix(contentOperator.Operands); fontState.TextMatrix = matrix; fontState.TextLineMatrix = matrix; break; } // translate line matrix case OpCodeName.Td: { var x = PdfUtilities.GetDouble(contentOperator.Operands[0]); var y = PdfUtilities.GetDouble(contentOperator.Operands[1]); // for some unknown reason the simple next statement doesn't // work, do it in small steps instead //fontState.TextLineMatrix.TranslatePrepend(x, y); var m = fontState.TextLineMatrix; m.TranslatePrepend(x, y); fontState.TextLineMatrix = m; fontState.TextMatrix = fontState.TextLineMatrix; break; } case OpCodeName.TD: { var x = PdfUtilities.GetDouble(contentOperator.Operands[0]); var y = PdfUtilities.GetDouble(contentOperator.Operands[1]); //fontState.TextLineMatrix.Translate(x, y); var m = fontState.TextLineMatrix; m.TranslatePrepend(x, y); fontState.TextLineMatrix = m; fontState.Leading = -y; fontState.TextMatrix = fontState.TextLineMatrix; break; } case OpCodeName.TL: { fontState.Leading = PdfUtilities.GetDouble(contentOperator.Operands[0]); break; } case OpCodeName.Tx: { var m = fontState.TextLineMatrix; m.TranslatePrepend(0, -fontState.Leading); fontState.TextLineMatrix = m; fontState.TextMatrix = fontState.TextLineMatrix; break; } case OpCodeName.QuoteSingle: { break; } case OpCodeName.QuoteDbl: { break; } // a single string case OpCodeName.Tj: { var text = (CString)contentOperator.Operands[0]; var textGraphic = textVectorizer.Vectorize(text.Value, currentGraphicsState, fontState); graphicGroup.Children.AddRange(textGraphic); break; } // multiple strings plus formatting case OpCodeName.TJ: { var array = (CArray)contentOperator.Operands[0]; HandleMultipleTextCommand(array); break; } // graphics state operators // push state onto the stack case OpCodeName.q: { var clone = currentGraphicsState.Clone(); graphicsStateStack.Push(clone); break; } // pop state from the stack case OpCodeName.Q: { currentGraphicsState = graphicsStateStack.Pop(); break; } // current transform matrix case OpCodeName.cm: { var matrix = PdfUtilities.GetMatrix(contentOperator.Operands); currentGraphicsState.TransformationMatrix *= matrix; break; } case OpCodeName.J: { currentGraphicsState.LineCap = GetLineCap(((CInteger)contentOperator.Operands[0]).Value); break; } case OpCodeName.j: { currentGraphicsState.LineJoin = GetLineJoin(((CInteger)contentOperator.Operands[0]).Value); break; } case OpCodeName.M: { currentGraphicsState.MiterLimit = PdfUtilities.GetDouble(contentOperator.Operands[0]); break; } case OpCodeName.d: { SetDashPattern(contentOperator.Operands); break; } // line width case OpCodeName.w: { currentGraphicsState.LineWidth = MatrixUtilities.TransformScale(PdfUtilities.GetDouble(contentOperator.Operands[0]), currentGraphicsState.CurrentTransformationMatrix); break; } // set parameters in the current graphic state of the given state name case OpCodeName.gs: { var name = contentOperator.Operands[0] as CName; extendedStatesManager.SetExtendedGraphicState(currentGraphicsState, fontState, name.Name); break; } case OpCodeName.Do: { var xObjectName = ((CName)contentOperator.Operands[0]).Name; RunXObject(xObjectName); break; } default: break; } } return(this.returnGraphicGroup); }
/// <summary> /// Reset the current path /// </summary> private void ResetCurrentGeometry() { currentGeometry = null; }
/// <summary> /// Add a char to the block and return its proxy /// </summary> /// <param name="character"></param> /// <returns></returns> public PositionBlockCharacter AddCharacter(GraphicPathGeometry character) { Characters.Add(character); return(new PositionBlockCharacter(this, Characters.Count - 1)); }
/// <summary> /// Convert a geometry to graphic geometry /// </summary> private static void ConvertToGraphicGeometry(GraphicPathGeometry graphicPathGeometry, Geometry geometry, Matrix fontTransformation) { switch (geometry) { case GeometryGroup group: { foreach (var child in group.Children) { ConvertToGraphicGeometry(graphicPathGeometry, child, fontTransformation); } break; } case PathGeometry path: { foreach (var figure in path.Figures) { var points = TransformPoint(figure.StartPoint, fontTransformation); var move = new GraphicMoveSegment { StartPoint = points }; move.IsClosed = figure.IsClosed; graphicPathGeometry.Segments.Add(move); foreach (var segment in figure.Segments) { switch (segment) { case LineSegment line: { var point = TransformPoint(line.Point, fontTransformation); var lineTo = new GraphicLineSegment { To = point }; graphicPathGeometry.Segments.Add(lineTo); break; } case BezierSegment bezier: { var gbezier = new GraphicCubicBezierSegment(); graphicPathGeometry.Segments.Add(gbezier); gbezier.ControlPoint1 = TransformPoint(bezier.Point1, fontTransformation); gbezier.ControlPoint2 = TransformPoint(bezier.Point2, fontTransformation); gbezier.EndPoint = TransformPoint(bezier.Point3, fontTransformation); break; } case PolyLineSegment polyLine: { foreach (var point in polyLine.Points) { var gpoint = TransformPoint(point, fontTransformation); var lineTo = new GraphicLineSegment { To = gpoint }; graphicPathGeometry.Segments.Add(lineTo); } break; } case PolyBezierSegment polyBezier: { for (int i = 0; i < polyBezier.Points.Count; i += 3) { var gbezier = new GraphicCubicBezierSegment(); graphicPathGeometry.Segments.Add(gbezier); gbezier.ControlPoint1 = TransformPoint(polyBezier.Points[i], fontTransformation); gbezier.ControlPoint2 = TransformPoint(polyBezier.Points[i + 1], fontTransformation); gbezier.EndPoint = TransformPoint(polyBezier.Points[i + 2], fontTransformation); } break; } } } } break; } } }
/// <summary> /// Initialize the generator /// </summary> public void Init() { Path = new GraphicPathGeometry(); currentPath = Path; }