fix wrong git ignore
This commit is contained in:
294
internal/pdf/model/outlines.go
Normal file
294
internal/pdf/model/outlines.go
Normal file
@@ -0,0 +1,294 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gitea.tecamino.com/paadi/pdfmerge/internal/pdf/common"
|
||||
"gitea.tecamino.com/paadi/pdfmerge/internal/pdf/core"
|
||||
)
|
||||
|
||||
type PdfOutlineTreeNode struct {
|
||||
context any // Allow accessing outer structure.
|
||||
First *PdfOutlineTreeNode
|
||||
Last *PdfOutlineTreeNode
|
||||
}
|
||||
|
||||
// PDF outline dictionary (Table 152 - p. 376).
|
||||
type PdfOutline struct {
|
||||
PdfOutlineTreeNode
|
||||
Parent *PdfOutlineTreeNode
|
||||
Count *int64
|
||||
|
||||
primitive *core.PdfIndirectObject
|
||||
}
|
||||
|
||||
// Pdf outline item dictionary (Table 153 - pp. 376 - 377).
|
||||
type PdfOutlineItem struct {
|
||||
PdfOutlineTreeNode
|
||||
Title *core.PdfObjectString
|
||||
Parent *PdfOutlineTreeNode
|
||||
Prev *PdfOutlineTreeNode
|
||||
Next *PdfOutlineTreeNode
|
||||
Count *int64
|
||||
Dest core.PdfObject
|
||||
A core.PdfObject
|
||||
SE core.PdfObject
|
||||
C core.PdfObject
|
||||
F core.PdfObject
|
||||
|
||||
primitive *core.PdfIndirectObject
|
||||
}
|
||||
|
||||
func NewPdfOutline() *PdfOutline {
|
||||
outline := &PdfOutline{}
|
||||
|
||||
container := &core.PdfIndirectObject{}
|
||||
container.PdfObject = core.MakeDict()
|
||||
|
||||
outline.primitive = container
|
||||
|
||||
return outline
|
||||
}
|
||||
|
||||
func NewPdfOutlineTree() *PdfOutline {
|
||||
outlineTree := NewPdfOutline()
|
||||
outlineTree.context = &outlineTree
|
||||
return outlineTree
|
||||
}
|
||||
|
||||
func NewPdfOutlineItem() *PdfOutlineItem {
|
||||
outlineItem := &PdfOutlineItem{}
|
||||
|
||||
container := &core.PdfIndirectObject{}
|
||||
container.PdfObject = core.MakeDict()
|
||||
|
||||
outlineItem.primitive = container
|
||||
return outlineItem
|
||||
}
|
||||
|
||||
func NewOutlineBookmark(title string, page *core.PdfIndirectObject) *PdfOutlineItem {
|
||||
bookmark := PdfOutlineItem{}
|
||||
bookmark.context = &bookmark
|
||||
|
||||
bookmark.Title = core.MakeString(title)
|
||||
|
||||
destArray := core.PdfObjectArray{}
|
||||
destArray = append(destArray, page)
|
||||
destArray = append(destArray, core.MakeName("Fit"))
|
||||
bookmark.Dest = &destArray
|
||||
|
||||
return &bookmark
|
||||
}
|
||||
|
||||
// Does not traverse the tree.
|
||||
func newPdfOutlineFromIndirectObject(container *core.PdfIndirectObject) (*PdfOutline, error) {
|
||||
dict, isDict := container.PdfObject.(*core.PdfObjectDictionary)
|
||||
if !isDict {
|
||||
return nil, fmt.Errorf("outline object not a dictionary")
|
||||
}
|
||||
|
||||
outline := PdfOutline{}
|
||||
outline.primitive = container
|
||||
outline.context = &outline
|
||||
|
||||
if obj := dict.Get("Type"); obj != nil {
|
||||
typeVal, ok := obj.(*core.PdfObjectName)
|
||||
if ok {
|
||||
if *typeVal != "Outlines" {
|
||||
common.Log.Debug("error Type != Outlines (%s)", *typeVal)
|
||||
// Should be "Outlines" if there, but some files have other types
|
||||
// Log as an error but do not quit.
|
||||
// Might be a good idea to log this kind of deviation from the standard separately.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if obj := dict.Get("Count"); obj != nil {
|
||||
// This should always be an integer, but in a few cases has been a float.
|
||||
count, err := getNumberAsInt64(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outline.Count = &count
|
||||
}
|
||||
|
||||
return &outline, nil
|
||||
}
|
||||
|
||||
// Does not traverse the tree.
|
||||
func (pr *PdfReader) newPdfOutlineItemFromIndirectObject(container *core.PdfIndirectObject) (*PdfOutlineItem, error) {
|
||||
dict, isDict := container.PdfObject.(*core.PdfObjectDictionary)
|
||||
if !isDict {
|
||||
return nil, fmt.Errorf("outline object not a dictionary")
|
||||
}
|
||||
|
||||
item := PdfOutlineItem{}
|
||||
item.primitive = container
|
||||
item.context = &item
|
||||
|
||||
// Title (required).
|
||||
obj := dict.Get("Title")
|
||||
if obj == nil {
|
||||
return nil, fmt.Errorf("missing Title from Outline Item (required)")
|
||||
}
|
||||
obj, err := pr.traceToObject(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
title, ok := core.TraceToDirectObject(obj).(*core.PdfObjectString)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("title not a string (%T)", obj)
|
||||
}
|
||||
item.Title = title
|
||||
|
||||
// Count (optional).
|
||||
if obj := dict.Get("Count"); obj != nil {
|
||||
countVal, ok := obj.(*core.PdfObjectInteger)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("count not an integer (%T)", obj)
|
||||
}
|
||||
count := int64(*countVal)
|
||||
item.Count = &count
|
||||
}
|
||||
|
||||
// Other keys.
|
||||
if obj := dict.Get("Dest"); obj != nil {
|
||||
item.Dest, err = pr.traceToObject(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err := pr.traverseObjectData(item.Dest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if obj := dict.Get("A"); obj != nil {
|
||||
item.A, err = pr.traceToObject(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err := pr.traverseObjectData(item.A)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if obj := dict.Get("SE"); obj != nil {
|
||||
// XXX: To add structure element support.
|
||||
// Currently not supporting structure elements.
|
||||
item.SE = nil
|
||||
}
|
||||
if obj := dict.Get("C"); obj != nil {
|
||||
item.C, err = pr.traceToObject(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if obj := dict.Get("F"); obj != nil {
|
||||
item.F, err = pr.traceToObject(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &item, nil
|
||||
}
|
||||
|
||||
// Get the outer object of the tree node (Outline or OutlineItem).
|
||||
func (n *PdfOutlineTreeNode) getOuter() PdfModel {
|
||||
if outline, isOutline := n.context.(*PdfOutline); isOutline {
|
||||
return outline
|
||||
}
|
||||
if outlineItem, isOutlineItem := n.context.(*PdfOutlineItem); isOutlineItem {
|
||||
return outlineItem
|
||||
}
|
||||
|
||||
common.Log.Debug("error Invalid outline tree node item") // Should never happen.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pot *PdfOutlineTreeNode) GetContainingPdfObject() core.PdfObject {
|
||||
return pot.getOuter().GetContainingPdfObject()
|
||||
}
|
||||
|
||||
func (pot *PdfOutlineTreeNode) ToPdfObject() core.PdfObject {
|
||||
return pot.getOuter().ToPdfObject()
|
||||
}
|
||||
|
||||
func (po *PdfOutline) GetContainingPdfObject() core.PdfObject {
|
||||
return po.primitive
|
||||
}
|
||||
|
||||
// Recursively build the Outline tree PDF object.
|
||||
func (po *PdfOutline) ToPdfObject() core.PdfObject {
|
||||
container := po.primitive
|
||||
dict := container.PdfObject.(*core.PdfObjectDictionary)
|
||||
|
||||
dict.Set("Type", core.MakeName("Outlines"))
|
||||
|
||||
if po.First != nil {
|
||||
dict.Set("First", po.First.ToPdfObject())
|
||||
}
|
||||
|
||||
if po.Last != nil {
|
||||
dict.Set("Last", po.Last.getOuter().GetContainingPdfObject())
|
||||
//PdfObjectConverterCache[this.Last.getOuter()]
|
||||
}
|
||||
|
||||
if po.Parent != nil {
|
||||
dict.Set("Parent", po.Parent.getOuter().GetContainingPdfObject())
|
||||
}
|
||||
|
||||
return container
|
||||
}
|
||||
|
||||
func (poi *PdfOutlineItem) GetContainingPdfObject() core.PdfObject {
|
||||
return poi.primitive
|
||||
}
|
||||
|
||||
// Outline item.
|
||||
// Recursively build the Outline tree PDF object.
|
||||
func (poi *PdfOutlineItem) ToPdfObject() core.PdfObject {
|
||||
container := poi.primitive
|
||||
dict := container.PdfObject.(*core.PdfObjectDictionary)
|
||||
|
||||
dict.Set("Title", poi.Title)
|
||||
if poi.A != nil {
|
||||
dict.Set("A", poi.A)
|
||||
}
|
||||
if obj := dict.Get("SE"); obj != nil {
|
||||
// XXX: Currently not supporting structure element hierarchy.
|
||||
// Remove it.
|
||||
dict.Remove("SE")
|
||||
// delete(*dict, "SE")
|
||||
}
|
||||
|
||||
if poi.C != nil {
|
||||
dict.Set("C", poi.C)
|
||||
}
|
||||
if poi.Dest != nil {
|
||||
dict.Set("Dest", poi.Dest)
|
||||
}
|
||||
if poi.F != nil {
|
||||
dict.Set("F", poi.F)
|
||||
}
|
||||
if poi.Count != nil {
|
||||
dict.Set("Count", core.MakeInteger(*poi.Count))
|
||||
}
|
||||
if poi.Next != nil {
|
||||
dict.Set("Next", poi.Next.ToPdfObject())
|
||||
}
|
||||
if poi.First != nil {
|
||||
dict.Set("First", poi.First.ToPdfObject())
|
||||
}
|
||||
if poi.Prev != nil {
|
||||
dict.Set("Prev", poi.Prev.getOuter().GetContainingPdfObject())
|
||||
}
|
||||
if poi.Last != nil {
|
||||
dict.Set("Last", poi.Last.getOuter().GetContainingPdfObject())
|
||||
}
|
||||
if poi.Parent != nil {
|
||||
dict.Set("Parent", poi.Parent.getOuter().GetContainingPdfObject())
|
||||
}
|
||||
|
||||
return container
|
||||
}
|
||||
Reference in New Issue
Block a user