#region PDFsharp - A .NET library for processing PDF // // Authors: // Stefan Lange // // Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany) // // http://www.pdfsharp.com // http://sourceforge.net/projects/pdfsharp // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. #endregion using System; using System.Collections.Generic; using System.Diagnostics; using System.Collections; using PdfSharp.Pdf.Content.Objects; using PdfSharp.Pdf.IO; namespace PdfSharp.Pdf.Advanced { /// /// Represents an array of PDF content streams of a page. /// public sealed class PdfContents : PdfArray { /// /// Initializes a new instance of the class. /// /// The document. public PdfContents(PdfDocument document) : base(document) { } internal PdfContents(PdfArray array) : base(array) { int count = Elements.Count; for (int idx = 0; idx < count; idx++) { // Convert the references from PdfDictionary to PdfContent PdfItem item = Elements[idx]; PdfReference iref = item as PdfReference; if (iref != null && iref.Value is PdfDictionary) { // The following line is correct! new PdfContent((PdfDictionary)iref.Value); } else throw new InvalidOperationException("Unexpected item in a content stream array."); } } /// /// Appends a new content stream and returns it. /// public PdfContent AppendContent() { Debug.Assert(Owner != null); SetModified(); PdfContent content = new PdfContent(Owner); Owner._irefTable.Add(content); Debug.Assert(content.Reference != null); Elements.Add(content.Reference); return content; } /// /// Prepends a new content stream and returns it. /// public PdfContent PrependContent() { Debug.Assert(Owner != null); SetModified(); PdfContent content = new PdfContent(Owner); Owner._irefTable.Add(content); Debug.Assert(content.Reference != null); Elements.Insert(0, content.Reference); return content; } /// /// Creates a single content stream with the bytes from the array of the content streams. /// This operation does not modify any of the content streams in this array. /// public PdfContent CreateSingleContent() { byte[] bytes = new byte[0]; byte[] bytes1; byte[] bytes2; foreach (PdfItem iref in Elements) { PdfDictionary cont = (PdfDictionary)((PdfReference)iref).Value; bytes1 = bytes; bytes2 = cont.Stream.UnfilteredValue; bytes = new byte[bytes1.Length + bytes2.Length + 1]; bytes1.CopyTo(bytes, 0); bytes[bytes1.Length] = (byte)'\n'; bytes2.CopyTo(bytes, bytes1.Length + 1); } PdfContent content = new PdfContent(Owner); content.Stream = new PdfDictionary.PdfStream(bytes, content); return content; } /// /// Replaces the current content of the page with the specified content sequence. /// public PdfContent ReplaceContent(CSequence cseq) { if (cseq == null) throw new ArgumentNullException(nameof(cseq)); return ReplaceContent(cseq.ToContent()); } /// /// Replaces the current content of the page with the specified bytes. /// PdfContent ReplaceContent(byte[] contentBytes) { Debug.Assert(Owner != null); PdfContent content = new PdfContent(Owner); content.CreateStream(contentBytes); Owner._irefTable.Add(content); Elements.Clear(); Elements.Add(content.Reference); return content; } void SetModified() { if (!_modified) { _modified = true; int count = Elements.Count; if (count == 1) { PdfContent content = (PdfContent)((PdfReference)Elements[0]).Value; content.PreserveGraphicsState(); } else if (count > 1) { // Surround content streams with q/Q operations byte[] value; int length; PdfContent content = (PdfContent)((PdfReference)Elements[0]).Value; if (content != null && content.Stream != null) { length = content.Stream.Length; value = new byte[length + 2]; value[0] = (byte)'q'; value[1] = (byte)'\n'; Array.Copy(content.Stream.Value, 0, value, 2, length); content.Stream.Value = value; content.Elements.SetInteger("/Length", length + 2); } content = (PdfContent)((PdfReference)Elements[count - 1]).Value; if (content != null && content.Stream != null) { length = content.Stream.Length; value = new byte[length + 3]; Array.Copy(content.Stream.Value, 0, value, 0, length); value[length] = (byte)' '; value[length + 1] = (byte)'Q'; value[length + 2] = (byte)'\n'; content.Stream.Value = value; content.Elements.SetInteger("/Length", length + 3); } } } } bool _modified; internal override void WriteObject(PdfWriter writer) { // Save two bytes in PDF stream... if (Elements.Count == 1) Elements[0].WriteObject(writer); else base.WriteObject(writer); } /// /// Gets the enumerator. /// public new IEnumerator GetEnumerator() { return new PdfPageContentEnumerator(this); } class PdfPageContentEnumerator : IEnumerator { internal PdfPageContentEnumerator(PdfContents list) { _contents = list; _index = -1; } public bool MoveNext() { if (_index < _contents.Elements.Count - 1) { _index++; _currentElement = (PdfContent)((PdfReference)_contents.Elements[_index]).Value; return true; } _index = _contents.Elements.Count; return false; } public void Reset() { _currentElement = null; _index = -1; } object IEnumerator.Current { get { return Current; } } public PdfContent Current { get { if (_index == -1 || _index >= _contents.Elements.Count) throw new InvalidOperationException(PSSR.ListEnumCurrentOutOfRange); return _currentElement; } } public void Dispose() { // Nothing to do. } PdfContent _currentElement; int _index; readonly PdfContents _contents; } } }