Skip to content

Commit ce2e404

Browse files
authored
Add outline to PDF generation (#2485)
1 parent 755f53f commit ce2e404

File tree

8 files changed

+58
-75
lines changed

8 files changed

+58
-75
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ await page.GoToAsync("http://www.google.com"); // In case of fonts being loaded
9090
await page.EvaluateExpressionHandleAsync("document.fonts.ready"); // Wait for fonts to be loaded. Omitting this might result in no text rendered in pdf.
9191
await page.PdfAsync(outputFile);
9292
```
93-
<sup><a href='https://github.com/hardkoded/puppeteer-sharp/blob/master/lib/PuppeteerSharp.Tests/PageTests/PdfTests.cs#L27-L37' title='Snippet source file'>snippet source</a> | <a href='#snippet-pdfasync' title='Start of snippet'>anchor</a></sup>
93+
<sup><a href='https://github.com/hardkoded/puppeteer-sharp/blob/master/lib/PuppeteerSharp.Tests/PageTests/PdfTests.cs#L23-L33' title='Snippet source file'>snippet source</a> | <a href='#snippet-pdfasync' title='Start of snippet'>anchor</a></sup>
9494
<!-- endSnippet -->
9595

9696
### Inject HTML
Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
<!DOCTYPE html>
22
<html lang="en">
3-
<head>
3+
<head>
44
<meta charset="UTF-8" />
55
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
66
<title>PDF</title>
7-
</head>
8-
<body>
9-
<div>PDF Content</div>
10-
</body>
7+
</head>
8+
<body>
9+
<h1>PDF Content</h1>
10+
<section>
11+
<h1>PDF Subcontent 1</h1>
12+
</section>
13+
<section>
14+
<h1>PDF Subcontent 2</h1>
15+
</section>
16+
</body>
1117
</html>

lib/PuppeteerSharp.Tests/PageTests/PdfTests.cs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,6 @@ namespace PuppeteerSharp.Tests.PageTests
1010
{
1111
public class PdfTests : PuppeteerPageBaseTest
1212
{
13-
public PdfTests() : base()
14-
{
15-
}
16-
1713
[Test]
1814
public async Task Usage()
1915
{
@@ -102,6 +98,31 @@ public async Task CanPrintToPdfWithAccessible()
10298
Assert.Greater(new FileInfo(accessibleOutputFile).Length, new FileInfo(outputFile).Length);
10399
}
104100

101+
[Test, Retry(2), PuppeteerTest("pdf.spec", "Page.pdf", "can print to PDF with outline")]
102+
public async Task CanPrintToPdfWithOutline()
103+
{
104+
var outputFile = Path.Combine(BaseDirectory, "output.pdf");
105+
var outputFileOutlined = Path.Combine(BaseDirectory, "output-outlined.pdf");
106+
var fileInfo = new FileInfo(outputFile);
107+
if (fileInfo.Exists)
108+
{
109+
fileInfo.Delete();
110+
}
111+
112+
fileInfo = new FileInfo(outputFileOutlined);
113+
if (fileInfo.Exists)
114+
{
115+
fileInfo.Delete();
116+
}
117+
118+
await Page.GoToAsync(TestConstants.ServerUrl + "/pdf.html");
119+
await Page.PdfAsync(outputFile);
120+
await Page.PdfAsync(outputFileOutlined, new PdfOptions { Tagged = true });
121+
122+
Assert.Greater(new FileInfo(outputFileOutlined).Length, new FileInfo(outputFile).Length);
123+
}
124+
125+
[Test]
105126
public void PdfOptionsShouldBeSerializable()
106127
{
107128
var pdfOptions = new PdfOptions

lib/PuppeteerSharp/ChromiumLauncher.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ internal static string[] GetDefaultArgs(LaunchOptions options)
9696
"--enable-automation",
9797
"--enable-blink-features=IdleDetection",
9898
"--export-tagged-pdf",
99+
"--generate-pdf-document-outline",
99100
"--force-color-profile=srgb",
100101
"--metrics-recording-only",
101102
"--no-first-run",

lib/PuppeteerSharp/ElementHandle.cs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ public Task<IElementHandle[]> XPathAsync(string expression)
340340

341341
/// <inheritdoc/>
342342
public Task<BoundingBox> BoundingBoxAsync()
343-
=> BindIsolatedHandleAsync<BoundingBox>(async handle =>
343+
=> BindIsolatedHandleAsync(async handle =>
344344
{
345345
var box = await handle.EvaluateFunctionAsync<BoundingBox>(@"element => {
346346
if (!(element instanceof Element)) {
@@ -377,7 +377,7 @@ public Task<BoundingBox> BoundingBoxAsync()
377377

378378
/// <inheritdoc/>
379379
public Task<BoxModel> BoxModelAsync()
380-
=> BindIsolatedHandleAsync<BoxModel>(async handle =>
380+
=> BindIsolatedHandleAsync(async handle =>
381381
{
382382
var model = await handle.EvaluateFunctionAsync<BoxModel>(@"element => {
383383
if (!(element instanceof Element)) {
@@ -683,11 +683,7 @@ await Page.Mouse
683683
public Task<BoxModelPoint> ClickablePointAsync(Offset? offset = null)
684684
=> BindIsolatedHandleAsync(async handle =>
685685
{
686-
var box = await handle.ClickableBoxAsync().ConfigureAwait(false);
687-
if (box == null)
688-
{
689-
throw new PuppeteerException("Node is either not clickable or not an Element");
690-
}
686+
var box = await handle.ClickableBoxAsync().ConfigureAwait(false) ?? throw new PuppeteerException("Node is either not clickable or not an Element");
691687

692688
if (offset != null)
693689
{

lib/PuppeteerSharp/Messaging/PagePrintToPDFRequest.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,7 @@ internal class PagePrintToPDFRequest
3333
public string TransferMode { get; set; }
3434

3535
public bool GenerateTaggedPDF { get; set; }
36+
37+
public bool GenerateDocumentOutline { get; set; }
3638
}
3739
}

lib/PuppeteerSharp/Page.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,6 +1183,11 @@ private async Task<byte[]> PdfInternalAsync(string file, PdfOptions options)
11831183
var marginBottom = ConvertPrintParameterToInches(options.MarginOptions.Bottom);
11841184
var marginRight = ConvertPrintParameterToInches(options.MarginOptions.Right);
11851185

1186+
if (options.Outline)
1187+
{
1188+
options.Tagged = true;
1189+
}
1190+
11861191
if (options.OmitBackground)
11871192
{
11881193
await _emulationManager.SetTransparentBackgroundColorAsync().ConfigureAwait(false);
@@ -1206,6 +1211,7 @@ private async Task<byte[]> PdfInternalAsync(string file, PdfOptions options)
12061211
PageRanges = options.PageRanges,
12071212
PreferCSSPageSize = options.PreferCSSPageSize,
12081213
GenerateTaggedPDF = options.Tagged,
1214+
GenerateDocumentOutline = options.Outline,
12091215
}).ConfigureAwait(false);
12101216

12111217
if (options.OmitBackground)

lib/PuppeteerSharp/PdfOptions.cs

Lines changed: 9 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace PuppeteerSharp
77
/// <summary>
88
/// Options to be used in <see cref="IPage.PdfAsync(string, PdfOptions)"/>, <see cref="IPage.PdfStreamAsync(PdfOptions)"/> and <see cref="IPage.PdfDataAsync(PdfOptions)"/>.
99
/// </summary>
10-
public class PdfOptions : IEquatable<PdfOptions>
10+
public record PdfOptions
1111
{
1212
/// <summary>
1313
/// Initializes a new instance of the <see cref="PuppeteerSharp.PdfOptions"/> class.
@@ -97,62 +97,13 @@ public PdfOptions()
9797
/// </summary>
9898
public bool Tagged { get; set; }
9999

100-
/// <summary>Overriding == operator for <see cref="PdfOptions"/>.</summary>
101-
/// <param name="left">the value to compare against <paramref name="right" />.</param>
102-
/// <param name="right">the value to compare against <paramref name="left" />.</param>
103-
/// <returns><c>true</c> if the two instances are equal to the same value.</returns>
104-
public static bool operator ==(PdfOptions left, PdfOptions right)
105-
=> EqualityComparer<PdfOptions>.Default.Equals(left, right);
106-
107-
/// <summary>Overriding != operator for <see cref="PdfOptions"/>.</summary>
108-
/// <param name="left">the value to compare against <paramref name="right" />.</param>
109-
/// <param name="right">the value to compare against <paramref name="left" />.</param>
110-
/// <returns><c>true</c> if the two instances are not equal to the same value.</returns>
111-
public static bool operator !=(PdfOptions left, PdfOptions right) => !(left == right);
112-
113-
/// <inheritdoc/>
114-
public override bool Equals(object obj)
115-
{
116-
if (obj == null || GetType() != obj.GetType())
117-
{
118-
return false;
119-
}
120-
121-
return Equals((PdfOptions)obj);
122-
}
123-
124-
/// <inheritdoc/>
125-
public bool Equals(PdfOptions options)
126-
=> options != null &&
127-
Scale == options.Scale &&
128-
DisplayHeaderFooter == options.DisplayHeaderFooter &&
129-
HeaderTemplate == options.HeaderTemplate &&
130-
FooterTemplate == options.FooterTemplate &&
131-
PrintBackground == options.PrintBackground &&
132-
Landscape == options.Landscape &&
133-
PageRanges == options.PageRanges &&
134-
EqualityComparer<PaperFormat>.Default.Equals(Format, options.Format) &&
135-
EqualityComparer<object>.Default.Equals(Width, options.Width) &&
136-
EqualityComparer<object>.Default.Equals(Height, options.Height) &&
137-
EqualityComparer<MarginOptions>.Default.Equals(MarginOptions, options.MarginOptions) &&
138-
PreferCSSPageSize == options.PreferCSSPageSize &&
139-
OmitBackground == options.OmitBackground;
140-
141-
/// <inheritdoc/>
142-
public override int GetHashCode()
143-
=> -711844102
144-
^ Scale.GetHashCode()
145-
^ DisplayHeaderFooter.GetHashCode()
146-
^ EqualityComparer<string>.Default.GetHashCode(HeaderTemplate)
147-
^ EqualityComparer<string>.Default.GetHashCode(FooterTemplate)
148-
^ PrintBackground.GetHashCode()
149-
^ OmitBackground.GetHashCode()
150-
^ Landscape.GetHashCode()
151-
^ EqualityComparer<string>.Default.GetHashCode(PageRanges)
152-
^ EqualityComparer<PaperFormat>.Default.GetHashCode(Format)
153-
^ EqualityComparer<object>.Default.GetHashCode(Width)
154-
^ EqualityComparer<object>.Default.GetHashCode(Height)
155-
^ EqualityComparer<MarginOptions>.Default.GetHashCode(MarginOptions)
156-
^ PreferCSSPageSize.GetHashCode();
100+
/// <summary>
101+
/// Generate document outline.
102+
/// </summary>
103+
/// <remarks>
104+
/// If this is enabled the PDF will also be tagged (accessible)
105+
/// Currently only works in old Headless (headless = true).
106+
/// </remarks>
107+
public bool Outline { get; set; } = false;
157108
}
158109
}

0 commit comments

Comments
 (0)