feat(chromium): add new omitBackground form field (closes #226)

This commit is contained in:
Julien Neuhart
2022-10-21 10:41:40 +02:00
parent 921b6b7ba4
commit f89726752f
4 changed files with 102 additions and 4 deletions

View File

@@ -11,6 +11,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/chromedp/cdproto/cdp"
"github.com/chromedp/cdproto/emulation" "github.com/chromedp/cdproto/emulation"
"github.com/chromedp/cdproto/fetch" "github.com/chromedp/cdproto/fetch"
"github.com/chromedp/cdproto/network" "github.com/chromedp/cdproto/network"
@@ -33,6 +34,10 @@ var (
// allowed/denied lists. // allowed/denied lists.
ErrURLNotAuthorized = errors.New("URL not authorized") 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 // ErrInvalidEmulatedMediaType happens if the emulated media type is not
// "screen" nor "print". Empty value are allowed though. // "screen" nor "print". Empty value are allowed though.
ErrInvalidEmulatedMediaType = errors.New("invalid emulated media type") ErrInvalidEmulatedMediaType = errors.New("invalid emulated media type")
@@ -144,6 +149,11 @@ type Options struct {
// Optional. // Optional.
PrintBackground bool PrintBackground bool
// OmitBackground hides default white background and allows generating PDFs
// with transparency.
// Optional.
OmitBackground bool
// Scale is the scale of the page rendering. // Scale is the scale of the page rendering.
// Optional. // Optional.
Scale float64 Scale float64
@@ -214,6 +224,7 @@ func DefaultOptions() Options {
ExtraScriptTags: nil, ExtraScriptTags: nil,
Landscape: false, Landscape: false,
PrintBackground: false, PrintBackground: false,
OmitBackground: false,
Scale: 1.0, Scale: 1.0,
PaperWidth: 8.5, PaperWidth: 8.5,
PaperHeight: 11, 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) 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 { chromedp.ActionFunc(func(ctx context.Context) error {
// See: // See:
// https://github.com/gotenberg/gotenberg/issues/354 // https://github.com/gotenberg/gotenberg/issues/354
@@ -767,10 +807,23 @@ func (mod Chromium) PDF(ctx context.Context, logger *zap.Logger, URL, outputPath
WithMarginLeft(options.MarginLeft). WithMarginLeft(options.MarginLeft).
WithMarginRight(options.MarginRight). WithMarginRight(options.MarginRight).
WithPageRanges(options.PageRanges). WithPageRanges(options.PageRanges).
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). WithDisplayHeaderFooter(true).
WithHeaderTemplate(options.HeaderTemplate). WithHeaderTemplate(options.HeaderTemplate).
WithFooterTemplate(options.FooterTemplate). WithFooterTemplate(options.FooterTemplate)
WithPreferCSSPageSize(options.PreferCSSPageSize) }
logger.Debug(fmt.Sprintf("print to PDF with: %+v", printToPDF)) logger.Debug(fmt.Sprintf("print to PDF with: %+v", printToPDF))

View File

@@ -335,6 +335,24 @@ func TestChromium_PDF(t *testing.T) {
EmulatedMediaType: "print", 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", name: "with extra script tags",
timeout: time.Duration(60) * time.Second, timeout: time.Duration(60) * time.Second,

View File

@@ -33,7 +33,7 @@ func FormDataChromiumPDFOptions(ctx *api.Context) (*api.FormData, Options) {
userAgent string userAgent string
extraHTTPHeaders map[string]string extraHTTPHeaders map[string]string
emulatedMediaType string emulatedMediaType string
landscape, printBackground bool landscape, printBackground, omitBackground bool
scale, paperWidth, paperHeight float64 scale, paperWidth, paperHeight float64
marginTop, marginBottom, marginLeft, marginRight float64 marginTop, marginBottom, marginLeft, marginRight float64
pageRanges string pageRanges string
@@ -78,6 +78,7 @@ func FormDataChromiumPDFOptions(ctx *api.Context) (*api.FormData, Options) {
}). }).
Bool("landscape", &landscape, defaultOptions.Landscape). Bool("landscape", &landscape, defaultOptions.Landscape).
Bool("printBackground", &printBackground, defaultOptions.PrintBackground). Bool("printBackground", &printBackground, defaultOptions.PrintBackground).
Bool("omitBackground", &omitBackground, defaultOptions.OmitBackground).
Float64("scale", &scale, defaultOptions.Scale). Float64("scale", &scale, defaultOptions.Scale).
Float64("paperWidth", &paperWidth, defaultOptions.PaperWidth). Float64("paperWidth", &paperWidth, defaultOptions.PaperWidth).
Float64("paperHeight", &paperHeight, defaultOptions.PaperHeight). Float64("paperHeight", &paperHeight, defaultOptions.PaperHeight).
@@ -102,6 +103,7 @@ func FormDataChromiumPDFOptions(ctx *api.Context) (*api.FormData, Options) {
ExtraScriptTags: defaultOptions.ExtraScriptTags, ExtraScriptTags: defaultOptions.ExtraScriptTags,
Landscape: landscape, Landscape: landscape,
PrintBackground: printBackground, PrintBackground: printBackground,
OmitBackground: omitBackground,
Scale: scale, Scale: scale,
PaperWidth: paperWidth, PaperWidth: paperWidth,
PaperHeight: paperHeight, 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 errors.Is(err, ErrInvalidEvaluationExpression) {
if options.WaitForExpression == "" { if options.WaitForExpression == "" {
// We do not expect the 'waitWindowStatus' form field to return // We do not expect the 'waitWindowStatus' form field to return

View File

@@ -667,6 +667,21 @@ func TestConvertURL(t *testing.T) {
expectHTTPErr: true, expectHTTPErr: true,
expectHTTPStatus: http.StatusForbidden, 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{}}, ctx: &api.ContextMock{Context: &api.Context{}},
api: func() API { api: func() API {