diff --git a/demo/out_outlines.pdf b/demo/out_outlines.pdf
new file mode 100644
index 00000000..367b5a4b
Binary files /dev/null and b/demo/out_outlines.pdf differ
diff --git a/demo/test_outlines.coffee b/demo/test_outlines.coffee
new file mode 100644
index 00000000..95fb7c9a
--- /dev/null
+++ b/demo/test_outlines.coffee
@@ -0,0 +1,82 @@
+PDFDocument = require 'pdfkit'
+fs = require 'fs'
+
+docOptions = {
+         hasOutlines: true,   # required for outlines
+         margins: { top : 40, left : 40, bottom : 40, right : 30 } }
+
+
+# Create a new PDFDocument
+doc = new PDFDocument(docOptions)
+doc.pipe fs.createWriteStream('out_outlines.pdf')
+
+doc.fontSize(16)
+title = 'Test Document With Outlines'
+
+# add outline on current level (0), with outline options: 
+# 'FitH' - top coordinate is positioned at the top edge of the window,
+#          document fits the entire width.
+# Can be any type according to PDF 1.3 specification, 7.2.1 Destinations (Table 7.2)
+doc.addOutline( title, doc.page, { type: 'FitH', top : 0 } )
+
+# text to point by outline should be added next
+doc.text(title, { paragraphGap : 8, align : 'center' } )
+
+doc.fontSize(12)  # usual text
+
+doc.info['Title']  = title
+doc.info['Author'] = 'Alexey Voytenko'
+
+loremIpsum_0_1 = 'LOREM IPSUM DOLOR.
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam in suscipit purus.
+ Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; 
+ Vivamus nec hendrerit felis. Morbi aliquam facilisis risus eu lacinia. Sed eu leo in turpis fringilla hendrerit. Ut nec accumsan nisl. 
+  Suspendisse rhoncus nisl posuere tortor tempus et dapibus elit porta.'
+
+loremIpsum_1_1 = 'CRAS LEO NEQUE.
+  Cras leo neque, elementum a rhoncus ut, vestibulum non nibh. Phasellus pretium justo turpis. 
+  Etiam vulputate, odio vitae tincidunt ultricies, eros odio dapibus nisi,
+   ut tincidunt lacus arcu eu elit.'
+
+loremIpsum_1_2 = 'AENEAN VELIT ERAT.
+Aenean velit erat, vehicula eget lacinia ut, dignissim non tellus. 
+Aliquam nec lacus mi, sed vestibulum nunc. Suspendisse potenti. Curabitur vitae sem turpis. 
+Vestibulum sed neque eget dolor dapibus porttitor at sit amet sem. Fusce a turpis lorem. 
+Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;
+Mauris at ante tellus. Vestibulum a metus lectus. Praesent tempor purus a lacus blandit eget 
+gravida ante hendrerit.'
+
+loremIpsum_0_2 = 'CRAS ET EROS METUS.
+Cras et eros metus. Sed commodo malesuada eros, vitae interdum augue semper quis. 
+Fusce id magna nunc. Curabitur sollicitudin placerat semper. Cras et mi neque, a dignissim risus. 
+Nulla venenatis porta lacus, vel rhoncus lectus tempor vitae. Duis sagittis venenatis rutrum. 
+Curabitur tempor massa tortor.'
+
+# add outline on current level (0) with default options - 'XYZ', positioning on text
+doc.addOutline('Lorem ipsum dolor', doc.page);
+
+doc.text( loremIpsum_0_1,
+   { paragraphGap : 2, indent : 30, align : 'justify' } )
+
+# create next level (1) of table of contents and add outline
+doc.addSublevelOutline('Cras leo neque', doc.page);
+doc.text( loremIpsum_1_1, { paragraphGap : 2, indent : 30, align : 'justify' } );
+
+# add outline on the same level 1 with positioning on text
+doc.addOutline('Aenean velit erat', doc.page );
+
+doc.text( loremIpsum_1_2, { paragraphGap : 2, indent : 30, align : 'justify' } );
+
+# go up in outlines levels
+doc.endOutlineSublevel();
+
+outl_options = { type: 'XYZ', unicode: true }
+
+# add outline on the level 0 with positioning on text ('XYZ' is by default), 
+# using non-ASCII characters in outline title: set unicode in this case 
+doc.addOutline('Тестовый заголовок', doc.page, outl_options);
+
+doc.text( loremIpsum_0_2, { paragraphGap : 2, indent : 30, align : 'justify' } );
+
+doc.end()
+console.log "out_outlines.pdf created" 
diff --git a/lib/document.coffee b/lib/document.coffee
index c17979c4..bf5696cb 100644
--- a/lib/document.coffee
+++ b/lib/document.coffee
@@ -8,6 +8,7 @@ fs = require 'fs'
 PDFObject = require './object'
 PDFReference = require './reference'
 PDFPage = require './page'
