Skip to content

Commit f91bdd6

Browse files
theBenForcealafr
authored andcommitted
Features/outline (#831)
Outline support by @alexvdev and @blforce Close #216, close #13
1 parent 34cf8d5 commit f91bdd6

7 files changed

Lines changed: 98 additions & 1 deletion

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,11 @@ Installation uses the [npm](http://npmjs.org/) package manager. Just type the f
4848
* Highlights
4949
* Underlines
5050
* etc.
51+
* Outlines
5152

5253
## Coming soon!
5354

5455
* Patterns fills
55-
* Outlines
5656
* PDF Security
5757
* Higher level APIs for creating tables and laying out content
5858
* More performance optimizations

docs/generate.coffee

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,11 @@ class Node
190190
if @type in ['h1', 'h2'] and lastType? and lastType isnt 'h1'
191191
doc.addPage()
192192

193+
if @type == 'h1'
194+
doc.h1Outline = doc.outline.addItem(fragment.text)
195+
else if @type == 'h2' && doc.h1Outline != null
196+
doc.h1Outline.addItem(fragment.text)
197+
193198
# set styles and whether this fragment is continued (for rich text wrapping)
194199
options = @setStyle doc
195200
options.continued ?= continued or index < @content.length - 1
@@ -227,6 +232,7 @@ renderTitlePage = (doc) ->
227232
doc.y = doc.page.height / 2 - doc.currentLineHeight()
228233
doc.text title, align: 'center'
229234
w = doc.widthOfString(title)
235+
doc.h1Outline = doc.outline.addItem(title)
230236

231237
doc.fontSize 20
232238
doc.y -= 10
@@ -250,5 +256,6 @@ do ->
250256
render doc, 'vector.coffee.md'
251257
render doc, 'text.coffee.md'
252258
render doc, 'images.coffee.md'
259+
render doc, 'outline.coffee.md'
253260
render doc, 'annotations.coffee.md'
254261
doc.end()

docs/guide.pdf

503 KB
Binary file not shown.

docs/outline.coffee.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Outlines in PDFKit
2+
3+
Outlines are the heirachical bookmarks that display in some PDF readers. Currently only page bookmarks are supported, but more may be added in the future. They are simple to add and only require a single method:
4+
5+
* `addItem(title, options)`
6+
7+
Here is an example of adding a bookmark with a single child bookmark.
8+
9+
# Get a reference to the Outline root
10+
outline = doc.outline
11+
12+
# Add a top-level bookmark
13+
top = outline.addItem('Top Level')
14+
15+
# Add a sub-section
16+
top.addItem('Sub-section')
17+
18+
## Options
19+
20+
The `options` parameter currently only has one property: `expanded`. If this value is set to `true` then all of that section's children will be visible by default. This value defaults to `false`.
21+
22+
In this example the 'Top Level' section will be expanded to show 'Sub-section'.
23+
24+
# Add a top-level bookmark
25+
top = outline.addItem('Top Level', { expanded: true })
26+
27+
# Add a sub-section
28+
top.addItem('Sub-section')

lib/document.coffee

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class PDFDocument extends stream.Readable
4444
@initFonts()
4545
@initText()
4646
@initImages()
47+
@initOutline()
4748

4849
# Initialize the metadata
4950
@info =
@@ -77,6 +78,7 @@ class PDFDocument extends stream.Readable
7778
mixin require './mixins/text'
7879
mixin require './mixins/images'
7980
mixin require './mixins/annotations'
81+
mixin require './mixins/outline'
8082

8183
addPage: (options = @options) ->
8284
# end the current page if needed
@@ -184,6 +186,8 @@ class PDFDocument extends stream.Readable
184186
for name, font of @_fontFamilies
185187
font.finalize()
186188

189+
@endOutline()
190+
187191
@_root.end()
188192
@_root.data.Pages.end()
189193

lib/mixins/outline.coffee

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
PDFOutline = require '../outline'
2+
3+
module.exports =
4+
initOutline: () ->
5+
@outline = new PDFOutline(this, null, null, null)
6+
7+
endOutline: () ->
8+
@outline.endOutline()
9+
if @outline.children.length > 0
10+
@_root.data.Outlines = @outline.dictionary
11+
@_root.data.PageMode = 'UseOutlines'

lib/outline.coffee

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
PDFObject = require './object'
2+
PDFPage = require './page'
3+
4+
class PDFOutline
5+
constructor: (@document, parent, title, dest, @options = { expanded: false }) ->
6+
7+
@outlineData = {}
8+
9+
if dest != null
10+
@outlineData['Dest'] = [dest.dictionary, 'Fit']
11+
12+
if parent != null
13+
@outlineData['Parent'] = parent
14+
15+
if title != null
16+
@outlineData['Title'] = new String(title)
17+
18+
@dictionary = @document.ref @outlineData
19+
@children = []
20+
21+
addItem: (title, options = { expanded: false }) ->
22+
result = new PDFOutline(@document, @dictionary, title, @document.page, options)
23+
@children.push(result)
24+
25+
return result
26+
27+
endOutline: () ->
28+
if @children.length > 0
29+
if @options.expanded
30+
@outlineData.Count = @children.length
31+
32+
[first, ..., last] = @children
33+
@outlineData.First = first.dictionary
34+
@outlineData.Last = last.dictionary
35+
36+
for i in [0...@children.length]
37+
child = @children[i]
38+
if i > 0
39+
child.outlineData.Prev = @children[i-1].dictionary
40+
if i < @children.length - 1
41+
child.outlineData.Next = @children[i+1].dictionary
42+
child.endOutline()
43+
44+
@dictionary.end()
45+
46+
47+
module.exports = PDFOutline

0 commit comments

Comments
 (0)