mirror of
https://github.com/gotenberg/gotenberg.git
synced 2026-08-17 04:32:15 +01:00
feat(chromium): add new omitBackground form field (closes #226)
This commit is contained in:
@@ -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,11 +807,24 @@ 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).
|
||||||
WithDisplayHeaderFooter(true).
|
|
||||||
WithHeaderTemplate(options.HeaderTemplate).
|
|
||||||
WithFooterTemplate(options.FooterTemplate).
|
|
||||||
WithPreferCSSPageSize(options.PreferCSSPageSize)
|
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))
|
logger.Debug(fmt.Sprintf("print to PDF with: %+v", printToPDF))
|
||||||
|
|
||||||
_, stream, err := printToPDF.Do(ctx)
|
_, stream, err := printToPDF.Do(ctx)
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user