diff --git a/pkg/modules/chromium/chromium.go b/pkg/modules/chromium/chromium.go index a5bbb646..a9c9c693 100644 --- a/pkg/modules/chromium/chromium.go +++ b/pkg/modules/chromium/chromium.go @@ -11,6 +11,7 @@ import ( "sync" "time" + "github.com/chromedp/cdproto/cdp" "github.com/chromedp/cdproto/emulation" "github.com/chromedp/cdproto/fetch" "github.com/chromedp/cdproto/network" @@ -33,6 +34,10 @@ var ( // allowed/denied lists. ErrURLNotAuthorized = errors.New("URL not authorized") + // ErrOmitBackgroundWithoutPrintBackground happens if + // Options.OmitBackground is set to true but not Options.PrintBackground. + ErrOmitBackgroundWithoutPrintBackground = errors.New("omit background without print background") + // ErrInvalidEmulatedMediaType happens if the emulated media type is not // "screen" nor "print". Empty value are allowed though. ErrInvalidEmulatedMediaType = errors.New("invalid emulated media type") @@ -144,6 +149,11 @@ type Options struct { // Optional. PrintBackground bool + // OmitBackground hides default white background and allows generating PDFs + // with transparency. + // Optional. + OmitBackground bool + // Scale is the scale of the page rendering. // Optional. Scale float64 @@ -214,6 +224,7 @@ func DefaultOptions() Options { ExtraScriptTags: nil, Landscape: false, PrintBackground: false, + OmitBackground: false, Scale: 1.0, PaperWidth: 8.5, PaperHeight: 11, @@ -524,6 +535,35 @@ func (mod Chromium) PDF(ctx context.Context, logger *zap.Logger, URL, outputPath return fmt.Errorf("wait for events: %w", err) }), + chromedp.ActionFunc(func(ctx context.Context) error { + // See https://github.com/gotenberg/gotenberg/issues/226. + if !options.OmitBackground { + logger.Debug("default white background not hidden") + + return nil + } + + if !options.PrintBackground { + // See https://github.com/chromedp/chromedp/issues/1179#issuecomment-1284794416. + return fmt.Errorf("validate omit background: %w", ErrOmitBackgroundWithoutPrintBackground) + } + + logger.Debug("hide default white background") + + err := emulation.SetDefaultBackgroundColorOverride().WithColor( + &cdp.RGBA{ + R: 0, + G: 0, + B: 0, + A: 0, + }).Do(ctx) + + if err == nil { + return nil + } + + return fmt.Errorf("hide default white background: %w", err) + }), chromedp.ActionFunc(func(ctx context.Context) error { // See: // https://github.com/gotenberg/gotenberg/issues/354 @@ -767,11 +807,24 @@ func (mod Chromium) PDF(ctx context.Context, logger *zap.Logger, URL, outputPath WithMarginLeft(options.MarginLeft). WithMarginRight(options.MarginRight). WithPageRanges(options.PageRanges). - WithDisplayHeaderFooter(true). - WithHeaderTemplate(options.HeaderTemplate). - WithFooterTemplate(options.FooterTemplate). WithPreferCSSPageSize(options.PreferCSSPageSize) + hasCustomHeaderFooter := options.HeaderTemplate != DefaultOptions().HeaderTemplate || + options.FooterTemplate != DefaultOptions().FooterTemplate + + if !hasCustomHeaderFooter { + logger.Debug("no custom header nor footer") + + printToPDF = printToPDF.WithDisplayHeaderFooter(false) + } else { + logger.Debug("with custom header and/or footer") + + printToPDF = printToPDF. + WithDisplayHeaderFooter(true). + WithHeaderTemplate(options.HeaderTemplate). + WithFooterTemplate(options.FooterTemplate) + } + logger.Debug(fmt.Sprintf("print to PDF with: %+v", printToPDF)) _, stream, err := printToPDF.Do(ctx) diff --git a/pkg/modules/chromium/chromium_test.go b/pkg/modules/chromium/chromium_test.go index 3aeefa48..20394f78 100644 --- a/pkg/modules/chromium/chromium_test.go +++ b/pkg/modules/chromium/chromium_test.go @@ -335,6 +335,24 @@ func TestChromium_PDF(t *testing.T) { EmulatedMediaType: "print", }, }, + { + name: "with omit background but not print background", + timeout: time.Duration(60) * time.Second, + URL: "file:///tests/test/testdata/chromium/html/sample4/index.html", + options: Options{ + OmitBackground: true, + }, + expectErr: true, + }, + { + name: "with omit background and print background", + timeout: time.Duration(60) * time.Second, + URL: "file:///tests/test/testdata/chromium/html/sample4/index.html", + options: Options{ + OmitBackground: true, + PrintBackground: true, + }, + }, { name: "with extra script tags", timeout: time.Duration(60) * time.Second, diff --git a/pkg/modules/chromium/routes.go b/pkg/modules/chromium/routes.go index 0217e0fe..897550fd 100644 --- a/pkg/modules/chromium/routes.go +++ b/pkg/modules/chromium/routes.go @@ -33,7 +33,7 @@ func FormDataChromiumPDFOptions(ctx *api.Context) (*api.FormData, Options) { userAgent string extraHTTPHeaders map[string]string emulatedMediaType string - landscape, printBackground bool + landscape, printBackground, omitBackground bool scale, paperWidth, paperHeight float64 marginTop, marginBottom, marginLeft, marginRight float64 pageRanges string @@ -78,6 +78,7 @@ func FormDataChromiumPDFOptions(ctx *api.Context) (*api.FormData, Options) { }). Bool("landscape", &landscape, defaultOptions.Landscape). Bool("printBackground", &printBackground, defaultOptions.PrintBackground). + Bool("omitBackground", &omitBackground, defaultOptions.OmitBackground). Float64("scale", &scale, defaultOptions.Scale). Float64("paperWidth", &paperWidth, defaultOptions.PaperWidth). Float64("paperHeight", &paperHeight, defaultOptions.PaperHeight). @@ -102,6 +103,7 @@ func FormDataChromiumPDFOptions(ctx *api.Context) (*api.FormData, Options) { ExtraScriptTags: defaultOptions.ExtraScriptTags, Landscape: landscape, PrintBackground: printBackground, + OmitBackground: omitBackground, Scale: scale, PaperWidth: paperWidth, PaperHeight: paperHeight, @@ -340,6 +342,16 @@ func convertURL(ctx *api.Context, chromium API, engine gotenberg.PDFEngine, URL, ) } + if errors.Is(err, ErrOmitBackgroundWithoutPrintBackground) { + return api.WrapError( + fmt.Errorf("convert to PDF: %w", err), + api.NewSentinelHTTPError( + http.StatusBadRequest, + "omitBackground requires printBackground set to true", + ), + ) + } + if errors.Is(err, ErrInvalidEvaluationExpression) { if options.WaitForExpression == "" { // We do not expect the 'waitWindowStatus' form field to return diff --git a/pkg/modules/chromium/routes_test.go b/pkg/modules/chromium/routes_test.go index 7edfb695..e841ffcf 100644 --- a/pkg/modules/chromium/routes_test.go +++ b/pkg/modules/chromium/routes_test.go @@ -667,6 +667,21 @@ func TestConvertURL(t *testing.T) { expectHTTPErr: true, expectHTTPStatus: http.StatusForbidden, }, + { + ctx: &api.ContextMock{Context: &api.Context{}}, + api: func() API { + chromiumAPI := struct{ ProtoAPI }{} + chromiumAPI.pdf = func(_ context.Context, _ *zap.Logger, _, _ string, _ Options) error { + return ErrOmitBackgroundWithoutPrintBackground + } + + return chromiumAPI + }(), + options: DefaultOptions(), + expectErr: true, + expectHTTPErr: true, + expectHTTPStatus: http.StatusForbidden, + }, { ctx: &api.ContextMock{Context: &api.Context{}}, api: func() API {