/// <summary> /// Replaces the current content of the page with the specified content sequence. /// </summary> public PdfContent ReplaceContent(CSequence cseq) { if (cseq == null) { throw new ArgumentNullException(nameof(cseq)); } return(ReplaceContent(cseq.ToContent())); }
/// <summary> /// Get a matrix out of a sequence fof operands /// </summary> public static Matrix GetMatrix(CSequence operands) { var matrix = new Matrix(PdfUtilities.GetDouble(operands[0]), PdfUtilities.GetDouble(operands[1]), PdfUtilities.GetDouble(operands[2]), PdfUtilities.GetDouble(operands[3]), PdfUtilities.GetDouble(operands[4]), PdfUtilities.GetDouble(operands[5])); return(matrix); }
/// <summary> /// Convert a operands array to a simple double array /// </summary> public static List <double> CreateDoubleArray(CSequence operands) { int num = operands.Count; List <double> values = new List <double>(); for (int i = 0; i < num; i++) { values.Add(GetDouble(operands[i])); } return(values); }
/// <summary> /// Get a brush descriptor /// </summary> public IBrushDescriptor GetBrushDescriptor(CSequence operands, Matrix matrix, double alpha) { float[] colorValues = new float[numberColorComponents]; for (int i = 0; i < numberColorComponents; i++) { colorValues[i] = (float)PdfUtilities.GetDouble(operands[i]); } Color color = Color.FromAValues((float)alpha, colorValues, GetProfileUri()); return(new ICCBasedBrushDescriptor(color)); }
public StreamDecoder(PdfPage page) { _page = page; // https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/pdf_reference_archives/PDFReference.pdf // Chapters 4, 5, 9. Start at page 134 (pdf154), table 4.1 - operator categories; 156 (table 4.7) and page 163 (table 4.9 - paths) // https://stackoverflow.com/questions/29467539/encoding-of-pdf-text-string _content = ContentReader.ReadContent(page); // Uncomment to spew the page into stdout /*foreach (var c in _content) * { * if (c is not COperator op) Console.WriteLine($"####???{c.GetType().Name} - {c}"); * else Console.WriteLine($"{op.GetType().FullName} => {op.Name} ({op.OpCode.Description}) - {ShortDesc(op.Operands)}"); * }*/ }
/// <summary> /// Get a brush descriptor /// </summary> public IBrushDescriptor GetBrushDescriptor(CSequence operands, Matrix matrix, double alpha) { CSequence newSequence = new CSequence(); var numberColorValues = baseColorSpace.GetNumberOfValuesPerColor(); int index = LimitIndexToBoundaries(PdfUtilities.GetInteger(operands[0])) * numberColorValues; for (int i = 0; i < numberColorValues; i++) { var real = new CReal(); real.Value = lookup[index + i]; newSequence.Add(real); } var brushDescriptor = baseColorSpace.GetBrushDescriptor(newSequence, matrix, alpha); return(new IndexedBrushDescriptor(brushDescriptor)); }
/// <summary> /// Set the initial color space and color /// </summary> private void InitColor() { var seq = new CSequence(); var real = new CReal { Value = 0.0 }; seq.Add(real); currentGraphicsState.ColorSpace = colorSpaceManager.GetColorSpace(PdfKeys.DeviceGray); currentGraphicsState.FillBrush = currentGraphicsState.ColorSpace.GetBrushDescriptor(seq, currentGraphicsState.CurrentTransformationMatrix, currentGraphicsState.FillAlpha.Current); currentGraphicsState.StrokeBrush = currentGraphicsState.ColorSpace.GetBrushDescriptor(seq, currentGraphicsState.CurrentTransformationMatrix, currentGraphicsState.FillAlpha.Current); }
/// <summary> /// Get a brush descriptor /// </summary> public IBrushDescriptor GetBrushDescriptor(CSequence operands, Matrix matrix, double alpha) { IBrushDescriptor altColorSpaceDescriptor = null; var values = PdfUtilities.CreateDoubleArray(operands); var altColorSpaceValues = function.Calculate(values); if (altColorSpaceValues != null) { var altColorOperands = new CSequence(); foreach (var val in altColorSpaceValues) { var real = new CReal(); real.Value = val; altColorOperands.Add(real); } altColorSpaceDescriptor = alternateColorSpace.GetBrushDescriptor(altColorOperands, matrix, alpha); } return(new DeviceNBrushDescriptor(altColorSpaceDescriptor)); }
/// <summary> /// Sets the dash pattern /// </summary> private void SetDashPattern(CSequence operands) { var dashArray = (CArray)operands[0]; var dashPhase = PdfUtilities.GetDouble(operands[1]); if (dashArray.Count == 0) { currentGraphicsState.Dashes = null; currentGraphicsState.DashOffset = 0; return; } var dashes = new List <double>(); foreach (var val in dashArray) { var dbl = MatrixUtilities.TransformScale(PdfUtilities.GetDouble(val), currentGraphicsState.CurrentTransformationMatrix); dashes.Add(dbl); } currentGraphicsState.Dashes = dashes; currentGraphicsState.DashOffset = dashPhase; }
/// <summary> /// Get an extended graphics state from the given state name /// </summary> public IShading GetShading(CSequence operands) { var shadingName = operands[0] as CName; return(shadings[shadingName.Name]); }
private string ShortDesc(CSequence opOperands) { return(string.Join("; ", opOperands.Select(Describe))); }
/// <summary> /// Parses whatever comes until the specified stop symbol is reached. /// </summary> void ParseObject(CSequence sequence, CSymbol stop) { CSymbol symbol; while ((symbol = ScanNextToken()) != CSymbol.Eof) { if (symbol == stop) { return; } switch (symbol) { case CSymbol.Comment: // ignore comments break; case CSymbol.Integer: CInteger n = new CInteger(); n.Value = lexer.TokenToInteger; operands.Add(n); break; case CSymbol.Real: CReal r = new CReal(); r.Value = lexer.TokenToReal; operands.Add(r); break; case CSymbol.String: case CSymbol.HexString: case CSymbol.UnicodeString: case CSymbol.UnicodeHexString: CString s = new CString(); s.Value = lexer.Token; operands.Add(s); break; case CSymbol.Name: CName name = new CName(); name.Name = lexer.Token; operands.Add(name); break; case CSymbol.Operator: COperator op = CreateOperator(); operands.Clear(); sequence.Add(op); break; case CSymbol.BeginArray: CArray array = new CArray(); Debug.Assert(operands.Count == 0, "Array within array..."); ParseObject(array, CSymbol.EndArray); array.Add(operands); operands.Clear(); operands.Add((CObject)array); break; case CSymbol.EndArray: throw new ContentReaderException("Unexpected: ']'"); } } }
/// <summary> /// Get a brush descriptor /// </summary> public IBrushDescriptor GetBrushDescriptor(CSequence operands, Matrix matrix, double alpha) { return(new UnknownBrushDescriptor(GetColor(null, alpha))); }
/// <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> /// Reads the specified content. /// </summary> /// <param name="content">The content.</param> static public CSequence ReadContent(MemoryStream content) { CParser parser = new CParser(content); CSequence sequence = parser.ReadContent(); return sequence; }
/// <summary> /// Get a brush descriptor /// </summary> public IBrushDescriptor GetBrushDescriptor(CSequence operands, Matrix matrix, double alpha) { var values = PdfUtilities.CreateDoubleArray(operands); return(new CMYKDeviceBrushDescriptor(GetColor(values, alpha))); }
/// <summary> /// Run the XObject with the given name /// </summary> private void RunXObject(string name) { var xobjectDict = xObjectManager.GetXObject(name); var subType = xobjectDict.Elements.GetName(PdfKeys.Subtype); if (subType != PdfKeys.Form) { return; } var cloneCurrentGraphicsState = currentGraphicsState.Clone(); var matrixArray = xobjectDict.Elements.GetArray(PdfKeys.Matrix); Matrix matrix = Matrix.Identity; if (matrixArray != null) { matrix = PdfUtilities.GetMatrix(matrixArray); cloneCurrentGraphicsState.TransformationMatrix *= matrix; } cloneCurrentGraphicsState.FillAlpha.Layer = 1.0; cloneCurrentGraphicsState.FillAlpha.Object = 1.0; cloneCurrentGraphicsState.StrokeAlpha.Layer = 1.0; cloneCurrentGraphicsState.StrokeAlpha.Object = 1.0; cloneCurrentGraphicsState.SoftMask = null; CSequence sequence = ContentReader.ReadContent(xobjectDict.Stream.UnfilteredValue); var interpreter = new ContentInterpreter(); var group = interpreter.Run(xobjectDict, sequence, cloneCurrentGraphicsState); // do some optimizations that the post-processor cannot do if (group.Children.Count == 1 && group.Clip == null && !DoubleUtilities.IsEqual(currentGraphicsState.FillAlpha.Object, 1.0)) { // the layer has only 1 child and the layer has an opacity set other than 1 -> // recreate the layer but with the layer opacity set which gets "added" to each single object // on that layer. Because there is only 1 object the result is the same as if the object sits // on a semi transparent layer. That saves a group for a single object. cloneCurrentGraphicsState = currentGraphicsState.Clone(); if (matrixArray != null) { cloneCurrentGraphicsState.TransformationMatrix *= matrix; } cloneCurrentGraphicsState.FillAlpha.Layer = currentGraphicsState.FillAlpha.Object; cloneCurrentGraphicsState.StrokeAlpha.Layer = currentGraphicsState.StrokeAlpha.Object; group = interpreter.Run(xobjectDict, sequence, cloneCurrentGraphicsState); graphicGroup.Children.Add(group.Children[0]); } else { group.Opacity = currentGraphicsState.FillAlpha.Object; graphicGroup.Children.Add(group); } }
/// <summary> /// Parses whatever comes until the specified stop symbol is reached. /// </summary> void ParseObject(CSequence sequence, CSymbol stop) { CSymbol symbol; while ((symbol = ScanNextToken()) != CSymbol.Eof) { if (symbol == stop) { return; } CString s; COperator op; switch (symbol) { case CSymbol.Comment: // ignore comments break; case CSymbol.Integer: CInteger n = new CInteger(); n.Value = _lexer.TokenToInteger; _operands.Add(n); break; case CSymbol.Real: CReal r = new CReal(); r.Value = _lexer.TokenToReal; _operands.Add(r); break; case CSymbol.String: case CSymbol.HexString: case CSymbol.UnicodeString: case CSymbol.UnicodeHexString: s = new CString(); s.Value = _lexer.Token; _operands.Add(s); break; case CSymbol.Dictionary: s = new CString(); s.Value = _lexer.Token; s.CStringType = CStringType.Dictionary; _operands.Add(s); op = CreateOperator(OpCodeName.Dictionary); //_operands.Clear(); sequence.Add(op); break; case CSymbol.Name: CName name = new CName(); name.Name = _lexer.Token; _operands.Add(name); break; case CSymbol.Operator: op = CreateOperator(); //_operands.Clear(); sequence.Add(op); break; case CSymbol.BeginArray: CArray array = new CArray(); if (_operands.Count != 0) { ContentReaderDiagnostics.ThrowContentReaderException("Array within array..."); } ParseObject(array, CSymbol.EndArray); array.Add(_operands); _operands.Clear(); _operands.Add((CObject)array); break; case CSymbol.EndArray: ContentReaderDiagnostics.HandleUnexpectedCharacter(']'); break; #if DEBUG default: Debug.Assert(false); break; #endif } } }
/// <summary> /// Reads the specified content. /// </summary> /// <param name="content">The content.</param> static public CSequence ReadContent(byte[] content) { CParser parser = new CParser(content); CSequence sequence = parser.ReadContent(); return sequence; }