Skip invalid outline nodes (#101)

* Skip invalid outline nodes when building outline tree
* Add methods for accessing and writing named destinations
This commit is contained in:
Adrian-George Bostan 2019-06-27 23:08:40 +03:00 committed by Gunnsteinn Hall
parent f5989ea574
commit 13e08e064c
3 changed files with 48 additions and 17 deletions

View File

@ -95,9 +95,7 @@ func newPdfOutlineFromIndirectObject(container *core.PdfIndirectObject) (*PdfOut
return nil, fmt.Errorf("outline object not a dictionary")
}
outline := PdfOutline{}
outline.primitive = container
outline.context = &outline
outline := NewPdfOutline()
if obj := dict.Get("Type"); obj != nil {
typeVal, ok := obj.(*core.PdfObjectName)
@ -120,7 +118,7 @@ func newPdfOutlineFromIndirectObject(container *core.PdfIndirectObject) (*PdfOut
outline.Count = &count
}
return &outline, nil
return outline, nil
}
// Does not traverse the tree.
@ -130,9 +128,7 @@ func (r *PdfReader) newPdfOutlineItemFromIndirectObject(container *core.PdfIndir
return nil, fmt.Errorf("outline object not a dictionary")
}
item := PdfOutlineItem{}
item.primitive = container
item.context = &item
item := NewPdfOutlineItem()
// Title (required).
obj := dict.Get("Title")
@ -186,7 +182,7 @@ func (r *PdfReader) newPdfOutlineItemFromIndirectObject(container *core.PdfIndir
item.F = core.ResolveReference(obj)
}
return &item, nil
return item, nil
}
// Get the outer object of the tree node (Outline or OutlineItem).

View File

@ -338,10 +338,11 @@ func (r *PdfReader) buildOutlineTree(obj core.PdfObject, parent *PdfOutlineTreeN
if !core.IsNullObject(firstObj) {
first, last, err := r.buildOutlineTree(firstObj, &outlineItem.PdfOutlineTreeNode, nil)
if err != nil {
return nil, nil, err
common.Log.Debug("DEBUG: could not build outline item tree: %v. Skipping node children.", err)
} else {
outlineItem.First = first
outlineItem.Last = last
}
outlineItem.First = first
outlineItem.Last = last
}
}
@ -351,10 +352,11 @@ func (r *PdfReader) buildOutlineTree(obj core.PdfObject, parent *PdfOutlineTreeN
if _, isNull := nextObj.(*core.PdfObjectNull); !isNull {
next, last, err := r.buildOutlineTree(nextObj, parent, &outlineItem.PdfOutlineTreeNode)
if err != nil {
return nil, nil, err
common.Log.Debug("DEBUG: could not build outline tree for Next node: %v. Skipping node.", err)
} else {
outlineItem.Next = next
return &outlineItem.PdfOutlineTreeNode, last, nil
}
outlineItem.Next = next
return &outlineItem.PdfOutlineTreeNode, last, nil
}
}
@ -375,10 +377,11 @@ func (r *PdfReader) buildOutlineTree(obj core.PdfObject, parent *PdfOutlineTreeN
if _, isNull := firstObjDirect.(*core.PdfObjectNull); !isNull && firstObjDirect != nil {
first, last, err := r.buildOutlineTree(firstObj, &outline.PdfOutlineTreeNode, nil)
if err != nil {
return nil, nil, err
common.Log.Debug("DEBUG: could not build outline tree: %v. Skipping node children.", err)
} else {
outline.First = first
outline.Last = last
}
outline.First = first
outline.Last = last
}
}
@ -736,6 +739,25 @@ func (r *PdfReader) GetOCProperties() (core.PdfObject, error) {
return obj, nil
}
// GetNamedDestinations returns the Names entry in the PDF catalog.
// See section 12.3.2.3 "Named Destinations" (p. 367 PDF32000_2008).
func (r *PdfReader) GetNamedDestinations() (core.PdfObject, error) {
obj := core.ResolveReference(r.catalog.Get("Names"))
if obj == nil {
return nil, nil
}
// Resolve references.
if !r.isLazy {
err := r.traverseObjectData(obj)
if err != nil {
return nil, err
}
}
return obj, nil
}
// Inspect inspects the object types, subtypes and content in the PDF file returning a map of
// object type to number of instances of each.
func (r *PdfReader) Inspect() (map[string]int, error) {

View File

@ -409,6 +409,19 @@ func (w *PdfWriter) SetOCProperties(ocProperties core.PdfObject) error {
return nil
}
// SetNamedDestinations sets the Names entry in the PDF catalog.
// See section 12.3.2.3 "Named Destinations" (p. 367 PDF32000_2008).
func (w *PdfWriter) SetNamedDestinations(names core.PdfObject) error {
if names == nil {
return nil
}
common.Log.Trace("Setting catalog Names...")
w.catalog.Set("Names", names)
w.addObjects(names)
return nil
}
// SetOptimizer sets the optimizer to optimize PDF before writing.
func (w *PdfWriter) SetOptimizer(optimizer Optimizer) {
w.optimizer = optimizer