dom-to-image-more
Version:
Generates an image from a DOM node using HTML5 canvas and SVG
256 lines (184 loc) • 14.2 kB
Markdown
# `util` reference
Internal utility helpers used throughout **dom-to-image-more**. They are exposed for
testing and advanced integration via:
```js
domtoimage.impl.util;
```
> ⚠️ These are **implementation details**, not part of the stable public API (`toSvg`,
> `toPng`, `toJpeg`, `toBlob`, `toCanvas`, `toPixelData`). They may change between
> releases. They are documented here because the test suite and some advanced callers
> depend on them.
The object is produced by `newUtil()` in
[`src/dom-to-image-more.js`](../src/dom-to-image-more.js) and attached to
`domtoimage.impl.util`. For the rest of the `impl` surface (`fontFaces`, `images`,
`inliner`, `urlCache`, `options`, `copyOptions`), see [IMPL.md](IMPL.md).
---
## Type guards
All of these return a `boolean` and are built on `isInstanceOf`, which checks the value
against the constructor from **both** its own window and the parent window (so they work
correctly across `<iframe>` boundaries).
| Function | Returns `true` when the value is… |
| --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `isElement(value)` | a DOM `Element` |
| `isHTMLElement(value)` | an `HTMLElement` |
| `isHTMLCanvasElement(value)` | an `HTMLCanvasElement` |
| `isHTMLImageElement(value)` | an `HTMLImageElement` |
| `isHTMLInputElement(value)` | an `HTMLInputElement` |
| `isHTMLLinkElement(value)` | an `HTMLLinkElement` |
| `isHTMLScriptElement(value)` | an `HTMLScriptElement` |
| `isHTMLStyleElement(value)` | an `HTMLStyleElement` |
| `isHTMLTextAreaElement(value)` | an `HTMLTextAreaElement` |
| `isSVGElement(value)` | an `SVGElement` |
| `isSVGImageElement(value)` | an `SVGImageElement` (a nested SVG `<image>`, whose `href`/`xlink:href` is inlined) |
| `isSVGSVGElement(value)` | an `SVGSVGElement` (an `<svg>` root; non-root SVG elements take a different render path) |
| `isSVGRectElement(value)` | an `SVGRectElement` |
| `isSVGUseElement(value)` | an `SVGUseElement` (a `<use>` referencing an element to inline) |
| `isShadowRoot(value)` | a `ShadowRoot` |
| `isInShadowRoot(value)` | a node whose root (`getRootNode()`) is a `ShadowRoot`. Safe for `null`/`undefined` and for nodes without `getRootNode`. |
| `isElementHostForOpenShadowRoot(value)` | an `Element` that hosts an **open** shadow root (`value.shadowRoot !== null`) |
| `isShadowSlotElement(value)` | an `HTMLSlotElement` that lives inside a shadow root |
### `isInstanceOf(value, typeName)`
`(value: any, typeName: string) => boolean`
Cross-realm `instanceof` check. Resolves the constructor named `typeName` from the value's
own window **and** `window.parent`, returning `true` if the value is an instance of
either. This is the primitive that all the guards above are built on, so type checks
survive elements that originate inside iframes.
### `isDataUrl(url)`
`(url: string) => boolean`
`true` if the string begins with `data:`.
### `isDimensionMissing(value)`
`(value: number) => boolean`
`true` when a measured dimension is unusable — i.e. `NaN`, `0`, or negative. Used to
decide when to fall back to default sizing (e.g. `width="100%"`).
---
## Geometry / dimensions
### `width(node)`
`(node: Element) => number`
Computed pixel width of `node`. Reads the CSS `width` via `getComputedStyle`; if that is
not a `px` value, falls back to `scrollWidth + border-left-width + border-right-width`.
### `height(node)`
`(node: Element) => number`
Computed pixel height of `node`. Same strategy as `width`, using
`scrollHeight + border-top-width + border-bottom-width` as the fallback.
> Note: both read live layout, so the value depends on the element's current rendered
> state (scrollbars, etc.).
---
## Window / document
### `getWindow(node)`
`(node?: Node) => Window`
Returns the `Window` that owns `node` (`node.ownerDocument.defaultView`), falling back to
`window`, then `global`, then `globalThis`. Each fallback is `typeof`-guarded so it does
not throw under SSR (Angular Universal, Next.js, plain Node) where `window`/`global` may
be absent. Tolerates a missing/`undefined` `node`. Underpins the cross-realm type guards.
---
## URLs & resources
### `resolveUrl(url, baseUrl)`
`(url: string, baseUrl: string) => string`
Resolves a possibly relative `url` against `baseUrl` and returns the absolute URL.
Implemented by letting the browser normalize an `<a href>` inside a throwaway document
that has a `<base>` set to `baseUrl`.
### `getAndEncode(url, type)`
`(url: string, type?: ResourceType) => Promise<string>`
Thin wrapper over the shared fetch core (see below) that resolves to a **data URL**
(base64) — used at the inline sites (images, fonts). `type` is the resource kind (a
`domtoimage.ResourceType` value: `IMAGE`, `CSS_IMAGE`, `FONT`, `STYLESHEET`) used by
`requestInterceptor` and to scope `imagePlaceholder`; it defaults to `undefined`. Resolves
to `''` when the resource is dropped.
### `getResourceText(url, type, allowNetwork)`
`(url: string, type?: ResourceType, allowNetwork?: boolean) => Promise<string | null>`
Sibling wrapper that resolves to the resource's **text** (via `readAsText`, no base64
round-trip) — used to load external stylesheets
([loadExternalStyleSheet](../README.md#loadexternalstylesheet)). `allowNetwork === false`
consults `requestInterceptor` but performs **no** network fetch (so a readable or
not-opted-in stylesheet can still be supplied by the interceptor without being
downloaded). Resolves to `null` when there's no resource.
#### Shared fetch core
Both wrappers share one fetch core that returns a Blob (network), a data URL string
(supplied by `requestInterceptor`/`imagePlaceholder`), or `null` (dropped); the wrappers
handle the encode/decode, so a resource is only base64-encoded where it's actually
inlined. Key behaviors:
- **Caches** by URL in `domtoimage.impl.urlCache`; concurrent/repeat requests for the same
URL share one promise. Reset with [`resetUrlCache()`](IMPL.md#implurlcache).
- **`requestInterceptor`** is consulted first, before the fetch:
`requestInterceptor(url, { type, status: undefined })` may return a data URL (or a
promise of one) to short-circuit the network.
- Honors options: `cacheBust`, `httpTimeout`, `useCredentials` / `useCredentialsFilters`,
and `corsImg` (proxy URL/method/headers/data with the `#{cors}` token substituted).
- Treats HTTP status `0` as success for `file://` URLs (Firefox local-file quirk).
- On any failure (network/timeout/non-2xx, **or** a response that isn't a usable Blob):
consults `requestInterceptor(url, { type, status })` for a recovery value (takes
precedence), then `imagePlaceholder` — **only for image types** (`IMAGE` / `CSS_IMAGE`;
a `FONT`/`STYLESHEET`, or an untyped call, drops) — then drops. Never rejects; every
failure is surfaced via `onImageError`.
### `makeImage(uri)`
`(uri: string) => Promise<HTMLImageElement | undefined>`
Loads `uri` into an `Image` (wrapped in an offscreen `<svg>` appended to `document.body`)
and resolves once it has loaded. Returns `undefined` for the empty data URL `data:,`.
Applies `crossOrigin = 'use-credentials'` when the `useCredentials` option is set. Removes
the temporary node on load/error; before resolving it awaits `image.decode()` (when
available) and then one `requestAnimationFrame`, so the bitmap is fully decoded before a
canvas reads it — guarding the Firefox/Safari blank-render timing race (issues #146,
#192).
### `canvasToBlob(canvas)`
`(canvas: HTMLCanvasElement) => Promise<Blob>`
Resolves to a PNG `Blob` of the canvas. Uses the native `canvas.toBlob` when available,
otherwise a manual `toDataURL` → `atob` → `Uint8Array` → `Blob` fallback.
---
## String helpers
### `escape(string)`
`(string: string) => string`
> Exposed as `util.escape` (implementation `escapeRegEx`).
Escapes characters that are special in a regular expression
(`. * + ? ^ $ { } ( ) | [ ] / \`) so the string can be used as a regex literal.
### `escapeXhtml(string)`
`(string: string) => string`
Escapes a string for safe embedding in the XHTML/`foreignObject` payload of the generated
SVG: replaces `%` → `%25`, `#` → `%23`, and newlines → `%0A`.
---
## Misc
### `asArray(arrayLike)`
`(arrayLike: ArrayLike<T>) => T[]`
Converts an array-like (e.g. a `NodeList` or `CSSStyleDeclaration`) into a real `Array` by
index copy.
### `uid()`
`() => string`
Returns a short unique id of the form `u<4-random-base36-chars><counter>` (e.g. `u3f9a0`).
The incrementing counter guarantees uniqueness within a session even if the random part
collides.
---
## Quick index
| Name | Category | Returns |
| -------------------------------- | ------------------------- | ---------------------------------------- |
| `isElement` | type guard | `boolean` |
| `isElementHostForOpenShadowRoot` | type guard | `boolean` |
| `isShadowRoot` | type guard | `boolean` |
| `isInShadowRoot` | type guard | `boolean` |
| `isHTMLElement` | type guard | `boolean` |
| `isHTMLCanvasElement` | type guard | `boolean` |
| `isHTMLInputElement` | type guard | `boolean` |
| `isHTMLImageElement` | type guard | `boolean` |
| `isHTMLLinkElement` | type guard | `boolean` |
| `isHTMLScriptElement` | type guard | `boolean` |
| `isHTMLStyleElement` | type guard | `boolean` |
| `isHTMLTextAreaElement` | type guard | `boolean` |
| `isShadowSlotElement` | type guard | `boolean` |
| `isSVGElement` | type guard | `boolean` |
| `isSVGImageElement` | type guard | `boolean` |
| `isSVGSVGElement` | type guard | `boolean` |
| `isSVGRectElement` | type guard | `boolean` |
| `isSVGUseElement` | type guard | `boolean` |
| `isInstanceOf` | type guard | `boolean` |
| `isDataUrl` | type guard | `boolean` |
| `isDimensionMissing` | dimensions | `boolean` |
| `width` | dimensions | `number` |
| `height` | dimensions | `number` |
| `getWindow` | window | `Window` |
| `resolveUrl` | url | `string` |
| `getAndEncode` | url, type? | `Promise<string>` |
| `getResourceText` | url, type?, allowNetwork? | `Promise<string \| null>` |
| `makeImage` | url | `Promise<HTMLImageElement \| undefined>` |
| `canvasToBlob` | url | `Promise<Blob>` |
| `escape` | string | `string` |
| `escapeXhtml` | string | `string` |
| `asArray` | misc | `Array` |
| `uid` | misc | `string` |