-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbookmark.go
More file actions
171 lines (155 loc) · 4.09 KB
/
bookmark.go
File metadata and controls
171 lines (155 loc) · 4.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
package gopdf
import (
"errors"
"fmt"
)
var (
ErrBookmarkNotFound = errors.New("bookmark not found")
ErrBookmarkOutOfRange = errors.New("bookmark index out of range")
)
// BookmarkStyle defines visual styling for a bookmark entry.
type BookmarkStyle struct {
// Bold makes the bookmark title bold.
Bold bool
// Italic makes the bookmark title italic.
Italic bool
// Color is the bookmark text color [R, G, B] (0.0-1.0). Zero value = default (black).
Color [3]float64
// Collapsed controls whether child bookmarks are initially hidden.
Collapsed bool
}
// ModifyBookmark modifies the title of a bookmark at the given 0-based index
// in the flat TOC list (as returned by GetTOC).
//
// Example:
//
// pdf.ModifyBookmark(0, "New Chapter Title")
func (gp *GoPdf) ModifyBookmark(index int, newTitle string) error {
outlineObjs := gp.getOutlineObjList()
if index < 0 || index >= len(outlineObjs) {
return ErrBookmarkOutOfRange
}
outlineObjs[index].title = newTitle
return nil
}
// DeleteBookmark removes a bookmark at the given 0-based index in the flat
// TOC list. Child bookmarks are also removed.
//
// Example:
//
// pdf.DeleteBookmark(2) // remove the 3rd bookmark
func (gp *GoPdf) DeleteBookmark(index int) error {
outlineObjs := gp.getOutlineObjList()
if index < 0 || index >= len(outlineObjs) {
return ErrBookmarkOutOfRange
}
target := outlineObjs[index]
// Fix linked list: connect prev to next.
if target.prev > 0 {
for _, o := range outlineObjs {
if o.index == target.prev {
o.next = target.next
break
}
}
}
if target.next > 0 {
for _, o := range outlineObjs {
if o.index == target.next {
o.prev = target.prev
break
}
}
}
// Update parent's first/last if needed.
if target.prev <= 0 {
// This was the first child — update parent's first.
if target.parent == gp.indexOfOutlinesObj+1 {
gp.outlines.first = target.next
} else {
for _, o := range outlineObjs {
if o.index == target.parent {
o.first = target.next
break
}
}
}
}
if target.next <= 0 {
// This was the last child — update parent's last.
if target.parent == gp.indexOfOutlinesObj+1 {
gp.outlines.last = target.prev
} else {
for _, o := range outlineObjs {
if o.index == target.parent {
o.last = target.prev
break
}
}
}
}
// Null out the object.
objIdx := target.index - 1 // convert 1-based to 0-based
if objIdx >= 0 && objIdx < len(gp.pdfObjs) {
gp.pdfObjs[objIdx] = nullObj{}
}
gp.outlines.count--
return nil
}
// SetBookmarkStyle sets the visual style (color, bold, italic, collapsed)
// for a bookmark at the given 0-based index.
//
// Example:
//
// pdf.SetBookmarkStyle(0, gopdf.BookmarkStyle{
// Bold: true,
// Color: [3]float64{1, 0, 0}, // red
// Collapsed: true,
// })
func (gp *GoPdf) SetBookmarkStyle(index int, style BookmarkStyle) error {
outlineObjs := gp.getOutlineObjList()
if index < 0 || index >= len(outlineObjs) {
return ErrBookmarkOutOfRange
}
outlineObjs[index].color = style.Color
outlineObjs[index].bold = style.Bold
outlineObjs[index].italic = style.Italic
outlineObjs[index].collapsed = style.Collapsed
return nil
}
// getOutlineObjList returns all OutlineObj instances in document order.
func (gp *GoPdf) getOutlineObjList() []*OutlineObj {
if gp.outlines == nil || gp.outlines.Count() == 0 {
return nil
}
outlineMap := make(map[int]*OutlineObj)
for i, obj := range gp.pdfObjs {
if o, ok := obj.(*OutlineObj); ok {
outlineMap[i+1] = o
}
}
// Traverse in linked-list order starting from first.
var result []*OutlineObj
visited := make(map[int]bool)
gp.collectOutlineObjs(outlineMap, gp.outlines.first, &result, visited)
return result
}
func (gp *GoPdf) collectOutlineObjs(m map[int]*OutlineObj, objID int, result *[]*OutlineObj, visited map[int]bool) {
if objID <= 0 || visited[objID] {
return
}
visited[objID] = true
o, ok := m[objID]
if !ok {
return
}
*result = append(*result, o)
if o.first > 0 {
gp.collectOutlineObjs(m, o.first, result, visited)
}
if o.next > 0 {
gp.collectOutlineObjs(m, o.next, result, visited)
}
}
// Ensure fmt is used.
var _ = fmt.Sprintf