private void RegisterAllMcrs() { pageToPageMcrs = new Dictionary <PdfIndirectReference, SortedDictionary <int, PdfMcr> >(); // we create new number tree and not using parentTree, because we want parentTree to be empty IDictionary <int?, PdfObject> parentTreeEntries = new PdfNumTree(structTreeRoot.GetDocument().GetCatalog(), PdfName.ParentTree).GetNumbers(); ICollection <PdfStructElem> mcrParents = new HashSet <PdfStructElem>(); int maxStructParentIndex = -1; foreach (KeyValuePair <int?, PdfObject> entry in parentTreeEntries) { if (entry.Key > maxStructParentIndex) { maxStructParentIndex = (int)entry.Key; } PdfObject entryValue = entry.Value; if (entryValue.IsDictionary()) { mcrParents.Add(new PdfStructElem((PdfDictionary)entryValue)); } else { if (entryValue.IsArray()) { PdfArray parentsArray = (PdfArray)entryValue; for (int i = 0; i < parentsArray.Size(); ++i) { PdfDictionary parent = parentsArray.GetAsDictionary(i); if (parent != null) { mcrParents.Add(new PdfStructElem(parent)); } } } } } structTreeRoot.GetPdfObject().Put(PdfName.ParentTreeNextKey, new PdfNumber(maxStructParentIndex + 1)); foreach (PdfStructElem mcrParent in mcrParents) { foreach (IStructureNode kid in mcrParent.GetKids()) { if (kid is PdfMcr) { RegisterMcr((PdfMcr)kid, true); } } } }
/// <returns>parent of the current structure element. Returns null if parent isn't set or if either current element or parent are invalid. /// </returns> public virtual IStructureNode GetParent() { PdfDictionary parent = GetPdfObject().GetAsDictionary(PdfName.P); if (parent == null) { return(null); } if (parent.IsFlushed()) { PdfDocument pdfDoc = GetDocument(); if (pdfDoc == null) { return(null); } PdfStructTreeRoot structTreeRoot = pdfDoc.GetStructTreeRoot(); return(structTreeRoot.GetPdfObject() == parent ? (IStructureNode)structTreeRoot : new iText.Kernel.Pdf.Tagging.PdfStructElem (parent)); } if (IsStructElem(parent)) { return(new iText.Kernel.Pdf.Tagging.PdfStructElem(parent)); } else { PdfDocument pdfDoc = GetDocument(); bool parentIsRoot = pdfDoc != null && PdfName.StructTreeRoot.Equals(parent.GetAsName(PdfName.Type)); parentIsRoot = parentIsRoot || pdfDoc != null && pdfDoc.GetStructTreeRoot().GetPdfObject() == parent; if (parentIsRoot) { return(pdfDoc.GetStructTreeRoot()); } else { return(null); } } }
/// <summary> /// Copies structure to a /// <paramref name="destDocument"/> /// and insert it in a specified position in the document. /// <br/><br/> /// NOTE: Works only for /// <c>PdfStructTreeRoot</c> /// that is read from the document opened in reading mode, /// otherwise an exception is thrown. /// <br/> /// Also, to insert a tagged page into existing tag structure, existing tag structure shouldn't be flushed, otherwise /// an exception may be raised. /// </summary> /// <param name="destDocument">document to copy structure to.</param> /// <param name="insertBeforePage">indicates where the structure to be inserted.</param> /// <param name="page2page">association between original page and copied page.</param> public static void CopyTo(PdfDocument destDocument, int insertBeforePage, IDictionary <PdfPage, PdfPage> page2page , PdfDocument callingDocument) { if (!destDocument.IsTagged()) { return; } // Here we separate the structure tree in two parts: struct elems that belong to the pages which indexes are // less then insertBeforePage and those struct elems that belong to other pages. Some elems might belong // to both parts and actually these are the ones that we are looking for. ICollection <PdfObject> firstPartElems = new HashSet <PdfObject>(); PdfStructTreeRoot destStructTreeRoot = destDocument.GetStructTreeRoot(); for (int i = 1; i < insertBeforePage; ++i) { PdfPage pageOfFirstHalf = destDocument.GetPage(i); ICollection <PdfMcr> pageMcrs = destStructTreeRoot.GetPageMarkedContentReferences(pageOfFirstHalf); if (pageMcrs != null) { foreach (PdfMcr mcr in pageMcrs) { firstPartElems.Add(mcr.GetPdfObject()); PdfDictionary top = AddAllParentsToSet(mcr, firstPartElems); if (top.IsFlushed()) { throw new PdfException(PdfException.TagFromTheExistingTagStructureIsFlushedCannotAddCopiedPageTags); } } } } IList <PdfDictionary> clonedTops = new List <PdfDictionary>(); PdfArray tops = destStructTreeRoot.GetKidsObject(); // Now we "walk" through all the elems which belong to the first part, and look for the ones that contain both // kids from first and second part. We clone found elements and move kids from the second part to cloned elems. int lastTopBefore = 0; for (int i_1 = 0; i_1 < tops.Size(); ++i_1) { PdfDictionary top = tops.GetAsDictionary(i_1); if (firstPartElems.Contains(top)) { lastTopBefore = i_1; StructureTreeCopier.LastClonedAncestor lastCloned = new StructureTreeCopier.LastClonedAncestor(); lastCloned.ancestor = top; PdfDictionary topClone = top.Clone(ignoreKeysForClone); topClone.Put(PdfName.P, destStructTreeRoot.GetPdfObject()); lastCloned.clone = topClone; SeparateKids(top, firstPartElems, lastCloned); if (topClone.ContainsKey(PdfName.K)) { topClone.MakeIndirect(destDocument); clonedTops.Add(topClone); } } } for (int i_2 = 0; i_2 < clonedTops.Count; ++i_2) { destStructTreeRoot.AddKidObject(lastTopBefore + 1 + i_2, clonedTops[i_2]); } CopyTo(destDocument, page2page, callingDocument, false, lastTopBefore + 1); }