diff --git a/docs/src/api/class-page.md b/docs/src/api/class-page.md index 03937505b8..21b51acde8 100644 --- a/docs/src/api/class-page.md +++ b/docs/src/api/class-page.md @@ -2988,6 +2988,18 @@ Give any CSS `@page` size declared in the page priority over what is declared in [`option: height`] or [`option: format`] options. Defaults to `false`, which will scale the content to fit the paper size. +### option: Page.pdf.tagged +* since: v1.42 +- `tagged` <[boolean]> + +Whether or not to generate tagged (accessible) PDF. Defaults to `false`. + +### option: Page.pdf.outline +* since: v1.42 +- `outline` <[boolean]> + +Whether or not to embed the document outline into the PDF. Defaults to `false`. + ## async method: Page.press * since: v1.8 * discouraged: Use locator-based [`method: Locator.press`] instead. Read more about [locators](../locators.md). diff --git a/packages/playwright-core/src/protocol/validator.ts b/packages/playwright-core/src/protocol/validator.ts index e67f38e9c2..f33a3891b6 100644 --- a/packages/playwright-core/src/protocol/validator.ts +++ b/packages/playwright-core/src/protocol/validator.ts @@ -1203,6 +1203,8 @@ scheme.PagePdfParams = tObject({ left: tOptional(tString), right: tOptional(tString), })), + tagged: tOptional(tBoolean), + outline: tOptional(tBoolean), }); scheme.PagePdfResult = tObject({ pdf: tBinary, diff --git a/packages/playwright-core/src/server/chromium/crPdf.ts b/packages/playwright-core/src/server/chromium/crPdf.ts index 0219c18444..8dae2d1fa1 100644 --- a/packages/playwright-core/src/server/chromium/crPdf.ts +++ b/packages/playwright-core/src/server/chromium/crPdf.ts @@ -78,6 +78,8 @@ export class CRPDF { pageRanges = '', preferCSSPageSize = false, margin = {}, + tagged = false, + outline = false } = options; let paperWidth = 8.5; @@ -96,7 +98,8 @@ export class CRPDF { const marginLeft = convertPrintParameterToInches(margin.left) || 0; const marginBottom = convertPrintParameterToInches(margin.bottom) || 0; const marginRight = convertPrintParameterToInches(margin.right) || 0; - + const generateDocumentOutline = outline; + const generateTaggedPDF = tagged; const result = await this._client.send('Page.printToPDF', { transferMode: 'ReturnAsStream', landscape, @@ -112,7 +115,9 @@ export class CRPDF { marginLeft, marginRight, pageRanges, - preferCSSPageSize + preferCSSPageSize, + generateTaggedPDF, + generateDocumentOutline }); return await readProtocolStream(this._client, result.stream!); } diff --git a/packages/playwright-core/types/types.d.ts b/packages/playwright-core/types/types.d.ts index 80bb5c52bb..95c0ddcdd0 100644 --- a/packages/playwright-core/types/types.d.ts +++ b/packages/playwright-core/types/types.d.ts @@ -3492,6 +3492,11 @@ export interface Page { left?: string|number; }; + /** + * Whether or not to embed the document outline into the PDF. Defaults to `false`. + */ + outline?: boolean; + /** * Paper ranges to print, e.g., '1-5, 8, 11-13'. Defaults to the empty string, which means print all pages. */ @@ -3519,6 +3524,11 @@ export interface Page { */ scale?: number; + /** + * Whether or not to generate tagged (accessible) PDF. Defaults to `false`. + */ + tagged?: boolean; + /** * Paper width, accepts values labeled with units. */ diff --git a/packages/protocol/src/channels.ts b/packages/protocol/src/channels.ts index 37811f4d6c..379b5a48e8 100644 --- a/packages/protocol/src/channels.ts +++ b/packages/protocol/src/channels.ts @@ -2174,6 +2174,8 @@ export type PagePdfParams = { left?: string, right?: string, }, + tagged?: boolean, + outline?: boolean, }; export type PagePdfOptions = { scale?: number, @@ -2193,6 +2195,8 @@ export type PagePdfOptions = { left?: string, right?: string, }, + tagged?: boolean, + outline?: boolean, }; export type PagePdfResult = { pdf: Binary, diff --git a/packages/protocol/src/protocol.yml b/packages/protocol/src/protocol.yml index feeda1c317..c21cd006e9 100644 --- a/packages/protocol/src/protocol.yml +++ b/packages/protocol/src/protocol.yml @@ -1560,6 +1560,8 @@ Page: bottom: string? left: string? right: string? + tagged: boolean? + outline: boolean? returns: pdf: binary diff --git a/tests/assets/headings.html b/tests/assets/headings.html new file mode 100644 index 0000000000..d1f1ad620a --- /dev/null +++ b/tests/assets/headings.html @@ -0,0 +1,15 @@ + + + + + Headings + + + +

Title

+

Subtitle

+

Subsubtitle

+

Subtitle

+ + + \ No newline at end of file diff --git a/tests/library/pdf.spec.ts b/tests/library/pdf.spec.ts index 74b89b776e..3ef002e25c 100644 --- a/tests/library/pdf.spec.ts +++ b/tests/library/pdf.spec.ts @@ -26,3 +26,18 @@ it('should be able to save file', async ({ contextFactory, headless, browserName await page.pdf({ path: outputFile }); expect(fs.readFileSync(outputFile).byteLength).toBeGreaterThan(0); }); + +it('should be able to generate outline', async ({ contextFactory, server, headless, browserName }, testInfo) => { + it.skip(!headless || browserName !== 'chromium', 'Printing to pdf is currently only supported in headless chromium.'); + // const context = await contextFactory(); + const context = await contextFactory({ + baseURL: server.PREFIX, + }); + const page = await context.newPage(); + await page.goto('/headings.html'); + const outputFileNoOutline = testInfo.outputPath('outputNoOutline.pdf'); + const outputFileOutline = testInfo.outputPath('outputOutline.pdf'); + await page.pdf({ path: outputFileNoOutline }); + await page.pdf({ path: outputFileOutline, tagged: true, outline: true }); + expect(fs.readFileSync(outputFileOutline).byteLength).toBeGreaterThan(fs.readFileSync(outputFileNoOutline).byteLength); +});