From 59be9cfc3cb572eabe6d0c3df2e28731c17a258c Mon Sep 17 00:00:00 2001 From: Jeroen Bobbeldijk Date: Tue, 19 Sep 2023 17:57:56 +0200 Subject: [PATCH] Add support for piping --- README.md | 2 ++ cmd/attachments.go | 15 +++----- cmd/explode.go | 52 +++++++++++++++++----------- cmd/images.go | 15 +++----- cmd/info.go | 13 +++---- cmd/javascripts.go | 15 +++----- cmd/merge.go | 34 +++++++++--------- cmd/pdf.go | 71 +++++++++++++++++++++++++++++++++----- cmd/render.go | 86 +++++++++++++++++++++++++++++----------------- cmd/text.go | 15 +++----- cmd/thumbnails.go | 14 +++----- 11 files changed, 192 insertions(+), 140 deletions(-) diff --git a/README.md b/README.md index 8faf321..f0c1694 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,8 @@ * Extracting attachments from PDFs * Extracting thumbnails from PDFs * Extracting JavaScripts from PDFs +* Piping input through stdin when the input is one file +* Piping output through stdout when the output is one file ## PDFium & Wazero diff --git a/cmd/attachments.go b/cmd/attachments.go index 110badf..1529ffa 100644 --- a/cmd/attachments.go +++ b/cmd/attachments.go @@ -19,13 +19,13 @@ func init() { var attachmentsCmd = &cobra.Command{ Use: "attachments [input] [output-folder]", Short: "Extract the attachments of a PDF", - Long: "Extract the attachments of a PDF and store them as file.", + Long: "Extract the attachments of a PDF and store them as file.\n[input] can either be a file path or - for stdin.", Args: func(cmd *cobra.Command, args []string) error { if err := cobra.ExactArgs(2)(cmd, args); err != nil { return err } - if _, err := os.Stat(args[0]); err != nil { + if err := validFile(args[0]); err != nil { return fmt.Errorf("could not open input file %s: %w\n", args[0], err) } @@ -48,19 +48,12 @@ var attachmentsCmd = &cobra.Command{ } defer pdf.ClosePdfium() - file, err := os.Open(args[0]) + document, closeFile, err := openFile(args[0]) if err != nil { cmd.PrintErrf("could not open input file %s: %w\n", args[0], err) return } - defer file.Close() - - document, err := openFile(file) - if err != nil { - cmd.PrintErrf("could not open input file %s: %w\n", args[0], err) - return - } - defer pdf.PdfiumInstance.FPDF_CloseDocument(&requests.FPDF_CloseDocument{Document: document.Document}) + defer closeFile() attachments, err := pdf.PdfiumInstance.GetAttachments(&requests.GetAttachments{ Document: document.Document, diff --git a/cmd/explode.go b/cmd/explode.go index 450c1d6..4f07914 100644 --- a/cmd/explode.go +++ b/cmd/explode.go @@ -2,6 +2,7 @@ package cmd import ( "fmt" + "io" "os" "strings" @@ -21,17 +22,17 @@ func init() { var explodeCmd = &cobra.Command{ Use: "explode [input] [output]", Short: "Explode a PDF into multiple PDFs", - Long: "Explode a PDF into multiple PDFs, the output filename should contain a \"%d\" placeholder for the page number, e.g. split invoice.pdf invoice-%d.pdf, the result for a 2-page PDF will be invoice-1.pdf and invoice-2.pdf.", + Long: "Explode a PDF into multiple PDFs.\n[input] can either be a file path or - for stdin.\n[output] can either be a file path or - for stdout, stdout is only supported when the output will be one file. The output filename should contain a \"%d\" placeholder for the page number, e.g. split invoice.pdf invoice-%d.pdf, the result for a 2-page PDF will be invoice-1.pdf and invoice-2.pdf.", Args: func(cmd *cobra.Command, args []string) error { if err := cobra.ExactArgs(2)(cmd, args); err != nil { return err } - if _, err := os.Stat(args[0]); err != nil { + if err := validFile(args[0]); err != nil { return fmt.Errorf("could not open input file %s: %w\n", args[0], err) } - if !strings.Contains(args[1], "%d") { + if args[1] != stdFilename && !strings.Contains(args[1], "%d") { return fmt.Errorf("output string %s should contain page pattern %%d\n", args[1]) } @@ -45,19 +46,12 @@ var explodeCmd = &cobra.Command{ } defer pdf.ClosePdfium() - file, err := os.Open(args[0]) + document, closeFile, err := openFile(args[0]) if err != nil { cmd.PrintErrf("could not open input file %s: %w\n", args[0], err) return } - defer file.Close() - - document, err := openFile(file) - if err != nil { - cmd.PrintErrf("could not open input file %s: %w\n", args[0], err) - return - } - defer pdf.PdfiumInstance.FPDF_CloseDocument(&requests.FPDF_CloseDocument{Document: document.Document}) + defer closeFile() pageCount, err := pdf.PdfiumInstance.FPDF_GetPageCount(&requests.FPDF_GetPageCount{ Document: document.Document, @@ -79,6 +73,12 @@ var explodeCmd = &cobra.Command{ } splitPages := strings.Split(*parsedPageRange, ",") + + if args[1] == stdFilename && len(splitPages) > 1 { + cmd.PrintErrf("could not explode into multiple pages with output to stdout\n") + return + } + for _, page := range splitPages { newDocument, err := pdf.PdfiumInstance.FPDF_CreateNewDocument(&requests.FPDF_CreateNewDocument{}) if err != nil { @@ -102,27 +102,39 @@ var explodeCmd = &cobra.Command{ } newFilePath := strings.Replace(args[1], "%d", page, -1) - createdFile, err := os.Create(newFilePath) - if err != nil { - cmd.PrintErrf("could not save document for page %s: %w\n", page, err) - return + + var fileWriter io.Writer + if args[1] == stdFilename { + fileWriter = os.Stdout + } else { + createdFile, err := os.Create(newFilePath) + if err != nil { + cmd.PrintErrf("could not save document for page %s: %w\n", page, err) + return + } + fileWriter = createdFile + originalCloseFunc := closeFunc + closeFunc = func() { + originalCloseFunc() + createdFile.Close() + } } _, err = pdf.PdfiumInstance.FPDF_SaveAsCopy(&requests.FPDF_SaveAsCopy{ Document: newDocument.Document, - FileWriter: createdFile, + FileWriter: fileWriter, }) if err != nil { closeFunc() - createdFile.Close() cmd.PrintErrf("could not save document for page %s: %w\n", page, err) return } closeFunc() - createdFile.Close() - cmd.Printf("Exploded page %s into %s\n", page, newFilePath) + if args[1] != stdFilename { + cmd.Printf("Exploded page %s into %s\n", page, newFilePath) + } } }, } diff --git a/cmd/images.go b/cmd/images.go index be9b2b2..2b49fc7 100644 --- a/cmd/images.go +++ b/cmd/images.go @@ -34,13 +34,13 @@ func init() { var imagesCmd = &cobra.Command{ Use: "images [input] [output-folder]", Short: "Extract the images of a PDF", - Long: "Extract the images of a PDF and store them as file.", + Long: "Extract the images of a PDF and store them as file.\n[input] can either be a file path or - for stdin.", Args: func(cmd *cobra.Command, args []string) error { if err := cobra.ExactArgs(2)(cmd, args); err != nil { return err } - if _, err := os.Stat(args[0]); err != nil { + if err := validFile(args[0]); err != nil { return fmt.Errorf("could not open input file %s: %w\n", args[0], err) } @@ -63,19 +63,12 @@ var imagesCmd = &cobra.Command{ } defer pdf.ClosePdfium() - file, err := os.Open(args[0]) + document, closeFile, err := openFile(args[0]) if err != nil { cmd.PrintErrf("could not open input file %s: %w\n", args[0], err) return } - defer file.Close() - - document, err := openFile(file) - if err != nil { - cmd.PrintErrf("could not open input file %s: %w\n", args[0], err) - return - } - defer pdf.PdfiumInstance.FPDF_CloseDocument(&requests.FPDF_CloseDocument{Document: document.Document}) + defer closeFile() pageCount, err := pdf.PdfiumInstance.FPDF_GetPageCount(&requests.FPDF_GetPageCount{ Document: document.Document, diff --git a/cmd/info.go b/cmd/info.go index fd4b26f..adf95fd 100644 --- a/cmd/info.go +++ b/cmd/info.go @@ -2,7 +2,6 @@ package cmd import ( "fmt" - "os" "strings" "github.com/klippa-app/pdfium-cli/pdf" @@ -25,7 +24,7 @@ var infoCmd = &cobra.Command{ return err } - if _, err := os.Stat(args[0]); err != nil { + if err := validFile(args[0]); err != nil { return fmt.Errorf("could not open input file %s: %w\n", args[0], err) } @@ -39,18 +38,14 @@ var infoCmd = &cobra.Command{ } defer pdf.ClosePdfium() - file, err := os.Open(args[0]) + document, closeFile, err := openFile(args[0]) if err != nil { cmd.PrintErrf("could not open input file %s: %w\n", args[0], err) return } - defer file.Close() - document, err := openFile(file) - if err != nil { - cmd.PrintErrf("could not open input file %s: %w\n", args[0], err) - return - } + defer closeFile() + defer pdf.PdfiumInstance.FPDF_CloseDocument(&requests.FPDF_CloseDocument{Document: document.Document}) fileVersion, err := pdf.PdfiumInstance.FPDF_GetFileVersion(&requests.FPDF_GetFileVersion{ diff --git a/cmd/javascripts.go b/cmd/javascripts.go index 19551a3..5d0d659 100644 --- a/cmd/javascripts.go +++ b/cmd/javascripts.go @@ -19,13 +19,13 @@ func init() { var javascriptsCmd = &cobra.Command{ Use: "javascripts [input] [output-folder]", Short: "Extract the javascripts of a PDF", - Long: "Extract the javascripts of a PDF and store them as file.", + Long: "Extract the javascripts of a PDF and store them as file.\n[input] can either be a file path or - for stdin.", Args: func(cmd *cobra.Command, args []string) error { if err := cobra.ExactArgs(2)(cmd, args); err != nil { return err } - if _, err := os.Stat(args[0]); err != nil { + if err := validFile(args[0]); err != nil { return fmt.Errorf("could not open input file %s: %w\n", args[0], err) } @@ -48,19 +48,12 @@ var javascriptsCmd = &cobra.Command{ } defer pdf.ClosePdfium() - file, err := os.Open(args[0]) + document, closeFile, err := openFile(args[0]) if err != nil { cmd.PrintErrf("could not open input file %s: %w\n", args[0], err) return } - defer file.Close() - - document, err := openFile(file) - if err != nil { - cmd.PrintErrf("could not open input file %s: %w\n", args[0], err) - return - } - defer pdf.PdfiumInstance.FPDF_CloseDocument(&requests.FPDF_CloseDocument{Document: document.Document}) + defer closeFile() javascripts, err := pdf.PdfiumInstance.GetJavaScriptActions(&requests.GetJavaScriptActions{ Document: document.Document, diff --git a/cmd/merge.go b/cmd/merge.go index 6cd1121..e367562 100644 --- a/cmd/merge.go +++ b/cmd/merge.go @@ -2,6 +2,7 @@ package cmd import ( "fmt" + "io" "os" "github.com/klippa-app/go-pdfium/requests" @@ -18,7 +19,7 @@ func init() { var mergeCmd = &cobra.Command{ Use: "merge [input] [input] ([input]...) [output]", Short: "Merge multiple PDFs into a single PDF", - Long: "Merge multiple PDFs into a single PDF", + Long: "Merge multiple PDFs into a single PDF.\n[output] can either be a file path or - for stdout.", Args: func(cmd *cobra.Command, args []string) error { if err := cobra.MinimumNArgs(3)(cmd, args); err != nil { return err @@ -48,21 +49,14 @@ var mergeCmd = &cobra.Command{ mergedPageCount := 0 for i := 0; i < len(args)-1; i++ { - file, err := os.Open(args[i]) - if err != nil { - cmd.PrintErrf("could not open input file %s: %w", args[i], err) - return - } - defer file.Close() - - document, err := openFile(file) + document, closeFile, err := openFile(args[i]) if err != nil { cmd.PrintErrf("could not open input file %s: %w", args[i], err) return } closeFunc := func() { - pdf.PdfiumInstance.FPDF_CloseDocument(&requests.FPDF_CloseDocument{Document: newDocument.Document}) + closeFile() } pageCount, err := pdf.PdfiumInstance.FPDF_GetPageCount(&requests.FPDF_GetPageCount{ @@ -107,17 +101,23 @@ var mergeCmd = &cobra.Command{ closeFunc() } - createdFile, err := os.Create(args[len(args)-1]) - if err != nil { - cmd.PrintErrf("could not save document: %w", err) - return - } + var fileWriter io.Writer + if args[len(args)-1] == stdFilename { + fileWriter = os.Stdout + } else { + createdFile, err := os.Create(args[len(args)-1]) + if err != nil { + cmd.PrintErrf("could not save document: %w", err) + return + } - defer createdFile.Close() + defer createdFile.Close() + fileWriter = createdFile + } _, err = pdf.PdfiumInstance.FPDF_SaveAsCopy(&requests.FPDF_SaveAsCopy{ Document: newDocument.Document, - FileWriter: createdFile, + FileWriter: fileWriter, }) if err != nil { cmd.PrintErrf("could not save new document %s: %w", err) diff --git a/cmd/pdf.go b/cmd/pdf.go index 9ebb800..265b0e3 100644 --- a/cmd/pdf.go +++ b/cmd/pdf.go @@ -1,7 +1,9 @@ package cmd import ( + "bytes" "github.com/klippa-app/pdfium-cli/pdf" + "io" "os" "github.com/klippa-app/go-pdfium/requests" @@ -23,20 +25,71 @@ func addPagesOption(intro string, command *cobra.Command) { 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.") } -func openFile(file *os.File) (*responses.OpenDocument, error) { - fileStat, err := file.Stat() - if err != nil { - return nil, nil - } +const stdFilename = "-" + +func openFile(filename string) (*responses.OpenDocument, func(), error) { + openDocumentRequest := &requests.OpenDocument{} + + closeFile := func() {} + + // Support opening file from stdin. + if filename == stdFilename { + // For stdin we need to read the full thing because pdfium doesn't + // support streaming when it doesn't know the size of the file. + readStdin, err := io.ReadAll(os.Stdin) + if err != nil { + return nil, nil, err + } + reader := bytes.NewReader(readStdin) + openDocumentRequest.FileReader = reader + openDocumentRequest.FileReaderSize = reader.Size() + } else { + file, err := os.Open(filename) + if err != nil { + return nil, nil, err + } - openDocumentRequest := &requests.OpenDocument{ - FileReader: file, - FileReaderSize: fileStat.Size(), + closeFile = func() { + file.Close() + } + + // For files we stat the file so that we can tell pdfium the file size + // which it will need to do proper seeking in the file. + fileStat, err := file.Stat() + if err != nil { + return nil, closeFile, nil + } + + openDocumentRequest.FileReader = file + openDocumentRequest.FileReaderSize = fileStat.Size() } if password != "" { openDocumentRequest.Password = &password } - return pdf.PdfiumInstance.OpenDocument(openDocumentRequest) + openedDocument, err := pdf.PdfiumInstance.OpenDocument(openDocumentRequest) + if err != nil { + return nil, closeFile, err + } + + originalCloseFile := closeFile + closeFile = func() { + pdf.PdfiumInstance.FPDF_CloseDocument(&requests.FPDF_CloseDocument{Document: openedDocument.Document}) + originalCloseFile() + } + + return openedDocument, closeFile, nil +} + +func validFile(filename string) error { + if filename == stdFilename { + return nil + } + + if _, err := os.Stat(filename); err != nil { + return err + } + + return nil } diff --git a/cmd/render.go b/cmd/render.go index f45c64a..e51b5f3 100644 --- a/cmd/render.go +++ b/cmd/render.go @@ -41,13 +41,13 @@ func init() { var renderCmd = &cobra.Command{ Use: "render [input] [output]", Short: "Render a PDF into images", - Long: "Render a PDF into images, the output filename should contain a \"%d\" placeholder for the page number when rendering more than one page and when not using the combine-pages option, e.g. render invoice.pdf invoice-%d.jpg, the result for a 2-page PDF will be invoice-1.jpg and invoice-2.jpg.", + Long: "Render a PDF into images.\n[input] can either be a file path or - for stdin.\n[output] can either be a file path or - for stdout, stdout is only supported when the output will be one file. The output filename should contain a \"%d\" placeholder for the page number when rendering more than one page and when not using the combine-pages option, e.g. render invoice.pdf invoice-%d.jpg, the result for a 2-page PDF will be invoice-1.jpg and invoice-2.jpg.", Args: func(cmd *cobra.Command, args []string) error { if err := cobra.ExactArgs(2)(cmd, args); err != nil { return err } - if _, err := os.Stat(args[0]); err != nil { + if err := validFile(args[0]); err != nil { return fmt.Errorf("could not open input file %s: %w", args[0], err) } @@ -61,19 +61,12 @@ var renderCmd = &cobra.Command{ } defer pdf.ClosePdfium() - file, err := os.Open(args[0]) + document, closeFile, err := openFile(args[0]) if err != nil { cmd.PrintErrf("could not open input file %s: %w\n", args[0], err) return } - defer file.Close() - - document, err := openFile(file) - if err != nil { - cmd.PrintErrf("could not open input file %s: %w\n", args[0], err) - return - } - defer pdf.PdfiumInstance.FPDF_CloseDocument(&requests.FPDF_CloseDocument{Document: document.Document}) + defer closeFile() pageCount, err := pdf.PdfiumInstance.FPDF_GetPageCount(&requests.FPDF_GetPageCount{ Document: document.Document, @@ -83,13 +76,6 @@ var renderCmd = &cobra.Command{ return } - if pageCount.PageCount > 1 && !combinePages { - if !strings.Contains(args[1], "%d") { - cmd.PrintErrf("output string %s should contain page pattern %%d\n", args[1]) - return - } - } - pageRange := "first-last" if pages != "" { pageRange = pages @@ -103,6 +89,19 @@ var renderCmd = &cobra.Command{ renderPages := []requests.Page{} splitPages := strings.Split(*parsedPageRange, ",") + + if len(splitPages) > 1 && !combinePages { + if args[1] != stdFilename && !strings.Contains(args[1], "%d") { + cmd.PrintErrf("output string %s should contain page pattern %%d\n", args[1]) + return + } + + if args[1] == stdFilename { + cmd.PrintErrf("could not render into multiple files with output to stdout\n") + return + } + } + for _, page := range splitPages { pageInt, _ := strconv.Atoi(page) renderPages = append(renderPages, requests.Page{ @@ -125,10 +124,15 @@ var renderCmd = &cobra.Command{ if combinePages { renderRequest := &requests.RenderToFile{ - OutputFormat: outputFormat, - OutputTarget: requests.RenderToFileOutputTargetFile, - TargetFilePath: args[1], - MaxFileSize: maxFileSize, + OutputFormat: outputFormat, + MaxFileSize: maxFileSize, + } + + if args[1] == stdFilename { + renderRequest.OutputTarget = requests.RenderToFileOutputTargetBytes + } else { + renderRequest.OutputTarget = requests.RenderToFileOutputTargetFile + renderRequest.TargetFilePath = args[1] } if maxWidth > 0 || maxHeight > 0 { @@ -158,24 +162,36 @@ var renderCmd = &cobra.Command{ } } - _, err := pdf.PdfiumInstance.RenderToFile(renderRequest) + result, err := pdf.PdfiumInstance.RenderToFile(renderRequest) if err != nil { cmd.PrintErrf("could not render pages %s into image: %w\n", *parsedPageRange, err) return } - cmd.Printf("Rendered pages %s into %s\n", *parsedPageRange, args[1]) + if args[1] != stdFilename { + cmd.Printf("Rendered pages %s into %s\n", *parsedPageRange, args[1]) + } else { + _, err = os.Stdout.Write(*result.ImageBytes) + if err != nil { + cmd.PrintErrf("could not render pages %s into image: %w\n", *parsedPageRange, err) + return + } + } } else { for _, renderPage := range renderPages { page := strconv.Itoa(renderPage.ByIndex.Index + 1) - newFilePath := strings.Replace(args[1], "%d", page, -1) renderRequest := &requests.RenderToFile{ - OutputFormat: outputFormat, - OutputTarget: requests.RenderToFileOutputTargetFile, - TargetFilePath: newFilePath, - MaxFileSize: maxFileSize, + OutputFormat: outputFormat, + MaxFileSize: maxFileSize, + } + + if args[1] == stdFilename { + renderRequest.OutputTarget = requests.RenderToFileOutputTargetBytes + } else { + renderRequest.OutputTarget = requests.RenderToFileOutputTargetFile + renderRequest.TargetFilePath = newFilePath } if maxWidth > 0 || maxHeight > 0 { @@ -201,13 +217,21 @@ var renderCmd = &cobra.Command{ } } - _, err := pdf.PdfiumInstance.RenderToFile(renderRequest) + result, err := pdf.PdfiumInstance.RenderToFile(renderRequest) if err != nil { cmd.PrintErrf("could not render page %s into image: %w\n", page, err) return } - cmd.Printf("Rendered page %s into %s\n", page, newFilePath) + if args[1] != stdFilename { + cmd.Printf("Rendered page %s into %s\n", page, newFilePath) + } else { + _, err = os.Stdout.Write(*result.ImageBytes) + if err != nil { + cmd.PrintErrf("could not render page %s into image: %w\n", page, err) + return + } + } } } }, diff --git a/cmd/text.go b/cmd/text.go index 10300ab..461fa81 100644 --- a/cmd/text.go +++ b/cmd/text.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "github.com/klippa-app/go-pdfium/responses" - "os" "strconv" "strings" @@ -43,13 +42,13 @@ func init() { var textCmd = &cobra.Command{ Use: "text [input]", Short: "Get the text of a PDF", - Long: "Get the text of a PDF in text or json.", + Long: "Get the text of a PDF in text or json.\n[input] can either be a file path or - for stdin.", Args: func(cmd *cobra.Command, args []string) error { if err := cobra.ExactArgs(1)(cmd, args); err != nil { return err } - if _, err := os.Stat(args[0]); err != nil { + if err := validFile(args[0]); err != nil { return fmt.Errorf("could not open input file %s: %w", args[0], err) } @@ -63,19 +62,13 @@ var textCmd = &cobra.Command{ } defer pdf.ClosePdfium() - file, err := os.Open(args[0]) + document, closeFile, err := openFile(args[0]) if err != nil { cmd.PrintErrf("could not open input file %s: %w\n", args[0], err) return } - defer file.Close() - document, err := openFile(file) - if err != nil { - cmd.PrintErrf("could not open input file %s: %w\n", args[0], err) - return - } - defer pdf.PdfiumInstance.FPDF_CloseDocument(&requests.FPDF_CloseDocument{Document: document.Document}) + defer closeFile() pageCount, err := pdf.PdfiumInstance.FPDF_GetPageCount(&requests.FPDF_GetPageCount{ Document: document.Document, diff --git a/cmd/thumbnails.go b/cmd/thumbnails.go index 5a7413c..5322e89 100644 --- a/cmd/thumbnails.go +++ b/cmd/thumbnails.go @@ -29,13 +29,13 @@ func init() { var thumbnailsCmd = &cobra.Command{ Use: "thumbnails [input] [output-folder]", Short: "Extract the attachments of a PDF", - Long: "Extract the attachments of a PDF and store them as file. This extracts embedded thumbnails, it does not render a thumbnail of the page. Not all PDFs and pages have thumbnails. You can use the render command if you want to generate thumbnails.", + Long: "Extract the attachments of a PDF and store them as file.\n[input] can either be a file path or - for stdin.\nThis extracts embedded thumbnails, it does not render a thumbnail of the page. Not all PDFs and pages have thumbnails. You can use the render command if you want to generate thumbnails.", Args: func(cmd *cobra.Command, args []string) error { if err := cobra.ExactArgs(2)(cmd, args); err != nil { return err } - if _, err := os.Stat(args[0]); err != nil { + if err := validFile(args[0]); err != nil { return fmt.Errorf("could not open input file %s: %w\n", args[0], err) } @@ -58,19 +58,13 @@ var thumbnailsCmd = &cobra.Command{ } defer pdf.ClosePdfium() - file, err := os.Open(args[0]) + document, closeFile, err := openFile(args[0]) if err != nil { cmd.PrintErrf("could not open input file %s: %w\n", args[0], err) return } - defer file.Close() - document, err := openFile(file) - if err != nil { - cmd.PrintErrf("could not open input file %s: %w\n", args[0], err) - return - } - defer pdf.PdfiumInstance.FPDF_CloseDocument(&requests.FPDF_CloseDocument{Document: document.Document}) + defer closeFile() pageCount, err := pdf.PdfiumInstance.FPDF_GetPageCount(&requests.FPDF_GetPageCount{ Document: document.Document,