@afixt/screenshot-utils 0.9.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/README.md +20 -20
- package/dist/index.js +172 -16
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +172 -16
- package/dist/index.mjs.map +1 -1
- package/dist/types/adapters/cdp.d.ts +28 -0
- package/dist/types/adapters/cdp.d.ts.map +1 -0
- package/dist/types/adapters/index.d.ts +5 -0
- package/dist/types/adapters/index.d.ts.map +1 -0
- package/dist/types/adapters/playwright.d.ts +28 -0
- package/dist/types/adapters/playwright.d.ts.map +1 -0
- package/dist/types/adapters/puppeteer.d.ts +20 -0
- package/dist/types/adapters/puppeteer.d.ts.map +1 -0
- package/dist/types/capture/element.d.ts +20 -0
- package/dist/types/capture/element.d.ts.map +1 -0
- package/dist/types/capture/index.d.ts +8 -0
- package/dist/types/capture/index.d.ts.map +1 -0
- package/dist/types/capture/long-page.d.ts +16 -0
- package/dist/types/capture/long-page.d.ts.map +1 -0
- package/dist/types/capture/page.d.ts +14 -0
- package/dist/types/capture/page.d.ts.map +1 -0
- package/dist/types/capture/responsive.d.ts +20 -0
- package/dist/types/capture/responsive.d.ts.map +1 -0
- package/dist/types/capture/settle.d.ts +14 -0
- package/dist/types/capture/settle.d.ts.map +1 -0
- package/dist/types/capture/viewport.d.ts +14 -0
- package/dist/types/capture/viewport.d.ts.map +1 -0
- package/dist/types/cli/index.d.ts +10 -0
- package/dist/types/cli/index.d.ts.map +1 -0
- package/dist/types/compose/annotate.d.ts +16 -0
- package/dist/types/compose/annotate.d.ts.map +1 -0
- package/dist/types/compose/diff.d.ts +15 -0
- package/dist/types/compose/diff.d.ts.map +1 -0
- package/dist/types/compose/heatmap.d.ts +17 -0
- package/dist/types/compose/heatmap.d.ts.map +1 -0
- package/dist/types/compose/index.d.ts +6 -0
- package/dist/types/compose/index.d.ts.map +1 -0
- package/dist/types/compose/theme.d.ts +17 -0
- package/dist/types/compose/theme.d.ts.map +1 -0
- package/dist/types/errors/adapter.d.ts +33 -0
- package/dist/types/errors/adapter.d.ts.map +1 -0
- package/dist/types/errors/base.d.ts +37 -0
- package/dist/types/errors/base.d.ts.map +1 -0
- package/dist/types/errors/capture.d.ts +109 -0
- package/dist/types/errors/capture.d.ts.map +1 -0
- package/dist/types/errors/compose.d.ts +35 -0
- package/dist/types/errors/compose.d.ts.map +1 -0
- package/dist/types/errors/index.d.ts +29 -0
- package/dist/types/errors/index.d.ts.map +1 -0
- package/dist/types/errors/optional.d.ts +23 -0
- package/dist/types/errors/optional.d.ts.map +1 -0
- package/dist/types/errors/redaction.d.ts +21 -0
- package/dist/types/errors/redaction.d.ts.map +1 -0
- package/dist/types/errors/tile.d.ts +29 -0
- package/dist/types/errors/tile.d.ts.map +1 -0
- package/dist/types/errors/transform.d.ts +35 -0
- package/dist/types/errors/transform.d.ts.map +1 -0
- package/dist/types/index.d.ts +58 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/redact/index.d.ts +5 -0
- package/dist/types/redact/index.d.ts.map +1 -0
- package/dist/types/redact/policy.d.ts +29 -0
- package/dist/types/redact/policy.d.ts.map +1 -0
- package/dist/types/redact/redact.d.ts +29 -0
- package/dist/types/redact/redact.d.ts.map +1 -0
- package/dist/types/tile/dzi.d.ts +18 -0
- package/dist/types/tile/dzi.d.ts.map +1 -0
- package/dist/types/tile/index.d.ts +3 -0
- package/dist/types/tile/index.d.ts.map +1 -0
- package/dist/types/transform/convert.d.ts +13 -0
- package/dist/types/transform/convert.d.ts.map +1 -0
- package/dist/types/transform/crop.d.ts +33 -0
- package/dist/types/transform/crop.d.ts.map +1 -0
- package/dist/types/transform/index.d.ts +7 -0
- package/dist/types/transform/index.d.ts.map +1 -0
- package/dist/types/transform/normalize.d.ts +14 -0
- package/dist/types/transform/normalize.d.ts.map +1 -0
- package/dist/types/transform/resize.d.ts +14 -0
- package/dist/types/transform/resize.d.ts.map +1 -0
- package/package.json +5 -4
- package/src/capture/element.js +48 -6
- package/src/capture/page.js +31 -10
- package/src/capture/settle.js +139 -4
- package/src/index.js +3 -0
- package/src/types/index.d.ts +10 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An operation needs an optional peer dependency that isn't installed
|
|
3
|
+
* (e.g., calling `diff()` without `pixelmatch`). The error message MUST
|
|
4
|
+
* include the install command for the missing package.
|
|
5
|
+
*
|
|
6
|
+
* @public
|
|
7
|
+
*/
|
|
8
|
+
export class OptionalDependencyMissingError extends ScreenshotUtilsError {
|
|
9
|
+
/**
|
|
10
|
+
* @param {string} message
|
|
11
|
+
* @param {object} [options]
|
|
12
|
+
* @param {string} [options.packageName] The npm package the caller must install.
|
|
13
|
+
* @param {string} [options.installCommand] Suggested install command (default: derived).
|
|
14
|
+
*/
|
|
15
|
+
constructor(message: string, options?: {
|
|
16
|
+
packageName?: string | undefined;
|
|
17
|
+
installCommand?: string | undefined;
|
|
18
|
+
});
|
|
19
|
+
packageName: string | undefined;
|
|
20
|
+
installCommand: string | undefined;
|
|
21
|
+
}
|
|
22
|
+
import { ScreenshotUtilsError } from "./base.js";
|
|
23
|
+
//# sourceMappingURL=optional.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"optional.d.ts","sourceRoot":"","sources":["../../../src/errors/optional.js"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH;IACI;;;;;OAKG;IACH,qBALW,MAAM,YAEd;QAAyB,WAAW;QACX,cAAc;KACzC,EAcA;IAPO,gCAA8B;IAG9B,mCAAoC;CAK/C"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base for errors arising during redaction (blur / mask / pixelate, PII policies).
|
|
3
|
+
*
|
|
4
|
+
* @public
|
|
5
|
+
*/
|
|
6
|
+
export class RedactionError extends ScreenshotUtilsError {
|
|
7
|
+
/**
|
|
8
|
+
* @param {string} message
|
|
9
|
+
* @param {object} [options]
|
|
10
|
+
*/
|
|
11
|
+
constructor(message: string, options?: object);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* A PII policy object is malformed or references unknown rule keys.
|
|
15
|
+
*
|
|
16
|
+
* @public
|
|
17
|
+
*/
|
|
18
|
+
export class PolicyError extends RedactionError {
|
|
19
|
+
}
|
|
20
|
+
import { ScreenshotUtilsError } from "./base.js";
|
|
21
|
+
//# sourceMappingURL=redaction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redaction.d.ts","sourceRoot":"","sources":["../../../src/errors/redaction.js"],"names":[],"mappings":"AAIA;;;;GAIG;AACH;IACI;;;OAGG;IACH,qBAHW,MAAM,YACN,MAAM,EAMhB;CACJ;AAED;;;;GAIG;AACH;CAUC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base for errors arising during DZI tile generation.
|
|
3
|
+
*
|
|
4
|
+
* @public
|
|
5
|
+
*/
|
|
6
|
+
export class TileError extends ScreenshotUtilsError {
|
|
7
|
+
/**
|
|
8
|
+
* @param {string} message
|
|
9
|
+
* @param {object} [options]
|
|
10
|
+
*/
|
|
11
|
+
constructor(message: string, options?: object);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* `tileSize` is invalid (must be 256 or 512 per spec § 8.4.1).
|
|
15
|
+
*
|
|
16
|
+
* @public
|
|
17
|
+
*/
|
|
18
|
+
export class TileSizeError extends TileError {
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Writing tiles to the output directory failed (only in `output: 'directory'` mode).
|
|
22
|
+
* Retriable because the underlying cause is usually transient (disk full, permissions race).
|
|
23
|
+
*
|
|
24
|
+
* @public
|
|
25
|
+
*/
|
|
26
|
+
export class TileWriteError extends TileError {
|
|
27
|
+
}
|
|
28
|
+
import { ScreenshotUtilsError } from "./base.js";
|
|
29
|
+
//# sourceMappingURL=tile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tile.d.ts","sourceRoot":"","sources":["../../../src/errors/tile.js"],"names":[],"mappings":"AAIA;;;;GAIG;AACH;IACI;;;OAGG;IACH,qBAHW,MAAM,YACN,MAAM,EAMhB;CACJ;AAED;;;;GAIG;AACH;CAUC;AAED;;;;;GAKG;AACH;CAUC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base for errors arising during image-buffer transforms (crop, resize, convert, normalize).
|
|
3
|
+
*
|
|
4
|
+
* @public
|
|
5
|
+
*/
|
|
6
|
+
export class TransformError extends ScreenshotUtilsError {
|
|
7
|
+
/**
|
|
8
|
+
* @param {string} message
|
|
9
|
+
* @param {object} [options]
|
|
10
|
+
*/
|
|
11
|
+
constructor(message: string, options?: object);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* A rect is malformed or lies outside the source image bounds.
|
|
15
|
+
*
|
|
16
|
+
* @public
|
|
17
|
+
*/
|
|
18
|
+
export class InvalidRectError extends TransformError {
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The requested output format is not supported (e.g., AVIF in v1.0).
|
|
22
|
+
*
|
|
23
|
+
* @public
|
|
24
|
+
*/
|
|
25
|
+
export class UnsupportedFormatError extends TransformError {
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Sharp could not decode the input buffer (truncated, wrong format, corrupt).
|
|
29
|
+
*
|
|
30
|
+
* @public
|
|
31
|
+
*/
|
|
32
|
+
export class BufferCorruptError extends TransformError {
|
|
33
|
+
}
|
|
34
|
+
import { ScreenshotUtilsError } from "./base.js";
|
|
35
|
+
//# sourceMappingURL=transform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../src/errors/transform.js"],"names":[],"mappings":"AAIA;;;;GAIG;AACH;IACI;;;OAGG;IACH,qBAHW,MAAM,YACN,MAAM,EAMhB;CACJ;AAED;;;;GAIG;AACH;CAUC;AAED;;;;GAIG;AACH;CAUC;AAED;;;;GAIG;AACH;CAUC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
declare const _exports: {
|
|
2
|
+
annotate: typeof compose.annotate;
|
|
3
|
+
defaultTheme: Readonly<import("./types/index.d.ts").AnnotationTheme>;
|
|
4
|
+
diff: typeof compose.diff;
|
|
5
|
+
heatmap: typeof compose.heatmap;
|
|
6
|
+
tileDzi: typeof tile.tileDzi;
|
|
7
|
+
crop: typeof transform.crop;
|
|
8
|
+
cropMany: typeof transform.cropMany;
|
|
9
|
+
convert: typeof transform.convert;
|
|
10
|
+
resize: typeof transform.resize;
|
|
11
|
+
normalize: typeof transform.normalize;
|
|
12
|
+
capturePage: typeof capture.capturePage;
|
|
13
|
+
waitForStable: typeof capture.waitForStable;
|
|
14
|
+
captureLongPage: typeof capture.captureLongPage;
|
|
15
|
+
captureElement: typeof capture.captureElement;
|
|
16
|
+
captureViewport: typeof capture.captureViewport;
|
|
17
|
+
captureResponsive: typeof capture.captureResponsive;
|
|
18
|
+
fromPuppeteerPage: typeof adapters.fromPuppeteerPage;
|
|
19
|
+
fromPlaywrightPage: typeof adapters.fromPlaywrightPage;
|
|
20
|
+
fromCDPSession: typeof adapters.fromCDPSession;
|
|
21
|
+
ScreenshotUtilsError: typeof errors.ScreenshotUtilsError;
|
|
22
|
+
CaptureError: typeof errors.CaptureError;
|
|
23
|
+
BrowserUnavailableError: typeof errors.BrowserUnavailableError;
|
|
24
|
+
PageTooTallError: typeof errors.PageTooTallError;
|
|
25
|
+
ElementNotFoundError: typeof errors.ElementNotFoundError;
|
|
26
|
+
ElementNotVisibleError: typeof errors.ElementNotVisibleError;
|
|
27
|
+
ElementMismatchError: typeof errors.ElementMismatchError;
|
|
28
|
+
ElementTooLargeError: typeof errors.ElementTooLargeError;
|
|
29
|
+
StabilityTimeoutError: typeof errors.StabilityTimeoutError;
|
|
30
|
+
CaptureTimeoutError: typeof errors.CaptureTimeoutError;
|
|
31
|
+
TransformError: typeof errors.TransformError;
|
|
32
|
+
InvalidRectError: typeof errors.InvalidRectError;
|
|
33
|
+
UnsupportedFormatError: typeof errors.UnsupportedFormatError;
|
|
34
|
+
BufferCorruptError: typeof errors.BufferCorruptError;
|
|
35
|
+
ComposeError: typeof errors.ComposeError;
|
|
36
|
+
DimensionMismatchError: typeof errors.DimensionMismatchError;
|
|
37
|
+
ThemeError: typeof errors.ThemeError;
|
|
38
|
+
HeatmapPointError: typeof errors.HeatmapPointError;
|
|
39
|
+
TileError: typeof errors.TileError;
|
|
40
|
+
TileSizeError: typeof errors.TileSizeError;
|
|
41
|
+
TileWriteError: typeof errors.TileWriteError;
|
|
42
|
+
RedactionError: typeof errors.RedactionError;
|
|
43
|
+
PolicyError: typeof errors.PolicyError;
|
|
44
|
+
AdapterError: typeof errors.AdapterError;
|
|
45
|
+
AdapterContractError: typeof errors.AdapterContractError;
|
|
46
|
+
BrowserApiError: typeof errors.BrowserApiError;
|
|
47
|
+
OptionalDependencyMissingError: typeof errors.OptionalDependencyMissingError;
|
|
48
|
+
defaults: Readonly<import("./types/index.d.ts").ScreenshotUtilsDefaults>;
|
|
49
|
+
version: string;
|
|
50
|
+
};
|
|
51
|
+
export = _exports;
|
|
52
|
+
import compose = require("./compose/index.js");
|
|
53
|
+
import tile = require("./tile/index.js");
|
|
54
|
+
import transform = require("./transform/index.js");
|
|
55
|
+
import capture = require("./capture/index.js");
|
|
56
|
+
import adapters = require("./adapters/index.js");
|
|
57
|
+
import errors = require("./errors/index.js");
|
|
58
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/redact/index.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Apply a PII policy to a screenshot using a pre-collected list of element
|
|
3
|
+
* rects + classification metadata.
|
|
4
|
+
*
|
|
5
|
+
* Implements `spec.md` § 8.5.2. The function does NOT inspect a DOM
|
|
6
|
+
* directly — callers run a page-context evaluator that produces the
|
|
7
|
+
* `regions` array (an array of `{ rect, classification? }` objects) and
|
|
8
|
+
* pass it here. This keeps the package DOM-agnostic.
|
|
9
|
+
*
|
|
10
|
+
* @public
|
|
11
|
+
* @param {Buffer} input
|
|
12
|
+
* @param {Array<{rect: import('../types/index.d.ts').Rect, classification?: string}>} regions
|
|
13
|
+
* @param {import('../types/index.d.ts').PiiPolicy} [policy]
|
|
14
|
+
* @returns {Promise<Buffer>}
|
|
15
|
+
*/
|
|
16
|
+
export function applyPiiPolicy(input: Buffer, regions: Array<{
|
|
17
|
+
rect: import("../types/index.d.ts").Rect;
|
|
18
|
+
classification?: string;
|
|
19
|
+
}>, policy?: import("../types/index.d.ts").PiiPolicy): Promise<Buffer>;
|
|
20
|
+
/**
|
|
21
|
+
* Default PII policy bundled with the package. Consumers tighten it per
|
|
22
|
+
* their privacy posture; this is the conservative starting point per
|
|
23
|
+
* `spec.md` § 8.5.2.
|
|
24
|
+
*
|
|
25
|
+
* @public
|
|
26
|
+
* @type {Readonly<import('../types/index.d.ts').PiiPolicy>}
|
|
27
|
+
*/
|
|
28
|
+
export const defaultPiiPolicy: Readonly<import("../types/index.d.ts").PiiPolicy>;
|
|
29
|
+
//# sourceMappingURL=policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../../src/redact/policy.js"],"names":[],"mappings":"AAoBA;;;;;;;;;;;;;;GAcG;AACH,sCALW,MAAM,WACN,KAAK,CAAC;IAAC,IAAI,EAAE,OAAO,qBAAqB,EAAE,IAAI,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAC,CAAC,WAC1E,OAAO,qBAAqB,EAAE,SAAS,GACrC,OAAO,CAAC,MAAM,CAAC,CA+B3B;AA3DD;;;;;;;GAOG;AACH,+BAFU,QAAQ,CAAC,OAAO,qBAAqB,EAAE,SAAS,CAAC,CAOxD"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Apply one of three redaction modes to specified regions of an image.
|
|
3
|
+
*
|
|
4
|
+
* Implements `spec.md` § 8.5.1.
|
|
5
|
+
*
|
|
6
|
+
* - `mode: 'blur'` — Gaussian blur with the given `radius`.
|
|
7
|
+
* - `mode: 'mask'` — solid-color fill (`color`, default `#000`).
|
|
8
|
+
* - `mode: 'pixelate'` — downscale-then-upscale with the given `cellSize`.
|
|
9
|
+
*
|
|
10
|
+
* @public
|
|
11
|
+
* @param {Buffer} input
|
|
12
|
+
* @param {Array<import('../types/index.d.ts').RedactRegion>} regions
|
|
13
|
+
* @param {import('../types/index.d.ts').RedactOptions} [options]
|
|
14
|
+
* @returns {Promise<Buffer>}
|
|
15
|
+
*/
|
|
16
|
+
export function redact(input: Buffer, regions: Array<import("../types/index.d.ts").RedactRegion>, options?: import("../types/index.d.ts").RedactOptions): Promise<Buffer>;
|
|
17
|
+
/**
|
|
18
|
+
* Parse a CSS color string (`#rgb`, `#rrggbb`, `#rrggbbaa`, or named black).
|
|
19
|
+
*
|
|
20
|
+
* @param {string} color
|
|
21
|
+
* @returns {{r: number, g: number, b: number, alpha: number}}
|
|
22
|
+
*/
|
|
23
|
+
export function parseColor(color: string): {
|
|
24
|
+
r: number;
|
|
25
|
+
g: number;
|
|
26
|
+
b: number;
|
|
27
|
+
alpha: number;
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=redact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../../../src/redact/redact.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;GAcG;AACH,8BALW,MAAM,WACN,KAAK,CAAC,OAAO,qBAAqB,EAAE,YAAY,CAAC,YACjD,OAAO,qBAAqB,EAAE,aAAa,GACzC,OAAO,CAAC,MAAM,CAAC,CA6C3B;AA4ID;;;;;GAKG;AACH,kCAHW,MAAM,GACJ;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,CAgC5D"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a Deep Zoom Image pyramid from a source buffer using
|
|
3
|
+
* `sharp().tile({ layout: 'dz' })`.
|
|
4
|
+
*
|
|
5
|
+
* Implements `spec.md` § 8.4.1. Three output modes:
|
|
6
|
+
* - `'buffers'` (default): returns tile bytes in memory, cleans up the temp dir.
|
|
7
|
+
* - `'directory'`: returns the path to the temp dir; the caller is responsible
|
|
8
|
+
* for moving / uploading / deleting it.
|
|
9
|
+
* - `'stream'`: NOT IMPLEMENTED in v1.0 (per spec § 22 — deferred to v1.1).
|
|
10
|
+
*
|
|
11
|
+
* @public
|
|
12
|
+
* @param {Buffer} input
|
|
13
|
+
* @param {import('../types/index.d.ts').TileDziOptions} [options]
|
|
14
|
+
* @returns {Promise<import('../types/index.d.ts').DziResult>}
|
|
15
|
+
*/
|
|
16
|
+
export function tileDzi(input: Buffer, options?: import("../types/index.d.ts").TileDziOptions): Promise<import("../types/index.d.ts").DziResult>;
|
|
17
|
+
export const MAX_TILES: 10000;
|
|
18
|
+
//# sourceMappingURL=dzi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dzi.d.ts","sourceRoot":"","sources":["../../../src/tile/dzi.js"],"names":[],"mappings":"AAWA;;;;;;;;;;;;;;GAcG;AACH,+BAJW,MAAM,YACN,OAAO,qBAAqB,EAAE,cAAc,GAC1C,OAAO,CAAC,OAAO,qBAAqB,EAAE,SAAS,CAAC,CA6F5D;AA5GD,wBAAkB,KAAM,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tile/index.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Re-encode a buffer to a different image format.
|
|
3
|
+
*
|
|
4
|
+
* Implements `spec.md` § 8.2.4. Thin wrapper over `sharp(buf).toFormat()`
|
|
5
|
+
* with safer defaults and the package's error contract.
|
|
6
|
+
*
|
|
7
|
+
* @public
|
|
8
|
+
* @param {Buffer} input
|
|
9
|
+
* @param {import('../types/index.d.ts').ConvertOptions} options
|
|
10
|
+
* @returns {Promise<Buffer>}
|
|
11
|
+
*/
|
|
12
|
+
export function convert(input: Buffer, options: import("../types/index.d.ts").ConvertOptions): Promise<Buffer>;
|
|
13
|
+
//# sourceMappingURL=convert.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../../../src/transform/convert.js"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AACH,+BAJW,MAAM,WACN,OAAO,qBAAqB,EAAE,cAAc,GAC1C,OAAO,CAAC,MAAM,CAAC,CA8B3B"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract a single rectangle from a source image buffer.
|
|
3
|
+
*
|
|
4
|
+
* Implements `spec.md` § 8.2.1. All coordinates are CSS pixels. Padding
|
|
5
|
+
* expands the rect in all four directions and is then clamped to the
|
|
6
|
+
* image bounds (we never error on padding causing under/overflow — the
|
|
7
|
+
* caller asked for slack, not arithmetic).
|
|
8
|
+
*
|
|
9
|
+
* @public
|
|
10
|
+
* @param {Buffer} input
|
|
11
|
+
* @param {import('../types/index.d.ts').Rect} rect
|
|
12
|
+
* @param {import('../types/index.d.ts').CropOptions} [options]
|
|
13
|
+
* @returns {Promise<Buffer>}
|
|
14
|
+
*/
|
|
15
|
+
export function crop(input: Buffer, rect: import("../types/index.d.ts").Rect, options?: import("../types/index.d.ts").CropOptions): Promise<Buffer>;
|
|
16
|
+
/**
|
|
17
|
+
* Extract many rectangles in parallel from one source. Used by the engine's
|
|
18
|
+
* `_captureIssueScreenshots` migration path (one full-page capture + many
|
|
19
|
+
* crops beats N per-element captures by ~20×).
|
|
20
|
+
*
|
|
21
|
+
* Implements `spec.md` § 8.2.2.
|
|
22
|
+
*
|
|
23
|
+
* @public
|
|
24
|
+
* @param {Buffer} input
|
|
25
|
+
* @param {Array<{ id: string, rect: import('../types/index.d.ts').Rect }>} entries
|
|
26
|
+
* @param {import('../types/index.d.ts').CropManyOptions} [options]
|
|
27
|
+
* @returns {Promise<Map<string, Buffer>>}
|
|
28
|
+
*/
|
|
29
|
+
export function cropMany(input: Buffer, entries: Array<{
|
|
30
|
+
id: string;
|
|
31
|
+
rect: import("../types/index.d.ts").Rect;
|
|
32
|
+
}>, options?: import("../types/index.d.ts").CropManyOptions): Promise<Map<string, Buffer>>;
|
|
33
|
+
//# sourceMappingURL=crop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crop.d.ts","sourceRoot":"","sources":["../../../src/transform/crop.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;GAaG;AACH,4BALW,MAAM,QACN,OAAO,qBAAqB,EAAE,IAAI,YAClC,OAAO,qBAAqB,EAAE,WAAW,GACvC,OAAO,CAAC,MAAM,CAAC,CAoB3B;AAED;;;;;;;;;;;;GAYG;AACH,gCALW,MAAM,WACN,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,qBAAqB,EAAE,IAAI,CAAA;CAAE,CAAC,YAC/D,OAAO,qBAAqB,EAAE,eAAe,GAC3C,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAoDxC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { crop } from "./crop.js";
|
|
2
|
+
import { cropMany } from "./crop.js";
|
|
3
|
+
import { convert } from "./convert.js";
|
|
4
|
+
import { resize } from "./resize.js";
|
|
5
|
+
import { normalize } from "./normalize.js";
|
|
6
|
+
export { crop, cropMany, convert, resize, normalize };
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/transform/index.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalize an image buffer to a target device-pixel ratio so its coordinate
|
|
3
|
+
* space is CSS pixels regardless of the source DPR.
|
|
4
|
+
*
|
|
5
|
+
* Implements `spec.md` § 8.2.5. Default behavior preserves the image's
|
|
6
|
+
* intrinsic DPR (caller opts in to normalization for cross-DPR comparison).
|
|
7
|
+
*
|
|
8
|
+
* @public
|
|
9
|
+
* @param {Buffer} input
|
|
10
|
+
* @param {import('../types/index.d.ts').NormalizeOptions} [options]
|
|
11
|
+
* @returns {Promise<import('../types/index.d.ts').NormalizeResult>}
|
|
12
|
+
*/
|
|
13
|
+
export function normalize(input: Buffer, options?: import("../types/index.d.ts").NormalizeOptions): Promise<import("../types/index.d.ts").NormalizeResult>;
|
|
14
|
+
//# sourceMappingURL=normalize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../../src/transform/normalize.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AACH,iCAJW,MAAM,YACN,OAAO,qBAAqB,EAAE,gBAAgB,GAC5C,OAAO,CAAC,OAAO,qBAAqB,EAAE,eAAe,CAAC,CAiClE"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resize an image buffer with sharp-native semantics.
|
|
3
|
+
*
|
|
4
|
+
* Implements `spec.md` § 8.2.3. Honors `width`, `height`, `fit`, `position`,
|
|
5
|
+
* `kernel`, and `withoutEnlargement`. At least one of `width` or `height`
|
|
6
|
+
* must be supplied.
|
|
7
|
+
*
|
|
8
|
+
* @public
|
|
9
|
+
* @param {Buffer} input
|
|
10
|
+
* @param {import('../types/index.d.ts').ResizeOptions} options
|
|
11
|
+
* @returns {Promise<Buffer>}
|
|
12
|
+
*/
|
|
13
|
+
export function resize(input: Buffer, options: import("../types/index.d.ts").ResizeOptions): Promise<Buffer>;
|
|
14
|
+
//# sourceMappingURL=resize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resize.d.ts","sourceRoot":"","sources":["../../../src/transform/resize.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AACH,8BAJW,MAAM,WACN,OAAO,qBAAqB,EAAE,aAAa,GACzC,OAAO,CAAC,MAAM,CAAC,CA0E3B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@afixt/screenshot-utils",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Screenshot capture, transform, compose, tile, and redact utilities for the AFixt/Revenant accessibility platform",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"access": "restricted"
|
|
84
84
|
},
|
|
85
85
|
"engines": {
|
|
86
|
-
"node": ">=
|
|
86
|
+
"node": ">=20.9.0"
|
|
87
87
|
},
|
|
88
88
|
"keywords": [
|
|
89
89
|
"screenshot",
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
"revenant"
|
|
102
102
|
],
|
|
103
103
|
"dependencies": {
|
|
104
|
-
"sharp": "0.
|
|
104
|
+
"sharp": "^0.35.3"
|
|
105
105
|
},
|
|
106
106
|
"peerDependencies": {
|
|
107
107
|
"@napi-rs/canvas": "^0.1.0",
|
|
@@ -132,7 +132,7 @@
|
|
|
132
132
|
"@commitlint/config-conventional": "20.5.3",
|
|
133
133
|
"@eslint/js": "10.0.1",
|
|
134
134
|
"@types/node": "22.19.19",
|
|
135
|
-
"@vitest/coverage-
|
|
135
|
+
"@vitest/coverage-istanbul": "4.1.5",
|
|
136
136
|
"clean-jsdoc-theme": "4.3.2",
|
|
137
137
|
"eslint": "10.3.0",
|
|
138
138
|
"eslint-plugin-import-x": "4.16.2",
|
|
@@ -151,6 +151,7 @@
|
|
|
151
151
|
"lint-staged": "17.0.2",
|
|
152
152
|
"markdownlint-cli": "0.48.0",
|
|
153
153
|
"npm-run-all2": "8.0.4",
|
|
154
|
+
"openseadragon": "6.0.2",
|
|
154
155
|
"pixelmatch": "7.1.0",
|
|
155
156
|
"playwright": "1.60.0",
|
|
156
157
|
"pngjs": "7.0.0",
|
package/src/capture/element.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { CaptureTimeoutError } = require('../errors/index.js');
|
|
4
|
+
const { waitForStable } = require('./settle.js');
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Capture a single element by selector or xpath.
|
|
@@ -31,6 +32,7 @@ async function captureElement(adapter, options = {}) {
|
|
|
31
32
|
timeout = 5000,
|
|
32
33
|
format = 'png',
|
|
33
34
|
quality = 90,
|
|
35
|
+
waitForStable: settleOpts = false,
|
|
34
36
|
events = null,
|
|
35
37
|
} = options;
|
|
36
38
|
|
|
@@ -77,6 +79,7 @@ async function captureElement(adapter, options = {}) {
|
|
|
77
79
|
}
|
|
78
80
|
|
|
79
81
|
let viewportRect = lookup.viewportRect;
|
|
82
|
+
let documentRect = lookup.documentRect;
|
|
80
83
|
if (scrollIntoView) {
|
|
81
84
|
await adapter.scrollTo({
|
|
82
85
|
x: 0,
|
|
@@ -93,6 +96,17 @@ async function captureElement(adapter, options = {}) {
|
|
|
93
96
|
}
|
|
94
97
|
}
|
|
95
98
|
|
|
99
|
+
// Optional render-stability wait. Critically, we re-read the element rect
|
|
100
|
+
// *after* settling: late reflow (lazy images, web fonts, JS layout) is the
|
|
101
|
+
// cause of blank/wrong-region element crops, so coordinates captured before
|
|
102
|
+
// settle cannot be trusted for the clip.
|
|
103
|
+
const settled = await settleAndReread(adapter, { selector, xpath, timeout, settleOpts });
|
|
104
|
+
const settleMs = settled.settleMs;
|
|
105
|
+
if (settled.rect) {
|
|
106
|
+
viewportRect = settled.rect.viewportRect;
|
|
107
|
+
documentRect = settled.rect.documentRect;
|
|
108
|
+
}
|
|
109
|
+
|
|
96
110
|
const clip = {
|
|
97
111
|
x: Math.max(0, Math.round(viewportRect.x - padding)),
|
|
98
112
|
y: Math.max(0, Math.round(viewportRect.y - padding)),
|
|
@@ -117,12 +131,12 @@ async function captureElement(adapter, options = {}) {
|
|
|
117
131
|
format,
|
|
118
132
|
bytes,
|
|
119
133
|
page: metrics,
|
|
120
|
-
timing: { settleMs
|
|
134
|
+
timing: { settleMs, captureMs, encodeMs: 0, totalMs },
|
|
121
135
|
warnings: [],
|
|
122
136
|
element: {
|
|
123
137
|
selector: selector ?? '',
|
|
124
138
|
xpath: xpath ?? '',
|
|
125
|
-
documentRect
|
|
139
|
+
documentRect,
|
|
126
140
|
viewportRect,
|
|
127
141
|
verified: Boolean(snippet),
|
|
128
142
|
},
|
|
@@ -131,6 +145,35 @@ async function captureElement(adapter, options = {}) {
|
|
|
131
145
|
return result;
|
|
132
146
|
}
|
|
133
147
|
|
|
148
|
+
/**
|
|
149
|
+
* Run waitForStable (when requested) and re-read the element rect afterwards.
|
|
150
|
+
* Kept out of `captureElement` so the main flow stays flat.
|
|
151
|
+
*
|
|
152
|
+
* @param {import('../types/index.d.ts').PageAdapter} adapter
|
|
153
|
+
* @param {{selector?: string, xpath?: string, timeout: number, settleOpts: import('../types/index.d.ts').WaitForStableOptions|boolean}} ctx
|
|
154
|
+
* @returns {Promise<{settleMs: number, rect: {viewportRect: import('../types/index.d.ts').Rect, documentRect: import('../types/index.d.ts').Rect}|null}>}
|
|
155
|
+
*/
|
|
156
|
+
async function settleAndReread(adapter, { selector, xpath, timeout, settleOpts }) {
|
|
157
|
+
if (!settleOpts) {
|
|
158
|
+
return { settleMs: 0, rect: null };
|
|
159
|
+
}
|
|
160
|
+
const settleStart = nowMs();
|
|
161
|
+
await waitForStable(adapter, settleOpts === true ? {} : settleOpts);
|
|
162
|
+
const settleMs = nowMs() - settleStart;
|
|
163
|
+
const reread = await withTimeout(
|
|
164
|
+
adapter.evaluate(findElementInPage, { selector, xpath }),
|
|
165
|
+
timeout,
|
|
166
|
+
{ operation: 'adapter.evaluate(findElement after settle)' }
|
|
167
|
+
);
|
|
168
|
+
if (reread && reread.found) {
|
|
169
|
+
return {
|
|
170
|
+
settleMs,
|
|
171
|
+
rect: { viewportRect: reread.viewportRect, documentRect: reread.documentRect },
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
return { settleMs, rect: null };
|
|
175
|
+
}
|
|
176
|
+
|
|
134
177
|
/**
|
|
135
178
|
* Page-context element lookup. Shipped to the browser via adapter.evaluate.
|
|
136
179
|
* Coverage suppressed for the same reason as `settle.js#runInPage` —
|
|
@@ -139,9 +182,9 @@ async function captureElement(adapter, options = {}) {
|
|
|
139
182
|
* @param {{selector?: string, xpath?: string}} args
|
|
140
183
|
* @returns {{found: false} | {found: true, outerHTML: string, documentRect: import('../types/index.d.ts').Rect, viewportRect: import('../types/index.d.ts').Rect}}
|
|
141
184
|
*/
|
|
142
|
-
/*
|
|
143
|
-
|
|
144
|
-
element-capture integration tests. */
|
|
185
|
+
/* istanbul ignore next -- runs in the browser via adapter.evaluate(); must NOT
|
|
186
|
+
be instrumented (injected counters don't exist in the page context) and is
|
|
187
|
+
exercised by the puppeteer/playwright element-capture integration tests. */
|
|
145
188
|
function findElementInPage(args) {
|
|
146
189
|
const doc = globalThis.document;
|
|
147
190
|
let element;
|
|
@@ -184,7 +227,6 @@ function findElementInPage(args) {
|
|
|
184
227
|
},
|
|
185
228
|
};
|
|
186
229
|
}
|
|
187
|
-
/* v8 ignore stop */
|
|
188
230
|
|
|
189
231
|
/**
|
|
190
232
|
* Build a failure-shaped ElementCaptureResult that preserves the engine's
|
package/src/capture/page.js
CHANGED
|
@@ -33,20 +33,12 @@ async function capturePage(adapter, options = {}) {
|
|
|
33
33
|
emit(events, 'capture:start', { format, fullPage });
|
|
34
34
|
|
|
35
35
|
let settleMs = 0;
|
|
36
|
-
|
|
36
|
+
let warnings = [];
|
|
37
37
|
if (settleOpts) {
|
|
38
38
|
const settleStart = nowMs();
|
|
39
39
|
const report = await waitForStable(adapter, settleOpts === true ? {} : settleOpts);
|
|
40
40
|
settleMs = nowMs() - settleStart;
|
|
41
|
-
|
|
42
|
-
warnings.push('fonts did not settle within maxWait');
|
|
43
|
-
}
|
|
44
|
-
if (report.animations === 'timeout') {
|
|
45
|
-
warnings.push('animations did not settle within maxWait');
|
|
46
|
-
}
|
|
47
|
-
if (report.images.failed > 0) {
|
|
48
|
-
warnings.push(`${report.images.failed} image(s) failed to load`);
|
|
49
|
-
}
|
|
41
|
+
warnings = settleWarnings(report);
|
|
50
42
|
}
|
|
51
43
|
|
|
52
44
|
const metrics = await adapter.getMetrics();
|
|
@@ -97,6 +89,35 @@ async function capturePage(adapter, options = {}) {
|
|
|
97
89
|
return result;
|
|
98
90
|
}
|
|
99
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Translate a StabilityReport into non-fatal warning strings.
|
|
94
|
+
*
|
|
95
|
+
* @param {import('../types/index.d.ts').StabilityReport} report
|
|
96
|
+
* @returns {string[]}
|
|
97
|
+
*/
|
|
98
|
+
function settleWarnings(report) {
|
|
99
|
+
const warnings = [];
|
|
100
|
+
if (report.fonts === 'timeout') {
|
|
101
|
+
warnings.push('fonts did not settle within maxWait');
|
|
102
|
+
}
|
|
103
|
+
if (report.animations === 'timeout') {
|
|
104
|
+
warnings.push('animations did not settle within maxWait');
|
|
105
|
+
}
|
|
106
|
+
if (report.images.failed > 0) {
|
|
107
|
+
warnings.push(`${report.images.failed} image(s) failed to load`);
|
|
108
|
+
}
|
|
109
|
+
if (report.backgroundImages && report.backgroundImages.failed > 0) {
|
|
110
|
+
warnings.push(`${report.backgroundImages.failed} background image(s) failed to load`);
|
|
111
|
+
}
|
|
112
|
+
if (report.network === 'timeout') {
|
|
113
|
+
warnings.push('network did not reach idle within maxWait');
|
|
114
|
+
}
|
|
115
|
+
if (report.layoutStable === 'timeout') {
|
|
116
|
+
warnings.push('layout did not stabilize within maxWait');
|
|
117
|
+
}
|
|
118
|
+
return warnings;
|
|
119
|
+
}
|
|
120
|
+
|
|
100
121
|
/**
|
|
101
122
|
* Map the user's desired output format to the format the browser should
|
|
102
123
|
* produce. Returns either the same format (no re-encode) or 'png' (when
|