@polotno/pdf-export 0.1.37 → 0.1.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -8
- package/lib/index.d.ts +66 -8
- package/lib/index.js +25 -145
- package/package.json +17 -18
- package/lib/browser-entry.d.ts +0 -7
- package/lib/browser-entry.js +0 -11
- package/lib/compare-render.d.ts +0 -1
- package/lib/compare-render.js +0 -185
- package/lib/core/index.d.ts +0 -26
- package/lib/core/index.js +0 -87
- package/lib/figure.d.ts +0 -10
- package/lib/figure.js +0 -54
- package/lib/filters.d.ts +0 -2
- package/lib/filters.js +0 -163
- package/lib/ghostscript.d.ts +0 -21
- package/lib/ghostscript.js +0 -132
- package/lib/group.d.ts +0 -5
- package/lib/group.js +0 -5
- package/lib/image.d.ts +0 -38
- package/lib/image.js +0 -279
- package/lib/line.d.ts +0 -10
- package/lib/line.js +0 -66
- package/lib/platform/adapter.d.ts +0 -37
- package/lib/platform/adapter.js +0 -13
- package/lib/platform/browser-polyfill.d.ts +0 -1
- package/lib/platform/browser-polyfill.js +0 -5
- package/lib/platform/browser.d.ts +0 -7
- package/lib/platform/browser.js +0 -145
- package/lib/platform/node.d.ts +0 -7
- package/lib/platform/node.js +0 -142
- package/lib/spot-colors.d.ts +0 -38
- package/lib/spot-colors.js +0 -141
- package/lib/svg-render.d.ts +0 -9
- package/lib/svg-render.js +0 -63
- package/lib/svg.d.ts +0 -12
- package/lib/svg.js +0 -224
- package/lib/text/fonts.d.ts +0 -16
- package/lib/text/fonts.js +0 -82
- package/lib/text/index.d.ts +0 -8
- package/lib/text/index.js +0 -42
- package/lib/text/layout.d.ts +0 -22
- package/lib/text/layout.js +0 -522
- package/lib/text/parser.d.ts +0 -46
- package/lib/text/parser.js +0 -415
- package/lib/text/render.d.ts +0 -8
- package/lib/text/render.js +0 -237
- package/lib/text/types.d.ts +0 -91
- package/lib/text/types.js +0 -1
- package/lib/text.d.ts +0 -49
- package/lib/text.js +0 -1277
- package/lib/utils.d.ts +0 -16
- package/lib/utils.js +0 -124
package/lib/platform/node.js
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import { Buffer } from 'buffer';
|
|
3
|
-
import { PassThrough } from 'stream';
|
|
4
|
-
import PDFDocument from 'pdfkit';
|
|
5
|
-
import SVGtoPDF from 'svg-to-pdfkit';
|
|
6
|
-
import Canvas from 'canvas';
|
|
7
|
-
import sharp from 'sharp';
|
|
8
|
-
import nodeFetch from 'node-fetch';
|
|
9
|
-
import { fileTypeFromBuffer } from 'file-type';
|
|
10
|
-
import { convertToPDFX1a, validatePDFX1a } from '../ghostscript.js';
|
|
11
|
-
function ensureBuffer(data) {
|
|
12
|
-
return Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
13
|
-
}
|
|
14
|
-
function getFetch() {
|
|
15
|
-
if (typeof globalThis.fetch === 'function') {
|
|
16
|
-
return globalThis.fetch.bind(globalThis);
|
|
17
|
-
}
|
|
18
|
-
return nodeFetch;
|
|
19
|
-
}
|
|
20
|
-
async function convertToPNG(buffer, mime) {
|
|
21
|
-
if (mime === 'image/png' || mime === 'image/jpeg') {
|
|
22
|
-
return buffer;
|
|
23
|
-
}
|
|
24
|
-
// Fall back to PNG conversion for other formats
|
|
25
|
-
return sharp(buffer).toFormat('png').toBuffer();
|
|
26
|
-
}
|
|
27
|
-
function attachAddSVG(doc) {
|
|
28
|
-
const existing = doc.addSVG;
|
|
29
|
-
if (!existing) {
|
|
30
|
-
doc.addSVG = function (svg, x, y, options) {
|
|
31
|
-
SVGtoPDF(this, svg, x, y, options);
|
|
32
|
-
return this;
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
async function writeBufferToFile(fileName, buffer) {
|
|
37
|
-
await fs.promises.writeFile(fileName, buffer);
|
|
38
|
-
}
|
|
39
|
-
export function createNodeAdapter() {
|
|
40
|
-
const fetchImpl = getFetch();
|
|
41
|
-
return {
|
|
42
|
-
async fetch(input, init) {
|
|
43
|
-
return (await fetchImpl(input, init));
|
|
44
|
-
},
|
|
45
|
-
async loadImage(src) {
|
|
46
|
-
let buffer;
|
|
47
|
-
let mime;
|
|
48
|
-
if (src.startsWith('data:')) {
|
|
49
|
-
const matches = src.match(/^data:(.+);base64,(.*)$/);
|
|
50
|
-
if (!matches) {
|
|
51
|
-
throw new Error('Invalid data URL');
|
|
52
|
-
}
|
|
53
|
-
mime = matches[1];
|
|
54
|
-
buffer = Buffer.from(matches[2], 'base64');
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
const response = await fetchImpl(src);
|
|
58
|
-
if (!response.ok) {
|
|
59
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
60
|
-
}
|
|
61
|
-
const arrayBuffer = await response.arrayBuffer();
|
|
62
|
-
buffer = Buffer.from(arrayBuffer);
|
|
63
|
-
const typeInfo = await fileTypeFromBuffer(buffer);
|
|
64
|
-
if (typeInfo) {
|
|
65
|
-
mime = typeInfo.mime;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
const normalizedBuffer = await convertToPNG(buffer, mime);
|
|
69
|
-
return Canvas.loadImage(normalizedBuffer);
|
|
70
|
-
},
|
|
71
|
-
createCanvas(width, height) {
|
|
72
|
-
return Canvas.createCanvas(width, height);
|
|
73
|
-
},
|
|
74
|
-
createPDFContext(options) {
|
|
75
|
-
const doc = new PDFDocument(options);
|
|
76
|
-
attachAddSVG(doc);
|
|
77
|
-
const stream = doc.pipe(new PassThrough());
|
|
78
|
-
const chunks = [];
|
|
79
|
-
stream.on('data', (chunk) => {
|
|
80
|
-
chunks.push(Buffer.from(chunk));
|
|
81
|
-
});
|
|
82
|
-
const resultPromise = new Promise((resolve, reject) => {
|
|
83
|
-
stream.on('end', () => resolve(Buffer.concat(chunks)));
|
|
84
|
-
stream.on('error', reject);
|
|
85
|
-
doc.on('error', reject);
|
|
86
|
-
});
|
|
87
|
-
const finalize = async (options) => {
|
|
88
|
-
const buffer = await resultPromise;
|
|
89
|
-
const outputBuffer = Buffer.from(buffer);
|
|
90
|
-
if (options?.fileName) {
|
|
91
|
-
const targetFile = options.fileName;
|
|
92
|
-
await writeBufferToFile(targetFile, outputBuffer);
|
|
93
|
-
if (options.attrs?.pdfx1a) {
|
|
94
|
-
const tempFile = targetFile.replace('.pdf', '-temp.pdf');
|
|
95
|
-
await fs.promises.rename(targetFile, tempFile);
|
|
96
|
-
try {
|
|
97
|
-
await convertToPDFX1a(tempFile, targetFile, {
|
|
98
|
-
metadata: options.attrs.metadata || {},
|
|
99
|
-
});
|
|
100
|
-
await fs.promises.unlink(tempFile);
|
|
101
|
-
if (options.attrs.validate) {
|
|
102
|
-
const isValid = await validatePDFX1a(targetFile);
|
|
103
|
-
if (!isValid) {
|
|
104
|
-
console.warn('Warning: Generated PDF may not be fully PDF/X-1a compliant');
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
catch (error) {
|
|
109
|
-
if (fs.existsSync(tempFile)) {
|
|
110
|
-
await fs.promises.rename(tempFile, targetFile);
|
|
111
|
-
}
|
|
112
|
-
throw new Error(`PDF/X-1a conversion failed: ${error.message}`);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
return new Uint8Array(outputBuffer);
|
|
117
|
-
};
|
|
118
|
-
return {
|
|
119
|
-
doc,
|
|
120
|
-
finalize,
|
|
121
|
-
};
|
|
122
|
-
},
|
|
123
|
-
registerFont(doc, name, data) {
|
|
124
|
-
const buffer = ensureBuffer(data);
|
|
125
|
-
doc.registerFont(name, buffer);
|
|
126
|
-
},
|
|
127
|
-
encodeBase64(data) {
|
|
128
|
-
return Buffer.from(data).toString('base64');
|
|
129
|
-
},
|
|
130
|
-
decodeBase64(value) {
|
|
131
|
-
return new Uint8Array(Buffer.from(value, 'base64'));
|
|
132
|
-
},
|
|
133
|
-
embedImage(doc, data, x, y, options, _mimeType) {
|
|
134
|
-
if (typeof data === 'string') {
|
|
135
|
-
doc.image(data, x, y, options);
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
const buffer = ensureBuffer(data);
|
|
139
|
-
doc.image(buffer, x, y, options);
|
|
140
|
-
},
|
|
141
|
-
};
|
|
142
|
-
}
|
package/lib/spot-colors.d.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
export interface SpotColorDefinition {
|
|
2
|
-
name?: string;
|
|
3
|
-
cmyk?: number[];
|
|
4
|
-
}
|
|
5
|
-
export interface SpotColorConfig {
|
|
6
|
-
[color: string]: SpotColorDefinition;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Normalize color to a consistent format for matching using Konva's color parser
|
|
10
|
-
* This ensures consistency with how Polotno/Konva handles colors
|
|
11
|
-
* @param color - Color in any format (string or [r, g, b, a] array)
|
|
12
|
-
* @returns Normalized color string in rgba format
|
|
13
|
-
*/
|
|
14
|
-
export declare function normalizeColor(color: string | number[]): string | null;
|
|
15
|
-
/**
|
|
16
|
-
* Get spot color definition for a given color
|
|
17
|
-
* @param color - Color to check
|
|
18
|
-
* @param spotColorConfig - Spot color configuration
|
|
19
|
-
* @returns Spot color definition or null
|
|
20
|
-
*/
|
|
21
|
-
export declare function getSpotColorForColor(color: string, spotColorConfig: SpotColorConfig): SpotColorDefinition | null;
|
|
22
|
-
/**
|
|
23
|
-
* Register a spot color using PDFKit's built-in addSpotColor method
|
|
24
|
-
* @param doc - PDFKit document
|
|
25
|
-
* @param spotName - Name of the spot color
|
|
26
|
-
* @param spotColorDef - Spot color definition with CMYK fallback
|
|
27
|
-
* @returns Reference to the registered spot color
|
|
28
|
-
*/
|
|
29
|
-
export declare function registerSpotColor(doc: any, spotName: string, spotColorDef: SpotColorDefinition): {
|
|
30
|
-
name: string;
|
|
31
|
-
cmyk: number[];
|
|
32
|
-
};
|
|
33
|
-
/**
|
|
34
|
-
* Enable spot color support on a PDFDocument by intercepting color methods
|
|
35
|
-
* @param doc - PDFKit document
|
|
36
|
-
* @param spotColorConfig - Spot color configuration mapping
|
|
37
|
-
*/
|
|
38
|
-
export declare function enableSpotColorSupport(doc: any, spotColorConfig: SpotColorConfig): void;
|
package/lib/spot-colors.js
DELETED
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import { Util } from 'konva/lib/Util.js';
|
|
2
|
-
/**
|
|
3
|
-
* Normalize color to a consistent format for matching using Konva's color parser
|
|
4
|
-
* This ensures consistency with how Polotno/Konva handles colors
|
|
5
|
-
* @param color - Color in any format (string or [r, g, b, a] array)
|
|
6
|
-
* @returns Normalized color string in rgba format
|
|
7
|
-
*/
|
|
8
|
-
export function normalizeColor(color) {
|
|
9
|
-
if (!color) {
|
|
10
|
-
return null;
|
|
11
|
-
}
|
|
12
|
-
try {
|
|
13
|
-
// Handle array format [r, g, b, a]
|
|
14
|
-
if (Array.isArray(color)) {
|
|
15
|
-
const r = Math.round(color[0]);
|
|
16
|
-
const g = Math.round(color[1]);
|
|
17
|
-
const b = Math.round(color[2]);
|
|
18
|
-
const a = color[3] !== undefined ? color[3] : 1;
|
|
19
|
-
return `rgba(${r},${g},${b},${a})`;
|
|
20
|
-
}
|
|
21
|
-
// Handle string format
|
|
22
|
-
if (typeof color !== 'string') {
|
|
23
|
-
return null;
|
|
24
|
-
}
|
|
25
|
-
// Use Konva's colorToRGBA for consistent color parsing
|
|
26
|
-
const rgba = Util.colorToRGBA(color);
|
|
27
|
-
if (!rgba) {
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
// Konva returns {r, g, b, a} object
|
|
31
|
-
// Normalize to rgba string format
|
|
32
|
-
return `rgba(${rgba.r},${rgba.g},${rgba.b},${rgba.a})`;
|
|
33
|
-
}
|
|
34
|
-
catch (error) {
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Get spot color definition for a given color
|
|
40
|
-
* @param color - Color to check
|
|
41
|
-
* @param spotColorConfig - Spot color configuration
|
|
42
|
-
* @returns Spot color definition or null
|
|
43
|
-
*/
|
|
44
|
-
export function getSpotColorForColor(color, spotColorConfig) {
|
|
45
|
-
if (!spotColorConfig || !color) {
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
const normalizedColor = normalizeColor(color);
|
|
49
|
-
if (!normalizedColor) {
|
|
50
|
-
return null;
|
|
51
|
-
}
|
|
52
|
-
// Check direct match first
|
|
53
|
-
if (spotColorConfig[color]) {
|
|
54
|
-
return spotColorConfig[color];
|
|
55
|
-
}
|
|
56
|
-
// Check normalized match
|
|
57
|
-
if (spotColorConfig[normalizedColor]) {
|
|
58
|
-
return spotColorConfig[normalizedColor];
|
|
59
|
-
}
|
|
60
|
-
// Check all configured colors with normalization
|
|
61
|
-
for (const [configColor, definition] of Object.entries(spotColorConfig)) {
|
|
62
|
-
const normalizedConfigColor = normalizeColor(configColor);
|
|
63
|
-
if (normalizedConfigColor === normalizedColor) {
|
|
64
|
-
return definition;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
return null;
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Register a spot color using PDFKit's built-in addSpotColor method
|
|
71
|
-
* @param doc - PDFKit document
|
|
72
|
-
* @param spotName - Name of the spot color
|
|
73
|
-
* @param spotColorDef - Spot color definition with CMYK fallback
|
|
74
|
-
* @returns Reference to the registered spot color
|
|
75
|
-
*/
|
|
76
|
-
export function registerSpotColor(doc, spotName, spotColorDef) {
|
|
77
|
-
const { cmyk = [0, 0, 0, 1] } = spotColorDef;
|
|
78
|
-
// Convert CMYK from 0-1 range to 0-100 percentage range for PDFKit
|
|
79
|
-
const c = Math.max(0, Math.min(100, cmyk[0] * 100));
|
|
80
|
-
const m = Math.max(0, Math.min(100, cmyk[1] * 100));
|
|
81
|
-
const y = Math.max(0, Math.min(100, cmyk[2] * 100));
|
|
82
|
-
const k = Math.max(0, Math.min(100, cmyk[3] * 100));
|
|
83
|
-
// Sanitize spot color name for PDF (no spaces or special characters)
|
|
84
|
-
const sanitizedName = spotName.replace(/[^a-zA-Z0-9-_]/g, '_');
|
|
85
|
-
// Use PDFKit's built-in spot color support
|
|
86
|
-
doc.addSpotColor(sanitizedName, c, m, y, k);
|
|
87
|
-
return {
|
|
88
|
-
name: sanitizedName,
|
|
89
|
-
cmyk: [c / 100, m / 100, y / 100, k / 100], // Store in 0-1 range
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Enable spot color support on a PDFDocument by intercepting color methods
|
|
94
|
-
* @param doc - PDFKit document
|
|
95
|
-
* @param spotColorConfig - Spot color configuration mapping
|
|
96
|
-
*/
|
|
97
|
-
export function enableSpotColorSupport(doc, spotColorConfig) {
|
|
98
|
-
if (!spotColorConfig || Object.keys(spotColorConfig).length === 0) {
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
// Store configuration and registered spot colors on the document
|
|
102
|
-
doc._spotColors = new Map();
|
|
103
|
-
doc._spotColorConfig = spotColorConfig;
|
|
104
|
-
// Register all spot colors using PDFKit's built-in addSpotColor method
|
|
105
|
-
for (const [color, definition] of Object.entries(spotColorConfig)) {
|
|
106
|
-
const spotName = definition.name || `Spot_${color}`;
|
|
107
|
-
const registered = registerSpotColor(doc, spotName, definition);
|
|
108
|
-
// Cache the registered color definition
|
|
109
|
-
const normalizedColor = normalizeColor(color);
|
|
110
|
-
doc._spotColors.set(normalizedColor, registered);
|
|
111
|
-
doc._spotColors.set(color, registered); // Also store original format
|
|
112
|
-
}
|
|
113
|
-
// Intercept fillColor method to automatically use spot colors
|
|
114
|
-
const originalFillColor = doc.fillColor.bind(doc);
|
|
115
|
-
doc.fillColor = function (color, opacity) {
|
|
116
|
-
const spotColorDef = getSpotColorForColor(color, spotColorConfig);
|
|
117
|
-
if (spotColorDef) {
|
|
118
|
-
const normalizedColor = normalizeColor(color);
|
|
119
|
-
const registered = doc._spotColors.get(normalizedColor) || doc._spotColors.get(color);
|
|
120
|
-
if (registered) {
|
|
121
|
-
// Use PDFKit's fillColor with the spot color name directly
|
|
122
|
-
return originalFillColor(registered.name, opacity);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
return originalFillColor(color, opacity);
|
|
126
|
-
};
|
|
127
|
-
// Intercept strokeColor method to automatically use spot colors
|
|
128
|
-
const originalStrokeColor = doc.strokeColor.bind(doc);
|
|
129
|
-
doc.strokeColor = function (color, opacity) {
|
|
130
|
-
const spotColorDef = getSpotColorForColor(color, spotColorConfig);
|
|
131
|
-
if (spotColorDef) {
|
|
132
|
-
const normalizedColor = normalizeColor(color);
|
|
133
|
-
const registered = doc._spotColors.get(normalizedColor) || doc._spotColors.get(color);
|
|
134
|
-
if (registered) {
|
|
135
|
-
// Use PDFKit's strokeColor with the spot color name directly
|
|
136
|
-
return originalStrokeColor(registered.name, opacity);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
return originalStrokeColor(color, opacity);
|
|
140
|
-
};
|
|
141
|
-
}
|
package/lib/svg-render.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { ImageCache } from './utils.js';
|
|
2
|
-
export interface SVGElement {
|
|
3
|
-
src: string;
|
|
4
|
-
width: number;
|
|
5
|
-
height: number;
|
|
6
|
-
opacity: number;
|
|
7
|
-
colorsReplace: Record<string, string>;
|
|
8
|
-
}
|
|
9
|
-
export declare function renderSVG(doc: any, element: SVGElement, cache?: ImageCache | null): Promise<void>;
|
package/lib/svg-render.js
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import * as svg from './svg.js';
|
|
2
|
-
import { Util } from 'konva/lib/Util.js';
|
|
3
|
-
export async function renderSVG(doc, element, cache = null) {
|
|
4
|
-
const str = await svg.urlToString(element.src, cache);
|
|
5
|
-
const replaceEntries = Object.entries(element.colorsReplace || {});
|
|
6
|
-
doc.addSVG(str, 0, 0, {
|
|
7
|
-
// Use 'none' to allow stretching to exact dimensions, 'xMinYMin meet' to preserve aspect ratio
|
|
8
|
-
preserveAspectRatio: 'none',
|
|
9
|
-
width: element.width,
|
|
10
|
-
height: element.height,
|
|
11
|
-
opacity: element.opacity,
|
|
12
|
-
colorCallback: (colors) => {
|
|
13
|
-
if (!colors) {
|
|
14
|
-
return colors;
|
|
15
|
-
}
|
|
16
|
-
const [rgb, opacity] = colors;
|
|
17
|
-
let colorString = null;
|
|
18
|
-
if (Array.isArray(rgb) && rgb.length === 3) {
|
|
19
|
-
colorString = `rgb(${rgb[0]},${rgb[1]},${rgb[2]})`;
|
|
20
|
-
}
|
|
21
|
-
else if (typeof rgb === 'string') {
|
|
22
|
-
colorString = rgb;
|
|
23
|
-
}
|
|
24
|
-
let nextColorString = colorString;
|
|
25
|
-
if (replaceEntries.length && colorString) {
|
|
26
|
-
for (const [from, to] of replaceEntries) {
|
|
27
|
-
if (svg.sameColors(from, colorString)) {
|
|
28
|
-
nextColorString = to;
|
|
29
|
-
break;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
let nextColorArray = rgb;
|
|
34
|
-
let finalOpacity = opacity * element.opacity;
|
|
35
|
-
if (nextColorString != null) {
|
|
36
|
-
const rgbaObject = Util.colorToRGBA(nextColorString);
|
|
37
|
-
if (rgbaObject) {
|
|
38
|
-
nextColorArray = [
|
|
39
|
-
Math.round(rgbaObject.r),
|
|
40
|
-
Math.round(rgbaObject.g),
|
|
41
|
-
Math.round(rgbaObject.b),
|
|
42
|
-
];
|
|
43
|
-
// Handle alpha channel from the color string
|
|
44
|
-
if (rgbaObject.a !== undefined) {
|
|
45
|
-
finalOpacity = rgbaObject.a * opacity * element.opacity;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
if (!Array.isArray(nextColorArray) &&
|
|
50
|
-
typeof nextColorArray === 'string') {
|
|
51
|
-
const rgbObject = Util.getRGB(nextColorArray);
|
|
52
|
-
if (rgbObject) {
|
|
53
|
-
nextColorArray = [
|
|
54
|
-
Math.round(rgbObject.r),
|
|
55
|
-
Math.round(rgbObject.g),
|
|
56
|
-
Math.round(rgbObject.b),
|
|
57
|
-
];
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return [nextColorArray, finalOpacity];
|
|
61
|
-
},
|
|
62
|
-
});
|
|
63
|
-
}
|
package/lib/svg.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { ImageCache } from './utils.js';
|
|
2
|
-
export declare function urlToBase64(url: string, cache?: ImageCache | null): Promise<string>;
|
|
3
|
-
export declare function urlToString(url: string, cache?: ImageCache | null): Promise<string>;
|
|
4
|
-
export declare function getColors(svgString: string): string[];
|
|
5
|
-
export declare function svgToURL(s: string): string;
|
|
6
|
-
export declare function getSvgSize(url: string): Promise<{
|
|
7
|
-
width: number;
|
|
8
|
-
height: number;
|
|
9
|
-
}>;
|
|
10
|
-
export declare function fixSize(svgString: string): string;
|
|
11
|
-
export declare const sameColors: (color1: any, color2: any) => boolean;
|
|
12
|
-
export declare function replaceColors(svgString: string, replaceMap: Map<string, string>): string;
|
package/lib/svg.js
DELETED
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
import { Util } from 'konva/lib/Util.js';
|
|
2
|
-
import { DOMParser, XMLSerializer } from 'xmldom';
|
|
3
|
-
import { fetchWithTimeout } from './utils.js';
|
|
4
|
-
function isInsideDef(element) {
|
|
5
|
-
while (element.parentNode) {
|
|
6
|
-
if (element.nodeName === 'defs') {
|
|
7
|
-
return true;
|
|
8
|
-
}
|
|
9
|
-
element = element.parentNode;
|
|
10
|
-
}
|
|
11
|
-
return false;
|
|
12
|
-
}
|
|
13
|
-
function parseStyleAttribute(style) {
|
|
14
|
-
if (!style) {
|
|
15
|
-
return {};
|
|
16
|
-
}
|
|
17
|
-
const styles = style.split(';');
|
|
18
|
-
const result = {};
|
|
19
|
-
styles.forEach((style) => {
|
|
20
|
-
const [key, value] = style.split(':');
|
|
21
|
-
if (key && value) {
|
|
22
|
-
result[key] = value;
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
return result;
|
|
26
|
-
}
|
|
27
|
-
function buildStyleAttribute(styleObject) {
|
|
28
|
-
return Object.keys(styleObject)
|
|
29
|
-
.map((key) => `${key}:${styleObject[key]}`)
|
|
30
|
-
.join(';');
|
|
31
|
-
}
|
|
32
|
-
function getElementColors(e) {
|
|
33
|
-
const style = parseStyleAttribute(e.getAttribute('style'));
|
|
34
|
-
const colors = {
|
|
35
|
-
fill: '',
|
|
36
|
-
stroke: '',
|
|
37
|
-
};
|
|
38
|
-
if (e.getAttribute('fill') && e.getAttribute('fill') !== 'none') {
|
|
39
|
-
colors.fill = e.getAttribute('fill');
|
|
40
|
-
}
|
|
41
|
-
if (!colors.fill && style && style.fill && style.fill !== 'none') {
|
|
42
|
-
colors.fill = style.fill;
|
|
43
|
-
}
|
|
44
|
-
if (e.getAttribute('stroke')) {
|
|
45
|
-
colors.stroke = e.getAttribute('stroke');
|
|
46
|
-
}
|
|
47
|
-
if (!colors.stroke && style && style.stroke) {
|
|
48
|
-
colors.stroke = style.stroke;
|
|
49
|
-
}
|
|
50
|
-
if (!colors.stroke && !colors.fill) {
|
|
51
|
-
colors.fill = 'black';
|
|
52
|
-
}
|
|
53
|
-
return colors;
|
|
54
|
-
}
|
|
55
|
-
const SVG_SHAPES = ['path', 'rect', 'circle'];
|
|
56
|
-
function getAllElementsWithColor(doc) {
|
|
57
|
-
var matchingElements = [];
|
|
58
|
-
var allElements = doc.getElementsByTagName('*');
|
|
59
|
-
for (var i = 0, n = allElements.length; i < n; i++) {
|
|
60
|
-
const element = allElements[i];
|
|
61
|
-
if (isInsideDef(element)) {
|
|
62
|
-
continue;
|
|
63
|
-
}
|
|
64
|
-
if (element.getAttribute('fill') !== null) {
|
|
65
|
-
matchingElements.push(element);
|
|
66
|
-
}
|
|
67
|
-
const style = element.getAttribute('style');
|
|
68
|
-
if (style != null && style.indexOf('fill') >= 0) {
|
|
69
|
-
matchingElements.push(element);
|
|
70
|
-
}
|
|
71
|
-
if (element.getAttribute('stroke') !== null) {
|
|
72
|
-
matchingElements.push(element);
|
|
73
|
-
}
|
|
74
|
-
else if (element.style && element.style['fill']) {
|
|
75
|
-
matchingElements.push(element);
|
|
76
|
-
}
|
|
77
|
-
else if (SVG_SHAPES.indexOf(element.nodeName) >= 0) {
|
|
78
|
-
matchingElements.push(element);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return matchingElements;
|
|
82
|
-
}
|
|
83
|
-
export async function urlToBase64(url, cache = null) {
|
|
84
|
-
// Check cache first
|
|
85
|
-
if (cache && cache.buffers.has(url)) {
|
|
86
|
-
return cache.buffers.get(url);
|
|
87
|
-
}
|
|
88
|
-
const req = await fetchWithTimeout(url);
|
|
89
|
-
let result;
|
|
90
|
-
if (req.arrayBuffer) {
|
|
91
|
-
const buffer = Buffer.from(await req.arrayBuffer());
|
|
92
|
-
result = `data:image/svg+xml;base64,${buffer.toString('base64')}`;
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
95
|
-
const svgString = await req.text();
|
|
96
|
-
result = svgToURL(svgString);
|
|
97
|
-
}
|
|
98
|
-
// Store in cache
|
|
99
|
-
if (cache) {
|
|
100
|
-
cache.buffers.set(url, result);
|
|
101
|
-
}
|
|
102
|
-
return result;
|
|
103
|
-
}
|
|
104
|
-
export async function urlToString(url, cache = null) {
|
|
105
|
-
// Check cache first
|
|
106
|
-
if (cache && cache.buffers.has(url)) {
|
|
107
|
-
const cached = cache.buffers.get(url);
|
|
108
|
-
// If cached value is a base64 data URL, decode it
|
|
109
|
-
if (cached.startsWith('data:')) {
|
|
110
|
-
return Buffer.from(cached.split('base64,')[1], 'base64').toString();
|
|
111
|
-
}
|
|
112
|
-
return cached;
|
|
113
|
-
}
|
|
114
|
-
let svgString;
|
|
115
|
-
if (url.startsWith('data:')) {
|
|
116
|
-
svgString = Buffer.from(url.split('base64,')[1], 'base64').toString();
|
|
117
|
-
}
|
|
118
|
-
else {
|
|
119
|
-
const req = await fetchWithTimeout(url);
|
|
120
|
-
svgString = await req.text();
|
|
121
|
-
}
|
|
122
|
-
// Store in cache
|
|
123
|
-
if (cache) {
|
|
124
|
-
cache.buffers.set(url, svgString);
|
|
125
|
-
}
|
|
126
|
-
return svgString;
|
|
127
|
-
}
|
|
128
|
-
export function getColors(svgString) {
|
|
129
|
-
var parser = new DOMParser();
|
|
130
|
-
var doc = parser.parseFromString(svgString, 'text/xml');
|
|
131
|
-
const elements = getAllElementsWithColor(doc);
|
|
132
|
-
const colors = [];
|
|
133
|
-
elements.forEach((e) => {
|
|
134
|
-
const { fill, stroke } = getElementColors(e);
|
|
135
|
-
const results = [fill, stroke];
|
|
136
|
-
results.forEach((color) => {
|
|
137
|
-
if (!color) {
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
const rgba = Util.colorToRGBA(color);
|
|
141
|
-
if (!rgba) {
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
if (colors.indexOf(color) === -1) {
|
|
145
|
-
colors.push(color);
|
|
146
|
-
}
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
return colors;
|
|
150
|
-
}
|
|
151
|
-
export function svgToURL(s) {
|
|
152
|
-
const uri = Buffer.from(unescape(encodeURIComponent(s))).toString('base64');
|
|
153
|
-
return 'data:image/svg+xml;base64,' + uri;
|
|
154
|
-
}
|
|
155
|
-
export async function getSvgSize(url) {
|
|
156
|
-
const svgString = await urlToString(url);
|
|
157
|
-
var parser = new DOMParser();
|
|
158
|
-
var doc = parser.parseFromString(svgString, 'image/svg+xml');
|
|
159
|
-
const viewBox = doc.documentElement.getAttribute('viewBox');
|
|
160
|
-
const [x, y, width, height] = viewBox?.split(' ') || [];
|
|
161
|
-
return { width: parseFloat(width), height: parseFloat(height) };
|
|
162
|
-
}
|
|
163
|
-
export function fixSize(svgString) {
|
|
164
|
-
var parser = new DOMParser();
|
|
165
|
-
var doc = parser.parseFromString(svgString, 'image/svg+xml');
|
|
166
|
-
const viewBox = doc.documentElement.getAttribute('viewBox');
|
|
167
|
-
const [x, y, width, height] = viewBox?.split(' ') || [];
|
|
168
|
-
if (!doc.documentElement.getAttribute('width')) {
|
|
169
|
-
doc.documentElement.setAttribute('width', width + 'px');
|
|
170
|
-
}
|
|
171
|
-
if (!doc.documentElement.getAttribute('height')) {
|
|
172
|
-
doc.documentElement.setAttribute('height', height + 'px');
|
|
173
|
-
}
|
|
174
|
-
var xmlSerializer = new XMLSerializer();
|
|
175
|
-
const str = xmlSerializer.serializeToString(doc);
|
|
176
|
-
return str;
|
|
177
|
-
}
|
|
178
|
-
export const sameColors = (color1, color2) => {
|
|
179
|
-
if (!color1 || !color2) {
|
|
180
|
-
return false;
|
|
181
|
-
}
|
|
182
|
-
if (color2 === 'currentColor' && color1 === 'black') {
|
|
183
|
-
return true;
|
|
184
|
-
}
|
|
185
|
-
const c1 = Util.colorToRGBA(color1);
|
|
186
|
-
const c2 = Util.colorToRGBA(color2);
|
|
187
|
-
if (!c1 || !c2) {
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
return c1.r === c2.r && c1.g === c2.g && c1.b === c2.b && c1.a === c2.a;
|
|
191
|
-
};
|
|
192
|
-
export function replaceColors(svgString, replaceMap) {
|
|
193
|
-
var parser = new DOMParser();
|
|
194
|
-
var doc = parser.parseFromString(svgString, 'text/xml');
|
|
195
|
-
const elements = getAllElementsWithColor(doc);
|
|
196
|
-
const oldColors = Array.from(replaceMap.keys());
|
|
197
|
-
elements.forEach((el) => {
|
|
198
|
-
const { fill, stroke } = getElementColors(el);
|
|
199
|
-
const colors = [
|
|
200
|
-
{ prop: 'fill', color: fill },
|
|
201
|
-
{ prop: 'stroke', color: stroke },
|
|
202
|
-
];
|
|
203
|
-
colors.forEach(({ prop, color }) => {
|
|
204
|
-
// find matched oldColor
|
|
205
|
-
const marchedOldValue = oldColors.find((oldColor) => {
|
|
206
|
-
return sameColors(oldColor, color);
|
|
207
|
-
});
|
|
208
|
-
if (!marchedOldValue) {
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
else {
|
|
212
|
-
el.setAttribute(prop, replaceMap.get(marchedOldValue));
|
|
213
|
-
const style = parseStyleAttribute(el.getAttribute('style'));
|
|
214
|
-
if (style && style[prop]) {
|
|
215
|
-
style[prop] = replaceMap.get(marchedOldValue);
|
|
216
|
-
el.setAttribute('style', buildStyleAttribute(style));
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
});
|
|
220
|
-
});
|
|
221
|
-
var xmlSerializer = new XMLSerializer();
|
|
222
|
-
const str = xmlSerializer.serializeToString(doc);
|
|
223
|
-
return svgToURL(str);
|
|
224
|
-
}
|
package/lib/text/fonts.d.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { TextElement, TextSegment } from './types.js';
|
|
2
|
-
export declare function registerFontUrl(fontFamily: string, url: string): void;
|
|
3
|
-
/**
|
|
4
|
-
* Get font weight string based on bold/italic state
|
|
5
|
-
*/
|
|
6
|
-
export declare function getFontWeight(bold: boolean, italic: boolean, baseFontWeight?: string): string;
|
|
7
|
-
/**
|
|
8
|
-
* Get font key for caching
|
|
9
|
-
*/
|
|
10
|
-
export declare function getFontKey(fontFamily: string, bold: boolean, italic: boolean, baseFontWeight?: string): string;
|
|
11
|
-
export declare function getGoogleFontPath(fontFamily: string, fontWeight?: string, italic?: boolean): Promise<string>;
|
|
12
|
-
/**
|
|
13
|
-
* Load font for a text element or segment
|
|
14
|
-
*/
|
|
15
|
-
export declare function loadFontForSegment(doc: any, segment: TextSegment | null, element: TextElement, fonts: Record<string, boolean>): Promise<string>;
|
|
16
|
-
export declare function loadFontIfNeeded(doc: any, element: TextElement, fonts: Record<string, boolean>): Promise<string>;
|