PDFLayers

Sample C# code to use Apryse SDK for creating and manipulating PDF layers (also known as Optional Content Groups - OCGs). These samples demonstrate how to create and extract layers, as well as to selectively render them (show, hide) in conforming PDF readers or printers. Learn more about our UWP SDK.

1//
2// Copyright (c) 2001-2020 by PDFTron Systems Inc. All Rights Reserved.
3//
4
5using System;
6using System.IO;
7using System.Threading.Tasks;
8using Windows.Foundation;
9
10using pdftron.Common;
11using pdftron.PDF;
12using pdftron.PDF.OCG;
13using pdftron.SDF;
14
15using PDFNetUniversalSamples.ViewModels;
16
17namespace PDFNetSamples
18{
19 public sealed class PDFLayersTest : Sample
20 {
21 public PDFLayersTest() :
22 base("PDFLayers", "This sample demonstrates how to create PDF layers (also known as Optional Content Groups - OCGs). The sample also shows how to extract and render PDF layers.")
23 {
24 }
25
26 public override IAsyncAction RunAsync()
27 {
28 return Task.Run(new System.Action(async () => {
29 WriteLine("--------------------------------");
30 WriteLine("Starting PDFLayers Test...");
31 WriteLine("--------------------------------\n");
32 try
33 {
34 PDFDoc doc = new PDFDoc();
35
36 // Create three layers...
37 Group image_layer = CreateLayer(doc, "Image Layer");
38 Group text_layer = CreateLayer(doc, "Text Layer");
39 Group vector_layer = CreateLayer(doc, "Vector Layer");
40
41 // Start a new page ------------------------------------
42 pdftron.PDF.Page page = doc.PageCreate();
43
44 ElementBuilder builder = new ElementBuilder(); // ElementBuilder is used to build new Element objects
45 ElementWriter writer = new ElementWriter(); // ElementWriter is used to write Elements to the page
46 writer.Begin(page); // begin writing to this page
47
48 // Add new content to the page and associate it with one of the layers.
49 Element element = builder.CreateForm(CreateGroup1(doc, image_layer.GetSDFObj()));
50 writer.WriteElement(element);
51
52 element = builder.CreateForm(CreateGroup2(doc, vector_layer.GetSDFObj()));
53 writer.WriteElement(element);
54
55 // Add the text layer to the page...
56 bool ocmdSample = false; // set to 'true' to enable 'ocmd' example.
57 if (ocmdSample)
58 {
59 // A bit more advanced example of how to create an OCMD text layer that
60 // is visible only if text, image and path layers are all 'ON'.
61 // An example of how to set 'Visibility Policy' in OCMD.
62 Obj ocgs = doc.CreateIndirectArray();
63 ocgs.PushBack(image_layer.GetSDFObj());
64 ocgs.PushBack(vector_layer.GetSDFObj());
65 ocgs.PushBack(text_layer.GetSDFObj());
66 OCMD text_ocmd = OCMD.Create(doc, ocgs, OCMDVisibilityPolicyType.e_AllOn);
67 element = builder.CreateForm(CreateGroup3(doc, text_ocmd.GetSDFObj()));
68 }
69 else {
70 element = builder.CreateForm(CreateGroup3(doc, text_layer.GetSDFObj()));
71 }
72 writer.WriteElement(element);
73
74 // Add some content to the page that does not belong to any layer...
75 // In this case this is a rectangle representing the page border.
76 element = builder.CreateRect(0, 0, page.GetPageWidth(), page.GetPageHeight());
77 element.SetPathFill(false);
78 element.SetPathStroke(true);
79 element.GetGState().SetLineWidth(40);
80 writer.WriteElement(element);
81
82 writer.End(); // save changes to the current page
83 doc.PagePushBack(page);
84
85 // Set the default viewing preference to display 'Layer' tab.
86 PDFDocViewPrefs prefs = doc.GetViewPrefs();
87 prefs.SetPageMode(PDFDocViewPrefsPageMode.e_UseOC);
88
89 string output_file_path = Path.Combine(OutputPath, "pdf_layers.pdf");
90 await doc.SaveAsync(output_file_path, SDFDocSaveOptions.e_linearized);
91 doc.Destroy();
92 WriteLine("Done. Results saved in " + output_file_path);
93 await AddFileToOutputList(output_file_path).ConfigureAwait(false);
94 }
95 catch (Exception e)
96 {
97 WriteLine(GetExceptionMessage(e));
98 }
99
100 // The following is a code snippet shows how to selectively render
101 // and export PDF layers.
102 try
103 {
104 PDFDoc doc = new PDFDoc(Path.Combine(OutputPath, "pdf_layers.pdf"));
105 doc.InitSecurityHandler();
106
107 if (!doc.HasOC())
108 {
109 WriteLine("The document does not contain 'Optional Content'");
110 }
111 else
112 {
113 Config init_cfg = doc.GetOCGConfig();
114 Context ctx = new Context(init_cfg);
115
116 PDFDraw pdfdraw = new PDFDraw();
117 pdfdraw.SetImageSize(1000, 1000);
118 pdfdraw.SetOCGContext(ctx); // Render the page using the given OCG context.
119
120 pdftron.PDF.Page page = doc.GetPage(1); // Get the first page in the document.
121 string output_file_path = Path.Combine(OutputPath, "pdf_layers_default.png");
122 pdfdraw.Export(page, output_file_path);
123 WriteLine("Exporting " + output_file_path);
124 await AddFileToOutputList(output_file_path).ConfigureAwait(false);
125
126 // Disable drawing of content that is not optional (i.e. is not part of any layer).
127 ctx.SetNonOCDrawing(false);
128
129 // Now render each layer in the input document to a separate image.
130 Obj ocgs = doc.GetOCGs(); // Get the array of all OCGs in the document.
131 if (ocgs != null)
132 {
133 int i, sz = ocgs.Size();
134 for (i=0; i<sz; ++i)
135 {
136 Group ocg = new Group(ocgs.GetAt(i));
137 ctx.ResetStates(false);
138 ctx.SetState(ocg, true);
139 string fname = Path.Combine(OutputPath, "pdf_layers_" + ocg.GetName() + ".png");
140 WriteLine(fname);
141 pdfdraw.Export(page, fname);
142 WriteLine("Exporting " + fname);
143 await AddFileToOutputList(fname).ConfigureAwait(false);
144 }
145 }
146
147 // Now draw content that is not part of any layer...
148 ctx.SetNonOCDrawing(true);
149 ctx.SetOCDrawMode(ContextOCDrawMode.e_NoOC);
150 output_file_path = Path.Combine(OutputPath, "pdf_layers_non_oc.png");
151 pdfdraw.Export(page, output_file_path);
152 WriteLine("Exporting " + output_file_path);
153 await AddFileToOutputList(output_file_path).ConfigureAwait(false);
154
155 doc.Destroy();
156 WriteLine("Done.");
157 }
158 }
159 catch (Exception e)
160 {
161 WriteLine(GetExceptionMessage(e));
162 }
163
164 WriteLine("\n--------------------------------");
165 WriteLine("Done PDFLayers Test.");
166 WriteLine("--------------------------------\n");
167 })).AsAsyncAction();
168 }
169
170 // A utility function used to add new Content Groups (Layers) to the document.
171 Group CreateLayer(PDFDoc doc, String layer_name)
172 {
173 Group grp = Group.Create(doc, layer_name);
174 Config cfg = doc.GetOCGConfig();
175 if (cfg == null)
176 {
177 cfg = Config.Create(doc, true);
178 cfg.SetName("Default");
179 }
180
181 // Add the new OCG to the list of layers that should appear in PDF viewer GUI.
182 Obj layer_order_array = cfg.GetOrder();
183 if (layer_order_array == null)
184 {
185 layer_order_array = doc.CreateIndirectArray();
186 cfg.SetOrder(layer_order_array);
187 }
188 layer_order_array.PushBack(grp.GetSDFObj());
189
190 return grp;
191 }
192
193 // Creates some content (3 images) and associate them with the image layer
194 Obj CreateGroup1(PDFDoc doc, Obj layer)
195 {
196 ElementWriter writer = new ElementWriter();
197 writer.Begin(doc.GetSDFDoc());
198
199 // Create an Image that can be reused in the document or on the same page.
200 pdftron.PDF.Image img = pdftron.PDF.Image.Create(doc.GetSDFDoc(), Path.Combine(InputPath, "peppers.jpg"));
201
202 ElementBuilder builder = new ElementBuilder();
203 Element element = builder.CreateImage(img, new Matrix2D(img.GetImageWidth()/2, -145, 20, img.GetImageHeight()/2, 200, 150));
204 writer.WritePlacedElement(element);
205
206 GState gstate = element.GetGState(); // use the same image (just change its matrix)
207 gstate.SetTransform(200, 0, 0, 300, 50, 450);
208 writer.WritePlacedElement(element);
209
210 // use the same image again (just change its matrix).
211 writer.WritePlacedElement(builder.CreateImage(img, 300, 600, 200, -150));
212
213 Obj grp_obj = writer.End();
214
215 // Indicate that this form (content group) belongs to the given layer (OCG).
216 grp_obj.PutName("Subtype","Form");
217 grp_obj.Put("OC", layer);
218 grp_obj.PutRect("BBox", 0, 0, 1000, 1000); // Set the clip box for the content.
219
220 // As an example of further configuration, set the image layer to
221 // be visible on screen, but not visible when printed...
222
223 // The AS entry is an auto state array consisting of one or more usage application
224 // dictionaries that specify how conforming readers shall automatically set the
225 // state of optional content groups based on external factors.
226 Obj cfg = doc.GetOCGConfig().GetSDFObj();
227 Obj auto_state = cfg.FindObj("AS");
228 if (auto_state == null) auto_state = cfg.PutArray("AS");
229 Obj print_state = auto_state.PushBackDict();
230 print_state.PutArray("Category").PushBackName("Print");
231 print_state.PutName("Event", "Print");
232 print_state.PutArray("OCGs").PushBack(layer);
233
234 Obj layer_usage = layer.PutDict("Usage");
235
236 Obj view_setting = layer_usage.PutDict("View");
237 view_setting.PutName("ViewState", "ON");
238
239 Obj print_setting = layer_usage.PutDict("Print");
240 print_setting.PutName("PrintState", "OFF");
241
242 return grp_obj;
243 }
244
245 // Creates some content (a path in the shape of a heart) and associate it with the vector layer
246 static public Obj CreateGroup2(PDFDoc doc, Obj layer)
247 {
248 ElementWriter writer = new ElementWriter();
249 writer.Begin(doc.GetSDFDoc());
250
251 // Create a path object in the shape of a heart.
252 ElementBuilder builder = new ElementBuilder();
253 builder.PathBegin(); // start constructing the path
254 builder.MoveTo(306, 396);
255 builder.CurveTo(681, 771, 399.75, 864.75, 306, 771);
256 builder.CurveTo(212.25, 864.75, -69, 771, 306, 396);
257 builder.ClosePath();
258 Element element = builder.PathEnd(); // the path geometry is now specified.
259
260 // Set the path FILL color space and color.
261 element.SetPathFill(true);
262 GState gstate = element.GetGState();
263 gstate.SetFillColorSpace(ColorSpace.CreateDeviceCMYK());
264 gstate.SetFillColor(new ColorPt(1, 0, 0, 0)); // cyan
265
266 // Set the path STROKE color space and color.
267 element.SetPathStroke(true);
268 gstate.SetStrokeColorSpace(ColorSpace.CreateDeviceRGB());
269 gstate.SetStrokeColor(new ColorPt(1, 0, 0)); // red
270 gstate.SetLineWidth(20);
271
272 gstate.SetTransform(0.5, 0, 0, 0.5, 280, 300);
273
274 writer.WriteElement(element);
275
276 Obj grp_obj = writer.End();
277
278 // Indicate that this form (content group) belongs to the given layer (OCG).
279 grp_obj.PutName("Subtype","Form");
280 grp_obj.Put("OC", layer);
281 grp_obj.PutRect("BBox", 0, 0, 1000, 1000); // Set the clip box for the content.
282
283 return grp_obj;
284 }
285
286 // Creates some text and associate it with the text layer
287 static public Obj CreateGroup3(PDFDoc doc, Obj layer)
288 {
289 ElementWriter writer = new ElementWriter();
290 writer.Begin(doc.GetSDFDoc());
291
292 // Create a path object in the shape of a heart.
293 ElementBuilder builder = new ElementBuilder();
294
295 // Begin writing a block of text
296 Element element = builder.CreateTextBegin(Font.Create(doc.GetSDFDoc(), FontStandardType1Font.e_times_roman), 120);
297 writer.WriteElement(element);
298
299 element = builder.CreateTextRun("A text layer!");
300
301 // Rotate text 45 degrees, than translate 180 pts horizontally and 100 pts vertically.
302 Matrix2D transform = Matrix2D.RotationMatrix(-45 * (3.1415/ 180.0));
303 transform.Concat(1, 0, 0, 1, 180, 100);
304 element.SetTextMatrix(transform);
305
306 writer.WriteElement(element);
307 writer.WriteElement(builder.CreateTextEnd());
308
309 Obj grp_obj = writer.End();
310
311 // Indicate that this form (content group) belongs to the given layer (OCG).
312 grp_obj.PutName("Subtype","Form");
313 grp_obj.Put("OC", layer);
314 grp_obj.PutRect("BBox", 0, 0, 1000, 1000); // Set the clip box for the content.
315
316 return grp_obj;
317 }
318 }
319}

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales