resvg-napi 0.1.2 → 0.2.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/README.md +29 -2
- package/fit.d.mts +62 -0
- package/index.d.ts +212 -191
- package/index.js +61 -54
- package/package.json +32 -22
- package/resvg-napi.wasi-browser.js +7 -0
- package/resvg-napi.wasi.cjs +8 -1
- package/resvg-napi.wasi.d.cts +212 -191
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# resvg-napi
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/resvg-napi)
|
|
4
|
+
[](#conformance)
|
|
5
|
+
[](#licence)
|
|
6
|
+
|
|
3
7
|
Node.js bindings for [resvg](https://github.com/linebender/resvg) 0.48: render
|
|
4
8
|
SVG to PNG, and read back what usvg made of the document — the resolved tree,
|
|
5
9
|
text metrics, paint, geometry.
|
|
@@ -45,10 +49,17 @@ one knows what it is:
|
|
|
45
49
|
const n = doc.node('surname')
|
|
46
50
|
n.kind // 'group' | 'path' | 'image' | 'text'
|
|
47
51
|
n.path() // geometry, fill, stroke — null unless it is a shape
|
|
48
|
-
n.text() // chunks, layouted spans, positioned glyphs
|
|
52
|
+
n.text() // chunks, layouted spans, positioned glyphs, decoration
|
|
49
53
|
n.renderPng() // that element alone, cropped to its own extent
|
|
50
54
|
```
|
|
51
55
|
|
|
56
|
+
A span carries what it is drawn with, down to the lines through it:
|
|
57
|
+
|
|
58
|
+
```js
|
|
59
|
+
const span = n.text().chunks[0].spans[0]
|
|
60
|
+
span.decoration.underline?.fill?.paint // …and .overline, .lineThrough
|
|
61
|
+
```
|
|
62
|
+
|
|
52
63
|
Paint is a discriminated union, so TypeScript narrows it:
|
|
53
64
|
|
|
54
65
|
```ts
|
|
@@ -64,7 +75,8 @@ that distinction bites.
|
|
|
64
75
|
|
|
65
76
|
**Fonts.** `FontDatabase` is `fontdb` itself: `loadSystemFonts()`,
|
|
66
77
|
`loadFontData(buffer)`, `loadFontFile(path)`, `faces()`, `query()`, and the
|
|
67
|
-
generic-family setters.
|
|
78
|
+
generic-family setters. A face reports its `families`, `weight`, `style`
|
|
79
|
+
(`'normal' | 'italic' | 'oblique'`) and whether it is `monospaced`. `pendingFonts()` on a parsed document names the
|
|
68
80
|
families it wanted and did not get; `pendingImages()` does the same for hrefs.
|
|
69
81
|
|
|
70
82
|
**Definitions.** `linearGradients()`, `radialGradients()`, `patterns()`,
|
|
@@ -75,6 +87,21 @@ Something missing? The generator keeps a report of every upstream member it
|
|
|
75
87
|
left alone, with the reason. `RESVG_NAPI_CODEGEN_LOG=1 cargo build` prints it,
|
|
76
88
|
and [CONTRIBUTING.md](CONTRIBUTING.md) explains what the reasons mean.
|
|
77
89
|
|
|
90
|
+
## Conformance
|
|
91
|
+
|
|
92
|
+
resvg's own test corpus, rendered through these bindings: **1715 of 1715 match**
|
|
93
|
+
the reference PNGs upstream asserts on, within 1/255 per channel — a tolerance
|
|
94
|
+
measured rather than chosen, with the reason recorded in
|
|
95
|
+
[`scripts/conformance.mjs`](scripts/conformance.mjs).
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
npm run conformance:fetch # the corpus, at the tag Cargo.toml pins
|
|
99
|
+
npm run conformance # 15 seconds including the fetch
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
CI runs it on every pull request, so a resvg bump that changes a render shows up
|
|
103
|
+
as a diff rather than passing unnoticed.
|
|
104
|
+
|
|
78
105
|
## Platforms
|
|
79
106
|
|
|
80
107
|
Thirteen targets.
|
package/fit.d.mts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Horizontal text fitting, driven by `data-maxwidth`.
|
|
3
|
+
*
|
|
4
|
+
* Declarations for `fit.mjs`, which is JavaScript with JSDoc: written by hand,
|
|
5
|
+
* unlike `index.d.ts`, so they can drift. `npm run typecheck` reads them.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** A `Resvg` instance, however the caller chose to build one. */
|
|
9
|
+
type Renderer = {
|
|
10
|
+
node(id: string): { extent(): { width: number } | null } | null
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** One element carrying a width constraint, and what is needed to rewrite it. */
|
|
14
|
+
export interface WidthConstraint {
|
|
15
|
+
/** The element's opening tag, verbatim. */
|
|
16
|
+
tag: string
|
|
17
|
+
/** The tag name: `text`, `tspan`, ... */
|
|
18
|
+
name: string
|
|
19
|
+
/** The attribute text inside that tag, verbatim. */
|
|
20
|
+
attrs: string
|
|
21
|
+
/** The element's `id`, or null when it had none and one must be generated. */
|
|
22
|
+
id: string | null
|
|
23
|
+
/** The limit, in the document's own units -- not canvas pixels. */
|
|
24
|
+
max: number
|
|
25
|
+
/** Byte offset of the tag in the source string. */
|
|
26
|
+
index: number
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** One element that was compressed, and by how much. */
|
|
30
|
+
export interface Adjustment {
|
|
31
|
+
id: string
|
|
32
|
+
/** Measured width before, in the document's units. */
|
|
33
|
+
from: number
|
|
34
|
+
/** The limit it was fitted to. */
|
|
35
|
+
to: number
|
|
36
|
+
/** The horizontal scale applied: `to / from`. */
|
|
37
|
+
factor: number
|
|
38
|
+
/** Measured width after, as a check on the one-pass assumption. */
|
|
39
|
+
measured: number
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface FitResult {
|
|
43
|
+
/** The source, with a `scale(k 1)` composed onto each fitted element. */
|
|
44
|
+
svg: string
|
|
45
|
+
adjustments: Adjustment[]
|
|
46
|
+
/** Constraints that could not be honoured, each saying why. */
|
|
47
|
+
problems: string[]
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Elements carrying a width constraint, with the tag text needed to rewrite it. */
|
|
51
|
+
export function findWidthConstraints(svg: string): WidthConstraint[]
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Fits every `data-maxwidth` element by compressing it horizontally.
|
|
55
|
+
*
|
|
56
|
+
* @param svg source, after any templating
|
|
57
|
+
* @param render `(svg) => Resvg`; supply fonts and options here
|
|
58
|
+
*/
|
|
59
|
+
export function fitTextWidths(
|
|
60
|
+
svg: string,
|
|
61
|
+
render: (svg: string) => Renderer,
|
|
62
|
+
): FitResult
|