mirror of
https://github.com/unidoc/unipdf.git
synced 2025-05-01 22:17:29 +08:00
Merge pull request #321 from adrg/pdf-outlines
Add Creator support for outlines
This commit is contained in:
commit
33d17ce9aa
@ -11,6 +11,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/unidoc/unidoc/common"
|
"github.com/unidoc/unidoc/common"
|
||||||
|
"github.com/unidoc/unidoc/pdf/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Chapter is used to arrange multiple drawables (paragraphs, images, etc) into a single section.
|
// Chapter is used to arrange multiple drawables (paragraphs, images, etc) into a single section.
|
||||||
@ -39,12 +40,18 @@ type Chapter struct {
|
|||||||
// Margins to be applied around the block when drawing on Page.
|
// Margins to be applied around the block when drawing on Page.
|
||||||
margins margins
|
margins margins
|
||||||
|
|
||||||
// Reference to the creator's TOC.
|
// Reference to the TOC of the creator.
|
||||||
toc *TOC
|
toc *TOC
|
||||||
|
|
||||||
|
// Reference to the outline of the creator.
|
||||||
|
outline *model.Outline
|
||||||
|
|
||||||
|
// The item of the chapter in the outline.
|
||||||
|
outlineItem *model.OutlineItem
|
||||||
}
|
}
|
||||||
|
|
||||||
// newChapter creates a new chapter with the specified title as the heading.
|
// newChapter creates a new chapter with the specified title as the heading.
|
||||||
func newChapter(toc *TOC, title string, number int, style TextStyle) *Chapter {
|
func newChapter(toc *TOC, outline *model.Outline, title string, number int, style TextStyle) *Chapter {
|
||||||
p := newParagraph(fmt.Sprintf("%d. %s", number, title), style)
|
p := newParagraph(fmt.Sprintf("%d. %s", number, title), style)
|
||||||
p.SetFont(style.Font)
|
p.SetFont(style.Font)
|
||||||
p.SetFontSize(16)
|
p.SetFontSize(16)
|
||||||
@ -55,6 +62,7 @@ func newChapter(toc *TOC, title string, number int, style TextStyle) *Chapter {
|
|||||||
showNumbering: true,
|
showNumbering: true,
|
||||||
includeInTOC: true,
|
includeInTOC: true,
|
||||||
toc: toc,
|
toc: toc,
|
||||||
|
outline: outline,
|
||||||
heading: p,
|
heading: p,
|
||||||
contents: []Drawable{},
|
contents: []Drawable{},
|
||||||
}
|
}
|
||||||
@ -141,21 +149,43 @@ func (chap *Chapter) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext,
|
|||||||
ctx.Page++ // Did not fit, moved to new Page block.
|
ctx.Page++ // Did not fit, moved to new Page block.
|
||||||
}
|
}
|
||||||
|
|
||||||
if chap.includeInTOC {
|
// Generate chapter title and number.
|
||||||
// Add to TOC.
|
chapTitle := chap.title
|
||||||
chapNumber := ""
|
var chapNumber string
|
||||||
if chap.showNumbering {
|
page := int64(ctx.Page)
|
||||||
if chap.number != 0 {
|
|
||||||
chapNumber = strconv.Itoa(chap.number) + "."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
line := chap.toc.Add(chapNumber, chap.title, strconv.Itoa(ctx.Page), 1)
|
if chap.showNumbering {
|
||||||
if chap.toc.showLinks {
|
if chap.number != 0 {
|
||||||
line.SetLink(int64(ctx.Page), origX, origY)
|
chapNumber = strconv.Itoa(chap.number) + "."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if chapNumber != "" {
|
||||||
|
chapTitle = fmt.Sprintf("%s %s", chapNumber, chapTitle)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to TOC.
|
||||||
|
if chap.includeInTOC {
|
||||||
|
line := chap.toc.Add(chapNumber, chap.title, strconv.FormatInt(page, 10), 1)
|
||||||
|
if chap.toc.showLinks {
|
||||||
|
line.SetLink(page, origX, origY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to outline.
|
||||||
|
if chap.outlineItem == nil {
|
||||||
|
chap.outlineItem = model.NewOutlineItem(
|
||||||
|
chapTitle,
|
||||||
|
model.NewOutlineDest(page-1, origX, origY),
|
||||||
|
)
|
||||||
|
chap.outline.Add(chap.outlineItem)
|
||||||
|
} else {
|
||||||
|
outlineDest := &chap.outlineItem.Dest
|
||||||
|
outlineDest.Page = page - 1
|
||||||
|
outlineDest.X = origX
|
||||||
|
outlineDest.Y = origY
|
||||||
|
}
|
||||||
|
|
||||||
for _, d := range chap.contents {
|
for _, d := range chap.contents {
|
||||||
newBlocks, c, err := d.GeneratePageBlocks(ctx)
|
newBlocks, c, err := d.GeneratePageBlocks(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -43,11 +43,17 @@ type Creator struct {
|
|||||||
|
|
||||||
finalized bool
|
finalized bool
|
||||||
|
|
||||||
|
// Controls whether a table of contents will be generated.
|
||||||
|
AddTOC bool
|
||||||
|
|
||||||
// The table of contents.
|
// The table of contents.
|
||||||
toc *TOC
|
toc *TOC
|
||||||
|
|
||||||
// Controls whether a table of contents will be added.
|
// Controls whether outlines will be generated.
|
||||||
AddTOC bool
|
AddOutlines bool
|
||||||
|
|
||||||
|
// Outline.
|
||||||
|
outline *model.Outline
|
||||||
|
|
||||||
// Forms.
|
// Forms.
|
||||||
acroForm *model.PdfAcroForm
|
acroForm *model.PdfAcroForm
|
||||||
@ -125,6 +131,10 @@ func New() *Creator {
|
|||||||
// Initialize creator table of contents.
|
// Initialize creator table of contents.
|
||||||
c.toc = c.NewTOC("Table of Contents")
|
c.toc = c.NewTOC("Table of Contents")
|
||||||
|
|
||||||
|
// Initialize outline.
|
||||||
|
c.AddOutlines = true
|
||||||
|
c.outline = model.NewOutline()
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -420,6 +430,44 @@ func (c *Creator) finalize() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Account for the front page and the table of content pages.
|
||||||
|
if c.outline != nil && c.AddOutlines {
|
||||||
|
var adjustOutlineDest func(item *model.OutlineItem)
|
||||||
|
adjustOutlineDest = func(item *model.OutlineItem) {
|
||||||
|
item.Dest.Page += int64(genpages)
|
||||||
|
|
||||||
|
// Reverse the Y axis of the destination coordinates.
|
||||||
|
// The user passes in the annotation coordinates as if
|
||||||
|
// position 0, 0 is at the top left of the page.
|
||||||
|
// However, position 0, 0 in the PDF is at the bottom
|
||||||
|
// left of the page.
|
||||||
|
item.Dest.Y = c.pageHeight - item.Dest.Y
|
||||||
|
|
||||||
|
outlineItems := item.Items()
|
||||||
|
for _, outlineItem := range outlineItems {
|
||||||
|
adjustOutlineDest(outlineItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outlineItems := c.outline.Items()
|
||||||
|
for _, outlineItem := range outlineItems {
|
||||||
|
adjustOutlineDest(outlineItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add outline TOC item.
|
||||||
|
if c.AddTOC {
|
||||||
|
var tocPage int64
|
||||||
|
if hasFrontPage {
|
||||||
|
tocPage = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
c.outline.Insert(0, model.NewOutlineItem(
|
||||||
|
"Table of Contents",
|
||||||
|
model.NewOutlineDest(tocPage, 0, c.pageHeight),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for idx, page := range c.pages {
|
for idx, page := range c.pages {
|
||||||
c.setActivePage(page)
|
c.setActivePage(page)
|
||||||
if c.drawHeaderFunc != nil {
|
if c.drawHeaderFunc != nil {
|
||||||
@ -540,7 +588,12 @@ func (c *Creator) Write(ws io.Writer) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pdf Writer access hook. Can be used to encrypt, etc. via the PdfWriter instance.
|
// Outlines.
|
||||||
|
if c.outline != nil && c.AddOutlines {
|
||||||
|
pdfWriter.AddOutlineTree(&c.outline.ToPdfOutline().PdfOutlineTreeNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pdf Writer access hook. Can be used to encrypt, etc. via the PdfWriter instance.
|
||||||
if c.pdfWriterAccessFunc != nil {
|
if c.pdfWriterAccessFunc != nil {
|
||||||
err := c.pdfWriterAccessFunc(&pdfWriter)
|
err := c.pdfWriterAccessFunc(&pdfWriter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -661,7 +714,7 @@ func (c *Creator) NewStyledTOCLine(number, title, page TextChunk, level uint, st
|
|||||||
// NewChapter creates a new chapter with the specified title as the heading.
|
// NewChapter creates a new chapter with the specified title as the heading.
|
||||||
func (c *Creator) NewChapter(title string) *Chapter {
|
func (c *Creator) NewChapter(title string) *Chapter {
|
||||||
c.chapters++
|
c.chapters++
|
||||||
return newChapter(c.toc, title, c.chapters, c.NewTextStyle())
|
return newChapter(c.toc, c.outline, title, c.chapters, c.NewTextStyle())
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSubchapter creates a new Subchapter under Chapter ch with specified title.
|
// NewSubchapter creates a new Subchapter under Chapter ch with specified title.
|
||||||
|
@ -10,12 +10,12 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/unidoc/unidoc/common"
|
"github.com/unidoc/unidoc/common"
|
||||||
|
"github.com/unidoc/unidoc/pdf/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Subchapter simply represents a sub chapter pertaining to a specific Chapter. It can contain
|
// Subchapter simply represents a sub chapter pertaining to a specific Chapter. It can contain
|
||||||
// multiple Drawables, just like a chapter.
|
// multiple Drawables, just like a chapter.
|
||||||
type Subchapter struct {
|
type Subchapter struct {
|
||||||
chapterNum int
|
|
||||||
subchapterNum int
|
subchapterNum int
|
||||||
title string
|
title string
|
||||||
heading *Paragraph
|
heading *Paragraph
|
||||||
@ -39,6 +39,15 @@ type Subchapter struct {
|
|||||||
|
|
||||||
// Reference to the creator's TOC.
|
// Reference to the creator's TOC.
|
||||||
toc *TOC
|
toc *TOC
|
||||||
|
|
||||||
|
// Reference to the chapter the subchapter belongs to.
|
||||||
|
chapter *Chapter
|
||||||
|
|
||||||
|
// Reference to the outline of the creator.
|
||||||
|
outline *model.Outline
|
||||||
|
|
||||||
|
// The item of the subchapter in the outline.
|
||||||
|
outlineItem *model.OutlineItem
|
||||||
}
|
}
|
||||||
|
|
||||||
// newSubchapter creates a new Subchapter under Chapter ch with specified title.
|
// newSubchapter creates a new Subchapter under Chapter ch with specified title.
|
||||||
@ -52,13 +61,14 @@ func newSubchapter(ch *Chapter, title string, style TextStyle) *Subchapter {
|
|||||||
|
|
||||||
subchapter := &Subchapter{
|
subchapter := &Subchapter{
|
||||||
subchapterNum: ch.subchapters,
|
subchapterNum: ch.subchapters,
|
||||||
chapterNum: ch.number,
|
|
||||||
title: title,
|
title: title,
|
||||||
showNumbering: true,
|
showNumbering: true,
|
||||||
includeInTOC: true,
|
includeInTOC: true,
|
||||||
heading: p,
|
heading: p,
|
||||||
contents: []Drawable{},
|
contents: []Drawable{},
|
||||||
|
chapter: ch,
|
||||||
toc: ch.toc,
|
toc: ch.toc,
|
||||||
|
outline: ch.outline,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add subchapter to chapter.
|
// Add subchapter to chapter.
|
||||||
@ -70,7 +80,7 @@ func newSubchapter(ch *Chapter, title string, style TextStyle) *Subchapter {
|
|||||||
// SetShowNumbering sets a flag to indicate whether or not to show chapter numbers as part of title.
|
// SetShowNumbering sets a flag to indicate whether or not to show chapter numbers as part of title.
|
||||||
func (subchap *Subchapter) SetShowNumbering(show bool) {
|
func (subchap *Subchapter) SetShowNumbering(show bool) {
|
||||||
if show {
|
if show {
|
||||||
heading := fmt.Sprintf("%d.%d. %s", subchap.chapterNum, subchap.subchapterNum, subchap.title)
|
heading := fmt.Sprintf("%d.%d. %s", subchap.chapter.number, subchap.subchapterNum, subchap.title)
|
||||||
subchap.heading.SetText(heading)
|
subchap.heading.SetText(heading)
|
||||||
} else {
|
} else {
|
||||||
heading := fmt.Sprintf("%s", subchap.title)
|
heading := fmt.Sprintf("%s", subchap.title)
|
||||||
@ -148,29 +158,51 @@ func (subchap *Subchapter) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawCo
|
|||||||
if len(blocks) > 1 {
|
if len(blocks) > 1 {
|
||||||
ctx.Page++ // did not fit - moved to next Page.
|
ctx.Page++ // did not fit - moved to next Page.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate subchapter title and number.
|
||||||
|
subchapTitle := subchap.title
|
||||||
|
var subchapNumber string
|
||||||
|
page := int64(ctx.Page)
|
||||||
|
|
||||||
|
if subchap.showNumbering {
|
||||||
|
if subchap.chapter.number != 0 {
|
||||||
|
subchapNumber = strconv.Itoa(subchap.chapter.number)
|
||||||
|
}
|
||||||
|
if subchap.subchapterNum != 0 {
|
||||||
|
if subchapNumber != "" {
|
||||||
|
subchapNumber += "."
|
||||||
|
}
|
||||||
|
|
||||||
|
subchapNumber += strconv.Itoa(subchap.subchapterNum) + "."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if subchapNumber != "" {
|
||||||
|
subchapTitle = fmt.Sprintf("%s %s", subchapNumber, subchapTitle)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to TOC.
|
||||||
if subchap.includeInTOC {
|
if subchap.includeInTOC {
|
||||||
// Add to TOC.
|
line := subchap.toc.Add(subchapNumber, subchap.title, strconv.FormatInt(page, 10), 2)
|
||||||
subchapNumber := ""
|
|
||||||
|
|
||||||
if subchap.showNumbering {
|
|
||||||
if subchap.chapterNum != 0 {
|
|
||||||
subchapNumber = strconv.Itoa(subchap.chapterNum)
|
|
||||||
}
|
|
||||||
if subchap.subchapterNum != 0 {
|
|
||||||
if subchapNumber != "" {
|
|
||||||
subchapNumber += "."
|
|
||||||
}
|
|
||||||
|
|
||||||
subchapNumber += strconv.Itoa(subchap.subchapterNum) + "."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
line := subchap.toc.Add(subchapNumber, subchap.title, strconv.Itoa(ctx.Page), 2)
|
|
||||||
if subchap.toc.showLinks {
|
if subchap.toc.showLinks {
|
||||||
line.SetLink(int64(ctx.Page), origX, origY)
|
line.SetLink(page, origX, origY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add to outline.
|
||||||
|
if subchap.outlineItem == nil {
|
||||||
|
subchap.outlineItem = model.NewOutlineItem(
|
||||||
|
subchapTitle,
|
||||||
|
model.NewOutlineDest(page-1, origX, origY),
|
||||||
|
)
|
||||||
|
subchap.chapter.outlineItem.Add(subchap.outlineItem)
|
||||||
|
} else {
|
||||||
|
outlineDest := &subchap.outlineItem.Dest
|
||||||
|
outlineDest.Page = page - 1
|
||||||
|
outlineDest.X = origX
|
||||||
|
outlineDest.Y = origY
|
||||||
|
}
|
||||||
|
|
||||||
for _, d := range subchap.contents {
|
for _, d := range subchap.contents {
|
||||||
newBlocks, c, err := d.GeneratePageBlocks(ctx)
|
newBlocks, c, err := d.GeneratePageBlocks(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
193
pdf/model/outline.go
Normal file
193
pdf/model/outline.go
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
/*
|
||||||
|
* This file is subject to the terms and conditions defined in
|
||||||
|
* file 'LICENSE.md', which is part of this source code package.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/unidoc/unidoc/pdf/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OutlineDest represents the destination of an outline item.
|
||||||
|
// It holds the page and the position on the page an outline item points to.
|
||||||
|
type OutlineDest struct {
|
||||||
|
Page int64
|
||||||
|
X float64
|
||||||
|
Y float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOutlineDest returns a new outline destination which can be used
|
||||||
|
// with outline items.
|
||||||
|
func NewOutlineDest(page int64, x, y float64) OutlineDest {
|
||||||
|
return OutlineDest{
|
||||||
|
Page: page,
|
||||||
|
X: x,
|
||||||
|
Y: y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToPdfObject returns a PDF object representation of the outline destination.
|
||||||
|
func (od OutlineDest) ToPdfObject() core.PdfObject {
|
||||||
|
return core.MakeArray(
|
||||||
|
core.MakeInteger(od.Page),
|
||||||
|
core.MakeName("XYZ"),
|
||||||
|
core.MakeFloat(od.X),
|
||||||
|
core.MakeFloat(od.Y),
|
||||||
|
core.MakeFloat(0),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Outline represents a PDF outline dictionary (Table 152 - p. 376).
|
||||||
|
// Currently, the Outline object can only be used to construct PDF outlines.
|
||||||
|
type Outline struct {
|
||||||
|
items []*OutlineItem
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOutline returns a new outline instance.
|
||||||
|
func NewOutline() *Outline {
|
||||||
|
return &Outline{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add appends a top level outline item to the outline.
|
||||||
|
func (o *Outline) Add(item *OutlineItem) {
|
||||||
|
o.items = append(o.items, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert adds a top level outline item in the outline,
|
||||||
|
// at the specified index.
|
||||||
|
func (o *Outline) Insert(index uint, item *OutlineItem) {
|
||||||
|
l := uint(len(o.items))
|
||||||
|
if index > l {
|
||||||
|
index = l
|
||||||
|
}
|
||||||
|
|
||||||
|
o.items = append(o.items[:index], append([]*OutlineItem{item}, o.items[index:]...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Items returns all children outline items.
|
||||||
|
func (o *Outline) Items() []*OutlineItem {
|
||||||
|
return o.items
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToPdfOutline returns a low level PdfOutline object, based on the current
|
||||||
|
// instance.
|
||||||
|
func (o *Outline) ToPdfOutline() *PdfOutline {
|
||||||
|
// Create outline.
|
||||||
|
outline := NewPdfOutline()
|
||||||
|
|
||||||
|
// Create outline items.
|
||||||
|
var outlineItems []*PdfOutlineItem
|
||||||
|
var prev *PdfOutlineItem
|
||||||
|
|
||||||
|
for _, item := range o.items {
|
||||||
|
outlineItem, _ := item.ToPdfOutlineItem()
|
||||||
|
outlineItem.Parent = &outline.PdfOutlineTreeNode
|
||||||
|
|
||||||
|
if prev != nil {
|
||||||
|
prev.Next = &outlineItem.PdfOutlineTreeNode
|
||||||
|
outlineItem.Prev = &prev.PdfOutlineTreeNode
|
||||||
|
}
|
||||||
|
|
||||||
|
outlineItems = append(outlineItems, outlineItem)
|
||||||
|
prev = outlineItem
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add outline linked list properties.
|
||||||
|
lenOutlineItems := int64(len(outlineItems))
|
||||||
|
if lenOutlineItems > 0 {
|
||||||
|
outline.First = &outlineItems[0].PdfOutlineTreeNode
|
||||||
|
outline.Last = &outlineItems[lenOutlineItems-1].PdfOutlineTreeNode
|
||||||
|
outline.Count = &lenOutlineItems
|
||||||
|
}
|
||||||
|
|
||||||
|
return outline
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToPdfObject returns a PDF object representation of the outline.
|
||||||
|
func (o *Outline) ToPdfObject() core.PdfObject {
|
||||||
|
return o.ToPdfOutline().ToPdfObject()
|
||||||
|
}
|
||||||
|
|
||||||
|
// OutlineItem represents a PDF outline item dictionary (Table 153 - pp. 376 - 377).
|
||||||
|
type OutlineItem struct {
|
||||||
|
Title string
|
||||||
|
Dest OutlineDest
|
||||||
|
|
||||||
|
items []*OutlineItem
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOutlineItem returns a new outline item instance.
|
||||||
|
func NewOutlineItem(title string, dest OutlineDest) *OutlineItem {
|
||||||
|
return &OutlineItem{
|
||||||
|
Title: title,
|
||||||
|
Dest: dest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add appends an outline item as a child of the current outline item.
|
||||||
|
func (oi *OutlineItem) Add(item *OutlineItem) {
|
||||||
|
oi.items = append(oi.items, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert adds an outline item as a child of the current outline item,
|
||||||
|
// at the specified index.
|
||||||
|
func (oi *OutlineItem) Insert(index uint, item *OutlineItem) {
|
||||||
|
l := uint(len(oi.items))
|
||||||
|
if index > l {
|
||||||
|
index = l
|
||||||
|
}
|
||||||
|
|
||||||
|
oi.items = append(oi.items[:index], append([]*OutlineItem{item}, oi.items[index:]...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Items returns all children outline items.
|
||||||
|
func (oi *OutlineItem) Items() []*OutlineItem {
|
||||||
|
return oi.items
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToPdfOutlineItem returns a low level PdfOutlineItem object,
|
||||||
|
// based on the current instance.
|
||||||
|
func (oi *OutlineItem) ToPdfOutlineItem() (*PdfOutlineItem, int64) {
|
||||||
|
// Create outline item.
|
||||||
|
currItem := NewPdfOutlineItem()
|
||||||
|
currItem.Title = core.MakeString(oi.Title)
|
||||||
|
currItem.Dest = oi.Dest.ToPdfObject()
|
||||||
|
|
||||||
|
// Create outline items.
|
||||||
|
var outlineItems []*PdfOutlineItem
|
||||||
|
var lenDescendants int64
|
||||||
|
var prev *PdfOutlineItem
|
||||||
|
|
||||||
|
for _, item := range oi.items {
|
||||||
|
outlineItem, lenChildren := item.ToPdfOutlineItem()
|
||||||
|
outlineItem.Parent = &currItem.PdfOutlineTreeNode
|
||||||
|
|
||||||
|
if prev != nil {
|
||||||
|
prev.Next = &outlineItem.PdfOutlineTreeNode
|
||||||
|
outlineItem.Prev = &prev.PdfOutlineTreeNode
|
||||||
|
}
|
||||||
|
|
||||||
|
outlineItems = append(outlineItems, outlineItem)
|
||||||
|
lenDescendants += lenChildren
|
||||||
|
prev = outlineItem
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add outline item linked list properties.
|
||||||
|
lenOutlineItems := len(outlineItems)
|
||||||
|
lenDescendants += int64(lenOutlineItems)
|
||||||
|
|
||||||
|
if lenOutlineItems > 0 {
|
||||||
|
currItem.First = &outlineItems[0].PdfOutlineTreeNode
|
||||||
|
currItem.Last = &outlineItems[lenOutlineItems-1].PdfOutlineTreeNode
|
||||||
|
currItem.Count = &lenDescendants
|
||||||
|
}
|
||||||
|
|
||||||
|
return currItem, lenDescendants
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToPdfObject returns a PDF object representation of the outline item.
|
||||||
|
func (oi *OutlineItem) ToPdfObject() core.PdfObject {
|
||||||
|
outlineItem, _ := oi.ToPdfOutlineItem()
|
||||||
|
return outlineItem.ToPdfObject()
|
||||||
|
}
|
@ -46,13 +46,11 @@ type PdfOutlineItem struct {
|
|||||||
|
|
||||||
// NewPdfOutline returns an initialized PdfOutline.
|
// NewPdfOutline returns an initialized PdfOutline.
|
||||||
func NewPdfOutline() *PdfOutline {
|
func NewPdfOutline() *PdfOutline {
|
||||||
outline := &PdfOutline{}
|
outline := &PdfOutline{
|
||||||
|
primitive: MakeIndirectObject(MakeDict()),
|
||||||
container := &PdfIndirectObject{}
|
}
|
||||||
container.PdfObject = MakeDict()
|
|
||||||
|
|
||||||
outline.primitive = container
|
|
||||||
|
|
||||||
|
outline.context = outline
|
||||||
return outline
|
return outline
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,12 +63,11 @@ func NewPdfOutlineTree() *PdfOutline {
|
|||||||
|
|
||||||
// NewPdfOutlineItem returns an initialized PdfOutlineItem.
|
// NewPdfOutlineItem returns an initialized PdfOutlineItem.
|
||||||
func NewPdfOutlineItem() *PdfOutlineItem {
|
func NewPdfOutlineItem() *PdfOutlineItem {
|
||||||
outlineItem := &PdfOutlineItem{}
|
outlineItem := &PdfOutlineItem{
|
||||||
|
primitive: MakeIndirectObject(MakeDict()),
|
||||||
|
}
|
||||||
|
|
||||||
container := &PdfIndirectObject{}
|
outlineItem.context = outlineItem
|
||||||
container.PdfObject = MakeDict()
|
|
||||||
|
|
||||||
outlineItem.primitive = container
|
|
||||||
return outlineItem
|
return outlineItem
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,6 +250,10 @@ func (o *PdfOutline) ToPdfObject() PdfObject {
|
|||||||
dict.Set("Parent", o.Parent.getOuter().GetContainingPdfObject())
|
dict.Set("Parent", o.Parent.getOuter().GetContainingPdfObject())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if o.Count != nil {
|
||||||
|
dict.Set("Count", MakeInteger(*o.Count))
|
||||||
|
}
|
||||||
|
|
||||||
return container
|
return container
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user