diff --git a/pkg/modules/chromium/tasks.go b/pkg/modules/chromium/tasks.go index 38662f20..6fa6cd5f 100644 --- a/pkg/modules/chromium/tasks.go +++ b/pkg/modules/chromium/tasks.go @@ -55,6 +55,7 @@ func printToPdfActionFunc(reqCtx context.Context, logger *slog.Logger, outputPat defer span.End() err := func() error { + paperWidth := options.PaperWidth paperHeight := options.PaperHeight pageRanges := options.PageRanges @@ -68,9 +69,20 @@ func printToPdfActionFunc(reqCtx context.Context, logger *slog.Logger, outputPat // There are 96 CSS pixels per inch. // See https://issues.chromium.org/issues/40267771#comment14. - // We add top and bottom margins so that the content area - // is large enough to fit the entire content. - paperHeight = (cssContentSize.Height / 96) + options.MarginTop + options.MarginBottom + 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 + // is large enough to fit the entire content. + paperHeight = (cssContentSize.Height / 96) + options.MarginTop + options.MarginBottom + } pageRanges = "1" // little dirty hack to avoid leftovers. } @@ -79,7 +91,7 @@ func printToPdfActionFunc(reqCtx context.Context, logger *slog.Logger, outputPat WithLandscape(options.Landscape). WithPrintBackground(options.PrintBackground). WithScale(options.Scale). - WithPaperWidth(options.PaperWidth). + WithPaperWidth(paperWidth). WithPaperHeight(paperHeight). WithMarginTop(options.MarginTop). WithMarginBottom(options.MarginBottom). diff --git a/test/integration/features/chromium_convert_html.feature b/test/integration/features/chromium_convert_html.feature index c111aa91..af256113 100644 --- a/test/integration/features/chromium_convert_html.feature +++ b/test/integration/features/chromium_convert_html.feature @@ -62,6 +62,24 @@ Feature: /forms/chromium/convert/html 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) 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): diff --git a/test/integration/scenario/scenario.go b/test/integration/scenario/scenario.go index 5ef72322..0478078e 100644 --- a/test/integration/scenario/scenario.go +++ b/test/integration/scenario/scenario.go @@ -1094,7 +1094,9 @@ func (s *scenario) thePdfShouldBeSetToLandscapeOrientation(ctx context.Context, } 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) if len(matches) < 3 { @@ -1103,22 +1105,22 @@ func (s *scenario) thePdfShouldBeSetToLandscapeOrientation(ctx context.Context, invert := kind == "should NOT" - width, err := strconv.Atoi(matches[1]) + width, err := strconv.ParseFloat(matches[1], 64) 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 { - 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 { - 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 { - 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 diff --git a/test/integration/testdata/wide-table-html/index.html b/test/integration/testdata/wide-table-html/index.html new file mode 100644 index 00000000..a7da1830 --- /dev/null +++ b/test/integration/testdata/wide-table-html/index.html @@ -0,0 +1,43 @@ + + +
+ +| Column 1 | +Column 2 | +Column 3 | +Column 4 | +Column 5 | +Column 6 | +Column 7 | +Column 8 | +Column 9 | +Column 10 | +Column 11 | +Column 12 | +