@mapka/sprites-generate 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { generateLayout, generateLayoutUnique } from './generate.js';
2
+ export { generateImage, generateOptimizedImage } from './image.js';
3
+ export { extractSvgMetadata } from './metadata.js';
4
+ export { validateMetadata } from './validate.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,cAAc,EAAE,oBAAoB,EAAC,MAAM,eAAe,CAAC;AACnE,OAAO,EAAC,aAAa,EAAE,sBAAsB,EAAC,MAAM,YAAY,CAAC;AAEjE,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AACjD,OAAO,EAAC,gBAAgB,EAAC,MAAM,eAAe,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Parses a SVG document and extracts metadata from its shapes and paths.
3
+ *
4
+ * @param {Object} [img]
5
+ * @param {Buffer|string} [img.svg] A string of the SVG.
6
+ * @param {number} [img.pixelRatio] Ratio of a 72dpi screen pixel to the destination pixel density
7
+ * @param {Function} callback Accepts two arguments, `err` and `metadata` Object
8
+ * @return {Metadata} metadata An object with the extracted information.
9
+ */
10
+ export function extractSvgMetadata(img?: {
11
+ svg?: string | Buffer<ArrayBufferLike> | undefined;
12
+ pixelRatio?: number | undefined;
13
+ }, callback: Function): Metadata;
14
+ //# sourceMappingURL=metadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../src/metadata.js"],"names":[],"mappings":"AA2IA;;;;;;;;GAQG;AACH,yCALG;IAAsC,GAAG;IACH,UAAU;CAChD,uBACU,QAAQ,CA6CpB"}
@@ -0,0 +1,175 @@
1
+ import { resolvePluginConfig } from 'svgo/lib/svgo/config.js';
2
+ import { parseSvg } from 'svgo/lib/parser.js';
3
+ import { stringifySvg } from 'svgo/lib/stringifier.js';
4
+ import { invokePlugins } from 'svgo/lib/svgo/plugins.js';
5
+ import svgBoundings from 'svg-boundings';
6
+ const computePathBounds = svgBoundings.path;
7
+ const metadataPrefix = 'mapbox-';
8
+ // Removes `style` attribute. Otherwise, transforms will not apply.
9
+ // Refer to https://github.com/svg/svgo/blob/a9834efa1603198ae606765292215462ae193d0d/plugins/applyTransforms.js#L55-L57
10
+ const removeStyleAttribute = {
11
+ name: 'removeStyleAttribute',
12
+ type: 'perItem',
13
+ fn: (item) => {
14
+ if (item.hasAttr('style'))
15
+ item.removeAttr('style');
16
+ return item;
17
+ }
18
+ };
19
+ // Transforms `id="mapbox-*"` into `mapbox:metadata="*"` so that the `convertPathData` step
20
+ // resolves transforms.
21
+ const renameMapboxMetadata = {
22
+ name: 'renameMapboxMetadata',
23
+ type: 'perItem',
24
+ fn: function (item) {
25
+ if (item.hasAttr('id')) {
26
+ const id = item.attr('id');
27
+ if (id.value.startsWith(metadataPrefix)) {
28
+ let valueSubstr = id.value.substring(metadataPrefix.length);
29
+ item.removeAttr('id');
30
+ item.addAttr({
31
+ name: 'mapbox:metadata',
32
+ value: valueSubstr,
33
+ prefix: '',
34
+ local: 'mapbox:metadata',
35
+ });
36
+ }
37
+ }
38
+ return item;
39
+ }
40
+ };
41
+ /**
42
+ * Decrease accuracy of floating-point numbers
43
+ * in path data keeping a specified number of decimals.
44
+ * Smart rounds values like 2.3491 to 2.35 instead of 2.349.
45
+ * Doesn't apply "smartness" if the number precision fits already.
46
+ *
47
+ * Taken from svgo at https://github.com/svg/svgo/blob/72db8eb/plugins/convertPathData.js#L773
48
+ */
49
+ function strongRound(value, precision) {
50
+ if (!precision) {
51
+ precision = 3;
52
+ }
53
+ const error = +Math.pow(0.1, precision).toFixed(precision);
54
+ if (+value.toFixed(precision) !== value) {
55
+ var rounded = +value.toFixed(precision - 1);
56
+ value = +Math.abs(rounded - value).toFixed(precision + 1) >= error ?
57
+ +value.toFixed(precision) :
58
+ rounded;
59
+ }
60
+ return value;
61
+ }
62
+ // Plugin for use with svgo that extracts metadata from paths.
63
+ const extractMapboxMetadata = {
64
+ name: 'extractMapboxMetadata',
65
+ type: 'perItem',
66
+ fn: function (item, params, info) {
67
+ if (item.isElem('path') && item.hasAttr('mapbox:metadata') && item.hasAttr('d')) {
68
+ const metadata = item.attr('mapbox:metadata');
69
+ const bounds = computePathBounds({ d: item.attr('d').value }, true);
70
+ // Make sure that we actually have a valid bounding box.
71
+ if (!Number.isFinite(bounds.left) || !Number.isFinite(bounds.right) ||
72
+ !Number.isFinite(bounds.top) || !Number.isFinite(bounds.bottom)) {
73
+ return true;
74
+ }
75
+ // Scale bounds by pixel ratio.
76
+ bounds.left = strongRound(bounds.left * info.pixelRatio);
77
+ bounds.top = strongRound(bounds.top * info.pixelRatio);
78
+ bounds.right = strongRound(bounds.right * info.pixelRatio);
79
+ bounds.bottom = strongRound(bounds.bottom * info.pixelRatio);
80
+ if (metadata.value.startsWith('stretch-x')) {
81
+ (info.metadata.stretchX = info.metadata.stretchX || []).push([bounds.left, bounds.right]);
82
+ }
83
+ else if (metadata.value.startsWith('stretch-y')) {
84
+ (info.metadata.stretchY = info.metadata.stretchY || []).push([bounds.top, bounds.bottom]);
85
+ }
86
+ else if (metadata.value === 'stretch') {
87
+ (info.metadata.stretchX = info.metadata.stretchX || []).push([bounds.left, bounds.right]);
88
+ (info.metadata.stretchY = info.metadata.stretchY || []).push([bounds.top, bounds.bottom]);
89
+ }
90
+ else if (metadata.value === 'content' || metadata.value === 'text-placeholder') {
91
+ const key = metadata.value === 'content' ? 'content' : 'placeholder';
92
+ info.metadata[key] = [bounds.left, bounds.top, bounds.right, bounds.bottom];
93
+ }
94
+ }
95
+ return true;
96
+ }
97
+ };
98
+ const preparePluginsConfig = [
99
+ {
100
+ name: 'cleanupIDs',
101
+ params: {
102
+ // Remove all IDs first so that `convertPathData` resolves transforms.
103
+ preservePrefixes: ['mapbox-']
104
+ }
105
+ },
106
+ renameMapboxMetadata,
107
+ 'convertShapeToPath'
108
+ ].map(resolvePluginConfig);
109
+ const collapsePluginsConfig = [
110
+ 'convertTransform',
111
+ 'moveGroupAttrsToElems',
112
+ 'collapseGroups'
113
+ ].map(resolvePluginConfig);
114
+ const extractPluginsConfig = [
115
+ removeStyleAttribute,
116
+ {
117
+ name: 'convertPathData',
118
+ params: {
119
+ // svg-boundings has trouble parsing consecutive numbers without space and without a leading
120
+ // zero. Therefore, we force leading zeros. Note that this option confusingly has to be set
121
+ // to _false_ to produce leading zeros.
122
+ // See https://github.com/kfitfk/svg-boundings/issues/2
123
+ leadingZero: false
124
+ }
125
+ },
126
+ extractMapboxMetadata
127
+ ].map(resolvePluginConfig);
128
+ /**
129
+ * Parses a SVG document and extracts metadata from its shapes and paths.
130
+ *
131
+ * @param {Object} [img]
132
+ * @param {Buffer|string} [img.svg] A string of the SVG.
133
+ * @param {number} [img.pixelRatio] Ratio of a 72dpi screen pixel to the destination pixel density
134
+ * @param {Function} callback Accepts two arguments, `err` and `metadata` Object
135
+ * @return {Metadata} metadata An object with the extracted information.
136
+ */
137
+ export function extractSvgMetadata(img, callback) {
138
+ try {
139
+ const imgSvg = Buffer.isBuffer(img.svg) ? img.svg.toString('utf-8') : img.svg;
140
+ let result = parseSvg(imgSvg);
141
+ // We'll add the metadata that we extract in the svgo plugin above to this object.
142
+ const info = {
143
+ metadata: {},
144
+ pixelRatio: Number.isFinite(img.pixelRatio) && img.pixelRatio || 1
145
+ };
146
+ let previousSVG;
147
+ let svg = img.svg;
148
+ try {
149
+ // A few initial plugins prepare the data, e.g. by moving IDs to custom attributes.
150
+ result = invokePlugins(result, info, preparePluginsConfig);
151
+ // We'll walk through the plugins that collapse groups until there are no changes to the output.
152
+ do {
153
+ previousSVG = svg;
154
+ result = invokePlugins(result, info, collapsePluginsConfig);
155
+ svg = stringifySvg(result).data;
156
+ } while (previousSVG !== svg);
157
+ // Finally, we'll run through the plugins that actually read and parse the metadata.
158
+ invokePlugins(result, info, extractPluginsConfig);
159
+ }
160
+ catch (err) {
161
+ return callback(err);
162
+ }
163
+ // Sort stretches ascending.
164
+ for (const key of ['stretchX', 'stretchY']) {
165
+ if (info.metadata[key]) {
166
+ info.metadata[key].sort((a, b) => a[0] - b[0]);
167
+ }
168
+ }
169
+ callback(null, info.metadata);
170
+ }
171
+ catch (err) {
172
+ return callback(err);
173
+ }
174
+ }
175
+ //# sourceMappingURL=metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../src/metadata.js"],"names":[],"mappings":"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"}
package/lib/types.d.ts ADDED
@@ -0,0 +1,37 @@
1
+ import type { Image } from "@mapnik/mapnik";
2
+ import type { Metadata } from "./validate.js";
3
+ export interface SvgImage {
4
+ svg: Buffer;
5
+ id: string;
6
+ x: number;
7
+ y: number;
8
+ width: number;
9
+ height: number;
10
+ buffer: Image;
11
+ }
12
+ export interface DataSvgImage extends Metadata {
13
+ svg: Buffer;
14
+ id: string;
15
+ width: number;
16
+ height: number;
17
+ buffer: Image;
18
+ }
19
+ export interface DataLayout {
20
+ [key: string]: {
21
+ width: number;
22
+ height: number;
23
+ x: number;
24
+ y: number;
25
+ pixelRatio: number;
26
+ content?: [number, number, number, number];
27
+ stretchX?: [number, number][];
28
+ stretchY?: [number, number][];
29
+ placeholder?: [number, number, number, number];
30
+ };
31
+ }
32
+ export interface ImgLayout {
33
+ width: number;
34
+ height: number;
35
+ items: SvgImage[];
36
+ }
37
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,KAAK,CAAC;CACf;AAED,MAAM,WAAW,YAAa,SAAQ,QAAQ;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,KAAK,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG;QACb,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;QACV,UAAU,EAAE,MAAM,CAAC;QACnB,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAC3C,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;QAC9B,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;QAC9B,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;KAChD,CAAC;CACH;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB"}
package/lib/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,20 @@
1
+ /** biome-ignore-all lint/suspicious/noExplicitAny: nature of this validate function */
2
+ export interface Metadata {
3
+ x: number;
4
+ y: number;
5
+ placeholder?: [number, number, number, number];
6
+ content?: [number, number, number, number];
7
+ stretchX?: [number, number][];
8
+ stretchY?: [number, number][];
9
+ }
10
+ export interface Image {
11
+ width?: number;
12
+ height?: number;
13
+ }
14
+ /**
15
+ * Validates metadata that is parsed from an SVG metadata
16
+ *
17
+ * @return {Error} if metadata is invalid
18
+ */
19
+ export declare function validateMetadata(img?: any, metadata?: any): Error | null;
20
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAAA,uFAAuF;AAEvF,MAAM,WAAW,QAAQ;IACrB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3C,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;IAC9B,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,KAAK;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,EAAE,GAAG,gBAsEzD"}
@@ -0,0 +1,65 @@
1
+ /** biome-ignore-all lint/suspicious/noExplicitAny: nature of this validate function */
2
+ /**
3
+ * Validates metadata that is parsed from an SVG metadata
4
+ *
5
+ * @return {Error} if metadata is invalid
6
+ */
7
+ export function validateMetadata(img, metadata) {
8
+ if (!img || typeof img !== 'object') {
9
+ return new Error('image is invalid');
10
+ }
11
+ if (!metadata || typeof metadata !== 'object') {
12
+ return new Error('image has invalid metadata');
13
+ }
14
+ if (typeof img.width !== 'number' || img.width <= 0) {
15
+ return new Error('image has invalid width');
16
+ }
17
+ if (typeof img.height !== 'number' || img.height <= 0) {
18
+ return new Error('image has invalid height');
19
+ }
20
+ if ('content' in metadata) {
21
+ const content = metadata.content;
22
+ if (!Array.isArray(content) || content.length !== 4 ||
23
+ typeof content[0] !== 'number' || typeof content[1] !== 'number' ||
24
+ typeof content[2] !== 'number' || typeof content[3] !== 'number') {
25
+ return new Error('image content area must be an array of 4 numbers');
26
+ }
27
+ if (content[0] >= content[2] || content[1] >= content[3]) {
28
+ return new Error('image content area must be positive');
29
+ }
30
+ if (content[0] < 0 || content[2] > img.width ||
31
+ content[1] < 0 || content[3] > img.height) {
32
+ return new Error('image content area must be within image bounds');
33
+ }
34
+ }
35
+ for (const key of ['stretchX', 'stretchY']) {
36
+ if (key in metadata) {
37
+ const stretches = metadata[key];
38
+ if (!Array.isArray(stretches)) {
39
+ return new Error(`image ${key} zones must be an array`);
40
+ }
41
+ for (const zone of stretches) {
42
+ if (!Array.isArray(zone) || zone.length !== 2 ||
43
+ typeof zone[0] !== 'number' || typeof zone[1] !== 'number') {
44
+ return new Error(`image ${key} zone must consist of two numbers`);
45
+ }
46
+ if (zone[0] >= zone[1]) {
47
+ return new Error(`image ${key} zone may not be zero-size`);
48
+ }
49
+ if (zone[0] < 0 || zone[1] > img.width) {
50
+ return new Error(`image ${key} zone must be within image bounds`);
51
+ }
52
+ }
53
+ for (let i = 1; i < stretches.length; i++) {
54
+ // Make sure that the previous stretch's end coordinate is
55
+ // smaller than this stretch's begin coordinate. Expects that
56
+ // stretch zones are sorted ascending by their first coordinate.
57
+ if (stretches[i][0] <= stretches[i - 1][1]) {
58
+ return new Error(`image ${key} zones may not overlap`);
59
+ }
60
+ }
61
+ }
62
+ }
63
+ return null;
64
+ }
65
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@mapka/sprites-generate",
3
+ "version": "0.4.1",
4
+ "description": "Generate sprites layout from individual svg icons",
5
+ "main": "./lib/index.js",
6
+ "license": "ISC",
7
+ "type": "module",
8
+ "sideEffects": false,
9
+ "publishConfig": {
10
+ "access": "public"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/mapka-dev/sprites.git"
15
+ },
16
+ "dependencies": {
17
+ "@mapka/shelf-pack": "^0.4.1",
18
+ "@mapnik/mapnik": "^4.7.3",
19
+ "svg-boundings": "^2.0.8",
20
+ "svgo": "^2.8.0"
21
+ },
22
+ "files": [
23
+ "src/",
24
+ "lib/",
25
+ "LICENSE",
26
+ "!**/__tests__/",
27
+ "!lib/buildInfo.json"
28
+ ],
29
+ "gitHead": "5ff8c7554e4a4eb2349337c662bb853b588f7e45"
30
+ }
@@ -0,0 +1,30 @@
1
+ import { globSync, readFileSync } from "node:fs";
2
+ import { basename, join, resolve } from "node:path";
3
+ import { bench } from "vitest";
4
+ import { generateLayout } from "../generate.js";
5
+
6
+ const fixtures = globSync(resolve(join(import.meta.dirname, "../__tests__/fixture/svg/*.svg"))).map((im) => ({
7
+ svg: readFileSync(im),
8
+ id: basename(im).replace(".svg", ""),
9
+ }));
10
+
11
+ function getFixtures() {
12
+ return fixtures.sort(() => Math.random() - 0.5);
13
+ }
14
+
15
+ bench("generateLayout bench (concurrency=1,x20)", async () => {
16
+ for (let i = 0; i < 20; i++) {
17
+ await generateLayout({ imgs: getFixtures(), pixelRatio: 1, format: false });
18
+ }
19
+ });
20
+
21
+ bench("generateLayout bench (concurrency=4,x20)", async () => {
22
+ for (let i = 0; i < 20; i += 4) {
23
+ await Promise.all([
24
+ generateLayout({ imgs: getFixtures(), pixelRatio: 1, format: false }),
25
+ generateLayout({ imgs: getFixtures(), pixelRatio: 1, format: false }),
26
+ generateLayout({ imgs: getFixtures(), pixelRatio: 1, format: false }),
27
+ generateLayout({ imgs: getFixtures(), pixelRatio: 1, format: false }),
28
+ ]);
29
+ }
30
+ });
@@ -0,0 +1,71 @@
1
+
2
+ /**
3
+ * @see https://mapnik.org/documentation/node-mapnik/3.6/#blend
4
+ */
5
+ interface BlendOptions {
6
+ /**
7
+ * Output image format
8
+ */
9
+ format?: "png" | "jpeg" | "webp";
10
+
11
+ /**
12
+ * Image width in pixels
13
+ */
14
+ width?: number;
15
+
16
+ /**
17
+ * Image height in pixels
18
+ */
19
+ height?: number;
20
+
21
+ /**
22
+ * Compression level - references internal zlib compression algorithm
23
+ * (platform-dependent values)
24
+ */
25
+ compression?: number;
26
+
27
+ /** Whether to re-encode the image */
28
+ reencode?: boolean;
29
+
30
+ /** Enable palette-based encoding */
31
+ palette?: boolean;
32
+
33
+ /**
34
+ * Color quantization algorithm mode
35
+ * - hextree: Hexadecimal tree algorithm
36
+ * - octree: Octree algorithm
37
+ */
38
+ mode?: 'hextree' | 'octree';
39
+
40
+ /**
41
+ * Image quality setting:
42
+ * - JPEG & WebP: 0-100 (0 = lowest quality, 100 = highest quality)
43
+ * - PNG: 2-256 (2 = highest quality, 256 = lowest quality)
44
+ */
45
+ quality?: number;
46
+ }
47
+
48
+ declare module "@mapnik/mapnik" {
49
+ export class Image {
50
+ constructor(width: number, height: number);
51
+ width(): number;
52
+ height(): number;
53
+ encodeSync(format: string): Buffer;
54
+ static fromSVGBytes(
55
+ svg: Buffer,
56
+ options: {
57
+ max_size?: number;
58
+ scale?: number
59
+ }, callback: (err: Error | null, image: Image) => void
60
+ );
61
+ }
62
+
63
+ /**
64
+ * @see https://mapnik.org/documentation/node-mapnik/3.6/#blend
65
+ */
66
+ export function blend(
67
+ items: Buffer[] | {buffer: Image}[],
68
+ options: BlendOptions,
69
+ callback: (err: Error | null, image: Buffer) => void
70
+ );
71
+ }