diff --git a/pkg/modules/chromium/browser.go b/pkg/modules/chromium/browser.go
index 060f2acb..d7a30326 100644
--- a/pkg/modules/chromium/browser.go
+++ b/pkg/modules/chromium/browser.go
@@ -258,6 +258,7 @@ func (b *chromiumBrowser) screenshot(ctx context.Context, logger *zap.Logger, ur
waitDelayBeforePrintActionFunc(logger, b.arguments.disableJavaScript, options.WaitDelay),
waitForExpressionBeforePrintActionFunc(logger, b.arguments.disableJavaScript, options.WaitForExpression),
// Screenshot specific.
+ setDeviceMetricsOverride(logger, options.Width, options.Height),
captureScreenshotActionFunc(logger, outputPath, options),
})
}
diff --git a/pkg/modules/chromium/browser_test.go b/pkg/modules/chromium/browser_test.go
index 89d8a937..4591f7b3 100644
--- a/pkg/modules/chromium/browser_test.go
+++ b/pkg/modules/chromium/browser_test.go
@@ -1996,6 +1996,54 @@ func TestChromiumBrowser_screenshot(t *testing.T) {
"no emulated media type",
"no wait delay",
"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("
Default options
"), 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 wait delay",
"no wait expression",
+ "set device metrics override",
},
},
} {
diff --git a/pkg/modules/chromium/chromium.go b/pkg/modules/chromium/chromium.go
index 1b6fd79d..cbf96181 100644
--- a/pkg/modules/chromium/chromium.go
+++ b/pkg/modules/chromium/chromium.go
@@ -239,6 +239,19 @@ func DefaultPdfOptions() PdfOptions {
type ScreenshotOptions struct {
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
// "webp".
// Optional.
@@ -258,6 +271,9 @@ type ScreenshotOptions struct {
func DefaultScreenshotOptions() ScreenshotOptions {
return ScreenshotOptions{
Options: DefaultOptions(),
+ Width: 800,
+ Height: 600,
+ Clip: false,
Format: "png",
Quality: 100,
OptimizeForSpeed: false,
diff --git a/pkg/modules/chromium/routes.go b/pkg/modules/chromium/routes.go
index d45203e5..a0436540 100644
--- a/pkg/modules/chromium/routes.go
+++ b/pkg/modules/chromium/routes.go
@@ -182,12 +182,17 @@ func FormDataChromiumScreenshotOptions(ctx *api.Context) (*api.FormData, Screens
defaultScreenshotOptions := DefaultScreenshotOptions()
var (
+ width, height int
+ clip bool
format string
quality int
optimizeForSpeed bool
)
form.
+ Int("width", &width, defaultScreenshotOptions.Width).
+ Int("height", &height, defaultScreenshotOptions.Height).
+ Bool("clip", &clip, defaultScreenshotOptions.Clip).
Custom("format", func(value string) error {
if value == "" {
format = defaultScreenshotOptions.Format
@@ -228,6 +233,9 @@ func FormDataChromiumScreenshotOptions(ctx *api.Context) (*api.FormData, Screens
screenshotOptions := ScreenshotOptions{
Options: options,
+ Width: width,
+ Height: height,
+ Clip: clip,
Format: format,
Quality: quality,
OptimizeForSpeed: optimizeForSpeed,
diff --git a/pkg/modules/chromium/routes_test.go b/pkg/modules/chromium/routes_test.go
index af0d4885..050fa769 100644
--- a/pkg/modules/chromium/routes_test.go
+++ b/pkg/modules/chromium/routes_test.go
@@ -385,6 +385,15 @@ func TestFormDataChromiumScreenshotOptions(t *testing.T) {
ctx: func() *api.ContextMock {
ctx := &api.ContextMock{Context: new(api.Context)}
ctx.SetValues(map[string][]string{
+ "width": {
+ "1280",
+ },
+ "height": {
+ "800",
+ },
+ "clip": {
+ "true",
+ },
"optimizeForSpeed": {
"true",
},
@@ -396,6 +405,9 @@ func TestFormDataChromiumScreenshotOptions(t *testing.T) {
}(),
expectedOptions: func() ScreenshotOptions {
options := DefaultScreenshotOptions()
+ options.Width = 1280
+ options.Height = 800
+ options.Clip = true
options.OptimizeForSpeed = true
options.EmulatedMediaType = "screen"
return options
diff --git a/pkg/modules/chromium/tasks.go b/pkg/modules/chromium/tasks.go
index 4047dde7..2c593da6 100644
--- a/pkg/modules/chromium/tasks.go
+++ b/pkg/modules/chromium/tasks.go
@@ -121,6 +121,14 @@ func captureScreenshotActionFunc(logger *zap.Logger, outputPath string, options
WithOptimizeForSpeed(options.OptimizeForSpeed).
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" {
captureScreenshot = captureScreenshot.
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 {
return func(ctx context.Context) error {
// See https://github.com/gotenberg/gotenberg/issues/753.