public virtual void RegisterMcr(PdfMcr mcr) { SortedDictionary <int, PdfMcr> pageMcrs = pageToPageMcrs.Get(mcr.GetPageObject().GetIndirectReference()); if (pageMcrs == null) { pageMcrs = new SortedDictionary <int, PdfMcr>(); pageToPageMcrs[mcr.GetPageObject().GetIndirectReference()] = pageMcrs; } if (mcr is PdfObjRef) { PdfDictionary obj = ((PdfDictionary)mcr.GetPdfObject()).GetAsDictionary(PdfName.Obj); if (obj == null || obj.IsFlushed()) { throw new PdfException(PdfException.WhenAddingObjectReferenceToTheTagTreeItMustBeConnectedToNotFlushedObject ); } PdfNumber n = obj.GetAsNumber(PdfName.StructParent); if (n != null) { pageMcrs[StructParentIndexIntoKey(n.IntValue())] = mcr; } else { throw new PdfException(PdfException.StructParentIndexNotFoundInTaggedObject); } } else { pageMcrs[mcr.GetMcid()] = mcr; } }
private static int SeparateStructure(PdfDocument document, int startPage, int beforePage, int startPageStructTopIndex ) { if (!document.IsTagged() || 1 > startPage || startPage > beforePage || beforePage > document.GetNumberOfPages () + 1) { return -1; } else { if (beforePage == startPage) { return startPageStructTopIndex; } else { if (beforePage == document.GetNumberOfPages() + 1) { return document.GetStructTreeRoot().GetKidsObject().Size(); } } } // Here we separate the structure tree in two parts: struct elems that belong to the pages which indexes are // less then separateBeforePage 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>(); for (int i = startPage; i < beforePage; ++i) { PdfPage pageOfFirstHalf = document.GetPage(i); ICollection<PdfMcr> pageMcrs = document.GetStructTreeRoot().GetPageMarkedContentReferences(pageOfFirstHalf ); if (pageMcrs != null) { foreach (PdfMcr mcr in pageMcrs) { firstPartElems.Add(mcr.GetPdfObject()); PdfDictionary top = AddAllParentsToSet(mcr, firstPartElems); if (top != null && top.IsFlushed()) { throw new PdfException(PdfException.TagFromTheExistingTagStructureIsFlushedCannotAddCopiedPageTags); } } } } IList<PdfDictionary> clonedTops = new List<PdfDictionary>(); PdfArray tops = document.GetStructTreeRoot().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 = startPageStructTopIndex - 1; for (int i = 0; i < tops.Size(); ++i) { PdfDictionary top = tops.GetAsDictionary(i); if (firstPartElems.Contains(top)) { lastTopBefore = i; StructureTreeCopier.LastClonedAncestor lastCloned = new StructureTreeCopier.LastClonedAncestor(); lastCloned.ancestor = top; PdfDictionary topClone = top.Clone(ignoreKeysForClone); topClone.Put(PdfName.P, document.GetStructTreeRoot().GetPdfObject()); lastCloned.clone = topClone; SeparateKids(top, firstPartElems, lastCloned, document); if (topClone.ContainsKey(PdfName.K)) { topClone.MakeIndirect(document); clonedTops.Add(topClone); } } } for (int i = 0; i < clonedTops.Count; ++i) { document.GetStructTreeRoot().AddKidObject(lastTopBefore + 1 + i, clonedTops[i]); } return lastTopBefore + 1; }
private static void CopyTo(PdfDocument destDocument, IDictionary <PdfPage, PdfPage> page2page, PdfDocument callingDocument, bool copyFromDestDocument, int insertIndex) { PdfDocument fromDocument = copyFromDestDocument ? destDocument : callingDocument; ICollection <PdfDictionary> tops = new HashSet <PdfDictionary>(); ICollection <PdfObject> objectsToCopy = new HashSet <PdfObject>(); IDictionary <PdfDictionary, PdfDictionary> page2pageDictionaries = new Dictionary <PdfDictionary, PdfDictionary >(); foreach (KeyValuePair <PdfPage, PdfPage> page in page2page) { page2pageDictionaries[page.Key.GetPdfObject()] = page.Value.GetPdfObject(); ICollection <PdfMcr> mcrs = fromDocument.GetStructTreeRoot().GetPageMarkedContentReferences(page.Key); if (mcrs != null) { foreach (PdfMcr mcr in mcrs) { if (mcr is PdfMcrDictionary || mcr is PdfObjRef) { objectsToCopy.Add(mcr.GetPdfObject()); } PdfDictionary top = AddAllParentsToSet(mcr, objectsToCopy); if (top.IsFlushed()) { throw new PdfException(PdfException.CannotCopyFlushedTag); } tops.Add(top); } } } IList <PdfDictionary> topsInOriginalOrder = new List <PdfDictionary>(); foreach (IPdfStructElem kid in fromDocument.GetStructTreeRoot().GetKids()) { if (kid == null) { continue; } PdfDictionary kidObject = ((PdfStructElem)kid).GetPdfObject(); if (tops.Contains(kidObject)) { topsInOriginalOrder.Add(kidObject); } } foreach (PdfDictionary top_1 in topsInOriginalOrder) { PdfDictionary copied = CopyObject(top_1, objectsToCopy, destDocument, page2pageDictionaries, copyFromDestDocument ); destDocument.GetStructTreeRoot().AddKidObject(insertIndex, copied); if (insertIndex > -1) { ++insertIndex; } } }
private static StructureTreeCopier.CopyStructureResult CopyStructure(PdfDocument destDocument, IDictionary <PdfPage, PdfPage> page2page, PdfDocument callingDocument, bool copyFromDestDocument) { PdfDocument fromDocument = copyFromDestDocument ? destDocument : callingDocument; IDictionary<PdfDictionary, PdfDictionary> topsToFirstDestPage = new Dictionary<PdfDictionary, PdfDictionary >(); ICollection<PdfObject> objectsToCopy = new HashSet<PdfObject>(); IDictionary<PdfDictionary, PdfDictionary> page2pageDictionaries = new Dictionary<PdfDictionary, PdfDictionary >(); foreach (KeyValuePair<PdfPage, PdfPage> page in page2page) { page2pageDictionaries.Put(page.Key.GetPdfObject(), page.Value.GetPdfObject()); ICollection<PdfMcr> mcrs = fromDocument.GetStructTreeRoot().GetPageMarkedContentReferences(page.Key); if (mcrs != null) { foreach (PdfMcr mcr in mcrs) { if (mcr is PdfMcrDictionary || mcr is PdfObjRef) { objectsToCopy.Add(mcr.GetPdfObject()); } PdfDictionary top = AddAllParentsToSet(mcr, objectsToCopy); if (top != null) { if (top.IsFlushed()) { throw new PdfException(PdfException.CannotCopyFlushedTag); } if (!topsToFirstDestPage.ContainsKey(top)) { topsToFirstDestPage.Put(top, page.Value.GetPdfObject()); } } } } } IList<PdfDictionary> topsInOriginalOrder = new List<PdfDictionary>(); foreach (IStructureNode kid in fromDocument.GetStructTreeRoot().GetKids()) { if (kid == null) { continue; } PdfDictionary kidObject = ((PdfStructElem)kid).GetPdfObject(); if (topsToFirstDestPage.ContainsKey(kidObject)) { topsInOriginalOrder.Add(kidObject); } } StructureTreeCopier.StructElemCopyingParams structElemCopyingParams = new StructureTreeCopier.StructElemCopyingParams (objectsToCopy, destDocument, page2pageDictionaries, copyFromDestDocument); PdfStructTreeRoot destStructTreeRoot = destDocument.GetStructTreeRoot(); destStructTreeRoot.MakeIndirect(destDocument); IList<PdfDictionary> copiedTops = new List<PdfDictionary>(); foreach (PdfDictionary top in topsInOriginalOrder) { PdfDictionary copied = CopyObject(top, topsToFirstDestPage.Get(top), false, structElemCopyingParams); copiedTops.Add(copied); } return new StructureTreeCopier.CopyStructureResult(copiedTops, structElemCopyingParams.GetCopiedNamespaces ()); }
/// <summary>Move tag structure of page to other place in the same document</summary> /// <param name="document">document in which modifications will take place (should be opened in read-write mode) /// </param> /// <param name="from">page, which tag structure will be moved</param> /// <param name="insertBefore">indicates before what page number structure will be inserted to</param> public static void Move(PdfDocument document, PdfPage from, int insertBefore) { if (!document.IsTagged() || insertBefore < 1 || insertBefore > document.GetNumberOfPages() + 1) { return; } int fromNum = document.GetPageNumber(from); if (fromNum == 0 || fromNum == insertBefore || fromNum + 1 == insertBefore) { return; } int destStruct; int currStruct = 0; if (fromNum > insertBefore) { destStruct = currStruct = SeparateStructure(document, 1, insertBefore, 0); currStruct = SeparateStructure(document, insertBefore, fromNum, currStruct); currStruct = SeparateStructure(document, fromNum, fromNum + 1, currStruct); } else { currStruct = SeparateStructure(document, 1, fromNum, 0); currStruct = SeparateStructure(document, fromNum, fromNum + 1, currStruct); destStruct = currStruct = SeparateStructure(document, fromNum + 1, insertBefore, currStruct); } ICollection<PdfDictionary> topsToMove = new HashSet<PdfDictionary>(); ICollection<PdfMcr> mcrs = document.GetStructTreeRoot().GetPageMarkedContentReferences(from); if (mcrs != null) { foreach (PdfMcr mcr in mcrs) { PdfDictionary top = GetTopmostParent(mcr); if (top != null) { if (top.IsFlushed()) { throw new PdfException(PdfException.CannotMoveFlushedTag); } topsToMove.Add(top); } } } IList<PdfDictionary> orderedTopsToMove = new List<PdfDictionary>(); PdfArray tops = document.GetStructTreeRoot().GetKidsObject(); for (int i = 0; i < tops.Size(); ++i) { PdfDictionary top = tops.GetAsDictionary(i); if (topsToMove.Contains(top)) { orderedTopsToMove.Add(top); tops.Remove(i); if (i < destStruct) { --destStruct; } } } foreach (PdfDictionary top in orderedTopsToMove) { document.GetStructTreeRoot().AddKidObject(destStruct++, top); } }
public virtual void UnregisterMcr(PdfMcr mcrToUnregister) { PdfDictionary pageDict = mcrToUnregister.GetPageObject(); if (pageDict == null) { // invalid mcr, ignore return; } if (pageDict.IsFlushed()) { throw new PdfException(PdfException.CannotRemoveMarkedContentReferenceBecauseItsPageWasAlreadyFlushed); } IDictionary <int, PdfMcr> pageMcrs = pageToPageMcrs.Get(pageDict.GetIndirectReference()); if (pageMcrs != null) { if (mcrToUnregister is PdfObjRef) { PdfDictionary obj = ((PdfDictionary)mcrToUnregister.GetPdfObject()).GetAsDictionary(PdfName.Obj); if (obj != null && !obj.IsFlushed()) { PdfNumber n = obj.GetAsNumber(PdfName.StructParent); if (n != null) { pageMcrs.JRemove(StructParentIndexIntoKey(n.IntValue())); structTreeRoot.SetModified(); return; } } foreach (KeyValuePair <int, PdfMcr> entry in pageMcrs) { if (entry.Value.GetPdfObject() == mcrToUnregister.GetPdfObject()) { pageMcrs.JRemove(entry.Key); structTreeRoot.SetModified(); break; } } } else { pageMcrs.JRemove(mcrToUnregister.GetMcid()); structTreeRoot.SetModified(); } } }
private static IList<PdfDictionary> RetrieveParents(PdfMcr mcr, bool all) { IList<PdfDictionary> parents = new List<PdfDictionary>(); IStructureNode firstParent = mcr.GetParent(); PdfDictionary previous = null; PdfDictionary current = firstParent is PdfStructElem ? ((PdfStructElem)firstParent).GetPdfObject() : null; while (current != null && !PdfName.StructTreeRoot.Equals(current.GetAsName(PdfName.Type))) { if (all) { parents.Add(current); } previous = current; current = previous.IsFlushed() ? null : previous.GetAsDictionary(PdfName.P); } if (!all) { parents.Add(previous); } return parents; }
private void RegisterMcr(PdfMcr mcr, bool registeringOnInit) { PdfDictionary mcrPageObject = mcr.GetPageObject(); if (mcrPageObject == null || (!(mcr is PdfObjRef) && mcr.GetMcid() < 0)) { ILog logger = LogManager.GetLogger(typeof(iText.Kernel.Pdf.Tagging.ParentTreeHandler)); logger.Error(iText.IO.LogMessageConstant.ENCOUNTERED_INVALID_MCR); return; } SortedDictionary <int, PdfMcr> pageMcrs = pageToPageMcrs.Get(mcrPageObject.GetIndirectReference()); if (pageMcrs == null) { pageMcrs = new SortedDictionary <int, PdfMcr>(); pageToPageMcrs.Put(mcrPageObject.GetIndirectReference(), pageMcrs); } if (mcr is PdfObjRef) { PdfDictionary obj = ((PdfDictionary)mcr.GetPdfObject()).GetAsDictionary(PdfName.Obj); if (obj == null || obj.IsFlushed()) { throw new PdfException(PdfException.WhenAddingObjectReferenceToTheTagTreeItMustBeConnectedToNotFlushedObject ); } PdfNumber n = obj.GetAsNumber(PdfName.StructParent); if (n != null) { pageMcrs.Put(StructParentIndexIntoKey(n.IntValue()), mcr); } else { throw new PdfException(PdfException.StructParentIndexNotFoundInTaggedObject); } } else { pageMcrs.Put(mcr.GetMcid(), mcr); } if (!registeringOnInit) { structTreeRoot.SetModified(); } }
// it is StructTreeRoot // should never happen as we always should have only one root tag and we don't remove it private void FlushParentIfBelongsToPage(PdfStructElem parent, PdfPage currentPage) { if (parent.IsFlushed() || connectedStructToModel.ContainsKey(parent.GetPdfObject()) || parent.GetPdfObject () == rootTagElement.GetPdfObject()) { return; } IList <IPdfStructElem> kids = parent.GetKids(); bool allKidsBelongToPage = true; foreach (IPdfStructElem kid in kids) { if (kid is PdfMcr) { PdfDictionary kidPage = ((PdfMcr)kid).GetPageObject(); if (!kidPage.IsFlushed() && !kidPage.Equals(currentPage.GetPdfObject())) { allKidsBelongToPage = false; break; } } else { if (kid is PdfStructElem) { // If kid is structElem and was already flushed then in kids list there will be null for it instead of // PdfStructElem. And therefore if we get into this if clause it means that some StructElem wasn't flushed. allKidsBelongToPage = false; break; } } } if (allKidsBelongToPage) { IPdfStructElem parentsParent = parent.GetParent(); parent.Flush(); if (parentsParent is PdfStructElem) { FlushParentIfBelongsToPage((PdfStructElem)parentsParent, currentPage); } } return; }
internal virtual void FlushParentIfBelongsToPage(PdfStructElem parent, PdfPage currentPage) { if (parent.IsFlushed() || waitingTagsManager.GetObjForStructDict(parent.GetPdfObject()) != null || parent. GetParent() is PdfStructTreeRoot) { return; } IList <IStructureNode> kids = parent.GetKids(); bool readyToBeFlushed = true; foreach (IStructureNode kid in kids) { if (kid is PdfMcr) { PdfDictionary kidPage = ((PdfMcr)kid).GetPageObject(); if (!kidPage.IsFlushed() && (currentPage == null || !kidPage.Equals(currentPage.GetPdfObject()))) { readyToBeFlushed = false; break; } } else { if (kid is PdfStructElem) { // If kid is structElem and was already flushed then in kids list there will be null for it instead of // PdfStructElement. And therefore if we get into this if-clause it means that some StructElem wasn't flushed. readyToBeFlushed = false; break; } } } if (readyToBeFlushed) { IStructureNode parentsParent = parent.GetParent(); parent.Flush(); if (parentsParent is PdfStructElem) { FlushParentIfBelongsToPage((PdfStructElem)parentsParent, currentPage); } } }
/// <returns>the topmost parent added to set. If encountered flushed element - stops and returns this flushed element. /// </returns> private static PdfDictionary AddAllParentsToSet(PdfMcr mcr, ICollection <PdfObject> set) { PdfDictionary elem = ((PdfStructElem)mcr.GetParent()).GetPdfObject(); set.Add(elem); for (; ;) { if (elem.IsFlushed()) { break; } PdfDictionary p = elem.GetAsDictionary(PdfName.P); if (p == null || PdfName.StructTreeRoot.Equals(p.GetAsName(PdfName.Type))) { break; } else { elem = p; set.Add(elem); } } return(elem); }
private static void SeparateKids(PdfDictionary structElem, ICollection <PdfObject> firstPartElems, StructureTreeCopier.LastClonedAncestor lastCloned) { PdfObject k = structElem.Get(PdfName.K); // If /K entry is not a PdfArray - it would be a kid which we won't clone at the moment, because it won't contain // kids from both parts at the same time. It would either be cloned as an ancestor later, or not cloned at all. // If it's kid is struct elem - it would definitely be structElem from the first part, so we simply call separateKids for it. if (!k.IsArray()) { if (k.IsDictionary() && PdfStructElem.IsStructElem((PdfDictionary)k)) { SeparateKids((PdfDictionary)k, firstPartElems, lastCloned); } } else { PdfDocument document = structElem.GetIndirectReference().GetDocument(); PdfArray kids = (PdfArray)k; for (int i = 0; i < kids.Size(); ++i) { PdfObject kid = kids.Get(i); PdfDictionary dictKid = null; if (kid.IsDictionary()) { dictKid = (PdfDictionary)kid; } if (dictKid != null && PdfStructElem.IsStructElem(dictKid)) { if (firstPartElems.Contains(kid)) { SeparateKids((PdfDictionary)kid, firstPartElems, lastCloned); } else { if (dictKid.IsFlushed()) { throw new PdfException(PdfException.TagFromTheExistingTagStructureIsFlushedCannotAddCopiedPageTags); } // elems with no kids will not be marked as from the first part, // but nonetheless we don't want to move all of them to the second part; we just leave them as is if (dictKid.ContainsKey(PdfName.K)) { CloneParents(structElem, lastCloned, document); kids.Remove(i--); PdfStructElem.AddKidObject(lastCloned.clone, -1, kid); } } } else { if (!firstPartElems.Contains(kid)) { CloneParents(structElem, lastCloned, document); PdfMcr mcr; if (dictKid != null) { if (dictKid.Get(PdfName.Type).Equals(PdfName.MCR)) { mcr = new PdfMcrDictionary(dictKid, new PdfStructElem(lastCloned.clone)); } else { mcr = new PdfObjRef(dictKid, new PdfStructElem(lastCloned.clone)); } } else { mcr = new PdfMcrNumber((PdfNumber)kid, new PdfStructElem(lastCloned.clone)); } kids.Remove(i--); PdfStructElem.AddKidObject(lastCloned.clone, -1, kid); document.GetStructTreeRoot().GetParentTreeHandler().RegisterMcr(mcr); } } } } // re-register mcr if (lastCloned.ancestor == structElem) { lastCloned.ancestor = lastCloned.ancestor.GetAsDictionary(PdfName.P); lastCloned.clone = lastCloned.clone.GetAsDictionary(PdfName.P); } }
/// <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); }
public virtual void UnregisterMcr(PdfMcr mcrToUnregister) { PdfDictionary pageDict = mcrToUnregister.GetPageObject(); if (pageDict == null) { // invalid mcr, ignore return; } if (pageDict.IsFlushed()) { throw new PdfException(PdfException.CannotRemoveMarkedContentReferenceBecauseItsPageWasAlreadyFlushed); } ParentTreeHandler.PageMcrsContainer pageMcrs = pageToPageMcrs.Get(pageDict.GetIndirectReference()); if (pageMcrs != null) { PdfObject stm; if ((stm = GetStm(mcrToUnregister)) != null) { PdfIndirectReference xObjectReference = stm is PdfIndirectReference ? (PdfIndirectReference)stm : stm.GetIndirectReference (); pageMcrs.GetPageResourceXObjects().Get(xObjectReference).JRemove(mcrToUnregister.GetMcid()); if (pageMcrs.GetPageResourceXObjects().Get(xObjectReference).IsEmpty()) { pageMcrs.GetPageResourceXObjects().JRemove(xObjectReference); xObjectToStructParentsInd.JRemove(xObjectReference); } structTreeRoot.SetModified(); } else { if (mcrToUnregister is PdfObjRef) { PdfDictionary obj = ((PdfDictionary)mcrToUnregister.GetPdfObject()).GetAsDictionary(PdfName.Obj); if (obj != null && !obj.IsFlushed()) { PdfNumber n = obj.GetAsNumber(PdfName.StructParent); if (n != null) { pageMcrs.GetObjRefs().JRemove(n.IntValue()); structTreeRoot.SetModified(); return; } } foreach (KeyValuePair <int, PdfMcr> entry in pageMcrs.GetObjRefs()) { if (entry.Value.GetPdfObject() == mcrToUnregister.GetPdfObject()) { pageMcrs.GetObjRefs().JRemove(entry.Key); structTreeRoot.SetModified(); break; } } } else { pageMcrs.GetPageContentStreamsMcrs().JRemove(mcrToUnregister.GetMcid()); structTreeRoot.SetModified(); } } } }
private void RegisterMcr(PdfMcr mcr, bool registeringOnInit) { PdfIndirectReference mcrPageIndRef = mcr.GetPageIndirectReference(); if (mcrPageIndRef == null || (!(mcr is PdfObjRef) && mcr.GetMcid() < 0)) { ILog logger = LogManager.GetLogger(typeof(iText.Kernel.Pdf.Tagging.ParentTreeHandler)); logger.Error(iText.IO.LogMessageConstant.ENCOUNTERED_INVALID_MCR); return; } ParentTreeHandler.PageMcrsContainer pageMcrs = pageToPageMcrs.Get(mcrPageIndRef); if (pageMcrs == null) { pageMcrs = new ParentTreeHandler.PageMcrsContainer(); pageToPageMcrs.Put(mcrPageIndRef, pageMcrs); } PdfObject stm; if ((stm = GetStm(mcr)) != null) { PdfIndirectReference stmIndRef; PdfStream xObjectStream; if (stm is PdfIndirectReference) { stmIndRef = (PdfIndirectReference)stm; xObjectStream = (PdfStream)stmIndRef.GetRefersTo(); } else { if (stm.GetIndirectReference() == null) { stm.MakeIndirect(structTreeRoot.GetDocument()); } stmIndRef = stm.GetIndirectReference(); xObjectStream = (PdfStream)stm; } int?structParent = xObjectStream.GetAsInt(PdfName.StructParents); if (structParent != null) { xObjectToStructParentsInd.Put(stmIndRef, structParent); } else { // TODO DEVSIX-3351 an error is thrown here because right now no /StructParents will be created. ILog logger = LogManager.GetLogger(typeof(iText.Kernel.Pdf.Tagging.ParentTreeHandler)); logger.Error(iText.IO.LogMessageConstant.XOBJECT_HAS_NO_STRUCT_PARENTS); } pageMcrs.PutXObjectMcr(stmIndRef, mcr); if (registeringOnInit) { xObjectStream.Release(); } } else { if (mcr is PdfObjRef) { PdfDictionary obj = ((PdfDictionary)mcr.GetPdfObject()).GetAsDictionary(PdfName.Obj); if (obj == null || obj.IsFlushed()) { throw new PdfException(PdfException.WhenAddingObjectReferenceToTheTagTreeItMustBeConnectedToNotFlushedObject ); } PdfNumber n = obj.GetAsNumber(PdfName.StructParent); if (n != null) { pageMcrs.PutObjectReferenceMcr(n.IntValue(), mcr); } else { throw new PdfException(PdfException.StructParentIndexNotFoundInTaggedObject); } } else { pageMcrs.PutPageContentStreamMcr(mcr.GetMcid(), mcr); } } if (!registeringOnInit) { structTreeRoot.SetModified(); } }