Skip to content

Commit

Permalink
Add bookmarks cmd, Fix #506, #621, #671, bump version
Browse files Browse the repository at this point in the history
  • Loading branch information
hhrutter committed Aug 20, 2023
1 parent be32323 commit 1d309dc
Show file tree
Hide file tree
Showing 90 changed files with 3,137 additions and 1,209 deletions.
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Expand Up @@ -18,6 +18,7 @@ jobs:
goarch: amd64
go:
- '1.20.x'
- '1.21.x'
runs-on: ubuntu-latest

steps:
Expand Down
22 changes: 16 additions & 6 deletions .goreleaser.yml
Expand Up @@ -5,23 +5,33 @@ builds:
ldflags:
- '-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'
goos:
- ios
- js
- linux
- darwin
- windows
goarch:
- "386"
- arm64
- wasm
- amd64
dist: ./dist
archives:
-
format: tar.xz
format_overrides:
- goos: windows
format: zip
replacements:
darwin: macOS
linux: Linux
windows: Windows
386: i386
amd64: x86_64
name_template: >-
{{- .ProjectName }}_
{{- .Version }}_
{{- title .Os }}_
{{- if eq .Arch "linux" }}Linux
{{- else if eq .Arch "windows" }}Windows
{{- else if eq .Arch "386" }}i386
{{- else if eq .Arch "amd64" }}x86_64
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}v{{ .Arm }}{{ end -}}
wrap_in_directory: true
checksum:
name_template: 'checksums.txt'
Expand Down
25 changes: 13 additions & 12 deletions README.md
Expand Up @@ -46,6 +46,7 @@ The main focus lies on strong support for batch processing and scripting via a r
* [annotations](https://pdfcpu.io/annot/annot)
* [attachments](https://pdfcpu.io/attach/attach)
* [booklet](https://pdfcpu.io/generate/booklet)
* [bookmarks](https://pdfcpu.io/bookmarks/bookmarks)
* [boxes](https://pdfcpu.io/boxes/boxes)
* [change owner password](https://pdfcpu.io/encrypt/change_opw)
* [change user password](https://pdfcpu.io/encrypt/change_upw)
Expand Down Expand Up @@ -115,30 +116,30 @@ Get the latest binary [here](https://github.com/pdfcpu/pdfcpu/releases).
### Using Go Modules

```
git clone https://github.com/pdfcpu/pdfcpu
cd pdfcpu/cmd/pdfcpu
go install
pdfcpu version
$ git clone https://github.com/pdfcpu/pdfcpu
$ cd pdfcpu/cmd/pdfcpu
$ go install
$ pdfcpu version
```

### Using Homebrew (macOS)
```
brew install pdfcpu
pdfcpu version
$ brew install pdfcpu
$ pdfcpu version
```

### Using DNF/YUM (Fedora)
```
sudo dnf install golang-github-pdfcpu
pdfcpu version
$ sudo dnf install golang-github-pdfcpu
$ pdfcpu version
```

### Run in a Docker container

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

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

``` sh
pdfcpu validate -v &> crash.log
$ pdfcpu validate -v &> crash.log
```

or to produce very verbose output

``` sh
pdfcpu validate -vv &> crash.log
$ pdfcpu validate -vv &> crash.log
```

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 hhrutter@gmail.com or if you prefer Slack you can get in touch on the Gopher slack #pdfcpu channel.
Expand Down
64 changes: 42 additions & 22 deletions cmd/pdfcpu/init.go
Expand Up @@ -41,6 +41,16 @@ func initCommandMap() {
attachCmdMap.register(k, v)
}

bookmarksCmdMap := newCommandMap()
for k, v := range map[string]command{
"list": {processListBookmarksCommand, nil, "", ""},
"import": {processImportBookmarksCommand, nil, "", ""},
"export": {processExportBookmarksCommand, nil, "", ""},
"remove": {processRemoveBookmarksCommand, nil, "", ""},
} {
bookmarksCmdMap.register(k, v)
}

boxesCmdMap := newCommandMap()
for k, v := range map[string]command{
"list": {processListBoxesCommand, nil, "", ""},
Expand Down Expand Up @@ -147,6 +157,7 @@ func initCommandMap() {
for k, v := range map[string]command{
"annotations": {nil, annotsCmdMap, usageAnnots, usageLongAnnots},
"attachments": {nil, attachCmdMap, usageAttach, usageLongAttach},
"bookmarks": {nil, bookmarksCmdMap, usageBookmarks, usageLongBookmarks},
"booklet": {processBookletCommand, nil, usageBooklet, usageLongBooklet},
"boxes": {nil, boxesCmdMap, usageBoxes, usageLongBoxes},
"changeopw": {processChangeOwnerPasswordCommand, nil, usageChangeOwnerPW, usageLongChangeOwnerPW},
Expand Down Expand Up @@ -193,54 +204,63 @@ func initCommandMap() {
}

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

modeUsage := "validate: strict|relaxed; extract: image|font|content|page|meta; encrypt: rc4|aes, stamp:text|image/pdf"
flag.StringVar(&mode, "mode", "", modeUsage)
flag.StringVar(&mode, "m", "", modeUsage)
bookmarksUsage := "create bookmarks while merging"
flag.BoolVar(&bookmarks, "bookmarks", true, bookmarksUsage)
flag.BoolVar(&bookmarks, "b", true, bookmarksUsage)

confUsage := "the config directory path | skip | none"
flag.StringVar(&conf, "config", "", confUsage)
flag.StringVar(&conf, "conf", "", confUsage)
flag.StringVar(&conf, "c", "", confUsage)

jsonUsage := "produce JSON output"
flag.BoolVar(&json, "json", false, jsonUsage)
flag.BoolVar(&json, "j", false, jsonUsage)

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

permUsage := "encrypt, perm set: none|all"
flag.StringVar(&perm, "perm", "none", permUsage)
linksUsage := "check for broken links"
flag.BoolVar(&links, "links", false, linksUsage)
flag.BoolVar(&links, "l", false, linksUsage)

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

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

permUsage := "encrypt, perm set: none|all"
flag.StringVar(&perm, "perm", "none", permUsage)

flag.BoolVar(&quiet, "quiet", false, "")
flag.BoolVar(&quiet, "q", false, "")

replaceUsage := "replace existing bookmarks"
flag.BoolVar(&replaceBookmarks, "replace", false, replaceUsage)
flag.BoolVar(&replaceBookmarks, "r", false, replaceUsage)

sortUsage := "sort files before merging"
flag.BoolVar(&sorted, "sort", false, sortUsage)
flag.BoolVar(&sorted, "s", false, sortUsage)

bookmarksUsage := "create bookmarks while merging"
flag.BoolVar(&bookmarks, "bookmarks", true, bookmarksUsage)
flag.BoolVar(&bookmarks, "b", true, bookmarksUsage)
statsUsage := "optimize: create a csv file for stats"
flag.StringVar(&fileStats, "stats", "", statsUsage)

unitUsage := "info: po|in|cm|mm"
flag.StringVar(&unit, "unit", "", unitUsage)
flag.StringVar(&unit, "u", "", unitUsage)

flag.BoolVar(&verbose, "verbose", false, "")
flag.BoolVar(&verbose, "v", false, "")
flag.BoolVar(&veryVerbose, "vv", false, "")

linksUsage := "check for broken links"
flag.BoolVar(&links, "links", false, linksUsage)
flag.BoolVar(&links, "l", false, linksUsage)

flag.StringVar(&upw, "upw", "", "user password")
flag.StringVar(&opw, "opw", "", "owner password")

confUsage := "the config directory path | skip | none"
flag.StringVar(&conf, "config", "", confUsage)
flag.StringVar(&conf, "conf", "", confUsage)
flag.StringVar(&conf, "c", "", confUsage)
}

func initLogging(verbose, veryVerbose bool) {
Expand Down
1 change: 1 addition & 0 deletions cmd/pdfcpu/main.go
Expand Up @@ -27,6 +27,7 @@ var (
upw, opw, key, perm, unit, conf string
verbose, veryVerbose bool
links, quiet, sorted, bookmarks bool
json, replaceBookmarks bool
needStackTrace = true
cmdMap commandMap
)
Expand Down
79 changes: 78 additions & 1 deletion cmd/pdfcpu/process.go
Expand Up @@ -1337,7 +1337,7 @@ func processInfoCommand(conf *model.Configuration) {

processDiplayUnit(conf)

process(cli.InfoCommand(filesIn, selectedPages, conf))
process(cli.InfoCommand(filesIn, selectedPages, json, conf))
}

func processListFontsCommand(conf *model.Configuration) {
Expand Down Expand Up @@ -2239,3 +2239,80 @@ func processCutCommand(conf *model.Configuration) {

process(cli.CutCommand(inFile, outDir, outFile, selectedPages, cut, conf))
}

func processListBookmarksCommand(conf *model.Configuration) {
if len(flag.Args()) < 1 || selectedPages != "" {
fmt.Fprintf(os.Stderr, "usage: %s\n\n", usageBookmarksList)
os.Exit(1)
}

inFile := flag.Arg(0)
if conf.CheckFileNameExt {
ensurePDFExtension(inFile)
}

process(cli.ListBookmarksCommand(inFile, conf))
}

func processExportBookmarksCommand(conf *model.Configuration) {
if len(flag.Args()) == 0 || len(flag.Args()) > 2 || selectedPages != "" {
fmt.Fprintf(os.Stderr, "usage: %s\n\n", usageBookmarksExport)
os.Exit(1)
}

inFile := flag.Arg(0)
if conf.CheckFileNameExt {
ensurePDFExtension(inFile)
}

outFileJSON := "out.json"
if len(flag.Args()) == 2 {
outFileJSON = flag.Arg(1)
ensureJSONExtension(outFileJSON)
}

process(cli.ExportBookmarksCommand(inFile, outFileJSON, conf))
}

func processImportBookmarksCommand(conf *model.Configuration) {
if len(flag.Args()) == 0 || len(flag.Args()) > 3 || selectedPages != "" {
fmt.Fprintf(os.Stderr, "usage: %s\n\n", usageBookmarksImport)
os.Exit(1)
}

inFile := flag.Arg(0)
if conf.CheckFileNameExt {
ensurePDFExtension(inFile)
}

inFileJSON := flag.Arg(1)
ensureJSONExtension(inFileJSON)

outFile := ""
if len(flag.Args()) == 3 {
outFile = flag.Arg(2)
ensurePDFExtension(outFile)
}

process(cli.ImportBookmarksCommand(inFile, inFileJSON, outFile, replaceBookmarks, conf))
}

func processRemoveBookmarksCommand(conf *model.Configuration) {
if len(flag.Args()) == 0 || len(flag.Args()) > 2 || selectedPages != "" {
fmt.Fprintf(os.Stderr, "usage: %s\n\n", usageBookmarksExport)
os.Exit(1)
}

inFile := flag.Arg(0)
if conf.CheckFileNameExt {
ensurePDFExtension(inFile)
}

outFile := ""
if len(flag.Args()) == 2 {
outFile = flag.Arg(1)
ensurePDFExtension(outFile)
}

process(cli.RemoveBookmarksCommand(inFile, outFile, conf))
}

0 comments on commit 1d309dc

Please sign in to comment.