svg-toolbox 1.1.11 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +156 -118
- package/es/analyze/__tests__/colors.test.d.ts +1 -0
- package/es/analyze/__tests__/colors.test.js +44 -0
- package/es/analyze/__tests__/colors.test.js.map +1 -0
- package/es/analyze/__tests__/paths.test.d.ts +1 -0
- package/es/analyze/__tests__/paths.test.js +71 -0
- package/es/analyze/__tests__/paths.test.js.map +1 -0
- package/es/analyze/colors.d.ts +8 -0
- package/es/analyze/colors.js +55 -0
- package/es/analyze/colors.js.map +1 -0
- package/es/analyze/paths.d.ts +20 -0
- package/es/analyze/paths.js +92 -0
- package/es/analyze/paths.js.map +1 -0
- package/es/compare/__tests__/diff.test.d.ts +1 -0
- package/es/compare/__tests__/diff.test.js +64 -0
- package/es/compare/__tests__/diff.test.js.map +1 -0
- package/es/compare/diff.d.ts +18 -0
- package/es/compare/diff.js +70 -0
- package/es/compare/diff.js.map +1 -0
- package/es/convert/__tests__/base64.test.d.ts +1 -0
- package/es/convert/__tests__/base64.test.js +49 -0
- package/es/convert/__tests__/base64.test.js.map +1 -0
- package/es/convert/base64.d.ts +11 -0
- package/es/convert/base64.js +38 -0
- package/es/convert/base64.js.map +1 -0
- package/es/convert/image.d.ts +18 -0
- package/es/convert/image.js +63 -0
- package/es/convert/image.js.map +1 -0
- package/es/core/__tests__/dimensions.test.d.ts +1 -0
- package/es/core/__tests__/dimensions.test.js +40 -0
- package/es/core/__tests__/dimensions.test.js.map +1 -0
- package/es/core/__tests__/element.test.d.ts +1 -0
- package/es/core/__tests__/element.test.js +79 -0
- package/es/core/__tests__/element.test.js.map +1 -0
- package/es/core/dimensions.d.ts +8 -0
- package/es/core/dimensions.js +34 -0
- package/es/core/dimensions.js.map +1 -0
- package/es/core/element.d.ts +24 -0
- package/es/core/element.js +52 -0
- package/es/core/element.js.map +1 -0
- package/es/index.d.ts +15 -10
- package/es/index.js +21 -10
- package/es/index.js.map +1 -1
- package/es/optimize/__tests__/cleanup.test.d.ts +1 -0
- package/es/optimize/__tests__/cleanup.test.js +95 -0
- package/es/optimize/__tests__/cleanup.test.js.map +1 -0
- package/es/optimize/__tests__/path.test.d.ts +1 -0
- package/es/optimize/__tests__/path.test.js +41 -0
- package/es/optimize/__tests__/path.test.js.map +1 -0
- package/es/optimize/cleanup.d.ts +27 -0
- package/es/optimize/cleanup.js +100 -0
- package/es/optimize/cleanup.js.map +1 -0
- package/es/optimize/path.d.ts +7 -0
- package/es/optimize/path.js +58 -0
- package/es/optimize/path.js.map +1 -0
- package/es/types/index.d.ts +31 -0
- package/es/types/index.js +5 -0
- package/es/types/index.js.map +1 -0
- package/es/utils/__tests__/path-validation.test.d.ts +1 -0
- package/es/utils/__tests__/path-validation.test.js +64 -0
- package/es/utils/__tests__/path-validation.test.js.map +1 -0
- package/es/utils/__tests__/validation.test.d.ts +1 -0
- package/es/utils/__tests__/validation.test.js +42 -0
- package/es/utils/__tests__/validation.test.js.map +1 -0
- package/es/utils/dom.d.ts +23 -0
- package/es/utils/dom.js +25 -0
- package/es/utils/dom.js.map +1 -0
- package/es/utils/path-validation.d.ts +29 -0
- package/es/utils/path-validation.js +101 -0
- package/es/utils/path-validation.js.map +1 -0
- package/es/utils/validation.d.ts +11 -0
- package/es/utils/validation.js +30 -0
- package/es/utils/validation.js.map +1 -0
- package/lib/analyze/__tests__/colors.test.d.ts +1 -0
- package/lib/analyze/__tests__/colors.test.js +46 -0
- package/lib/analyze/__tests__/colors.test.js.map +1 -0
- package/lib/analyze/__tests__/paths.test.d.ts +1 -0
- package/lib/analyze/__tests__/paths.test.js +73 -0
- package/lib/analyze/__tests__/paths.test.js.map +1 -0
- package/lib/analyze/colors.d.ts +8 -0
- package/lib/analyze/colors.js +58 -0
- package/lib/analyze/colors.js.map +1 -0
- package/lib/analyze/paths.d.ts +20 -0
- package/lib/analyze/paths.js +97 -0
- package/lib/analyze/paths.js.map +1 -0
- package/lib/compare/__tests__/diff.test.d.ts +1 -0
- package/lib/compare/__tests__/diff.test.js +128 -0
- package/lib/compare/__tests__/diff.test.js.map +1 -0
- package/lib/compare/diff.d.ts +18 -0
- package/lib/compare/diff.js +134 -0
- package/lib/compare/diff.js.map +1 -0
- package/lib/convert/__tests__/base64.test.d.ts +1 -0
- package/lib/convert/__tests__/base64.test.js +51 -0
- package/lib/convert/__tests__/base64.test.js.map +1 -0
- package/lib/convert/base64.d.ts +11 -0
- package/lib/convert/base64.js +42 -0
- package/lib/convert/base64.js.map +1 -0
- package/lib/convert/image.d.ts +18 -0
- package/lib/{extra-apply/applySvg2Png.js → convert/image.js} +62 -53
- package/lib/convert/image.js.map +1 -0
- package/lib/core/__tests__/dimensions.test.d.ts +1 -0
- package/lib/core/__tests__/dimensions.test.js +42 -0
- package/lib/core/__tests__/dimensions.test.js.map +1 -0
- package/lib/core/__tests__/element.test.d.ts +1 -0
- package/lib/core/__tests__/element.test.js +81 -0
- package/lib/core/__tests__/element.test.js.map +1 -0
- package/lib/core/dimensions.d.ts +8 -0
- package/lib/core/dimensions.js +37 -0
- package/lib/core/dimensions.js.map +1 -0
- package/lib/core/element.d.ts +24 -0
- package/lib/core/element.js +58 -0
- package/lib/core/element.js.map +1 -0
- package/lib/index.d.ts +15 -10
- package/lib/index.js +48 -20
- package/lib/index.js.map +1 -1
- package/lib/optimize/__tests__/cleanup.test.d.ts +1 -0
- package/lib/optimize/__tests__/cleanup.test.js +97 -0
- package/lib/optimize/__tests__/cleanup.test.js.map +1 -0
- package/lib/optimize/__tests__/path.test.d.ts +1 -0
- package/lib/optimize/__tests__/path.test.js +43 -0
- package/lib/optimize/__tests__/path.test.js.map +1 -0
- package/lib/optimize/cleanup.d.ts +27 -0
- package/lib/optimize/cleanup.js +106 -0
- package/lib/optimize/cleanup.js.map +1 -0
- package/lib/optimize/path.d.ts +7 -0
- package/lib/optimize/path.js +63 -0
- package/lib/optimize/path.js.map +1 -0
- package/lib/types/index.d.ts +31 -0
- package/lib/types/index.js +6 -0
- package/lib/types/index.js.map +1 -0
- package/lib/utils/__tests__/path-validation.test.d.ts +1 -0
- package/lib/utils/__tests__/path-validation.test.js +69 -0
- package/lib/utils/__tests__/path-validation.test.js.map +1 -0
- package/lib/utils/__tests__/validation.test.d.ts +1 -0
- package/lib/utils/__tests__/validation.test.js +44 -0
- package/lib/utils/__tests__/validation.test.js.map +1 -0
- package/lib/utils/dom.d.ts +23 -0
- package/lib/utils/dom.js +31 -0
- package/lib/utils/dom.js.map +1 -0
- package/lib/utils/path-validation.d.ts +29 -0
- package/lib/utils/path-validation.js +109 -0
- package/lib/utils/path-validation.js.map +1 -0
- package/lib/utils/validation.d.ts +11 -0
- package/lib/utils/validation.js +35 -0
- package/lib/utils/validation.js.map +1 -0
- package/package.json +17 -4
- package/es/common.d.ts +0 -68
- package/es/common.js +0 -110
- package/es/common.js.map +0 -1
- package/es/extra-apply/applyDiffSvg.d.ts +0 -11
- package/es/extra-apply/applyDiffSvg.js +0 -63
- package/es/extra-apply/applyDiffSvg.js.map +0 -1
- package/es/extra-apply/applyRemoveNanCoordinates.d.ts +0 -6
- package/es/extra-apply/applyRemoveNanCoordinates.js +0 -75
- package/es/extra-apply/applyRemoveNanCoordinates.js.map +0 -1
- package/es/extra-apply/applySvg2Png.d.ts +0 -16
- package/es/extra-apply/applySvg2Png.js +0 -64
- package/es/extra-apply/applySvg2Png.js.map +0 -1
- package/es/utils/pixelLevelDiffPng.d.ts +0 -4
- package/es/utils/pixelLevelDiffPng.js +0 -29
- package/es/utils/pixelLevelDiffPng.js.map +0 -1
- package/es/validate.d.ts +0 -14
- package/es/validate.js +0 -44
- package/es/validate.js.map +0 -1
- package/lib/common.d.ts +0 -68
- package/lib/common.js +0 -117
- package/lib/common.js.map +0 -1
- package/lib/extra-apply/applyDiffSvg.d.ts +0 -11
- package/lib/extra-apply/applyDiffSvg.js +0 -116
- package/lib/extra-apply/applyDiffSvg.js.map +0 -1
- package/lib/extra-apply/applyRemoveNanCoordinates.d.ts +0 -6
- package/lib/extra-apply/applyRemoveNanCoordinates.js +0 -78
- package/lib/extra-apply/applyRemoveNanCoordinates.js.map +0 -1
- package/lib/extra-apply/applySvg2Png.d.ts +0 -16
- package/lib/extra-apply/applySvg2Png.js.map +0 -1
- package/lib/utils/pixelLevelDiffPng.d.ts +0 -4
- package/lib/utils/pixelLevelDiffPng.js +0 -36
- package/lib/utils/pixelLevelDiffPng.js.map +0 -1
- package/lib/validate.d.ts +0 -14
- package/lib/validate.js +0 -48
- package/lib/validate.js.map +0 -1
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* SVG path analysis utilities
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.parsePathData = parsePathData;
|
|
7
|
+
exports.analyzePaths = analyzePaths;
|
|
8
|
+
exports.getPathStatistics = getPathStatistics;
|
|
9
|
+
var jsdom_1 = require("jsdom");
|
|
10
|
+
var element_1 = require("../core/element");
|
|
11
|
+
var validation_1 = require("../utils/validation");
|
|
12
|
+
/**
|
|
13
|
+
* Maximum allowed path data length to prevent ReDoS attacks
|
|
14
|
+
*/
|
|
15
|
+
var MAX_PATH_DATA_LENGTH = 100000; // 100KB should be sufficient for most SVG paths
|
|
16
|
+
/**
|
|
17
|
+
* Parses the 'd' attribute of a path element into command objects
|
|
18
|
+
*/
|
|
19
|
+
function parsePathData(pathData) {
|
|
20
|
+
// Validate input length to prevent ReDoS attacks
|
|
21
|
+
if (pathData.length > MAX_PATH_DATA_LENGTH) {
|
|
22
|
+
throw new Error("Path data length exceeds maximum allowed length of ".concat(MAX_PATH_DATA_LENGTH, " characters"));
|
|
23
|
+
}
|
|
24
|
+
var commands = [];
|
|
25
|
+
// Split by path commands (M, L, H, V, C, S, Q, T, A, Z)
|
|
26
|
+
var commandRegex = /([MmLlHhVvCcSsQqTtAaZz])((?:\s*-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?\s*,?\s*)*)/g;
|
|
27
|
+
var match;
|
|
28
|
+
var iterations = 0;
|
|
29
|
+
var MAX_ITERATIONS = 10000; // Prevent infinite loops
|
|
30
|
+
while ((match = commandRegex.exec(pathData)) !== null) {
|
|
31
|
+
iterations++;
|
|
32
|
+
if (iterations > MAX_ITERATIONS) {
|
|
33
|
+
throw new Error('Path parsing exceeded maximum iterations. Path data may be malformed.');
|
|
34
|
+
}
|
|
35
|
+
var type = match[1];
|
|
36
|
+
var paramsStr = match[2].trim();
|
|
37
|
+
if (type.toLowerCase() === 'z') {
|
|
38
|
+
commands.push({ type: type, params: [] });
|
|
39
|
+
}
|
|
40
|
+
else if (paramsStr) {
|
|
41
|
+
var params = paramsStr
|
|
42
|
+
.split(/[\s,]+/)
|
|
43
|
+
.filter(function (p) { return p.trim() !== ''; })
|
|
44
|
+
.map(Number)
|
|
45
|
+
.filter(function (n) { return !isNaN(n); });
|
|
46
|
+
commands.push({ type: type, params: params });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return commands;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Analyzes all paths in an SVG and returns their command structures
|
|
53
|
+
*/
|
|
54
|
+
function analyzePaths(svgContent) {
|
|
55
|
+
var svgString = (0, validation_1.isValidSvgString)(svgContent)
|
|
56
|
+
? svgContent
|
|
57
|
+
: (0, element_1.serializeSVG)(svgContent);
|
|
58
|
+
var dom = new jsdom_1.JSDOM(svgString, {
|
|
59
|
+
contentType: 'image/svg+xml'
|
|
60
|
+
});
|
|
61
|
+
var document = dom.window.document;
|
|
62
|
+
var svgElement = document.querySelector('svg');
|
|
63
|
+
if (!svgElement) {
|
|
64
|
+
throw new Error('No SVG element found in the provided content.');
|
|
65
|
+
}
|
|
66
|
+
var paths = svgElement.querySelectorAll('path');
|
|
67
|
+
var pathAnalysis = new Map();
|
|
68
|
+
Array.from(paths).forEach(function (path, index) {
|
|
69
|
+
var d = path.getAttribute('d');
|
|
70
|
+
if (d) {
|
|
71
|
+
var id = path.getAttribute('id') || "path-".concat(index);
|
|
72
|
+
pathAnalysis.set(id, parsePathData(d));
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
return pathAnalysis;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Gets statistics about paths in an SVG
|
|
79
|
+
*/
|
|
80
|
+
function getPathStatistics(svgContent) {
|
|
81
|
+
var pathAnalysis = analyzePaths(svgContent);
|
|
82
|
+
var totalCommands = 0;
|
|
83
|
+
var commandTypes = {};
|
|
84
|
+
pathAnalysis.forEach(function (commands) {
|
|
85
|
+
totalCommands += commands.length;
|
|
86
|
+
commands.forEach(function (cmd) {
|
|
87
|
+
var type = cmd.type.toUpperCase();
|
|
88
|
+
commandTypes[type] = (commandTypes[type] || 0) + 1;
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
return {
|
|
92
|
+
totalPaths: pathAnalysis.size,
|
|
93
|
+
totalCommands: totalCommands,
|
|
94
|
+
commandTypes: commandTypes
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/analyze/paths.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
39
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
|
+
};
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
var diff_1 = require("../diff");
|
|
43
|
+
var fs_1 = __importDefault(require("fs"));
|
|
44
|
+
var path_1 = __importDefault(require("path"));
|
|
45
|
+
describe('Image Diff', function () {
|
|
46
|
+
var fixturesDir = path_1.default.join(__dirname, '../../../test-fixtures');
|
|
47
|
+
var test1Path = path_1.default.join(fixturesDir, 'test1.svg');
|
|
48
|
+
var test2Path = path_1.default.join(fixturesDir, 'test2.svg');
|
|
49
|
+
var outputDir = path_1.default.join(fixturesDir, 'diff-output');
|
|
50
|
+
var diffImagePath = path_1.default.join(outputDir, 'diff-test1-test2.png');
|
|
51
|
+
beforeAll(function () {
|
|
52
|
+
// Ensure output directory exists
|
|
53
|
+
if (!fs_1.default.existsSync(outputDir)) {
|
|
54
|
+
fs_1.default.mkdirSync(outputDir, { recursive: true });
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
afterAll(function () {
|
|
58
|
+
// Clean up: optionally remove the diff image after tests
|
|
59
|
+
// Uncomment the following line if you want to clean up after tests
|
|
60
|
+
// if (fs.existsSync(diffImagePath)) {
|
|
61
|
+
// fs.unlinkSync(diffImagePath);
|
|
62
|
+
// }
|
|
63
|
+
});
|
|
64
|
+
it('should generate diff image between two similar but different SVGs', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
65
|
+
var result, savedFile;
|
|
66
|
+
return __generator(this, function (_a) {
|
|
67
|
+
switch (_a.label) {
|
|
68
|
+
case 0:
|
|
69
|
+
// Verify test fixtures exist
|
|
70
|
+
expect(fs_1.default.existsSync(test1Path)).toBe(true);
|
|
71
|
+
expect(fs_1.default.existsSync(test2Path)).toBe(true);
|
|
72
|
+
return [4 /*yield*/, (0, diff_1.diffImages)(test1Path, test2Path, diffImagePath, 0.1)];
|
|
73
|
+
case 1:
|
|
74
|
+
result = _a.sent();
|
|
75
|
+
// Verify diff image was created
|
|
76
|
+
expect(fs_1.default.existsSync(diffImagePath)).toBe(true);
|
|
77
|
+
// Verify result contains expected properties
|
|
78
|
+
expect(result).toHaveProperty('diffPngBuffer');
|
|
79
|
+
expect(result).toHaveProperty('numDiffPixels');
|
|
80
|
+
expect(result.diffPngBuffer).toBeInstanceOf(Buffer);
|
|
81
|
+
expect(typeof result.numDiffPixels).toBe('number');
|
|
82
|
+
// Since the SVGs are different, there should be some differences
|
|
83
|
+
expect(result.numDiffPixels).toBeGreaterThan(0);
|
|
84
|
+
savedFile = fs_1.default.readFileSync(diffImagePath);
|
|
85
|
+
expect(savedFile.equals(result.diffPngBuffer)).toBe(true);
|
|
86
|
+
// Verify file size is reasonable (not empty)
|
|
87
|
+
expect(savedFile.length).toBeGreaterThan(0);
|
|
88
|
+
console.log("Diff image saved to: ".concat(diffImagePath));
|
|
89
|
+
console.log("Number of different pixels: ".concat(result.numDiffPixels));
|
|
90
|
+
return [2 /*return*/];
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}); });
|
|
94
|
+
it('should handle identical SVGs (no differences)', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
95
|
+
var identicalDiffPath, result;
|
|
96
|
+
return __generator(this, function (_a) {
|
|
97
|
+
switch (_a.label) {
|
|
98
|
+
case 0:
|
|
99
|
+
identicalDiffPath = path_1.default.join(outputDir, 'diff-identical.png');
|
|
100
|
+
return [4 /*yield*/, (0, diff_1.diffImages)(test1Path, test1Path, identicalDiffPath, 0.1)];
|
|
101
|
+
case 1:
|
|
102
|
+
result = _a.sent();
|
|
103
|
+
// Should have no differences
|
|
104
|
+
expect(result.numDiffPixels).toBe(0);
|
|
105
|
+
expect(fs_1.default.existsSync(identicalDiffPath)).toBe(true);
|
|
106
|
+
console.log("Identical comparison diff saved to: ".concat(identicalDiffPath));
|
|
107
|
+
console.log("Number of different pixels: ".concat(result.numDiffPixels));
|
|
108
|
+
return [2 /*return*/];
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}); });
|
|
112
|
+
it('should generate diff without saving to file', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
113
|
+
var result;
|
|
114
|
+
return __generator(this, function (_a) {
|
|
115
|
+
switch (_a.label) {
|
|
116
|
+
case 0: return [4 /*yield*/, (0, diff_1.diffImages)(test1Path, test2Path, undefined, 0.1)];
|
|
117
|
+
case 1:
|
|
118
|
+
result = _a.sent();
|
|
119
|
+
// Should still return result even without file path
|
|
120
|
+
expect(result).toHaveProperty('diffPngBuffer');
|
|
121
|
+
expect(result).toHaveProperty('numDiffPixels');
|
|
122
|
+
expect(result.numDiffPixels).toBeGreaterThan(0);
|
|
123
|
+
return [2 /*return*/];
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}); });
|
|
127
|
+
});
|
|
128
|
+
//# sourceMappingURL=diff.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.test.js","sourceRoot":"","sources":["../../../src/compare/__tests__/diff.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image comparison and diff utilities
|
|
3
|
+
*/
|
|
4
|
+
import { DiffResult } from '../types';
|
|
5
|
+
/**
|
|
6
|
+
* Compares two PNG images at the pixel level and generates a diff image
|
|
7
|
+
*/
|
|
8
|
+
export declare function pixelLevelDiff(pngA: Buffer, pngB: Buffer, threshold?: number): DiffResult;
|
|
9
|
+
/**
|
|
10
|
+
* Compares two image files (SVG or PNG) and generates a diff image
|
|
11
|
+
*/
|
|
12
|
+
export declare function diffImages(pathA: string, pathB: string, diffFilePath?: string, threshold?: number): Promise<DiffResult>;
|
|
13
|
+
/**
|
|
14
|
+
* Legacy function name for diffImages
|
|
15
|
+
*
|
|
16
|
+
* @deprecated Use diffImages instead
|
|
17
|
+
*/
|
|
18
|
+
export declare function diffSvg(pathA: string, pathB: string, diffFilePath: string): Promise<DiffResult | void>;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Image comparison and diff utilities
|
|
4
|
+
*/
|
|
5
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
6
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
7
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
8
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
9
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
10
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
11
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
12
|
+
});
|
|
13
|
+
};
|
|
14
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
15
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
16
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
17
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
18
|
+
function step(op) {
|
|
19
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
20
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
21
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
22
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
23
|
+
switch (op[0]) {
|
|
24
|
+
case 0: case 1: t = op; break;
|
|
25
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
26
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
27
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
28
|
+
default:
|
|
29
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
30
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
31
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
32
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
33
|
+
if (t[2]) _.ops.pop();
|
|
34
|
+
_.trys.pop(); continue;
|
|
35
|
+
}
|
|
36
|
+
op = body.call(thisArg, _);
|
|
37
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
38
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
42
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
43
|
+
};
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.pixelLevelDiff = pixelLevelDiff;
|
|
46
|
+
exports.diffImages = diffImages;
|
|
47
|
+
exports.diffSvg = diffSvg;
|
|
48
|
+
var fs_1 = __importDefault(require("fs"));
|
|
49
|
+
var path_1 = __importDefault(require("path"));
|
|
50
|
+
var sharp_1 = __importDefault(require("sharp"));
|
|
51
|
+
var pngjs_1 = require("pngjs");
|
|
52
|
+
var pixelmatch_1 = __importDefault(require("pixelmatch"));
|
|
53
|
+
var path_validation_1 = require("../utils/path-validation");
|
|
54
|
+
/**
|
|
55
|
+
* Compares two PNG images at the pixel level and generates a diff image
|
|
56
|
+
*/
|
|
57
|
+
function pixelLevelDiff(pngA, pngB, threshold) {
|
|
58
|
+
if (threshold === void 0) { threshold = 0.1; }
|
|
59
|
+
var img1 = pngjs_1.PNG.sync.read(pngA);
|
|
60
|
+
var img2 = pngjs_1.PNG.sync.read(pngB);
|
|
61
|
+
var width = img1.width, height = img1.height;
|
|
62
|
+
if (img2.width !== width || img2.height !== height) {
|
|
63
|
+
throw new Error('Images must have the same dimensions');
|
|
64
|
+
}
|
|
65
|
+
var diff = new pngjs_1.PNG({ width: width, height: height });
|
|
66
|
+
var numDiffPixels = (0, pixelmatch_1.default)(img1.data, img2.data, diff.data, width, height, { threshold: threshold });
|
|
67
|
+
var diffPngBuffer = pngjs_1.PNG.sync.write(diff);
|
|
68
|
+
return {
|
|
69
|
+
diffPngBuffer: diffPngBuffer,
|
|
70
|
+
numDiffPixels: numDiffPixels
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Compares two image files (SVG or PNG) and generates a diff image
|
|
75
|
+
*/
|
|
76
|
+
function diffImages(pathA_1, pathB_1, diffFilePath_1) {
|
|
77
|
+
return __awaiter(this, arguments, void 0, function (pathA, pathB, diffFilePath, threshold) {
|
|
78
|
+
var validatedPathA, validatedPathB, pngA, pngB, result, ext, validatedWritePath;
|
|
79
|
+
if (threshold === void 0) { threshold = 0.1; }
|
|
80
|
+
return __generator(this, function (_a) {
|
|
81
|
+
switch (_a.label) {
|
|
82
|
+
case 0:
|
|
83
|
+
validatedPathA = (0, path_validation_1.validateReadPath)(pathA, ['.svg', '.png', '.jpg', '.jpeg', '.webp']);
|
|
84
|
+
validatedPathB = (0, path_validation_1.validateReadPath)(pathB, ['.svg', '.png', '.jpg', '.jpeg', '.webp']);
|
|
85
|
+
if (!fs_1.default.existsSync(validatedPathA)) {
|
|
86
|
+
throw new Error("File not found: ".concat(validatedPathA));
|
|
87
|
+
}
|
|
88
|
+
if (!fs_1.default.existsSync(validatedPathB)) {
|
|
89
|
+
throw new Error("File not found: ".concat(validatedPathB));
|
|
90
|
+
}
|
|
91
|
+
return [4 /*yield*/, (0, sharp_1.default)(validatedPathA).png().toBuffer()];
|
|
92
|
+
case 1:
|
|
93
|
+
pngA = _a.sent();
|
|
94
|
+
return [4 /*yield*/, (0, sharp_1.default)(validatedPathB).png().toBuffer()];
|
|
95
|
+
case 2:
|
|
96
|
+
pngB = _a.sent();
|
|
97
|
+
result = pixelLevelDiff(pngA, pngB, threshold);
|
|
98
|
+
if (diffFilePath) {
|
|
99
|
+
ext = path_1.default.extname(diffFilePath);
|
|
100
|
+
if (!ext) {
|
|
101
|
+
throw new Error('Diff file path must have a file extension');
|
|
102
|
+
}
|
|
103
|
+
validatedWritePath = (0, path_validation_1.validateWritePath)(diffFilePath, ['.png']);
|
|
104
|
+
fs_1.default.writeFileSync(validatedWritePath, result.diffPngBuffer);
|
|
105
|
+
}
|
|
106
|
+
return [2 /*return*/, result];
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Legacy function name for diffImages
|
|
113
|
+
*
|
|
114
|
+
* @deprecated Use diffImages instead
|
|
115
|
+
*/
|
|
116
|
+
function diffSvg(pathA, pathB, diffFilePath) {
|
|
117
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
118
|
+
var error_1;
|
|
119
|
+
return __generator(this, function (_a) {
|
|
120
|
+
switch (_a.label) {
|
|
121
|
+
case 0:
|
|
122
|
+
_a.trys.push([0, 2, , 3]);
|
|
123
|
+
return [4 /*yield*/, diffImages(pathA, pathB, diffFilePath)];
|
|
124
|
+
case 1: return [2 /*return*/, _a.sent()];
|
|
125
|
+
case 2:
|
|
126
|
+
error_1 = _a.sent();
|
|
127
|
+
console.error("Error comparing images: ".concat(error_1 instanceof Error ? error_1.message : String(error_1)));
|
|
128
|
+
return [2 /*return*/];
|
|
129
|
+
case 3: return [2 /*return*/];
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/compare/diff.ts"],"names":[],"mappings":";AAAA;;GAEG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAaH,wCA6BC;AAKD,gCAmCC;AAOD,0BAWC;AAlGD,0CAAoB;AACpB,8CAAwB;AACxB,gDAA0B;AAC1B,+BAA4B;AAC5B,0DAAoC;AAEpC,4DAA+E;AAE/E;;GAEG;AACH,SAAgB,cAAc,CAC5B,IAAY,EACZ,IAAY,EACZ,SAAuB;IAAvB,0BAAA,EAAA,eAAuB;IAEvB,IAAM,IAAI,GAAG,WAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjC,IAAM,IAAI,GAAG,WAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,IAAA,KAAK,GAAa,IAAI,MAAjB,EAAE,MAAM,GAAK,IAAI,OAAT,CAAU;IAE/B,IAAI,IAAI,CAAC,KAAK,KAAK,KAAK,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IAED,IAAM,IAAI,GAAG,IAAI,WAAG,CAAC,EAAE,KAAK,OAAA,EAAE,MAAM,QAAA,EAAE,CAAC,CAAC;IACxC,IAAM,aAAa,GAAG,IAAA,oBAAU,EAC9B,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,IAAI,EACT,KAAK,EACL,MAAM,EACN,EAAE,SAAS,WAAA,EAAE,CACd,CAAC;IAEF,IAAM,aAAa,GAAG,WAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAE3C,OAAO;QACL,aAAa,eAAA;QACb,aAAa,eAAA;KACd,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAsB,UAAU;wDAC9B,KAAa,EACb,KAAa,EACb,YAAqB,EACrB,SAAuB;;QAAvB,0BAAA,EAAA,eAAuB;;;;oBAGjB,cAAc,GAAG,IAAA,kCAAgB,EAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;oBACrF,cAAc,GAAG,IAAA,kCAAgB,EAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;oBAE3F,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;wBACnC,MAAM,IAAI,KAAK,CAAC,0BAAmB,cAAc,CAAE,CAAC,CAAC;oBACvD,CAAC;oBAED,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;wBACnC,MAAM,IAAI,KAAK,CAAC,0BAAmB,cAAc,CAAE,CAAC,CAAC;oBACvD,CAAC;oBAGY,qBAAM,IAAA,eAAK,EAAC,cAAc,CAAC,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,EAAA;;oBAAnD,IAAI,GAAG,SAA4C;oBAC5C,qBAAM,IAAA,eAAK,EAAC,cAAc,CAAC,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,EAAA;;oBAAnD,IAAI,GAAG,SAA4C;oBAEnD,MAAM,GAAG,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;oBAErD,IAAI,YAAY,EAAE,CAAC;wBACX,GAAG,GAAG,cAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;wBACvC,IAAI,CAAC,GAAG,EAAE,CAAC;4BACT,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;wBAC/D,CAAC;wBAEK,kBAAkB,GAAG,IAAA,mCAAiB,EAAC,YAAY,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;wBACrE,YAAE,CAAC,aAAa,CAAC,kBAAkB,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC;oBAC7D,CAAC;oBAED,sBAAO,MAAM,EAAC;;;;CACf;AAED;;;;GAIG;AACH,SAAsB,OAAO,CAC3B,KAAa,EACb,KAAa,EACb,YAAoB;;;;;;;oBAGX,qBAAM,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,EAAA;wBAAnD,sBAAO,SAA4C,EAAC;;;oBAEpD,OAAO,CAAC,KAAK,CAAC,kCAA2B,OAAK,YAAY,KAAK,CAAC,CAAC,CAAC,OAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAK,CAAC,CAAE,CAAC,CAAC;oBACnG,sBAAO;;;;;CAEV"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
var base64_3 = require("../base64");
|
|
4
|
+
var element_1 = require("../../core/element");
|
|
5
|
+
describe('Base64 Conversion', function () {
|
|
6
|
+
var testSvg = '<svg viewBox="0 0 100 100"><circle cx="50" cy="50" r="40" /></svg>';
|
|
7
|
+
describe('convertSVGToBase64', function () {
|
|
8
|
+
it('should convert SVG string to base64 data URI', function () {
|
|
9
|
+
var base64 = (0, base64_3.convertSVGToBase64)(testSvg);
|
|
10
|
+
expect(base64).toMatch(/^data:image\/svg\+xml;base64,/);
|
|
11
|
+
expect(base64.length).toBeGreaterThan(50);
|
|
12
|
+
});
|
|
13
|
+
it('should convert SVG element to base64 data URI', function () {
|
|
14
|
+
var element = (0, element_1.createSVGElement)(testSvg);
|
|
15
|
+
var base64 = (0, base64_3.convertSVGToBase64)(element);
|
|
16
|
+
expect(base64).toMatch(/^data:image\/svg\+xml;base64,/);
|
|
17
|
+
});
|
|
18
|
+
it('should produce consistent results for same input', function () {
|
|
19
|
+
var base64_1 = (0, base64_3.convertSVGToBase64)(testSvg);
|
|
20
|
+
var base64_2 = (0, base64_3.convertSVGToBase64)(testSvg);
|
|
21
|
+
expect(base64_1).toBe(base64_2);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
describe('convertBase64ToSVG', function () {
|
|
25
|
+
it('should convert base64 data URI back to SVG string', function () {
|
|
26
|
+
var base64 = (0, base64_3.convertSVGToBase64)(testSvg);
|
|
27
|
+
var svgString = (0, base64_3.convertBase64ToSVG)(base64);
|
|
28
|
+
expect(svgString).toContain('<svg');
|
|
29
|
+
expect(svgString).toContain('circle');
|
|
30
|
+
});
|
|
31
|
+
it('should handle base64 string without data URI prefix', function () {
|
|
32
|
+
var base64 = (0, base64_3.convertSVGToBase64)(testSvg);
|
|
33
|
+
var base64Only = base64.split(',')[1];
|
|
34
|
+
var svgString = (0, base64_3.convertBase64ToSVG)(base64Only);
|
|
35
|
+
expect(svgString).toContain('<svg');
|
|
36
|
+
});
|
|
37
|
+
it('should throw error for invalid base64 string', function () {
|
|
38
|
+
expect(function () { return (0, base64_3.convertBase64ToSVG)('invalid-base64!!!'); }).toThrow('Invalid Base64 string');
|
|
39
|
+
});
|
|
40
|
+
it('should round-trip correctly', function () {
|
|
41
|
+
var original = testSvg;
|
|
42
|
+
var base64 = (0, base64_3.convertSVGToBase64)(original);
|
|
43
|
+
var converted = (0, base64_3.convertBase64ToSVG)(base64);
|
|
44
|
+
// Remove whitespace differences for comparison
|
|
45
|
+
var normalize = function (s) { return s.replace(/\s+/g, ' ').trim(); };
|
|
46
|
+
expect(normalize(converted)).toContain('<svg');
|
|
47
|
+
expect(normalize(converted)).toContain('circle');
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
//# sourceMappingURL=base64.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base64.test.js","sourceRoot":"","sources":["../../../src/convert/__tests__/base64.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base64 encoding/decoding utilities for SVG
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Converts an SVG element or SVG string to a Base64-encoded data URI
|
|
6
|
+
*/
|
|
7
|
+
export declare function convertSVGToBase64(svgContent: Element | string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Converts a Base64-encoded data URI back to an SVG string
|
|
10
|
+
*/
|
|
11
|
+
export declare function convertBase64ToSVG(base64String: string): string;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Base64 encoding/decoding utilities for SVG
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.convertSVGToBase64 = convertSVGToBase64;
|
|
7
|
+
exports.convertBase64ToSVG = convertBase64ToSVG;
|
|
8
|
+
var element_1 = require("../core/element");
|
|
9
|
+
/**
|
|
10
|
+
* Converts an SVG element or SVG string to a Base64-encoded data URI
|
|
11
|
+
*/
|
|
12
|
+
function convertSVGToBase64(svgContent) {
|
|
13
|
+
var svgString = (0, element_1.serializeSVG)(svgContent);
|
|
14
|
+
return "data:image/svg+xml;base64,".concat(Buffer.from(svgString).toString('base64'));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Converts a Base64-encoded data URI back to an SVG string
|
|
18
|
+
*/
|
|
19
|
+
function convertBase64ToSVG(base64String) {
|
|
20
|
+
try {
|
|
21
|
+
var base64Data = base64String.includes(',')
|
|
22
|
+
? base64String.split(',')[1]
|
|
23
|
+
: base64String;
|
|
24
|
+
// Validate base64 string format
|
|
25
|
+
if (!/^[A-Za-z0-9+/]*={0,2}$/.test(base64Data)) {
|
|
26
|
+
throw new Error('Invalid Base64 string.');
|
|
27
|
+
}
|
|
28
|
+
var svgString = Buffer.from(base64Data, 'base64').toString('utf-8');
|
|
29
|
+
// Basic validation that result looks like SVG
|
|
30
|
+
if (!svgString.includes('<svg') && !svgString.includes('<SVG')) {
|
|
31
|
+
throw new Error('Invalid Base64 string.');
|
|
32
|
+
}
|
|
33
|
+
return svgString;
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
if (error instanceof Error && error.message === 'Invalid Base64 string.') {
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
throw new Error('Invalid Base64 string.');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=base64.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base64.js","sourceRoot":"","sources":["../../src/convert/base64.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAQH,gDAGC;AAKD,gDAyBC;AAtCD,2CAA+C;AAE/C;;GAEG;AACH,SAAgB,kBAAkB,CAAC,UAA4B;IAC7D,IAAM,SAAS,GAAG,IAAA,sBAAY,EAAC,UAAU,CAAC,CAAC;IAC3C,OAAO,oCAA6B,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAE,CAAC;AAClF,CAAC;AAED;;GAEG;AACH,SAAgB,kBAAkB,CAAC,YAAoB;IACrD,IAAI,CAAC;QACH,IAAM,UAAU,GAAG,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC;YAC3C,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC5B,CAAC,CAAC,YAAY,CAAC;QAEjB,gCAAgC;QAChC,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YAC/C,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAC5C,CAAC;QAED,IAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAEtE,8CAA8C;QAC9C,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAC/D,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAC5C,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,KAAK,wBAAwB,EAAE,CAAC;YACzE,MAAM,KAAK,CAAC;QACd,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SVG to image format conversion utilities
|
|
3
|
+
*/
|
|
4
|
+
import { ConversionOptions } from '../types';
|
|
5
|
+
/**
|
|
6
|
+
* Converts an SVG file to PNG format
|
|
7
|
+
*
|
|
8
|
+
* @param svgPath - Path to the SVG file
|
|
9
|
+
* @param options - Conversion options including scale, format, and quality
|
|
10
|
+
* @returns Promise resolving to a Buffer containing the converted image
|
|
11
|
+
*/
|
|
12
|
+
export declare function svgToImage(svgPath: string, options?: ConversionOptions): Promise<Buffer>;
|
|
13
|
+
/**
|
|
14
|
+
* Converts an SVG file to PNG format (legacy function name)
|
|
15
|
+
*
|
|
16
|
+
* @deprecated Use svgToImage instead
|
|
17
|
+
*/
|
|
18
|
+
export declare function svg2Png(svgPath: string, pngPath?: string, scale?: number): Promise<void | Buffer>;
|