@midscene/shared 0.7.2 → 0.7.3-beta-20241104100519.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/package.json CHANGED
@@ -1,46 +1,63 @@
1
1
  {
2
2
  "name": "@midscene/shared",
3
- "version": "0.7.2",
3
+ "version": "0.7.3-beta-20241104100519.0",
4
4
  "repository": "https://github.com/web-infra-dev/midscene",
5
5
  "homepage": "https://midscenejs.com/",
6
- "types": "./dist/types/index.d.ts",
6
+ "types": "./src/index.ts",
7
+ "type": "commonjs",
7
8
  "main": "./dist/lib/index.js",
8
9
  "module": "./dist/es/index.js",
9
10
  "exports": {
10
11
  ".": {
11
- "types": "./dist/types/index.d.ts",
12
- "import": "./dist/es/index.js",
13
- "require": "./dist/lib/index.js"
12
+ "types": "./dist/lib/index.d.ts",
13
+ "require": "./dist/lib/index.js",
14
+ "import": "./dist/es/index.js"
14
15
  },
15
16
  "./constants": {
16
- "types": "./dist/types/constants.d.ts",
17
- "import": "./dist/es/constants.js",
18
- "require": "./dist/lib/constants.js"
17
+ "types": "./dist/lib/constants.d.ts",
18
+ "require": "./dist/lib/constants.js",
19
+ "import": "./dist/es/constants.js"
20
+ },
21
+ "./fs": {
22
+ "types": "./dist/lib/fs.d.ts",
23
+ "require": "./dist/lib/fs.js",
24
+ "import": "./dist/es/fs.js"
19
25
  },
20
26
  "./img": {
21
- "types": "./dist/types/img.d.ts",
22
- "import": "./dist/es/img.js",
23
- "require": "./dist/lib/img.js"
27
+ "types": "./dist/lib/img.d.ts",
28
+ "require": "./dist/lib/img.js",
29
+ "import": "./dist/es/img.js"
24
30
  },
25
- "./fs": {
26
- "types": "./dist/types/fs.d.ts",
27
- "import": "./dist/es/fs.js",
28
- "require": "./dist/lib/fs.js"
31
+ "./browser/img": {
32
+ "types": "./dist/browser/img.d.ts",
33
+ "require": "./dist/browser/img.js",
34
+ "import": "./dist/browser/img.js"
35
+ },
36
+ "./utils": {
37
+ "types": "./dist/lib/utils.d.ts",
38
+ "require": "./dist/lib/utils.js",
39
+ "import": "./dist/es/utils.js"
29
40
  }
30
41
  },
31
42
  "typesVersions": {
32
43
  "*": {
33
44
  ".": [
34
- "./dist/types/index.d.ts"
45
+ "./dist/lib/index.d.ts"
35
46
  ],
36
47
  "constants": [
37
- "./dist/types/constants.d.ts"
48
+ "./dist/lib/constants.d.ts"
38
49
  ],
39
50
  "img": [
40
- "./dist/types/img.d.ts"
51
+ "./dist/lib/img.d.ts"
52
+ ],
53
+ "browser/img": [
54
+ "./dist/browser/img.d.ts"
41
55
  ],
42
56
  "fs": [
43
- "./dist/types/fs.d.ts"
57
+ "./dist/lib/fs.d.ts"
58
+ ],
59
+ "utils": [
60
+ "./dist/lib/utils.d.ts"
44
61
  ]
45
62
  }
46
63
  },
@@ -54,7 +71,7 @@
54
71
  },
55
72
  "peerDependencies": {},
56
73
  "devDependencies": {
57
- "@modern-js/module-tools": "2.58.2",
74
+ "@modern-js/module-tools": "2.60.6",
58
75
  "typescript": "~5.0.4",
59
76
  "@types/node": "^18.0.0",
60
77
  "rimraf": "~3.0.2",
package/src/fs/index.ts CHANGED
@@ -8,25 +8,29 @@ interface PkgInfo {
8
8
  dir: string;
9
9
  }
10
10
 
11
- let pkg: PkgInfo | undefined;
12
- export function getMidscenePkgInfo(dir: string): PkgInfo {
13
- if (pkg) {
14
- return pkg;
11
+ const pkgCacheMap: Record<string, PkgInfo> = {};
12
+ const ifInBrowser = typeof window !== 'undefined';
13
+ export function getRunningPkgInfo(dir?: string): PkgInfo | null {
14
+ if (ifInBrowser) {
15
+ return null;
16
+ }
17
+ const dirToCheck = dir || process.cwd();
18
+ if (pkgCacheMap[dirToCheck]) {
19
+ return pkgCacheMap[dirToCheck];
15
20
  }
16
21
 
17
- const pkgDir = findNearestPackageJson(dir || process.cwd());
18
- assert(pkgDir, 'package.json not found');
19
- const pkgJsonFile = join(pkgDir, 'package.json');
22
+ const pkgDir = findNearestPackageJson(dirToCheck);
23
+ const pkgJsonFile = pkgDir ? join(pkgDir, 'package.json') : null;
20
24
 
21
- if (pkgJsonFile) {
25
+ if (pkgDir && pkgJsonFile) {
22
26
  const { name, version } = JSON.parse(readFileSync(pkgJsonFile, 'utf-8'));
23
- pkg = { name, version, dir: pkgDir };
24
- return pkg;
27
+ pkgCacheMap[dirToCheck] = { name, version, dir: pkgDir };
28
+ return pkgCacheMap[dirToCheck];
25
29
  }
26
30
  return {
27
- name: 'midscene-unknown-page-name',
31
+ name: 'midscene-unknown-package-name',
28
32
  version: '0.0.0',
29
- dir: pkgDir,
33
+ dir: dirToCheck,
30
34
  };
31
35
  }
32
36
 
@@ -1,231 +1,246 @@
1
1
  import assert from 'node:assert';
2
- import { Buffer } from 'node:buffer';
2
+ import type { Buffer } from 'node:buffer';
3
3
  import type { Rect } from '@/types';
4
- import Jimp from 'jimp';
4
+ import type Jimp from 'jimp';
5
5
  import type { NodeType } from '../constants';
6
+ import getJimp from './get-jimp';
7
+ import { bufferFromBase64, imageInfo, imageInfoOfBase64 } from './index';
6
8
 
7
9
  // Define picture path
8
10
  type ElementType = {
9
- locator: string;
11
+ locator?: string;
10
12
 
11
13
  rect: Rect;
12
14
 
13
- center: [number, number];
15
+ center?: [number, number];
14
16
 
15
- id: string;
17
+ id?: string;
16
18
 
17
19
  indexId: number;
18
20
 
19
- attributes: {
21
+ attributes?: {
20
22
  nodeType: NodeType;
21
23
  [key: string]: string;
22
24
  };
23
25
  };
24
26
 
25
- const createSvgOverlay = (
27
+ let cachedFont: any = null;
28
+
29
+ const createSvgOverlay = async (
26
30
  elements: Array<ElementType>,
27
31
  imageWidth: number,
28
32
  imageHeight: number,
29
- ) => {
30
- const createPngOverlay = async (
31
- elements: Array<ElementType>,
32
- imageWidth: number,
33
- imageHeight: number,
34
- ) => {
35
- const image = new Jimp(imageWidth, imageHeight, 0x00000000);
36
-
37
- // Define color array
38
- const colors = [
39
- { rect: 0xff0000ff, text: 0xffffffff }, // red, white
40
- // { rect: 0x0000ffff, text: 0xffffffff }, // blue, white
41
- // { rect: 0x8b4513ff, text: 0xffffffff }, // brown, white
42
- ];
33
+ ): Promise<Jimp> => {
34
+ const Jimp = await getJimp();
35
+ const image = new Jimp(imageWidth, imageHeight, 0x00000000);
43
36
 
44
- const boxPadding = 5;
45
- for (let index = 0; index < elements.length; index++) {
46
- const element = elements[index];
47
- const color = colors[index % colors.length];
37
+ // Define color array
38
+ const colors = [
39
+ { rect: 0xff0000ff, text: 0xffffffff }, // red, white
40
+ // { rect: 0x0000ffff, text: 0xffffffff }, // blue, white
41
+ // { rect: 0x8b4513ff, text: 0xffffffff }, // brown, white
42
+ ];
48
43
 
49
- // Add 5px padding to the rect
50
- const paddedRect = {
51
- left: Math.max(0, element.rect.left - boxPadding),
52
- top: Math.max(0, element.rect.top - boxPadding),
53
- width: Math.min(
54
- imageWidth - element.rect.left,
55
- element.rect.width + boxPadding * 2,
56
- ),
57
- height: Math.min(
58
- imageHeight - element.rect.top,
59
- element.rect.height + boxPadding * 2,
60
- ),
61
- };
44
+ const boxPadding = 5;
45
+ for (let index = 0; index < elements.length; index++) {
46
+ const element = elements[index];
47
+ const color = colors[index % colors.length];
62
48
 
63
- // Draw rectangle
64
- image.scan(
65
- paddedRect.left,
66
- paddedRect.top,
67
- paddedRect.width,
68
- paddedRect.height,
69
- function (x, y, idx) {
70
- if (
71
- x === paddedRect.left ||
72
- x === paddedRect.left + paddedRect.width - 1 ||
73
- y === paddedRect.top ||
74
- y === paddedRect.top + paddedRect.height - 1
75
- ) {
76
- this.bitmap.data[idx + 0] = (color.rect >> 24) & 0xff; // R
77
- this.bitmap.data[idx + 1] = (color.rect >> 16) & 0xff; // G
78
- this.bitmap.data[idx + 2] = (color.rect >> 8) & 0xff; // B
79
- this.bitmap.data[idx + 3] = color.rect & 0xff; // A
80
- }
81
- },
82
- );
49
+ // Add 5px padding to the rect
50
+ const paddedRect = {
51
+ left: Math.max(0, element.rect.left - boxPadding),
52
+ top: Math.max(0, element.rect.top - boxPadding),
53
+ width: Math.min(
54
+ imageWidth - element.rect.left,
55
+ element.rect.width + boxPadding * 2,
56
+ ),
57
+ height: Math.min(
58
+ imageHeight - element.rect.top,
59
+ element.rect.height + boxPadding * 2,
60
+ ),
61
+ };
83
62
 
84
- // Calculate text position
85
- const textWidth = element.indexId.toString().length * 8;
86
- const textHeight = 12;
87
- const rectWidth = textWidth + 5;
88
- const rectHeight = textHeight + 4;
89
- let rectX = paddedRect.left - rectWidth;
90
- let rectY = paddedRect.top + paddedRect.height / 2 - textHeight / 2 - 2;
63
+ // Draw rectangle
64
+ image.scan(
65
+ paddedRect.left,
66
+ paddedRect.top,
67
+ paddedRect.width,
68
+ paddedRect.height,
69
+ function (x, y, idx) {
70
+ if (
71
+ x === paddedRect.left ||
72
+ x === paddedRect.left + paddedRect.width - 1 ||
73
+ y === paddedRect.top ||
74
+ y === paddedRect.top + paddedRect.height - 1
75
+ ) {
76
+ this.bitmap.data[idx + 0] = (color.rect >> 24) & 0xff; // R
77
+ this.bitmap.data[idx + 1] = (color.rect >> 16) & 0xff; // G
78
+ this.bitmap.data[idx + 2] = (color.rect >> 8) & 0xff; // B
79
+ this.bitmap.data[idx + 3] = color.rect & 0xff; // A
80
+ }
81
+ },
82
+ );
91
83
 
92
- // Check if this new position overlaps with any existing boxes
93
- // Function to check if a given position overlaps with any existing boxes
94
- const checkOverlap = (x: number, y: number) => {
95
- // Check against all previously processed elements
96
- return elements.slice(0, index).some((otherElement) => {
97
- // Check if the rectangles overlap
98
- return (
99
- x < otherElement.rect.left + otherElement.rect.width &&
100
- x + rectWidth > otherElement.rect.left &&
101
- y < otherElement.rect.top + otherElement.rect.height &&
102
- y + rectHeight > otherElement.rect.top
103
- );
104
- });
105
- };
84
+ // Calculate text position
85
+ const textWidth = element.indexId.toString().length * 8;
86
+ const textHeight = 12;
87
+ const rectWidth = textWidth + 5;
88
+ const rectHeight = textHeight + 4;
89
+ let rectX = paddedRect.left - rectWidth;
90
+ let rectY = paddedRect.top + paddedRect.height / 2 - textHeight / 2 - 2;
106
91
 
107
- // Function to check if a given position is within the image bounds
108
- const isWithinBounds = (x: number, y: number) => {
92
+ // Check if this new position overlaps with any existing boxes
93
+ // Function to check if a given position overlaps with any existing boxes
94
+ const checkOverlap = (x: number, y: number) => {
95
+ // Check against all previously processed elements
96
+ return elements.slice(0, index).some((otherElement) => {
97
+ // Check if the rectangles overlap
109
98
  return (
110
- x >= 0 &&
111
- x + rectWidth <= imageWidth &&
112
- y >= 0 &&
113
- y + rectHeight <= imageHeight
99
+ x < otherElement.rect.left + otherElement.rect.width &&
100
+ x + rectWidth > otherElement.rect.left &&
101
+ y < otherElement.rect.top + otherElement.rect.height &&
102
+ y + rectHeight > otherElement.rect.top
114
103
  );
115
- };
104
+ });
105
+ };
116
106
 
117
- // Check left side (original position)
118
- if (checkOverlap(rectX, rectY) || !isWithinBounds(rectX, rectY)) {
119
- // If the original position overlaps or is out of bounds, try alternative positions
107
+ // Function to check if a given position is within the image bounds
108
+ const isWithinBounds = (x: number, y: number) => {
109
+ return (
110
+ x >= 0 &&
111
+ x + rectWidth <= imageWidth &&
112
+ y >= 0 &&
113
+ y + rectHeight <= imageHeight
114
+ );
115
+ };
120
116
 
121
- // Check top position
122
- if (
123
- !checkOverlap(paddedRect.left, paddedRect.top - rectHeight - 2) &&
124
- isWithinBounds(paddedRect.left, paddedRect.top - rectHeight - 2)
125
- ) {
126
- rectX = paddedRect.left;
127
- rectY = paddedRect.top - rectHeight - 2;
128
- }
129
- // Check bottom position
130
- else if (
131
- !checkOverlap(
132
- paddedRect.left,
133
- paddedRect.top + paddedRect.height + 2,
134
- ) &&
135
- isWithinBounds(
136
- paddedRect.left,
137
- paddedRect.top + paddedRect.height + 2,
138
- )
139
- ) {
140
- rectX = paddedRect.left;
141
- rectY = paddedRect.top + paddedRect.height + 2;
142
- }
143
- // Check right position
144
- else if (
145
- !checkOverlap(
146
- paddedRect.left + paddedRect.width + 2,
147
- paddedRect.top,
148
- ) &&
149
- isWithinBounds(paddedRect.left + paddedRect.width + 2, paddedRect.top)
150
- ) {
151
- rectX = paddedRect.left + paddedRect.width + 2;
152
- rectY = paddedRect.top;
153
- }
154
- // If all sides are overlapped or out of bounds, place it inside the box at the top
155
- else {
156
- rectX = paddedRect.left;
157
- rectY = paddedRect.top + 2;
158
- }
159
- }
160
- // Note: If the original left position doesn't overlap and is within bounds, we keep it as is
117
+ // Check left side (original position)
118
+ if (checkOverlap(rectX, rectY) || !isWithinBounds(rectX, rectY)) {
119
+ // If the original position overlaps or is out of bounds, try alternative positions
161
120
 
162
- // Draw text background
163
- image.scan(rectX, rectY, rectWidth, rectHeight, function (x, y, idx) {
164
- this.bitmap.data[idx + 0] = (color.rect >> 24) & 0xff; // R
165
- this.bitmap.data[idx + 1] = (color.rect >> 16) & 0xff; // G
166
- this.bitmap.data[idx + 2] = (color.rect >> 8) & 0xff; // B
167
- this.bitmap.data[idx + 3] = color.rect & 0xff; // A
168
- });
169
- // Draw text (simplified, as Jimp doesn't have built-in text drawing)
170
- const font = await Jimp.loadFont(Jimp.FONT_SANS_16_WHITE);
171
- image.print(
172
- font,
173
- rectX,
174
- rectY,
175
- {
176
- text: element.indexId.toString(),
177
- alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER,
178
- alignmentY: Jimp.VERTICAL_ALIGN_MIDDLE,
179
- },
180
- rectWidth,
181
- rectHeight,
182
- );
121
+ // Check top position
122
+ if (
123
+ !checkOverlap(paddedRect.left, paddedRect.top - rectHeight - 2) &&
124
+ isWithinBounds(paddedRect.left, paddedRect.top - rectHeight - 2)
125
+ ) {
126
+ rectX = paddedRect.left;
127
+ rectY = paddedRect.top - rectHeight - 2;
128
+ }
129
+ // Check bottom position
130
+ else if (
131
+ !checkOverlap(
132
+ paddedRect.left,
133
+ paddedRect.top + paddedRect.height + 2,
134
+ ) &&
135
+ isWithinBounds(paddedRect.left, paddedRect.top + paddedRect.height + 2)
136
+ ) {
137
+ rectX = paddedRect.left;
138
+ rectY = paddedRect.top + paddedRect.height + 2;
139
+ }
140
+ // Check right position
141
+ else if (
142
+ !checkOverlap(paddedRect.left + paddedRect.width + 2, paddedRect.top) &&
143
+ isWithinBounds(paddedRect.left + paddedRect.width + 2, paddedRect.top)
144
+ ) {
145
+ rectX = paddedRect.left + paddedRect.width + 2;
146
+ rectY = paddedRect.top;
147
+ }
148
+ // If all sides are overlapped or out of bounds, place it inside the box at the top
149
+ else {
150
+ rectX = paddedRect.left;
151
+ rectY = paddedRect.top + 2;
152
+ }
183
153
  }
154
+ // Note: If the original left position doesn't overlap and is within bounds, we keep it as is
184
155
 
185
- return image.getBufferAsync(Jimp.MIME_PNG);
186
- };
156
+ // Draw text background
157
+ image.scan(rectX, rectY, rectWidth, rectHeight, function (x, y, idx) {
158
+ this.bitmap.data[idx + 0] = (color.rect >> 24) & 0xff; // R
159
+ this.bitmap.data[idx + 1] = (color.rect >> 16) & 0xff; // G
160
+ this.bitmap.data[idx + 2] = (color.rect >> 8) & 0xff; // B
161
+ this.bitmap.data[idx + 3] = color.rect & 0xff; // A
162
+ });
163
+ // Draw text (simplified, as Jimp doesn't have built-in text drawing)
164
+ try {
165
+ cachedFont = cachedFont || (await Jimp.loadFont(Jimp.FONT_SANS_16_WHITE));
166
+ } catch (error) {
167
+ console.error('Error loading font', error);
168
+ }
169
+ image.print(
170
+ cachedFont,
171
+ rectX,
172
+ rectY,
173
+ {
174
+ text: element.indexId.toString(),
175
+ alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER,
176
+ alignmentY: Jimp.VERTICAL_ALIGN_MIDDLE,
177
+ },
178
+ rectWidth,
179
+ rectHeight,
180
+ );
181
+ }
187
182
 
188
- return createPngOverlay(elements, imageWidth, imageHeight);
183
+ return image;
189
184
  };
190
185
 
191
186
  export const compositeElementInfoImg = async (options: {
192
187
  inputImgBase64: string;
193
188
  elementsPositionInfo: Array<ElementType>;
189
+ size?: { width: number; height: number };
194
190
  }) => {
195
- const { inputImgBase64, elementsPositionInfo } = options;
196
- const imageBuffer = Buffer.from(inputImgBase64, 'base64');
197
- const image = await Jimp.read(imageBuffer);
198
- const { width, height } = image.bitmap;
191
+ assert(options.inputImgBase64, 'inputImgBase64 is required');
192
+ let width = 0;
193
+ let height = 0;
194
+ let jimpImage: Jimp;
195
+
196
+ const Jimp = await getJimp();
197
+
198
+ if (options.size) {
199
+ width = options.size.width;
200
+ height = options.size.height;
201
+ }
202
+
203
+ if (!width || !height) {
204
+ const info = await imageInfoOfBase64(options.inputImgBase64);
205
+ width = info.width;
206
+ height = info.height;
207
+ jimpImage = info.jimpImage;
208
+ } else {
209
+ const imageBuffer = await bufferFromBase64(options.inputImgBase64);
210
+ jimpImage = await Jimp.read(imageBuffer);
211
+ }
199
212
 
200
213
  if (!width || !height) {
201
214
  throw Error('Image processing failed because width or height is undefined');
202
215
  }
203
216
 
204
- // Create svg overlay
205
- const svgOverlay = await createSvgOverlay(
206
- elementsPositionInfo,
207
- width,
208
- height,
209
- );
217
+ const { elementsPositionInfo } = options;
210
218
 
211
- return await Jimp.read(imageBuffer)
219
+ const result = await Promise.resolve(jimpImage)
212
220
  .then(async (image: Jimp) => {
221
+ // Create svg overlay
222
+ const svgOverlay = await createSvgOverlay(
223
+ elementsPositionInfo,
224
+ width,
225
+ height,
226
+ );
213
227
  const svgImage = await Jimp.read(svgOverlay);
214
- return image.composite(svgImage, 0, 0, {
228
+ const compositeImage = await image.composite(svgImage, 0, 0, {
215
229
  mode: Jimp.BLEND_SOURCE_OVER,
216
230
  opacitySource: 1,
217
231
  opacityDest: 1,
218
232
  });
233
+ return compositeImage;
219
234
  })
220
- .then((compositeImage: Jimp) => {
221
- return compositeImage.getBufferAsync(Jimp.MIME_PNG);
222
- })
223
- .then((buffer: Buffer) => {
224
- return buffer.toString('base64');
235
+ .then(async (compositeImage: Jimp) => {
236
+ const base64 = await compositeImage.getBase64Async(Jimp.MIME_PNG);
237
+ return base64;
225
238
  })
226
239
  .catch((error: unknown) => {
227
240
  throw error;
228
241
  });
242
+
243
+ return result;
229
244
  };
230
245
 
231
246
  export const processImageElementInfo = async (options: {
@@ -0,0 +1,11 @@
1
+ import type Jimp from 'jimp/browser/lib/jimp.js';
2
+
3
+ const ifInBrowser = typeof window !== 'undefined';
4
+ export default async function getJimp(): Promise<typeof Jimp> {
5
+ if (ifInBrowser) {
6
+ await import('jimp/browser/lib/jimp.js');
7
+ return (window as any).Jimp;
8
+ }
9
+ // return Jimp;
10
+ return (await import('jimp')).default;
11
+ }
package/src/img/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export {
2
2
  imageInfo,
3
3
  imageInfoOfBase64,
4
+ bufferFromBase64,
4
5
  base64Encoded,
5
6
  base64ToPngFormat,
6
7
  } from './info';
@@ -8,6 +9,7 @@ export {
8
9
  trimImage,
9
10
  calculateNewDimensions,
10
11
  resizeImg,
12
+ resizeImgBase64,
11
13
  transformImgPathToBase64,
12
14
  saveBase64Image,
13
15
  } from './transform';
package/src/img/info.ts CHANGED
@@ -1,13 +1,18 @@
1
1
  import assert from 'node:assert';
2
2
  import { Buffer } from 'node:buffer';
3
3
  import { readFileSync } from 'node:fs';
4
- import Jimp from 'jimp';
4
+ import type Jimp from 'jimp';
5
+ import getJimp from './get-jimp';
5
6
 
6
7
  export interface Size {
7
8
  width: number;
8
9
  height: number;
9
10
  }
10
11
 
12
+ export interface ImageInfo extends Size {
13
+ jimpImage: Jimp;
14
+ }
15
+
11
16
  /**
12
17
  * Retrieves the dimensions of an image asynchronously
13
18
  *
@@ -15,12 +20,17 @@ export interface Size {
15
20
  * @returns A Promise that resolves to an object containing the width and height of the image
16
21
  * @throws Error if the image data is invalid
17
22
  */
18
- export async function imageInfo(image: string | Buffer): Promise<Size> {
23
+ export async function imageInfo(
24
+ image: string | Buffer | Jimp,
25
+ ): Promise<ImageInfo> {
26
+ const Jimp = await getJimp();
19
27
  let jimpImage: Jimp;
20
28
  if (typeof image === 'string') {
21
29
  jimpImage = await Jimp.read(image);
22
30
  } else if (Buffer.isBuffer(image)) {
23
31
  jimpImage = await Jimp.read(image);
32
+ } else if (image instanceof Jimp) {
33
+ jimpImage = image;
24
34
  } else {
25
35
  throw new Error('Invalid image input: must be a string path or a Buffer');
26
36
  }
@@ -29,7 +39,7 @@ export async function imageInfo(image: string | Buffer): Promise<Size> {
29
39
  width && height,
30
40
  `Invalid image: ${typeof image === 'string' ? image : 'Buffer'}`,
31
41
  );
32
- return { width, height };
42
+ return { width, height, jimpImage };
33
43
  }
34
44
 
35
45
  /**
@@ -39,10 +49,18 @@ export async function imageInfo(image: string | Buffer): Promise<Size> {
39
49
  * @returns A Promise that resolves to an object containing the width and height of the image
40
50
  * @throws Error if the image data is invalid
41
51
  */
42
- export async function imageInfoOfBase64(imageBase64: string): Promise<Size> {
43
- const base64Data = imageBase64.replace(/^data:image\/\w+;base64,/, '');
52
+ export async function imageInfoOfBase64(
53
+ imageBase64: string,
54
+ ): Promise<ImageInfo> {
55
+ // const base64Data = imageBase64.replace(/^data:image\/\w+;base64,/, '');
44
56
  // Call the imageInfo function to get the dimensions of the image
45
- return imageInfo(Buffer.from(base64Data, 'base64'));
57
+ const buffer = await bufferFromBase64(imageBase64);
58
+ return imageInfo(buffer);
59
+ }
60
+
61
+ export async function bufferFromBase64(imageBase64: string): Promise<Buffer> {
62
+ const base64Data = imageBase64.replace(/^data:image\/\w+;base64,/, '');
63
+ return Buffer.from(base64Data, 'base64');
46
64
  }
47
65
 
48
66
  /**
@@ -0,0 +1,4 @@
1
+ declare module 'jimp/browser/lib/jimp.js' {
2
+ import Jimp from 'jimp';
3
+ export default Jimp;
4
+ }