Skip to content

Commit 1d309dc

Browse files
committed
Add bookmarks cmd, Fix #506, #621, #671, bump version
1 parent be32323 commit 1d309dc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+3137
-1209
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ jobs:
1818
goarch: amd64
1919
go:
2020
- '1.20.x'
21+
- '1.21.x'
2122
runs-on: ubuntu-latest
2223

2324
steps:

.goreleaser.yml

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,33 @@ builds:
55
ldflags:
66
- '-s -w -X main.version={{.Version}} -X github.com/pdfcpu/pdfcpu/pkg/pdfcpu.VersionStr={{.Version}} -X main.commit={{.ShortCommit}} -X main.date={{.Date}} -X main.builtBy=goreleaser'
77
goos:
8+
- ios
89
- js
910
- linux
1011
- darwin
1112
- windows
13+
goarch:
14+
- "386"
15+
- arm64
16+
- wasm
17+
- amd64
1218
dist: ./dist
1319
archives:
1420
-
1521
format: tar.xz
1622
format_overrides:
1723
- goos: windows
1824
format: zip
19-
replacements:
20-
darwin: macOS
21-
linux: Linux
22-
windows: Windows
23-
386: i386
24-
amd64: x86_64
25+
name_template: >-
26+
{{- .ProjectName }}_
27+
{{- .Version }}_
28+
{{- title .Os }}_
29+
{{- if eq .Arch "linux" }}Linux
30+
{{- else if eq .Arch "windows" }}Windows
31+
{{- else if eq .Arch "386" }}i386
32+
{{- else if eq .Arch "amd64" }}x86_64
33+
{{- else }}{{ .Arch }}{{ end }}
34+
{{- if .Arm }}v{{ .Arm }}{{ end -}}
2535
wrap_in_directory: true
2636
checksum:
2737
name_template: 'checksums.txt'

