From cbbfe21f94ea53f0800feaf4e9c06c038ddc1e6e Mon Sep 17 00:00:00 2001 From: Kurt Jung Date: Tue, 16 Sep 2014 22:38:49 -0400 Subject: Added layer functionality. This allows content to be placed into layers, the visibility of which can be controlled from the document reader. --- def.go | 1 + fpdf.go | 9 ++++- fpdf_test.go | 39 +++++++++++++++++++ layer.go | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 layer.go diff --git a/def.go b/def.go index 422eb1c..6d12af3 100644 --- a/def.go +++ b/def.go @@ -197,6 +197,7 @@ type Fpdf struct { transformNest int // Number of active transformation contexts err error // Set if error occurs during life cycle of instance protect protectType // document protection structure + layer layerRecType // manages optional layers in document colorFlag bool // indicates whether fill and text colors are different color struct { // Composite values of colors draw, fill, text clrType diff --git a/fpdf.go b/fpdf.go index 20705b8..5fd3f63 100644 --- a/fpdf.go +++ b/fpdf.go @@ -173,6 +173,7 @@ func fpdfNew(orientationStr, unitStr, sizeStr, fontDirStr string, size SizeType) f.gradientList = append(f.gradientList, gradientType{}) // gradientList[0] is unused // Set default PDF version number f.pdfVersion = "1.3" + f.layerInit() return } @@ -2346,6 +2347,7 @@ func (f *Fpdf) beginpage(orientationStr string, size SizeType) { } func (f *Fpdf) endpage() { + f.EndLayer() f.state = 1 } @@ -3028,7 +3030,8 @@ func (f *Fpdf) putresourcedict() { } f.out(">>") } - + // Layers + f.layerPutResourceDict() } func (f *Fpdf) putBlendModes() { @@ -3072,6 +3075,7 @@ func (f *Fpdf) putresources() { if f.err != nil { return } + f.layerPutLayers() f.putBlendModes() f.putGradients() f.putfonts() @@ -3148,6 +3152,8 @@ func (f *Fpdf) putcatalog() { f.outf("/Outlines %d 0 R", f.outlineRoot) f.out("/PageMode /UseOutlines") } + // Layers + f.layerPutCatalog() } func (f *Fpdf) putheader() { @@ -3224,6 +3230,7 @@ func (f *Fpdf) enddoc() { if f.err != nil { return } + f.layerEndDoc() f.putheader() f.putpages() f.putresources() diff --git a/fpdf_test.go b/fpdf_test.go index 0da5e73..964985d 100644 --- a/fpdf_test.go +++ b/fpdf_test.go @@ -1246,3 +1246,42 @@ func ExampleFpdf_tutorial25() { // Output: // Successfully generated pdf/tutorial25.pdf } + +// This example demonstrates document layers. The initial visibility of a layer +// is specified with the second parameter to AddLayer(). The layer list +// displayed by the document reader allows layer visibility to be controlled +// interactively. +func ExampleFpdf_tutorial26() { + + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.AddPage() + pdf.SetFont("Arial", "", 15) + pdf.Write(8, "This line doesn't belong to any layer.\n") + + // Define layers + l1 := pdf.AddLayer("Layer 1", true) + l2 := pdf.AddLayer("Layer 2", true) + + // Open layer pane in PDF viewer + pdf.OpenLayerPane() + + // First layer + pdf.BeginLayer(l1) + pdf.Write(8, "This line belongs to layer 1.\n") + pdf.EndLayer() + + // Second layer + pdf.BeginLayer(l2) + pdf.Write(8, "This line belongs to layer 2.\n") + pdf.EndLayer() + + // First layer again + pdf.BeginLayer(l1) + pdf.Write(8, "This line belongs to layer 1 again.\n") + pdf.EndLayer() + + pdf.OutputAndClose(docWriter(pdf, 26)) + + // Output: + // Successfully generated pdf/tutorial26.pdf +} diff --git a/layer.go b/layer.go new file mode 100644 index 0000000..d567e37 --- /dev/null +++ b/layer.go @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2014 Kurt Jung (Gmail: kurt.w.jung) + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package gofpdf + +// Routines in this file are translated from +// http://www.fpdf.org/en/script/script97.php + +type layerType struct { + name string + visible bool + objNum int // object number +} + +type layerRecType struct { + list []layerType + currentLayer int + openLayerPane bool +} + +func (f *Fpdf) layerInit() { + f.layer.list = make([]layerType, 0) + f.layer.currentLayer = -1 + f.layer.openLayerPane = false +} + +// AddLayer defines a layer that can be shown or hidden when the document is +// displayed. name specifies the layer name that the document reader will +// display in the layer list. visible specifies whether the layer will be +// initially visible. The return value is an integer ID that is used in a call +// to BeginLayer(). +// +// Layers are demonstrated in tutorial 26. +func (f *Fpdf) AddLayer(name string, visible bool) (layerID int) { + layerID = len(f.layer.list) + f.layer.list = append(f.layer.list, layerType{name: name, visible: visible}) + return +} + +// BeginLayer is called to begin adding content to the specified layer. All +// content added to the page between a call to BeginLayer and a call to +// EndLayer is added to the layer specified by id. See AddLayer for more +// details. +func (f *Fpdf) BeginLayer(id int) { + f.EndLayer() + if id >= 0 && id < len(f.layer.list) { + f.outf("/OC /OC%d BDC", id) + f.layer.currentLayer = id + } +} + +// EndLayer is called to stop adding content to the currently active layer. See +// BeginLayer for more details. +func (f *Fpdf) EndLayer() { + if f.layer.currentLayer >= 0 { + f.out("EMC") + f.layer.currentLayer = -1 + } +} + +// OpenLayerPane advises the document reader to open the layer pane when the +// document is initially displayed. +func (f *Fpdf) OpenLayerPane() { + f.layer.openLayerPane = true +} + +func (f *Fpdf) layerEndDoc() { + if len(f.layer.list) > 0 { + if f.pdfVersion < "1.5" { + f.pdfVersion = "1.5" + } + } +} + +func (f *Fpdf) layerPutLayers() { + for j, l := range f.layer.list { + f.newobj() + f.layer.list[j].objNum = f.n + f.outf("<>", f.textstring(utf8toutf16(l.name))) + f.out("endobj") + } +} + +func (f *Fpdf) layerPutResourceDict() { + if len(f.layer.list) > 0 { + f.out("/Properties <<") + for j, layer := range f.layer.list { + f.outf("/OC%d %d 0 R", j, layer.objNum) + } + f.out(">>") + } + +} + +func (f *Fpdf) layerPutCatalog() { + if len(f.layer.list) > 0 { + onStr := "" + offStr := "" + for _, layer := range f.layer.list { + onStr += sprintf("%d 0 R ", layer.objNum) + if !layer.visible { + offStr += sprintf("%d 0 R ", layer.objNum) + } + } + f.outf("/OCProperties <>>>", onStr, offStr, onStr) + if f.layer.openLayerPane { + f.out("/PageMode /UseOC") + } + } +} -- cgit v1.2.1-24-ge1ad