internal virtual PdfDestination CopyDestination(PdfObject dest, IDictionary <PdfPage, PdfPage> page2page, PdfDocument toDocument) { PdfDestination d = null; if (dest.IsArray()) { PdfObject pageObject = ((PdfArray)dest).Get(0); foreach (PdfPage oldPage in page2page.Keys) { if (oldPage.GetPdfObject() == pageObject) { // in the copiedArray old page ref will be correctly replaced by the new page ref as this page is already copied PdfArray copiedArray = (PdfArray)dest.CopyTo(toDocument, false); d = new PdfExplicitDestination(copiedArray); break; } } } else { if (dest.IsString() || dest.IsName()) { PdfNameTree destsTree = GetNameTree(PdfName.Dests); IDictionary <String, PdfObject> dests = destsTree.GetNames(); String srcDestName = dest.IsString() ? ((PdfString)dest).ToUnicodeString() : ((PdfName)dest).GetValue(); PdfArray srcDestArray = (PdfArray)dests.Get(srcDestName); if (srcDestArray != null) { PdfObject pageObject = srcDestArray.Get(0); if (pageObject is PdfNumber) { pageObject = GetDocument().GetPage(((PdfNumber)pageObject).IntValue() + 1).GetPdfObject(); } foreach (PdfPage oldPage in page2page.Keys) { if (oldPage.GetPdfObject() == pageObject) { d = new PdfStringDestination(srcDestName); if (!IsEqualSameNameDestExist(page2page, toDocument, srcDestName, srcDestArray, oldPage)) { // in the copiedArray old page ref will be correctly replaced by the new page ref as this page is already copied PdfArray copiedArray = (PdfArray)srcDestArray.CopyTo(toDocument, false); // here we can safely replace first item of the array because array of NamedDestination or StringDestination // never refers to page in another document via PdfNumber, but should always refer to page within current document // via page object reference. copiedArray.Set(0, page2page.Get(oldPage).GetPdfObject()); toDocument.AddNamedDestination(srcDestName, copiedArray); } break; } } } } } return(d); }
internal virtual PdfDestination CopyDestination(PdfObject dest, IDictionary <PdfPage, PdfPage> page2page, PdfDocument toDocument) { PdfDestination d = null; if (dest.IsArray()) { PdfObject pageObject = ((PdfArray)dest).Get(0); foreach (PdfPage oldPage in page2page.Keys) { if (oldPage.GetPdfObject() == pageObject) { PdfArray array = new PdfArray((PdfArray)dest); array.Set(0, page2page.Get(oldPage).GetPdfObject()); d = new PdfExplicitDestination(array); } } } else { if (dest.IsString()) { PdfNameTree destsTree = GetNameTree(PdfName.Dests); IDictionary <String, PdfObject> dests = destsTree.GetNames(); String name = ((PdfString)dest).ToUnicodeString(); PdfArray array = (PdfArray)dests.Get(name); if (array != null) { PdfObject pageObject = array.Get(0); foreach (PdfPage oldPage in page2page.Keys) { if (oldPage.GetPdfObject() == pageObject) { array.Set(0, page2page.Get(oldPage).GetPdfObject()); d = new PdfStringDestination(name); toDocument.AddNamedDestination(name, array); } } } } } return(d); }
private void LoadPage(int pageNum) { PdfDictionary targetPage = pageRefs[pageNum]; if (targetPage != null) { return; } //if we go here, we have to split PdfPages that contains pageNum int parentIndex = FindPageParent(pageNum); PdfPages parent = parents[parentIndex]; PdfArray kids = parent.GetKids(); if (kids == null) { throw new PdfException(PdfException.InvalidPageStructure1).SetMessageParams(pageNum + 1); } int kidsCount = parent.GetCount(); // we should handle separated pages, it means every PdfArray kids must contain either PdfPage or PdfPages, // mix of PdfPage and PdfPages not allowed. bool findPdfPages = false; // NOTE optimization? when we already found needed index for (int i = 0; i < kids.Size(); i++) { PdfDictionary page = kids.GetAsDictionary(i); if (page == null) { // null values not allowed in pages tree. throw new PdfException(PdfException.InvalidPageStructure1).SetMessageParams(pageNum + 1); } PdfObject pageKids = page.Get(PdfName.Kids); if (pageKids != null) { if (pageKids.GetObjectType() == PdfObject.ARRAY) { findPdfPages = true; } else { // kids must be of type array throw new PdfException(PdfException.InvalidPageStructure1).SetMessageParams(pageNum + 1); } } } if (findPdfPages) { // handle mix of PdfPage and PdfPages. // handle count property! IList <PdfPages> newParents = new List <PdfPages>(kids.Size()); PdfPages lastPdfPages = null; for (int i_1 = 0; i_1 < kids.Size() && kidsCount > 0; i_1++) { PdfDictionary pdfPagesObject = kids.GetAsDictionary(i_1); if (pdfPagesObject.GetAsArray(PdfName.Kids) == null) { // pdfPagesObject is PdfPage if (lastPdfPages == null) { // possible if only first kid is PdfPage lastPdfPages = new PdfPages(parent.GetFrom(), document, parent); kids.Set(i_1, lastPdfPages.GetPdfObject()); newParents.Add(lastPdfPages); } lastPdfPages.AddPage(pdfPagesObject); kids.Remove(i_1); i_1--; kidsCount--; } else { // pdfPagesObject is PdfPages int from = lastPdfPages == null?parent.GetFrom() : lastPdfPages.GetFrom() + lastPdfPages.GetCount(); lastPdfPages = new PdfPages(from, kidsCount, pdfPagesObject, parent); newParents.Add(lastPdfPages); kidsCount -= lastPdfPages.GetCount(); } } parents.JRemoveAt(parentIndex); for (int i_2 = newParents.Count - 1; i_2 >= 0; i_2--) { parents.Add(parentIndex, newParents[i_2]); } // recursive call, to load needed pageRef. // NOTE optimization? add to loadPage startParentIndex. LoadPage(pageNum); } else { int from = parent.GetFrom(); // Possible exception in case kids.getSize() < parent.getCount(). // In any case parent.getCount() has higher priority. // NOTE optimization? when we already found needed index for (int i_1 = 0; i_1 < parent.GetCount(); i_1++) { pageRefs[from + i_1] = kids.GetAsDictionary(i_1); } } }
private void LoadPage(int pageNum) { PdfIndirectReference targetPage = pageRefs[pageNum]; if (targetPage != null) { return; } //if we go here, we have to split PdfPages that contains pageNum int parentIndex = FindPageParent(pageNum); PdfPages parent = parents[parentIndex]; PdfArray kids = parent.GetKids(); if (kids == null) { throw new PdfException(PdfException.InvalidPageStructure1).SetMessageParams(pageNum + 1); } int kidsCount = parent.GetCount(); // we should handle separated pages, it means every PdfArray kids must contain either PdfPage or PdfPages, // mix of PdfPage and PdfPages not allowed. bool findPdfPages = false; // NOTE optimization? when we already found needed index for (int i = 0; i < kids.Size(); i++) { PdfDictionary page = kids.GetAsDictionary(i); // null values not allowed in pages tree. if (page == null) { throw new PdfException(PdfException.InvalidPageStructure1).SetMessageParams(pageNum + 1); } PdfObject pageKids = page.Get(PdfName.Kids); if (pageKids != null) { if (pageKids.IsArray()) { findPdfPages = true; } else { // kids must be of type array throw new PdfException(PdfException.InvalidPageStructure1).SetMessageParams(pageNum + 1); } } if (document.GetReader().IsMemorySavingMode() && !findPdfPages && parent.GetFrom() + i != pageNum) { page.Release(); } } if (findPdfPages) { // handle mix of PdfPage and PdfPages. // handle count property! IList <PdfPages> newParents = new List <PdfPages>(kids.Size()); PdfPages lastPdfPages = null; for (int i = 0; i < kids.Size() && kidsCount > 0; i++) { /* * We don't release pdfPagesObject in the end of each loop because we enter this for-cycle only when parent has PdfPages kids. * If all of the kids are PdfPages, then there's nothing to release, because we don't release PdfPages at this point. * If there are kids that are instances of PdfPage, then there's no sense in releasing them: * in this case ParentTreeStructure is being rebuilt by inserting an intermediate PdfPages between the parent and a PdfPage, * thus modifying the page object by resetting its parent, thus making it impossible to release the object. */ PdfDictionary pdfPagesObject = kids.GetAsDictionary(i); if (pdfPagesObject.GetAsArray(PdfName.Kids) == null) { // pdfPagesObject is PdfPage // possible if only first kid is PdfPage if (lastPdfPages == null) { lastPdfPages = new PdfPages(parent.GetFrom(), document, parent); kids.Set(i, lastPdfPages.GetPdfObject()); newParents.Add(lastPdfPages); } else { // Only remove from kids if we did not replace the entry with new PdfPages kids.Remove(i); i--; } // decrement count first so that page is not counted twice when moved to lastPdfPages parent.DecrementCount(); lastPdfPages.AddPage(pdfPagesObject); kidsCount--; } else { // pdfPagesObject is PdfPages int from = lastPdfPages == null?parent.GetFrom() : lastPdfPages.GetFrom() + lastPdfPages.GetCount(); lastPdfPages = new PdfPages(from, kidsCount, pdfPagesObject, parent); newParents.Add(lastPdfPages); kidsCount -= lastPdfPages.GetCount(); } } parents.JRemoveAt(parentIndex); for (int i = newParents.Count - 1; i >= 0; i--) { parents.Add(parentIndex, newParents[i]); } // recursive call, to load needed pageRef. // NOTE optimization? add to loadPage startParentIndex. LoadPage(pageNum); } else { int from = parent.GetFrom(); // Possible exception in case kids.getSize() < parent.getCount(). // In any case parent.getCount() has higher priority. // NOTE optimization? when we already found needed index for (int i = 0; i < parent.GetCount(); i++) { PdfObject kid = kids.Get(i, false); if (kid is PdfIndirectReference) { pageRefs[from + i] = (PdfIndirectReference)kid; } else { pageRefs[from + i] = kid.GetIndirectReference(); } } } }