git-svn-id: https://pdfsharp.svn.codeplex.com/svn@39620 56d0cb2f-6006-4f69-a5a2-94740...
[pdfsharp:pdfsharp.git] / PDFsharp / code / PdfSharp / PdfSharp.Pdf.Advanced / PdfShading.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.Globalization;\r
33 using System.Collections;\r
34 using System.Text;\r
35 using System.IO;\r
36 #if GDI\r
37 using System.Drawing;\r
38 using System.Drawing.Imaging;\r
39 #endif\r
40 #if WPF\r
41 using System.Windows.Media;\r
42 #endif\r
43 using PdfSharp.Drawing;\r
44 using PdfSharp.Fonts.OpenType;\r
45 using PdfSharp.Internal;\r
46 using PdfSharp.Pdf.Internal;\r
47 \r
48 namespace PdfSharp.Pdf.Advanced\r
49 {\r
50   /// <summary>\r
51   /// Represents a shading dictionary.\r
52   /// </summary>\r
53   public sealed class PdfShading : PdfDictionary\r
54   {\r
55     /// <summary>\r
56     /// Initializes a new instance of the <see cref="PdfShading"/> class.\r
57     /// </summary>\r
58     public PdfShading(PdfDocument document)\r
59       : base(document)\r
60     { }\r
61 \r
62     /// <summary>\r
63     /// Setups the shading from the specified brush.\r
64     /// </summary>\r
65     public void SetupFromBrush(XLinearGradientBrush brush)\r
66     {\r
67       if (brush == null)\r
68         throw new ArgumentNullException("brush");\r
69 \r
70       PdfColorMode colorMode = this.document.Options.ColorMode;\r
71       XColor color1 = ColorSpaceHelper.EnsureColorMode(colorMode, brush.color1);\r
72       XColor color2 = ColorSpaceHelper.EnsureColorMode(colorMode, brush.color2);\r
73 \r
74       PdfDictionary function = new PdfDictionary();\r
75 \r
76       Elements[Keys.ShadingType] = new PdfInteger(2);\r
77       if (colorMode != PdfColorMode.Cmyk)\r
78         Elements[Keys.ColorSpace] = new PdfName("/DeviceRGB");\r
79       else\r
80         Elements[Keys.ColorSpace] = new PdfName("/DeviceCMYK");\r
81 \r
82       double x1 = 0, y1 = 0, x2 = 0, y2 = 0;\r
83       if (brush.useRect)\r
84       {\r
85         switch (brush.linearGradientMode)\r
86         {\r
87           case XLinearGradientMode.Horizontal:\r
88             x1 = brush.rect.x;\r
89             y1 = brush.rect.y;\r
90             x2 = brush.rect.x + brush.rect.width;\r
91             y2 = brush.rect.y;\r
92             break;\r
93 \r
94           case XLinearGradientMode.Vertical:\r
95             x1 = brush.rect.x;\r
96             y1 = brush.rect.y;\r
97             x2 = brush.rect.x;\r
98             y2 = brush.rect.y + brush.rect.height;\r
99             break;\r
100 \r
101           case XLinearGradientMode.ForwardDiagonal:\r
102             x1 = brush.rect.x;\r
103             y1 = brush.rect.y;\r
104             x2 = brush.rect.x + brush.rect.width;\r
105             y2 = brush.rect.y + brush.rect.height;\r
106             break;\r
107 \r
108           case XLinearGradientMode.BackwardDiagonal:\r
109             x1 = brush.rect.x + brush.rect.width;\r
110             y1 = brush.rect.y;\r
111             x2 = brush.rect.x;\r
112             y2 = brush.rect.y + brush.rect.height;\r
113             break;\r
114         }\r
115       }\r
116       else\r
117       {\r
118         x1 = brush.point1.x;\r
119         y1 = brush.point1.y;\r
120         x2 = brush.point2.x;\r
121         y2 = brush.point2.y;\r
122       }\r
123       Elements[Keys.Coords] = new PdfLiteral("[{0:0.###} {1:0.###} {2:0.###} {3:0.###}]", x1, y1, x2, y2);\r
124 \r
125       //Elements[Keys.Background] = new PdfRawItem("[0 1 1]");\r
126       //Elements[Keys.Domain] = \r
127       Elements[Keys.Function] = function;\r
128       //Elements[Keys.Extend] = new PdfRawItem("[true true]");\r
129 \r
130       string clr1 = "[" + PdfEncoders.ToString(color1, colorMode) + "]";\r
131       string clr2 = "[" + PdfEncoders.ToString(color2, colorMode) + "]";\r
132 \r
133       function.Elements["/FunctionType"] = new PdfInteger(2);\r
134       function.Elements["/C0"] = new PdfLiteral(clr1);\r
135       function.Elements["/C1"] = new PdfLiteral(clr2);\r
136       function.Elements["/Domain"] = new PdfLiteral("[0 1]");\r
137       function.Elements["/N"] = new PdfInteger(1);\r
138     }\r
139 \r
140     /// <summary>\r
141     /// Common keys for all streams.\r
142     /// </summary>\r
143     internal sealed class Keys : KeysBase\r
144     {\r
145       /// <summary>\r
146       /// (Required) The shading type:\r
147       /// 1 Function-based shading\r
148       /// 2 Axial shading\r
149       /// 3 Radial shading\r
150       /// 4 Free-form Gouraud-shaded triangle mesh\r
151       /// 5 Lattice-form Gouraud-shaded triangle mesh\r
152       /// 6 Coons patch mesh\r
153       /// 7 Tensor-product patch mesh\r
154       /// </summary>\r
155       [KeyInfo(KeyType.Integer | KeyType.Required)]\r
156       public const string ShadingType = "/ShadingType";\r
157 \r
158       /// <summary>\r
159       /// (Required) The color space in which color values are expressed. This may be any device, \r
160       /// CIE-based, or special color space except a Pattern space.\r
161       /// </summary>\r
162       [KeyInfo(KeyType.NameOrArray | KeyType.Required)]\r
163       public const string ColorSpace = "/ColorSpace";\r
164 \r
165       /// <summary>\r
166       /// (Optional) An array of color components appropriate to the color space, specifying\r
167       /// a single background color value. If present, this color is used, before any painting \r
168       /// operation involving the shading, to fill those portions of the area to be painted \r
169       /// that lie outside the bounds of the shading object. In the opaque imaging model, \r
170       /// the effect is as if the painting operation were performed twice: first with the \r
171       /// background color and then with the shading.\r
172       /// </summary>\r
173       [KeyInfo(KeyType.Array | KeyType.Optional)]\r
174       public const string Background = "/Background";\r
175 \r
176       /// <summary>\r
177       /// (Optional) An array of four numbers giving the left, bottom, right, and top coordinates, \r
178       /// respectively, of the shading\92s bounding box. The coordinates are interpreted in the \r
179       /// shading\92s target coordinate space. If present, this bounding box is applied as a temporary \r
180       /// clipping boundary when the shading is painted, in addition to the current clipping path\r
181       /// and any other clipping boundaries in effect at that time.\r
182       /// </summary>\r
183       [KeyInfo(KeyType.Rectangle | KeyType.Optional)]\r
184       public const string BBox = "/BBox";\r
185 \r
186       /// <summary>\r
187       /// (Optional) A flag indicating whether to filter the shading function to prevent aliasing \r
188       /// artifacts. The shading operators sample shading functions at a rate determined by the \r
189       /// resolution of the output device. Aliasing can occur if the function is not smooth\97that\r
190       /// is, if it has a high spatial frequency relative to the sampling rate. Anti-aliasing can\r
191       /// be computationally expensive and is usually unnecessary, since most shading functions\r
192       /// are smooth enough or are sampled at a high enough frequency to avoid aliasing effects.\r
193       /// Anti-aliasing may not be implemented on some output devices, in which case this flag\r
194       /// is ignored.\r
195       /// Default value: false.\r
196       /// </summary>\r
197       [KeyInfo(KeyType.Boolean | KeyType.Optional)]\r
198       public const string AntiAlias = "/AntiAlias";\r
199 \r
200 \r
201       // ---- Type 2 ----------------------------------------------------------\r
202 \r
203       /// <summary>\r
204       /// (Required) An array of four numbers [x0 y0 x1 y1] specifying the starting and\r
205       /// ending coordinates of the axis, expressed in the shading\92s target coordinate space.\r
206       /// </summary>\r
207       [KeyInfo(KeyType.Array | KeyType.Required)]\r
208       public const string Coords = "/Coords";\r
209 \r
210       /// <summary>\r
211       /// (Optional) An array of two numbers [t0 t1] specifying the limiting values of a\r
212       /// parametric variable t. The variable is considered to vary linearly between these\r
213       /// two values as the color gradient varies between the starting and ending points of\r
214       /// the axis. The variable t becomes the input argument to the color function(s).\r
215       /// Default value: [0.0 1.0].\r
216       /// </summary>\r
217       [KeyInfo(KeyType.Array | KeyType.Optional)]\r
218       public const string Domain = "/Domain";\r
219 \r
220       /// <summary>\r
221       /// (Required) A 1-in, n-out function or an array of n 1-in, 1-out functions (where n\r
222       /// is the number of color components in the shading dictionary\92s color space). The\r
223       /// function(s) are called with values of the parametric variable t in the domain defined\r
224       /// by the Domain entry. Each function\92s domain must be a superset of that of the shading\r
225       /// dictionary. If the value returned by the function for a given color component is out\r
226       /// of range, it is adjusted to the nearest valid value.\r
227       /// </summary>\r
228       [KeyInfo(KeyType.Function | KeyType.Required)]\r
229       public const string Function = "/Function";\r
230 \r
231       /// <summary>\r
232       /// (Optional) An array of two boolean values specifying whether to extend the shading\r
233       /// beyond the starting and ending points of the axis, respectively.\r
234       /// Default value: [false false].\r
235       /// </summary>\r
236       [KeyInfo(KeyType.Array | KeyType.Optional)]\r
237       public const string Extend = "/Extend";\r
238 \r
239       /// <summary>\r
240       /// Gets the KeysMeta for these keys.\r
241       /// </summary>\r
242       internal static DictionaryMeta Meta\r
243       {\r
244         get\r
245         {\r
246           if (Keys.meta == null)\r
247             Keys.meta = CreateMeta(typeof(Keys));\r
248           return Keys.meta;\r
249         }\r
250       }\r
251       static DictionaryMeta meta;\r
252     }\r
253 \r
254     /// <summary>\r
255     /// Gets the KeysMeta of this dictionary type.\r
256     /// </summary>\r
257     internal override DictionaryMeta Meta\r
258     {\r
259       get { return Keys.Meta; }\r
260     }\r
261   }\r
262 }\r