git-svn-id: https://pdfsharp.svn.codeplex.com/svn@39620 56d0cb2f-6006-4f69-a5a2-94740...
[pdfsharp:pdfsharp.git] / PDFsharp / code / PdfSharp / PdfSharp.Pdf.Advanced / PdfContents.cs
1 #region PDFsharp - A .NET library for processing PDF\r
2 //\r
3 // Authors:\r
4 //   Stefan Lange (mailto:Stefan.Lange@pdfsharp.com)\r
5 //\r
6 // Copyright (c) 2005-2009 empira Software GmbH, Cologne (Germany)\r
7 //\r
8 // http://www.pdfsharp.com\r
9 // http://sourceforge.net/projects/pdfsharp\r
10 //\r
11 // Permission is hereby granted, free of charge, to any person obtaining a\r
12 // copy of this software and associated documentation files (the "Software"),\r
13 // to deal in the Software without restriction, including without limitation\r
14 // the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
15 // and/or sell copies of the Software, and to permit persons to whom the\r
16 // Software is furnished to do so, subject to the following conditions:\r
17 //\r
18 // The above copyright notice and this permission notice shall be included\r
19 // in all copies or substantial portions of the Software.\r
20 //\r
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
24 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r
26 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \r
27 // DEALINGS IN THE SOFTWARE.\r
28 #endregion\r
29 \r
30 using System;\r
31 using System.Diagnostics;\r
32 using System.Collections;\r
33 using System.Text;\r
34 using System.IO;\r
35 using PdfSharp.Drawing;\r
36 using PdfSharp.Drawing.Pdf;\r
37 using PdfSharp.Pdf;\r
38 using PdfSharp.Pdf.Internal;\r
39 using PdfSharp.Pdf.Filters;\r
40 using PdfSharp.Pdf.IO;\r
41 \r
42 namespace PdfSharp.Pdf.Advanced\r
43 {\r
44   /// <summary>\r
45   /// Represents an array of PDF content streams of a page.\r
46   /// </summary>\r
47   public sealed class PdfContents : PdfArray\r
48   {\r
49     /// <summary>\r
50     /// Initializes a new instance of the <see cref="PdfContents"/> class.\r
51     /// </summary>\r
52     /// <param name="document">The document.</param>\r
53     public PdfContents(PdfDocument document)\r
54       : base(document)\r
55     {\r
56     }\r
57 \r
58     internal PdfContents(PdfArray array)\r
59       : base(array)\r
60     {\r
61       int count = Elements.Count;\r
62       for (int idx = 0; idx < count; idx++)\r
63       {\r
64         // Convert the references from PdfDictionary to PdfContent\r
65         PdfItem item = Elements[idx];\r
66         PdfReference iref = item as PdfReference;\r
67         if (iref != null && iref.Value is PdfDictionary)\r
68         {\r
69           // The following line is correct!\r
70           new PdfContent((PdfDictionary)iref.Value);\r
71         }\r
72         else\r
73           throw new InvalidOperationException("Unexpected item in a content stream array.");\r
74       }\r
75     }\r
76 \r
77     /// <summary>\r
78     /// Appends a new content stream and returns it.\r
79     /// </summary>\r
80     public PdfContent AppendContent()\r
81     {\r
82       Debug.Assert(this.Owner != null);\r
83 \r
84       SetModified();\r
85       PdfContent content = new PdfContent(this.Owner);\r
86       Owner.irefTable.Add(content);\r
87       Debug.Assert(content.Reference != null);\r
88       Elements.Add(content.Reference);\r
89       return content;\r
90     }\r
91 \r
92     /// <summary>\r
93     /// Prepends a new content stream and returns it.\r
94     /// </summary>\r
95     public PdfContent PrependContent()\r
96     {\r
97       Debug.Assert(this.Owner != null);\r
98 \r
99       SetModified();\r
100       PdfContent content = new PdfContent(this.Owner);\r
101       Owner.irefTable.Add(content);\r
102       Debug.Assert(content.Reference != null);\r
103       Elements.Insert(0, content.Reference);\r
104       return content;\r
105     }\r
106 \r
107     /// <summary>\r
108     /// Creates a single content stream with the bytes from the array of the content streams.\r
109     /// This operation does not modify any of the content streams in this array.\r
110     /// </summary>\r
111     public PdfContent CreateSingleContent()\r
112     {\r
113       byte[] bytes = new byte[0];\r
114       byte[] bytes1;\r
115       byte[] bytes2;\r
116       foreach (PdfItem iref in Elements)\r
117       {\r
118         PdfDictionary cont = (PdfDictionary)((PdfReference)iref).Value;\r
119         bytes1 = bytes;\r
120         bytes2 = cont.Stream.UnfilteredValue;\r
121         bytes = new byte[bytes1.Length + bytes2.Length + 1];\r
122         bytes1.CopyTo(bytes, 0);\r
123         bytes[bytes1.Length] = (byte)'\n';\r
124         bytes2.CopyTo(bytes, bytes1.Length + 1);\r
125       }\r
126       PdfContent content = new PdfContent(this.Owner);\r
127       content.Stream = new PdfDictionary.PdfStream(bytes, content);\r
128       return content;\r
129     }\r
130 \r
131     void SetModified()\r
132     {\r
133       if (!this.modified)\r
134       {\r
135         this.modified = true;\r
136         int count = Elements.Count;\r
137 \r
138         if (count == 1)\r
139         {\r
140           PdfContent content = (PdfContent)((PdfReference)Elements[0]).Value;\r
141           content.PreserveGraphicsState();\r
142         }\r
143         else if (count > 1)\r
144         {\r
145           // Surround content streams with q/Q operations\r
146           byte[] value;\r
147           int length;\r
148           PdfContent content = (PdfContent)((PdfReference)Elements[0]).Value;\r
149           if (content != null && content.Stream != null)\r
150           {\r
151             length = content.Stream.Length;\r
152             value = new byte[length + 2];\r
153             value[0] = (byte)'q';\r
154             value[1] = (byte)'\n';\r
155             Array.Copy(content.Stream.Value, 0, value, 2, length);\r
156             content.Stream.Value = value;\r
157             content.Elements.SetInteger("/Length", length + 2);\r
158           }\r
159           content = (PdfContent)((PdfReference)Elements[count - 1]).Value;\r
160           if (content != null && content.Stream != null)\r
161           {\r
162             length = content.Stream.Length;\r
163             value = new byte[length + 3];\r
164             Array.Copy(content.Stream.Value, 0, value, 0, length);\r
165             value[length] = (byte)' ';\r
166             value[length + 1] = (byte)'Q';\r
167             value[length + 2] = (byte)'\n';\r
168             content.Stream.Value = value;\r
169             content.Elements.SetInteger("/Length", length + 3);\r
170           }\r
171         }\r
172       }\r
173     }\r
174     bool modified;\r
175 \r
176     internal override void WriteObject(PdfWriter writer)\r
177     {\r
178       // Save two bytes in PDF stream...\r
179       if (Elements.Count == 1)\r
180         Elements[0].WriteObject(writer);\r
181       else\r
182         base.WriteObject(writer);\r
183     }\r
184   }\r
185 }\r