fix(chromium): fit the page to content for landscape single-page (#1390)

This commit is contained in:
Julien Neuhart
2026-08-13 14:14:48 +02:00
parent 8d1eeaa73a
commit b213f2ffed
4 changed files with 86 additions and 11 deletions

View File

@@ -55,6 +55,7 @@ func printToPdfActionFunc(reqCtx context.Context, logger *slog.Logger, outputPat
defer span.End() defer span.End()
err := func() error { err := func() error {
paperWidth := options.PaperWidth
paperHeight := options.PaperHeight paperHeight := options.PaperHeight
pageRanges := options.PageRanges pageRanges := options.PageRanges
@@ -68,9 +69,20 @@ func printToPdfActionFunc(reqCtx context.Context, logger *slog.Logger, outputPat
// There are 96 CSS pixels per inch. // There are 96 CSS pixels per inch.
// See https://issues.chromium.org/issues/40267771#comment14. // See https://issues.chromium.org/issues/40267771#comment14.
if options.Landscape {
// Landscape swaps the paper dimensions, so the page is
// WithPaperHeight wide by WithPaperWidth tall. Size both to
// the content so the width expands to fit a wide document
// (e.g. a table) instead of the height-only expansion
// landing on the width axis and truncating it.
// See https://github.com/gotenberg/gotenberg/issues/1390.
paperWidth = (cssContentSize.Height / 96) + options.MarginTop + options.MarginBottom
paperHeight = (cssContentSize.Width / 96) + options.MarginLeft + options.MarginRight
} else {
// We add top and bottom margins so that the content area // We add top and bottom margins so that the content area
// is large enough to fit the entire content. // is large enough to fit the entire content.
paperHeight = (cssContentSize.Height / 96) + options.MarginTop + options.MarginBottom paperHeight = (cssContentSize.Height / 96) + options.MarginTop + options.MarginBottom
}
pageRanges = "1" // little dirty hack to avoid leftovers. pageRanges = "1" // little dirty hack to avoid leftovers.
} }
@@ -79,7 +91,7 @@ func printToPdfActionFunc(reqCtx context.Context, logger *slog.Logger, outputPat
WithLandscape(options.Landscape). WithLandscape(options.Landscape).
WithPrintBackground(options.PrintBackground). WithPrintBackground(options.PrintBackground).
WithScale(options.Scale). WithScale(options.Scale).
WithPaperWidth(options.PaperWidth). WithPaperWidth(paperWidth).
WithPaperHeight(paperHeight). WithPaperHeight(paperHeight).
WithMarginTop(options.MarginTop). WithMarginTop(options.MarginTop).
WithMarginBottom(options.MarginBottom). WithMarginBottom(options.MarginBottom).

View File

@@ -62,6 +62,24 @@ Feature: /forms/chromium/convert/html
Page 12 Page 12
""" """
# A wide table on one landscape page: the page must expand its width to the
# content, so the rightmost column is not truncated and the page comes out
# landscape instead of the narrow-tall strip the height-only expansion used
# to produce. See https://github.com/gotenberg/gotenberg/issues/1390.
Scenario: POST /forms/chromium/convert/html (Single Page Landscape)
Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):
| files | testdata/wide-table-html/index.html | file |
| singlePage | true | field |
| landscape | true | field |
| Gotenberg-Output-Filename | foo | header |
Then the response status code should be 200
Then the response header "Content-Type" should be "application/pdf"
Then there should be 1 PDF(s) in the response
Then the "foo.pdf" PDF should have 1 page(s)
Then the "foo.pdf" PDF should be set to landscape orientation
Then the "foo.pdf" PDF should have content matching "Column 12" at page 1
Scenario: POST /forms/chromium/convert/html (Landscape) Scenario: POST /forms/chromium/convert/html (Landscape)
Given I have a default Gotenberg container Given I have a default Gotenberg container
When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s): When I make a "POST" request to Gotenberg at the "/forms/chromium/convert/html" endpoint with the following form data and header(s):

View File

@@ -1094,7 +1094,9 @@ func (s *scenario) thePdfShouldBeSetToLandscapeOrientation(ctx context.Context,
} }
output = strings.ReplaceAll(output, " ", "") output = strings.ReplaceAll(output, " ", "")
re := regexp.MustCompile(`Pagesize:(\d+)x(\d+).*`) // The dimensions can be fractional (e.g. a content-sized single page),
// so match floats, not just integers.
re := regexp.MustCompile(`Pagesize:([\d.]+)x([\d.]+)`)
matches := re.FindStringSubmatch(output) matches := re.FindStringSubmatch(output)
if len(matches) < 3 { if len(matches) < 3 {
@@ -1103,22 +1105,22 @@ func (s *scenario) thePdfShouldBeSetToLandscapeOrientation(ctx context.Context,
invert := kind == "should NOT" invert := kind == "should NOT"
width, err := strconv.Atoi(matches[1]) width, err := strconv.ParseFloat(matches[1], 64)
if err != nil { if err != nil {
return fmt.Errorf("convert width value %q to integer: %w", matches[1], err) return fmt.Errorf("convert width value %q to float: %w", matches[1], err)
} }
height, err := strconv.Atoi(matches[2]) height, err := strconv.ParseFloat(matches[2], 64)
if err != nil { if err != nil {
return fmt.Errorf("convert height value %q to integer: %w", matches[2], err) return fmt.Errorf("convert height value %q to float: %w", matches[2], err)
} }
if invert && height < width { if invert && height < width {
return fmt.Errorf("expected height %d to be greater than width %d", height, width) return fmt.Errorf("expected height %g to be greater than width %g", height, width)
} }
if !invert && width < height { if !invert && width < height {
return fmt.Errorf("expected width %d to be greater than height %d", width, height) return fmt.Errorf("expected width %g to be greater than height %g", width, height)
} }
return nil return nil

View File

@@ -0,0 +1,43 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Wide table</title>
<style>
html,
body {
margin: 0;
padding: 0;
}
table {
border-collapse: collapse;
white-space: nowrap;
}
td {
border: 1px solid #000;
padding: 8px 24px;
}
</style>
</head>
<body>
<!-- A single wide row: much wider than tall, so a correct single page is
landscape, and the rightmost column only survives if the width was
expanded to the content instead of truncated. -->
<table>
<tr>
<td>Column 1</td>
<td>Column 2</td>
<td>Column 3</td>
<td>Column 4</td>
<td>Column 5</td>
<td>Column 6</td>
<td>Column 7</td>
<td>Column 8</td>
<td>Column 9</td>
<td>Column 10</td>
<td>Column 11</td>
<td>Column 12</td>
</tr>
</table>
</body>
</html>