/** <summary>Gets the direction corresponding to the given value.</summary> */ public static RotationEnum Get( PdfInteger value ) { if(value == null) return RotationEnum.Downward; int normalizedValue = (int)(Math.Round(value.RawValue / 90d) % 4) * 90; if(normalizedValue < 0) {normalizedValue += 360 * (int)Math.Ceiling(-normalizedValue / 360d);} return (RotationEnum)normalizedValue; }
/// <summary> /// Writes the specified value to the PDF stream. /// </summary> public void Write(PdfInteger value) { WriteSeparator(CharCat.Character); _lastCat = CharCat.Character; WriteRaw(value.Value.ToString(CultureInfo.InvariantCulture)); }
/** * <summary>Loads the font data.</summary> */ private void Load( OpenFontParser parser ) { glyphIndexes = parser.GlyphIndexes; glyphKernings = parser.GlyphKernings; glyphWidths = parser.GlyphWidths; PdfDictionary baseDataObject = BaseDataObject; // BaseFont. baseDataObject[PdfName.BaseFont] = new PdfName(parser.FontName); // Subtype. baseDataObject[PdfName.Subtype] = PdfName.Type0; // Encoding. baseDataObject[PdfName.Encoding] = PdfName.IdentityH; //TODO: this is a simplification (to refine later). // Descendant font. PdfDictionary cidFontDictionary = new PdfDictionary( new PdfName[] { PdfName.Type }, new PdfDirectObject[] { PdfName.Font } ); // CIDFont dictionary [PDF:1.6:5.6.3]. { // Subtype. PdfName subType; switch (parser.OutlineFormat) { case OpenFontParser.OutlineFormatEnum.TrueType: subType = PdfName.CIDFontType2; break; case OpenFontParser.OutlineFormatEnum.CFF: subType = PdfName.CIDFontType0; break; default: throw new NotImplementedException(); } cidFontDictionary[PdfName.Subtype] = subType; // BaseFont. cidFontDictionary[PdfName.BaseFont] = new PdfName(parser.FontName); // CIDSystemInfo. cidFontDictionary[PdfName.CIDSystemInfo] = new PdfDictionary( new PdfName[] { PdfName.Registry, PdfName.Ordering, PdfName.Supplement }, new PdfDirectObject[] { new PdfTextString("Adobe"), new PdfTextString("Identity"), PdfInteger.Get(0) } ); // Generic predefined CMap (Identity-H/V (Adobe-Identity-0)) [PDF:1.6:5.6.4]. // FontDescriptor. cidFontDictionary[PdfName.FontDescriptor] = Load_CreateFontDescriptor(parser); // Encoding. Load_CreateEncoding(baseDataObject, cidFontDictionary); } baseDataObject[PdfName.DescendantFonts] = new PdfArray(new PdfDirectObject[] { File.Register(cidFontDictionary) }); Load(); }
/// <summary> /// Writes the specified value to the PDF stream. /// </summary> public void Write(PdfInteger value) { WriteSeparator(CharCat.Character); this.lastCat = CharCat.Character; WriteRaw(value.Value.ToString()); }
/** * <summary>Serializes the xref stream entries into the stream body.</summary> */ private void Flush( IOutputStream stream ) { // 1. Body. PdfArray indexArray = new PdfArray(); int[] entryFieldSizes = new int[] { EntryField0Size, GetFieldSize((int)stream.Length), // NOTE: We assume this xref stream is the last indirect object. EntryField2Size }; { // Get the stream buffer! IBuffer body = Body; // Delete the old entries! body.SetLength(0); // Serializing the entries into the stream buffer... int prevObjectNumber = -2; // Previous-entry object number. foreach (XRefEntry entry in entries.Values) { int entryNumber = entry.Number; if (entryNumber - prevObjectNumber != 1) // Current subsection terminated. { if (indexArray.Count > 0) { indexArray.Add(PdfInteger.Get(prevObjectNumber - ((PdfInteger)indexArray[indexArray.Count - 1]).IntValue + 1)); } // Number of entries in the previous subsection. indexArray.Add(PdfInteger.Get(entryNumber)); // First object number in the next subsection. } prevObjectNumber = entryNumber; switch (entry.Usage) { case XRefEntry.UsageEnum.Free: body.Append((byte)FreeEntryType); body.Append(NumberToByteArray(entry.Offset, entryFieldSizes[1])); body.Append(NumberToByteArray(entry.Generation, entryFieldSizes[2])); break; case XRefEntry.UsageEnum.InUse: body.Append((byte)InUseEntryType); body.Append(NumberToByteArray(entry.Offset, entryFieldSizes[1])); body.Append(NumberToByteArray(entry.Generation, entryFieldSizes[2])); break; case XRefEntry.UsageEnum.InUseCompressed: body.Append((byte)InUseCompressedEntryType); body.Append(NumberToByteArray(entry.StreamNumber, entryFieldSizes[1])); body.Append(NumberToByteArray(entry.Offset, entryFieldSizes[2])); break; default: throw new NotSupportedException(); } } indexArray.Add(PdfInteger.Get(prevObjectNumber - ((PdfInteger)indexArray[indexArray.Count - 1]).IntValue + 1)); // Number of entries in the previous subsection. } // 2. Header. { PdfDictionary header = Header; header[PdfName.Index] = indexArray; header[PdfName.Size] = PdfInteger.Get(File.IndirectObjects.Count + 1); header[PdfName.W] = new PdfArray( PdfInteger.Get(entryFieldSizes[0]), PdfInteger.Get(entryFieldSizes[1]), PdfInteger.Get(entryFieldSizes[2]) ); } }
/** * <summary>Creates the character code mapping for composite fonts.</summary> */ private void Load_CreateEncoding( PdfDictionary font, PdfDictionary cidFont ) { /* * NOTE: Composite fonts map text shown by content stream strings through a 2-level encoding * scheme: * character code -> CID (character index) -> GID (glyph index) * This works for rendering purposes, but if we want our text data to be intrinsically meaningful, * we need a further mapping towards some standard character identification scheme (Unicode): * Unicode <- character code -> CID -> GID * Such mapping may be provided by a known CID collection or (in case of custom encodings like * Identity-H) by an explicit ToUnicode CMap. * CID -> GID mapping is typically identity, that is CIDS correspond to GIDS, so we don't bother * about that. Our base encoding is Identity-H, that is character codes correspond to CIDs; * however, sometimes a font maps multiple Unicode codepoints to the same GID (for example, the * hyphen glyph may be associated to the hyphen (\u2010) and minus (\u002D) symbols), breaking * the possibility to recover their original Unicode values once represented as character codes * in content stream strings. In this case, we are forced to remap the exceeding codes and * generate an explicit CMap (TODO: I tried to emit a differential CMap using the usecmap * operator in order to import Identity-H as base encoding, but it failed in several engines * (including Acrobat, Ghostscript, Poppler, whilst it surprisingly worked with pdf.js), so we * have temporarily to stick with full CMaps). */ // Encoding [PDF:1.7:5.6.1,5.6.4]. PdfDirectObject encodingObject = PdfName.IdentityH; SortedDictionary <ByteArray, int> sortedCodes; { codes = new BiDictionary <ByteArray, int>(glyphIndexes.Count); int lastRemappedCharCodeValue = 0; IList <int> removedGlyphIndexKeys = null; foreach (KeyValuePair <int, int> glyphIndexEntry in glyphIndexes.ToList()) { int glyphIndex = glyphIndexEntry.Value; ByteArray charCode = new ByteArray(new byte[] { (byte)((glyphIndex >> 8) & 0xFF), (byte)(glyphIndex & 0xFF) }); // Checking for multiple Unicode codepoints which map to the same glyph index... /* * NOTE: In case the same glyph index maps to multiple Unicode codepoints, we are forced to * alter the identity encoding creating distinct cmap entries for the exceeding codepoints. */ if (codes.ContainsKey(charCode)) { if (glyphIndex == 0) // .notdef glyph already mapped. { if (removedGlyphIndexKeys == null) { removedGlyphIndexKeys = new List <int>(); } removedGlyphIndexKeys.Add(glyphIndexEntry.Key); continue; } // Assigning the new character code... /* * NOTE: As our base encoding is identity, we have to look for a value that doesn't * collide with existing glyph indices. */ while (glyphIndexes.ContainsValue(++lastRemappedCharCodeValue)) { ; } charCode.Data[0] = (byte)((lastRemappedCharCodeValue >> 8) & 0xFF); charCode.Data[1] = (byte)(lastRemappedCharCodeValue & 0xFF); } else if (glyphIndex == 0) // .notdef glyph. { DefaultCode = glyphIndexEntry.Key; } codes[charCode] = glyphIndexEntry.Key; } if (removedGlyphIndexKeys != null) { foreach (int removedGlyphIndexKey in removedGlyphIndexKeys) { glyphIndexes.Remove(removedGlyphIndexKey); } } sortedCodes = new SortedDictionary <ByteArray, int>(codes); if (lastRemappedCharCodeValue > 0) // Custom encoding. { string cmapName = "Custom"; bytes::IBuffer cmapBuffer = CMapBuilder.Build( CMapBuilder.EntryTypeEnum.CID, cmapName, sortedCodes, delegate(KeyValuePair <ByteArray, int> codeEntry) { return(glyphIndexes[codeEntry.Value]); } ); encodingObject = File.Register( new PdfStream( new PdfDictionary( new PdfName[] { PdfName.Type, PdfName.CMapName, PdfName.CIDSystemInfo }, new PdfDirectObject[] { PdfName.CMap, new PdfName(cmapName), new PdfDictionary( new PdfName[] { PdfName.Registry, PdfName.Ordering, PdfName.Supplement }, new PdfDirectObject[] { PdfTextString.Get("Adobe"), PdfTextString.Get("Identity"), PdfInteger.Get(0) } ) } ), cmapBuffer ) ); } } font[PdfName.Encoding] = encodingObject; // Character-code-to-CID mapping. cidFont[PdfName.CIDToGIDMap] = PdfName.Identity; // CID-to-glyph-index mapping. // ToUnicode [PDF:1.6:5.9.2]. PdfDirectObject toUnicodeObject = null; { bytes::IBuffer toUnicodeBuffer = CMapBuilder.Build( CMapBuilder.EntryTypeEnum.BaseFont, null, sortedCodes, delegate(KeyValuePair <ByteArray, int> codeEntry) { return(codeEntry.Value); } ); toUnicodeObject = File.Register(new PdfStream(toUnicodeBuffer)); } font[PdfName.ToUnicode] = toUnicodeObject; // Character-code-to-Unicode mapping. // Glyph widths. PdfArray widthsObject = new PdfArray(); { int lastGlyphIndex = -10; PdfArray lastGlyphWidthRangeObject = null; foreach (int glyphIndex in glyphIndexes.Values.OrderBy(x => x).ToList()) { int width; if (!glyphWidths.TryGetValue(glyphIndex, out width)) { width = 0; } if (glyphIndex - lastGlyphIndex != 1) { widthsObject.Add(PdfInteger.Get(glyphIndex)); widthsObject.Add(lastGlyphWidthRangeObject = new PdfArray()); } lastGlyphWidthRangeObject.Add(PdfInteger.Get(width)); lastGlyphIndex = glyphIndex; } } cidFont[PdfName.W] = widthsObject; // Glyph widths. }
public PdfObject ParseObject(List <PdfObject> knownObjects) { PdfObject obj = null; long startPosition = _streamPosition; do { SkipWhitespace(); byte character = PeekChar(); if (character == '%') { SkipComment(); } else if (IsDigit(character)) { IPdfElement objectID = ParseNumber(); SkipWhitespace(); IPdfElement objectGeneration = ParseNumber(); SkipWhitespace(); string token = ParseToken(); if (token == "obj") { SkipWhitespace(); IPdfElement element = ParseElement(); string endToken = ParseToken(); // Intercept streams if (endToken == "stream") { PdfDictionary streamDict = element as PdfDictionary; if (streamDict == null) { throw new Exception(string.Format("Stream after a not dictionary element at: {0}", _streamPosition)); } SkipEndOfLine(); // Find the length of the stream long length = -1; if (streamDict.Values.ContainsKey("Length")) { length = PdfElementUtils.GetInt(streamDict.Values["Length"], -1); if (length == -1 && streamDict.Values["Length"] is PdfObjectReference) { IPdfElement lenghtObj = SearchObjectID(knownObjects, ((PdfObjectReference)streamDict.Values["Length"]).ObjectID); length = PdfElementUtils.GetInt(lenghtObj, -1); } } if (length == -1) { byte lineFeed = 0x0A; byte carriageReturn = 0x0D; length = MeasureToMarkers(new char[][] { new char[] { (char)carriageReturn, (char)lineFeed, 'e', 'n', 'd', 's', 't', 'r', 'e', 'a', 'm' }, new char[] { (char)lineFeed, 'e', 'n', 'd', 's', 't', 'r', 'e', 'a', 'm' }, new char[] { 'e', 'n', 'd', 's', 't', 'r', 'e', 'a', 'm', (char)lineFeed }, new char[] { 'e', 'n', 'd', 's', 't', 'r', 'e', 'a', 'm', (char)carriageReturn, (char)lineFeed }, }); } // Get the stream byte[] streamBody = GetRawData(length); SkipEndOfLine(); endToken = ParseToken(); if (endToken != "endstream") { throw new Exception(string.Format("Expected \"endstream\" token, \"{0}\" found at: {1}", token, _streamPosition)); } SkipWhitespace(); endToken = ParseToken(); PdfStream stream = new PdfStream(); stream.Dictionary = streamDict; stream.Data = streamBody; element = stream; } if (endToken == "endobj") { obj = new PdfObject(); obj.ObjectID = (int)((PdfInteger)objectID).Value; obj.ObjectGeneration = (int)((PdfInteger)objectGeneration).Value; obj.Data = element; break; } } } else { long streamPosition = _streamPosition; string token = ParseToken(); if (token == "startxref") { // TODO: PdfParser: Ignoring startxref for now SkipEndOfLine(); SkipToEndOfLine(); SkipEndOfLine(); SkipToEndOfLine(); SkipEndOfLine(); SkipWhitespace(); continue; } if (token == "xref") { // TODO: PdfParser: Ignoring xref for now SkipToEndOfLine(); SkipEndOfLine(); do { SkipWhitespace(); IPdfElement objNumber = ParseNumber(); SkipWhitespace(); objNumber = ParseNumber(); SkipEndOfLine(); PdfInteger refNumber = objNumber as PdfInteger; for (int i = 0; i < refNumber.Value; i++) { SkipToEndOfLine(); SkipEndOfLine(); } long currentPosition = _streamPosition; IPdfElement testElem = ParseElement(); _streamPosition = currentPosition; if ((testElem is PdfInteger) == false) { break; } } while (IsEndOfStream() == false); continue; } if (token == "trailer") { // TODO: PdfParser: Ignoring trailer for now SkipEndOfLine(); ParseElement(); SkipWhitespace(); SkipToEndOfLine(); SkipEndOfLine(); SkipToEndOfLine(); SkipEndOfLine(); SkipToEndOfLine(); SkipEndOfLine(); SkipWhitespace(); continue; } // Try to find an object marker byte lineFeed = 0x0A; byte carriageReturn = 0x0D; long distToObject = MeasureToMarkers(new char[][] { new char[] { ' ', 'o', 'b', 'j', (char)lineFeed }, new char[] { ' ', 'o', 'b', 'j', (char)carriageReturn, (char)lineFeed }, }); if (distToObject > 0) { // Object marker found, backtrack and retry long originalPosition = _streamPosition; _streamPosition += distToObject; long marker = _streamPosition; SkipWhitespaceBack(); if (_streamPosition == marker) { // Abort backtrack, skip garbage _streamPosition = originalPosition + distToObject + 4; continue; } marker = _streamPosition; SkipDigitsBack(); if (_streamPosition == marker) { // Abort backtrack, skip garbage _streamPosition = originalPosition + distToObject + 4; continue; } marker = _streamPosition; SkipWhitespaceBack(); if (_streamPosition == marker) { // Abort backtrack, skip garbage _streamPosition = originalPosition + distToObject + 4; continue; } marker = _streamPosition; SkipDigitsBack(); if (_streamPosition == marker) { // Abort backtrack, skip garbage _streamPosition = originalPosition + distToObject + 4; continue; } NextChar(); } else { // No more obj markers found, abort all. _streamPosition = _stream.Length; } } } while (IsEndOfStream() == false); return(obj); }
public SetLineCap(LineCapEnum value) : base(OperatorKeyword, PdfInteger.Get((int)value)) { }
/** * <summary>Ends the content row.</summary> * <param name="broken">Indicates whether this is the end of a paragraph.</param> */ private void EndRow( bool broken ) { if (rowEnded) { return; } rowEnded = true; List <RowObject> objects = currentRow.Objects; double[] objectXOffsets = new double[objects.Count]; // Horizontal object displacements. double wordSpace = 0; // Exceeding space among words. double rowXOffset = 0; // Horizontal row offset. // Horizontal alignment. XAlignmentEnum xAlignment = this.xAlignment; switch (xAlignment) { case XAlignmentEnum.Left: break; case XAlignmentEnum.Right: rowXOffset = frame.Width - currentRow.Width; break; case XAlignmentEnum.Center: rowXOffset = (frame.Width - currentRow.Width) / 2; break; case XAlignmentEnum.Justify: if (currentRow.SpaceCount == 0 || broken) // NO spaces. { /* NOTE: This situation equals a simple left alignment. */ xAlignment = XAlignmentEnum.Left; } else // Spaces exist. { // Calculate the exceeding spacing among the words! wordSpace = (frame.Width - currentRow.Width) / currentRow.SpaceCount; // Define the horizontal offsets for justified alignment. for ( int index = 1, count = objects.Count; index < count; index++ ) { /* * NOTE: The offset represents the horizontal justification gap inserted at the left * side of each object. */ objectXOffsets[index] = objectXOffsets[index - 1] + objects[index - 1].SpaceCount * wordSpace; } } currentRow.WordSpaceAdjustment.Value = wordSpace; break; } // Vertical alignment and translation. for ( int index = objects.Count - 1; index >= 0; index-- ) { RowObject obj = objects[index]; // Vertical alignment. double objectYOffset = 0; { LineAlignmentEnum lineAlignment; double lineRise; { object objectLineAlignment = obj.LineAlignment; if (objectLineAlignment is Double) { lineAlignment = LineAlignmentEnum.BaseLine; lineRise = (double)objectLineAlignment; } else { lineAlignment = (LineAlignmentEnum)objectLineAlignment; lineRise = 0; } } switch (lineAlignment) { case LineAlignmentEnum.Top: /* NOOP */ break; case LineAlignmentEnum.Middle: objectYOffset = -(currentRow.Height - obj.Height) / 2; break; case LineAlignmentEnum.BaseLine: objectYOffset = -(currentRow.BaseLine - obj.BaseLine - lineRise); break; case LineAlignmentEnum.Bottom: objectYOffset = -(currentRow.Height - obj.Height); break; default: throw new NotImplementedException("Line alignment " + lineAlignment + " unknown."); } } IList <ContentObject> containedGraphics = obj.Container.Objects; // Translation. containedGraphics.Insert( 0, new ModifyCTM( 1, 0, 0, 1, objectXOffsets[index] + rowXOffset, // Horizontal alignment. objectYOffset // Vertical alignment. ) ); // Word spacing. if (obj.Type == RowObject.TypeEnum.Text) { /* * TODO: This temporary hack adjusts the word spacing in case of composite font. * When DocumentComposer replaces BlockComposer, all the graphical properties of contents * will be declared as styles and their composition will occur as a single pass without such * ugly tweakings. */ ShowText showTextOperation = (ShowText)((Text)((LocalGraphicsState)containedGraphics[1]).Objects[1]).Objects[1]; if (showTextOperation is ShowAdjustedText) { PdfInteger wordSpaceObject = PdfInteger.Get((int)Math.Round(-wordSpace * 1000 * obj.Scale / obj.FontSize)); PdfArray textParams = (PdfArray)showTextOperation.Operands[0]; for (int textParamIndex = 1, textParamsLength = textParams.Count; textParamIndex < textParamsLength; textParamIndex += 2) { textParams[textParamIndex] = wordSpaceObject; } } } } // Update the actual block height! boundBox.Height = (float)(currentRow.Y + currentRow.Height); // Update the actual block vertical location! double yOffset; switch (yAlignment) { case YAlignmentEnum.Bottom: yOffset = frame.Height - boundBox.Height; break; case YAlignmentEnum.Middle: yOffset = (frame.Height - boundBox.Height) / 2; break; case YAlignmentEnum.Top: default: yOffset = 0; break; } boundBox.Y = (float)(frame.Y + yOffset); // Discard the current row! currentRow = null; }
private PdfArray GetVerticalMetrics(int[] values) { if (values.Length == 0) { throw new ArgumentException("length of values must be > 0"); } float scaling = 1000f / ttf.Header.UnitsPerEm; long lastCid = values[0]; long lastW1Value = (long)Math.Round(-values[1] * scaling); long lastVxValue = (long)Math.Round(values[2] * scaling / 2f); long lastVyValue = (long)Math.Round(values[3] * scaling); PdfArray inner = new PdfArray(); PdfArray outer = new PdfArray(); outer.Add(PdfInteger.Get(lastCid)); State state = State.FIRST; for (int i = 4; i < values.Length; i += 4) { long cid = values[i]; if (cid == int.MinValue) { // no glyph for this cid continue; } long w1Value = (long)Math.Round(-values[i + 1] * scaling); long vxValue = (long)Math.Round(values[i + 2] * scaling / 2); long vyValue = (long)Math.Round(values[i + 3] * scaling); switch (state) { case State.FIRST: if (cid == lastCid + 1 && w1Value == lastW1Value && vxValue == lastVxValue && vyValue == lastVyValue) { state = State.SERIAL; } else if (cid == lastCid + 1) { state = State.BRACKET; inner = new PdfArray(); inner.Add(PdfInteger.Get(lastW1Value)); inner.Add(PdfInteger.Get(lastVxValue)); inner.Add(PdfInteger.Get(lastVyValue)); } else { inner = new PdfArray(); inner.Add(PdfInteger.Get(lastW1Value)); inner.Add(PdfInteger.Get(lastVxValue)); inner.Add(PdfInteger.Get(lastVyValue)); outer.Add(inner); outer.Add(PdfInteger.Get(cid)); } break; case State.BRACKET: if (cid == lastCid + 1 && w1Value == lastW1Value && vxValue == lastVxValue && vyValue == lastVyValue) { state = State.SERIAL; outer.Add(inner); outer.Add(PdfInteger.Get(lastCid)); } else if (cid == lastCid + 1) { inner.Add(PdfInteger.Get(lastW1Value)); inner.Add(PdfInteger.Get(lastVxValue)); inner.Add(PdfInteger.Get(lastVyValue)); } else { state = State.FIRST; inner.Add(PdfInteger.Get(lastW1Value)); inner.Add(PdfInteger.Get(lastVxValue)); inner.Add(PdfInteger.Get(lastVyValue)); outer.Add(inner); outer.Add(PdfInteger.Get(cid)); } break; case State.SERIAL: if (cid != lastCid + 1 || w1Value != lastW1Value || vxValue != lastVxValue || vyValue != lastVyValue) { outer.Add(PdfInteger.Get(lastCid)); outer.Add(PdfInteger.Get(lastW1Value)); outer.Add(PdfInteger.Get(lastVxValue)); outer.Add(PdfInteger.Get(lastVyValue)); outer.Add(PdfInteger.Get(cid)); state = State.FIRST; } break; } lastW1Value = w1Value; lastVxValue = vxValue; lastVyValue = vyValue; lastCid = cid; } switch (state) { case State.FIRST: inner = new PdfArray(); inner.Add(PdfInteger.Get(lastW1Value)); inner.Add(PdfInteger.Get(lastVxValue)); inner.Add(PdfInteger.Get(lastVyValue)); outer.Add(inner); break; case State.BRACKET: inner.Add(PdfInteger.Get(lastW1Value)); inner.Add(PdfInteger.Get(lastVxValue)); inner.Add(PdfInteger.Get(lastVyValue)); outer.Add(inner); break; case State.SERIAL: outer.Add(PdfInteger.Get(lastCid)); outer.Add(PdfInteger.Get(lastW1Value)); outer.Add(PdfInteger.Get(lastVxValue)); outer.Add(PdfInteger.Get(lastVyValue)); break; } return(outer); }
private PdfArray GetWidths(int[] widths) { if (widths.Length == 0) { throw new ArgumentException("length of widths must be > 0"); } float scaling = 1000f / ttf.Header.UnitsPerEm; long lastCid = widths[0]; long lastValue = (long)Math.Round(widths[1] * scaling); PdfArray inner = new PdfArray(); PdfArray outer = new PdfArray(); outer.Add(PdfInteger.Get(lastCid)); State state = State.FIRST; for (int i = 2; i < widths.Length; i += 2) { long cid = widths[i]; long value = (long)Math.Round(widths[i + 1] * scaling); switch (state) { case State.FIRST: if (cid == lastCid + 1 && value == lastValue) { state = State.SERIAL; } else if (cid == lastCid + 1) { state = State.BRACKET; inner = new PdfArray(); inner.Add(PdfInteger.Get(lastValue)); } else { inner = new PdfArray(); inner.Add(PdfInteger.Get(lastValue)); outer.Add(inner); outer.Add(PdfInteger.Get(cid)); } break; case State.BRACKET: if (cid == lastCid + 1 && value == lastValue) { state = State.SERIAL; outer.Add(inner); outer.Add(PdfInteger.Get(lastCid)); } else if (cid == lastCid + 1) { inner.Add(PdfInteger.Get(lastValue)); } else { state = State.FIRST; inner.Add(PdfInteger.Get(lastValue)); outer.Add(inner); outer.Add(PdfInteger.Get(cid)); } break; case State.SERIAL: if (cid != lastCid + 1 || value != lastValue) { outer.Add(PdfInteger.Get(lastCid)); outer.Add(PdfInteger.Get(lastValue)); outer.Add(PdfInteger.Get(cid)); state = State.FIRST; } break; } lastValue = value; lastCid = cid; } switch (state) { case State.FIRST: inner = new PdfArray(); inner.Add(PdfInteger.Get(lastValue)); outer.Add(inner); break; case State.BRACKET: inner.Add(PdfInteger.Get(lastValue)); outer.Add(inner); break; case State.SERIAL: outer.Add(PdfInteger.Get(lastCid)); outer.Add(PdfInteger.Get(lastValue)); break; } return(outer); }
protected override void WriteIncremental() { // 1. Original content (header, body and previous trailer). FileParser parser = file.Reader.Parser; stream.Write(parser.Stream); // 2. Body update (modified indirect objects insertion). XRefEntry xrefStreamEntry; { // Create the xref stream! /* * NOTE: Incremental xref information structure comprises multiple sections; this update adds * a new section. */ XRefStream xrefStream = new XRefStream(file); // 2.1. Indirect objects. IndirectObjects indirectObjects = file.IndirectObjects; // 2.1.1. Modified indirect objects serialization. XRefEntry prevFreeEntry = null; /* * NOTE: Any uncompressed indirect object will be compressed. */ ObjectStream objectStream = null; /* * NOTE: Any previously-compressed indirect object will have its original object stream * updated through a new extension object stream. */ IDictionary <int, ObjectStream> extensionObjectStreams = new Dictionary <int, ObjectStream>(); int indirectObjectsPrecompressCount = indirectObjects.Count; foreach (PdfIndirectObject indirectObject in new List <PdfIndirectObject>(indirectObjects.ModifiedObjects.Values)) { if (indirectObject.IsCompressible()) { if (objectStream == null || objectStream.Count >= ObjectStreamMaxEntryCount) { file.Register(objectStream = new ObjectStream()); } indirectObject.Compress(objectStream); } prevFreeEntry = AddXRefEntry( indirectObject, xrefStream, prevFreeEntry, extensionObjectStreams ); } // 2.1.2. Additional object streams serialization. for (int index = indirectObjectsPrecompressCount, limit = indirectObjects.Count; index < limit; index++) { prevFreeEntry = AddXRefEntry( indirectObjects[index], xrefStream, prevFreeEntry, null ); } if (prevFreeEntry != null) { prevFreeEntry.Offset = 0; // Links back to the first free object. NOTE: The first entry in the table (object number 0) is always free. } // 2.2. XRef stream. UpdateTrailer(xrefStream.Header, stream); xrefStream.Header[PdfName.Prev] = PdfInteger.Get((int)parser.RetrieveXRefOffset()); AddXRefEntry( /* * NOTE: This xref stream indirect object is purposely temporary (i.e. not registered into * the file's indirect objects collection). */ new PdfIndirectObject( file, xrefStream, xrefStreamEntry = new XRefEntry(indirectObjects.Count, 0, (int)stream.Length, XRefEntry.UsageEnum.InUse) ), xrefStream, null, null ); } // 3. Tail. WriteTail(xrefStreamEntry.Offset); }
/** * <summary>Creates the character code mapping for composite fonts.</summary> */ private void Load_CreateEncoding( PdfDictionary font, PdfDictionary cidFont ) { // CMap [PDF:1.6:5.6.4]. bytes::Buffer cmapBuffer = new bytes::Buffer(); cmapBuffer.Append( "%!PS-Adobe-3.0 Resource-CMap\n" + "%%DocumentNeededResources: ProcSet (CIDInit)\n" + "%%IncludeResource: ProcSet (CIDInit)\n" + "%%BeginResource: CMap (Adobe-Identity-UCS)\n" + "%%Title: (Adobe-Identity-UCS Adobe Identity 0)\n" + "%%Version: 1\n" + "%%EndComments\n" + "/CIDInit /ProcSet findresource begin\n" + "12 dict begin\n" + "begincmap\n" + "/CIDSystemInfo\n" + "3 dict dup begin\n" + "/Registry (Adobe) def\n" + "/Ordering (Identity) def\n" + "/Supplement 0 def\n" + "end def\n" + "/CMapName /Adobe-Identity-UCS def\n" + "/CMapVersion 1 def\n" + "/CMapType 0 def\n" + "/WMode 0 def\n" + "2 begincodespacerange\n" + "<20> <20>\n" + "<0000> <19FF>\n" + "endcodespacerange\n" + glyphIndexes.Count + " begincidchar\n" ); // ToUnicode [PDF:1.6:5.9.2]. bytes::Buffer toUnicodeBuffer = new bytes::Buffer(); toUnicodeBuffer.Append( "/CIDInit /ProcSet findresource begin\n" + "12 dict begin\n" + "begincmap\n" + "/CIDSystemInfo\n" + "<< /Registry (Adobe)\n" + "/Ordering (UCS)\n" + "/Supplement 0\n" + ">> def\n" + "/CMapName /Adobe-Identity-UCS def\n" + "/CMapVersion 10.001 def\n" + "/CMapType 2 def\n" + "2 begincodespacerange\n" + "<20> <20>\n" + "<0000> <19FF>\n" + "endcodespacerange\n" + glyphIndexes.Count + " beginbfchar\n" ); // CIDToGIDMap [PDF:1.6:5.6.3]. bytes::Buffer gIdBuffer = new bytes::Buffer(); gIdBuffer.Append((byte)0); gIdBuffer.Append((byte)0); int code = 0; codes = new BiDictionary <ByteArray, int>(glyphIndexes.Count); PdfArray widthsObject = new PdfArray(glyphWidths.Count); foreach (KeyValuePair <int, int> glyphIndexEntry in glyphIndexes) { // Character code (unicode to codepoint) entry. code++; byte[] charCode = (glyphIndexEntry.Key == 32 ? new byte[] { 32 } : new byte[] { (byte)((code >> 8) & 0xFF), (byte)(code & 0xFF) }); codes[new ByteArray(charCode)] = glyphIndexEntry.Key; // CMap entry. cmapBuffer.Append("<"); toUnicodeBuffer.Append("<"); for (int charCodeBytesIndex = 0, charCodeBytesLength = charCode.Length; charCodeBytesIndex < charCodeBytesLength; charCodeBytesIndex++ ) { string hex = ((int)charCode[charCodeBytesIndex]).ToString("X2"); cmapBuffer.Append(hex); toUnicodeBuffer.Append(hex); } cmapBuffer.Append("> " + code + "\n"); toUnicodeBuffer.Append("> <" + glyphIndexEntry.Key.ToString("X4") + ">\n"); // CID-to-GID entry. int glyphIndex = glyphIndexEntry.Value; gIdBuffer.Append((byte)((glyphIndex >> 8) & 0xFF)); gIdBuffer.Append((byte)(glyphIndex & 0xFF)); // Width. int width; if (!glyphWidths.TryGetValue(glyphIndex, out width)) { width = 0; } else if (width > 1000) { width = 1000; } widthsObject.Add(PdfInteger.Get(width)); } cmapBuffer.Append( "endcidchar\n" + "endcmap\n" + "CMapName currentdict /CMap defineresource pop\n" + "end\n" + "end\n" + "%%EndResource\n" + "%%EOF" ); PdfStream cmapStream = new PdfStream(cmapBuffer); PdfDictionary cmapHead = cmapStream.Header; cmapHead[PdfName.Type] = PdfName.CMap; cmapHead[PdfName.CMapName] = new PdfName("Adobe-Identity-UCS"); cmapHead[PdfName.CIDSystemInfo] = new PdfDictionary( new PdfName[] { PdfName.Registry, PdfName.Ordering, PdfName.Supplement }, new PdfDirectObject[] { new PdfTextString("Adobe"), new PdfTextString("Identity"), PdfInteger.Get(0) } ); // Generic predefined CMap (Identity-H/V (Adobe-Identity-0)) [PDF:1.6:5.6.4]. font[PdfName.Encoding] = File.Register(cmapStream); PdfStream gIdStream = new PdfStream(gIdBuffer); cidFont[PdfName.CIDToGIDMap] = File.Register(gIdStream); cidFont[PdfName.W] = new PdfArray(new PdfDirectObject[] { PdfInteger.Get(1), widthsObject }); toUnicodeBuffer.Append( "endbfchar\n" + "endcmap\n" + "CMapName currentdict /CMap defineresource pop\n" + "end\n" + "end\n" ); PdfStream toUnicodeStream = new PdfStream(toUnicodeBuffer); font[PdfName.ToUnicode] = File.Register(toUnicodeStream); }
/** * <summary>Retrieves the file information.</summary> */ public FileInfo ReadInfo() { //TODO:hybrid xref table/stream Version version = Version.Get(parser.RetrieveVersion()); PdfDictionary trailer = null; SortedDictionary <int, XRefEntry> xrefEntries = new SortedDictionary <int, XRefEntry>(); { long sectionOffset = parser.RetrieveXRefOffset(); while (sectionOffset > -1) { // Move to the start of the xref section! parser.Seek(sectionOffset); PdfDictionary sectionTrailer; if (parser.GetToken(1).Equals(Keyword.XRef)) // XRef-table section. { // Looping sequentially across the subsections inside the current xref-table section... while (true) { /* * NOTE: Each iteration of this block represents the scanning of one subsection. * We get its bounds (first and last object numbers within its range) and then collect * its entries. */ // 1. First object number. parser.MoveNext(); if ((parser.TokenType == PostScriptParser.TokenTypeEnum.Keyword) && parser.Token.Equals(Keyword.Trailer)) // XRef-table section ended. { break; } else if (parser.TokenType != PostScriptParser.TokenTypeEnum.Integer) { throw new PostScriptParseException("Neither object number of the first object in this xref subsection nor end of xref section found.", parser); } // Get the object number of the first object in this xref-table subsection! int startObjectNumber = (int)parser.Token; // 2. Last object number. parser.MoveNext(); if (parser.TokenType != PostScriptParser.TokenTypeEnum.Integer) { throw new PostScriptParseException("Number of entries in this xref subsection not found.", parser); } // Get the object number of the last object in this xref-table subsection! int endObjectNumber = (int)parser.Token + startObjectNumber; // 3. XRef-table subsection entries. for (int index = startObjectNumber; index < endObjectNumber; index++) { if (xrefEntries.ContainsKey(index)) // Already-defined entry. { // Skip to the next entry! parser.MoveNext(3); continue; } // Get the indirect object offset! int offset = (int)parser.GetToken(1); // Get the object generation number! int generation = (int)parser.GetToken(1); // Get the usage tag! XRefEntry.UsageEnum usage; { string usageToken = (string)parser.GetToken(1); if (usageToken.Equals(Keyword.InUseXrefEntry, StringComparison.Ordinal)) { usage = XRefEntry.UsageEnum.InUse; } else if (usageToken.Equals(Keyword.FreeXrefEntry, StringComparison.Ordinal)) { usage = XRefEntry.UsageEnum.Free; } else { throw new PostScriptParseException("Invalid xref entry.", parser); } } // Define entry! xrefEntries[index] = new XRefEntry( index, generation, offset, usage ); } } // Get the previous trailer! sectionTrailer = (PdfDictionary)parser.ParsePdfObject(1); } else // XRef-stream section. { XRefStream stream = (XRefStream)parser.ParsePdfObject(3); // Gets the xref stream skipping the indirect-object header. // XRef-stream subsection entries. foreach (XRefEntry xrefEntry in stream.Values) { if (xrefEntries.ContainsKey(xrefEntry.Number)) // Already-defined entry. { continue; } // Define entry! xrefEntries[xrefEntry.Number] = xrefEntry; } // Get the previous trailer! sectionTrailer = stream.Header; } if (trailer == null) { trailer = sectionTrailer; } // Get the previous xref-table section's offset! PdfInteger prevXRefOffset = (PdfInteger)sectionTrailer[PdfName.Prev]; sectionOffset = (prevXRefOffset != null ? prevXRefOffset.IntValue : -1); } } return(new FileInfo(version, trailer, xrefEntries)); }
public SetTextRenderMode( TextRenderModeEnum value ) : base(OperatorKeyword, PdfInteger.Get((int)value)) { }
private static void HandleInteger(PdfInteger item, StringBuilder target) { target.Append(item.Value); }
public Dictionary <char, string> ParseToUnicode() { var toUnicode = new Dictionary <char, string>(); long skip = MeasureToMarkers(new char[][] { new char[] { 'b', 'e', 'g', 'i', 'n', 'c', 'm', 'a', 'p' }, }); _streamPosition = skip; var stack = new List <IPdfElement>(); do { SkipWhitespace(); IPdfElement elem = ParseElement(); if (elem != null) { stack.Add(elem); } else { string token = ParseToken(); if (token == "begincodespacerange") { PdfInteger numCodespaces = stack.Last() as PdfInteger; if (numCodespaces == null) { throw new Exception(string.Format("ParseToUnicode: \"begincodespacerange\" found without preceding count at: {0}", _streamPosition)); } for (int i = 0; i < numCodespaces.Value; i++) { // Skip CodeSpaceRanges SkipWhitespace(); PdfString strStart = ParseString(); SkipWhitespace(); PdfString strEnd = ParseString(); } SkipWhitespace(); string endToken = ParseToken(); if (endToken != "endcodespacerange") { throw new Exception(string.Format("ParseToUnicode: Expected \"endcodespacerange\", found \"{0}\", at: {1}", endToken, _streamPosition)); } } else if (token == "beginbfrange") { PdfInteger numRanges = stack.Last() as PdfInteger; if (numRanges == null) { throw new Exception(string.Format("ParseToUnicode: \"beginbfrange\" found without preceding count at: {0}", _streamPosition)); } for (int i = 0; i < numRanges.Value; i++) { SkipWhitespace(); PdfString pdfStrStart = ParseString(); SkipWhitespace(); PdfString pdfStrEnd = ParseString(); SkipWhitespace(); IPdfElement pdfElemDest = ParseElement(); char chStart = ReencodeStringToUTF16BE(pdfStrStart.Value)[0]; char chEnd = ReencodeStringToUTF16BE(pdfStrEnd.Value)[0]; if (chStart == chEnd && pdfElemDest is PdfString) { string strDst = ReencodeStringToUTF16BE(((PdfString)pdfElemDest).Value); toUnicode.Add(chStart, strDst); continue; } if (chEnd > chStart && pdfElemDest is PdfString) { string strDst = ReencodeStringToUTF16BE(((PdfString)pdfElemDest).Value); char[] chsDest = strDst.ToArray(); for (char c = chStart; c <= chEnd; c++) { toUnicode.Add(c, new string(chsDest)); chsDest[chsDest.Length - 1]++; } continue; } if (chEnd > chStart && pdfElemDest is PdfArray) { PdfArray array = pdfElemDest as PdfArray; int length = chEnd - chStart; for (int j = 0; j <= length; j++) { char c = (char)(chStart + j); string strDst = ReencodeStringToUTF16BE(((PdfString)array.Values[j]).Value); toUnicode.Add(c, strDst); } continue; } } SkipWhitespace(); string endToken = ParseToken(); if (endToken != "endbfrange") { throw new Exception(string.Format("ParseToUnicode: Expected \"endbfrange\", found \"{0}\", at: {1}", endToken, _streamPosition)); } } else if (token == "beginbfchar") { PdfInteger numChars = stack.Last() as PdfInteger; if (numChars == null) { throw new Exception(string.Format("ParseToUnicode: \"beginbfchar\" found without preceding count at: {0}", _streamPosition)); } for (int i = 0; i < numChars.Value; i++) { SkipWhitespace(); PdfString pdfStrOrig = ParseString(); SkipWhitespace(); PdfString pdfStrDest = ParseString(); char chOrig = ReencodeStringToUTF16BE(pdfStrOrig.Value)[0]; string strDst = ReencodeStringToUTF16BE(((PdfString)pdfStrDest).Value); toUnicode.Add(chOrig, strDst); } SkipWhitespace(); string endToken = ParseToken(); if (endToken != "endbfchar") { throw new Exception(string.Format("ParseToUnicode: Expected \"endbfchar\", found \"{0}\", at: {1}", endToken, _streamPosition)); } } else { // Ignore rest of tokens } } } while (IsEndOfStream() == false); return(toUnicode); }
/** * <summary>Parses the current PDF object [PDF:1.6:3.2].</summary> */ public virtual PdfDataObject ParsePdfObject() { switch (TokenType) { case TokenTypeEnum.Integer: return(PdfInteger.Get((int)Token)); case TokenTypeEnum.Name: return(new PdfName((string)Token, true)); case TokenTypeEnum.DictionaryBegin: { PdfDictionary dictionary = new PdfDictionary(); dictionary.Updateable = false; while (true) { // Key. MoveNext(); if (TokenType == TokenTypeEnum.DictionaryEnd) { break; } PdfName key = (PdfName)ParsePdfObject(); // Value. MoveNext(); PdfDirectObject value = (PdfDirectObject)ParsePdfObject(); // Add the current entry to the dictionary! if (dictionary.ContainsKey(key)) { key = new PdfName(key.StringValue + "Dublicat"); } dictionary[key] = value; } dictionary.Updateable = true; return(dictionary); } case TokenTypeEnum.ArrayBegin: { PdfArray array = new PdfArray(); array.Updateable = false; while (true) { // Value. MoveNext(); if (TokenType == TokenTypeEnum.ArrayEnd) { break; } // Add the current item to the array! array.Add((PdfDirectObject)ParsePdfObject()); } array.Updateable = true; return(array); } case TokenTypeEnum.Literal: if (Token is DateTime) { return(PdfDate.Get((DateTime)Token)); } else { return(new PdfTextString(Token == null ? null : Encoding.Pdf.Encode((string)Token))); } case TokenTypeEnum.Hex: return(new PdfTextString((string)Token, PdfString.SerializationModeEnum.Hex)); case TokenTypeEnum.Real: return(PdfReal.Get((double)Token)); case TokenTypeEnum.Boolean: return(PdfBoolean.Get((bool)Token)); case TokenTypeEnum.Null: return(null); default: throw new PostScriptParseException(String.Format("Unknown type beginning: '{0}'", Token), this); } }
public IndexedColor(int index) : this(new PdfArray(new PdfDirectObject[] { PdfInteger.Get(index) })) { }
/** * <summary>Creates the font descriptor.</summary> */ private PdfReference Load_CreateFontDescriptor( OpenFontParser parser ) { PdfDictionary fontDescriptor = new PdfDictionary(); { OpenFontParser.FontMetrics metrics = parser.Metrics; // Type. fontDescriptor[PdfName.Type] = PdfName.FontDescriptor; // FontName. fontDescriptor[PdfName.FontName] = BaseDataObject[PdfName.BaseFont]; // Flags [PDF:1.6:5.7.1]. FlagsEnum flags = 0; if (metrics.IsFixedPitch) { flags |= FlagsEnum.FixedPitch; } if (metrics.IsCustomEncoding) { flags |= FlagsEnum.Symbolic; } else { flags |= FlagsEnum.Nonsymbolic; } fontDescriptor[PdfName.Flags] = PdfInteger.Get(Convert.ToInt32(flags)); // FontBBox. fontDescriptor[PdfName.FontBBox] = new Rectangle( new drawing::PointF(metrics.XMin * metrics.UnitNorm, metrics.YMin * metrics.UnitNorm), new drawing::PointF(metrics.XMax * metrics.UnitNorm, metrics.YMax * metrics.UnitNorm) ).BaseDataObject; // ItalicAngle. fontDescriptor[PdfName.ItalicAngle] = PdfReal.Get(metrics.ItalicAngle); // Ascent. fontDescriptor[PdfName.Ascent] = PdfReal.Get( metrics.STypoAscender == 0 ? metrics.Ascender * metrics.UnitNorm : (metrics.STypoLineGap == 0 ? metrics.SCapHeight : metrics.STypoAscender) * metrics.UnitNorm ); // Descent. fontDescriptor[PdfName.Descent] = PdfReal.Get( metrics.STypoDescender == 0 ? metrics.Descender * metrics.UnitNorm : metrics.STypoDescender * metrics.UnitNorm ); // CapHeight. fontDescriptor[PdfName.CapHeight] = PdfReal.Get(metrics.SCapHeight * metrics.UnitNorm); // StemV. /* * NOTE: '100' is just a rule-of-thumb value, 'cause I've still to solve the * 'cvt' table puzzle (such a harsh headache!) for TrueType fonts... * TODO:IMPL TrueType and CFF stemv real value to extract!!! */ fontDescriptor[PdfName.StemV] = PdfInteger.Get(100); // FontFile. fontDescriptor[PdfName.FontFile2] = File.Register( new PdfStream(new bytes::Buffer(parser.FontData.ToByteArray())) ); } return(File.Register(fontDescriptor)); }
public static MonitorSpecifierEnum? Get( PdfInteger code ) { if(code == null) return MonitorSpecifierEnum.LargestDocumentWindowSection; MonitorSpecifierEnum? monitorSpecifier = codes.GetKey(code); if(!monitorSpecifier.HasValue) throw new NotSupportedException("Monitor specifier unknown: " + code); return monitorSpecifier; }
/// <summary> /// Prepares the security handler for encrypting the document. /// </summary> public void PrepareEncryption() { //#if !SILVERLIGHT Debug.Assert(_document._securitySettings.DocumentSecurityLevel != PdfDocumentSecurityLevel.None); int permissions = (int)Permission; bool strongEncryption = _document._securitySettings.DocumentSecurityLevel == PdfDocumentSecurityLevel.Encrypted128Bit; PdfInteger vValue; PdfInteger length; PdfInteger rValue; if (strongEncryption) { vValue = new PdfInteger(2); length = new PdfInteger(128); rValue = new PdfInteger(3); } else { vValue = new PdfInteger(1); length = new PdfInteger(40); rValue = new PdfInteger(2); } if (String.IsNullOrEmpty(_userPassword)) { _userPassword = ""; } // Use user password twice if no owner password provided. if (String.IsNullOrEmpty(_ownerPassword)) { _ownerPassword = _userPassword; } // Correct permission bits permissions |= (int)(strongEncryption ? (uint)0xfffff0c0 : (uint)0xffffffc0); permissions &= unchecked ((int)0xfffffffc); PdfInteger pValue = new PdfInteger(permissions); Debug.Assert(_ownerPassword.Length > 0, "Empty owner password."); byte[] userPad = PadPassword(_userPassword); byte[] ownerPad = PadPassword(_ownerPassword); _md5.Initialize(); _ownerKey = ComputeOwnerKey(userPad, ownerPad, strongEncryption); byte[] documentID = PdfEncoders.RawEncoding.GetBytes(_document.Internals.FirstDocumentID); InitWithUserPassword(documentID, _userPassword, _ownerKey, permissions, strongEncryption); PdfString oValue = new PdfString(PdfEncoders.RawEncoding.GetString(_ownerKey, 0, _ownerKey.Length)); PdfString uValue = new PdfString(PdfEncoders.RawEncoding.GetString(_userKey, 0, _userKey.Length)); Elements[Keys.Filter] = new PdfName("/Standard"); Elements[Keys.V] = vValue; Elements[Keys.Length] = length; Elements[Keys.R] = rValue; Elements[Keys.O] = oValue; Elements[Keys.U] = uValue; Elements[Keys.P] = pValue; //#endif }
/** * Add a collection of pages at the specified position. * <param name="index">Addition position. To append, use value -1.</param> * <param name="pages">Collection of pages to add.</param> */ private void CommonAddAll <TPage>(int index, ICollection <TPage> pages) where TPage : Page { PdfDirectObject parent; PdfDictionary parentData; PdfDirectObject kids; PdfArray kidsData; int offset; // Append operation? if (index == -1) // Append operation. { // Get the parent tree node! parent = BaseObject; parentData = BaseDataObject; // Get the parent's page collection! kids = parentData[PdfName.Kids]; kidsData = (PdfArray)PdfObject.Resolve(kids); offset = 0; // Not used. } else // Insert operation. { // Get the page currently at the specified position! Page pivotPage = this[index]; // Get the parent tree node! parent = pivotPage.BaseDataObject[PdfName.Parent]; parentData = (PdfDictionary)parent.Resolve(); // Get the parent's page collection! kids = parentData[PdfName.Kids]; kidsData = (PdfArray)kids.Resolve(); // Get the insertion's relative position within the parent's page collection! offset = kidsData.IndexOf(pivotPage.BaseObject); } // Adding the pages... foreach (Page page in pages) { // Append? if (index == -1) // Append. { // Append the page to the collection! kidsData.Add(page.BaseObject); } else // Insert. { // Insert the page into the collection! kidsData.Insert(offset++, page.BaseObject); } // Bind the page to the collection! page.BaseDataObject[PdfName.Parent] = parent; } // Incrementing the pages counters... do { // Get the page collection counter! PdfInteger countObject = (PdfInteger)parentData[PdfName.Count]; // Increment the counter at the current level! parentData[PdfName.Count] = PdfInteger.Get(countObject.IntValue + pages.Count); // Iterate upward! parent = parentData[PdfName.Parent]; parentData = (PdfDictionary)PdfObject.Resolve(parent); } while (parent != null); }
public virtual PdfObject Visit( PdfInteger obj, object data ) { return obj; }
public static Render.OperationEnum? Get( PdfInteger code ) { if(code == null) return null; Render.OperationEnum? operation = codes.GetKey(code); if(!operation.HasValue) throw new NotSupportedException("Operation unknown: " + code); return operation; }