+PDFOutline = require './outline'
 
 class PDFDocument extends stream.Readable
   constructor: (@options = {}) ->
@@ -31,9 +32,24 @@ class PDFDocument extends stream.Readable
         Type: 'Pages'
         Count: 0
         Kids: []
+
+    if @options.hasOutlines
+        @_root.data['PageMode'] = 'UseOutlines'
+        @_root.data['Outlines'] = @ref
+            Type: 'Outlines'
+            Count: 0
+
+    @root_outlines = @_root.data['Outlines'] 
     
     # The current page
     @page = null
+
+    # Outlines data structures
+    @outlines = []  # a multitier tree, represented by lists ( [] )
+    @cur       = @outlines       # current level list
+    @levelHead = @root_outlines  # head of current level list
+    @levs  = []  # stack of sublevel lists heads
+    @prevs = []  # stack of sublevel lists
     
     # Initialize mixins
     @initColor()
@@ -97,10 +113,100 @@ class PDFDocument extends stream.Readable
     @transform 1, 0, 0, -1, 0, @page.height
     
     return this
+
+  isRoot: () ->
+    return @prevs.length == 0
+
+  addOutline: (title, dest, options) ->
+
+    if not @options.hasOutlines
+        return this
+
+    prevNode = null
+    if @isRoot()
+        parent = @root_outlines
+    else
+        parent = @levelHead.dictionary
+
+    if @cur.length > 0  # can be on Root level
+        prevNode = @cur[@cur.length-1]
+        if prevNode instanceof Array # prev is a sublevel list
+            prevNode = @cur[@cur.length-2]  # there *must* be an element before
+
+    # create an outline object
+    outline = new PDFOutline(this, parent, title, dest, options)
+    
+    # update list header info
+    if @outlines.length == 0  # init root level list
+        @root_outlines.data['First'] = outline.dictionary
+
+    parent.data['Last'] = outline.dictionary   # can be root level
+    parent.data['Count']++
+
+    if prevNode != null   # not first in the list
+        outline.dictionary.data['Prev']  = prevNode.dictionary
+        prevNode.dictionary.data['Next'] = outline.dictionary
+
+    # add to the current level list
+    @cur.push outline
+
+    return this
+
+  addSublevelOutline: (title, dest, options) ->
+
+    if not @options.hasOutlines
+        return this
+
+    if @cur.length == 0 or ( @cur[@cur.length-1] instanceof Array )
+       throw new Error '
+          Cannot start sublevel with empty current level:
+          add current level outline first.'
+        
+    @levs.push @levelHead
+    @levelHead = @cur[@cur.length-1]  # head of sublevel list
+    @prevs.push @cur  # remember up level container
+    @cur.push []      # add sublevel container
+    @cur = @cur[@cur.length-1]
+
+    outline = new PDFOutline(this, @levelHead.dictionary, title, dest, options)
+    @cur.push outline
+    @levelHead.dictionary.data['First'] = outline.dictionary
+    @levelHead.dictionary.data['Last']  = outline.dictionary
+    @levelHead.dictionary.data['Count'] = 1  # important: not ++ (field is absent now)
+
+    return this
+
+  endOutlineSublevel: () ->
+
+    if not @options.hasOutlines
+        return this
+
+    if @isRoot()
+        throw new Error 'cannot end root outlines level'
+
+    # restore previous list as current
+    @cur  = @prevs.pop()
+    count = @levelHead.dictionary.data['Count']
+    @levelHead = @levs.pop()
+
+    # add child sublist counter (will contain all child counters)
+    if @isRoot()
+        @levelHead.data['Count'] += count
+    else
+        @levelHead.dictionary.data['Count'] += count
+
+    return this
+
+  endOutlines: (outlines) ->
+      for outline in outlines
+         if outline instanceof Array
+           @endOutlines(outline)
+         else
+           outline.dictionary.end()
     
   ref: (data) ->
     ref = new PDFReference(this, @_offsets.length + 1, data)
