@overtone-art/canvas-editor-core 0.2.5 → 0.2.7
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/dist/chunk-NINRTPOJ.mjs +104 -0
- package/dist/chunk-NINRTPOJ.mjs.map +1 -0
- package/dist/index.d.mts +144 -225
- package/dist/index.d.ts +144 -225
- package/dist/index.global.js +506 -0
- package/dist/index.global.js.map +1 -0
- package/dist/index.js +1109 -94
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1020 -92
- package/dist/index.mjs.map +1 -1
- package/dist/node.d.mts +37 -0
- package/dist/node.d.ts +37 -0
- package/dist/node.js +281 -0
- package/dist/node.js.map +1 -0
- package/dist/node.mjs +233 -0
- package/dist/node.mjs.map +1 -0
- package/dist/types-bOY7oYVq.d.mts +383 -0
- package/dist/types-bOY7oYVq.d.ts +383 -0
- package/package.json +13 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ilia Dzhiubanskii
|
|
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.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// src/export.ts
|
|
2
|
+
function computePrintAreaClip(area, scaleX, scaleY, targetWidth, targetHeight) {
|
|
3
|
+
const left = Math.max(0, Math.min(targetWidth, area.left * scaleX));
|
|
4
|
+
const top = Math.max(0, Math.min(targetHeight, area.top * scaleY));
|
|
5
|
+
const right = Math.max(left, Math.min(targetWidth, (area.left + area.width) * scaleX));
|
|
6
|
+
const bottom = Math.max(top, Math.min(targetHeight, (area.top + area.height) * scaleY));
|
|
7
|
+
return { left, top, width: right - left, height: bottom - top };
|
|
8
|
+
}
|
|
9
|
+
function computeCoverPlacement(sourceWidth, sourceHeight, targetWidth, targetHeight) {
|
|
10
|
+
if (sourceWidth <= 0 || sourceHeight <= 0 || targetWidth <= 0 || targetHeight <= 0) {
|
|
11
|
+
throw new Error("Cover dimensions must be positive");
|
|
12
|
+
}
|
|
13
|
+
const scale = Math.max(targetWidth / sourceWidth, targetHeight / sourceHeight);
|
|
14
|
+
const width = sourceWidth * scale;
|
|
15
|
+
const height = sourceHeight * scale;
|
|
16
|
+
return {
|
|
17
|
+
left: (targetWidth - width) / 2,
|
|
18
|
+
top: (targetHeight - height) / 2,
|
|
19
|
+
width,
|
|
20
|
+
height
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function canvasElementToBlob(output, format, quality) {
|
|
24
|
+
const mime = format === "jpeg" ? "image/jpeg" : `image/${format}`;
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
output.toBlob(
|
|
27
|
+
(blob) => blob ? resolve(blob) : reject(new Error(`Failed to export ${format}`)),
|
|
28
|
+
mime,
|
|
29
|
+
quality
|
|
30
|
+
);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
async function exportPNG(canvas, options = {}) {
|
|
34
|
+
const { multiplier = 1, format = "png", quality = 1 } = options;
|
|
35
|
+
const output = canvas.toCanvasElement(multiplier);
|
|
36
|
+
return canvasElementToBlob(output, format, quality);
|
|
37
|
+
}
|
|
38
|
+
async function exportMockup(canvas, mockup, options = {}) {
|
|
39
|
+
const { multiplier = 1, format = "png", quality = 1 } = options;
|
|
40
|
+
const design = canvas.toCanvasElement(multiplier);
|
|
41
|
+
const output = design.ownerDocument.createElement("canvas");
|
|
42
|
+
output.width = design.width;
|
|
43
|
+
output.height = design.height;
|
|
44
|
+
const context = output.getContext("2d");
|
|
45
|
+
if (!context) throw new Error("2D canvas context is unavailable");
|
|
46
|
+
const loadImage = (url) => new Promise((resolve, reject) => {
|
|
47
|
+
const element = new Image();
|
|
48
|
+
element.crossOrigin = "anonymous";
|
|
49
|
+
element.onload = () => resolve(element);
|
|
50
|
+
element.onerror = () => reject(new Error(`Failed to load mockup image: ${url}`));
|
|
51
|
+
element.src = url;
|
|
52
|
+
});
|
|
53
|
+
const drawCover = (image) => {
|
|
54
|
+
const placement = computeCoverPlacement(
|
|
55
|
+
image.naturalWidth || image.width,
|
|
56
|
+
image.naturalHeight || image.height,
|
|
57
|
+
output.width,
|
|
58
|
+
output.height
|
|
59
|
+
);
|
|
60
|
+
context.drawImage(image, placement.left, placement.top, placement.width, placement.height);
|
|
61
|
+
};
|
|
62
|
+
drawCover(await loadImage(mockup.image));
|
|
63
|
+
context.save();
|
|
64
|
+
if (mockup.printArea && mockup.clipToPrintArea !== false) {
|
|
65
|
+
const clip = computePrintAreaClip(
|
|
66
|
+
mockup.printArea,
|
|
67
|
+
output.width / canvas.getWidth(),
|
|
68
|
+
output.height / canvas.getHeight(),
|
|
69
|
+
output.width,
|
|
70
|
+
output.height
|
|
71
|
+
);
|
|
72
|
+
context.beginPath();
|
|
73
|
+
context.rect(clip.left, clip.top, clip.width, clip.height);
|
|
74
|
+
context.clip();
|
|
75
|
+
}
|
|
76
|
+
context.globalAlpha = Math.max(0, Math.min(1, mockup.designOpacity ?? 1));
|
|
77
|
+
context.globalCompositeOperation = !mockup.designBlendMode || mockup.designBlendMode === "normal" ? "source-over" : mockup.designBlendMode;
|
|
78
|
+
context.drawImage(design, 0, 0);
|
|
79
|
+
context.restore();
|
|
80
|
+
if (mockup.overlay) {
|
|
81
|
+
context.save();
|
|
82
|
+
context.globalAlpha = Math.max(0, Math.min(1, mockup.overlay.opacity ?? 1));
|
|
83
|
+
context.globalCompositeOperation = mockup.overlay.blendMode === "normal" ? "source-over" : mockup.overlay.blendMode ?? "multiply";
|
|
84
|
+
drawCover(await loadImage(mockup.overlay.image));
|
|
85
|
+
context.restore();
|
|
86
|
+
}
|
|
87
|
+
return canvasElementToBlob(output, format, quality);
|
|
88
|
+
}
|
|
89
|
+
function exportSVG(canvas) {
|
|
90
|
+
return canvas.toSVG();
|
|
91
|
+
}
|
|
92
|
+
function exportDataURL(canvas, format = "png", multiplier = 1) {
|
|
93
|
+
return canvas.toDataURL({ format, multiplier });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export {
|
|
97
|
+
computePrintAreaClip,
|
|
98
|
+
computeCoverPlacement,
|
|
99
|
+
exportPNG,
|
|
100
|
+
exportMockup,
|
|
101
|
+
exportSVG,
|
|
102
|
+
exportDataURL
|
|
103
|
+
};
|
|
104
|
+
//# sourceMappingURL=chunk-NINRTPOJ.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/export.ts"],"sourcesContent":["import type { Canvas, ImageFormat } from 'fabric';\nimport type { MockupConfig, MockupPrintArea } from './types';\n\nexport interface PngExportOptions {\n multiplier?: number;\n format?: ImageFormat;\n quality?: number;\n}\n\nexport interface CoverPlacement {\n left: number;\n top: number;\n width: number;\n height: number;\n}\n\nexport function computePrintAreaClip(\n area: MockupPrintArea,\n scaleX: number,\n scaleY: number,\n targetWidth: number,\n targetHeight: number,\n): MockupPrintArea {\n const left = Math.max(0, Math.min(targetWidth, area.left * scaleX));\n const top = Math.max(0, Math.min(targetHeight, area.top * scaleY));\n const right = Math.max(left, Math.min(targetWidth, (area.left + area.width) * scaleX));\n const bottom = Math.max(top, Math.min(targetHeight, (area.top + area.height) * scaleY));\n return { left, top, width: right - left, height: bottom - top };\n}\n\n/** Object-fit: cover geometry, exported for deterministic preview/composite tests. */\nexport function computeCoverPlacement(\n sourceWidth: number,\n sourceHeight: number,\n targetWidth: number,\n targetHeight: number,\n): CoverPlacement {\n if (sourceWidth <= 0 || sourceHeight <= 0 || targetWidth <= 0 || targetHeight <= 0) {\n throw new Error('Cover dimensions must be positive');\n }\n const scale = Math.max(targetWidth / sourceWidth, targetHeight / sourceHeight);\n const width = sourceWidth * scale;\n const height = sourceHeight * scale;\n return {\n left: (targetWidth - width) / 2,\n top: (targetHeight - height) / 2,\n width,\n height,\n };\n}\n\nfunction canvasElementToBlob(\n output: HTMLCanvasElement,\n format: ImageFormat,\n quality: number,\n): Promise<Blob> {\n const mime = format === 'jpeg' ? 'image/jpeg' : `image/${format}`;\n return new Promise<Blob>((resolve, reject) => {\n output.toBlob(\n (blob) => (blob ? resolve(blob) : reject(new Error(`Failed to export ${format}`))),\n mime,\n quality,\n );\n });\n}\n\nexport async function exportPNG(canvas: Canvas, options: PngExportOptions = {}): Promise<Blob> {\n const { multiplier = 1, format = 'png' as ImageFormat, quality = 1 } = options;\n const output = canvas.toCanvasElement(multiplier);\n return canvasElementToBlob(output, format, quality);\n}\n\n/** Rasterize the browser mockup preview together with the transparent design. */\nexport async function exportMockup(\n canvas: Canvas,\n mockup: MockupConfig,\n options: PngExportOptions = {},\n): Promise<Blob> {\n const { multiplier = 1, format = 'png' as ImageFormat, quality = 1 } = options;\n const design = canvas.toCanvasElement(multiplier);\n const output = design.ownerDocument.createElement('canvas');\n output.width = design.width;\n output.height = design.height;\n const context = output.getContext('2d');\n if (!context) throw new Error('2D canvas context is unavailable');\n\n const loadImage = (url: string) =>\n new Promise<HTMLImageElement>((resolve, reject) => {\n const element = new Image();\n element.crossOrigin = 'anonymous';\n element.onload = () => resolve(element);\n element.onerror = () => reject(new Error(`Failed to load mockup image: ${url}`));\n element.src = url;\n });\n const drawCover = (image: HTMLImageElement) => {\n const placement = computeCoverPlacement(\n image.naturalWidth || image.width,\n image.naturalHeight || image.height,\n output.width,\n output.height,\n );\n context.drawImage(image, placement.left, placement.top, placement.width, placement.height);\n };\n\n drawCover(await loadImage(mockup.image));\n context.save();\n if (mockup.printArea && mockup.clipToPrintArea !== false) {\n const clip = computePrintAreaClip(\n mockup.printArea,\n output.width / canvas.getWidth(),\n output.height / canvas.getHeight(),\n output.width,\n output.height,\n );\n context.beginPath();\n context.rect(clip.left, clip.top, clip.width, clip.height);\n context.clip();\n }\n context.globalAlpha = Math.max(0, Math.min(1, mockup.designOpacity ?? 1));\n context.globalCompositeOperation =\n !mockup.designBlendMode || mockup.designBlendMode === 'normal'\n ? 'source-over'\n : mockup.designBlendMode;\n context.drawImage(design, 0, 0);\n context.restore();\n\n if (mockup.overlay) {\n context.save();\n context.globalAlpha = Math.max(0, Math.min(1, mockup.overlay.opacity ?? 1));\n context.globalCompositeOperation =\n mockup.overlay.blendMode === 'normal'\n ? 'source-over'\n : (mockup.overlay.blendMode ?? 'multiply');\n drawCover(await loadImage(mockup.overlay.image));\n context.restore();\n }\n return canvasElementToBlob(output, format, quality);\n}\n\nexport function exportSVG(canvas: Canvas): string {\n return canvas.toSVG();\n}\n\nexport function exportDataURL(canvas: Canvas, format: ImageFormat = 'png', multiplier = 1): string {\n return canvas.toDataURL({ format, multiplier });\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,221 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
type LayerType = 'image' | 'text' | 'shape' | 'template' | 'group';
|
|
5
|
-
interface LayerData {
|
|
6
|
-
id: string;
|
|
7
|
-
type: LayerType;
|
|
8
|
-
name: string;
|
|
9
|
-
visible: boolean;
|
|
10
|
-
locked: boolean;
|
|
11
|
-
opacity: number;
|
|
12
|
-
/** Non-fabric metadata persisted with the layer (pattern config, etc). */
|
|
13
|
-
meta?: LayerMeta;
|
|
14
|
-
}
|
|
15
|
-
interface LayerMeta {
|
|
16
|
-
pattern?: PatternState;
|
|
17
|
-
[key: string]: unknown;
|
|
18
|
-
}
|
|
19
|
-
interface SerializedLayer extends LayerData {
|
|
20
|
-
fabricObject: Record<string, unknown>;
|
|
21
|
-
}
|
|
22
|
-
interface EditorState {
|
|
23
|
-
version: string;
|
|
24
|
-
canvas: {
|
|
25
|
-
width: number;
|
|
26
|
-
height: number;
|
|
27
|
-
};
|
|
28
|
-
layers: SerializedLayer[];
|
|
29
|
-
background?: string;
|
|
30
|
-
mockup?: MockupConfig | null;
|
|
31
|
-
}
|
|
32
|
-
interface EditorConfig {
|
|
33
|
-
width: number;
|
|
34
|
-
height: number;
|
|
35
|
-
backgroundColor?: string;
|
|
36
|
-
fileAdapter?: FileAdapter;
|
|
37
|
-
imageProvider?: ImageProvider;
|
|
38
|
-
preserveObjectStacking?: boolean;
|
|
39
|
-
unit?: Unit;
|
|
40
|
-
dpi?: number;
|
|
41
|
-
}
|
|
42
|
-
type ExportFormat = 'png' | 'svg' | 'json';
|
|
43
|
-
interface FileAdapter {
|
|
44
|
-
save(data: Blob | string, filename: string, format: ExportFormat): Promise<string>;
|
|
45
|
-
}
|
|
46
|
-
interface ImageProviderResult {
|
|
47
|
-
url: string;
|
|
48
|
-
width: number;
|
|
49
|
-
height: number;
|
|
50
|
-
}
|
|
51
|
-
interface ImageProvider {
|
|
52
|
-
upload(file: File): Promise<ImageProviderResult>;
|
|
53
|
-
browse?(): Promise<ImageProviderResult | null>;
|
|
54
|
-
}
|
|
55
|
-
interface ShapePlugin {
|
|
56
|
-
name: string;
|
|
57
|
-
icon: string;
|
|
58
|
-
category?: string;
|
|
59
|
-
create(options?: Record<string, unknown>): FabricObject;
|
|
60
|
-
}
|
|
61
|
-
interface TemplateParameter {
|
|
62
|
-
key: string;
|
|
63
|
-
label: string;
|
|
64
|
-
type: 'text' | 'color' | 'number' | 'font';
|
|
65
|
-
default: string | number;
|
|
66
|
-
}
|
|
67
|
-
interface TemplateDefinition {
|
|
68
|
-
id: string;
|
|
69
|
-
name: string;
|
|
70
|
-
category: string;
|
|
71
|
-
svg: string;
|
|
72
|
-
parameters: TemplateParameter[];
|
|
73
|
-
preview?: string;
|
|
74
|
-
}
|
|
75
|
-
interface PrintifyPositioning {
|
|
76
|
-
x: number;
|
|
77
|
-
y: number;
|
|
78
|
-
scale: number;
|
|
79
|
-
angle: number;
|
|
80
|
-
}
|
|
81
|
-
type TileMode = 'grid' | 'brick-horizontal' | 'brick-vertical';
|
|
82
|
-
interface PatternConfig {
|
|
83
|
-
mode: TileMode;
|
|
84
|
-
/**
|
|
85
|
-
* Tile size as a % of the source image's on-canvas size (100 = natural).
|
|
86
|
-
* Smaller values pack more repeats across the print area; larger values make
|
|
87
|
-
* fewer, bigger tiles. Independent of how the source layer was placed.
|
|
88
|
-
*/
|
|
89
|
-
scale: number;
|
|
90
|
-
/** Extra horizontal gap between tiles, as % of tile width. */
|
|
91
|
-
horizontalSpacing: number;
|
|
92
|
-
/** Extra vertical gap between tiles, as % of tile height. */
|
|
93
|
-
verticalSpacing: number;
|
|
94
|
-
/** Rotation of the whole pattern, in degrees. */
|
|
95
|
-
angle: number;
|
|
96
|
-
/** Brick row/column shift, as % of tile size. */
|
|
97
|
-
horizontalOffset: number;
|
|
98
|
-
/**
|
|
99
|
-
* Phase shift of the whole tile grid inside the print area, as % of tile
|
|
100
|
-
* width. The pattern object itself is pinned to the print area (it can't be
|
|
101
|
-
* dragged — that would expose bare edges), so this is how the tiling is
|
|
102
|
-
* nudged into alignment. Clamped to ±100% so coverage is never broken.
|
|
103
|
-
*/
|
|
104
|
-
offsetX: number;
|
|
105
|
-
/** Phase shift of the tile grid, as % of tile height. See {@link offsetX}. */
|
|
106
|
-
offsetY: number;
|
|
107
|
-
/** Added rotation per horizontal step, in degrees. */
|
|
108
|
-
rotationStepH: number;
|
|
109
|
-
/** Added rotation per vertical step, in degrees. */
|
|
110
|
-
rotationStepV: number;
|
|
111
|
-
}
|
|
112
|
-
/** Fabric interaction flags frozen while a layer is rendered as a pattern. */
|
|
113
|
-
interface PatternLocks {
|
|
114
|
-
lockMovementX: boolean;
|
|
115
|
-
lockMovementY: boolean;
|
|
116
|
-
lockScalingX: boolean;
|
|
117
|
-
lockScalingY: boolean;
|
|
118
|
-
lockRotation: boolean;
|
|
119
|
-
hasControls: boolean;
|
|
120
|
-
}
|
|
121
|
-
/** Persisted on a layer's meta while it is rendered as a repeating pattern. */
|
|
122
|
-
interface PatternState {
|
|
123
|
-
config: PatternConfig;
|
|
124
|
-
/** Original (pre-pattern) image source, as a durable data URL when possible. */
|
|
125
|
-
originalSrc: string;
|
|
126
|
-
/**
|
|
127
|
-
* Serialized `clipPath` the image carried before it became a pattern, or null
|
|
128
|
-
* if it had none. A pattern must fill the whole print area, so any pre-pattern
|
|
129
|
-
* clip (e.g. a template crop sized to the original box) is stripped while the
|
|
130
|
-
* pattern is on and re-applied when it is turned off. Persisted so it survives
|
|
131
|
-
* serialization / reload / undo.
|
|
132
|
-
*/
|
|
133
|
-
originalClip?: Record<string, unknown> | null;
|
|
134
|
-
/**
|
|
135
|
-
* Interaction flags the object carried before it became a pattern. A pattern
|
|
136
|
-
* fills the whole print area, so while it is on the object is locked in place
|
|
137
|
-
* (a drag/resize would slide the tiled bitmap off the area and leave a bare
|
|
138
|
-
* band); the captured flags are restored when the pattern is turned off.
|
|
139
|
-
*/
|
|
140
|
-
originalLocks?: PatternLocks;
|
|
141
|
-
/** Original fabric transform, restored when the pattern is turned off. */
|
|
142
|
-
original: {
|
|
143
|
-
left: number;
|
|
144
|
-
top: number;
|
|
145
|
-
scaleX: number;
|
|
146
|
-
scaleY: number;
|
|
147
|
-
width: number;
|
|
148
|
-
height: number;
|
|
149
|
-
angle: number;
|
|
150
|
-
cropX: number;
|
|
151
|
-
cropY: number;
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
declare const DEFAULT_PATTERN_CONFIG: PatternConfig;
|
|
155
|
-
interface MockupPrintArea {
|
|
156
|
-
left: number;
|
|
157
|
-
top: number;
|
|
158
|
-
width: number;
|
|
159
|
-
height: number;
|
|
160
|
-
}
|
|
161
|
-
interface MockupConfig {
|
|
162
|
-
/** Garment/product image rendered behind the design (preview only). */
|
|
163
|
-
image: string;
|
|
164
|
-
/** Print-area rectangle, in canvas pixels. Drawn as a guide. */
|
|
165
|
-
printArea?: MockupPrintArea;
|
|
166
|
-
}
|
|
167
|
-
interface EditorEvents {
|
|
168
|
-
'layer:added': {
|
|
169
|
-
layer: LayerData;
|
|
170
|
-
};
|
|
171
|
-
'layer:removed': {
|
|
172
|
-
layerId: string;
|
|
173
|
-
};
|
|
174
|
-
'layer:selected': {
|
|
175
|
-
layerId: string | null;
|
|
176
|
-
};
|
|
177
|
-
'layer:modified': {
|
|
178
|
-
layerId: string;
|
|
179
|
-
};
|
|
180
|
-
'layer:reordered': {
|
|
181
|
-
layerIds: string[];
|
|
182
|
-
};
|
|
183
|
-
'layers:changed': {
|
|
184
|
-
layers: LayerData[];
|
|
185
|
-
};
|
|
186
|
-
'selection:changed': {
|
|
187
|
-
selected: string[];
|
|
188
|
-
};
|
|
189
|
-
'history:changed': {
|
|
190
|
-
canUndo: boolean;
|
|
191
|
-
canRedo: boolean;
|
|
192
|
-
};
|
|
193
|
-
'zoom:changed': {
|
|
194
|
-
zoom: number;
|
|
195
|
-
};
|
|
196
|
-
'snap:changed': {
|
|
197
|
-
enabled: boolean;
|
|
198
|
-
};
|
|
199
|
-
'crop:changed': {
|
|
200
|
-
active: boolean;
|
|
201
|
-
layerId: string | null;
|
|
202
|
-
};
|
|
203
|
-
'mockup:changed': {
|
|
204
|
-
mockup: MockupConfig | null;
|
|
205
|
-
};
|
|
206
|
-
'canvas:modified': Record<string, never>;
|
|
207
|
-
'export:start': {
|
|
208
|
-
format: string;
|
|
209
|
-
};
|
|
210
|
-
'export:complete': {
|
|
211
|
-
format: string;
|
|
212
|
-
url?: string;
|
|
213
|
-
};
|
|
214
|
-
error: {
|
|
215
|
-
message: string;
|
|
216
|
-
error?: unknown;
|
|
217
|
-
};
|
|
218
|
-
}
|
|
1
|
+
import { Canvas, FabricObject, ImageFormat } from 'fabric';
|
|
2
|
+
import { b as EditorEvents, l as LayerType, k as LayerMeta, L as LayerData, S as SerializedLayer, t as PatternSourceResolver, P as PatternConfig, s as PatternLocks, U as Unit, r as MockupPrintArea, p as MockupConfig, e as FontDefinition, m as LicenseConfig, o as LicenseStatus, y as ProjectState, E as EditorConfig, z as ShapePlugin, T as TemplateDefinition, I as ImageAdjustments, c as EditorState, A as SvgExportOptions, w as PrintifyPositioning, N as NormalizedLayerPosition, v as PositioningAdapter, h as ImageProviderResult, i as ImageSearchOptions, j as ImageSearchResult, F as FileAdapter, g as ImageProvider, B as BackgroundImageOptions, R as ResizeOptions, a as DpiIssue, C as CanvasSizePreset } from './types-bOY7oYVq.mjs';
|
|
3
|
+
export { D as DEFAULT_PATTERN_CONFIG, d as ExportFormat, f as ImageAttribution, n as LicensePayload, M as MockupBlendMode, q as MockupOverlay, u as PatternState, x as ProjectPage, G as TemplateParameter, H as TileMode } from './types-bOY7oYVq.mjs';
|
|
219
4
|
|
|
220
5
|
type EventHandler<T> = (data: T) => void;
|
|
221
6
|
declare class EventEmitter<TEvents extends {} = Record<string, unknown>> {
|
|
@@ -236,7 +21,7 @@ declare class Layer {
|
|
|
236
21
|
opacity: number;
|
|
237
22
|
/** Non-fabric data (e.g. pattern config) that must persist with the layer. */
|
|
238
23
|
meta: LayerMeta;
|
|
239
|
-
|
|
24
|
+
fabricObject: FabricObject;
|
|
240
25
|
constructor(type: LayerType, fabricObject: FabricObject, name?: string, id?: string);
|
|
241
26
|
private hasMeta;
|
|
242
27
|
toData(): LayerData;
|
|
@@ -246,9 +31,13 @@ declare class LayerManager {
|
|
|
246
31
|
private canvas;
|
|
247
32
|
private events;
|
|
248
33
|
private layers;
|
|
34
|
+
private onPropertyChanged?;
|
|
249
35
|
constructor(canvas: Canvas, events: EventEmitter<EditorEvents>);
|
|
36
|
+
setHistoryCallback(callback: () => void): void;
|
|
250
37
|
add(type: LayerType, fabricObject: FabricObject, name?: string, id?: string): Layer;
|
|
251
38
|
remove(id: string): boolean;
|
|
39
|
+
/** Replace a layer's render object while preserving its immutable ID and panel state. */
|
|
40
|
+
replaceObject(id: string, fabricObject: FabricObject): boolean;
|
|
252
41
|
reorder(id: string, newIndex: number): boolean;
|
|
253
42
|
select(id: string | null): void;
|
|
254
43
|
get(id: string): Layer | undefined;
|
|
@@ -267,21 +56,28 @@ declare class HistoryManager {
|
|
|
267
56
|
private undoStack;
|
|
268
57
|
private redoStack;
|
|
269
58
|
private maxSize;
|
|
59
|
+
private maxBytes;
|
|
270
60
|
private paused;
|
|
271
61
|
private debounceTimer;
|
|
272
62
|
private debounceMs;
|
|
273
63
|
private getState;
|
|
274
64
|
private restoreState;
|
|
275
65
|
private events;
|
|
66
|
+
private transactionDepth;
|
|
67
|
+
private transactionDirty;
|
|
276
68
|
constructor(opts: {
|
|
277
69
|
getState: () => string;
|
|
278
70
|
restoreState: (state: string) => Promise<void>;
|
|
279
71
|
events: EventEmitter<EditorEvents>;
|
|
280
72
|
maxSize?: number;
|
|
73
|
+
maxBytes?: number;
|
|
281
74
|
debounceMs?: number;
|
|
282
75
|
});
|
|
283
76
|
save(): void;
|
|
284
77
|
saveImmediate(): void;
|
|
78
|
+
beginTransaction(): void;
|
|
79
|
+
endTransaction(): void;
|
|
80
|
+
transaction<T>(operation: () => T | Promise<T>): Promise<T>;
|
|
285
81
|
undo(): Promise<void>;
|
|
286
82
|
redo(): Promise<void>;
|
|
287
83
|
/** True while a restore (undo/redo/deserialize) is in flight. Managers that
|
|
@@ -292,9 +88,12 @@ declare class HistoryManager {
|
|
|
292
88
|
canUndo(): boolean;
|
|
293
89
|
canRedo(): boolean;
|
|
294
90
|
clear(): void;
|
|
91
|
+
getSnapshotBytes(): number;
|
|
295
92
|
private cancelPending;
|
|
296
93
|
dispose(): void;
|
|
297
94
|
private emitChanged;
|
|
95
|
+
private snapshotBytes;
|
|
96
|
+
private trimToBudget;
|
|
298
97
|
}
|
|
299
98
|
|
|
300
99
|
/**
|
|
@@ -357,8 +156,10 @@ declare class PatternManager {
|
|
|
357
156
|
private canvas;
|
|
358
157
|
private layers;
|
|
359
158
|
private history;
|
|
159
|
+
private events;
|
|
160
|
+
private sourceResolver?;
|
|
360
161
|
private chains;
|
|
361
|
-
constructor(canvas: Canvas, layers: LayerManager, history: HistoryManager);
|
|
162
|
+
constructor(canvas: Canvas, layers: LayerManager, history: HistoryManager, events: EventEmitter<EditorEvents>, sourceResolver?: PatternSourceResolver | undefined);
|
|
362
163
|
isPattern(layerId: string): boolean;
|
|
363
164
|
getConfig(layerId: string): PatternConfig | null;
|
|
364
165
|
/** Turn a plain image layer into a pattern, or update an existing one. */
|
|
@@ -388,6 +189,7 @@ declare function applyPatternLocks(obj: FabricObject): void;
|
|
|
388
189
|
* leaving it frozen forever.
|
|
389
190
|
*/
|
|
390
191
|
declare function restoreLocks(obj: FabricObject, locks: PatternLocks | undefined): void;
|
|
192
|
+
declare function loadPatternImage(src: string, resolver?: PatternSourceResolver): Promise<HTMLImageElement>;
|
|
391
193
|
/** Clear the decoded-image cache (e.g. on teardown). Exported for completeness. */
|
|
392
194
|
declare function clearPatternImageCache(): void;
|
|
393
195
|
/**
|
|
@@ -396,7 +198,7 @@ declare function clearPatternImageCache(): void;
|
|
|
396
198
|
*
|
|
397
199
|
* Exported for unit testing of the tile geometry.
|
|
398
200
|
*/
|
|
399
|
-
declare function buildPatternDataURL(src: string, config: PatternConfig, targetW: number, targetH: number, baseW: number, baseH: number): Promise<string>;
|
|
201
|
+
declare function buildPatternDataURL(src: string, config: PatternConfig, targetW: number, targetH: number, baseW: number, baseH: number, sourceResolver?: PatternSourceResolver): Promise<string>;
|
|
400
202
|
/** Placement of one tile, relative to the (already rotated) pattern centre. */
|
|
401
203
|
interface TilePlacement {
|
|
402
204
|
/** Tile-centre offset from the pattern centre, in px. */
|
|
@@ -442,10 +244,70 @@ interface PngExportOptions {
|
|
|
442
244
|
format?: ImageFormat;
|
|
443
245
|
quality?: number;
|
|
444
246
|
}
|
|
247
|
+
interface CoverPlacement {
|
|
248
|
+
left: number;
|
|
249
|
+
top: number;
|
|
250
|
+
width: number;
|
|
251
|
+
height: number;
|
|
252
|
+
}
|
|
253
|
+
declare function computePrintAreaClip(area: MockupPrintArea, scaleX: number, scaleY: number, targetWidth: number, targetHeight: number): MockupPrintArea;
|
|
254
|
+
/** Object-fit: cover geometry, exported for deterministic preview/composite tests. */
|
|
255
|
+
declare function computeCoverPlacement(sourceWidth: number, sourceHeight: number, targetWidth: number, targetHeight: number): CoverPlacement;
|
|
445
256
|
declare function exportPNG(canvas: Canvas, options?: PngExportOptions): Promise<Blob>;
|
|
257
|
+
/** Rasterize the browser mockup preview together with the transparent design. */
|
|
258
|
+
declare function exportMockup(canvas: Canvas, mockup: MockupConfig, options?: PngExportOptions): Promise<Blob>;
|
|
446
259
|
declare function exportSVG(canvas: Canvas): string;
|
|
447
260
|
declare function exportDataURL(canvas: Canvas, format?: ImageFormat, multiplier?: number): string;
|
|
448
261
|
|
|
262
|
+
/** Browser font loader and SVG embedding registry. */
|
|
263
|
+
declare class FontRegistry {
|
|
264
|
+
private definitions;
|
|
265
|
+
private loads;
|
|
266
|
+
register(definition: FontDefinition): void;
|
|
267
|
+
unregister(family: string): boolean;
|
|
268
|
+
getAll(): FontDefinition[];
|
|
269
|
+
load(family: string): Promise<FontFace>;
|
|
270
|
+
ready(): Promise<void>;
|
|
271
|
+
getEmbeddedCss(): Promise<string>;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/** Inert, honor-system licensing and usage seam; it never performs a network request. */
|
|
275
|
+
declare class LicenseManager {
|
|
276
|
+
private config;
|
|
277
|
+
private status;
|
|
278
|
+
private readyPromise;
|
|
279
|
+
constructor(config?: LicenseConfig);
|
|
280
|
+
getStatus(): LicenseStatus;
|
|
281
|
+
ready(): Promise<LicenseStatus>;
|
|
282
|
+
hasFeature(feature: string): boolean;
|
|
283
|
+
track(name: string): void;
|
|
284
|
+
private validate;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/** Multi-page document state bound to one live editor canvas. */
|
|
288
|
+
declare class ProjectManager {
|
|
289
|
+
private editor;
|
|
290
|
+
private pages;
|
|
291
|
+
private activePageId;
|
|
292
|
+
constructor(editor: CanvasEditor);
|
|
293
|
+
getAll(): Array<{
|
|
294
|
+
id: string;
|
|
295
|
+
name: string;
|
|
296
|
+
}>;
|
|
297
|
+
getActivePageId(): string;
|
|
298
|
+
add(name?: string, cloneCurrent?: boolean): string;
|
|
299
|
+
switchTo(id: string): Promise<boolean>;
|
|
300
|
+
duplicate(id: string): Promise<string | null>;
|
|
301
|
+
remove(id: string): Promise<boolean>;
|
|
302
|
+
rename(id: string, name: string): boolean;
|
|
303
|
+
reorder(id: string, newIndex: number): boolean;
|
|
304
|
+
toJSON(): ProjectState;
|
|
305
|
+
fromJSON(project: ProjectState): Promise<void>;
|
|
306
|
+
private saveCurrent;
|
|
307
|
+
private blankState;
|
|
308
|
+
private emitChanged;
|
|
309
|
+
}
|
|
310
|
+
|
|
449
311
|
declare class CanvasEditor {
|
|
450
312
|
readonly canvas: Canvas;
|
|
451
313
|
readonly layers: LayerManager;
|
|
@@ -455,16 +317,22 @@ declare class CanvasEditor {
|
|
|
455
317
|
readonly snapping: SnapManager;
|
|
456
318
|
readonly crop: CropController;
|
|
457
319
|
readonly patterns: PatternManager;
|
|
320
|
+
readonly fonts: FontRegistry;
|
|
321
|
+
readonly licensing: LicenseManager;
|
|
322
|
+
readonly pages: ProjectManager;
|
|
458
323
|
private fileAdapter?;
|
|
459
324
|
private imageProvider?;
|
|
460
325
|
private zoomLevel;
|
|
461
326
|
private mockup;
|
|
462
327
|
private designBackground;
|
|
328
|
+
private designBackgroundImage;
|
|
463
329
|
constructor(canvasElement: HTMLCanvasElement, config: EditorConfig);
|
|
464
330
|
addImage(url: string, options?: Partial<Record<string, unknown>>): Promise<Layer>;
|
|
331
|
+
/** Replace an image source without changing its layer identity or visual transform. */
|
|
332
|
+
replaceImageSource(layerId: string, url: string): Promise<Layer>;
|
|
465
333
|
addText(text: string, options?: Partial<Record<string, unknown>>): Layer;
|
|
466
334
|
addShape(plugin: ShapePlugin, options?: Record<string, unknown>): Layer;
|
|
467
|
-
addTemplate(template: TemplateDefinition,
|
|
335
|
+
addTemplate(template: TemplateDefinition, params: Record<string, string | number>): Promise<Layer>;
|
|
468
336
|
removeLayer(id: string): void;
|
|
469
337
|
selectLayer(id: string | null): void;
|
|
470
338
|
getSelectedLayer(): Layer | null;
|
|
@@ -472,11 +340,22 @@ declare class CanvasEditor {
|
|
|
472
340
|
flipLayer(id: string, axis: 'horizontal' | 'vertical'): void;
|
|
473
341
|
/** Clone a layer (offset slightly) and select the copy. */
|
|
474
342
|
duplicateLayer(id: string): Promise<Layer | null>;
|
|
343
|
+
applyImageAdjustments(layerId: string, adjustments: ImageAdjustments): boolean;
|
|
344
|
+
/** Combine two or more layers into a single editable group layer. */
|
|
345
|
+
groupLayers(ids: string[], name?: string): Promise<Layer | null>;
|
|
346
|
+
/** Restore a group created by groupLayers back to its original layer records. */
|
|
347
|
+
ungroupLayer(id: string): Promise<Layer[]>;
|
|
475
348
|
toJSON(): EditorState;
|
|
476
349
|
fromJSON(state: EditorState): Promise<void>;
|
|
477
350
|
toPNG(options?: PngExportOptions): Promise<Blob>;
|
|
351
|
+
toJPEG(options?: Omit<PngExportOptions, 'format'>): Promise<Blob>;
|
|
352
|
+
toWebP(options?: Omit<PngExportOptions, 'format'>): Promise<Blob>;
|
|
353
|
+
private toRaster;
|
|
478
354
|
toSVG(): string;
|
|
355
|
+
toSVGAsync(options?: SvgExportOptions): Promise<string>;
|
|
479
356
|
toDataURL(format?: ImageFormat, multiplier?: number): string;
|
|
357
|
+
/** Export the current product-preview composite. Advanced warping is host-defined. */
|
|
358
|
+
toMockupImage(options?: PngExportOptions): Promise<Blob>;
|
|
480
359
|
/**
|
|
481
360
|
* Run an export with the configured design background applied, even when a
|
|
482
361
|
* mockup preview has forced the live canvas transparent — so exports reflect
|
|
@@ -484,14 +363,34 @@ declare class CanvasEditor {
|
|
|
484
363
|
*/
|
|
485
364
|
private withDesignBackground;
|
|
486
365
|
toPrintifyPositioning(): Record<string, PrintifyPositioning>;
|
|
487
|
-
|
|
366
|
+
/** Provider-neutral, ID-stable placement data in 0..1 canvas coordinates. */
|
|
367
|
+
toNormalizedPositioning(): NormalizedLayerPosition[];
|
|
368
|
+
toProviderPositioning<T>(adapter: PositioningAdapter<T>): T;
|
|
369
|
+
save(filename: string, format: 'png' | 'jpeg' | 'webp' | 'svg' | 'json'): Promise<string | undefined>;
|
|
488
370
|
uploadImage(file: File): Promise<ImageProviderResult | undefined>;
|
|
489
371
|
browseImages(): Promise<ImageProviderResult | null>;
|
|
372
|
+
searchImages(query: string, options?: ImageSearchOptions): Promise<ImageSearchResult | null>;
|
|
373
|
+
/** Track provider usage, then insert its hotlinked image as a normal layer. */
|
|
374
|
+
addProviderImage(image: ImageProviderResult, options?: Partial<Record<string, unknown>>): Promise<Layer>;
|
|
490
375
|
setFileAdapter(adapter: FileAdapter): void;
|
|
491
376
|
setImageProvider(provider: ImageProvider): void;
|
|
492
377
|
setBackground(color: string): void;
|
|
493
378
|
getDesignBackground(): string;
|
|
494
|
-
|
|
379
|
+
getDesignBackgroundImage(): FabricObject | null;
|
|
380
|
+
setBackgroundImage(url: string | null, options?: BackgroundImageOptions): Promise<void>;
|
|
381
|
+
/** Used by state restoration and advanced integrations with an existing Fabric object. */
|
|
382
|
+
setBackgroundImageObject(image: FabricObject | null, save?: boolean): void;
|
|
383
|
+
setTransparentBackground(): void;
|
|
384
|
+
resize(width: number, height: number, options?: ResizeOptions): void;
|
|
385
|
+
/** Effective source resolution for an image at its current physical size. */
|
|
386
|
+
getImageDpi(layerId: string): number | null;
|
|
387
|
+
validateImageDpi(minimumDpi?: number): DpiIssue[];
|
|
388
|
+
/** Render a small data-URL preview without changing document dimensions. */
|
|
389
|
+
toThumbnail(maxWidth?: number, maxHeight?: number, format?: ImageFormat): string;
|
|
390
|
+
bringToFront(id: string): boolean;
|
|
391
|
+
sendToBack(id: string): boolean;
|
|
392
|
+
bringForward(id: string): boolean;
|
|
393
|
+
sendBackward(id: string): boolean;
|
|
495
394
|
setZoom(level: number): void;
|
|
496
395
|
/** @deprecated use setZoom — kept for backward compatibility. */
|
|
497
396
|
zoom(level: number): void;
|
|
@@ -501,6 +400,8 @@ declare class CanvasEditor {
|
|
|
501
400
|
resetZoom(): void;
|
|
502
401
|
/** Fit the canvas inside a viewport (in px), accounting for padding. */
|
|
503
402
|
zoomToFit(viewportWidth: number, viewportHeight: number, padding?: number): void;
|
|
403
|
+
/** Zoom until the current selection fills the artboard viewport. */
|
|
404
|
+
zoomToSelection(padding?: number): void;
|
|
504
405
|
applyPattern(layerId: string, config: PatternConfig): Promise<void>;
|
|
505
406
|
clearPattern(layerId: string): Promise<void>;
|
|
506
407
|
setMockup(mockup: MockupConfig | null): void;
|
|
@@ -515,7 +416,25 @@ declare const generateId: () => string;
|
|
|
515
416
|
declare function clamp(v: number, min: number, max: number): number;
|
|
516
417
|
declare function round2(v: number): number;
|
|
517
418
|
|
|
419
|
+
/** XML text/attribute escaping for values interpolated into an SVG document. */
|
|
420
|
+
declare function escapeXml(value: string | number): string;
|
|
421
|
+
/**
|
|
422
|
+
* Strip active and externally-loaded content from an SVG before it is parsed
|
|
423
|
+
* into canvas objects.
|
|
424
|
+
*
|
|
425
|
+
* This is the single implementation of the control — every path that turns
|
|
426
|
+
* untrusted SVG into layers must call it, so it is exported rather than
|
|
427
|
+
* re-declared per package.
|
|
428
|
+
*/
|
|
429
|
+
declare function sanitizeSvg(svg: string): string;
|
|
430
|
+
|
|
431
|
+
/** True for values safe to use as a canvas/SVG colour. Empty means transparent. */
|
|
432
|
+
declare function isCssColor(value: unknown, allowEmpty?: boolean): value is string;
|
|
433
|
+
|
|
518
434
|
declare function serializeEditor(editor: CanvasEditor): EditorState;
|
|
519
435
|
declare function deserializeEditor(editor: CanvasEditor, state: EditorState): Promise<void>;
|
|
520
436
|
|
|
521
|
-
|
|
437
|
+
/** Common print and digital canvas sizes. */
|
|
438
|
+
declare const CANVAS_SIZE_PRESETS: readonly CanvasSizePreset[];
|
|
439
|
+
|
|
440
|
+
export { BackgroundImageOptions, CANVAS_SIZE_PRESETS, CanvasEditor, CanvasSizePreset, type CoverPlacement, CropController, DpiIssue, EditorConfig, EditorEvents, EditorState, EventEmitter, FileAdapter, FontDefinition, FontRegistry, HistoryManager, ImageAdjustments, ImageProvider, ImageProviderResult, ImageSearchOptions, ImageSearchResult, Layer, LayerData, LayerManager, LayerMeta, LayerType, LicenseConfig, LicenseManager, LicenseStatus, MockupConfig, MockupPrintArea, NormalizedLayerPosition, PatternConfig, PatternLocks, PatternManager, PatternSourceResolver, type PngExportOptions, PositioningAdapter, PrintifyPositioning, ProjectManager, ProjectState, ResizeOptions, SerializedLayer, ShapePlugin, SnapManager, SvgExportOptions, TemplateDefinition, type TilePlacement, Unit, UnitConverter, applyPatternLocks, buildPatternDataURL, captureLocks, clamp, clearPatternImageCache, computeCoverPlacement, computePrintAreaClip, computeTilePositions, deserializeEditor, drawTiles, escapeXml, exportDataURL, exportMockup, exportPNG, exportSVG, generateId, isCssColor, loadPatternImage, restoreLocks, round2, sanitizeSvg, serializeEditor };
|