public void AppendDocument(Catalog catalog, decimal version, IPdfTokenScanner tokenScanner, IReadOnlyList <int> pages) { IEnumerable <int> pageIndices; if (pages == null) { var pagesCount = catalog.PagesDictionary.GetIntOrDefault(NameToken.Count); if (pagesCount < 1) { return; } pageIndices = Enumerable.Range(1, pagesCount); } else if (pages.Count < 1) { return; } else { pageIndices = pages; } currentVersion = Math.Max(version, currentVersion); var referencesFromDocument = new Dictionary <IndirectReference, IndirectReferenceToken>(); var currentNodeReference = context.ReserveNumberToken(); var pagesReferences = new List <IndirectReferenceToken>(); var resources = new Dictionary <string, IToken>(); bool DoesAEntryCollide(PageTreeNode node) { while (node != null) { var dictionary = node.NodeDictionary; if (dictionary.TryGet(NameToken.Resources, tokenScanner, out DictionaryToken resourcesDictionary)) { var nonCollidingResources = resourcesDictionary.Data.Keys.Except(resources.Keys); if (nonCollidingResources.Count() != resourcesDictionary.Data.Count) { // This means that at least one of the resources collided return(true); } } /* TODO: How to handle? * `Rotate` * `CropBox` * `MediaBox` */ // No colliding entry was found, in this node // Keep walking up into the tree node = node.Parent; } return(false); } void CopyEntries(PageTreeNode node) { while (node != null) { var dictionary = node.NodeDictionary; if (dictionary.TryGet(NameToken.Resources, tokenScanner, out DictionaryToken resourcesDictionary)) { foreach (var pair in resourcesDictionary.Data) { resources.Add(pair.Key, CopyToken(pair.Value, tokenScanner, referencesFromDocument)); } } /* TODO: How to handle? * `Rotate` * `CropBox` * `MediaBox` */ // Keep walking up into the tree node = node.Parent; } } void CreateTree() { if (pagesReferences.Count < 1) { throw new InvalidOperationException("Pages reference should always be more than 1 when executing this function"); } var newPagesNode = new Dictionary <NameToken, IToken> { { NameToken.Type, NameToken.Pages }, { NameToken.Kids, new ArrayToken(pagesReferences) }, { NameToken.Count, new NumericToken(pagesReferences.Count) }, { NameToken.Parent, rootPagesReference } }; if (resources.Count > 0) { newPagesNode.Add(NameToken.Resources, DictionaryToken.With(resources)); } var pagesDictionary = new DictionaryToken(newPagesNode); pagesTokenReferences.Add(context.WriteToken(pagesDictionary, (int)currentNodeReference.Data.ObjectNumber)); pageCount += pagesReferences.Count; }; foreach (var pageIndex in pageIndices) { var pageNode = catalog.GetPageNode(pageIndex); if (pagesReferences.Count >= ARTIFICIAL_NODE_LIMIT || DoesAEntryCollide(pageNode)) { CreateTree(); currentNodeReference = context.ReserveNumberToken(); pagesReferences = new List <IndirectReferenceToken>(); resources = new Dictionary <string, IToken>(); } CopyEntries(pageNode.Parent); pagesReferences.Add(CopyPageNode(pageNode, currentNodeReference, tokenScanner, referencesFromDocument)); } if (pagesReferences.Count < 1) { throw new InvalidOperationException("Pages reference couldn't be less than 1 because we have reserved a indirect reference token"); } CreateTree(); }
public DocumentMerger() { rootPagesReference = context.ReserveNumberToken(); }
public DocumentMerger(Stream baseStream) { context = new PdfStreamWriter(baseStream, false); rootPagesReference = context.ReserveNumberToken(); }