Some test text!

menu
search
chevron_right Xamarin samples

PDF layers (OCG) in C# (Xamarin)

Sample C# (Xamarin) code to use PDFTron 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.

To run this sample, get started with a free trial of PDFTron SDK.

// Generated code. Do not modify!
//
// Copyright (c) 2001-2019 by PDFTron Systems Inc. All Rights Reserved.
//

using System;
using pdftron;
using pdftron.Common;
using pdftron.Filters;
using pdftron.SDF;
using pdftron.PDF;
using pdftron.PDF.OCG;

/// <summary>
//-----------------------------------------------------------------------------------
// This sample demonstrates how to create layers in PDF.
// The sample also shows how to extract and render PDF layers in documents 
// that contain optional content groups (OCGs)
//
// With the introduction of PDF version 1.5 came the concept of Layers. 
// Layers, or as they are more formally known Optional Content Groups (OCGs),
// refer to sections of content in a PDF document that can be selectively 
// viewed or hidden by document authors or consumers. This capability is useful 
// in CAD drawings, layered artwork, maps, multi-language documents etc.
//
// Notes: 
// ---------------------------------------
// - This sample is using CreateLayer() utility method to create new OCGs. 
//   CreateLayer() is relatively basic, however it can be extended to set 
//   other optional entries in the 'OCG' and 'OCProperties' dictionary. For 
//   a complete listing of possible entries in OC dictionary please refer to 
//   section 4.10 'Optional Content' in the PDF Reference Manual.
// - The sample is grouping all layer content into separate Form XObjects. 
//   Although using PDFNet is is also possible to specify Optional Content in 
//   Content Streams (Section 4.10.2 in PDF Reference), Optional Content in  
//   XObjects results in PDFs that are cleaner, less-error prone, and faster 
//   to process.
//-----------------------------------------------------------------------------------
/// </summary>
using NUnit.Framework;

namespace MiscellaneousSamples
{
	[TestFixture]
	public class PDFLayersTest
	{			
		
		// Relative path to the folder containing test files.
		const string input_path =  "TestFiles/";

