feat(chromium): add clip options to screenshot routes

This commit is contained in:
Julien Neuhart
2024-04-25 17:24:23 +02:00
parent a890968ee4
commit 0f0a6ce042
6 changed files with 107 additions and 0 deletions

View File

@@ -258,6 +258,7 @@ func (b *chromiumBrowser) screenshot(ctx context.Context, logger *zap.Logger, ur
waitDelayBeforePrintActionFunc(logger, b.arguments.disableJavaScript, options.WaitDelay), waitDelayBeforePrintActionFunc(logger, b.arguments.disableJavaScript, options.WaitDelay),
waitForExpressionBeforePrintActionFunc(logger, b.arguments.disableJavaScript, options.WaitForExpression), waitForExpressionBeforePrintActionFunc(logger, b.arguments.disableJavaScript, options.WaitForExpression),
// Screenshot specific. // Screenshot specific.
setDeviceMetricsOverride(logger, options.Width, options.Height),
captureScreenshotActionFunc(logger, outputPath, options), captureScreenshotActionFunc(logger, outputPath, options),
}) })
} }

View File

@@ -1996,6 +1996,54 @@ func TestChromiumBrowser_screenshot(t *testing.T) {
"no emulated media type", "no emulated media type",
"no wait delay", "no wait delay",
"no wait expression", "no wait expression",
"set device metrics override",
},
},
{
scenario: "success (clip)",
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("<h1>Default options</h1>"), 0o755)
if err != nil {
t.Fatalf("expected no error but got: %v", err)
}
return fs
}(),
options: func() ScreenshotOptions {
options := DefaultScreenshotOptions()
options.Clip = true
return options
}(),
noDeadline: false,
start: true,
expectError: false,
expectedLogEntries: []string{
"cache not cleared",
"cookies not cleared",
"JavaScript not disabled",
"no cookies to set",
"no extra HTTP headers",
"navigate to",
"default white background not hidden",
"no emulated media type",
"no wait delay",
"no wait expression",
"set device metrics override",
}, },
}, },
{ {
@@ -2042,6 +2090,7 @@ func TestChromiumBrowser_screenshot(t *testing.T) {
"no emulated media type", "no emulated media type",
"no wait delay", "no wait delay",
"no wait expression", "no wait expression",
"set device metrics override",
}, },
}, },
} { } {

View File

@@ -239,6 +239,19 @@ func DefaultPdfOptions() PdfOptions {
type ScreenshotOptions struct { type ScreenshotOptions struct {
Options Options
// Width is the device screen width in pixels.
// Optional.
Width int
// Height is the device screen height in pixels.
// Optional.
Height int
// Clip defines whether to clip the screenshot according to the device
// dimensions.
// Optional.
Clip bool
// Format is the image compression format, either "png" or "jpeg" or // Format is the image compression format, either "png" or "jpeg" or
// "webp". // "webp".
// Optional. // Optional.
@@ -258,6 +271,9 @@ type ScreenshotOptions struct {
func DefaultScreenshotOptions() ScreenshotOptions { func DefaultScreenshotOptions() ScreenshotOptions {
return ScreenshotOptions{ return ScreenshotOptions{
Options: DefaultOptions(), Options: DefaultOptions(),
Width: 800,
Height: 600,
Clip: false,
Format: "png", Format: "png",
Quality: 100, Quality: 100,
OptimizeForSpeed: false, OptimizeForSpeed: false,

View File

@@ -182,12 +182,17 @@ func FormDataChromiumScreenshotOptions(ctx *api.Context) (*api.FormData, Screens
defaultScreenshotOptions := DefaultScreenshotOptions() defaultScreenshotOptions := DefaultScreenshotOptions()
var ( var (
width, height int
clip bool
format string format string
quality int quality int
optimizeForSpeed bool optimizeForSpeed bool
) )
form. form.
Int("width", &width, defaultScreenshotOptions.Width).
Int("height", &height, defaultScreenshotOptions.Height).
Bool("clip", &clip, defaultScreenshotOptions.Clip).
Custom("format", func(value string) error { Custom("format", func(value string) error {
if value == "" { if value == "" {
format = defaultScreenshotOptions.Format format = defaultScreenshotOptions.Format
@@ -228,6 +233,9 @@ func FormDataChromiumScreenshotOptions(ctx *api.Context) (*api.FormData, Screens
screenshotOptions := ScreenshotOptions{ screenshotOptions := ScreenshotOptions{
Options: options, Options: options,
Width: width,
Height: height,
Clip: clip,
Format: format, Format: format,
Quality: quality, Quality: quality,
OptimizeForSpeed: optimizeForSpeed, OptimizeForSpeed: optimizeForSpeed,

View File

@@ -385,6 +385,15 @@ func TestFormDataChromiumScreenshotOptions(t *testing.T) {
ctx: func() *api.ContextMock { ctx: func() *api.ContextMock {
ctx := &api.ContextMock{Context: new(api.Context)} ctx := &api.ContextMock{Context: new(api.Context)}
ctx.SetValues(map[string][]string{ ctx.SetValues(map[string][]string{
"width": {
"1280",
},
"height": {
"800",
},
"clip": {
"true",
},
"optimizeForSpeed": { "optimizeForSpeed": {
"true", "true",
}, },
@@ -396,6 +405,9 @@ func TestFormDataChromiumScreenshotOptions(t *testing.T) {
}(), }(),
expectedOptions: func() ScreenshotOptions { expectedOptions: func() ScreenshotOptions {
options := DefaultScreenshotOptions() options := DefaultScreenshotOptions()
options.Width = 1280
options.Height = 800
options.Clip = true
options.OptimizeForSpeed = true options.OptimizeForSpeed = true
options.EmulatedMediaType = "screen" options.EmulatedMediaType = "screen"
return options return options

View File

@@ -121,6 +121,14 @@ func captureScreenshotActionFunc(logger *zap.Logger, outputPath string, options
WithOptimizeForSpeed(options.OptimizeForSpeed). WithOptimizeForSpeed(options.OptimizeForSpeed).
WithFormat(page.CaptureScreenshotFormat(options.Format)) WithFormat(page.CaptureScreenshotFormat(options.Format))
if options.Clip {
captureScreenshot = captureScreenshot.WithClip(&page.Viewport{
Width: float64(options.Width),
Height: float64(options.Height),
Scale: 1,
})
}
if options.Format == "jpeg" { if options.Format == "jpeg" {
captureScreenshot = captureScreenshot. captureScreenshot = captureScreenshot.
WithQuality(int64(options.Quality)) WithQuality(int64(options.Quality))
@@ -154,6 +162,19 @@ func captureScreenshotActionFunc(logger *zap.Logger, outputPath string, options
} }
} }
func setDeviceMetricsOverride(logger *zap.Logger, width, height int) chromedp.ActionFunc {
return func(ctx context.Context) error {
logger.Debug("set device metrics override")
err := emulation.SetDeviceMetricsOverride(int64(width), int64(height), 1.0, false).Do(ctx)
if err == nil {
return nil
}
return fmt.Errorf("set device metrics override: %w", err)
}
}
func clearCacheActionFunc(logger *zap.Logger, clear bool) chromedp.ActionFunc { func clearCacheActionFunc(logger *zap.Logger, clear bool) chromedp.ActionFunc {
return func(ctx context.Context) error { return func(ctx context.Context) error {
// See https://github.com/gotenberg/gotenberg/issues/753. // See https://github.com/gotenberg/gotenberg/issues/753.