@palmerama/hd-canvas 1.0.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.
Files changed (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +412 -0
  3. package/dist/bridge/Canvas2DBridge.d.ts +37 -0
  4. package/dist/bridge/Canvas2DBridge.d.ts.map +1 -0
  5. package/dist/bridge/Canvas2DBridge.js +116 -0
  6. package/dist/bridge/Canvas2DBridge.js.map +1 -0
  7. package/dist/core/ColorBuffer.d.ts +41 -0
  8. package/dist/core/ColorBuffer.d.ts.map +1 -0
  9. package/dist/core/ColorBuffer.js +138 -0
  10. package/dist/core/ColorBuffer.js.map +1 -0
  11. package/dist/core/HDCanvas.d.ts +80 -0
  12. package/dist/core/HDCanvas.d.ts.map +1 -0
  13. package/dist/core/HDCanvas.js +104 -0
  14. package/dist/core/HDCanvas.js.map +1 -0
  15. package/dist/core/PaperSize.d.ts +40 -0
  16. package/dist/core/PaperSize.d.ts.map +1 -0
  17. package/dist/core/PaperSize.js +63 -0
  18. package/dist/core/PaperSize.js.map +1 -0
  19. package/dist/export/ExportPipeline.d.ts +94 -0
  20. package/dist/export/ExportPipeline.d.ts.map +1 -0
  21. package/dist/export/ExportPipeline.js +121 -0
  22. package/dist/export/ExportPipeline.js.map +1 -0
  23. package/dist/export/PNGExporter.d.ts +62 -0
  24. package/dist/export/PNGExporter.d.ts.map +1 -0
  25. package/dist/export/PNGExporter.js +146 -0
  26. package/dist/export/PNGExporter.js.map +1 -0
  27. package/dist/export/ToneMapper.d.ts +88 -0
  28. package/dist/export/ToneMapper.d.ts.map +1 -0
  29. package/dist/export/ToneMapper.js +175 -0
  30. package/dist/export/ToneMapper.js.map +1 -0
  31. package/dist/index.d.ts +16 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +22 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/preview/FitStrategy.d.ts +27 -0
  36. package/dist/preview/FitStrategy.d.ts.map +1 -0
  37. package/dist/preview/FitStrategy.js +31 -0
  38. package/dist/preview/FitStrategy.js.map +1 -0
  39. package/dist/preview/PreviewRenderer.d.ts +71 -0
  40. package/dist/preview/PreviewRenderer.d.ts.map +1 -0
  41. package/dist/preview/PreviewRenderer.js +304 -0
  42. package/dist/preview/PreviewRenderer.js.map +1 -0
  43. package/package.json +47 -0
@@ -0,0 +1,138 @@
1
+ /**
2
+ * ColorBuffer — Float32/Float64 RGBA pixel buffer
3
+ *
4
+ * The foundation of the HD Canvas framework. Stores pixel data as
5
+ * unbounded floats (0.0–1.0 is "standard" range, >1.0 is HDR).
6
+ * Row-major layout, 4 floats per pixel (R, G, B, A).
7
+ */
8
+ export class ColorBuffer {
9
+ width;
10
+ height;
11
+ depth;
12
+ data;
13
+ constructor(width, height, depth = 32) {
14
+ if (!Number.isInteger(width) || width <= 0) {
15
+ throw new RangeError(`width must be a positive integer, got ${width}`);
16
+ }
17
+ if (!Number.isInteger(height) || height <= 0) {
18
+ throw new RangeError(`height must be a positive integer, got ${height}`);
19
+ }
20
+ this.width = width;
21
+ this.height = height;
22
+ this.depth = depth;
23
+ const length = width * height * 4;
24
+ this.data = depth === 64 ? new Float64Array(length) : new Float32Array(length);
25
+ }
26
+ /** Byte size of the underlying typed array */
27
+ get byteLength() {
28
+ return this.data.byteLength;
29
+ }
30
+ offset(x, y) {
31
+ if (x < 0 || x >= this.width || y < 0 || y >= this.height) {
32
+ throw new RangeError(`Pixel (${x}, ${y}) out of bounds for ${this.width}×${this.height} buffer`);
33
+ }
34
+ return (y * this.width + x) * 4;
35
+ }
36
+ setPixel(x, y, r, g, b, a = 1.0) {
37
+ const i = this.offset(x, y);
38
+ this.data[i] = r;
39
+ this.data[i + 1] = g;
40
+ this.data[i + 2] = b;
41
+ this.data[i + 3] = a;
42
+ }
43
+ getPixel(x, y) {
44
+ const i = this.offset(x, y);
45
+ return [
46
+ this.data[i],
47
+ this.data[i + 1],
48
+ this.data[i + 2],
49
+ this.data[i + 3],
50
+ ];
51
+ }
52
+ /**
53
+ * Blend a color onto the existing pixel using the specified blend mode.
54
+ * All modes use standard alpha compositing for the alpha channel.
55
+ */
56
+ blendPixel(x, y, r, g, b, a, mode = 'normal') {
57
+ const i = this.offset(x, y);
58
+ const dstR = this.data[i];
59
+ const dstG = this.data[i + 1];
60
+ const dstB = this.data[i + 2];
61
+ const dstA = this.data[i + 3];
62
+ let blendedR;
63
+ let blendedG;
64
+ let blendedB;
65
+ switch (mode) {
66
+ case 'normal':
67
+ blendedR = r;
68
+ blendedG = g;
69
+ blendedB = b;
70
+ break;
71
+ case 'add':
72
+ blendedR = dstR + r;
73
+ blendedG = dstG + g;
74
+ blendedB = dstB + b;
75
+ break;
76
+ case 'multiply':
77
+ blendedR = dstR * r;
78
+ blendedG = dstG * g;
79
+ blendedB = dstB * b;
80
+ break;
81
+ default: {
82
+ const _exhaustive = mode;
83
+ throw new Error(`Unknown blend mode: ${_exhaustive}`);
84
+ }
85
+ }
86
+ // Alpha compositing: src over dst
87
+ const outA = a + dstA * (1 - a);
88
+ if (outA === 0) {
89
+ this.data[i] = 0;
90
+ this.data[i + 1] = 0;
91
+ this.data[i + 2] = 0;
92
+ this.data[i + 3] = 0;
93
+ }
94
+ else {
95
+ this.data[i] = (blendedR * a + dstR * dstA * (1 - a)) / outA;
96
+ this.data[i + 1] = (blendedG * a + dstG * dstA * (1 - a)) / outA;
97
+ this.data[i + 2] = (blendedB * a + dstB * dstA * (1 - a)) / outA;
98
+ this.data[i + 3] = outA;
99
+ }
100
+ }
101
+ /** Fill the entire buffer with a single color (default: transparent black) */
102
+ clear(r = 0, g = 0, b = 0, a = 0) {
103
+ for (let i = 0; i < this.data.length; i += 4) {
104
+ this.data[i] = r;
105
+ this.data[i + 1] = g;
106
+ this.data[i + 2] = b;
107
+ this.data[i + 3] = a;
108
+ }
109
+ }
110
+ /** Extract a rectangular region as a new ColorBuffer */
111
+ getRegion(x, y, w, h) {
112
+ if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) {
113
+ throw new RangeError(`Region (${x},${y} ${w}×${h}) exceeds buffer bounds ${this.width}×${this.height}`);
114
+ }
115
+ if (w <= 0 || h <= 0) {
116
+ throw new RangeError(`Region dimensions must be positive, got ${w}×${h}`);
117
+ }
118
+ const region = new ColorBuffer(w, h, this.depth);
119
+ for (let row = 0; row < h; row++) {
120
+ const srcStart = ((y + row) * this.width + x) * 4;
121
+ const dstStart = row * w * 4;
122
+ region.data.set(this.data.subarray(srcStart, srcStart + w * 4), dstStart);
123
+ }
124
+ return region;
125
+ }
126
+ /** Write a ColorBuffer region into this buffer at the given position */
127
+ putRegion(x, y, region) {
128
+ if (x < 0 || y < 0 || x + region.width > this.width || y + region.height > this.height) {
129
+ throw new RangeError(`Region (${x},${y} ${region.width}×${region.height}) exceeds buffer bounds ${this.width}×${this.height}`);
130
+ }
131
+ for (let row = 0; row < region.height; row++) {
132
+ const srcStart = row * region.width * 4;
133
+ const dstStart = ((y + row) * this.width + x) * 4;
134
+ this.data.set(region.data.subarray(srcStart, srcStart + region.width * 4), dstStart);
135
+ }
136
+ }
137
+ }
138
+ //# sourceMappingURL=ColorBuffer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ColorBuffer.js","sourceRoot":"","sources":["../../src/core/ColorBuffer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * HDCanvas — Main class for the HD Canvas framework
3
+ *
4
+ * Wires together ColorBuffer + PaperSize into a single API surface.
5
+ * Construct with paper size + DPI, draw with float colors, preview on screen, export.
6
+ */
7
+ import { ColorBuffer, type ColorDepth, type BlendMode, type RGBA } from './ColorBuffer.js';
8
+ import { type PaperSizeKey, type PaperDimensions, type Orientation } from './PaperSize.js';
9
+ import { type DrawWith2DOptions } from '../bridge/Canvas2DBridge.js';
10
+ export interface HDCanvasOptions {
11
+ /** Predefined paper size key or custom dimensions in mm */
12
+ paperSize: PaperSizeKey | {
13
+ widthMM: number;
14
+ heightMM: number;
15
+ };
16
+ /** Dots per inch — default 300 */
17
+ dpi?: number;
18
+ /** Float32 or Float64 color depth — default 32 */
19
+ colorDepth?: ColorDepth;
20
+ /** Portrait or landscape — default portrait */
21
+ orientation?: Orientation;
22
+ }
23
+ export interface ExportOptions {
24
+ /** Tone mapping algorithm */
25
+ toneMap?: 'reinhard' | 'aces' | 'clamp';
26
+ /** Exposure adjustment (stops) */
27
+ exposure?: number;
28
+ /** Gamma correction */
29
+ gamma?: number;
30
+ /** Output format */
31
+ format?: 'png';
32
+ }
33
+ export declare class HDCanvas {
34
+ readonly widthPx: number;
35
+ readonly heightPx: number;
36
+ readonly dpi: number;
37
+ readonly colorDepth: ColorDepth;
38
+ readonly buffer: ColorBuffer;
39
+ readonly paperMM: PaperDimensions;
40
+ private previewRenderer;
41
+ private exportFn;
42
+ constructor(options: HDCanvasOptions);
43
+ setPixel(x: number, y: number, r: number, g: number, b: number, a?: number): void;
44
+ getPixel(x: number, y: number): RGBA;
45
+ blendPixel(x: number, y: number, r: number, g: number, b: number, a: number, mode?: BlendMode): void;
46
+ clear(r?: number, g?: number, b?: number, a?: number): void;
47
+ getRegion(x: number, y: number, w: number, h: number): ColorBuffer;
48
+ putRegion(x: number, y: number, region: ColorBuffer): void;
49
+ /**
50
+ * Draw using the familiar Canvas 2D API. Creates a temporary offscreen canvas,
51
+ * passes the 2D context to your callback, and reads pixels back into the float buffer.
52
+ *
53
+ * Note: Canvas 2D is 8-bit, so this is for convenience shapes/text, not HDR input.
54
+ * For HDR drawing, use the pixel API directly.
55
+ *
56
+ * Automatically tiles for large canvases (A0+) to stay within browser limits.
57
+ */
58
+ drawWith2D(callback: (ctx: CanvasRenderingContext2D) => void, options?: DrawWith2DOptions): void;
59
+ /**
60
+ * Attach a preview renderer. The renderer is injected to avoid
61
+ * coupling the core to DOM APIs (enables Node.js usage for headless export).
62
+ */
63
+ setPreviewRenderer(renderer: {
64
+ refresh(): void;
65
+ destroy(): void;
66
+ }): void;
67
+ /** Trigger a preview refresh. No-op if no renderer attached. */
68
+ refreshPreview(): void;
69
+ /**
70
+ * Register an export function. Injected to decouple core from export pipeline.
71
+ */
72
+ setExportFn(fn: (buffer: ColorBuffer, options: ExportOptions) => Promise<Blob>): void;
73
+ /** Export the canvas to a Blob. Requires an export function to be registered. */
74
+ export(options?: ExportOptions): Promise<Blob>;
75
+ /** Estimated memory usage of the buffer in bytes */
76
+ get memoryBytes(): number;
77
+ /** Clean up resources */
78
+ destroy(): void;
79
+ }
80
+ //# sourceMappingURL=HDCanvas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HDCanvas.d.ts","sourceRoot":"","sources":["../../src/core/HDCanvas.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * HDCanvas — Main class for the HD Canvas framework
3
+ *
4
+ * Wires together ColorBuffer + PaperSize into a single API surface.
5
+ * Construct with paper size + DPI, draw with float colors, preview on screen, export.
6
+ */
7
+ import { ColorBuffer } from './ColorBuffer.js';
8
+ import { resolvePaperSize, sizeToPx, } from './PaperSize.js';
9
+ import { drawWith2D } from '../bridge/Canvas2DBridge.js';
10
+ export class HDCanvas {
11
+ widthPx;
12
+ heightPx;
13
+ dpi;
14
+ colorDepth;
15
+ buffer;
16
+ paperMM;
17
+ previewRenderer = null;
18
+ exportFn = null;
19
+ constructor(options) {
20
+ const dpi = options.dpi ?? 300;
21
+ const colorDepth = options.colorDepth ?? 32;
22
+ const orientation = options.orientation ?? 'portrait';
23
+ if (dpi <= 0) {
24
+ throw new RangeError(`DPI must be positive, got ${dpi}`);
25
+ }
26
+ this.dpi = dpi;
27
+ this.colorDepth = colorDepth;
28
+ this.paperMM = resolvePaperSize(options.paperSize, orientation);
29
+ const px = sizeToPx(this.paperMM, dpi);
30
+ this.widthPx = px.width;
31
+ this.heightPx = px.height;
32
+ this.buffer = new ColorBuffer(this.widthPx, this.heightPx, colorDepth);
33
+ }
34
+ // --- Drawing API (delegates to ColorBuffer) ---
35
+ setPixel(x, y, r, g, b, a) {
36
+ this.buffer.setPixel(x, y, r, g, b, a);
37
+ }
38
+ getPixel(x, y) {
39
+ return this.buffer.getPixel(x, y);
40
+ }
41
+ blendPixel(x, y, r, g, b, a, mode) {
42
+ this.buffer.blendPixel(x, y, r, g, b, a, mode);
43
+ }
44
+ clear(r, g, b, a) {
45
+ this.buffer.clear(r, g, b, a);
46
+ }
47
+ getRegion(x, y, w, h) {
48
+ return this.buffer.getRegion(x, y, w, h);
49
+ }
50
+ putRegion(x, y, region) {
51
+ this.buffer.putRegion(x, y, region);
52
+ }
53
+ // --- Canvas 2D Bridge ---
54
+ /**
55
+ * Draw using the familiar Canvas 2D API. Creates a temporary offscreen canvas,
56
+ * passes the 2D context to your callback, and reads pixels back into the float buffer.
57
+ *
58
+ * Note: Canvas 2D is 8-bit, so this is for convenience shapes/text, not HDR input.
59
+ * For HDR drawing, use the pixel API directly.
60
+ *
61
+ * Automatically tiles for large canvases (A0+) to stay within browser limits.
62
+ */
63
+ drawWith2D(callback, options) {
64
+ drawWith2D(this.buffer, callback, options);
65
+ }
66
+ // --- Preview ---
67
+ /**
68
+ * Attach a preview renderer. The renderer is injected to avoid
69
+ * coupling the core to DOM APIs (enables Node.js usage for headless export).
70
+ */
71
+ setPreviewRenderer(renderer) {
72
+ this.previewRenderer?.destroy();
73
+ this.previewRenderer = renderer;
74
+ }
75
+ /** Trigger a preview refresh. No-op if no renderer attached. */
76
+ refreshPreview() {
77
+ this.previewRenderer?.refresh();
78
+ }
79
+ // --- Export ---
80
+ /**
81
+ * Register an export function. Injected to decouple core from export pipeline.
82
+ */
83
+ setExportFn(fn) {
84
+ this.exportFn = fn;
85
+ }
86
+ /** Export the canvas to a Blob. Requires an export function to be registered. */
87
+ async export(options = {}) {
88
+ if (!this.exportFn) {
89
+ throw new Error('No export function registered. Call setExportFn() or use the export pipeline module.');
90
+ }
91
+ return this.exportFn(this.buffer, options);
92
+ }
93
+ /** Estimated memory usage of the buffer in bytes */
94
+ get memoryBytes() {
95
+ return this.buffer.byteLength;
96
+ }
97
+ /** Clean up resources */
98
+ destroy() {
99
+ this.previewRenderer?.destroy();
100
+ this.previewRenderer = null;
101
+ this.exportFn = null;
102
+ }
103
+ }
104
+ //# sourceMappingURL=HDCanvas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HDCanvas.js","sourceRoot":"","sources":["../../src/core/HDCanvas.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * PaperSize — Paper size definitions and DPI→pixel calculations
3
+ *
4
+ * Supports ISO A-series (A0–A6) and US sizes (Letter, Legal, Tabloid).
5
+ * All dimensions stored in millimeters, converted to pixels via DPI.
6
+ */
7
+ export interface PaperDimensions {
8
+ /** Width in millimeters */
9
+ readonly widthMM: number;
10
+ /** Height in millimeters */
11
+ readonly heightMM: number;
12
+ }
13
+ export interface PixelDimensions {
14
+ readonly width: number;
15
+ readonly height: number;
16
+ }
17
+ export type Orientation = 'portrait' | 'landscape';
18
+ /** Predefined paper size keys */
19
+ export type PaperSizeKey = 'A0' | 'A1' | 'A2' | 'A3' | 'A4' | 'A5' | 'A6' | 'Letter' | 'Legal' | 'Tabloid';
20
+ /**
21
+ * Paper size registry — all dimensions in portrait orientation (width < height).
22
+ * Millimeter values per ISO 216 and ANSI standards.
23
+ */
24
+ export declare const PAPER_SIZES: Readonly<Record<PaperSizeKey, PaperDimensions>>;
25
+ /**
26
+ * Convert paper dimensions + DPI to pixel dimensions.
27
+ * Formula: pixels = (mm / 25.4) * dpi, rounded to nearest integer.
28
+ */
29
+ export declare function sizeToPx(size: PaperDimensions, dpi: number): PixelDimensions;
30
+ /**
31
+ * Resolve a paper size input to millimeter dimensions, applying orientation.
32
+ * Accepts either a predefined key or custom { widthMM, heightMM }.
33
+ */
34
+ export declare function resolvePaperSize(size: PaperSizeKey | PaperDimensions, orientation?: Orientation): PaperDimensions;
35
+ /**
36
+ * Estimate memory usage for a buffer at the given size, DPI, and color depth.
37
+ * Returns size in bytes.
38
+ */
39
+ export declare function estimateBufferBytes(size: PaperSizeKey | PaperDimensions, dpi: number, depth?: 32 | 64): number;
40
+ //# sourceMappingURL=PaperSize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PaperSize.d.ts","sourceRoot":"","sources":["../../src/core/PaperSize.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,eAAe;IAC9B,2BAA2B;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,4BAA4B;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,WAAW,CAAC;AAEnD,iCAAiC;AACjC,MAAM,MAAM,YAAY,GACpB,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAC9C,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;AAEnC;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,CAa9D,CAAC;AAIX;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,GAAG,eAAe,CAQ5E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,YAAY,GAAG,eAAe,EACpC,WAAW,GAAE,WAAwB,GACpC,eAAe,CAajB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,YAAY,GAAG,eAAe,EACpC,GAAG,EAAE,MAAM,EACX,KAAK,GAAE,EAAE,GAAG,EAAO,GAClB,MAAM,CAKR"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * PaperSize — Paper size definitions and DPI→pixel calculations
3
+ *
4
+ * Supports ISO A-series (A0–A6) and US sizes (Letter, Legal, Tabloid).
5
+ * All dimensions stored in millimeters, converted to pixels via DPI.
6
+ */
7
+ /**
8
+ * Paper size registry — all dimensions in portrait orientation (width < height).
9
+ * Millimeter values per ISO 216 and ANSI standards.
10
+ */
11
+ export const PAPER_SIZES = {
12
+ // ISO A-series
13
+ A0: { widthMM: 841, heightMM: 1189 },
14
+ A1: { widthMM: 594, heightMM: 841 },
15
+ A2: { widthMM: 420, heightMM: 594 },
16
+ A3: { widthMM: 297, heightMM: 420 },
17
+ A4: { widthMM: 210, heightMM: 297 },
18
+ A5: { widthMM: 148, heightMM: 210 },
19
+ A6: { widthMM: 105, heightMM: 148 },
20
+ // US sizes (converted to mm)
21
+ Letter: { widthMM: 215.9, heightMM: 279.4 },
22
+ Legal: { widthMM: 215.9, heightMM: 355.6 },
23
+ Tabloid: { widthMM: 279.4, heightMM: 431.8 },
24
+ };
25
+ const MM_PER_INCH = 25.4;
26
+ /**
27
+ * Convert paper dimensions + DPI to pixel dimensions.
28
+ * Formula: pixels = (mm / 25.4) * dpi, rounded to nearest integer.
29
+ */
30
+ export function sizeToPx(size, dpi) {
31
+ if (dpi <= 0) {
32
+ throw new RangeError(`DPI must be positive, got ${dpi}`);
33
+ }
34
+ return {
35
+ width: Math.round((size.widthMM / MM_PER_INCH) * dpi),
36
+ height: Math.round((size.heightMM / MM_PER_INCH) * dpi),
37
+ };
38
+ }
39
+ /**
40
+ * Resolve a paper size input to millimeter dimensions, applying orientation.
41
+ * Accepts either a predefined key or custom { widthMM, heightMM }.
42
+ */
43
+ export function resolvePaperSize(size, orientation = 'portrait') {
44
+ const dims = typeof size === 'string' ? PAPER_SIZES[size] : size;
45
+ if (dims.widthMM <= 0 || dims.heightMM <= 0) {
46
+ throw new RangeError(`Paper dimensions must be positive, got ${dims.widthMM}×${dims.heightMM}mm`);
47
+ }
48
+ if (orientation === 'landscape') {
49
+ return { widthMM: dims.heightMM, heightMM: dims.widthMM };
50
+ }
51
+ return dims;
52
+ }
53
+ /**
54
+ * Estimate memory usage for a buffer at the given size, DPI, and color depth.
55
+ * Returns size in bytes.
56
+ */
57
+ export function estimateBufferBytes(size, dpi, depth = 32) {
58
+ const resolved = typeof size === 'string' ? PAPER_SIZES[size] : size;
59
+ const px = sizeToPx(resolved, dpi);
60
+ const bytesPerFloat = depth === 64 ? 8 : 4;
61
+ return px.width * px.height * 4 * bytesPerFloat; // 4 channels (RGBA)
62
+ }
63
+ //# sourceMappingURL=PaperSize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PaperSize.js","sourceRoot":"","sources":["../../src/core/PaperSize.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAqBH;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAoD;IAC1E,eAAe;IACf,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE;IACpC,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE;IACnC,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE;IACnC,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE;IACnC,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE;IACnC,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE;IACnC,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE;IACnC,6BAA6B;IAC7B,MAAM,EAAG,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE;IAC5C,KAAK,EAAI,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE;IAC5C,OAAO,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE;CACpC,CAAC;AAEX,MAAM,WAAW,GAAG,IAAI,CAAC;AAEzB;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAqB,EAAE,GAAW;IACzD,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;QACb,MAAM,IAAI,UAAU,CAAC,6BAA6B,GAAG,EAAE,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO;QACL,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG,WAAW,CAAC,GAAG,GAAG,CAAC;QACrD,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,WAAW,CAAC,GAAG,GAAG,CAAC;KACxD,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,IAAoC,EACpC,cAA2B,UAAU;IAErC,MAAM,IAAI,GAAoB,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAElF,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,EAAE,CAAC;QAC5C,MAAM,IAAI,UAAU,CAClB,0CAA0C,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,QAAQ,IAAI,CAC5E,CAAC;IACJ,CAAC;IAED,IAAI,WAAW,KAAK,WAAW,EAAE,CAAC;QAChC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;IAC5D,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CACjC,IAAoC,EACpC,GAAW,EACX,QAAiB,EAAE;IAEnB,MAAM,QAAQ,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACrE,MAAM,EAAE,GAAG,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IACnC,MAAM,aAAa,GAAG,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,OAAO,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC,MAAM,GAAG,CAAC,GAAG,aAAa,CAAC,CAAC,oBAAoB;AACvE,CAAC"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * ExportPipeline — Wires ToneMapper + PNGExporter into HDCanvas.export()
3
+ *
4
+ * This is the integration layer. It creates the export function that
5
+ * HDCanvas.setExportFn() expects, connecting the float buffer to the
6
+ * tone mapping → PNG encoding → Blob pipeline.
7
+ *
8
+ * Usage:
9
+ * import { HDCanvas } from '../core/HDCanvas.js';
10
+ * import { attachExportPipeline } from './ExportPipeline.js';
11
+ *
12
+ * const canvas = new HDCanvas({ paperSize: 'A3', dpi: 300 });
13
+ * attachExportPipeline(canvas);
14
+ *
15
+ * // Now canvas.export() works:
16
+ * const blob = await canvas.export({ toneMap: 'aces', exposure: 1.2 });
17
+ */
18
+ import type { IColorBuffer } from '../core/ColorBuffer.js';
19
+ /**
20
+ * Export options — matches the ExportOptions interface from HDCanvas.
21
+ * We re-declare here to avoid importing from canvas-dev's code directly,
22
+ * keeping the export pipeline decoupled.
23
+ */
24
+ export interface ExportOptions {
25
+ /** Tone mapping algorithm. Default: 'reinhard'. */
26
+ toneMap?: 'reinhard' | 'aces' | 'clamp';
27
+ /** Exposure adjustment in stops. Default: 0. */
28
+ exposure?: number;
29
+ /** Gamma correction. Default: 2.2 (sRGB). */
30
+ gamma?: number;
31
+ /** Output format. Default: 'png'. */
32
+ format?: 'png';
33
+ }
34
+ /**
35
+ * Progress callback for large exports.
36
+ */
37
+ export type ExportProgressFn = (percent: number) => void;
38
+ /**
39
+ * Extended export options with progress tracking.
40
+ */
41
+ export interface ExportPipelineOptions extends ExportOptions {
42
+ /** DPI for the output file metadata. */
43
+ dpi: number;
44
+ /** Progress callback. */
45
+ onProgress?: ExportProgressFn;
46
+ }
47
+ /**
48
+ * Execute the full export pipeline: tone map → encode PNG → return Blob.
49
+ *
50
+ * This is the pure function that does the work. It takes a ColorBuffer
51
+ * and options, returns a Blob. No side effects, no DOM dependency.
52
+ */
53
+ export declare function exportBuffer(buffer: IColorBuffer, options: ExportPipelineOptions): Blob;
54
+ /**
55
+ * Minimal interface for the HDCanvas we need to attach to.
56
+ * Avoids importing the full HDCanvas class — keeps coupling loose.
57
+ */
58
+ export interface ExportableCanvas {
59
+ readonly buffer: IColorBuffer;
60
+ readonly dpi: number;
61
+ setExportFn(fn: (buffer: IColorBuffer, options: ExportOptions) => Promise<Blob>): void;
62
+ }
63
+ /**
64
+ * Attach the export pipeline to an HDCanvas instance.
65
+ *
66
+ * After calling this, `canvas.export()` will work:
67
+ * const blob = await canvas.export({ toneMap: 'aces', exposure: 1.2 });
68
+ *
69
+ * @param canvas - An HDCanvas instance (or anything matching ExportableCanvas)
70
+ * @param onProgress - Optional progress callback for all exports
71
+ */
72
+ export declare function attachExportPipeline(canvas: ExportableCanvas, onProgress?: ExportProgressFn): void;
73
+ /**
74
+ * Trigger a browser download of a Blob.
75
+ *
76
+ * Creates a temporary <a> element, clicks it, and cleans up.
77
+ * Only works in browser environments with DOM access.
78
+ */
79
+ export declare function downloadBlob(blob: Blob, filename: string): void;
80
+ /**
81
+ * Generate a descriptive filename for an export.
82
+ *
83
+ * @example generateFilename(3508, 4961, 300) → "artwork-3508x4961-300dpi.png"
84
+ */
85
+ export declare function generateFilename(width: number, height: number, dpi: number, prefix?: string): string;
86
+ /**
87
+ * Convenience: export an HDCanvas and trigger a browser download.
88
+ *
89
+ * @param canvas - HDCanvas with export pipeline attached
90
+ * @param options - Export options (toneMap, exposure, gamma)
91
+ * @param filename - Custom filename (auto-generated if omitted)
92
+ */
93
+ export declare function exportAndDownload(canvas: ExportableCanvas, options?: ExportOptions, filename?: string): Promise<void>;
94
+ //# sourceMappingURL=ExportPipeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExportPipeline.d.ts","sourceRoot":"","sources":["../../src/export/ExportPipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAI3D;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,mDAAmD;IACnD,OAAO,CAAC,EAAE,UAAU,GAAG,MAAM,GAAG,OAAO,CAAC;IACxC,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,MAAM,CAAC,EAAE,KAAK,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;AAEzD;;GAEG;AACH,MAAM,WAAW,qBAAsB,SAAQ,aAAa;IAC1D,wCAAwC;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,yBAAyB;IACzB,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAID;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,qBAAqB,GAC7B,IAAI,CA4CN;AAID;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,EAAE,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACxF;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,gBAAgB,EACxB,UAAU,CAAC,EAAE,gBAAgB,GAC5B,IAAI,CAQN;AAID;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAkB/D;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,MAAM,GAAE,MAAkB,GACzB,MAAM,CAER;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,gBAAgB,EACxB,OAAO,GAAE,aAAkB,EAC3B,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAaf"}