		[Test]
		public static void Sample()
		{

			try
			{
				using (PDFDoc doc = new PDFDoc())
				using (ElementBuilder builder = new ElementBuilder()) // ElementBuilder is used to build new Element objects
				using (ElementWriter writer = new ElementWriter()) // ElementWriter is used to write Elements to the page
				{
					// Create three layers...
					Group image_layer = CreateLayer(doc, "Image Layer");
					Group text_layer = CreateLayer(doc, "Text Layer");
					Group vector_layer = CreateLayer(doc, "Vector Layer");

					// Start a new page ------------------------------------
					Page page = doc.PageCreate();

					writer.Begin(page);	// begin writing to this page

					// Add new content to the page and associate it with one of the layers.
					Element element = builder.CreateForm(CreateGroup1(doc, image_layer.GetSDFObj()));
					writer.WriteElement(element);

					element = builder.CreateForm(CreateGroup2(doc, vector_layer.GetSDFObj()));
					writer.WriteElement(element);

					// Add the text layer to the page...
					bool enableOCMD = false; // set to 'true' to enable 'ocmd' example.
					if (enableOCMD)  
					{
						// A bit more advanced example of how to create an OCMD text layer that 
						// is visible only if text, image and path layers are all 'ON'.
						// An example of how to set 'Visibility Policy' in OCMD.
						Obj ocgs = doc.CreateIndirectArray();
						ocgs.PushBack(image_layer.GetSDFObj());
						ocgs.PushBack(vector_layer.GetSDFObj());
						ocgs.PushBack(text_layer.GetSDFObj());
						OCMD text_ocmd = OCMD.Create(doc, ocgs, OCMD.VisibilityPolicyType.e_AllOn);
						element = builder.CreateForm(CreateGroup3(doc, text_ocmd.GetSDFObj()));
					}
					else {
						element = builder.CreateForm(CreateGroup3(doc, text_layer.GetSDFObj()));
					}
					writer.WriteElement(element);

					// Add some content to the page that does not belong to any layer...
					// In this case this is a rectangle representing the page border.
					element = builder.CreateRect(0, 0, page.GetPageWidth(), page.GetPageHeight());
					element.SetPathFill(false);
					element.SetPathStroke(true);
					element.GetGState().SetLineWidth(40);
					writer.WriteElement(element);

					writer.End();  // save changes to the current page
					doc.PagePushBack(page);

					// Set the default viewing preference to display 'Layer' tab.
					PDFDocViewPrefs prefs = doc.GetViewPrefs();
					prefs.SetPageMode(PDFDocViewPrefs.PageMode.e_UseOC);

					doc.Save(Utils.CreateExternalFile("pdf_layers.pdf"), SDFDoc.SaveOptions.e_linearized);
					Console.WriteLine("Done.");
				}
			}
			catch (PDFNetException e)
			{
				Console.WriteLine(e.Message);
				Assert.True(false);
			}

			// The following is a code snippet shows how to selectively render 
			// and export PDF layers.
			try  
			{	 
				using (PDFDoc doc = new PDFDoc(Utils.CreateExternalFile("pdf_layers.pdf")))
				{
					doc.InitSecurityHandler();

					if (!doc.HasOC()) 
					{
						Console.WriteLine("The document does not contain 'Optional Content'");
					}
					else 
					{
						Config init_cfg = doc.GetOCGConfig();
						Context ctx = new Context(init_cfg);

						using (PDFDraw pdfdraw = new PDFDraw())
						{
							pdfdraw.SetImageSize(1000, 1000);
							pdfdraw.SetOCGContext(ctx); // Render the page using the given OCG context.

							Page page = doc.GetPage(1); // Get the first page in the document.
							pdfdraw.Export(page, Utils.CreateExternalFile("pdf_layers_default.png"));

							// Disable drawing of content that is not optional (i.e. is not part of any layer).
							ctx.SetNonOCDrawing(false);

							// Now render each layer in the input document to a separate image.
							Obj ocgs = doc.GetOCGs(); // Get the array of all OCGs in the document.
							if (ocgs != null) 
							{
								int i, sz = ocgs.Size();
								for (i=0; i<sz; ++i) 
								{
									Group ocg = new Group(ocgs.GetAt(i));
									ctx.ResetStates(false);
									ctx.SetState(ocg, true);
									string fname = "pdf_layers_" + ocg.GetName() + ".png";
									Console.WriteLine(fname);
									pdfdraw.Export(page, Utils.CreateExternalFile(fname));
								}
							}

							// Now draw content that is not part of any layer...
							ctx.SetNonOCDrawing(true);
							ctx.SetOCDrawMode(Context.OCDrawMode.e_NoOC);
							pdfdraw.Export(page, Utils.CreateExternalFile("pdf_layers_non_oc.png"));

							Console.WriteLine("Done.");
						}
					}
				}
			}
			catch (PDFNetException e)
			{
				Console.WriteLine(e.Message);
				Assert.True(false);
			}


		}

		// A utility function used to add new Content Groups (Layers) to the document.
		static Group CreateLayer(PDFDoc doc, String layer_name)
		{
			Group grp = Group.Create(doc, layer_name);
			Config cfg = doc.GetOCGConfig();
			if (cfg == null) 
			{
				cfg = Config.Create(doc, true);
				cfg.SetName("Default");
			}

			// Add the new OCG to the list of layers that should appear in PDF viewer GUI.
			Obj layer_order_array = cfg.GetOrder();
			if (layer_order_array == null) 
			{
				layer_order_array = doc.CreateIndirectArray();
				cfg.SetOrder(layer_order_array);
			}
			layer_order_array.PushBack(grp.GetSDFObj());

			return grp;
		}

		// Creates some content (3 images) and associate them with the image layer
		static Obj CreateGroup1(PDFDoc doc, Obj layer)
		{
			using (ElementWriter writer = new ElementWriter())
			using (ElementBuilder builder = new ElementBuilder())
			{
				writer.Begin(doc);

				// Create an Image that can be reused in the document or on the same page.		
				Image img = Image.Create(doc.GetSDFDoc(), (Utils.GetAssetTempFile(input_path + "peppers.jpg")));

				Element element = builder.CreateImage(img, new Matrix2D(img.GetImageWidth()/2, -145, 20, img.GetImageHeight()/2, 200, 150));
				writer.WritePlacedElement(element);

				GState gstate = element.GetGState();	// use the same image (just change its matrix)
				gstate.SetTransform(200, 0, 0, 300, 50, 450);
				writer.WritePlacedElement(element);

				// use the same image again (just change its matrix).
				writer.WritePlacedElement(builder.CreateImage(img, 300, 600, 200, -150));

				Obj grp_obj = writer.End();	

				// Indicate that this form (content group) belongs to the given layer (OCG).
				grp_obj.PutName("Subtype","Form");
				grp_obj.Put("OC", layer);	
				grp_obj.PutRect("BBox", 0, 0, 1000, 1000);  // Set the clip box for the content.

				// As an example of further configuration, set the image layer to
				// be visible on screen, but not visible when printed...

				// The AS entry is an auto state array consisting of one or more usage application 
				// dictionaries that specify how conforming readers shall automatically set the 
				// state of optional content groups based on external factors.
				Obj cfg = doc.GetOCGConfig().GetSDFObj();
				Obj auto_state = cfg.FindObj("AS");
				if (auto_state == null) auto_state = cfg.PutArray("AS");
				Obj print_state = auto_state.PushBackDict();
				print_state.PutArray("Category").PushBackName("Print");
				print_state.PutName("Event", "Print");
				print_state.PutArray("OCGs").PushBack(layer);

				Obj layer_usage = layer.PutDict("Usage");

				Obj view_setting = layer_usage.PutDict("View");
				view_setting.PutName("ViewState", "ON");

				Obj print_setting = layer_usage.PutDict("Print");
				print_setting.PutName("PrintState", "OFF");

				return grp_obj;
			}
		}

