Exemple #1
0
        /// <summary>
        /// Creates a document builder using the supplied stream.
        /// </summary>
        /// <param name="stream">Steam to write pdf to.</param>
        /// <param name="disposeStream">If stream should be disposed when builder is.</param>
        /// <param name="type">Type of pdf stream writer to use</param>
        /// <param name="version">Pdf version to use in header.</param>
        public PdfDocumentBuilder(Stream stream, bool disposeStream = false, PdfWriterType type = PdfWriterType.Default, decimal version = 1.7m)
        {
            switch (type)
            {
            case PdfWriterType.ObjectInMemoryDedup:
                context = new PdfDedupStreamWriter(stream, disposeStream);
                break;

            default:
                context = new PdfStreamWriter(stream, disposeStream);
                break;
            }
            context.InitializePdf(version);
        }
Exemple #2
0
            public IndirectReferenceToken Write(IPdfStreamWriter writer)
            {
                using (var memoryStream = new MemoryStream())
                {
                    foreach (var operation in operations)
                    {
                        operation.Write(memoryStream);
                    }

                    var bytes = memoryStream.ToArray();

                    var stream = DataCompresser.CompressToStream(bytes);

                    return(writer.WriteToken(stream));
                }
            }
Exemple #3
0
        public IndirectReferenceToken WriteFont(IPdfStreamWriter writer, IndirectReferenceToken reservedIndirect = null)
        {
            var dictionary = new Dictionary <NameToken, IToken>
            {
                { NameToken.Type, NameToken.Font },
                { NameToken.Subtype, NameToken.Type1 },
                { NameToken.BaseFont, NameToken.Create(metrics.FontName) },
                { NameToken.Encoding, NameToken.MacRomanEncoding }
            };

            var token = new DictionaryToken(dictionary);

            if (reservedIndirect != null)
            {
                return(writer.WriteToken(token, reservedIndirect));
            }

            var result = writer.WriteToken(token);

            return(result);
        }
Exemple #4
0
        public IndirectReferenceToken  WriteFont(IPdfStreamWriter writer, IndirectReferenceToken reservedIndirect = null)
        {
            var newEncoding = new TrueTypeSubsetEncoding(characterMapping.Keys.ToList());
            var subsetBytes = TrueTypeSubsetter.Subset(fontFileBytes.ToArray(), newEncoding);

            var embeddedFile = DataCompresser.CompressToStream(subsetBytes);

            var fileRef = writer.WriteToken(embeddedFile);

            var baseFont = NameToken.Create(font.TableRegister.NameTable.GetPostscriptName());

            var postscript = font.TableRegister.PostScriptTable;
            var hhead      = font.TableRegister.HorizontalHeaderTable;

            var bbox = font.TableRegister.HeaderTable.Bounds;

            var scaling = 1000m / font.TableRegister.HeaderTable.UnitsPerEm;
            var descriptorDictionary = new Dictionary <NameToken, IToken>
            {
                { NameToken.Type, NameToken.FontDescriptor },
                { NameToken.FontName, baseFont },
                // TODO: get flags TrueTypeEmbedder.java
                { NameToken.Flags, new NumericToken((int)FontDescriptorFlags.Symbolic) },
                { NameToken.FontBbox, GetBoundingBox(bbox, scaling) },
                { NameToken.ItalicAngle, new NumericToken((decimal)postscript.ItalicAngle) },
                { NameToken.Ascent, new NumericToken(Math.Round(hhead.Ascent * scaling, 2)) },
                { NameToken.Descent, new NumericToken(Math.Round(hhead.Descent * scaling, 2)) },
                { NameToken.CapHeight, new NumericToken(90) },
                { NameToken.StemV, new NumericToken(90) },
                { NameToken.FontFile2, fileRef }
            };

            var os2 = font.TableRegister.Os2Table;

            if (os2 == null)
            {
                throw new InvalidFontFormatException("Embedding TrueType font requires OS/2 table.");
            }

            if (os2 is Os2Version2To4OpenTypeTable twoPlus)
            {
                descriptorDictionary[NameToken.CapHeight] = new NumericToken(twoPlus.CapHeight);
                descriptorDictionary[NameToken.Xheight]   = new NumericToken(twoPlus.XHeight);
            }

            descriptorDictionary[NameToken.StemV] = new NumericToken(((decimal)bbox.Width) * scaling * 0.13m);

            var lastCharacter = 0;
            var widths        = new List <NumericToken> {
                NumericToken.Zero
            };

            foreach (var kvp in characterMapping)
            {
                if (kvp.Value > lastCharacter)
                {
                    lastCharacter = kvp.Value;
                }

                var glyphId = font.WindowsUnicodeCMap.CharacterCodeToGlyphIndex(kvp.Key);
                var width   = decimal.Round(font.TableRegister.HorizontalMetricsTable.GetAdvanceWidth(glyphId) * scaling, 2);

                widths.Add(new NumericToken(width));
            }

            var descriptor = writer.WriteToken(new DictionaryToken(descriptorDictionary));

            var toUnicodeCMap   = ToUnicodeCMapBuilder.ConvertToCMapStream(characterMapping);
            var toUnicodeStream = DataCompresser.CompressToStream(toUnicodeCMap);
            var toUnicode       = writer.WriteToken(toUnicodeStream);

            var dictionary = new Dictionary <NameToken, IToken>
            {
                { NameToken.Type, NameToken.Font },
                { NameToken.Subtype, NameToken.TrueType },
                { NameToken.BaseFont, baseFont },
                { NameToken.FontDescriptor, descriptor },
                { NameToken.FirstChar, new NumericToken(0) },
                { NameToken.LastChar, new NumericToken(lastCharacter) },
                { NameToken.Widths, new ArrayToken(widths) },
                { NameToken.ToUnicode, toUnicode }
            };

            var token = new DictionaryToken(dictionary);

            if (reservedIndirect != null)
            {
                return(writer.WriteToken(token, reservedIndirect));
            }

            return(writer.WriteToken(token));
        }