-    @_offsets.push null # placeholder for this object's offset once it is finalized
+    @_offsets.push null # placeholder for this object''s offset once it is finalized
     @_waiting++
     return ref
     
@@ -161,6 +267,8 @@ class PDFDocument extends stream.Readable
         
     @_root.end()
     @_root.data.Pages.end()
+    @_root.data.Outlines.end()
+    @endOutlines(@outlines)
     
     if @_waiting is 0
       @_finalize()
diff --git a/lib/outline.coffee b/lib/outline.coffee
new file mode 100644
index 00000000..4a924f2d
--- /dev/null
+++ b/lib/outline.coffee
@@ -0,0 +1,54 @@
+###
+PDFOutline - represents a table of contents in the PDF 1.3 document
+By Alexey Voytenko
+see also methods addOutline, addSublevelOutline, endOutlineSublevel
+of PDFDocument class
+###
+
+PDFObject = require './object'
+PDFPage   = require './page'
+
+class PDFOutline
+    constructor: ( @document, parent, @title, @dest, @options = {} ) ->
+
+        @type    = @options.type or 'XYZ'
+        @unicode = @options.unicode or false
+
+        # to convert library y coordinate to requred user space coordinate
+        height = @document.page.height
+
+        # see PDFReference 1.3, 7.2.1 Destinations
+        switch @type  
+            when 'Fit', 'FitB'
+                destination = [@dest.dictionary, @type]
+
+            when 'FitH', 'FitBH'
+                top = height - ( @options.top or 0 )
+                destination = [@dest.dictionary, @type, top]
+
+            when 'FitV', 'FitBV'
+                top = height - ( @options.left or 0 )
+                destination = [@dest.dictionary, @type, left]
+
+            when 'FitR'
+                left   = @options.left or 0
+                bottom = height - ( @options.bottom or 0 )
+                right  = @options.right or 0
+                top    = height - ( @options.top or 0 )
+                destination = [@dest.dictionary, @type, left, bottom, right, top]
+
+            else  # assuming 'XYZ' - most common
+                # XY - coordinates of page top left in user space system,
+                # Z  - zoom factor (null for X,Y,Z - previous value unchanged)
+                X = @options.X or 0
+                Y = height - ( @options.Y or @document.y )
+                Z = @options.Z or null
+                destination = [@dest.dictionary, @type, X, Y, Z]
+
+        # The outline dictionary
+        @dictionary = @document.ref
+            Title:  PDFObject.s @title, @unicode  # need to specify if unicode
+            Parent: parent      # dictionary
+            Dest:   destination
+
+module.exports = PDFOutline
diff --git a/lib/page.coffee b/lib/page.coffee
index 2584b3ba..fbe6be57 100644
--- a/lib/page.coffee
+++ b/lib/page.coffee
@@ -121,4 +121,4 @@ class PDFPage
     LETTER: [612.00, 792.00]
     TABLOID: [792.00, 1224.00]
   
-module.exports = PDFPage
\ No newline at end of file
+module.exports = PDFPage
