@jsonpdf/plugins 0.1.0-alpha.1
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/LICENSE +21 -0
- package/README.md +59 -0
- package/dist/barcode/barcode-generator.d.ts +18 -0
- package/dist/barcode/barcode-generator.d.ts.map +1 -0
- package/dist/barcode/barcode-generator.js +94 -0
- package/dist/barcode/barcode-generator.js.map +1 -0
- package/dist/barcode/barcode-plugin.d.ts +4 -0
- package/dist/barcode/barcode-plugin.d.ts.map +1 -0
- package/dist/barcode/barcode-plugin.js +70 -0
- package/dist/barcode/barcode-plugin.js.map +1 -0
- package/dist/barcode/barcode-types.d.ts +29 -0
- package/dist/barcode/barcode-types.d.ts.map +1 -0
- package/dist/barcode/barcode-types.js +60 -0
- package/dist/barcode/barcode-types.js.map +1 -0
- package/dist/chart/chart-generator.d.ts +17 -0
- package/dist/chart/chart-generator.d.ts.map +1 -0
- package/dist/chart/chart-generator.js +77 -0
- package/dist/chart/chart-generator.js.map +1 -0
- package/dist/chart/chart-plugin.d.ts +4 -0
- package/dist/chart/chart-plugin.d.ts.map +1 -0
- package/dist/chart/chart-plugin.js +65 -0
- package/dist/chart/chart-plugin.js.map +1 -0
- package/dist/chart/chart-types.d.ts +18 -0
- package/dist/chart/chart-types.d.ts.map +1 -0
- package/dist/chart/chart-types.js +18 -0
- package/dist/chart/chart-types.js.map +1 -0
- package/dist/container/container-plugin.d.ts +15 -0
- package/dist/container/container-plugin.d.ts.map +1 -0
- package/dist/container/container-plugin.js +190 -0
- package/dist/container/container-plugin.js.map +1 -0
- package/dist/frame/frame-plugin.d.ts +4 -0
- package/dist/frame/frame-plugin.d.ts.map +1 -0
- package/dist/frame/frame-plugin.js +52 -0
- package/dist/frame/frame-plugin.js.map +1 -0
- package/dist/frame/frame-types.d.ts +8 -0
- package/dist/frame/frame-types.d.ts.map +1 -0
- package/dist/frame/frame-types.js +17 -0
- package/dist/frame/frame-types.js.map +1 -0
- package/dist/image/image-loader.d.ts +13 -0
- package/dist/image/image-loader.d.ts.map +1 -0
- package/dist/image/image-loader.js +73 -0
- package/dist/image/image-loader.js.map +1 -0
- package/dist/image/image-plugin.d.ts +19 -0
- package/dist/image/image-plugin.d.ts.map +1 -0
- package/dist/image/image-plugin.js +112 -0
- package/dist/image/image-plugin.js.map +1 -0
- package/dist/image/svg-rasterizer.d.ts +30 -0
- package/dist/image/svg-rasterizer.d.ts.map +1 -0
- package/dist/image/svg-rasterizer.js +97 -0
- package/dist/image/svg-rasterizer.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/line/line-plugin.d.ts +11 -0
- package/dist/line/line-plugin.d.ts.map +1 -0
- package/dist/line/line-plugin.js +68 -0
- package/dist/line/line-plugin.js.map +1 -0
- package/dist/list/list-plugin.d.ts +13 -0
- package/dist/list/list-plugin.d.ts.map +1 -0
- package/dist/list/list-plugin.js +194 -0
- package/dist/list/list-plugin.js.map +1 -0
- package/dist/list/list-types.d.ts +9 -0
- package/dist/list/list-types.d.ts.map +1 -0
- package/dist/list/list-types.js +9 -0
- package/dist/list/list-types.js.map +1 -0
- package/dist/platform/base64.d.ts +7 -0
- package/dist/platform/base64.d.ts.map +1 -0
- package/dist/platform/base64.js +17 -0
- package/dist/platform/base64.js.map +1 -0
- package/dist/platform/font-store.d.ts +3 -0
- package/dist/platform/font-store.d.ts.map +1 -0
- package/dist/platform/font-store.js +8 -0
- package/dist/platform/font-store.js.map +1 -0
- package/dist/platform/fs.browser.d.ts +6 -0
- package/dist/platform/fs.browser.d.ts.map +1 -0
- package/dist/platform/fs.browser.js +10 -0
- package/dist/platform/fs.browser.js.map +1 -0
- package/dist/platform/fs.d.ts +5 -0
- package/dist/platform/fs.d.ts.map +1 -0
- package/dist/platform/fs.js +10 -0
- package/dist/platform/fs.js.map +1 -0
- package/dist/platform/init.browser.d.ts +10 -0
- package/dist/platform/init.browser.d.ts.map +1 -0
- package/dist/platform/init.browser.js +24 -0
- package/dist/platform/init.browser.js.map +1 -0
- package/dist/platform/init.d.ts +6 -0
- package/dist/platform/init.d.ts.map +1 -0
- package/dist/platform/init.js +12 -0
- package/dist/platform/init.js.map +1 -0
- package/dist/platform/svg-rasterizer.browser.d.ts +2 -0
- package/dist/platform/svg-rasterizer.browser.d.ts.map +1 -0
- package/dist/platform/svg-rasterizer.browser.js +2 -0
- package/dist/platform/svg-rasterizer.browser.js.map +1 -0
- package/dist/platform/svg-rasterizer.d.ts +2 -0
- package/dist/platform/svg-rasterizer.d.ts.map +1 -0
- package/dist/platform/svg-rasterizer.js +2 -0
- package/dist/platform/svg-rasterizer.js.map +1 -0
- package/dist/registry.d.ts +32 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +67 -0
- package/dist/registry.js.map +1 -0
- package/dist/shape/shape-plugin.d.ts +21 -0
- package/dist/shape/shape-plugin.d.ts.map +1 -0
- package/dist/shape/shape-plugin.js +148 -0
- package/dist/shape/shape-plugin.js.map +1 -0
- package/dist/table/table-plugin.d.ts +4 -0
- package/dist/table/table-plugin.d.ts.map +1 -0
- package/dist/table/table-plugin.js +232 -0
- package/dist/table/table-plugin.js.map +1 -0
- package/dist/table/table-types.d.ts +50 -0
- package/dist/table/table-types.d.ts.map +1 -0
- package/dist/table/table-types.js +129 -0
- package/dist/table/table-types.js.map +1 -0
- package/dist/text/text-decoration.d.ts +22 -0
- package/dist/text/text-decoration.d.ts.map +1 -0
- package/dist/text/text-decoration.js +43 -0
- package/dist/text/text-decoration.js.map +1 -0
- package/dist/text/text-plugin.d.ts +9 -0
- package/dist/text/text-plugin.d.ts.map +1 -0
- package/dist/text/text-plugin.js +496 -0
- package/dist/text/text-plugin.js.map +1 -0
- package/dist/text/word-wrap.d.ts +41 -0
- package/dist/text/word-wrap.d.ts.map +1 -0
- package/dist/text/word-wrap.js +149 -0
- package/dist/text/word-wrap.js.map +1 -0
- package/dist/types.d.ts +96 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +8 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +27 -0
- package/dist/utils.js.map +1 -0
- package/package.json +62 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 JsonPDF
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# @jsonpdf/plugins
|
|
2
|
+
|
|
3
|
+
Element type implementations for the jsonpdf rendering pipeline. Each plugin provides `measure()` and `render()` methods for a specific visual element type.
|
|
4
|
+
|
|
5
|
+
Plugins receive resolved values and never touch LiquidJS — expression resolution is handled upstream by the renderer.
|
|
6
|
+
|
|
7
|
+
## Plugins
|
|
8
|
+
|
|
9
|
+
| Plugin | Description |
|
|
10
|
+
| ----------- | --------------------------------------------------------------------------- |
|
|
11
|
+
| `text` | Text rendering with word wrapping and decoration (underline, strikethrough) |
|
|
12
|
+
| `line` | Line drawing with configurable dash patterns |
|
|
13
|
+
| `list` | Bullet, numbered, and lettered lists |
|
|
14
|
+
| `shape` | Rectangle, circle, ellipse, and rounded rectangle |
|
|
15
|
+
| `image` | Image rendering with fit modes (contain, cover, stretch, none) |
|
|
16
|
+
| `container` | Horizontal, vertical, absolute, and grid layouts |
|
|
17
|
+
| `table` | Table rendering with automatic column width calculation |
|
|
18
|
+
| `barcode` | Barcode and QR code generation via bwip-js |
|
|
19
|
+
| `chart` | Chart rendering via Vega-Lite |
|
|
20
|
+
| `frame` | Nested band container for sub-layouts |
|
|
21
|
+
|
|
22
|
+
## Platform abstraction
|
|
23
|
+
|
|
24
|
+
The package uses Node.js subpath imports (`#platform/*`) to swap implementations between Node and browser environments:
|
|
25
|
+
|
|
26
|
+
| Module | Node | Browser |
|
|
27
|
+
| -------------------------- | -------------------------- | -------------------------------------------------- |
|
|
28
|
+
| `#platform/fs` | Node `fs` for file reading | Throws (files must be inlined) |
|
|
29
|
+
| `#platform/svg-rasterizer` | `@resvg/resvg-js` (native) | `@resvg/resvg-wasm` |
|
|
30
|
+
| `#platform/init` | No-op | Requires `initBrowser(resvgWasm)` before rendering |
|
|
31
|
+
|
|
32
|
+
Browser consumers must call `initBrowser(resvgWasm)` once before rendering.
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { textPlugin, imagePlugin, PluginRegistry } from '@jsonpdf/plugins';
|
|
38
|
+
|
|
39
|
+
// Plugins are registered automatically when imported
|
|
40
|
+
// Use the registry to look up plugins by element type
|
|
41
|
+
const plugin = PluginRegistry.get('text');
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Exports
|
|
45
|
+
|
|
46
|
+
| Category | Exports |
|
|
47
|
+
| --------- | --------------------------------------------------------------------------------------------- |
|
|
48
|
+
| Registry | `PluginRegistry`, `registerPlugin`, `getPlugin`, `hasPlugin`, `getAllPlugins`, `clearPlugins` |
|
|
49
|
+
| Text | `textPlugin`, `wrapText`, `measureTextWidth` |
|
|
50
|
+
| Line | `linePlugin` |
|
|
51
|
+
| List | `listPlugin`, `ListItem`, `isListItem`, `toListItem` |
|
|
52
|
+
| Shape | `shapePlugin`, `roundedRectPath` |
|
|
53
|
+
| Image | `imagePlugin`, `computeFitDimensions`, `createImageCache`, `loadImageBytes`, `rasterizeSvg` |
|
|
54
|
+
| Container | `containerPlugin` |
|
|
55
|
+
| Table | `tablePlugin`, `TableColumn`, `computeColumnWidths` |
|
|
56
|
+
| Barcode | `barcodePlugin`, `generateBarcode`, `createBarcodeCache`, `BarcodeFormat` |
|
|
57
|
+
| Chart | `chartPlugin`, `generateChart`, `createChartCache`, `buildFinalSpec` |
|
|
58
|
+
| Frame | `framePlugin` |
|
|
59
|
+
| Platform | `readFileBytes`, `uint8ArrayToBase64`, `initBrowser` |
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { BarcodeProps } from './barcode-types.js';
|
|
2
|
+
/** Cache for generated barcode data URIs, keyed by deterministic option string. */
|
|
3
|
+
export type BarcodeCache = Map<string, Promise<string>>;
|
|
4
|
+
/** Create a new barcode cache instance. */
|
|
5
|
+
export declare function createBarcodeCache(): BarcodeCache;
|
|
6
|
+
/**
|
|
7
|
+
* Strip '#' from a hex color for bwip-js (expects hex without prefix).
|
|
8
|
+
* Handles both '#RGB' shorthand and '#RRGGBB'.
|
|
9
|
+
*/
|
|
10
|
+
export declare function toBwipColor(hex: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Generate a barcode PNG and return it as a data URI string.
|
|
13
|
+
*
|
|
14
|
+
* Uses the provided cache to deduplicate calls with identical props
|
|
15
|
+
* (important because the two-pass renderer calls measure+render twice).
|
|
16
|
+
*/
|
|
17
|
+
export declare function generateBarcode(props: BarcodeProps, cache: BarcodeCache): Promise<string>;
|
|
18
|
+
//# sourceMappingURL=barcode-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"barcode-generator.d.ts","sourceRoot":"","sources":["../../src/barcode/barcode-generator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAKvD,mFAAmF;AACnF,MAAM,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;AAExD,2CAA2C;AAC3C,wBAAgB,kBAAkB,IAAI,YAAY,CAEjD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAM/C;AAiBD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAqBzF"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import BwipJs from 'bwip-js';
|
|
2
|
+
import { TWO_D_FORMATS } from './barcode-types.js';
|
|
3
|
+
import { rasterizeSvg } from '../image/svg-rasterizer.js';
|
|
4
|
+
import { uint8ArrayToBase64 } from '../platform/base64.js';
|
|
5
|
+
/** Create a new barcode cache instance. */
|
|
6
|
+
export function createBarcodeCache() {
|
|
7
|
+
return new Map();
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Strip '#' from a hex color for bwip-js (expects hex without prefix).
|
|
11
|
+
* Handles both '#RGB' shorthand and '#RRGGBB'.
|
|
12
|
+
*/
|
|
13
|
+
export function toBwipColor(hex) {
|
|
14
|
+
const raw = hex.startsWith('#') ? hex.slice(1) : hex;
|
|
15
|
+
if (raw.length === 3) {
|
|
16
|
+
return raw[0] + raw[0] + raw[1] + raw[1] + raw[2] + raw[2];
|
|
17
|
+
}
|
|
18
|
+
return raw;
|
|
19
|
+
}
|
|
20
|
+
/** Build a deterministic cache key from barcode props. */
|
|
21
|
+
function cacheKey(props) {
|
|
22
|
+
return JSON.stringify({
|
|
23
|
+
v: props.value,
|
|
24
|
+
f: props.format,
|
|
25
|
+
bc: props.barColor ?? '#000000',
|
|
26
|
+
bg: props.backgroundColor ?? '#FFFFFF',
|
|
27
|
+
it: props.includeText ?? false,
|
|
28
|
+
ts: props.textSize,
|
|
29
|
+
s: props.scale ?? 3,
|
|
30
|
+
mh: props.moduleHeight ?? 10,
|
|
31
|
+
p: props.padding ?? 2,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Generate a barcode PNG and return it as a data URI string.
|
|
36
|
+
*
|
|
37
|
+
* Uses the provided cache to deduplicate calls with identical props
|
|
38
|
+
* (important because the two-pass renderer calls measure+render twice).
|
|
39
|
+
*/
|
|
40
|
+
export function generateBarcode(props, cache) {
|
|
41
|
+
const key = cacheKey(props);
|
|
42
|
+
const existing = cache.get(key);
|
|
43
|
+
if (existing) {
|
|
44
|
+
return existing;
|
|
45
|
+
}
|
|
46
|
+
// Wrap in a Promise constructor so synchronous throws become rejections
|
|
47
|
+
// without creating a transiently unhandled rejected promise.
|
|
48
|
+
const promise = new Promise((resolve, reject) => {
|
|
49
|
+
try {
|
|
50
|
+
resolve(generateBarcodeUncached(props));
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
// Remove from cache on failure so retries can succeed
|
|
57
|
+
promise.catch(() => cache.delete(key));
|
|
58
|
+
cache.set(key, promise);
|
|
59
|
+
return promise;
|
|
60
|
+
}
|
|
61
|
+
function generateBarcodeUncached(props) {
|
|
62
|
+
const options = {
|
|
63
|
+
bcid: props.format,
|
|
64
|
+
text: props.value,
|
|
65
|
+
scale: props.scale ?? 3,
|
|
66
|
+
paddingwidth: props.padding ?? 2,
|
|
67
|
+
paddingheight: props.padding ?? 2,
|
|
68
|
+
backgroundcolor: toBwipColor(props.backgroundColor ?? '#FFFFFF'),
|
|
69
|
+
barcolor: toBwipColor(props.barColor ?? '#000000'),
|
|
70
|
+
};
|
|
71
|
+
// Only set height for linear barcodes (not 2D codes)
|
|
72
|
+
if (!TWO_D_FORMATS.has(props.format)) {
|
|
73
|
+
options.height = props.moduleHeight ?? 10;
|
|
74
|
+
}
|
|
75
|
+
if (props.includeText) {
|
|
76
|
+
options.includetext = true;
|
|
77
|
+
options.textxalign = 'center';
|
|
78
|
+
if (props.textSize !== undefined) {
|
|
79
|
+
options.textsize = props.textSize;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
let svgString;
|
|
83
|
+
try {
|
|
84
|
+
svgString = BwipJs.toSVG(options);
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
88
|
+
throw new Error(`Barcode generation failed for format "${props.format}" with value "${props.value}": ${message}`);
|
|
89
|
+
}
|
|
90
|
+
const { pngBytes } = rasterizeSvg(svgString, 1);
|
|
91
|
+
const base64 = uint8ArrayToBase64(pngBytes);
|
|
92
|
+
return `data:image/png;base64,${base64}`;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=barcode-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"barcode-generator.js","sourceRoot":"","sources":["../../src/barcode/barcode-generator.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,SAAS,CAAC;AAE7B,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAK3D,2CAA2C;AAC3C,MAAM,UAAU,kBAAkB;IAChC,OAAO,IAAI,GAAG,EAAE,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,MAAM,GAAG,GAAG,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACrD,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,0DAA0D;AAC1D,SAAS,QAAQ,CAAC,KAAmB;IACnC,OAAO,IAAI,CAAC,SAAS,CAAC;QACpB,CAAC,EAAE,KAAK,CAAC,KAAK;QACd,CAAC,EAAE,KAAK,CAAC,MAAM;QACf,EAAE,EAAE,KAAK,CAAC,QAAQ,IAAI,SAAS;QAC/B,EAAE,EAAE,KAAK,CAAC,eAAe,IAAI,SAAS;QACtC,EAAE,EAAE,KAAK,CAAC,WAAW,IAAI,KAAK;QAC9B,EAAE,EAAE,KAAK,CAAC,QAAQ;QAClB,CAAC,EAAE,KAAK,CAAC,KAAK,IAAI,CAAC;QACnB,EAAE,EAAE,KAAK,CAAC,YAAY,IAAI,EAAE;QAC5B,CAAC,EAAE,KAAK,CAAC,OAAO,IAAI,CAAC;KACtB,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,KAAmB,EAAE,KAAmB;IACtE,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE5B,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,wEAAwE;IACxE,6DAA6D;IAC7D,MAAM,OAAO,GAAG,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACtD,IAAI,CAAC;YACH,OAAO,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC,CAAC,CAAC;IACH,sDAAsD;IACtD,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACvC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACxB,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,uBAAuB,CAAC,KAAmB;IAClD,MAAM,OAAO,GAAyB;QACpC,IAAI,EAAE,KAAK,CAAC,MAAM;QAClB,IAAI,EAAE,KAAK,CAAC,KAAK;QACjB,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,CAAC;QACvB,YAAY,EAAE,KAAK,CAAC,OAAO,IAAI,CAAC;QAChC,aAAa,EAAE,KAAK,CAAC,OAAO,IAAI,CAAC;QACjC,eAAe,EAAE,WAAW,CAAC,KAAK,CAAC,eAAe,IAAI,SAAS,CAAC;QAChE,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC,QAAQ,IAAI,SAAS,CAAC;KACnD,CAAC;IAEF,qDAAqD;IACrD,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;QACrC,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC,YAAY,IAAI,EAAE,CAAC;IAC5C,CAAC;IAED,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;QACtB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;QAC3B,OAAO,CAAC,UAAU,GAAG,QAAQ,CAAC;QAC9B,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YACjC,OAAO,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;QACpC,CAAC;IACH,CAAC;IAED,IAAI,SAAiB,CAAC;IACtB,IAAI,CAAC;QACH,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,MAAM,IAAI,KAAK,CACb,yCAAyC,KAAK,CAAC,MAAM,iBAAiB,KAAK,CAAC,KAAK,MAAM,OAAO,EAAE,CACjG,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,QAAQ,EAAE,GAAG,YAAY,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAC5C,OAAO,yBAAyB,MAAM,EAAE,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"barcode-plugin.d.ts","sourceRoot":"","sources":["../../src/barcode/barcode-plugin.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAgD,MAAM,aAAa,CAAC;AAExF,OAAO,EACL,KAAK,YAAY,EAIlB,MAAM,oBAAoB,CAAC;AAY5B,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,YAAY,CAoF9C,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { computeFitDimensions } from '../image/image-plugin.js';
|
|
2
|
+
import { barcodePropsSchema, BARCODE_DEFAULTS, SUPPORTED_FORMATS, } from './barcode-types.js';
|
|
3
|
+
import { generateBarcode, createBarcodeCache } from './barcode-generator.js';
|
|
4
|
+
/** Module-level barcode cache shared across measure and render passes. */
|
|
5
|
+
const barcodeCache = createBarcodeCache();
|
|
6
|
+
/** Get the barcode as an embedded PDF image. */
|
|
7
|
+
async function getBarcode(props, ctx) {
|
|
8
|
+
const dataUri = await generateBarcode(props, barcodeCache);
|
|
9
|
+
return ctx.imageCache.getOrEmbed(dataUri, ctx.pdfDoc);
|
|
10
|
+
}
|
|
11
|
+
export const barcodePlugin = {
|
|
12
|
+
type: 'barcode',
|
|
13
|
+
propsSchema: barcodePropsSchema,
|
|
14
|
+
defaultProps: BARCODE_DEFAULTS,
|
|
15
|
+
resolveProps(raw) {
|
|
16
|
+
return { ...BARCODE_DEFAULTS, ...raw };
|
|
17
|
+
},
|
|
18
|
+
validate(props) {
|
|
19
|
+
const errors = [];
|
|
20
|
+
if (!props.value || typeof props.value !== 'string' || props.value.trim().length === 0) {
|
|
21
|
+
errors.push({ path: '/value', message: 'value is required and must be a non-empty string' });
|
|
22
|
+
}
|
|
23
|
+
if (!SUPPORTED_FORMATS.includes(props.format)) {
|
|
24
|
+
errors.push({
|
|
25
|
+
path: '/format',
|
|
26
|
+
message: `format must be one of: ${SUPPORTED_FORMATS.join(', ')}`,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
if (props.barColor !== undefined &&
|
|
30
|
+
typeof props.barColor === 'string' &&
|
|
31
|
+
!props.barColor.startsWith('#')) {
|
|
32
|
+
errors.push({ path: '/barColor', message: 'barColor must be a hex string starting with #' });
|
|
33
|
+
}
|
|
34
|
+
if (props.backgroundColor !== undefined &&
|
|
35
|
+
typeof props.backgroundColor === 'string' &&
|
|
36
|
+
!props.backgroundColor.startsWith('#')) {
|
|
37
|
+
errors.push({
|
|
38
|
+
path: '/backgroundColor',
|
|
39
|
+
message: 'backgroundColor must be a hex string starting with #',
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return errors;
|
|
43
|
+
},
|
|
44
|
+
async measure(props, ctx) {
|
|
45
|
+
if (!props.value || props.value.trim().length === 0) {
|
|
46
|
+
return { width: 0, height: 0 };
|
|
47
|
+
}
|
|
48
|
+
await getBarcode(props, ctx);
|
|
49
|
+
return { width: ctx.availableWidth, height: ctx.availableHeight };
|
|
50
|
+
},
|
|
51
|
+
async render(props, ctx) {
|
|
52
|
+
if (!props.value || props.value.trim().length === 0) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const embedded = await getBarcode(props, ctx);
|
|
56
|
+
const { drawWidth, drawHeight, offsetX, offsetY } = computeFitDimensions(embedded.width, embedded.height, ctx.width, ctx.height, 'contain');
|
|
57
|
+
// pdf-lib drawImage: x,y is the bottom-left corner.
|
|
58
|
+
// ctx.x, ctx.y is the top-left of content area in pdf-lib coords (y up).
|
|
59
|
+
const imgX = ctx.x + offsetX;
|
|
60
|
+
const imgY = ctx.y - offsetY - drawHeight;
|
|
61
|
+
ctx.page.drawImage(embedded.image, {
|
|
62
|
+
x: imgX,
|
|
63
|
+
y: imgY,
|
|
64
|
+
width: drawWidth,
|
|
65
|
+
height: drawHeight,
|
|
66
|
+
opacity: ctx.opacity,
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=barcode-plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"barcode-plugin.js","sourceRoot":"","sources":["../../src/barcode/barcode-plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { JSONSchema } from '@jsonpdf/core';
|
|
2
|
+
/** Supported barcode/QR format identifiers (bwip-js bcid values). */
|
|
3
|
+
export declare const SUPPORTED_FORMATS: readonly ["qrcode", "datamatrix", "pdf417", "azteccode", "azteccodecompact", "maxicode", "code128", "code39", "ean13", "ean8", "upca", "upce", "itf14", "codabar", "interleaved2of5", "code93", "isbn", "issn", "gs1-128"];
|
|
4
|
+
export type BarcodeFormat = (typeof SUPPORTED_FORMATS)[number];
|
|
5
|
+
export interface BarcodeProps {
|
|
6
|
+
/** Data to encode (required). */
|
|
7
|
+
value: string;
|
|
8
|
+
/** Barcode type — bwip-js bcid (required). */
|
|
9
|
+
format: BarcodeFormat;
|
|
10
|
+
/** Bar/module color as hex string. Default '#000000'. */
|
|
11
|
+
barColor?: string;
|
|
12
|
+
/** Background color as hex string. Default '#FFFFFF'. */
|
|
13
|
+
backgroundColor?: string;
|
|
14
|
+
/** Show human-readable text below linear barcodes. Default false. */
|
|
15
|
+
includeText?: boolean;
|
|
16
|
+
/** Font size for the human-readable text in points. */
|
|
17
|
+
textSize?: number;
|
|
18
|
+
/** Module scale factor. Default 3. Higher = larger PNG before fitting. */
|
|
19
|
+
scale?: number;
|
|
20
|
+
/** Bar height in mm for linear barcodes. Default 10. Ignored for 2D codes. */
|
|
21
|
+
moduleHeight?: number;
|
|
22
|
+
/** Quiet zone padding in modules. Default 2. */
|
|
23
|
+
padding?: number;
|
|
24
|
+
}
|
|
25
|
+
export declare const barcodePropsSchema: JSONSchema;
|
|
26
|
+
export declare const BARCODE_DEFAULTS: BarcodeProps;
|
|
27
|
+
/** Set of 2D barcode formats where moduleHeight does not apply. */
|
|
28
|
+
export declare const TWO_D_FORMATS: ReadonlySet<string>;
|
|
29
|
+
//# sourceMappingURL=barcode-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"barcode-types.d.ts","sourceRoot":"","sources":["../../src/barcode/barcode-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,qEAAqE;AACrE,eAAO,MAAM,iBAAiB,4NAsBpB,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/D,MAAM,WAAW,YAAY;IAC3B,iCAAiC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,MAAM,EAAE,aAAa,CAAC;IACtB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qEAAqE;IACrE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,uDAAuD;IACvD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,kBAAkB,EAAE,UAehC,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,YAS9B,CAAC;AAEF,mEAAmE;AACnE,eAAO,MAAM,aAAa,EAAE,WAAW,CAAC,MAAM,CAO5C,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/** Supported barcode/QR format identifiers (bwip-js bcid values). */
|
|
2
|
+
export const SUPPORTED_FORMATS = [
|
|
3
|
+
// 2D codes
|
|
4
|
+
'qrcode',
|
|
5
|
+
'datamatrix',
|
|
6
|
+
'pdf417',
|
|
7
|
+
'azteccode',
|
|
8
|
+
'azteccodecompact',
|
|
9
|
+
'maxicode',
|
|
10
|
+
// Linear codes
|
|
11
|
+
'code128',
|
|
12
|
+
'code39',
|
|
13
|
+
'ean13',
|
|
14
|
+
'ean8',
|
|
15
|
+
'upca',
|
|
16
|
+
'upce',
|
|
17
|
+
'itf14',
|
|
18
|
+
'codabar',
|
|
19
|
+
'interleaved2of5',
|
|
20
|
+
'code93',
|
|
21
|
+
'isbn',
|
|
22
|
+
'issn',
|
|
23
|
+
'gs1-128',
|
|
24
|
+
];
|
|
25
|
+
export const barcodePropsSchema = {
|
|
26
|
+
type: 'object',
|
|
27
|
+
required: ['value', 'format'],
|
|
28
|
+
additionalProperties: false,
|
|
29
|
+
properties: {
|
|
30
|
+
value: { type: 'string', minLength: 1 },
|
|
31
|
+
format: { type: 'string', enum: [...SUPPORTED_FORMATS] },
|
|
32
|
+
barColor: { type: 'string' },
|
|
33
|
+
backgroundColor: { type: 'string' },
|
|
34
|
+
includeText: { type: 'boolean' },
|
|
35
|
+
textSize: { type: 'number', minimum: 1 },
|
|
36
|
+
scale: { type: 'number', minimum: 1 },
|
|
37
|
+
moduleHeight: { type: 'number', minimum: 1 },
|
|
38
|
+
padding: { type: 'number', minimum: 0 },
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
export const BARCODE_DEFAULTS = {
|
|
42
|
+
value: '',
|
|
43
|
+
format: 'qrcode',
|
|
44
|
+
barColor: '#000000',
|
|
45
|
+
backgroundColor: '#FFFFFF',
|
|
46
|
+
includeText: false,
|
|
47
|
+
scale: 3,
|
|
48
|
+
moduleHeight: 10,
|
|
49
|
+
padding: 2,
|
|
50
|
+
};
|
|
51
|
+
/** Set of 2D barcode formats where moduleHeight does not apply. */
|
|
52
|
+
export const TWO_D_FORMATS = new Set([
|
|
53
|
+
'qrcode',
|
|
54
|
+
'datamatrix',
|
|
55
|
+
'pdf417',
|
|
56
|
+
'azteccode',
|
|
57
|
+
'azteccodecompact',
|
|
58
|
+
'maxicode',
|
|
59
|
+
]);
|
|
60
|
+
//# sourceMappingURL=barcode-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"barcode-types.js","sourceRoot":"","sources":["../../src/barcode/barcode-types.ts"],"names":[],"mappings":"AAEA,qEAAqE;AACrE,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,WAAW;IACX,QAAQ;IACR,YAAY;IACZ,QAAQ;IACR,WAAW;IACX,kBAAkB;IAClB,UAAU;IACV,eAAe;IACf,SAAS;IACT,QAAQ;IACR,OAAO;IACP,MAAM;IACN,MAAM;IACN,MAAM;IACN,OAAO;IACP,SAAS;IACT,iBAAiB;IACjB,QAAQ;IACR,MAAM;IACN,MAAM;IACN,SAAS;CACD,CAAC;AAyBX,MAAM,CAAC,MAAM,kBAAkB,GAAe;IAC5C,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC;IAC7B,oBAAoB,EAAE,KAAK;IAC3B,UAAU,EAAE;QACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,EAAE;QACvC,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,GAAG,iBAAiB,CAAC,EAAE;QACxD,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC5B,eAAe,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACnC,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;QAChC,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE;QACxC,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE;QACrC,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE;QAC5C,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE;KACxC;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAiB;IAC5C,KAAK,EAAE,EAAE;IACT,MAAM,EAAE,QAAQ;IAChB,QAAQ,EAAE,SAAS;IACnB,eAAe,EAAE,SAAS;IAC1B,WAAW,EAAE,KAAK;IAClB,KAAK,EAAE,CAAC;IACR,YAAY,EAAE,EAAE;IAChB,OAAO,EAAE,CAAC;CACX,CAAC;AAEF,mEAAmE;AACnE,MAAM,CAAC,MAAM,aAAa,GAAwB,IAAI,GAAG,CAAC;IACxD,QAAQ;IACR,YAAY;IACZ,QAAQ;IACR,WAAW;IACX,kBAAkB;IAClB,UAAU;CACX,CAAC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ChartProps } from './chart-types.js';
|
|
2
|
+
/** Cache for generated chart PNG data URIs. */
|
|
3
|
+
export type ChartCache = Map<string, Promise<string>>;
|
|
4
|
+
/** Create a new chart cache instance. */
|
|
5
|
+
export declare function createChartCache(): ChartCache;
|
|
6
|
+
/**
|
|
7
|
+
* Build the final Vega-Lite spec by merging dataSource and background.
|
|
8
|
+
*/
|
|
9
|
+
export declare function buildFinalSpec(props: ChartProps): Record<string, unknown>;
|
|
10
|
+
/**
|
|
11
|
+
* Generate a chart PNG data URI from a resolved Vega-Lite spec.
|
|
12
|
+
*
|
|
13
|
+
* Uses the provided cache to deduplicate calls with identical specs
|
|
14
|
+
* (important because the two-pass renderer calls measure+render twice).
|
|
15
|
+
*/
|
|
16
|
+
export declare function generateChart(props: ChartProps, cache: ChartCache): Promise<string>;
|
|
17
|
+
//# sourceMappingURL=chart-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chart-generator.d.ts","sourceRoot":"","sources":["../../src/chart/chart-generator.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,+CAA+C;AAC/C,MAAM,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;AAEtD,yCAAyC;AACzC,wBAAgB,gBAAgB,IAAI,UAAU,CAE7C;AAOD;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAYzE;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAYnF"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import * as vl from 'vega-lite';
|
|
2
|
+
import * as vega from 'vega';
|
|
3
|
+
import { rasterizeSvg } from '../image/svg-rasterizer.js';
|
|
4
|
+
import { uint8ArrayToBase64 } from '../platform/base64.js';
|
|
5
|
+
/** Create a new chart cache instance. */
|
|
6
|
+
export function createChartCache() {
|
|
7
|
+
return new Map();
|
|
8
|
+
}
|
|
9
|
+
/** Build a deterministic cache key from resolved spec + scale. */
|
|
10
|
+
function cacheKey(spec, scale) {
|
|
11
|
+
return JSON.stringify({ s: spec, sc: scale });
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Build the final Vega-Lite spec by merging dataSource and background.
|
|
15
|
+
*/
|
|
16
|
+
export function buildFinalSpec(props) {
|
|
17
|
+
let spec = { ...props.spec };
|
|
18
|
+
if (props.dataSource !== undefined) {
|
|
19
|
+
spec = { ...spec, data: { values: props.dataSource } };
|
|
20
|
+
}
|
|
21
|
+
if (props.background !== undefined) {
|
|
22
|
+
spec = { ...spec, background: props.background };
|
|
23
|
+
}
|
|
24
|
+
return spec;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Generate a chart PNG data URI from a resolved Vega-Lite spec.
|
|
28
|
+
*
|
|
29
|
+
* Uses the provided cache to deduplicate calls with identical specs
|
|
30
|
+
* (important because the two-pass renderer calls measure+render twice).
|
|
31
|
+
*/
|
|
32
|
+
export function generateChart(props, cache) {
|
|
33
|
+
const finalSpec = buildFinalSpec(props);
|
|
34
|
+
const scale = props.scale ?? 2;
|
|
35
|
+
const key = cacheKey(finalSpec, scale);
|
|
36
|
+
const existing = cache.get(key);
|
|
37
|
+
if (existing)
|
|
38
|
+
return existing;
|
|
39
|
+
const promise = generateChartUncached(finalSpec, scale);
|
|
40
|
+
promise.catch(() => cache.delete(key));
|
|
41
|
+
cache.set(key, promise);
|
|
42
|
+
return promise;
|
|
43
|
+
}
|
|
44
|
+
async function generateChartUncached(spec, scale) {
|
|
45
|
+
// Step 1: Compile Vega-Lite spec to Vega spec
|
|
46
|
+
let vegaSpec;
|
|
47
|
+
try {
|
|
48
|
+
const result = vl.compile(spec);
|
|
49
|
+
vegaSpec = result.spec;
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
53
|
+
throw new Error(`Vega-Lite compilation failed: ${message}`);
|
|
54
|
+
}
|
|
55
|
+
// Step 2: Render Vega spec to SVG
|
|
56
|
+
let svgString;
|
|
57
|
+
const runtime = vega.parse(vegaSpec);
|
|
58
|
+
const view = new vega.View(runtime, { renderer: 'none' });
|
|
59
|
+
try {
|
|
60
|
+
view.initialize();
|
|
61
|
+
await view.runAsync();
|
|
62
|
+
svgString = await view.toSVG();
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
66
|
+
throw new Error(`Vega chart rendering failed: ${message}`);
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
view.finalize();
|
|
70
|
+
}
|
|
71
|
+
// Step 3: Rasterize SVG to PNG
|
|
72
|
+
const { pngBytes } = rasterizeSvg(svgString, scale);
|
|
73
|
+
// Step 4: Convert to data URI
|
|
74
|
+
const base64 = uint8ArrayToBase64(pngBytes);
|
|
75
|
+
return `data:image/png;base64,${base64}`;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=chart-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chart-generator.js","sourceRoot":"","sources":["../../src/chart/chart-generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chart-plugin.d.ts","sourceRoot":"","sources":["../../src/chart/chart-plugin.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAgD,MAAM,aAAa,CAAC;AAExF,OAAO,EAAE,KAAK,UAAU,EAAoC,MAAM,kBAAkB,CAAC;AAYrF,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,UAAU,CA0E1C,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { computeFitDimensions } from '../image/image-plugin.js';
|
|
2
|
+
import { chartPropsSchema, CHART_DEFAULTS } from './chart-types.js';
|
|
3
|
+
import { generateChart, createChartCache } from './chart-generator.js';
|
|
4
|
+
/** Module-level chart cache shared across measure and render passes. */
|
|
5
|
+
const chartCache = createChartCache();
|
|
6
|
+
/** Get the chart as an embedded PDF image. */
|
|
7
|
+
async function getChart(props, ctx) {
|
|
8
|
+
const dataUri = await generateChart(props, chartCache);
|
|
9
|
+
return ctx.imageCache.getOrEmbed(dataUri, ctx.pdfDoc);
|
|
10
|
+
}
|
|
11
|
+
export const chartPlugin = {
|
|
12
|
+
type: 'chart',
|
|
13
|
+
propsSchema: chartPropsSchema,
|
|
14
|
+
defaultProps: CHART_DEFAULTS,
|
|
15
|
+
resolveProps(raw) {
|
|
16
|
+
return { ...CHART_DEFAULTS, ...raw };
|
|
17
|
+
},
|
|
18
|
+
validate(props) {
|
|
19
|
+
const errors = [];
|
|
20
|
+
const spec = props.spec;
|
|
21
|
+
if (!spec || typeof spec !== 'object' || Array.isArray(spec)) {
|
|
22
|
+
errors.push({ path: '/spec', message: 'spec is required and must be a non-empty object' });
|
|
23
|
+
}
|
|
24
|
+
else if (Object.keys(props.spec).length === 0) {
|
|
25
|
+
errors.push({ path: '/spec', message: 'spec must not be empty' });
|
|
26
|
+
}
|
|
27
|
+
if (props.dataSource !== undefined && !Array.isArray(props.dataSource)) {
|
|
28
|
+
errors.push({ path: '/dataSource', message: 'dataSource must be an array' });
|
|
29
|
+
}
|
|
30
|
+
if (props.fit !== undefined && !['contain', 'cover', 'fill', 'none'].includes(props.fit)) {
|
|
31
|
+
errors.push({ path: '/fit', message: 'fit must be contain, cover, fill, or none' });
|
|
32
|
+
}
|
|
33
|
+
if (props.scale !== undefined && (typeof props.scale !== 'number' || props.scale < 0.5)) {
|
|
34
|
+
errors.push({ path: '/scale', message: 'scale must be a number >= 0.5' });
|
|
35
|
+
}
|
|
36
|
+
return errors;
|
|
37
|
+
},
|
|
38
|
+
async measure(props, ctx) {
|
|
39
|
+
if (Object.keys(props.spec).length === 0) {
|
|
40
|
+
return { width: 0, height: 0 };
|
|
41
|
+
}
|
|
42
|
+
await getChart(props, ctx);
|
|
43
|
+
return { width: ctx.availableWidth, height: ctx.availableHeight };
|
|
44
|
+
},
|
|
45
|
+
async render(props, ctx) {
|
|
46
|
+
if (Object.keys(props.spec).length === 0) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const embedded = await getChart(props, ctx);
|
|
50
|
+
const fit = props.fit ?? 'contain';
|
|
51
|
+
const { drawWidth, drawHeight, offsetX, offsetY } = computeFitDimensions(embedded.width, embedded.height, ctx.width, ctx.height, fit);
|
|
52
|
+
// pdf-lib drawImage: x,y is the bottom-left corner.
|
|
53
|
+
// ctx.x, ctx.y is the top-left of content area in pdf-lib coords (y up).
|
|
54
|
+
const imgX = ctx.x + offsetX;
|
|
55
|
+
const imgY = ctx.y - offsetY - drawHeight;
|
|
56
|
+
ctx.page.drawImage(embedded.image, {
|
|
57
|
+
x: imgX,
|
|
58
|
+
y: imgY,
|
|
59
|
+
width: drawWidth,
|
|
60
|
+
height: drawHeight,
|
|
61
|
+
opacity: ctx.opacity,
|
|
62
|
+
});
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
//# sourceMappingURL=chart-plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chart-plugin.js","sourceRoot":"","sources":["../../src/chart/chart-plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { JSONSchema } from '@jsonpdf/core';
|
|
2
|
+
/** Fit mode for chart image within element bounds. */
|
|
3
|
+
export type ChartFit = 'contain' | 'cover' | 'fill' | 'none';
|
|
4
|
+
export interface ChartProps {
|
|
5
|
+
/** Vega-Lite specification object (fully resolved by renderer). */
|
|
6
|
+
spec: Record<string, unknown>;
|
|
7
|
+
/** Optional data array to inject as spec.data.values. */
|
|
8
|
+
dataSource?: unknown[];
|
|
9
|
+
/** How the chart image fits within the element bounds. Default 'contain'. */
|
|
10
|
+
fit?: ChartFit;
|
|
11
|
+
/** Scale factor for SVG rasterization. Default 2 (HiDPI). */
|
|
12
|
+
scale?: number;
|
|
13
|
+
/** Background color for the chart. If set, overrides spec.background. */
|
|
14
|
+
background?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare const chartPropsSchema: JSONSchema;
|
|
17
|
+
export declare const CHART_DEFAULTS: ChartProps;
|
|
18
|
+
//# sourceMappingURL=chart-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chart-types.d.ts","sourceRoot":"","sources":["../../src/chart/chart-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,sDAAsD;AACtD,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAE7D,MAAM,WAAW,UAAU;IACzB,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,yDAAyD;IACzD,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;IACvB,6EAA6E;IAC7E,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,gBAAgB,EAAE,UAW9B,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,UAI5B,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const chartPropsSchema = {
|
|
2
|
+
type: 'object',
|
|
3
|
+
required: ['spec'],
|
|
4
|
+
additionalProperties: false,
|
|
5
|
+
properties: {
|
|
6
|
+
spec: { type: 'object' },
|
|
7
|
+
dataSource: { type: 'array' },
|
|
8
|
+
fit: { type: 'string', enum: ['contain', 'cover', 'fill', 'none'] },
|
|
9
|
+
scale: { type: 'number', minimum: 0.5 },
|
|
10
|
+
background: { type: 'string' },
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
export const CHART_DEFAULTS = {
|
|
14
|
+
spec: {},
|
|
15
|
+
fit: 'contain',
|
|
16
|
+
scale: 2,
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=chart-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chart-types.js","sourceRoot":"","sources":["../../src/chart/chart-types.ts"],"names":[],"mappings":"AAkBA,MAAM,CAAC,MAAM,gBAAgB,GAAe;IAC1C,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,MAAM,CAAC;IAClB,oBAAoB,EAAE,KAAK;IAC3B,UAAU,EAAE;QACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACxB,UAAU,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;QAC7B,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE;QACnE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE;QACvC,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KAC/B;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAe;IACxC,IAAI,EAAE,EAAE;IACR,GAAG,EAAE,SAAS;IACd,KAAK,EAAE,CAAC;CACT,CAAC"}
|