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"
"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)

View File

@@ -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,

View File

@@ -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

View File

@@ -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 {