/** * Contrast check (#748): the text of a laid-out document against the * ground it is set on, found on the VDT so it runs as soon as a page is * laid out. A tagged PDF says what the text is; this says whether it can * be read. * * Two renditions, since the same pages go to a screen and to a press: * * - `screen`: the WCAG 2 contrast ratio of the sRGB colours, as the * canvas, the HTML and an RGB PDF show them. * - `print`: the same ratio worked out from the luminance each colour has * on paper — its separation on the job's output profile (the values of * a colour authored in CMYK as they are), read back through the profile * and taken relative to the bare paper, which is the white of a printed * page as the display's white is the white of a screen. Ink is never a * perfect black, least of all on uncoated stock: black on newsprint is * about 5:1 where a screen gives 21:1, and the number says so. Needs * the profile's transform (`options.transform`); without it only the * reversed text is checked. * * The threshold follows the text's size and weight (large text: 18 pt, or * 14 pt bold) and the level asked (`contrast.level`, AA or AAA). * * In print, text knocked out of an inked ground is reported on its own * (`reversedText`) when it is small, italic or light: its strokes fill in * on press whatever the ratio says. * * What it reads: the lines of every block (inline bold, italic, reference * and chip colours included), list markers, drop caps, captions, notes and * table cells, the words drawn on a picture (a figure's labels, #902, read * on their plate, else inside their halo; bare on the picture they are * skipped), and the text of design slots (running heads, openers, * heading designs, box titles, a composed page's decoration). The ground * is the topmost fill under the text: a design box, a callout, a caption * bar, a table cell, a chip, the box of a composed page's frame or the * template decoration under it (in the page's paint order, * `composedPaintOrder`), else the page's paper colour; a translucent colour is blended with what is * under it. Text over a picture is skipped (its ground is not a colour), * as are comic lettering, ruby and formulas. * * The pairs `contrast.allow` names (#1124: by colours, by the style the * text is set in, or both) are still reported, as accepted with the * entry's reason, so a host lists them apart and does not count them. */ import type { CmykPercent, ContrastAllowEntry, ContrastLevel, ResolvedContrastConfig } from './types.js'; import type { BoundingBox, ResolvedConfig, VDTDocument } from './vdt.js'; import { type OutputTransform } from './color/transform.js'; export type ContrastMedium = 'screen' | 'print'; /** What a piece of text is, for a host that words its findings. */ export type ContrastRole = 'body' | 'heading' | 'caption' | 'table' | 'runningHead' | 'design' | 'chip' | 'marker' | 'label'; /** Why reversed text is reported: under the size for any face, or under * the size for thin strokes while italic or light. */ export type ReversedTextReason = 'small' | 'italic' | 'light'; /** One text and ground combination the document sets, at one size and * weight, whether it passes or not. */ export interface ContrastPair { /** The text colour as painted (`#rrggbb`, a translucent one blended * with its ground). */ color: string; /** The ground as painted (`#rrggbb`). */ background: string; /** The same two as the configuration writes them (lower case, alpha * kept): what a colour field holds. */ textColor: string; groundColor: string; sizePt: number; weight: number; italic: boolean; /** Large text (18 pt, or 14 pt bold): the lower threshold applies. */ large: boolean; role: ContrastRole; /** How many runs of text are set so. */ count: number; /** Where the first one is: book-absolute page index, its box on the * sheet (page px) and its source range when it has one. */ pageIndex: number; rect: BoundingBox; sourceStart?: number; sourceEnd?: number; /** The first run's text, cut to 40 characters. */ text: string; /** The ratio the level asks of this size and weight. */ required: number; /** The WCAG ratio of the sRGB colours. */ screen: number; /** The ratio on paper; present when the output transform was given. */ print?: number; /** Set when the text is knocked out of an inked ground and is under the * sizes of `contrast.reversedText`. `inks`: how many of the four the * ground is built of. */ reversed?: { reasons: ReversedTextReason[]; minimumPt: number; inks: number; }; /** The styles the text is set in, innermost first (a chip style, a * label style, a paragraph or heading style, the box styles round it): * set only while `contrast.allow` names a style, the pairs then kept * apart by them. */ styles?: string[]; } /** Why a finding is accepted: the `contrast.allow` entry it matches. */ export interface ContrastAccepted { reason: string; fg?: string; bg?: string; style?: string; } export type ContrastIssue = { /** Book-absolute page index of the first occurrence. */ pageIndex: number; rect: BoundingBox; sourceStart?: number; sourceEnd?: number; color: string; background: string; /** The smallest size the pair is set at, and that run's weight. */ sizePt: number; weight: number; italic: boolean; role: ContrastRole; text: string; /** Runs of text set so, over every size sharing the finding. */ count: number; /** The pair is one `contrast.allow` accepts (#1124): listed, not a * warning. */ accepted?: ContrastAccepted; } & ({ kind: 'lowContrast'; level: ContrastLevel; large: boolean; required: number; /** The ratio in each rendition checked. */ screen?: number; print?: number; /** The renditions under `required`. */ failing: ContrastMedium[]; } | { kind: 'reversedText'; reasons: ReversedTextReason[]; minimumPt: number; inks: number; }); export type ContrastKind = ContrastIssue['kind']; export interface ContrastOptions { /** The settings to check against; the document's `config.contrast` * (else the defaults) when omitted. */ contrast?: ResolvedContrastConfig; /** The renditions to check, whatever `contrast.mode` says. */ media?: readonly ContrastMedium[]; /** The separation of the job's output profile: gives the print ratio * and counts the inks of a ground. */ transform?: OutputTransform; /** `contrastPairs(doc, …)` under the same settings and transform, when * the host already has them: `contrastDocument` then skips the walk. */ pairs?: readonly ContrastPair[]; } /** `top` painted over `under`, as `#rrggbb`: a translucent colour * (`#rrggbbaa`) blended, an opaque one as it is. `under` reads as opaque. * A colour that is no hex gives `under`. */ export declare function blendColors(top: string, under: string): string; /** The relative luminance of an sRGB colour (WCAG 2), 0 for black to 1 for * white. Alpha is ignored; a colour that is no hex reads as black. */ export declare function relativeLuminance(color: string): number; /** The WCAG 2 contrast ratio of two sRGB colours, 1 to 21. */ export declare function contrastRatio(a: string, b: string): number; /** Whether text counts as large (WCAG 2): 18 pt, or 14 pt at a weight of * 700 and over. */ export declare function isLargeText(sizePt: number, weight?: number): boolean; /** The ratio a level asks: AA 4.5:1 (3:1 for large text), AAA 7:1 * (4.5:1). */ export declare function contrastThreshold(level: ContrastLevel, large: boolean): number; /** What the print measures need: the job's separation, and the colours of * the configuration authored in CMYK (`authoredCmykColors`), which print * as written. */ export interface PrintContrastContext { transform: OutputTransform; authored?: ReadonlyMap; } /** The process values a colour prints with, percent: its authored CMYK, * else its separation on the output profile. */ export declare function printSeparation(color: string, context: PrintContrastContext): CmykPercent; /** The luminance a colour has printed, relative to the bare paper: its * separation read back through the profile (media-relative), 0 to 1. * Paper is 1, as a display's white is in the screen measure; solid black * is about 0.02 on coated stock and 0.1 to 0.17 on newsprint. */ export declare function printLuminance(color: string, context: PrintContrastContext): number; /** The contrast ratio of two colours on paper: the WCAG formula over * their printed luminances. */ export declare function printContrastRatio(a: string, b: string, context: PrintContrastContext): number; /** The renditions a document is checked in under `contrast.mode`: with * `'auto'`, the screen always and print for a book set up for print (a * PDF/X standard, a CMYK PDF, or crop marks). */ export declare function contrastMedia(config: ResolvedConfig, contrast?: ResolvedContrastConfig): ContrastMedium[]; /** * Every text and ground combination `doc` sets, with its ratio on screen * and, when `options.transform` is given, on paper — passing or not, one * entry per colours, size, weight and slant. Runs whatever * `contrast.enabled` says: a host shows these beside its colour fields. */ export declare function contrastPairs(doc: VDTDocument, options?: ContrastOptions): ContrastPair[]; /** * The text of `doc` that does not read: every text and ground pair under * the ratio its size, its weight and `contrast.level` ask, in the * renditions `contrast.mode` names (`lowContrast`, one finding per pair * and threshold, at its first occurrence), and in print the reversed text * under the sizes of `contrast.reversedText` (`reversedText`). Worst * ratio first. Empty when `contrast.enabled` is off. */ export declare function contrastDocument(doc: VDTDocument, options?: ContrastOptions): ContrastIssue[]; /** The first `contrast.allow` entry (resolved: colours `#rrggbb` in lower * case) that accepts `pair`: its colours are the text's and the ground's * as written or as painted, its style one the text is set in. */ export declare function allowEntryFor(pair: ContrastPair, allow: readonly ContrastAllowEntry[]): ContrastAllowEntry | undefined; //# sourceMappingURL=contrast.d.ts.map