Skip to content

Commit d77fba2

Browse files
committed
Fix #608, #632, #650
1 parent fd12f8b commit d77fba2

28 files changed

+539
-158
lines changed

cmd/pdfcpu/init.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,10 @@ func initFlags() {
222222
flag.BoolVar(&sorted, "sort", false, sortUsage)
223223
flag.BoolVar(&sorted, "s", false, sortUsage)
224224

225+
bookmarksUsage := "create bookmarks while merging"
226+
flag.BoolVar(&bookmarks, "bookmarks", true, bookmarksUsage)
227+
flag.BoolVar(&bookmarks, "b", true, bookmarksUsage)
228+
225229
flag.BoolVar(&verbose, "verbose", false, "")
226230
flag.BoolVar(&verbose, "v", false, "")
227231
flag.BoolVar(&veryVerbose, "vv", false, "")

cmd/pdfcpu/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ var (
2626
fileStats, mode, selectedPages string
2727
upw, opw, key, perm, unit, conf string
2828
verbose, veryVerbose bool
29-
links, quiet, sorted bool
29+
links, quiet, sorted, bookmarks bool
3030
needStackTrace = true
3131
cmdMap commandMap
3232
)

cmd/pdfcpu/process.go

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,13 @@ func processMergeCommand(conf *model.Configuration) {
319319

320320
}
321321

322+
if conf == nil {
323+
conf = model.NewDefaultConfiguration()
324+
conf.CreateBookmarks = bookmarks
325+
}
326+
327+
conf.CreateBookmarks = bookmarks
328+
322329
var cmd *cli.Command
323330

324331
switch mode {
@@ -1301,14 +1308,26 @@ func processDiplayUnit(conf *model.Configuration) {
13011308
}
13021309

13031310
func processInfoCommand(conf *model.Configuration) {
1304-
if len(flag.Args()) != 1 {
1311+
if len(flag.Args()) < 1 {
13051312
fmt.Fprintf(os.Stderr, "%s\n\n", usageInfo)
13061313
os.Exit(1)
13071314
}
13081315

1309-
inFile := flag.Arg(0)
1310-
if conf.CheckFileNameExt {
1311-
ensurePDFExtension(inFile)
1316+
filesIn := []string{}
1317+
for _, arg := range flag.Args() {
1318+
if strings.Contains(arg, "*") {
1319+
matches, err := filepath.Glob(arg)
1320+
if err != nil {
1321+
fmt.Fprintf(os.Stderr, "%s", err)
1322+
os.Exit(1)
1323+
}
1324+
filesIn = append(filesIn, matches...)
1325+
continue
1326+
}
1327+
if conf.CheckFileNameExt {
1328+
ensurePDFExtension(arg)
1329+
}
1330+
filesIn = append(filesIn, arg)
13121331
}
13131332

13141333
selectedPages, err := api.ParsePageSelection(selectedPages)
@@ -1319,7 +1338,7 @@ func processInfoCommand(conf *model.Configuration) {
13191338

13201339
processDiplayUnit(conf)
13211340

1322-
process(cli.InfoCommand(inFile, selectedPages, conf))
1341+
process(cli.InfoCommand(filesIn, selectedPages, conf))
13231342
}
13241343

13251344
func processListFontsCommand(conf *model.Configuration) {

cmd/pdfcpu/usage.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,12 @@ The split modes are:
122122
span will be ignored.
123123
Assumption: inFile contains an outline dictionary.`
124124

125-
usageMerge = "usage: pdfcpu merge [-m(ode) create|append] [-s(ort)] outFile inFile..." + generalFlags
125+
usageMerge = "usage: pdfcpu merge [-m(ode) create|append] [-s(ort) -b(ookmarks)] outFile inFile..." + generalFlags
126126
usageLongMerge = `Concatenate a sequence of PDFs/inFiles into outFile.
127127
128128
mode ... merge mode (defaults to create)
129129
sort ... sort inFiles by file name
130+
bookmarks ... create bookmarks
130131
outFile ... output pdf file
131132
inFile ... a list of pdf files subject to concatenation.
132133
@@ -135,7 +136,9 @@ The merge modes are:
135136
create ... outFile will be created and possibly overwritten (default).
136137
137138
append ... if outFile does not exist, it will be created (like in default mode).
138-
if outFile already exists, inFiles will be appended to outFile.`
139+
if outFile already exists, inFiles will be appended to outFile.
140+
141+
Skip bookmark creation like so: -bookmarks=false`
139142

140143
usagePageSelection = `'-pages' selects pages for processing and is a comma separated list of expressions:
141144
@@ -769,11 +772,11 @@ Examples: pdfcpu grid out.pdf 1 10 in.pdf
769772
usageSelectedPages = "usage: pdfcpu selectedpages"
770773
usageLongSelectedPages = "Print definition of the -pages flag."
771774

772-
usageInfo = "usage: pdfcpu info [-p(ages) selectedPages] inFile" + generalFlags
775+
usageInfo = "usage: pdfcpu info [-p(ages) selectedPages] inFile..." + generalFlags
773776
usageLongInfo = `Print info about a PDF file.
774777
775778
pages ... Please refer to "pdfcpu selectedpages"
776-
inFile ... input pdf file`
779+
inFile ... a list of pdf input files`
777780

778781
usageFontsList = "pdfcpu fonts list"
779782
usageFontsInstall = "pdfcpu fonts install fontFiles..."

pkg/api/info.go

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package api
1818

1919
import (
20+
"fmt"
2021
"io"
2122
"os"
2223
"time"
@@ -52,10 +53,35 @@ func Info(rs io.ReadSeeker, selectedPages []string, conf *model.Configuration) (
5253

5354
// InfoFile returns information about inFile.
5455
func InfoFile(inFile string, selectedPages []string, conf *model.Configuration) ([]string, error) {
56+
5557
f, err := os.Open(inFile)
5658
if err != nil {
5759
return nil, err
5860
}
5961
defer f.Close()
60-
return Info(f, selectedPages, conf)
62+
ss, err := Info(f, selectedPages, conf)
63+
s := fmt.Sprintf("%s:", inFile)
64+
return append([]string{s}, ss...), err
65+
}
66+
67+
// InfoFile returns information about inFile.
68+
func InfoFiles(inFiles []string, selectedPages []string, conf *model.Configuration) ([]string, error) {
69+
70+
var ss []string
71+
72+
for i, fn := range inFiles {
73+
if i > 0 {
74+
ss = append(ss, "")
75+
}
76+
ssx, err := InfoFile(fn, selectedPages, conf)
77+
if err != nil {
78+
if len(inFiles) == 1 {
79+
return nil, err
80+
}
81+
fmt.Fprintf(os.Stderr, "%s: %v\n", fn, err)
82+
}
83+
ss = append(ss, ssx...)
84+
}
85+
86+
return ss, nil
6187
}

pkg/api/merge.go

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ package api
1919
import (
2020
"io"
2121
"os"
22+
"path/filepath"
23+
"strconv"
2224
"time"
2325

2426
"github.com/pdfcpu/pdfcpu/pkg/log"
@@ -28,14 +30,14 @@ import (
2830
)
2931

3032
// appendTo appends inFile to ctxDest's page tree.
31-
func appendTo(rs io.ReadSeeker, ctxDest *model.Context) error {
33+
func appendTo(rs io.ReadSeeker, fName string, ctxDest *model.Context) error {
3234
ctxSource, _, _, err := readAndValidate(rs, ctxDest.Configuration, time.Now())
3335
if err != nil {
3436
return err
3537
}
3638

3739
// Merge source context into dest context.
38-
return pdfcpu.MergeXRefTables(ctxSource, ctxDest)
40+
return pdfcpu.MergeXRefTables(fName, ctxSource, ctxDest)
3941
}
4042

4143
// MergeRaw merges a sequence of PDF streams and writes the result to w.
@@ -61,8 +63,8 @@ func MergeRaw(rsc []io.ReadSeeker, w io.Writer, conf *model.Configuration) error
6163

6264
ctxDest.EnsureVersionForWriting()
6365

64-
for _, f := range rsc[1:] {
65-
if err = appendTo(f, ctxDest); err != nil {
66+
for i, f := range rsc[1:] {
67+
if err = appendTo(f, strconv.Itoa(i), ctxDest); err != nil {
6668
return err
6769
}
6870
}
@@ -112,6 +114,12 @@ func Merge(destFile string, inFiles []string, w io.Writer, conf *model.Configura
112114
return err
113115
}
114116

117+
if conf.CreateBookmarks {
118+
if err := pdfcpu.EnsureOutlines(ctxDest, filepath.Base(destFile)); err != nil {
119+
return err
120+
}
121+
}
122+
115123
ctxDest.EnsureVersionForWriting()
116124

117125
for _, fName := range inFiles {
@@ -123,7 +131,7 @@ func Merge(destFile string, inFiles []string, w io.Writer, conf *model.Configura
123131
defer f.Close()
124132

125133
log.CLI.Println(fName)
126-
if err = appendTo(f, ctxDest); err != nil {
134+
if err = appendTo(f, filepath.Base(fName), ctxDest); err != nil {
127135
return err
128136
}
129137

@@ -138,12 +146,6 @@ func Merge(destFile string, inFiles []string, w io.Writer, conf *model.Configura
138146
return err
139147
}
140148

141-
if conf.ValidationMode != model.ValidationNone {
142-
if err := ValidateContext(ctxDest); err != nil {
143-
return err
144-
}
145-
}
146-
147149
return WriteContext(ctxDest, w)
148150
}
149151

pkg/api/test/bookmark_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func TestAddSimpleBookmarks(t *testing.T) {
4545
{PageFrom: 16, Title: "Page 16: The birthday of Smalltalk", Color: &bookmarkColor},
4646
{PageFrom: 17, Title: "Page 17: Gray", Color: &color.Gray},
4747
{PageFrom: 18, Title: "Page 18: Red", Color: &color.Red},
48-
{PageFrom: 19, Title: "Page 19: Bold Red ", Color: &color.Red, Bold: true},
48+
{PageFrom: 19, Title: "Page 19: Bold Red", Color: &color.Red, Bold: true},
4949
}
5050

5151
replace := true // Replace existing bookmarks.

pkg/api/test/merge_test.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"testing"
2424

2525
"github.com/pdfcpu/pdfcpu/pkg/api"
26+
"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/model"
2627
)
2728

2829
func TestMergeCreateNew(t *testing.T) {
@@ -31,11 +32,16 @@ func TestMergeCreateNew(t *testing.T) {
3132
filepath.Join(inDir, "Acroforms2.pdf"),
3233
filepath.Join(inDir, "adobe_errata.pdf"),
3334
}
34-
outFile := filepath.Join(outDir, "test.pdf")
35+
outFile := filepath.Join(outDir, "out.pdf")
3536

3637
// Merge inFiles by concatenation in the order specified and write the result to outFile.
3738
// outFile will be overwritten.
38-
if err := api.MergeCreateFile(inFiles, outFile, nil); err != nil {
39+
40+
// Bookmarks for the merged document will be created/preserved per default (see config.yaml)
41+
conf := model.NewDefaultConfiguration()
42+
//conf.CreateBookmarks = false
43+
44+
if err := api.MergeCreateFile(inFiles, outFile, conf); err != nil {
3945
t.Fatalf("%s: %v\n", msg, err)
4046
}
4147
}

pkg/cli/cli.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ func ExtractAttachments(cmd *Command) ([]string, error) {
180180

181181
// Info gathers information about inFile and returns the result as []string.
182182
func Info(cmd *Command) ([]string, error) {
183-
return api.InfoFile(*cmd.InFile, cmd.PageSelection, cmd.Conf)
183+
return api.InfoFiles(cmd.InFiles, cmd.PageSelection, cmd.Conf)
184184
}
185185

186186
// CreateCheatSheetsFonts creates single page PDF cheat sheets for user fonts in current dir.

pkg/cli/cmd.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -542,14 +542,14 @@ func BookletCommand(inFiles []string, outFile string, pageSelection []string, nu
542542
}
543543

544544
// InfoCommand creates a new command to output information about inFile.
545-
func InfoCommand(inFile string, pageSelection []string, conf *model.Configuration) *Command {
545+
func InfoCommand(inFiles []string, pageSelection []string, conf *model.Configuration) *Command {
546546
if conf == nil {
547547
conf = model.NewDefaultConfiguration()
548548
}
549549
conf.Cmd = model.INFO
550550
return &Command{
551551
Mode: model.INFO,
552-
InFile: &inFile,
552+
InFiles: inFiles,
553553
PageSelection: pageSelection,
554554
Conf: conf}
555555
}

0 commit comments

Comments
 (0)