Example #1
0
        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;
 }
Example #3
0
        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);
     }
 }
Example #6
0
        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;
 }
Example #8
0
        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();
            }
        }
Example #9
0
        // 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;
        }
Example #10
0
        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);
                }
            }
        }
Example #11
0
        /// <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);
        }
Example #12
0
        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);
            }
        }
Example #13
0
        /// <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();
            }
        }