README.md

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ The main focus lies on strong support for batch processing and scripting via a r
4646
* [annotations](https://pdfcpu.io/annot/annot)
4747
* [attachments](https://pdfcpu.io/attach/attach)
4848
* [booklet](https://pdfcpu.io/generate/booklet)
49+
* [bookmarks](https://pdfcpu.io/bookmarks/bookmarks)
4950
* [boxes](https://pdfcpu.io/boxes/boxes)
5051
* [change owner password](https://pdfcpu.io/encrypt/change_opw)
5152
* [change user password](https://pdfcpu.io/encrypt/change_upw)
@@ -115,30 +116,30 @@ Get the latest binary [here](https://github.com/pdfcpu/pdfcpu/releases).
115116
### Using Go Modules
116117

117118
```
118-
git clone https://github.com/pdfcpu/pdfcpu
119-
cd pdfcpu/cmd/pdfcpu
120-
go install
121-
pdfcpu version
119+
$ git clone https://github.com/pdfcpu/pdfcpu
120+
$ cd pdfcpu/cmd/pdfcpu
121+
$ go install
122+
$ pdfcpu version
122123
```
123124

124125
### Using Homebrew (macOS)
125126
```
126-
brew install pdfcpu
127-
pdfcpu version
127+
$ brew install pdfcpu
128+
$ pdfcpu version
128129
```
129130

130131
### Using DNF/YUM (Fedora)
131132
```
132-
sudo dnf install golang-github-pdfcpu
133-
pdfcpu version
133+
$ sudo dnf install golang-github-pdfcpu
134+
$ pdfcpu version
134135
```
135136

136137
### Run in a Docker container
137138

138139
```
139-
docker build -t pdfcpu .
140+
$ docker build -t pdfcpu .
140141
# mount current folder into container to process local files
141-
docker run -it --mount type=bind,source="$(pwd)",target=/app pdfcpu ./pdfcpu validate -mode strict /app/pdfs/a.pdf
142+
$ docker run -it --mount type=bind,source="$(pwd)",target=/app pdfcpu ./pdfcpu validate -mode strict /app/pdfs/a.pdf
142143
```
143144

144145
## Contributing
@@ -166,13 +167,13 @@ For the majority of the cases this is due to a diverse pool of PDF Writers out t
166167
Regardless of the pdfcpu operation, please start using the pdfcpu command line to validate your file:
167168

168169
``` sh
169-
pdfcpu validate -v &> crash.log
170+
$ pdfcpu validate -v &> crash.log
170171
```
171172

172173
or to produce very verbose output
173174

174175
``` sh
175-
pdfcpu validate -vv &> crash.log
176+
$ pdfcpu validate -vv &> crash.log
176177
```
177178

178179
will produce what's needed to investigate a crash. Then open an issue and post `crash.log` or its contents. Ideally post a test PDF you can share to reproduce this. You can also email to [email protected] or if you prefer Slack you can get in touch on the Gopher slack #pdfcpu channel.

cmd/pdfcpu/init.go

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,16 @@ func initCommandMap() {
4141
attachCmdMap.register(k, v)
4242
}
4343

44+
bookmarksCmdMap := newCommandMap()
45+
for k, v := range map[string]command{
46+
"list": {processListBookmarksCommand, nil, "", ""},
47+
"import": {processImportBookmarksCommand, nil, "", ""},
48+
"export": {processExportBookmarksCommand, nil, "", ""},
49+
"remove": {processRemoveBookmarksCommand, nil, "", ""},
50+
} {
51+
bookmarksCmdMap.register(k, v)
52+
}
53+
4454
boxesCmdMap := newCommandMap()
4555
for k, v := range map[string]command{
4656
"list": {processListBoxesCommand, nil, "", ""},
@@ -147,6 +157,7 @@ func initCommandMap() {
147157
for k, v := range map[string]command{
148158
"annotations": {nil, annotsCmdMap, usageAnnots, usageLongAnnots},
149159
"attachments": {nil, attachCmdMap, usageAttach, usageLongAttach},
160+
"bookmarks": {nil, bookmarksCmdMap, usageBookmarks, usageLongBookmarks},
150161
"booklet": {processBookletCommand, nil, usageBooklet, usageLongBooklet},
151162
"boxes": {nil, boxesCmdMap, usageBoxes, usageLongBoxes},
152163
"changeopw": {processChangeOwnerPasswordCommand, nil, usageChangeOwnerPW, usageLongChangeOwnerPW},
@@ -193,54 +204,63 @@ func initCommandMap() {
193204
}
194205

195206
func initFlags() {
196-
statsUsage := "optimize: create a csv file for stats"
197-
flag.StringVar(&fileStats, "stats", "", statsUsage)
198207

199-
modeUsage := "validate: strict|relaxed; extract: image|font|content|page|meta; encrypt: rc4|aes, stamp:text|image/pdf"
200-
flag.StringVar(&mode, "mode", "", modeUsage)
201-
flag.StringVar(&mode, "m", "", modeUsage)
208+
bookmarksUsage := "create bookmarks while merging"
209+
flag.BoolVar(&bookmarks, "bookmarks", true, bookmarksUsage)
210+
flag.BoolVar(&bookmarks, "b", true, bookmarksUsage)
211+
212+
confUsage := "the config directory path | skip | none"
213+
flag.StringVar(&conf, "config", "", confUsage)
214+
flag.StringVar(&conf, "conf", "", confUsage)
215+
flag.StringVar(&conf, "c", "", confUsage)
216+
217+
jsonUsage := "produce JSON output"
218+
flag.BoolVar(&json, "json", false, jsonUsage)
219+
flag.BoolVar(&json, "j", false, jsonUsage)
202220

203221
keyUsage := "encrypt: 40|128|256"
204222
flag.StringVar(&key, "key", "256", keyUsage)
205223
flag.StringVar(&key, "k", "256", keyUsage)
206224

207-
permUsage := "encrypt, perm set: none|all"
208-
flag.StringVar(&perm, "perm", "none", permUsage)
225+
linksUsage := "check for broken links"
226+
flag.BoolVar(&links, "links", false, linksUsage)
227+
flag.BoolVar(&links, "l", false, linksUsage)
209228

210-
unitUsage := "info: po|in|cm|mm"
211-
flag.StringVar(&unit, "unit", "", unitUsage)
212-
flag.StringVar(&unit, "u", "", unitUsage)
229+
modeUsage := "validate: strict|relaxed; extract: image|font|content|page|meta; encrypt: rc4|aes, stamp:text|image/pdf"
230+
flag.StringVar(&mode, "mode", "", modeUsage)
231+
flag.StringVar(&mode, "m", "", modeUsage)
213232

214233
selectedPagesUsage := "a comma separated list of pages or page ranges, see pdfcpu selectedpages"
215234
flag.StringVar(&selectedPages, "pages", "", selectedPagesUsage)
216235
flag.StringVar(&selectedPages, "p", "", selectedPagesUsage)
217236

237+
permUsage := "encrypt, perm set: none|all"
238+
flag.StringVar(&perm, "perm", "none", permUsage)
239+
218240
flag.BoolVar(&quiet, "quiet", false, "")
219241
flag.BoolVar(&quiet, "q", false, "")
220242

243+
replaceUsage := "replace existing bookmarks"
244+
flag.BoolVar(&replaceBookmarks, "replace", false, replaceUsage)
245+
flag.BoolVar(&replaceBookmarks, "r", false, replaceUsage)
246+
221247
sortUsage := "sort files before merging"
222248
flag.BoolVar(&sorted, "sort", false, sortUsage)
223249
flag.BoolVar(&sorted, "s", false, sortUsage)
224250

225-
bookmarksUsage := "create bookmarks while merging"
226-
flag.BoolVar(&bookmarks, "bookmarks", true, bookmarksUsage)
227-
flag.BoolVar(&bookmarks, "b", true, bookmarksUsage)
251+
statsUsage := "optimize: create a csv file for stats"
252+
flag.StringVar(&fileStats, "stats", "", statsUsage)
253+
254+
unitUsage := "info: po|in|cm|mm"
255+
flag.StringVar(&unit, "unit", "", unitUsage)
256+
flag.StringVar(&unit, "u", "", unitUsage)
228257

229258
flag.BoolVar(&verbose, "verbose", false, "")
230259
flag.BoolVar(&verbose, "v", false, "")
231260
flag.BoolVar(&veryVerbose, "vv", false, "")
232261

233-
linksUsage := "check for broken links"
234-
flag.BoolVar(&links, "links", false, linksUsage)
235-
flag.BoolVar(&links, "l", false, linksUsage)
236-
237262
flag.StringVar(&upw, "upw", "", "user password")
238263
flag.StringVar(&opw, "opw", "", "owner password")
239-
240-
confUsage := "the config directory path | skip | none"
241-
flag.StringVar(&conf, "config", "", confUsage)
242-
flag.StringVar(&conf, "conf", "", confUsage)
243-
flag.StringVar(&conf, "c", "", confUsage)
244264
}
245265

246266
func initLogging(verbose, veryVerbose bool) {

cmd/pdfcpu/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ var (
2727
upw, opw, key, perm, unit, conf string
2828
verbose, veryVerbose bool
2929
links, quiet, sorted, bookmarks bool
30+
json, replaceBookmarks bool
3031
needStackTrace = true
3132
cmdMap commandMap
3233
)

cmd/pdfcpu/process.go

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1337,7 +1337,7 @@ func processInfoCommand(conf *model.Configuration) {
13371337

13381338
processDiplayUnit(conf)
13391339

1340-
process(cli.InfoCommand(filesIn, selectedPages, conf))
1340+
process(cli.InfoCommand(filesIn, selectedPages, json, conf))
13411341
}
13421342

13431343
func processListFontsCommand(conf *model.Configuration) {
@@ -2239,3 +2239,80 @@ func processCutCommand(conf *model.Configuration) {
22392239

22402240
process(cli.CutCommand(inFile, outDir, outFile, selectedPages, cut, conf))
22412241
}
2242+
2243+
func processListBookmarksCommand(conf *model.Configuration) {
2244+
if len(flag.Args()) < 1 || selectedPages != "" {
2245+
fmt.Fprintf(os.Stderr, "usage: %s\n\n", usageBookmarksList)
2246+
os.Exit(1)
2247+
}
2248+
2249+
inFile := flag.Arg(0)
2250+
if conf.CheckFileNameExt {
2251+
ensurePDFExtension(inFile)
2252+
}
2253+
2254+
process(cli.ListBookmarksCommand(inFile, conf))
2255+
}
2256+
2257+
func processExportBookmarksCommand(conf *model.Configuration) {
2258+
if len(flag.Args()) == 0 || len(flag.Args()) > 2 || selectedPages != "" {
2259+
fmt.Fprintf(os.Stderr, "usage: %s\n\n", usageBookmarksExport)
2260+
os.Exit(1)
2261+
}
2262+
2263+
inFile := flag.Arg(0)
2264+
if conf.CheckFileNameExt {
2265+
ensurePDFExtension(inFile)
2266+
}
2267+
2268+
outFileJSON := "out.json"
2269+
if len(flag.Args()) == 2 {
2270+
outFileJSON = flag.Arg(1)
2271+
ensureJSONExtension(outFileJSON)
2272+
}
2273+
2274+
process(cli.ExportBookmarksCommand(inFile, outFileJSON, conf))
2275+
}
2276+
2277+
func processImportBookmarksCommand(conf *model.Configuration) {
2278+
if len(flag.Args()) == 0 || len(flag.Args()) > 3 || selectedPages != "" {
2279+
fmt.Fprintf(os.Stderr, "usage: %s\n\n", usageBookmarksImport)
2280+
os.Exit(1)
2281+
}
2282+
2283+
inFile := flag.Arg(0)
2284+
if conf.CheckFileNameExt {
2285+
ensurePDFExtension(inFile)
2286+
}
2287+
2288+
inFileJSON := flag.Arg(1)
2289+
ensureJSONExtension(inFileJSON)
2290+
2291+
outFile := ""
2292+
if len(flag.Args()) == 3 {
2293+
outFile = flag.Arg(2)
2294+
ensurePDFExtension(outFile)
2295+
}
2296+
2297+
process(cli.ImportBookmarksCommand(inFile, inFileJSON, outFile, replaceBookmarks, conf))
2298+
}
2299+
2300+
func processRemoveBookmarksCommand(conf *model.Configuration) {
2301+
if len(flag.Args()) == 0 || len(flag.Args()) > 2 || selectedPages != "" {
2302+
fmt.Fprintf(os.Stderr, "usage: %s\n\n", usageBookmarksExport)
2303+
os.Exit(1)
2304+
}
2305+
2306+
inFile := flag.Arg(0)
2307+
if conf.CheckFileNameExt {
2308+
ensurePDFExtension(inFile)
2309+
}
2310+
2311+
outFile := ""
2312+
if len(flag.Args()) == 2 {
2313+
outFile = flag.Arg(1)
2314+
ensurePDFExtension(outFile)
2315+
}
2316+
2317+
process(cli.RemoveBookmarksCommand(inFile, outFile, conf))
2318+
}

0 commit comments

Comments
 (0)