private static void CopyDArrayField(PdfName fieldToCopy, ICollection<PdfIndirectReference> fromOcgsToCopy, PdfDictionary fromDict, PdfDictionary toDict, PdfDocument toDocument) { if (fromDict.GetAsArray(fieldToCopy) == null) { return; } PdfArray fromArray = fromDict.GetAsArray(fieldToCopy); if (toDict.GetAsArray(fieldToCopy) == null) { toDict.Put(fieldToCopy, new PdfArray()); } PdfArray toArray = toDict.GetAsArray(fieldToCopy); ICollection<PdfIndirectReference> toOcgsToCopy = new HashSet<PdfIndirectReference>(); foreach (PdfIndirectReference fromRef in fromOcgsToCopy) { toOcgsToCopy.Add(fromRef.GetRefersTo().CopyTo(toDocument, false).GetIndirectReference()); } if (PdfName.Order.Equals(fieldToCopy)) { // Stage 1: delete all Order the entire branches from the output document in which the copied OCGs were IList<int> removeIndex = new List<int>(); for (int i = 0; i < toArray.Size(); i++) { PdfObject toOrderItem = toArray.Get(i); if (iText.Kernel.Pdf.OcgPropertiesCopier.OrderBranchContainsSetElements(toOrderItem, toArray, i, toOcgsToCopy , null, null)) { removeIndex.Add(i); } } for (int i = removeIndex.Count - 1; i > -1; i--) { toArray.Remove(removeIndex[i]); } PdfArray toOcgs = toDocument.GetCatalog().GetPdfObject().GetAsDictionary(PdfName.OCProperties).GetAsArray( PdfName.OCGs); // Stage 2: copy all the Order the entire branches in which the copied OСGs were for (int i = 0; i < fromArray.Size(); i++) { PdfObject fromOrderItem = fromArray.Get(i); if (iText.Kernel.Pdf.OcgPropertiesCopier.OrderBranchContainsSetElements(fromOrderItem, fromArray, i, fromOcgsToCopy , toOcgs, toDocument)) { toArray.Add(fromOrderItem.CopyTo(toDocument, false)); } } } else { // Stage 3: remove from Order OCGs not presented in the output document. When forming // the Order dictionary in the PdfOcProperties constructor, only those OCGs that are // in the OCProperties/OCGs array will be taken into account if (PdfName.RBGroups.Equals(fieldToCopy)) { // Stage 1: delete all RBGroups from the output document in which the copied OCGs were for (int i = toArray.Size() - 1; i > -1; i--) { PdfArray toRbGroup = (PdfArray)toArray.Get(i); foreach (PdfObject toRbGroupItemObj in toRbGroup) { if (toOcgsToCopy.Contains(toRbGroupItemObj.GetIndirectReference())) { toArray.Remove(i); break; } } } // Stage 2: copy all the RBGroups in which the copied OCGs were foreach (PdfObject fromRbGroupObj in fromArray) { PdfArray fromRbGroup = (PdfArray)fromRbGroupObj; foreach (PdfObject fromRbGroupItemObj in fromRbGroup) { if (fromOcgsToCopy.Contains(fromRbGroupItemObj.GetIndirectReference())) { toArray.Add(fromRbGroup.CopyTo(toDocument, false)); break; } } } } else { // Stage 3: remove from RBGroups OCGs not presented in the output // document (is in the PdfOcProperties#fillDictionary method) foreach (PdfObject fromObj in fromArray) { iText.Kernel.Pdf.OcgPropertiesCopier.AttemptToAddObjectToArray(fromOcgsToCopy, fromObj, toArray, toDocument ); } } } if (toArray.IsEmpty()) { toDict.Remove(fieldToCopy); } }
/// <summary>Writes cross reference table and trailer to PDF.</summary> protected internal virtual void WriteXrefTableAndTrailer(PdfDocument document, PdfObject fileId, PdfObject crypto) { PdfWriter writer = document.GetWriter(); if (!document.properties.appendMode) { for (int i = count; i > 0; --i) { PdfIndirectReference lastRef = xref[i]; if (lastRef == null || lastRef.IsFree()) { RemoveFreeRefFromList(i); --count; } else { break; } } } PdfStream xrefStream = null; if (writer.IsFullCompression()) { xrefStream = new PdfStream(); xrefStream.MakeIndirect(document); } IList <int> sections = CreateSections(document, false); bool noModifiedObjects = (sections.Count == 0) || (xrefStream != null && sections.Count == 2 && sections[0 ] == count && sections[1] == 1); if (document.properties.appendMode && noModifiedObjects) { // No modifications in document xref = null; return; } long startxref = writer.GetCurrentPos(); long xRefStmPos = -1; if (xrefStream != null) { xrefStream.Put(PdfName.Type, PdfName.XRef); xrefStream.Put(PdfName.ID, fileId); if (crypto != null) { xrefStream.Put(PdfName.Encrypt, crypto); } xrefStream.Put(PdfName.Size, new PdfNumber(this.Size())); int offsetSize = GetOffsetSize(Math.Max(startxref, Size())); xrefStream.Put(PdfName.W, new PdfArray(JavaUtil.ArraysAsList((PdfObject) new PdfNumber(1), new PdfNumber(offsetSize ), new PdfNumber(2)))); xrefStream.Put(PdfName.Info, document.GetDocumentInfo().GetPdfObject()); xrefStream.Put(PdfName.Root, document.GetCatalog().GetPdfObject()); PdfArray index = new PdfArray(); foreach (int?section in sections) { index.Add(new PdfNumber((int)section)); } if (document.properties.appendMode && !document.reader.hybridXref) { // "not meaningful in hybrid-reference files" PdfNumber lastXref = new PdfNumber(document.reader.GetLastXref()); xrefStream.Put(PdfName.Prev, lastXref); } xrefStream.Put(PdfName.Index, index); xrefStream.GetIndirectReference().SetOffset(startxref); iText.Kernel.Pdf.PdfXrefTable xrefTable = document.GetXref(); for (int k = 0; k < sections.Count; k += 2) { int first = (int)sections[k]; int len = (int)sections[k + 1]; for (int i = first; i < first + len; i++) { PdfIndirectReference reference = xrefTable.Get(i); if (reference.IsFree()) { xrefStream.GetOutputStream().Write(0); xrefStream.GetOutputStream().Write(reference.GetOffset(), offsetSize); xrefStream.GetOutputStream().Write(reference.GetGenNumber(), 2); } else { if (reference.GetObjStreamNumber() == 0) { xrefStream.GetOutputStream().Write(1); xrefStream.GetOutputStream().Write(reference.GetOffset(), offsetSize); xrefStream.GetOutputStream().Write(reference.GetGenNumber(), 2); } else { xrefStream.GetOutputStream().Write(2); xrefStream.GetOutputStream().Write(reference.GetObjStreamNumber(), offsetSize); xrefStream.GetOutputStream().Write(reference.GetIndex(), 2); } } } } xrefStream.Flush(); xRefStmPos = startxref; } // For documents with hybrid cross-reference table, i.e. containing xref streams as well as regular xref sections, // we write additional regular xref section at the end of the document because the /Prev reference from // xref stream to a regular xref section doesn't seem to be valid bool needsRegularXref = !writer.IsFullCompression() || (document.properties.appendMode && document.reader. hybridXref); if (needsRegularXref) { startxref = writer.GetCurrentPos(); writer.WriteString("xref\n"); iText.Kernel.Pdf.PdfXrefTable xrefTable = document.GetXref(); if (xRefStmPos != -1) { // Get rid of all objects from object stream. This is done for hybrid documents sections = CreateSections(document, true); } for (int k = 0; k < sections.Count; k += 2) { int first = (int)sections[k]; int len = (int)sections[k + 1]; writer.WriteInteger(first).WriteSpace().WriteInteger(len).WriteByte((byte)'\n'); for (int i = first; i < first + len; i++) { PdfIndirectReference reference = xrefTable.Get(i); StringBuilder off = new StringBuilder("0000000000").Append(reference.GetOffset()); StringBuilder gen = new StringBuilder("00000").Append(reference.GetGenNumber()); writer.WriteString(off.JSubstring(off.Length - 10, off.Length)).WriteSpace().WriteString(gen.JSubstring(gen .Length - 5, gen.Length)).WriteSpace(); if (reference.IsFree()) { writer.WriteBytes(freeXRefEntry); } else { writer.WriteBytes(inUseXRefEntry); } } } PdfDictionary trailer = document.GetTrailer(); // Remove all unused keys in case stamp mode in case original file has full compression, but destination file has not. trailer.Remove(PdfName.W); trailer.Remove(PdfName.Index); trailer.Remove(PdfName.Type); trailer.Remove(PdfName.Length); trailer.Put(PdfName.Size, new PdfNumber(this.Size())); trailer.Put(PdfName.ID, fileId); if (xRefStmPos != -1) { trailer.Put(PdfName.XRefStm, new PdfNumber(xRefStmPos)); } if (crypto != null) { trailer.Put(PdfName.Encrypt, crypto); } writer.WriteString("trailer\n"); if (document.properties.appendMode) { PdfNumber lastXref = new PdfNumber(document.reader.GetLastXref()); trailer.Put(PdfName.Prev, lastXref); } writer.Write(document.GetTrailer()); writer.Write('\n'); } WriteKeyInfo(document); writer.WriteString("startxref\n").WriteLong(startxref).WriteString("\n%%EOF\n"); xref = null; freeReferencesLinkedList.Clear(); }
/// <summary>Writes cross reference table and trailer to PDF.</summary> /// <exception cref="System.IO.IOException"/> protected internal virtual void WriteXrefTableAndTrailer(PdfDocument document, PdfObject fileId, PdfObject crypto) { PdfWriter writer = document.GetWriter(); if (!document.properties.appendMode) { for (int i = count; i > 0; --i) { PdfIndirectReference lastRef = xref[i]; if (lastRef == null || lastRef.IsFree()) { RemoveFreeRefFromList(i); --count; } else { break; } } } IList <int> sections = new List <int>(); int first = 0; int len = 0; for (int i = 0; i < Size(); i++) { PdfIndirectReference reference = xref[i]; if (document.properties.appendMode && reference != null && !reference.CheckState(PdfObject.MODIFIED)) { reference = null; } if (reference == null) { if (len > 0) { sections.Add(first); sections.Add(len); } len = 0; } else { if (len > 0) { len++; } else { first = i; len = 1; } } } if (len > 0) { sections.Add(first); sections.Add(len); } if (document.properties.appendMode && sections.Count == 0) { // no modifications. xref = null; return; } long startxref = writer.GetCurrentPos(); if (writer.IsFullCompression()) { PdfStream xrefStream = (PdfStream) new PdfStream().MakeIndirect(document); xrefStream.MakeIndirect(document); xrefStream.Put(PdfName.Type, PdfName.XRef); xrefStream.Put(PdfName.ID, fileId); if (crypto != null) { xrefStream.Put(PdfName.Encrypt, crypto); } xrefStream.Put(PdfName.Size, new PdfNumber(this.Size())); int offsetSize = GetOffsetSize(Math.Max(startxref, Size())); xrefStream.Put(PdfName.W, new PdfArray(JavaUtil.ArraysAsList((PdfObject) new PdfNumber(1), new PdfNumber(offsetSize ), new PdfNumber(2)))); xrefStream.Put(PdfName.Info, document.GetDocumentInfo().GetPdfObject()); xrefStream.Put(PdfName.Root, document.GetCatalog().GetPdfObject()); PdfArray index = new PdfArray(); foreach (int?section in sections) { index.Add(new PdfNumber((int)section)); } if (document.properties.appendMode) { PdfNumber lastXref = new PdfNumber(document.reader.GetLastXref()); xrefStream.Put(PdfName.Prev, lastXref); } xrefStream.Put(PdfName.Index, index); iText.Kernel.Pdf.PdfXrefTable xrefTable = document.GetXref(); for (int k = 0; k < sections.Count; k += 2) { first = (int)sections[k]; len = (int)sections[k + 1]; for (int i = first; i < first + len; i++) { PdfIndirectReference reference = xrefTable.Get(i); if (reference.IsFree()) { xrefStream.GetOutputStream().Write(0); xrefStream.GetOutputStream().Write(reference.GetOffset(), offsetSize); xrefStream.GetOutputStream().Write(reference.GetGenNumber(), 2); } else { if (reference.GetObjStreamNumber() == 0) { xrefStream.GetOutputStream().Write(1); xrefStream.GetOutputStream().Write(reference.GetOffset(), offsetSize); xrefStream.GetOutputStream().Write(reference.GetGenNumber(), 2); } else { xrefStream.GetOutputStream().Write(2); xrefStream.GetOutputStream().Write(reference.GetObjStreamNumber(), offsetSize); xrefStream.GetOutputStream().Write(reference.GetIndex(), 2); } } } } xrefStream.Flush(); } else { writer.WriteString("xref\n"); iText.Kernel.Pdf.PdfXrefTable xrefTable = document.GetXref(); for (int k = 0; k < sections.Count; k += 2) { first = (int)sections[k]; len = (int)sections[k + 1]; writer.WriteInteger(first).WriteSpace().WriteInteger(len).WriteByte((byte)'\n'); for (int i = first; i < first + len; i++) { PdfIndirectReference reference = xrefTable.Get(i); StringBuilder off = new StringBuilder("0000000000").Append(reference.GetOffset()); StringBuilder gen = new StringBuilder("00000").Append(reference.GetGenNumber()); writer.WriteString(off.JSubstring(off.Length - 10, off.Length)).WriteSpace().WriteString(gen.JSubstring(gen .Length - 5, gen.Length)).WriteSpace(); if (reference.IsFree()) { writer.WriteBytes(freeXRefEntry); } else { writer.WriteBytes(inUseXRefEntry); } } } PdfDictionary trailer = document.GetTrailer(); // Remove all unused keys in case stamp mode in case original file has full compression, but destination file has not. trailer.Remove(PdfName.W); trailer.Remove(PdfName.Index); trailer.Remove(PdfName.Type); trailer.Remove(PdfName.Length); trailer.Put(PdfName.Size, new PdfNumber(this.Size())); trailer.Put(PdfName.ID, fileId); if (crypto != null) { trailer.Put(PdfName.Encrypt, crypto); } writer.WriteString("trailer\n"); if (document.properties.appendMode) { PdfNumber lastXref = new PdfNumber(document.reader.GetLastXref()); trailer.Put(PdfName.Prev, lastXref); } writer.Write(document.GetTrailer()); writer.Write('\n'); } WriteKeyInfo(document); writer.WriteString("startxref\n").WriteLong(startxref).WriteString("\n%%EOF\n"); xref = null; freeReferencesLinkedList.Clear(); }
/// <summary>Build a PdfDictionary containing the name tree</summary> /// <returns>PdfDictionary containing the name tree</returns> public virtual PdfDictionary BuildTree() { String[] names = new String[items.Count]; names = items.Keys.ToArray(names); JavaUtil.Sort(names); if (names.Length <= NODE_SIZE) { PdfDictionary dic = new PdfDictionary(); PdfArray ar = new PdfArray(); foreach (String name in names) { ar.Add(new PdfString(name, null)); ar.Add(items.Get(name)); } dic.Put(PdfName.Names, ar); return(dic); } int skip = NODE_SIZE; PdfDictionary[] kids = new PdfDictionary[(names.Length + NODE_SIZE - 1) / NODE_SIZE]; for (int k = 0; k < kids.Length; ++k) { int offset = k * NODE_SIZE; int end = Math.Min(offset + NODE_SIZE, names.Length); PdfDictionary dic = new PdfDictionary(); PdfArray arr = new PdfArray(); arr.Add(new PdfString(names[offset], null)); arr.Add(new PdfString(names[end - 1], null)); dic.Put(PdfName.Limits, arr); arr = new PdfArray(); for (; offset < end; ++offset) { arr.Add(new PdfString(names[offset], null)); arr.Add(items.Get(names[offset])); } dic.Put(PdfName.Names, arr); dic.MakeIndirect(catalog.GetDocument()); kids[k] = dic; } int top = kids.Length; while (true) { if (top <= NODE_SIZE) { PdfArray arr = new PdfArray(); for (int i = 0; i < top; ++i) { arr.Add(kids[i]); } PdfDictionary dic = new PdfDictionary(); dic.Put(PdfName.Kids, arr); return(dic); } skip *= NODE_SIZE; int tt = (names.Length + skip - 1) / skip; for (int i = 0; i < tt; ++i) { int offset = i * NODE_SIZE; int end = Math.Min(offset + NODE_SIZE, top); PdfDictionary dic = (PdfDictionary) new PdfDictionary().MakeIndirect(catalog.GetDocument()); PdfArray arr = new PdfArray(); arr.Add(new PdfString(names[i * skip], null)); arr.Add(new PdfString(names[Math.Min((i + 1) * skip, names.Length) - 1], null)); dic.Put(PdfName.Limits, arr); arr = new PdfArray(); for (; offset < end; ++offset) { arr.Add(kids[offset]); } dic.Put(PdfName.Kids, arr); kids[i] = dic; } top = tt; } }
public virtual PdfDictionary BuildTree() { int?[] numbers = new int?[items.Count]; numbers = items.Keys.ToArray(numbers); iText.IO.Util.JavaUtil.Sort(numbers); if (numbers.Length <= NODE_SIZE) { PdfDictionary dic = new PdfDictionary(); PdfArray ar = new PdfArray(); for (int k = 0; k < numbers.Length; ++k) { ar.Add(new PdfNumber((int)numbers[k])); ar.Add(items.Get(numbers[k])); } dic.Put(PdfName.Nums, ar); return(dic); } int skip = NODE_SIZE; PdfDictionary[] kids = new PdfDictionary[(numbers.Length + NODE_SIZE - 1) / NODE_SIZE]; for (int i = 0; i < kids.Length; ++i) { int offset = i * NODE_SIZE; int end = Math.Min(offset + NODE_SIZE, numbers.Length); PdfDictionary dic = new PdfDictionary(); PdfArray arr = new PdfArray(); arr.Add(new PdfNumber((int)numbers[offset])); arr.Add(new PdfNumber((int)numbers[end - 1])); dic.Put(PdfName.Limits, arr); arr = new PdfArray(); for (; offset < end; ++offset) { arr.Add(new PdfNumber((int)numbers[offset])); arr.Add(items.Get(numbers[offset])); } dic.Put(PdfName.Nums, arr); dic.MakeIndirect(catalog.GetDocument()); kids[i] = dic; } int top = kids.Length; while (true) { if (top <= NODE_SIZE) { PdfArray arr = new PdfArray(); for (int k = 0; k < top; ++k) { arr.Add(kids[k]); } PdfDictionary dic = new PdfDictionary(); dic.Put(PdfName.Kids, arr); return(dic); } skip *= NODE_SIZE; int tt = (numbers.Length + skip - 1) / skip; for (int k_1 = 0; k_1 < tt; ++k_1) { int offset = k_1 * NODE_SIZE; int end = Math.Min(offset + NODE_SIZE, top); PdfDictionary dic = ((PdfDictionary) new PdfDictionary().MakeIndirect(catalog.GetDocument())); PdfArray arr = new PdfArray(); arr.Add(new PdfNumber((int)numbers[k_1 * skip])); arr.Add(new PdfNumber((int)numbers[Math.Min((k_1 + 1) * skip, numbers.Length) - 1])); dic.Put(PdfName.Limits, arr); arr = new PdfArray(); for (; offset < end; ++offset) { arr.Add(kids[offset]); } dic.Put(PdfName.Kids, arr); kids[k_1] = dic; } top = tt; } }