diff options
| -rw-r--r-- | def.go | 1 | ||||
| -rw-r--r-- | fpdf.go | 9 | ||||
| -rw-r--r-- | fpdf_test.go | 39 | ||||
| -rw-r--r-- | layer.go | 123 | 
4 files changed, 171 insertions, 1 deletions
| @@ -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 @@ -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("<</Type /OCG /Name %s>>", 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 <</OCGs [%s] /D <</OFF [%s] /Order [%s]>>>>", onStr, offStr, onStr) +		if f.layer.openLayerPane { +			f.out("/PageMode /UseOC") +		} +	} +} | 
