1import type { SnapShotAccessibilityNode, SnapShotSource } from "@t3tools/contracts";
2
3/** Keep image-relative accessibility coordinates aligned with a recompressed attachment. */
4export function resizeSnapShotSource(
5 source: SnapShotSource,
6 imageSize?: { readonly width: number; readonly height: number },
7): SnapShotSource {
8 const accessibility = source.accessibility;
9 if (
10 !imageSize ||
11 accessibility?.format !== "element-tree" ||
12 (imageSize.width === accessibility.imageSize.width &&
13 imageSize.height === accessibility.imageSize.height)
14 )
15 return source;
16
17 const scaleX = imageSize.width / accessibility.imageSize.width;
18 const scaleY = imageSize.height / accessibility.imageSize.height;
19 const resizeNode = (node: SnapShotAccessibilityNode): SnapShotAccessibilityNode => {
20 let bounds = null;
21 if (node.bounds) {
22 const x = Math.min(imageSize.width, Math.round(node.bounds.x * scaleX));
23 const y = Math.min(imageSize.height, Math.round(node.bounds.y * scaleY));
24 const right = Math.min(
25 imageSize.width,
26 Math.round((node.bounds.x + node.bounds.width) * scaleX),
27 );
28 const bottom = Math.min(
29 imageSize.height,
30 Math.round((node.bounds.y + node.bounds.height) * scaleY),
31 );
32 if (right > x && bottom > y) bounds = { x, y, width: right - x, height: bottom - y };
33 }
34 return { ...node, bounds, children: node.children.map(resizeNode) };
35 };
36 return {
37 ...source,
38 accessibility: { ...accessibility, imageSize, root: resizeNode(accessibility.root) },
39 };
40}