refactor: move PDF options to utilities (#11651)

This commit is contained in:
jrandolf 2024-01-08 19:45:32 +01:00 committed by GitHub
parent cf16cb49c9
commit 27dd2fc8ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 112 additions and 113 deletions

View File

@ -47,12 +47,7 @@ import {
} from '../common/EventEmitter.js';
import type {FileChooser} from '../common/FileChooser.js';
import {NetworkManagerEvent} from '../common/NetworkManagerEvents.js';
import {
paperFormats,
type LowerCasePaperFormat,
type ParsedPDFOptions,
type PDFOptions,
} from '../common/PDFOptions.js';
import type {PDFOptions} from '../common/PDFOptions.js';
import {TimeoutSettings} from '../common/TimeoutSettings.js';
import type {
Awaitable,
@ -64,14 +59,12 @@ import type {
import {
debugError,
importFSPromises,
isNumber,
isString,
timeout,
withSourcePuppeteerURLIfNone,
} from '../common/util.js';
import type {Viewport} from '../common/Viewport.js';
import type {ScreenRecorder} from '../node/ScreenRecorder.js';
import {assert} from '../util/assert.js';
import {guarded} from '../util/decorators.js';
import {
AsyncDisposableStack,
@ -2499,60 +2492,6 @@ export abstract class Page extends EventEmitter<PageEvents> {
*/
abstract _screenshot(options: Readonly<ScreenshotOptions>): Promise<string>;
/**
* @internal
*/
_getPDFOptions(
options: PDFOptions = {},
lengthUnit: 'in' | 'cm' = 'in'
): ParsedPDFOptions {
const defaults: Omit<ParsedPDFOptions, 'width' | 'height' | 'margin'> = {
scale: 1,
displayHeaderFooter: false,
headerTemplate: '',
footerTemplate: '',
printBackground: false,
landscape: false,
pageRanges: '',
preferCSSPageSize: false,
omitBackground: false,
timeout: 30000,
tagged: false,
};
let width = 8.5;
let height = 11;
if (options.format) {
const format =
paperFormats[options.format.toLowerCase() as LowerCasePaperFormat];
assert(format, 'Unknown paper format: ' + options.format);
width = format.width;
height = format.height;
} else {
width = convertPrintParameterToInches(options.width, lengthUnit) ?? width;
height =
convertPrintParameterToInches(options.height, lengthUnit) ?? height;
}
const margin = {
top: convertPrintParameterToInches(options.margin?.top, lengthUnit) || 0,
left:
convertPrintParameterToInches(options.margin?.left, lengthUnit) || 0,
bottom:
convertPrintParameterToInches(options.margin?.bottom, lengthUnit) || 0,
right:
convertPrintParameterToInches(options.margin?.right, lengthUnit) || 0,
};
return {
...defaults,
...options,
width,
height,
margin,
};
}
/**
* Generates a PDF of the page with the `print` CSS media type.
*
@ -3017,50 +2956,6 @@ export const supportedMetrics = new Set<string>([
'JSHeapTotalSize',
]);
/**
* @internal
*/
export const unitToPixels = {
px: 1,
in: 96,
cm: 37.8,
mm: 3.78,
};
function convertPrintParameterToInches(
parameter?: string | number,
lengthUnit: 'in' | 'cm' = 'in'
): number | undefined {
if (typeof parameter === 'undefined') {
return undefined;
}
let pixels;
if (isNumber(parameter)) {
// Treat numbers as pixel values to be aligned with phantom's paperSize.
pixels = parameter;
} else if (isString(parameter)) {
const text = parameter;
let unit = text.substring(text.length - 2).toLowerCase();
let valueText = '';
if (unit in unitToPixels) {
valueText = text.substring(0, text.length - 2);
} else {
// In case of unknown unit try to parse the whole parameter as number of pixels.
// This is consistent with phantom's paperSize behavior.
unit = 'px';
valueText = text;
}
const value = Number(valueText);
assert(!isNaN(value), 'Failed to parse parameter value: ' + text);
pixels = value * unitToPixels[unit as keyof typeof unitToPixels];
} else {
throw new Error(
'page.pdf() Cannot handle parameter type: ' + typeof parameter
);
}
return pixels / unitToPixels[lengthUnit];
}
/** @see https://w3c.github.io/webdriver-bidi/#normalize-rect */
function normalizeRectangle<BoundingBoxType extends BoundingBox>(
clip: Readonly<BoundingBoxType>

View File

@ -48,6 +48,7 @@ import {
debugError,
evaluationString,
NETWORK_IDLE_TIME,
parsePDFOptions,
timeout,
validateDialogType,
waitForHTTP,
@ -586,7 +587,8 @@ export class BidiPage extends Page {
}
override async pdf(options: PDFOptions = {}): Promise<Buffer> {
const {path = undefined} = options;
const {timeout: ms = this._timeoutSettings.timeout(), path = undefined} =
options;
const {
printBackground: background,
margin,
@ -596,8 +598,7 @@ export class BidiPage extends Page {
pageRanges: ranges,
scale,
preferCSSPageSize,
timeout: ms,
} = this._getPDFOptions(options, 'cm');
} = parsePDFOptions(options, 'cm');
const pageRanges = ranges ? ranges.split(', ') : [];
const {result} = await firstValueFrom(
from(

View File

@ -45,6 +45,7 @@ import {
getReadableFromProtocolStream,
NETWORK_IDLE_TIME,
pageBindingInitString,
parsePDFOptions,
timeout,
validateDialogType,
valueFromRemoteObject,
@ -1134,6 +1135,7 @@ export class CdpPage extends Page {
}
override async createPDFStream(options: PDFOptions = {}): Promise<Readable> {
const {timeout: ms = this._timeoutSettings.timeout()} = options;
const {
landscape,
displayHeaderFooter,
@ -1147,9 +1149,8 @@ export class CdpPage extends Page {
pageRanges,
preferCSSPageSize,
omitBackground,
timeout: ms,
tagged: generateTaggedPDF,
} = this._getPDFOptions(options);
} = parsePDFOptions(options);
if (omitBackground) {
await this.#emulationManager.setTransparentBackgroundColor();

View File

@ -195,7 +195,7 @@ export interface ParsedPDFOptionsInterface {
* @internal
*/
export type ParsedPDFOptions = Required<
Omit<PDFOptions, 'path' | 'format'> & ParsedPDFOptionsInterface
Omit<PDFOptions, 'path' | 'format' | 'timeout'> & ParsedPDFOptionsInterface
>;
/**

View File

@ -9,11 +9,11 @@ import type {Readable} from 'stream';
import type {Protocol} from 'devtools-protocol';
import type {Observable} from '../../third_party/rxjs/rxjs.js';
import {
map,
NEVER,
timer,
type Observable,
firstValueFrom,
fromEvent,
filterAsync,
@ -30,6 +30,12 @@ import {debug} from './Debug.js';
import {TimeoutError} from './Errors.js';
import type {EventEmitter, EventType} from './EventEmitter.js';
import type {NetworkManagerEvents} from './NetworkManagerEvents.js';
import type {
LowerCasePaperFormat,
ParsedPDFOptions,
PDFOptions,
} from './PDFOptions.js';
import {paperFormats} from './PDFOptions.js';
/**
* @internal
@ -609,3 +615,99 @@ export async function waitForHTTP<T extends {url(): string}>(
* @internal
*/
export const NETWORK_IDLE_TIME = 500;
/**
* @internal
*/
export function parsePDFOptions(
options: PDFOptions = {},
lengthUnit: 'in' | 'cm' = 'in'
): ParsedPDFOptions {
const defaults: Omit<ParsedPDFOptions, 'width' | 'height' | 'margin'> = {
scale: 1,
displayHeaderFooter: false,
headerTemplate: '',
footerTemplate: '',
printBackground: false,
landscape: false,
pageRanges: '',
preferCSSPageSize: false,
omitBackground: false,
tagged: false,
};
let width = 8.5;
let height = 11;
if (options.format) {
const format =
paperFormats[options.format.toLowerCase() as LowerCasePaperFormat];
assert(format, 'Unknown paper format: ' + options.format);
width = format.width;
height = format.height;
} else {
width = convertPrintParameterToInches(options.width, lengthUnit) ?? width;
height =
convertPrintParameterToInches(options.height, lengthUnit) ?? height;
}
const margin = {
top: convertPrintParameterToInches(options.margin?.top, lengthUnit) || 0,
left: convertPrintParameterToInches(options.margin?.left, lengthUnit) || 0,
bottom:
convertPrintParameterToInches(options.margin?.bottom, lengthUnit) || 0,
right:
convertPrintParameterToInches(options.margin?.right, lengthUnit) || 0,
};
return {
...defaults,
...options,
width,
height,
margin,
};
}
/**
* @internal
*/
export const unitToPixels = {
px: 1,
in: 96,
cm: 37.8,
mm: 3.78,
};
function convertPrintParameterToInches(
parameter?: string | number,
lengthUnit: 'in' | 'cm' = 'in'
): number | undefined {
if (typeof parameter === 'undefined') {
return undefined;
}
let pixels;
if (isNumber(parameter)) {
// Treat numbers as pixel values to be aligned with phantom's paperSize.
pixels = parameter;
} else if (isString(parameter)) {
const text = parameter;
let unit = text.substring(text.length - 2).toLowerCase();
let valueText = '';
if (unit in unitToPixels) {
valueText = text.substring(0, text.length - 2);
} else {
// In case of unknown unit try to parse the whole parameter as number of pixels.
// This is consistent with phantom's paperSize behavior.
unit = 'px';
valueText = text;
}
const value = Number(valueText);
assert(!isNaN(value), 'Failed to parse parameter value: ' + text);
pixels = value * unitToPixels[unit as keyof typeof unitToPixels];
} else {
throw new Error(
'page.pdf() Cannot handle parameter type: ' + typeof parameter
);
}
return pixels / unitToPixels[lengthUnit];
}