Skip to content

Commit 967b294

Browse files
committed
Add option to give page range for merge
1 parent 7782951 commit 967b294

2 files changed

Lines changed: 42 additions & 13 deletions

File tree

cmd/merge.go

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,61 @@
11
package cmd
22

33
import (
4+
"errors"
45
"fmt"
56
"io"
67
"os"
8+
"strings"
79

810
"github.com/klippa-app/go-pdfium/requests"
911

1012
"github.com/klippa-app/pdfium-cli/pdf"
1113
"github.com/spf13/cobra"
1214
)
1315

16+
// parseFileWithPageRange parses a file argument that may contain an optional page range
17+
// in the format "filename.pdf[1-3]". Returns the filename and page range string.
18+
// If no page range is specified, returns "first-last" as the page range.
19+
func parseFileWithPageRange(arg string) (string, string) {
20+
if strings.HasSuffix(arg, "]") {
21+
bracketIdx := strings.LastIndex(arg, "[")
22+
if bracketIdx != -1 {
23+
pageRange := arg[bracketIdx+1 : len(arg)-1]
24+
if pageRange != "" {
25+
return arg[:bracketIdx], pageRange
26+
}
27+
}
28+
}
29+
return arg, "first-last"
30+
}
31+
1432
func init() {
1533
addGenericPDFOptions(mergeCmd)
34+
addIgnoreInvalidPagesOption(mergeCmd)
1635
rootCmd.AddCommand(mergeCmd)
1736
}
1837

1938
var mergeCmd = &cobra.Command{
20-
Use: "merge [input] [input] ([input]...) [output]",
39+
Use: "merge [input] ([input]...) [output]",
2140
Short: "Merge multiple PDFs into a single PDF",
22-
Long: "Merge multiple PDFs into a single PDF.\n[output] can either be a file path or - for stdout.",
41+
Long: "Merge multiple PDFs into a single PDF.\n[output] can either be a file path or - for stdout.\nEach [input] can optionally include a page range using the syntax filename.pdf[{pagerange}],\nfor example invoice.pdf[1-3] to include only pages 1, 2 and 3.",
2342
Args: func(cmd *cobra.Command, args []string) error {
43+
if len(args) < 1 {
44+
return newExitCodeError(errors.New("no input given"), ExitCodeInvalidArguments)
45+
}
2446
if args[0] == stdFilename {
25-
if err := cobra.MinimumNArgs(2)(cmd, args); err != nil {
47+
if err := cobra.MinimumNArgs(1)(cmd, args); err != nil {
2648
return newExitCodeError(err, ExitCodeInvalidArguments)
2749
}
2850
} else {
29-
if err := cobra.MinimumNArgs(3)(cmd, args); err != nil {
51+
if err := cobra.MinimumNArgs(2)(cmd, args); err != nil {
3052
return newExitCodeError(err, ExitCodeInvalidArguments)
3153
}
3254

3355
for i := 0; i < len(args)-1; i++ {
34-
if _, err := os.Stat(args[i]); err != nil {
35-
return fmt.Errorf("could not open input file %s: %w", args[0], newExitCodeError(err, ExitCodeInvalidInput))
56+
filename, _ := parseFileWithPageRange(args[i])
57+
if _, err := os.Stat(filename); err != nil {
58+
return fmt.Errorf("could not open input file %s: %w", filename, newExitCodeError(err, ExitCodeInvalidInput))
3659
}
3760
}
3861
}
@@ -57,14 +80,16 @@ var mergeCmd = &cobra.Command{
5780
i := 0
5881
for true {
5982
var filename string
83+
var filePageRange string
6084
if args[0] == stdFilename {
6185
filename = stdFilename
86+
filePageRange = "first-last"
6287
} else {
6388
// Reached last file.
6489
if i == len(args)-1 {
6590
break
6691
}
67-
filename = args[i]
92+
filename, filePageRange = parseFileWithPageRange(args[i])
6893
}
6994

7095
document, closeFile, err := openFile(filename)
@@ -73,7 +98,7 @@ var mergeCmd = &cobra.Command{
7398
if err == stdinNoMoreFiles {
7499
break
75100
}
76-
handleError(cmd, fmt.Errorf("could not open input file %s: %w\n", args[i], err), ExitCodeInvalidInput)
101+
handleError(cmd, fmt.Errorf("could not open input file %s: %w\n", filename, err), ExitCodeInvalidInput)
77102
return
78103
}
79104

@@ -86,14 +111,14 @@ var mergeCmd = &cobra.Command{
86111
})
87112
if err != nil {
88113
closeFunc()
89-
handleError(cmd, fmt.Errorf("could not get page ranges for file %s: %w", args[i], newPdfiumError(err)), ExitCodePdfiumError)
114+
handleError(cmd, fmt.Errorf("could not get page ranges for file %s: %w", filename, newPdfiumError(err)), ExitCodePdfiumError)
90115
return
91116
}
92117

93-
pageRange, calculatedPageCount, err := pdf.NormalizePageRange(pageCount.PageCount, "first-last", false)
118+
pageRange, calculatedPageCount, err := pdf.NormalizePageRange(pageCount.PageCount, filePageRange, ignoreInvalidPages)
94119
if err != nil {
95120
closeFunc()
96-
handleError(cmd, fmt.Errorf("invalid page range 'first-last': %w\n", err), ExitCodeInvalidPageRange)
121+
handleError(cmd, fmt.Errorf("invalid page range '%s' for file %s: %w\n", filePageRange, filename, err), ExitCodeInvalidPageRange)
97122
return
98123
}
99124

@@ -105,7 +130,7 @@ var mergeCmd = &cobra.Command{
105130
})
106131
if err != nil {
107132
closeFunc()
108-
handleError(cmd, fmt.Errorf("could not import pages for file %s: %w", args[i], newPdfiumError(err)), ExitCodePdfiumError)
133+
handleError(cmd, fmt.Errorf("could not import pages for file %s: %w", filename, newPdfiumError(err)), ExitCodePdfiumError)
109134
return
110135
}
111136

@@ -116,7 +141,7 @@ var mergeCmd = &cobra.Command{
116141
})
117142
if err != nil {
118143
closeFunc()
119-
handleError(cmd, fmt.Errorf("could not close document for file %s: %w", args[i], newPdfiumError(err)), ExitCodePdfiumError)
144+
handleError(cmd, fmt.Errorf("could not close document for file %s: %w", filename, newPdfiumError(err)), ExitCodePdfiumError)
120145
return
121146
}
122147

cmd/pdf.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ func addGenericPDFOptions(command *cobra.Command) {
3030

3131
func addPagesOption(intro string, command *cobra.Command) {
3232
command.Flags().StringVarP(&pages, "pages", "", "first-last", intro+". Ranges are like '1-3,5', which will result in a PDF file with pages 1, 2, 3 and 5. You can use the keywords first and last. You can prepend a page number with r to start counting from the end. Examples: use '2-last' for the second page until the last page, use '3-r1' for page 3 until the second-last page.")
33+
addIgnoreInvalidPagesOption(command)
34+
}
35+
36+
func addIgnoreInvalidPagesOption(command *cobra.Command) {
3337
command.Flags().BoolVarP(&ignoreInvalidPages, "ignore-invalid-pages", "", false, "Ignore non-existing pages in the pages option.")
3438
}
3539

0 commit comments

Comments
 (0)