' ' Copyright (c) 2001-2012 by PDFTron Systems Inc. All Rights Reserved. ' Imports System Imports pdftron Imports pdftron.Common Imports pdftron.Filters Imports pdftron.SDF Imports PDFTRON.PDF Imports PDFTRON.PDF.OCG '----------------------------------------------------------------------------------- ' 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. '----------------------------------------------------------------------------------- Module Module1 ' Relative path to the folder containing test files. Dim input_path As String = "../../../TestFiles/" Dim output_path As String = "../../../TestFiles/Output/" Sub Main() PDFNet.Initialize() Try Dim doc As PDFDoc = New PDFDoc ' Create three layers... Dim image_layer As Group = CreateLayer(doc, "Image Layer") Dim text_layer As Group = CreateLayer(doc, "Text Layer") Dim vector_layer As Group = CreateLayer(doc, "Vector Layer") ' Start a new page ------------------------------------ Dim page As Page = doc.PageCreate() Dim builder As ElementBuilder = New ElementBuilder ' ElementBuilder is used to build new Element objects Dim writer As ElementWriter = New ElementWriter ' ElementWriter is used to write Elements to the page writer.Begin(page) ' begin writing to this page ' Add new content to the page and associate it with one of the layers. Dim element As Element = builder.CreateForm(CreateGroup1(doc, image_layer.GetSDFObj())) writer.WriteElement(element) element = builder.CreateForm(CreateGroup2(doc, vector_layer.GetSDFObj())) writer.WriteElement(element) 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) ' Calling Dispose() on ElementReader/Writer/Builder can result in increased performance and lower memory consumption. builder.Dispose() writer.Dispose() doc.Save(output_path + "pdf_layers.pdf", SDF.SDFDoc.SaveOptions.e_linearized) doc.Close() Console.WriteLine("Done.") Catch ex As PDFNetException Console.WriteLine(ex.Message) Catch ex As Exception MsgBox(ex.Message) End Try ' The following is a code snippet shows how to selectively render ' and export PDF layers. Try Dim doc As PDFDoc = New PDFDoc(output_path + "pdf_layers.pdf") doc.InitSecurityHandler() If doc.HasOC() = False Then Console.WriteLine("The document does not contain 'Optional Content'") Else Dim init_cfg As Config = doc.GetOCGConfig() Dim ctx As Context = New Context(init_cfg) Dim pdfdraw As PDFDraw = New PDFDraw pdfdraw.SetImageSize(1000, 1000) pdfdraw.SetOCGContext(ctx) ' Render the page using the given OCG context. Dim page As Page = doc.GetPage(1) ' Get the first page in the document. pdfdraw.Export(page, output_path + "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. Dim ocgs As Obj = doc.GetOCGs() ' Get the array of all OCGs in the document. If Not ocgs Is Nothing Then Dim i As Integer = 0 Dim sz As Integer = ocgs.Size() While (i < sz) Dim ocg As Group = New Group(ocgs.GetAt(i)) ctx.ResetStates(False) ctx.SetState(ocg, True) Dim fname As String = output_path + "pdf_layers_" + ocg.GetName() + ".png" Console.WriteLine(fname) pdfdraw.Export(page, fname) i = i + 1 End While End If ' Now draw content that is not part of any layer... ctx.SetNonOCDrawing(True) ctx.SetOCDrawMode(Context.OCDrawMode.e_NoOC) pdfdraw.Export(page, output_path + "pdf_layers_non_oc.png") pdfdraw.Dispose() ' Calling Dispose() on PDFDraw when it is not anymore in use can result in increased performance and lower memory consumption. doc.Close() Console.WriteLine("Done.") End If Catch ex As PDFNetException Console.WriteLine(ex.Message) Catch ex As Exception MsgBox(ex.Message) End Try PDFNet.Terminate() End Sub ' A utility function used to add new Content Groups (Layers) to the document. Function CreateLayer(ByRef doc As PDFDoc, ByVal layer_name As String) As Group Dim grp As Group = Group.Create(doc, layer_name) Dim cfg As Config = doc.GetOCGConfig() If cfg Is Nothing Then cfg = Config.Create(doc, True) cfg.SetName("Default") End If ' Add the new OCG to the list of layers that should appear in PDF viewer GUI. Dim layer_order_array As Obj = cfg.GetOrder() If layer_order_array Is Nothing Then layer_order_array = doc.CreateIndirectArray() cfg.SetOrder(layer_order_array) End If layer_order_array.PushBack(grp.GetSDFObj()) Return grp End Function ' Creates some content (3 images) and associate them with the image layer Function CreateGroup1(ByRef doc As PDFDoc, ByRef layer As Obj) As Obj Dim writer As ElementWriter = New ElementWriter writer.Begin(doc.GetSDFDoc()) ' Create an Image that can be reused in the document or on the same page. Dim img As Image = Image.Create(doc.GetSDFDoc(), (input_path + "peppers.jpg")) Dim builder As ElementBuilder = New ElementBuilder Dim element As Element = builder.CreateImage(img, New Matrix2D(img.GetImageWidth() / 2, -145, 20, img.GetImageHeight() / 2, 200, 150)) writer.WritePlacedElement(element) Dim gstate As 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)) Dim grp_obj As Obj = writer.End() ' Calling Dispose() on ElementReader/Writer/Builder can result in increased performance and lower memory consumption. builder.Dispose() writer.Dispose() ' 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 End Function ' Creates some content (a path in the shape of a heart) and associate it with the vector layer Function CreateGroup2(ByRef doc As PDFDoc, ByRef layer As Obj) As Obj Dim writer As ElementWriter = New ElementWriter writer.Begin(doc.GetSDFDoc()) Dim builder As ElementBuilder = New ElementBuilder ' 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() Dim element As Element = builder.PathEnd() ' the path geometry is now specified. ' Set the path FILL color space and color. element.SetPathFill(True) Dim gstate As 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) Dim grp_obj As Obj = writer.End() ' Calling Dispose() on ElementReader/Writer/Builder can result in increased performance and lower memory consumption. builder.Dispose() writer.Dispose() ' 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 End Function ' Creates some text and associate it with the text layer Function CreateGroup3(ByRef doc As PDFDoc, ByRef layer As Obj) As Obj Dim writer As ElementWriter = New ElementWriter writer.Begin(doc.GetSDFDoc()) Dim builder As ElementBuilder = New ElementBuilder ' Begin writing a block of text Dim element As 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. Dim transform As Matrix2D = 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()) Dim grp_obj As Obj = writer.End() ' Calling Dispose() on ElementReader/Writer/Builder can result in increased performance and lower memory consumption. builder.Dispose() writer.Dispose() ' 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 End Function End Module