diff --git a/pkg/modules/chromium/browser_test.go b/pkg/modules/chromium/browser_test.go index 4a4bc540..b33b5ae3 100644 --- a/pkg/modules/chromium/browser_test.go +++ b/pkg/modules/chromium/browser_test.go @@ -950,6 +950,41 @@ func TestChromiumBrowser_pdf(t *testing.T) { "wait until 'window.globalVar === 'ready'' is true before print", }, }, + { + scenario: "single page", + browser: newChromiumBrowser( + browserArguments{ + binPath: os.Getenv("CHROMIUM_BIN_PATH"), + wsUrlReadTimeout: 5 * time.Second, + allowList: regexp2.MustCompile("", 0), + denyList: regexp2.MustCompile("", 0), + }, + ), + fs: func() *gotenberg.FileSystem { + fs := gotenberg.NewFileSystem() + + err := os.MkdirAll(fs.WorkingDirPath(), 0o755) + if err != nil { + t.Fatalf(fmt.Sprintf("expected no error but got: %v", err)) + } + + err = os.WriteFile(fmt.Sprintf("%s/index.html", fs.WorkingDirPath()), []byte("

Custom header and footer

"), 0o755) + if err != nil { + t.Fatalf("expected no error but got: %v", err) + } + + return fs + }(), + options: PdfOptions{ + SinglePage: true, + }, + noDeadline: false, + start: true, + expectError: false, + expectedLogEntries: []string{ + "single page PDF", + }, + }, { scenario: "custom header and footer", browser: newChromiumBrowser( diff --git a/pkg/modules/chromium/chromium.go b/pkg/modules/chromium/chromium.go index 9a3594ea..0ab4ad36 100644 --- a/pkg/modules/chromium/chromium.go +++ b/pkg/modules/chromium/chromium.go @@ -150,6 +150,11 @@ type PdfOptions struct { // Optional. Scale float64 + // SinglePage defines whether to print the entire content in one single + // page. + // Optional. + SinglePage bool + // PaperWidth is the paper width, in inches. // Optional. PaperWidth float64 @@ -209,6 +214,7 @@ func DefaultPdfOptions() PdfOptions { Landscape: false, PrintBackground: false, Scale: 1.0, + SinglePage: false, PaperWidth: 8.5, PaperHeight: 11, MarginTop: 0.39, diff --git a/pkg/modules/chromium/routes.go b/pkg/modules/chromium/routes.go index e43400a7..f490963c 100644 --- a/pkg/modules/chromium/routes.go +++ b/pkg/modules/chromium/routes.go @@ -109,7 +109,7 @@ func FormDataChromiumPdfOptions(ctx *api.Context) (*api.FormData, PdfOptions) { defaultPdfOptions := DefaultPdfOptions() var ( - landscape, printBackground bool + landscape, printBackground, singlePage bool scale, paperWidth, paperHeight float64 marginTop, marginBottom, marginLeft, marginRight float64 pageRanges string @@ -121,6 +121,7 @@ func FormDataChromiumPdfOptions(ctx *api.Context) (*api.FormData, PdfOptions) { Bool("landscape", &landscape, defaultPdfOptions.Landscape). Bool("printBackground", &printBackground, defaultPdfOptions.PrintBackground). Float64("scale", &scale, defaultPdfOptions.Scale). + Bool("singlePage", &singlePage, defaultPdfOptions.SinglePage). Float64("paperWidth", &paperWidth, defaultPdfOptions.PaperWidth). Float64("paperHeight", &paperHeight, defaultPdfOptions.PaperHeight). Float64("marginTop", &marginTop, defaultPdfOptions.MarginTop). @@ -137,6 +138,7 @@ func FormDataChromiumPdfOptions(ctx *api.Context) (*api.FormData, PdfOptions) { Landscape: landscape, PrintBackground: printBackground, Scale: scale, + SinglePage: singlePage, PaperWidth: paperWidth, PaperHeight: paperHeight, MarginTop: marginTop, diff --git a/pkg/modules/chromium/tasks.go b/pkg/modules/chromium/tasks.go index d77688b6..76068dd1 100644 --- a/pkg/modules/chromium/tasks.go +++ b/pkg/modules/chromium/tasks.go @@ -17,19 +17,37 @@ import ( func printToPdfActionFunc(logger *zap.Logger, outputPath string, options PdfOptions) chromedp.ActionFunc { return func(ctx context.Context) error { + paperHeight := options.PaperHeight + pageRanges := options.PageRanges + + if options.SinglePage { + logger.Debug("single page PDF") + + _, _, _, _, _, cssContentSize, err := page.GetLayoutMetrics().Do(ctx) + if err != nil { + return fmt.Errorf("get layout metrics: %w", err) + } + + // There are 96 CSS pixels per inch. + // See https://issues.chromium.org/issues/40267771#comment14. + paperHeight = cssContentSize.Height / 96 + pageRanges = "1" // little dirty hack to avoid leftovers. + } + printToPdf := page.PrintToPDF(). WithTransferMode(page.PrintToPDFTransferModeReturnAsStream). WithLandscape(options.Landscape). WithPrintBackground(options.PrintBackground). WithScale(options.Scale). WithPaperWidth(options.PaperWidth). - WithPaperHeight(options.PaperHeight). + WithPaperHeight(paperHeight). WithMarginTop(options.MarginTop). WithMarginBottom(options.MarginBottom). WithMarginLeft(options.MarginLeft). WithMarginRight(options.MarginRight). - WithPageRanges(options.PageRanges). - WithPreferCSSPageSize(options.PreferCssPageSize) + WithPageRanges(pageRanges). + WithPreferCSSPageSize(options.PreferCssPageSize). + WithGenerateTaggedPDF(true) hasCustomHeaderFooter := options.HeaderTemplate != DefaultPdfOptions().HeaderTemplate || options.FooterTemplate != DefaultPdfOptions().FooterTemplate