From 642428cd0e23a9792acfcb073156fe0b72eb142f Mon Sep 17 00:00:00 2001 From: Kurt Jung Date: Sun, 8 Sep 2013 09:31:34 -0400 Subject: Bookmark outline support submitted by Manuel Cornes --- def.go | 11 +++++++++ doc.go | 3 ++- fpdf.go | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ fpdf_test.go | 20 ++++++++++++++++ 4 files changed, 107 insertions(+), 1 deletion(-) 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("<>") + f.out("endobj") + } + f.newobj() + f.outlineRoot = f.n + f.outf("<>", 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 +} -- cgit v1.2.1-24-ge1ad