summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--def.go11
-rw-r--r--doc.go3
-rw-r--r--fpdf.go74
-rw-r--r--fpdf_test.go20
4 files changed, 107 insertions, 1 deletions
diff --git a/def.go b/def.go
index d877f9c..ed37f11 100644
--- a/def.go
+++ b/def.go
@@ -79,6 +79,14 @@ type intLinkType struct {
y float64
}
+// outlineType is used for a sidebar outline of bookmarks
+type outlineType struct {
+ text string
+ level, parent, first, last, next, prev int
+ y float64
+ p int
+}
+
// InitType is used with NewCustom() to customize an Fpdf instance.
// OrientationStr, UnitStr, SizeStr and FontDirStr correspond to the arguments
// accepted by New(). If the Wd and Ht fields of Size are each greater than
@@ -92,6 +100,7 @@ type InitType struct {
FontDirStr string
}
+// Principal structure for creating a single PDF document
type Fpdf struct {
page int // current page number
n int // current object number
@@ -137,6 +146,8 @@ type Fpdf struct {
images map[string]imageInfoType // array of used images
pageLinks [][]linkType // pageLinks[page][link], both 1-based
links []intLinkType // array of internal links
+ outlines []outlineType // array of outlines
+ outlineRoot int // root of outlines
autoPageBreak bool // automatic page breaking
acceptPageBreak func() bool // returns true to accept page break
pageBreakTrigger float64 // threshold used to trigger page breaks
diff --git a/doc.go b/doc.go
index 091cd5a..1e2c4f5 100644
--- a/doc.go
+++ b/doc.go
@@ -22,7 +22,8 @@ created by Olivier Plathey, and a number of font and image resources are copied
directly from it. Drawing support is adapted from the FPDF geometric figures
script by David Hernández Sanz. Transparency support is adapted from the FPDF
transparency script by Martin Hall-May. Support for gradients and clipping is
-adapted from FPDF scripts by Andreas Würmser.
+adapted from FPDF scripts by Andreas Würmser. Support for outline bookmarks is
+adapted from Olivier Plathey by Manuel Cornes.
The FPDF website is http://www.fpdf.org/.
diff --git a/fpdf.go b/fpdf.go
index a7fb350..2a15310 100644
--- a/fpdf.go
+++ b/fpdf.go
@@ -1381,6 +1381,20 @@ func (f *Fpdf) LinkString(x, y, w, h float64, linkStr string) {
f.newLink(x, y, w, h, 0, linkStr)
}
+// Sets a bookmark that will be displayed in a sidebar outline. txtStr is the
+// title of the bookmark. level specifies the level of the bookmark in the
+// outline; 0 is the top level, 1 is just below, and so on. y specifies the
+// vertical position of the bookmark destination in the current page; -1
+// indicates the current position.
+//
+// See tutorial 16 for an bookmark example.
+func (f *Fpdf) Bookmark(txtStr string, level int, y float64) {
+ if y == -1 {
+ y = f.y
+ }
+ f.outlines = append(f.outlines, outlineType{text: txtStr, level: level, y: y, p: f.PageNo(), prev: -1, last: -1, next: -1, first: -1})
+}
+
// Prints a character string. The origin (x, y) is on the left of the first
// character at the baseline. This method allows to place a string precisely on
// the page, but it is usually easier to use Cell(), MultiCell() or Write()
@@ -2844,6 +2858,11 @@ func (f *Fpdf) putcatalog() {
case "two":
f.out("/PageLayout /TwoColumnLeft")
}
+ // Bookmarks
+ if len(f.outlines) > 0 {
+ f.outf("/Outlines %d 0 R", f.outlineRoot)
+ f.out("/PageMode /UseOutlines")
+ }
}
func (f *Fpdf) putheader() {
@@ -2859,6 +2878,59 @@ func (f *Fpdf) puttrailer() {
f.outf("/Info %d 0 R", f.n-1)
}
+func (f *Fpdf) putbookmarks() {
+ nb := len(f.outlines)
+ if nb > 0 {
+ lru := make(map[int]int)
+ level := 0
+ for i, o := range f.outlines {
+ if o.level > 0 {
+ parent := lru[o.level-1]
+ f.outlines[i].parent = parent
+ f.outlines[parent].last = i
+ if o.level > level {
+ f.outlines[parent].first = i
+ }
+ } else {
+ f.outlines[i].parent = nb
+ }
+ if o.level <= level && i > 0 {
+ prev := lru[o.level]
+ f.outlines[prev].next = i
+ f.outlines[i].prev = prev
+ }
+ lru[o.level] = i
+ level = o.level
+ }
+ n := f.n + 1
+ for _, o := range f.outlines {
+ f.newobj()
+ f.outf("<</Title %s", f.textstring(o.text))
+ f.outf("/Parent %d 0 R", n+o.parent)
+ if o.prev != -1 {
+ f.outf("/Prev %d 0 R", n+o.prev)
+ }
+ if o.next != -1 {
+ f.outf("/Next %d 0 R", n+o.next)
+ }
+ if o.first != -1 {
+ f.outf("/First %d 0 R", n+o.first)
+ }
+ if o.last != -1 {
+ f.outf("/Last %d 0 R", n+o.last)
+ }
+ f.outf("/Dest [%d 0 R /XYZ 0 %.2f null]", 1+2*o.p, (f.h-o.y)*f.k)
+ f.out("/Count 0>>")
+ f.out("endobj")
+ }
+ f.newobj()
+ f.outlineRoot = f.n
+ f.outf("<</Type /Outlines /First %d 0 R", n)
+ f.outf("/Last %d 0 R>>", n+lru[0])
+ f.out("endobj")
+ }
+}
+
func (f *Fpdf) enddoc() {
if f.err != nil {
return
@@ -2869,6 +2941,8 @@ func (f *Fpdf) enddoc() {
if f.err != nil {
return
}
+ // Bookmarks
+ f.putbookmarks()
// Info
f.newobj()
f.out("<<")
diff --git a/fpdf_test.go b/fpdf_test.go
index 57fee6e..fad67bc 100644
--- a/fpdf_test.go
+++ b/fpdf_test.go
@@ -944,3 +944,23 @@ func ExampleFpdf_tutorial15() {
// 3: 3.00 in, 12.00 in
// Successfully generated pdf/tutorial15.pdf
}
+
+// Bookmark test
+func ExampleFpdf_tutorial16() {
+ pdf := gofpdf.New("P", "mm", "A4", FONT_DIR)
+ pdf.AddPage()
+ pdf.SetFont("Arial", "", 15)
+ pdf.Bookmark("Page 1", 0, 0)
+ pdf.Bookmark("Paragraph 1", 1, -1)
+ pdf.Cell(0, 6, "Paragraph 1")
+ pdf.Ln(50)
+ pdf.Bookmark("Paragraph 2", 1, -1)
+ pdf.Cell(0, 6, "Paragraph 2")
+ pdf.AddPage()
+ pdf.Bookmark("Page 2", 0, 0)
+ pdf.Bookmark("Paragraph 3", 1, -1)
+ pdf.Cell(0, 6, "Paragraph 3")
+ pdf.OutputAndClose(docWriter(pdf, 16))
+ // Output:
+ // Successfully generated pdf/tutorial16.pdf
+}