private void Write(PdfDictionary pdfDictionary) { WriteBytes(openDict); foreach (KeyValuePair <PdfName, PdfObject> entry in pdfDictionary.EntrySet()) { bool isAlreadyWriteSpace = false; Write(entry.Key); PdfObject value = entry.Value; if (value == null) { ILogger logger = LoggerFactory.GetLogger(typeof(iText.Kernel.Pdf.PdfOutputStream)); logger.Warn(String.Format(LogMessageConstant.INVALID_KEY_VALUE_KEY_0_HAS_NULL_VALUE, entry.Key)); value = PdfNull.PDF_NULL; } if ((value.GetObjectType() == PdfObject.NUMBER || value.GetObjectType() == PdfObject.LITERAL || value.GetObjectType () == PdfObject.BOOLEAN || value.GetObjectType() == PdfObject.NULL || value.GetObjectType() == PdfObject .INDIRECT_REFERENCE || value.CheckState(PdfObject.MUST_BE_INDIRECT))) { isAlreadyWriteSpace = true; WriteSpace(); } PdfIndirectReference indirectReference; if ((indirectReference = value.GetIndirectReference()) != null) { if (!isAlreadyWriteSpace) { WriteSpace(); } Write(indirectReference); } else { Write(value); } } WriteBytes(closeDict); }
private void CheckAndResolveCircularReferences(PdfObject pdfObject) { // Consider the situation when an XObject references the resources of the first page. // We add this XObject to the first page, there is no need to resolve any circular references // and then we flush this object and try to add it to the second page. // Now there are circular references and we cannot resolve them because the object is flushed // and we cannot get resources. // On the other hand, this situation may occur any time when object is already flushed and we // try to add it to resources and it seems difficult to overcome this without keeping /Resources key value. if (pdfObject is PdfDictionary && !pdfObject.IsFlushed()) { PdfDictionary pdfXObject = (PdfDictionary)pdfObject; PdfObject pdfXObjectResources = pdfXObject.Get(PdfName.Resources); if (pdfXObjectResources != null && pdfXObjectResources.GetIndirectReference() != null) { if (pdfXObjectResources.GetIndirectReference().Equals(GetPdfObject().GetIndirectReference())) { PdfObject cloneResources = GetPdfObject().Clone(); cloneResources.MakeIndirect(GetPdfObject().GetIndirectReference().GetDocument()); pdfXObject.Put(PdfName.Resources, cloneResources.GetIndirectReference()); } } } }
private void FlushObjectRecursively(PdfObject obj, PageFlushingHelper.DeepFlushingContext context) { if (obj == null) { return; } bool avoidReleaseForIndirectObjInstance = false; if (obj.IsIndirectReference()) { PdfIndirectReference indRef = (PdfIndirectReference)obj; if (indRef.refersTo == null || indRef.CheckState(PdfObject.FLUSHED)) { return; } obj = indRef.GetRefersTo(); } else { if (obj.IsFlushed()) { return; } else { if (release && obj.IsIndirect()) { // We should avoid the case when object is going to be released but is stored in containing object // not as indirect reference. This can happen when containing object is somehow modified. // Generally containing objects should not contain released read-only object instance. System.Diagnostics.Debug.Assert(obj.IsReleaseForbidden() || obj.GetIndirectReference() == null); avoidReleaseForIndirectObjInstance = true; } } } if (pdfDoc.IsDocumentFont(obj.GetIndirectReference()) || layersRefs.Contains(obj.GetIndirectReference())) { return; } if (obj.IsDictionary() || obj.IsStream()) { if (!currNestedObjParents.Add(obj)) { return; } FlushDictRecursively((PdfDictionary)obj, context); currNestedObjParents.Remove(obj); } else { if (obj.IsArray()) { if (!currNestedObjParents.Add(obj)) { return; } PdfArray array = (PdfArray)obj; for (int i = 0; i < array.Size(); ++i) { FlushObjectRecursively(array.Get(i, false), context); } currNestedObjParents.Remove(obj); } } if (!avoidReleaseForIndirectObjInstance) { FlushOrRelease(obj); } }
// For internal usage only /// <summary>Write a PdfObject to the outputstream.</summary> /// <param name="pdfObject">PdfObject to write</param> /// <returns>this PdfOutPutStream</returns> public virtual iText.Kernel.Pdf.PdfOutputStream Write(PdfObject pdfObject) { if (pdfObject.CheckState(PdfObject.MUST_BE_INDIRECT) && document != null) { pdfObject.MakeIndirect(document); pdfObject = pdfObject.GetIndirectReference(); } if (pdfObject.CheckState(PdfObject.READ_ONLY)) { throw new PdfException(PdfException.CannotWriteObjectAfterItWasReleased); } switch (pdfObject.GetObjectType()) { case PdfObject.ARRAY: { Write((PdfArray)pdfObject); break; } case PdfObject.DICTIONARY: { Write((PdfDictionary)pdfObject); break; } case PdfObject.INDIRECT_REFERENCE: { Write((PdfIndirectReference)pdfObject); break; } case PdfObject.NAME: { Write((PdfName)pdfObject); break; } case PdfObject.NULL: case PdfObject.BOOLEAN: { Write((PdfPrimitiveObject)pdfObject); break; } case PdfObject.LITERAL: { Write((PdfLiteral)pdfObject); break; } case PdfObject.STRING: { Write((PdfString)pdfObject); break; } case PdfObject.NUMBER: { Write((PdfNumber)pdfObject); break; } case PdfObject.STREAM: { Write((PdfStream)pdfObject); break; } } return(this); }
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(); } } } }
/// <summary>Add an entry to the name tree</summary> /// <param name="key">key of the entry</param> /// <param name="value">object to add</param> public virtual void AddEntry(String key, PdfObject value) { PdfObject existingVal = items.Get(key); if (existingVal != null) { if (value.GetIndirectReference() != null && value.GetIndirectReference().Equals(existingVal.GetIndirectReference ())) { return; } else { ILog logger = LogManager.GetLogger(typeof(iText.Kernel.Pdf.PdfNameTree)); logger.Warn(MessageFormatUtil.Format(iText.IO.LogMessageConstant.NAME_ALREADY_EXISTS_IN_THE_NAME_TREE, key )); } } modified = true; items.Put(key, value); }
protected internal virtual int GetCopyObjectKey(PdfObject obj) { return(CalculateIndRefKey(obj.GetIndirectReference())); }