		// Creates some content (a path in the shape of a heart) and associate it with the vector layer
		static Obj CreateGroup2(PDFDoc doc, Obj layer)
		{
			using (ElementWriter writer = new ElementWriter())
			using (ElementBuilder builder = new ElementBuilder())
			{
				writer.Begin(doc);

				// Create a path object in the shape of a heart.
				builder.PathBegin();		// start constructing the path
				builder.MoveTo(306, 396);
				builder.CurveTo(681, 771, 399.75, 864.75, 306, 771);
				builder.CurveTo(212.25, 864.75, -69, 771, 306, 396);
				builder.ClosePath();
				Element element = builder.PathEnd(); // the path geometry is now specified.

				// Set the path FILL color space and color.
				element.SetPathFill(true);
				GState gstate = element.GetGState();
				gstate.SetFillColorSpace(ColorSpace.CreateDeviceCMYK()); 
				gstate.SetFillColor(new ColorPt(1, 0, 0, 0));  // cyan

				// Set the path STROKE color space and color.
				element.SetPathStroke(true); 
				gstate.SetStrokeColorSpace(ColorSpace.CreateDeviceRGB()); 
				gstate.SetStrokeColor(new ColorPt(1, 0, 0));  // red
				gstate.SetLineWidth(20);

				gstate.SetTransform(0.5, 0, 0, 0.5, 280, 300);

				writer.WriteElement(element);

				Obj grp_obj = writer.End();	


				// Indicate that this form (content group) belongs to the given layer (OCG).
				grp_obj.PutName("Subtype","Form");
				grp_obj.Put("OC", layer);
				grp_obj.PutRect("BBox", 0, 0, 1000, 1000); 	// Set the clip box for the content.

				return grp_obj;
			}
		}

		// Creates some text and associate it with the text layer
		static Obj CreateGroup3(PDFDoc doc, Obj layer)
		{
			using (ElementWriter writer = new ElementWriter())
			using (ElementBuilder builder = new ElementBuilder())
			{
				writer.Begin(doc);

				// Begin writing a block of text
				Element element = builder.CreateTextBegin(Font.Create(doc, Font.StandardType1Font.e_times_roman), 120);
				writer.WriteElement(element);

				element = builder.CreateTextRun("A text layer!");

				// Rotate text 45 degrees, than translate 180 pts horizontally and 100 pts vertically.
				Matrix2D transform = Matrix2D.RotationMatrix(-45 *  (3.1415/ 180.0));
				transform.Concat(1, 0, 0, 1, 180, 100);  
				element.SetTextMatrix(transform);

				writer.WriteElement(element);
				writer.WriteElement(builder.CreateTextEnd());

				Obj grp_obj = writer.End();	

				// Indicate that this form (content group) belongs to the given layer (OCG).
				grp_obj.PutName("Subtype","Form");
				grp_obj.Put("OC", layer);
				grp_obj.PutRect("BBox", 0, 0, 1000, 1000); 	// Set the clip box for the content.

				return grp_obj;
			}
		}
	}
}
close

Free Trial

Get unlimited trial usage of PDFTron SDK to bring accurate, reliable, and fast document processing capabilities to any application or workflow.

Select a platform to get started with your free trial.

Unlimited usage. No email address required.

PDFTron Receives USD$71 Million Growth Investment Led By Silversmith Capital Partners

Learn more
close