Exemple #5
0
 public IndirectReferenceToken Write(IPdfStreamWriter writer)
 {
     return(token);
 }
Exemple #6
0
 /// <summary>
 /// Creates a document builder keeping resources in memory.
 /// </summary>
 /// <param name="version">Pdf version to use in header.</param>
 public PdfDocumentBuilder(decimal version)
 {
     context = new PdfStreamWriter(new MemoryStream(), true);
     context.InitializePdf(version);
 }
Exemple #7
0
 /// <summary>
 /// Creates a document builder keeping resources in memory.
 /// </summary>
 public PdfDocumentBuilder()
 {
     context = new PdfStreamWriter(new MemoryStream(), true);
     context.InitializePdf(1.7m);
 }
Exemple #8
0
        /// <summary>
        /// The purpose of this method is to resolve indirect reference. That mean copy the reference's content to the new document's stream
        /// and replace the indirect reference with the correct/new one
        /// </summary>
        /// <param name="writer">PDF stream writer</param>
        /// <param name="tokenToCopy">Token to inspect for reference</param>
        /// <param name="tokenScanner">scanner get the content from the original document</param>
        /// <param name="referencesFromDocument">Map of previously copied tokens for original document.</param>
        /// <param name="callstack">Call stack of indirect references</param>
        /// <returns>A reference of the token that was copied. With all the reference updated</returns>
        public static IToken CopyToken(IPdfStreamWriter writer, IToken tokenToCopy, IPdfTokenScanner tokenScanner,
                                       IDictionary <IndirectReference, IndirectReferenceToken> referencesFromDocument, Dictionary <IndirectReference, IndirectReferenceToken> callstack = null)
        {
            if (callstack == null)
            {
                callstack = new Dictionary <IndirectReference, IndirectReferenceToken>();
            }

            // This token need to be deep copied, because they could contain reference. So we have to update them.
            switch (tokenToCopy)
            {
            case DictionaryToken dictionaryToken:
            {
                var newContent = new Dictionary <NameToken, IToken>();
                foreach (var setPair in dictionaryToken.Data)
                {
                    var name  = setPair.Key;
                    var token = setPair.Value;
                    newContent.Add(NameToken.Create(name), CopyToken(writer, token, tokenScanner, referencesFromDocument, callstack));
                }

                return(new DictionaryToken(newContent));
            }

            case ArrayToken arrayToken:
            {
                var newArray = new List <IToken>(arrayToken.Length);
                foreach (var token in arrayToken.Data)
                {
                    newArray.Add(CopyToken(writer, token, tokenScanner, referencesFromDocument, callstack));
                }

                return(new ArrayToken(newArray));
            }

            case IndirectReferenceToken referenceToken:
            {
                if (referencesFromDocument.TryGetValue(referenceToken.Data, out var newReferenceToken))
                {
                    return(newReferenceToken);
                }

                if (callstack.ContainsKey(referenceToken.Data) && callstack[referenceToken.Data] == null)
                {
                    newReferenceToken = writer.ReserveObjectNumber();
                    callstack[referenceToken.Data] = newReferenceToken;
                    referencesFromDocument.Add(referenceToken.Data, newReferenceToken);
                    return(newReferenceToken);
                }

                callstack.Add(referenceToken.Data, null);

                // we add the token to referencesFromDocument to prevent stackoverflow on references cycles
                // newReferenceToken = context.ReserveNumberToken();
                // callstack.Add(newReferenceToken.Data.ObjectNumber);
                // referencesFromDocument.Add(referenceToken.Data, newReferenceToken);
                //
                var tokenObject = DirectObjectFinder.Get <IToken>(referenceToken.Data, tokenScanner);
                if (tokenObject is null)         //NullToken allowed
                {
                    return(null);
                }

                Debug.Assert(!(tokenObject is IndirectReferenceToken));
                var result = CopyToken(writer, tokenObject, tokenScanner, referencesFromDocument, callstack);

                if (callstack[referenceToken.Data] != null)
                {
                    return(writer.WriteToken(result, callstack[referenceToken.Data]));
                }

                newReferenceToken = writer.WriteToken(result);
                referencesFromDocument.Add(referenceToken.Data, newReferenceToken);
                return(newReferenceToken);
            }

            case StreamToken streamToken:
            {
                var properties = CopyToken(writer, streamToken.StreamDictionary, tokenScanner, referencesFromDocument, callstack) as DictionaryToken;
                Debug.Assert(properties != null);

                var bytes = streamToken.Data;
                return(new StreamToken(properties, bytes));
            }

            case ObjectToken _:
            {
                // Since we don't write token directly to the stream.
                // We can't know the offset. Therefore the token would be invalid
                throw new NotSupportedException("Copying a Object token is not supported");
            }
            }

            return(tokenToCopy);
        }