@midscene/shared 1.10.6 → 1.10.7-beta-20260720030503.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/dist/es/cli/screenshot-file.mjs +4 -3
- package/dist/es/cli/verbose-screenshot.mjs +1 -1
- package/dist/es/env/parse-model-config.mjs +1 -1
- package/dist/es/img/canvas-fallback.mjs +7 -2
- package/dist/es/img/image-format.mjs +54 -0
- package/dist/es/img/index.mjs +3 -2
- package/dist/es/img/info.mjs +6 -2
- package/dist/es/img/transform.mjs +10 -11
- package/dist/lib/cli/screenshot-file.js +4 -3
- package/dist/lib/cli/verbose-screenshot.js +1 -1
- package/dist/lib/env/parse-model-config.js +1 -1
- package/dist/lib/img/canvas-fallback.js +7 -2
- package/dist/lib/img/image-format.js +106 -0
- package/dist/lib/img/index.js +37 -12
- package/dist/lib/img/info.js +8 -1
- package/dist/lib/img/transform.js +10 -11
- package/dist/types/agent-tools/types.d.ts +1 -1
- package/dist/types/img/image-format.d.ts +9 -0
- package/dist/types/img/index.d.ts +2 -1
- package/dist/types/img/info.d.ts +8 -2
- package/dist/types/img/transform.d.ts +2 -1
- package/package.json +1 -1
- package/src/agent-tools/types.ts +1 -1
- package/src/cli/screenshot-file.ts +10 -7
- package/src/cli/verbose-screenshot.ts +3 -1
- package/src/img/canvas-fallback.ts +12 -2
- package/src/img/image-format.ts +131 -0
- package/src/img/index.ts +12 -0
- package/src/img/info.ts +17 -3
- package/src/img/transform.ts +24 -39
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
+
import { screenshotImageFormatFromExtension, screenshotImageFormatFromMimeType } from "../img/image-format.mjs";
|
|
4
5
|
function safeScreenshotFilenamePart(value) {
|
|
5
6
|
const text = 'string' == typeof value && value.length > 0 ? value : 'shot';
|
|
6
7
|
return text.replace(/[^a-zA-Z0-9._-]/g, '_') || 'shot';
|
|
7
8
|
}
|
|
8
9
|
function extensionFromImageMetadata(mimeType, extension) {
|
|
9
|
-
|
|
10
|
-
if (
|
|
11
|
-
return
|
|
10
|
+
const extensionFormat = screenshotImageFormatFromExtension(extension);
|
|
11
|
+
if (extensionFormat) return extensionFormat;
|
|
12
|
+
return screenshotImageFormatFromMimeType(mimeType) ?? 'png';
|
|
12
13
|
}
|
|
13
14
|
function writeCliScreenshotFile(rawBase64, options = {}) {
|
|
14
15
|
const extension = extensionFromImageMetadata(options.mimeType, options.extension);
|
|
@@ -30,7 +30,7 @@ function screenshotRawBase64(value) {
|
|
|
30
30
|
const rawBase64 = getStringProperty(value, 'rawBase64');
|
|
31
31
|
if (rawBase64) return rawBase64;
|
|
32
32
|
const base64 = getStringProperty(value, 'base64');
|
|
33
|
-
const match = base64?.match(/^data:image\/(?:png|jpeg|jpg);base64,(.+)$/);
|
|
33
|
+
const match = base64?.match(/^data:image\/(?:png|jpeg|jpg|webp);base64,(.+)$/);
|
|
34
34
|
return match?.[1];
|
|
35
35
|
}
|
|
36
36
|
function inlineScreenshotCacheKey(rawBase64, serialized, directoryPath, directoryName, extension) {
|
|
@@ -5,7 +5,7 @@ import { assert } from "../utils.mjs";
|
|
|
5
5
|
import { maskConfig, parseJson } from "./helper.mjs";
|
|
6
6
|
import { initDebugConfig } from "./init-debug.mjs";
|
|
7
7
|
const MODEL_CONFIG_DOC_URL = 'https://midscenejs.com/model-common-config.html';
|
|
8
|
-
const getCurrentVersion = ()=>"1.10.
|
|
8
|
+
const getCurrentVersion = ()=>"1.10.7-beta-20260720030503.0";
|
|
9
9
|
const getInvalidModelFamilyMessage = (modelFamily)=>`Invalid MIDSCENE_MODEL_FAMILY value: ${modelFamily}. Current version v${getCurrentVersion()} accepts the following model families: ${MODEL_FAMILY_VALUES.join(', ')}. You can also visit ${MODEL_CONFIG_DOC_URL} for the latest configuration information.`;
|
|
10
10
|
const KEYS_MAP = {
|
|
11
11
|
insight: INSIGHT_MODEL_CONFIG_KEYS,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getDebug } from "../logger.mjs";
|
|
2
|
+
import { detectScreenshotImageFormatFromBuffer, inferScreenshotImageFormatFromBase64, screenshotImageMimeType } from "./image-format.mjs";
|
|
2
3
|
function _define_property(obj, key, value) {
|
|
3
4
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
4
5
|
value: value,
|
|
@@ -52,15 +53,19 @@ class CanvasImage {
|
|
|
52
53
|
reject(new Error('Failed to load image'));
|
|
53
54
|
};
|
|
54
55
|
if (base64Body.startsWith('data:')) img.src = base64Body;
|
|
55
|
-
else
|
|
56
|
+
else {
|
|
57
|
+
const format = inferScreenshotImageFormatFromBase64(base64Body) ?? 'png';
|
|
58
|
+
img.src = `data:${screenshotImageMimeType(format)};base64,${base64Body}`;
|
|
59
|
+
}
|
|
56
60
|
});
|
|
57
61
|
}
|
|
58
62
|
static async new_from_byteslice(bytes) {
|
|
59
63
|
return new Promise((resolve, reject)=>{
|
|
64
|
+
const format = detectScreenshotImageFormatFromBuffer(bytes) ?? 'png';
|
|
60
65
|
const blob = new Blob([
|
|
61
66
|
bytes
|
|
62
67
|
], {
|
|
63
|
-
type:
|
|
68
|
+
type: screenshotImageMimeType(format)
|
|
64
69
|
});
|
|
65
70
|
const url = URL.createObjectURL(blob);
|
|
66
71
|
const img = new Image();
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const mimeTypeByFormat = {
|
|
2
|
+
png: 'image/png',
|
|
3
|
+
jpeg: 'image/jpeg',
|
|
4
|
+
webp: 'image/webp'
|
|
5
|
+
};
|
|
6
|
+
function screenshotImageMimeType(format) {
|
|
7
|
+
return mimeTypeByFormat[format];
|
|
8
|
+
}
|
|
9
|
+
function screenshotImageExtension(format) {
|
|
10
|
+
return format;
|
|
11
|
+
}
|
|
12
|
+
function screenshotImageFormatFromExtension(extension) {
|
|
13
|
+
if ('string' != typeof extension) return;
|
|
14
|
+
switch(extension.toLowerCase()){
|
|
15
|
+
case 'png':
|
|
16
|
+
return 'png';
|
|
17
|
+
case 'jpeg':
|
|
18
|
+
case 'jpg':
|
|
19
|
+
return 'jpeg';
|
|
20
|
+
case 'webp':
|
|
21
|
+
return 'webp';
|
|
22
|
+
default:
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function screenshotImageFormatFromMimeType(mimeType) {
|
|
27
|
+
if ('string' != typeof mimeType) return;
|
|
28
|
+
switch(mimeType.toLowerCase()){
|
|
29
|
+
case 'image/png':
|
|
30
|
+
return 'png';
|
|
31
|
+
case 'image/jpeg':
|
|
32
|
+
case 'image/jpg':
|
|
33
|
+
return 'jpeg';
|
|
34
|
+
case 'image/webp':
|
|
35
|
+
return 'webp';
|
|
36
|
+
default:
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function isScreenshotImageMimeType(mimeType) {
|
|
41
|
+
return 'image/png' === mimeType || 'image/jpeg' === mimeType || 'image/webp' === mimeType;
|
|
42
|
+
}
|
|
43
|
+
function inferScreenshotImageFormatFromBase64(base64Body) {
|
|
44
|
+
const normalizedBody = base64Body.replace(/\s/g, '');
|
|
45
|
+
if (normalizedBody.startsWith('iVBORw0KGgo')) return 'png';
|
|
46
|
+
if (normalizedBody.startsWith('/9j/')) return 'jpeg';
|
|
47
|
+
if (normalizedBody.startsWith('UklGR')) return 'webp';
|
|
48
|
+
}
|
|
49
|
+
function detectScreenshotImageFormatFromBuffer(buffer) {
|
|
50
|
+
if (buffer.length >= 8 && 0x89 === buffer[0] && 0x50 === buffer[1] && 0x4e === buffer[2] && 0x47 === buffer[3] && 0x0d === buffer[4] && 0x0a === buffer[5] && 0x1a === buffer[6] && 0x0a === buffer[7]) return 'png';
|
|
51
|
+
if (buffer.length >= 3 && 0xff === buffer[0] && 0xd8 === buffer[1] && 0xff === buffer[2]) return 'jpeg';
|
|
52
|
+
if (buffer.length >= 12 && 0x52 === buffer[0] && 0x49 === buffer[1] && 0x46 === buffer[2] && 0x46 === buffer[3] && 0x57 === buffer[8] && 0x45 === buffer[9] && 0x42 === buffer[10] && 0x50 === buffer[11]) return 'webp';
|
|
53
|
+
}
|
|
54
|
+
export { detectScreenshotImageFormatFromBuffer, inferScreenshotImageFormatFromBase64, isScreenshotImageMimeType, screenshotImageExtension, screenshotImageFormatFromExtension, screenshotImageFormatFromMimeType, screenshotImageMimeType };
|
package/dist/es/img/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { imageInfoOfBase64, isValidImageBuffer, isValidJPEGImageBuffer, isValidPNGImageBuffer, validateScreenshotBuffer } from "./info.mjs";
|
|
1
|
+
import { imageInfoOfBase64, isValidImageBuffer, isValidJPEGImageBuffer, isValidPNGImageBuffer, isValidWebPImageBuffer, validateScreenshotBuffer } from "./info.mjs";
|
|
2
|
+
import { detectScreenshotImageFormatFromBuffer, inferScreenshotImageFormatFromBase64, isScreenshotImageMimeType, screenshotImageExtension, screenshotImageFormatFromExtension, screenshotImageFormatFromMimeType, screenshotImageMimeType } from "./image-format.mjs";
|
|
2
3
|
import { convertImgBufferToJpeg, createImgBase64ByFormat, cropByRect, httpImg2Base64, inferBase64ImageFormat, localImg2Base64, normalizeBase64Image, normalizeScreenshotBase64, paddingToMatchBlockByBase64, parseBase64, preProcessImageUrl, resizeAndConvertImgBuffer, resizeImgBase64, saveBase64Image, scaleImage, zoomForGPT4o } from "./transform.mjs";
|
|
3
4
|
import { annotateRects, compositeElementInfoImg, compositePointMarkerImg, processImageElementInfo } from "./box-select.mjs";
|
|
4
|
-
export { annotateRects, compositeElementInfoImg, compositePointMarkerImg, convertImgBufferToJpeg, createImgBase64ByFormat, cropByRect, httpImg2Base64, imageInfoOfBase64, inferBase64ImageFormat, isValidImageBuffer, isValidJPEGImageBuffer, isValidPNGImageBuffer, localImg2Base64, normalizeBase64Image, normalizeScreenshotBase64, paddingToMatchBlockByBase64, parseBase64, preProcessImageUrl, processImageElementInfo, resizeAndConvertImgBuffer, resizeImgBase64, saveBase64Image, scaleImage, validateScreenshotBuffer, zoomForGPT4o };
|
|
5
|
+
export { annotateRects, compositeElementInfoImg, compositePointMarkerImg, convertImgBufferToJpeg, createImgBase64ByFormat, cropByRect, detectScreenshotImageFormatFromBuffer, httpImg2Base64, imageInfoOfBase64, inferBase64ImageFormat, inferScreenshotImageFormatFromBase64, isScreenshotImageMimeType, isValidImageBuffer, isValidJPEGImageBuffer, isValidPNGImageBuffer, isValidWebPImageBuffer, localImg2Base64, normalizeBase64Image, normalizeScreenshotBase64, paddingToMatchBlockByBase64, parseBase64, preProcessImageUrl, processImageElementInfo, resizeAndConvertImgBuffer, resizeImgBase64, saveBase64Image, scaleImage, screenshotImageExtension, screenshotImageFormatFromExtension, screenshotImageFormatFromMimeType, screenshotImageMimeType, validateScreenshotBuffer, zoomForGPT4o };
|
package/dist/es/img/info.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import { Buffer } from "node:buffer";
|
|
|
3
3
|
import { ifInNode } from "../utils.mjs";
|
|
4
4
|
import get_photon from "./get-photon.mjs";
|
|
5
5
|
import get_sharp from "./get-sharp.mjs";
|
|
6
|
+
import { detectScreenshotImageFormatFromBuffer } from "./image-format.mjs";
|
|
6
7
|
async function imageInfoOfBase64(imageBase64) {
|
|
7
8
|
const base64Data = imageBase64.replace(/^data:image\/\w+;base64,/, '').replace(/\s/g, '');
|
|
8
9
|
node_assert(base64Data, 'Invalid image: empty base64 data');
|
|
@@ -68,8 +69,11 @@ function isValidJPEGImageBuffer(buffer) {
|
|
|
68
69
|
if (!buffer || buffer.length < 3) return false;
|
|
69
70
|
return 0xff === buffer[0] && 0xd8 === buffer[1] && 0xff === buffer[2];
|
|
70
71
|
}
|
|
72
|
+
function isValidWebPImageBuffer(buffer) {
|
|
73
|
+
return 'webp' === detectScreenshotImageFormatFromBuffer(buffer);
|
|
74
|
+
}
|
|
71
75
|
function isValidImageBuffer(buffer) {
|
|
72
|
-
return isValidPNGImageBuffer(buffer) || isValidJPEGImageBuffer(buffer);
|
|
76
|
+
return isValidPNGImageBuffer(buffer) || isValidJPEGImageBuffer(buffer) || isValidWebPImageBuffer(buffer);
|
|
73
77
|
}
|
|
74
78
|
function validateScreenshotBuffer(screenshotBuffer, { label, minBufferSize = 0 }) {
|
|
75
79
|
const bufferSize = screenshotBuffer?.length ?? 0;
|
|
@@ -77,4 +81,4 @@ function validateScreenshotBuffer(screenshotBuffer, { label, minBufferSize = 0 }
|
|
|
77
81
|
if (!isValidImageBuffer(screenshotBuffer)) throw new Error(`${label} buffer has invalid image format`);
|
|
78
82
|
if (minBufferSize > 0 && bufferSize < minBufferSize) throw new Error(`${label} validation failed: buffer size ${bufferSize} bytes (minimum: ${minBufferSize})`);
|
|
79
83
|
}
|
|
80
|
-
export { imageInfoOfBase64, isValidImageBuffer, isValidJPEGImageBuffer, isValidPNGImageBuffer, validateScreenshotBuffer };
|
|
84
|
+
export { imageInfoOfBase64, isValidImageBuffer, isValidJPEGImageBuffer, isValidPNGImageBuffer, isValidWebPImageBuffer, validateScreenshotBuffer };
|
|
@@ -7,6 +7,7 @@ import { getDebug } from "../logger.mjs";
|
|
|
7
7
|
import { ifInNode } from "../utils.mjs";
|
|
8
8
|
import get_photon from "./get-photon.mjs";
|
|
9
9
|
import get_sharp from "./get-sharp.mjs";
|
|
10
|
+
import { detectScreenshotImageFormatFromBuffer, inferScreenshotImageFormatFromBase64, screenshotImageMimeType } from "./image-format.mjs";
|
|
10
11
|
const imgDebug = getDebug('img');
|
|
11
12
|
async function saveBase64Image(options) {
|
|
12
13
|
const { base64Data, outputPath } = options;
|
|
@@ -86,17 +87,13 @@ async function convertImgBufferToJpeg(inputData, quality = 90) {
|
|
|
86
87
|
}
|
|
87
88
|
}
|
|
88
89
|
const base64ImageDataUrlPattern = /^data:image\/[a-zA-Z0-9.+-]+;base64,/i;
|
|
89
|
-
const supportedScreenshotDataUriPattern = /^data:image\/(png|jpe?g);base64,([\s\S]*)$/i;
|
|
90
|
+
const supportedScreenshotDataUriPattern = /^data:image\/(png|jpe?g|webp);base64,([\s\S]*)$/i;
|
|
90
91
|
const rawBase64BodyPattern = /^[A-Za-z0-9+/=\s]+$/;
|
|
91
|
-
const inferBase64ImageFormat = (base64Body)=>
|
|
92
|
-
if (base64Body.startsWith('iVBORw0KGgo')) return 'png';
|
|
93
|
-
return 'jpeg';
|
|
94
|
-
};
|
|
92
|
+
const inferBase64ImageFormat = (base64Body)=>inferScreenshotImageFormatFromBase64(base64Body) ?? 'jpeg';
|
|
95
93
|
function detectImageMimeTypeFromBuffer(buffer) {
|
|
96
|
-
|
|
97
|
-
if (
|
|
94
|
+
const screenshotFormat = detectScreenshotImageFormatFromBuffer(buffer);
|
|
95
|
+
if (screenshotFormat) return screenshotImageMimeType(screenshotFormat);
|
|
98
96
|
if (buffer.length >= 6 && 'GIF' === buffer.subarray(0, 3).toString('ascii')) return 'image/gif';
|
|
99
|
-
if (buffer.length >= 12 && 'RIFF' === buffer.subarray(0, 4).toString('ascii') && 'WEBP' === buffer.subarray(8, 12).toString('ascii')) return 'image/webp';
|
|
100
97
|
if (buffer.length >= 2 && 0x42 === buffer[0] && 0x4d === buffer[1]) return 'image/bmp';
|
|
101
98
|
}
|
|
102
99
|
const createImgBase64ByFormat = (format, body)=>`data:image/${format};base64,${normalizeBase64Body(body)}`;
|
|
@@ -111,9 +108,11 @@ const normalizeScreenshotBase64 = (base64, options)=>{
|
|
|
111
108
|
if (!normalizeBase64Body(body)) throw new Error(`${label} cannot be empty`);
|
|
112
109
|
return createImgBase64ByFormat(imageFormat, body);
|
|
113
110
|
}
|
|
114
|
-
if (trimmedBase64.startsWith('data:')) throw new Error(`${label} must be a PNG/JPEG data URI or raw PNG base64 string`);
|
|
115
|
-
if (!rawBase64BodyPattern.test(trimmedBase64)) throw new Error(`${label} must be a PNG/JPEG data URI or raw PNG base64 string`);
|
|
116
|
-
|
|
111
|
+
if (trimmedBase64.startsWith('data:')) throw new Error(`${label} must be a PNG/JPEG/WebP data URI or raw PNG/WebP base64 string`);
|
|
112
|
+
if (!rawBase64BodyPattern.test(trimmedBase64)) throw new Error(`${label} must be a PNG/JPEG/WebP data URI or raw PNG/WebP base64 string`);
|
|
113
|
+
const base64Body = normalizeBase64Body(trimmedBase64);
|
|
114
|
+
const inferredFormat = inferScreenshotImageFormatFromBase64(base64Body);
|
|
115
|
+
return createImgBase64ByFormat('webp' === inferredFormat ? 'webp' : 'png', base64Body);
|
|
117
116
|
};
|
|
118
117
|
const normalizeBase64Image = (base64)=>{
|
|
119
118
|
const trimmedBase64 = base64.trim();
|
|
@@ -29,14 +29,15 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
29
29
|
const external_node_fs_namespaceObject = require("node:fs");
|
|
30
30
|
const external_node_os_namespaceObject = require("node:os");
|
|
31
31
|
const external_node_path_namespaceObject = require("node:path");
|
|
32
|
+
const image_format_js_namespaceObject = require("../img/image-format.js");
|
|
32
33
|
function safeScreenshotFilenamePart(value) {
|
|
33
34
|
const text = 'string' == typeof value && value.length > 0 ? value : 'shot';
|
|
34
35
|
return text.replace(/[^a-zA-Z0-9._-]/g, '_') || 'shot';
|
|
35
36
|
}
|
|
36
37
|
function extensionFromImageMetadata(mimeType, extension) {
|
|
37
|
-
|
|
38
|
-
if (
|
|
39
|
-
return
|
|
38
|
+
const extensionFormat = (0, image_format_js_namespaceObject.screenshotImageFormatFromExtension)(extension);
|
|
39
|
+
if (extensionFormat) return extensionFormat;
|
|
40
|
+
return (0, image_format_js_namespaceObject.screenshotImageFormatFromMimeType)(mimeType) ?? 'png';
|
|
40
41
|
}
|
|
41
42
|
function writeCliScreenshotFile(rawBase64, options = {}) {
|
|
42
43
|
const extension = extensionFromImageMetadata(options.mimeType, options.extension);
|
|
@@ -61,7 +61,7 @@ function screenshotRawBase64(value) {
|
|
|
61
61
|
const rawBase64 = getStringProperty(value, 'rawBase64');
|
|
62
62
|
if (rawBase64) return rawBase64;
|
|
63
63
|
const base64 = getStringProperty(value, 'base64');
|
|
64
|
-
const match = base64?.match(/^data:image\/(?:png|jpeg|jpg);base64,(.+)$/);
|
|
64
|
+
const match = base64?.match(/^data:image\/(?:png|jpeg|jpg|webp);base64,(.+)$/);
|
|
65
65
|
return match?.[1];
|
|
66
66
|
}
|
|
67
67
|
function inlineScreenshotCacheKey(rawBase64, serialized, directoryPath, directoryName, extension) {
|
|
@@ -37,7 +37,7 @@ const external_utils_js_namespaceObject = require("../utils.js");
|
|
|
37
37
|
const external_helper_js_namespaceObject = require("./helper.js");
|
|
38
38
|
const external_init_debug_js_namespaceObject = require("./init-debug.js");
|
|
39
39
|
const MODEL_CONFIG_DOC_URL = 'https://midscenejs.com/model-common-config.html';
|
|
40
|
-
const getCurrentVersion = ()=>"1.10.
|
|
40
|
+
const getCurrentVersion = ()=>"1.10.7-beta-20260720030503.0";
|
|
41
41
|
const getInvalidModelFamilyMessage = (modelFamily)=>`Invalid MIDSCENE_MODEL_FAMILY value: ${modelFamily}. Current version v${getCurrentVersion()} accepts the following model families: ${external_types_js_namespaceObject.MODEL_FAMILY_VALUES.join(', ')}. You can also visit ${MODEL_CONFIG_DOC_URL} for the latest configuration information.`;
|
|
42
42
|
const KEYS_MAP = {
|
|
43
43
|
insight: external_constants_js_namespaceObject.INSIGHT_MODEL_CONFIG_KEYS,
|
|
@@ -38,6 +38,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
38
38
|
canvasWatermark: ()=>canvasWatermark
|
|
39
39
|
});
|
|
40
40
|
const external_logger_js_namespaceObject = require("../logger.js");
|
|
41
|
+
const external_image_format_js_namespaceObject = require("./image-format.js");
|
|
41
42
|
function _define_property(obj, key, value) {
|
|
42
43
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
43
44
|
value: value,
|
|
@@ -91,15 +92,19 @@ class CanvasImage {
|
|
|
91
92
|
reject(new Error('Failed to load image'));
|
|
92
93
|
};
|
|
93
94
|
if (base64Body.startsWith('data:')) img.src = base64Body;
|
|
94
|
-
else
|
|
95
|
+
else {
|
|
96
|
+
const format = (0, external_image_format_js_namespaceObject.inferScreenshotImageFormatFromBase64)(base64Body) ?? 'png';
|
|
97
|
+
img.src = `data:${(0, external_image_format_js_namespaceObject.screenshotImageMimeType)(format)};base64,${base64Body}`;
|
|
98
|
+
}
|
|
95
99
|
});
|
|
96
100
|
}
|
|
97
101
|
static async new_from_byteslice(bytes) {
|
|
98
102
|
return new Promise((resolve, reject)=>{
|
|
103
|
+
const format = (0, external_image_format_js_namespaceObject.detectScreenshotImageFormatFromBuffer)(bytes) ?? 'png';
|
|
99
104
|
const blob = new Blob([
|
|
100
105
|
bytes
|
|
101
106
|
], {
|
|
102
|
-
type:
|
|
107
|
+
type: (0, external_image_format_js_namespaceObject.screenshotImageMimeType)(format)
|
|
103
108
|
});
|
|
104
109
|
const url = URL.createObjectURL(blob);
|
|
105
110
|
const img = new Image();
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
var __webpack_exports__ = {};
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
detectScreenshotImageFormatFromBuffer: ()=>detectScreenshotImageFormatFromBuffer,
|
|
28
|
+
inferScreenshotImageFormatFromBase64: ()=>inferScreenshotImageFormatFromBase64,
|
|
29
|
+
isScreenshotImageMimeType: ()=>isScreenshotImageMimeType,
|
|
30
|
+
screenshotImageExtension: ()=>screenshotImageExtension,
|
|
31
|
+
screenshotImageFormatFromExtension: ()=>screenshotImageFormatFromExtension,
|
|
32
|
+
screenshotImageFormatFromMimeType: ()=>screenshotImageFormatFromMimeType,
|
|
33
|
+
screenshotImageMimeType: ()=>screenshotImageMimeType
|
|
34
|
+
});
|
|
35
|
+
const mimeTypeByFormat = {
|
|
36
|
+
png: 'image/png',
|
|
37
|
+
jpeg: 'image/jpeg',
|
|
38
|
+
webp: 'image/webp'
|
|
39
|
+
};
|
|
40
|
+
function screenshotImageMimeType(format) {
|
|
41
|
+
return mimeTypeByFormat[format];
|
|
42
|
+
}
|
|
43
|
+
function screenshotImageExtension(format) {
|
|
44
|
+
return format;
|
|
45
|
+
}
|
|
46
|
+
function screenshotImageFormatFromExtension(extension) {
|
|
47
|
+
if ('string' != typeof extension) return;
|
|
48
|
+
switch(extension.toLowerCase()){
|
|
49
|
+
case 'png':
|
|
50
|
+
return 'png';
|
|
51
|
+
case 'jpeg':
|
|
52
|
+
case 'jpg':
|
|
53
|
+
return 'jpeg';
|
|
54
|
+
case 'webp':
|
|
55
|
+
return 'webp';
|
|
56
|
+
default:
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function screenshotImageFormatFromMimeType(mimeType) {
|
|
61
|
+
if ('string' != typeof mimeType) return;
|
|
62
|
+
switch(mimeType.toLowerCase()){
|
|
63
|
+
case 'image/png':
|
|
64
|
+
return 'png';
|
|
65
|
+
case 'image/jpeg':
|
|
66
|
+
case 'image/jpg':
|
|
67
|
+
return 'jpeg';
|
|
68
|
+
case 'image/webp':
|
|
69
|
+
return 'webp';
|
|
70
|
+
default:
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function isScreenshotImageMimeType(mimeType) {
|
|
75
|
+
return 'image/png' === mimeType || 'image/jpeg' === mimeType || 'image/webp' === mimeType;
|
|
76
|
+
}
|
|
77
|
+
function inferScreenshotImageFormatFromBase64(base64Body) {
|
|
78
|
+
const normalizedBody = base64Body.replace(/\s/g, '');
|
|
79
|
+
if (normalizedBody.startsWith('iVBORw0KGgo')) return 'png';
|
|
80
|
+
if (normalizedBody.startsWith('/9j/')) return 'jpeg';
|
|
81
|
+
if (normalizedBody.startsWith('UklGR')) return 'webp';
|
|
82
|
+
}
|
|
83
|
+
function detectScreenshotImageFormatFromBuffer(buffer) {
|
|
84
|
+
if (buffer.length >= 8 && 0x89 === buffer[0] && 0x50 === buffer[1] && 0x4e === buffer[2] && 0x47 === buffer[3] && 0x0d === buffer[4] && 0x0a === buffer[5] && 0x1a === buffer[6] && 0x0a === buffer[7]) return 'png';
|
|
85
|
+
if (buffer.length >= 3 && 0xff === buffer[0] && 0xd8 === buffer[1] && 0xff === buffer[2]) return 'jpeg';
|
|
86
|
+
if (buffer.length >= 12 && 0x52 === buffer[0] && 0x49 === buffer[1] && 0x46 === buffer[2] && 0x46 === buffer[3] && 0x57 === buffer[8] && 0x45 === buffer[9] && 0x42 === buffer[10] && 0x50 === buffer[11]) return 'webp';
|
|
87
|
+
}
|
|
88
|
+
exports.detectScreenshotImageFormatFromBuffer = __webpack_exports__.detectScreenshotImageFormatFromBuffer;
|
|
89
|
+
exports.inferScreenshotImageFormatFromBase64 = __webpack_exports__.inferScreenshotImageFormatFromBase64;
|
|
90
|
+
exports.isScreenshotImageMimeType = __webpack_exports__.isScreenshotImageMimeType;
|
|
91
|
+
exports.screenshotImageExtension = __webpack_exports__.screenshotImageExtension;
|
|
92
|
+
exports.screenshotImageFormatFromExtension = __webpack_exports__.screenshotImageFormatFromExtension;
|
|
93
|
+
exports.screenshotImageFormatFromMimeType = __webpack_exports__.screenshotImageFormatFromMimeType;
|
|
94
|
+
exports.screenshotImageMimeType = __webpack_exports__.screenshotImageMimeType;
|
|
95
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
96
|
+
"detectScreenshotImageFormatFromBuffer",
|
|
97
|
+
"inferScreenshotImageFormatFromBase64",
|
|
98
|
+
"isScreenshotImageMimeType",
|
|
99
|
+
"screenshotImageExtension",
|
|
100
|
+
"screenshotImageFormatFromExtension",
|
|
101
|
+
"screenshotImageFormatFromMimeType",
|
|
102
|
+
"screenshotImageMimeType"
|
|
103
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
104
|
+
Object.defineProperty(exports, '__esModule', {
|
|
105
|
+
value: true
|
|
106
|
+
});
|
package/dist/lib/img/index.js
CHANGED
|
@@ -25,32 +25,41 @@ var __webpack_exports__ = {};
|
|
|
25
25
|
__webpack_require__.r(__webpack_exports__);
|
|
26
26
|
__webpack_require__.d(__webpack_exports__, {
|
|
27
27
|
convertImgBufferToJpeg: ()=>external_transform_js_namespaceObject.convertImgBufferToJpeg,
|
|
28
|
-
|
|
29
|
-
localImg2Base64: ()=>external_transform_js_namespaceObject.localImg2Base64,
|
|
28
|
+
detectScreenshotImageFormatFromBuffer: ()=>external_image_format_js_namespaceObject.detectScreenshotImageFormatFromBuffer,
|
|
30
29
|
paddingToMatchBlockByBase64: ()=>external_transform_js_namespaceObject.paddingToMatchBlockByBase64,
|
|
31
|
-
parseBase64: ()=>external_transform_js_namespaceObject.parseBase64,
|
|
32
|
-
resizeAndConvertImgBuffer: ()=>external_transform_js_namespaceObject.resizeAndConvertImgBuffer,
|
|
33
30
|
resizeImgBase64: ()=>external_transform_js_namespaceObject.resizeImgBase64,
|
|
34
31
|
saveBase64Image: ()=>external_transform_js_namespaceObject.saveBase64Image,
|
|
35
32
|
isValidImageBuffer: ()=>external_info_js_namespaceObject.isValidImageBuffer,
|
|
36
33
|
validateScreenshotBuffer: ()=>external_info_js_namespaceObject.validateScreenshotBuffer,
|
|
37
|
-
normalizeScreenshotBase64: ()=>external_transform_js_namespaceObject.normalizeScreenshotBase64,
|
|
38
34
|
preProcessImageUrl: ()=>external_transform_js_namespaceObject.preProcessImageUrl,
|
|
39
|
-
annotateRects: ()=>external_box_select_js_namespaceObject.annotateRects,
|
|
40
|
-
compositeElementInfoImg: ()=>external_box_select_js_namespaceObject.compositeElementInfoImg,
|
|
41
|
-
isValidPNGImageBuffer: ()=>external_info_js_namespaceObject.isValidPNGImageBuffer,
|
|
42
|
-
normalizeBase64Image: ()=>external_transform_js_namespaceObject.normalizeBase64Image,
|
|
43
|
-
compositePointMarkerImg: ()=>external_box_select_js_namespaceObject.compositePointMarkerImg,
|
|
44
35
|
cropByRect: ()=>external_transform_js_namespaceObject.cropByRect,
|
|
45
|
-
|
|
36
|
+
compositeElementInfoImg: ()=>external_box_select_js_namespaceObject.compositeElementInfoImg,
|
|
46
37
|
processImageElementInfo: ()=>external_box_select_js_namespaceObject.processImageElementInfo,
|
|
38
|
+
normalizeBase64Image: ()=>external_transform_js_namespaceObject.normalizeBase64Image,
|
|
47
39
|
scaleImage: ()=>external_transform_js_namespaceObject.scaleImage,
|
|
48
40
|
zoomForGPT4o: ()=>external_transform_js_namespaceObject.zoomForGPT4o,
|
|
49
41
|
createImgBase64ByFormat: ()=>external_transform_js_namespaceObject.createImgBase64ByFormat,
|
|
50
42
|
imageInfoOfBase64: ()=>external_info_js_namespaceObject.imageInfoOfBase64,
|
|
51
|
-
httpImg2Base64: ()=>external_transform_js_namespaceObject.httpImg2Base64
|
|
43
|
+
httpImg2Base64: ()=>external_transform_js_namespaceObject.httpImg2Base64,
|
|
44
|
+
inferBase64ImageFormat: ()=>external_transform_js_namespaceObject.inferBase64ImageFormat,
|
|
45
|
+
localImg2Base64: ()=>external_transform_js_namespaceObject.localImg2Base64,
|
|
46
|
+
screenshotImageFormatFromMimeType: ()=>external_image_format_js_namespaceObject.screenshotImageFormatFromMimeType,
|
|
47
|
+
isValidWebPImageBuffer: ()=>external_info_js_namespaceObject.isValidWebPImageBuffer,
|
|
48
|
+
isScreenshotImageMimeType: ()=>external_image_format_js_namespaceObject.isScreenshotImageMimeType,
|
|
49
|
+
parseBase64: ()=>external_transform_js_namespaceObject.parseBase64,
|
|
50
|
+
resizeAndConvertImgBuffer: ()=>external_transform_js_namespaceObject.resizeAndConvertImgBuffer,
|
|
51
|
+
normalizeScreenshotBase64: ()=>external_transform_js_namespaceObject.normalizeScreenshotBase64,
|
|
52
|
+
annotateRects: ()=>external_box_select_js_namespaceObject.annotateRects,
|
|
53
|
+
isValidPNGImageBuffer: ()=>external_info_js_namespaceObject.isValidPNGImageBuffer,
|
|
54
|
+
screenshotImageFormatFromExtension: ()=>external_image_format_js_namespaceObject.screenshotImageFormatFromExtension,
|
|
55
|
+
compositePointMarkerImg: ()=>external_box_select_js_namespaceObject.compositePointMarkerImg,
|
|
56
|
+
isValidJPEGImageBuffer: ()=>external_info_js_namespaceObject.isValidJPEGImageBuffer,
|
|
57
|
+
screenshotImageExtension: ()=>external_image_format_js_namespaceObject.screenshotImageExtension,
|
|
58
|
+
screenshotImageMimeType: ()=>external_image_format_js_namespaceObject.screenshotImageMimeType,
|
|
59
|
+
inferScreenshotImageFormatFromBase64: ()=>external_image_format_js_namespaceObject.inferScreenshotImageFormatFromBase64
|
|
52
60
|
});
|
|
53
61
|
const external_info_js_namespaceObject = require("./info.js");
|
|
62
|
+
const external_image_format_js_namespaceObject = require("./image-format.js");
|
|
54
63
|
const external_transform_js_namespaceObject = require("./transform.js");
|
|
55
64
|
const external_box_select_js_namespaceObject = require("./box-select.js");
|
|
56
65
|
exports.annotateRects = __webpack_exports__.annotateRects;
|
|
@@ -59,12 +68,16 @@ exports.compositePointMarkerImg = __webpack_exports__.compositePointMarkerImg;
|
|
|
59
68
|
exports.convertImgBufferToJpeg = __webpack_exports__.convertImgBufferToJpeg;
|
|
60
69
|
exports.createImgBase64ByFormat = __webpack_exports__.createImgBase64ByFormat;
|
|
61
70
|
exports.cropByRect = __webpack_exports__.cropByRect;
|
|
71
|
+
exports.detectScreenshotImageFormatFromBuffer = __webpack_exports__.detectScreenshotImageFormatFromBuffer;
|
|
62
72
|
exports.httpImg2Base64 = __webpack_exports__.httpImg2Base64;
|
|
63
73
|
exports.imageInfoOfBase64 = __webpack_exports__.imageInfoOfBase64;
|
|
64
74
|
exports.inferBase64ImageFormat = __webpack_exports__.inferBase64ImageFormat;
|
|
75
|
+
exports.inferScreenshotImageFormatFromBase64 = __webpack_exports__.inferScreenshotImageFormatFromBase64;
|
|
76
|
+
exports.isScreenshotImageMimeType = __webpack_exports__.isScreenshotImageMimeType;
|
|
65
77
|
exports.isValidImageBuffer = __webpack_exports__.isValidImageBuffer;
|
|
66
78
|
exports.isValidJPEGImageBuffer = __webpack_exports__.isValidJPEGImageBuffer;
|
|
67
79
|
exports.isValidPNGImageBuffer = __webpack_exports__.isValidPNGImageBuffer;
|
|
80
|
+
exports.isValidWebPImageBuffer = __webpack_exports__.isValidWebPImageBuffer;
|
|
68
81
|
exports.localImg2Base64 = __webpack_exports__.localImg2Base64;
|
|
69
82
|
exports.normalizeBase64Image = __webpack_exports__.normalizeBase64Image;
|
|
70
83
|
exports.normalizeScreenshotBase64 = __webpack_exports__.normalizeScreenshotBase64;
|
|
@@ -76,6 +89,10 @@ exports.resizeAndConvertImgBuffer = __webpack_exports__.resizeAndConvertImgBuffe
|
|
|
76
89
|
exports.resizeImgBase64 = __webpack_exports__.resizeImgBase64;
|
|
77
90
|
exports.saveBase64Image = __webpack_exports__.saveBase64Image;
|
|
78
91
|
exports.scaleImage = __webpack_exports__.scaleImage;
|
|
92
|
+
exports.screenshotImageExtension = __webpack_exports__.screenshotImageExtension;
|
|
93
|
+
exports.screenshotImageFormatFromExtension = __webpack_exports__.screenshotImageFormatFromExtension;
|
|
94
|
+
exports.screenshotImageFormatFromMimeType = __webpack_exports__.screenshotImageFormatFromMimeType;
|
|
95
|
+
exports.screenshotImageMimeType = __webpack_exports__.screenshotImageMimeType;
|
|
79
96
|
exports.validateScreenshotBuffer = __webpack_exports__.validateScreenshotBuffer;
|
|
80
97
|
exports.zoomForGPT4o = __webpack_exports__.zoomForGPT4o;
|
|
81
98
|
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
@@ -85,12 +102,16 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
|
85
102
|
"convertImgBufferToJpeg",
|
|
86
103
|
"createImgBase64ByFormat",
|
|
87
104
|
"cropByRect",
|
|
105
|
+
"detectScreenshotImageFormatFromBuffer",
|
|
88
106
|
"httpImg2Base64",
|
|
89
107
|
"imageInfoOfBase64",
|
|
90
108
|
"inferBase64ImageFormat",
|
|
109
|
+
"inferScreenshotImageFormatFromBase64",
|
|
110
|
+
"isScreenshotImageMimeType",
|
|
91
111
|
"isValidImageBuffer",
|
|
92
112
|
"isValidJPEGImageBuffer",
|
|
93
113
|
"isValidPNGImageBuffer",
|
|
114
|
+
"isValidWebPImageBuffer",
|
|
94
115
|
"localImg2Base64",
|
|
95
116
|
"normalizeBase64Image",
|
|
96
117
|
"normalizeScreenshotBase64",
|
|
@@ -102,6 +123,10 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
|
102
123
|
"resizeImgBase64",
|
|
103
124
|
"saveBase64Image",
|
|
104
125
|
"scaleImage",
|
|
126
|
+
"screenshotImageExtension",
|
|
127
|
+
"screenshotImageFormatFromExtension",
|
|
128
|
+
"screenshotImageFormatFromMimeType",
|
|
129
|
+
"screenshotImageMimeType",
|
|
105
130
|
"validateScreenshotBuffer",
|
|
106
131
|
"zoomForGPT4o"
|
|
107
132
|
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
package/dist/lib/img/info.js
CHANGED
|
@@ -36,6 +36,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
36
36
|
isValidPNGImageBuffer: ()=>isValidPNGImageBuffer,
|
|
37
37
|
isValidImageBuffer: ()=>isValidImageBuffer,
|
|
38
38
|
validateScreenshotBuffer: ()=>validateScreenshotBuffer,
|
|
39
|
+
isValidWebPImageBuffer: ()=>isValidWebPImageBuffer,
|
|
39
40
|
imageInfoOfBase64: ()=>imageInfoOfBase64,
|
|
40
41
|
isValidJPEGImageBuffer: ()=>isValidJPEGImageBuffer
|
|
41
42
|
});
|
|
@@ -47,6 +48,7 @@ const external_get_photon_js_namespaceObject = require("./get-photon.js");
|
|
|
47
48
|
var external_get_photon_js_default = /*#__PURE__*/ __webpack_require__.n(external_get_photon_js_namespaceObject);
|
|
48
49
|
const external_get_sharp_js_namespaceObject = require("./get-sharp.js");
|
|
49
50
|
var external_get_sharp_js_default = /*#__PURE__*/ __webpack_require__.n(external_get_sharp_js_namespaceObject);
|
|
51
|
+
const external_image_format_js_namespaceObject = require("./image-format.js");
|
|
50
52
|
async function imageInfoOfBase64(imageBase64) {
|
|
51
53
|
const base64Data = imageBase64.replace(/^data:image\/\w+;base64,/, '').replace(/\s/g, '');
|
|
52
54
|
external_node_assert_default()(base64Data, 'Invalid image: empty base64 data');
|
|
@@ -112,8 +114,11 @@ function isValidJPEGImageBuffer(buffer) {
|
|
|
112
114
|
if (!buffer || buffer.length < 3) return false;
|
|
113
115
|
return 0xff === buffer[0] && 0xd8 === buffer[1] && 0xff === buffer[2];
|
|
114
116
|
}
|
|
117
|
+
function isValidWebPImageBuffer(buffer) {
|
|
118
|
+
return 'webp' === (0, external_image_format_js_namespaceObject.detectScreenshotImageFormatFromBuffer)(buffer);
|
|
119
|
+
}
|
|
115
120
|
function isValidImageBuffer(buffer) {
|
|
116
|
-
return isValidPNGImageBuffer(buffer) || isValidJPEGImageBuffer(buffer);
|
|
121
|
+
return isValidPNGImageBuffer(buffer) || isValidJPEGImageBuffer(buffer) || isValidWebPImageBuffer(buffer);
|
|
117
122
|
}
|
|
118
123
|
function validateScreenshotBuffer(screenshotBuffer, { label, minBufferSize = 0 }) {
|
|
119
124
|
const bufferSize = screenshotBuffer?.length ?? 0;
|
|
@@ -125,12 +130,14 @@ exports.imageInfoOfBase64 = __webpack_exports__.imageInfoOfBase64;
|
|
|
125
130
|
exports.isValidImageBuffer = __webpack_exports__.isValidImageBuffer;
|
|
126
131
|
exports.isValidJPEGImageBuffer = __webpack_exports__.isValidJPEGImageBuffer;
|
|
127
132
|
exports.isValidPNGImageBuffer = __webpack_exports__.isValidPNGImageBuffer;
|
|
133
|
+
exports.isValidWebPImageBuffer = __webpack_exports__.isValidWebPImageBuffer;
|
|
128
134
|
exports.validateScreenshotBuffer = __webpack_exports__.validateScreenshotBuffer;
|
|
129
135
|
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
130
136
|
"imageInfoOfBase64",
|
|
131
137
|
"isValidImageBuffer",
|
|
132
138
|
"isValidJPEGImageBuffer",
|
|
133
139
|
"isValidPNGImageBuffer",
|
|
140
|
+
"isValidWebPImageBuffer",
|
|
134
141
|
"validateScreenshotBuffer"
|
|
135
142
|
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
136
143
|
Object.defineProperty(exports, '__esModule', {
|
|
@@ -67,6 +67,7 @@ const external_get_photon_js_namespaceObject = require("./get-photon.js");
|
|
|
67
67
|
var external_get_photon_js_default = /*#__PURE__*/ __webpack_require__.n(external_get_photon_js_namespaceObject);
|
|
68
68
|
const external_get_sharp_js_namespaceObject = require("./get-sharp.js");
|
|
69
69
|
var external_get_sharp_js_default = /*#__PURE__*/ __webpack_require__.n(external_get_sharp_js_namespaceObject);
|
|
70
|
+
const external_image_format_js_namespaceObject = require("./image-format.js");
|
|
70
71
|
const imgDebug = (0, external_logger_js_namespaceObject.getDebug)('img');
|
|
71
72
|
async function saveBase64Image(options) {
|
|
72
73
|
const { base64Data, outputPath } = options;
|
|
@@ -146,17 +147,13 @@ async function convertImgBufferToJpeg(inputData, quality = 90) {
|
|
|
146
147
|
}
|
|
147
148
|
}
|
|
148
149
|
const base64ImageDataUrlPattern = /^data:image\/[a-zA-Z0-9.+-]+;base64,/i;
|
|
149
|
-
const supportedScreenshotDataUriPattern = /^data:image\/(png|jpe?g);base64,([\s\S]*)$/i;
|
|
150
|
+
const supportedScreenshotDataUriPattern = /^data:image\/(png|jpe?g|webp);base64,([\s\S]*)$/i;
|
|
150
151
|
const rawBase64BodyPattern = /^[A-Za-z0-9+/=\s]+$/;
|
|
151
|
-
const inferBase64ImageFormat = (base64Body)=>
|
|
152
|
-
if (base64Body.startsWith('iVBORw0KGgo')) return 'png';
|
|
153
|
-
return 'jpeg';
|
|
154
|
-
};
|
|
152
|
+
const inferBase64ImageFormat = (base64Body)=>(0, external_image_format_js_namespaceObject.inferScreenshotImageFormatFromBase64)(base64Body) ?? 'jpeg';
|
|
155
153
|
function detectImageMimeTypeFromBuffer(buffer) {
|
|
156
|
-
|
|
157
|
-
if (
|
|
154
|
+
const screenshotFormat = (0, external_image_format_js_namespaceObject.detectScreenshotImageFormatFromBuffer)(buffer);
|
|
155
|
+
if (screenshotFormat) return (0, external_image_format_js_namespaceObject.screenshotImageMimeType)(screenshotFormat);
|
|
158
156
|
if (buffer.length >= 6 && 'GIF' === buffer.subarray(0, 3).toString('ascii')) return 'image/gif';
|
|
159
|
-
if (buffer.length >= 12 && 'RIFF' === buffer.subarray(0, 4).toString('ascii') && 'WEBP' === buffer.subarray(8, 12).toString('ascii')) return 'image/webp';
|
|
160
157
|
if (buffer.length >= 2 && 0x42 === buffer[0] && 0x4d === buffer[1]) return 'image/bmp';
|
|
161
158
|
}
|
|
162
159
|
const createImgBase64ByFormat = (format, body)=>`data:image/${format};base64,${normalizeBase64Body(body)}`;
|
|
@@ -171,9 +168,11 @@ const normalizeScreenshotBase64 = (base64, options)=>{
|
|
|
171
168
|
if (!normalizeBase64Body(body)) throw new Error(`${label} cannot be empty`);
|
|
172
169
|
return createImgBase64ByFormat(imageFormat, body);
|
|
173
170
|
}
|
|
174
|
-
if (trimmedBase64.startsWith('data:')) throw new Error(`${label} must be a PNG/JPEG data URI or raw PNG base64 string`);
|
|
175
|
-
if (!rawBase64BodyPattern.test(trimmedBase64)) throw new Error(`${label} must be a PNG/JPEG data URI or raw PNG base64 string`);
|
|
176
|
-
|
|
171
|
+
if (trimmedBase64.startsWith('data:')) throw new Error(`${label} must be a PNG/JPEG/WebP data URI or raw PNG/WebP base64 string`);
|
|
172
|
+
if (!rawBase64BodyPattern.test(trimmedBase64)) throw new Error(`${label} must be a PNG/JPEG/WebP data URI or raw PNG/WebP base64 string`);
|
|
173
|
+
const base64Body = normalizeBase64Body(trimmedBase64);
|
|
174
|
+
const inferredFormat = (0, external_image_format_js_namespaceObject.inferScreenshotImageFormatFromBase64)(base64Body);
|
|
175
|
+
return createImgBase64ByFormat('webp' === inferredFormat ? 'webp' : 'png', base64Body);
|
|
177
176
|
};
|
|
178
177
|
const normalizeBase64Image = (base64)=>{
|
|
179
178
|
const trimmedBase64 = base64.trim();
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type ScreenshotImageFormat = 'png' | 'jpeg' | 'webp';
|
|
2
|
+
export type ScreenshotImageMimeType = 'image/png' | 'image/jpeg' | 'image/webp';
|
|
3
|
+
export declare function screenshotImageMimeType(format: ScreenshotImageFormat): ScreenshotImageMimeType;
|
|
4
|
+
export declare function screenshotImageExtension(format: ScreenshotImageFormat): ScreenshotImageFormat;
|
|
5
|
+
export declare function screenshotImageFormatFromExtension(extension: unknown): ScreenshotImageFormat | undefined;
|
|
6
|
+
export declare function screenshotImageFormatFromMimeType(mimeType: unknown): ScreenshotImageFormat | undefined;
|
|
7
|
+
export declare function isScreenshotImageMimeType(mimeType: unknown): mimeType is ScreenshotImageMimeType;
|
|
8
|
+
export declare function inferScreenshotImageFormatFromBase64(base64Body: string): ScreenshotImageFormat | undefined;
|
|
9
|
+
export declare function detectScreenshotImageFormatFromBuffer(buffer: Uint8Array): ScreenshotImageFormat | undefined;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export { imageInfoOfBase64, isValidPNGImageBuffer, isValidJPEGImageBuffer, isValidImageBuffer, validateScreenshotBuffer, type ValidateScreenshotBufferOptions, } from './info';
|
|
1
|
+
export { imageInfoOfBase64, isValidPNGImageBuffer, isValidJPEGImageBuffer, isValidWebPImageBuffer, isValidImageBuffer, validateScreenshotBuffer, type ValidateScreenshotBufferOptions, } from './info';
|
|
2
|
+
export { detectScreenshotImageFormatFromBuffer, inferScreenshotImageFormatFromBase64, isScreenshotImageMimeType, screenshotImageExtension, screenshotImageFormatFromExtension, screenshotImageFormatFromMimeType, screenshotImageMimeType, type ScreenshotImageFormat, type ScreenshotImageMimeType, } from './image-format';
|
|
2
3
|
export { resizeAndConvertImgBuffer, convertImgBufferToJpeg, resizeImgBase64, zoomForGPT4o, saveBase64Image, paddingToMatchBlockByBase64, cropByRect, scaleImage, localImg2Base64, httpImg2Base64, preProcessImageUrl, parseBase64, createImgBase64ByFormat, inferBase64ImageFormat, normalizeBase64Image, normalizeScreenshotBase64, type NormalizeScreenshotBase64Options, } from './transform';
|
|
3
4
|
export { processImageElementInfo, compositeElementInfoImg, compositePointMarkerImg, annotateRects, } from './box-select';
|
package/dist/types/img/info.d.ts
CHANGED
|
@@ -23,9 +23,15 @@ export declare function isValidPNGImageBuffer(buffer: Buffer): boolean;
|
|
|
23
23
|
*/
|
|
24
24
|
export declare function isValidJPEGImageBuffer(buffer: Buffer): boolean;
|
|
25
25
|
/**
|
|
26
|
-
* Check if the Buffer
|
|
26
|
+
* Check if the Buffer has a WebP signature.
|
|
27
27
|
* @param buffer The Buffer to check
|
|
28
|
-
* @returns true if the Buffer
|
|
28
|
+
* @returns true if the Buffer has a WebP signature, otherwise false
|
|
29
|
+
*/
|
|
30
|
+
export declare function isValidWebPImageBuffer(buffer: Buffer): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Check if the Buffer is a supported screenshot image (PNG, JPEG, or WebP)
|
|
33
|
+
* @param buffer The Buffer to check
|
|
34
|
+
* @returns true if the Buffer has a supported image signature, otherwise false
|
|
29
35
|
*/
|
|
30
36
|
export declare function isValidImageBuffer(buffer: Buffer): boolean;
|
|
31
37
|
export interface ValidateScreenshotBufferOptions {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer';
|
|
2
2
|
import type { PhotonImage as PhotonImageType } from '@silvia-odwyer/photon';
|
|
3
3
|
import type { Rect } from '../types';
|
|
4
|
+
import { type ScreenshotImageFormat } from './image-format';
|
|
4
5
|
/**
|
|
5
6
|
* Saves a Base64-encoded image to a file
|
|
6
7
|
*
|
|
@@ -29,7 +30,7 @@ export declare function resizeAndConvertImgBuffer(inputFormat: string, inputData
|
|
|
29
30
|
export declare const normalizeBase64Body: (body: string) => string;
|
|
30
31
|
/** Convert an image buffer to JPEG without changing its dimensions. */
|
|
31
32
|
export declare function convertImgBufferToJpeg(inputData: Buffer, quality?: number): Promise<Buffer>;
|
|
32
|
-
export declare const inferBase64ImageFormat: (base64Body: string) =>
|
|
33
|
+
export declare const inferBase64ImageFormat: (base64Body: string) => ScreenshotImageFormat;
|
|
33
34
|
export declare const createImgBase64ByFormat: (format: string, body: string) => string;
|
|
34
35
|
export interface NormalizeScreenshotBase64Options {
|
|
35
36
|
label?: string;
|
package/package.json
CHANGED
package/src/agent-tools/types.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { tmpdir } from 'node:os';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
|
+
import {
|
|
5
|
+
type ScreenshotImageFormat,
|
|
6
|
+
screenshotImageFormatFromExtension,
|
|
7
|
+
screenshotImageFormatFromMimeType,
|
|
8
|
+
} from '../img/image-format';
|
|
4
9
|
|
|
5
10
|
export interface WriteCliScreenshotFileOptions {
|
|
6
11
|
id?: unknown;
|
|
@@ -20,14 +25,12 @@ function safeScreenshotFilenamePart(value: unknown): string {
|
|
|
20
25
|
function extensionFromImageMetadata(
|
|
21
26
|
mimeType: unknown,
|
|
22
27
|
extension: unknown,
|
|
23
|
-
):
|
|
24
|
-
|
|
25
|
-
|
|
28
|
+
): ScreenshotImageFormat {
|
|
29
|
+
const extensionFormat = screenshotImageFormatFromExtension(extension);
|
|
30
|
+
if (extensionFormat) {
|
|
31
|
+
return extensionFormat;
|
|
26
32
|
}
|
|
27
|
-
|
|
28
|
-
return 'png';
|
|
29
|
-
}
|
|
30
|
-
return mimeType === 'image/jpeg' ? 'jpeg' : 'png';
|
|
33
|
+
return screenshotImageFormatFromMimeType(mimeType) ?? 'png';
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
export function writeCliScreenshotFile(
|
|
@@ -71,7 +71,9 @@ function screenshotRawBase64(value: unknown): string | undefined {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
const base64 = getStringProperty(value, 'base64');
|
|
74
|
-
const match = base64?.match(
|
|
74
|
+
const match = base64?.match(
|
|
75
|
+
/^data:image\/(?:png|jpeg|jpg|webp);base64,(.+)$/,
|
|
76
|
+
);
|
|
75
77
|
return match?.[1];
|
|
76
78
|
}
|
|
77
79
|
|
|
@@ -4,6 +4,11 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { getDebug } from '../logger';
|
|
7
|
+
import {
|
|
8
|
+
detectScreenshotImageFormatFromBuffer,
|
|
9
|
+
inferScreenshotImageFormatFromBase64,
|
|
10
|
+
screenshotImageMimeType,
|
|
11
|
+
} from './image-format';
|
|
7
12
|
|
|
8
13
|
const debug = getDebug('img:canvas-fallback');
|
|
9
14
|
|
|
@@ -89,7 +94,9 @@ export class CanvasImage {
|
|
|
89
94
|
if (base64Body.startsWith('data:')) {
|
|
90
95
|
img.src = base64Body;
|
|
91
96
|
} else {
|
|
92
|
-
|
|
97
|
+
const format =
|
|
98
|
+
inferScreenshotImageFormatFromBase64(base64Body) ?? 'png';
|
|
99
|
+
img.src = `data:${screenshotImageMimeType(format)};base64,${base64Body}`;
|
|
93
100
|
}
|
|
94
101
|
});
|
|
95
102
|
}
|
|
@@ -99,7 +106,10 @@ export class CanvasImage {
|
|
|
99
106
|
*/
|
|
100
107
|
static async new_from_byteslice(bytes: Uint8Array): Promise<CanvasImage> {
|
|
101
108
|
return new Promise((resolve, reject) => {
|
|
102
|
-
const
|
|
109
|
+
const format = detectScreenshotImageFormatFromBuffer(bytes) ?? 'png';
|
|
110
|
+
const blob = new Blob([bytes], {
|
|
111
|
+
type: screenshotImageMimeType(format),
|
|
112
|
+
});
|
|
103
113
|
const url = URL.createObjectURL(blob);
|
|
104
114
|
const img = new Image();
|
|
105
115
|
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
export type ScreenshotImageFormat = 'png' | 'jpeg' | 'webp';
|
|
2
|
+
|
|
3
|
+
export type ScreenshotImageMimeType = 'image/png' | 'image/jpeg' | 'image/webp';
|
|
4
|
+
|
|
5
|
+
const mimeTypeByFormat: Record<ScreenshotImageFormat, ScreenshotImageMimeType> =
|
|
6
|
+
{
|
|
7
|
+
png: 'image/png',
|
|
8
|
+
jpeg: 'image/jpeg',
|
|
9
|
+
webp: 'image/webp',
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export function screenshotImageMimeType(
|
|
13
|
+
format: ScreenshotImageFormat,
|
|
14
|
+
): ScreenshotImageMimeType {
|
|
15
|
+
return mimeTypeByFormat[format];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function screenshotImageExtension(
|
|
19
|
+
format: ScreenshotImageFormat,
|
|
20
|
+
): ScreenshotImageFormat {
|
|
21
|
+
return format;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function screenshotImageFormatFromExtension(
|
|
25
|
+
extension: unknown,
|
|
26
|
+
): ScreenshotImageFormat | undefined {
|
|
27
|
+
if (typeof extension !== 'string') {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
switch (extension.toLowerCase()) {
|
|
32
|
+
case 'png':
|
|
33
|
+
return 'png';
|
|
34
|
+
case 'jpeg':
|
|
35
|
+
case 'jpg':
|
|
36
|
+
return 'jpeg';
|
|
37
|
+
case 'webp':
|
|
38
|
+
return 'webp';
|
|
39
|
+
default:
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function screenshotImageFormatFromMimeType(
|
|
45
|
+
mimeType: unknown,
|
|
46
|
+
): ScreenshotImageFormat | undefined {
|
|
47
|
+
if (typeof mimeType !== 'string') {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
switch (mimeType.toLowerCase()) {
|
|
52
|
+
case 'image/png':
|
|
53
|
+
return 'png';
|
|
54
|
+
case 'image/jpeg':
|
|
55
|
+
case 'image/jpg':
|
|
56
|
+
return 'jpeg';
|
|
57
|
+
case 'image/webp':
|
|
58
|
+
return 'webp';
|
|
59
|
+
default:
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function isScreenshotImageMimeType(
|
|
65
|
+
mimeType: unknown,
|
|
66
|
+
): mimeType is ScreenshotImageMimeType {
|
|
67
|
+
return (
|
|
68
|
+
mimeType === 'image/png' ||
|
|
69
|
+
mimeType === 'image/jpeg' ||
|
|
70
|
+
mimeType === 'image/webp'
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function inferScreenshotImageFormatFromBase64(
|
|
75
|
+
base64Body: string,
|
|
76
|
+
): ScreenshotImageFormat | undefined {
|
|
77
|
+
const normalizedBody = base64Body.replace(/\s/g, '');
|
|
78
|
+
if (normalizedBody.startsWith('iVBORw0KGgo')) {
|
|
79
|
+
return 'png';
|
|
80
|
+
}
|
|
81
|
+
if (normalizedBody.startsWith('/9j/')) {
|
|
82
|
+
return 'jpeg';
|
|
83
|
+
}
|
|
84
|
+
if (normalizedBody.startsWith('UklGR')) {
|
|
85
|
+
return 'webp';
|
|
86
|
+
}
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function detectScreenshotImageFormatFromBuffer(
|
|
91
|
+
buffer: Uint8Array,
|
|
92
|
+
): ScreenshotImageFormat | undefined {
|
|
93
|
+
if (
|
|
94
|
+
buffer.length >= 8 &&
|
|
95
|
+
buffer[0] === 0x89 &&
|
|
96
|
+
buffer[1] === 0x50 &&
|
|
97
|
+
buffer[2] === 0x4e &&
|
|
98
|
+
buffer[3] === 0x47 &&
|
|
99
|
+
buffer[4] === 0x0d &&
|
|
100
|
+
buffer[5] === 0x0a &&
|
|
101
|
+
buffer[6] === 0x1a &&
|
|
102
|
+
buffer[7] === 0x0a
|
|
103
|
+
) {
|
|
104
|
+
return 'png';
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (
|
|
108
|
+
buffer.length >= 3 &&
|
|
109
|
+
buffer[0] === 0xff &&
|
|
110
|
+
buffer[1] === 0xd8 &&
|
|
111
|
+
buffer[2] === 0xff
|
|
112
|
+
) {
|
|
113
|
+
return 'jpeg';
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (
|
|
117
|
+
buffer.length >= 12 &&
|
|
118
|
+
buffer[0] === 0x52 &&
|
|
119
|
+
buffer[1] === 0x49 &&
|
|
120
|
+
buffer[2] === 0x46 &&
|
|
121
|
+
buffer[3] === 0x46 &&
|
|
122
|
+
buffer[8] === 0x57 &&
|
|
123
|
+
buffer[9] === 0x45 &&
|
|
124
|
+
buffer[10] === 0x42 &&
|
|
125
|
+
buffer[11] === 0x50
|
|
126
|
+
) {
|
|
127
|
+
return 'webp';
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return undefined;
|
|
131
|
+
}
|
package/src/img/index.ts
CHANGED
|
@@ -2,10 +2,22 @@ export {
|
|
|
2
2
|
imageInfoOfBase64,
|
|
3
3
|
isValidPNGImageBuffer,
|
|
4
4
|
isValidJPEGImageBuffer,
|
|
5
|
+
isValidWebPImageBuffer,
|
|
5
6
|
isValidImageBuffer,
|
|
6
7
|
validateScreenshotBuffer,
|
|
7
8
|
type ValidateScreenshotBufferOptions,
|
|
8
9
|
} from './info';
|
|
10
|
+
export {
|
|
11
|
+
detectScreenshotImageFormatFromBuffer,
|
|
12
|
+
inferScreenshotImageFormatFromBase64,
|
|
13
|
+
isScreenshotImageMimeType,
|
|
14
|
+
screenshotImageExtension,
|
|
15
|
+
screenshotImageFormatFromExtension,
|
|
16
|
+
screenshotImageFormatFromMimeType,
|
|
17
|
+
screenshotImageMimeType,
|
|
18
|
+
type ScreenshotImageFormat,
|
|
19
|
+
type ScreenshotImageMimeType,
|
|
20
|
+
} from './image-format';
|
|
9
21
|
export {
|
|
10
22
|
resizeAndConvertImgBuffer,
|
|
11
23
|
convertImgBufferToJpeg,
|
package/src/img/info.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { Size } from '../types';
|
|
|
4
4
|
import { ifInNode } from '../utils';
|
|
5
5
|
import getPhoton from './get-photon';
|
|
6
6
|
import getSharp from './get-sharp';
|
|
7
|
+
import { detectScreenshotImageFormatFromBuffer } from './image-format';
|
|
7
8
|
|
|
8
9
|
export interface ImageInfo extends Size {}
|
|
9
10
|
|
|
@@ -118,12 +119,25 @@ export function isValidJPEGImageBuffer(buffer: Buffer): boolean {
|
|
|
118
119
|
}
|
|
119
120
|
|
|
120
121
|
/**
|
|
121
|
-
* Check if the Buffer
|
|
122
|
+
* Check if the Buffer has a WebP signature.
|
|
122
123
|
* @param buffer The Buffer to check
|
|
123
|
-
* @returns true if the Buffer
|
|
124
|
+
* @returns true if the Buffer has a WebP signature, otherwise false
|
|
125
|
+
*/
|
|
126
|
+
export function isValidWebPImageBuffer(buffer: Buffer): boolean {
|
|
127
|
+
return detectScreenshotImageFormatFromBuffer(buffer) === 'webp';
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Check if the Buffer is a supported screenshot image (PNG, JPEG, or WebP)
|
|
132
|
+
* @param buffer The Buffer to check
|
|
133
|
+
* @returns true if the Buffer has a supported image signature, otherwise false
|
|
124
134
|
*/
|
|
125
135
|
export function isValidImageBuffer(buffer: Buffer): boolean {
|
|
126
|
-
return
|
|
136
|
+
return (
|
|
137
|
+
isValidPNGImageBuffer(buffer) ||
|
|
138
|
+
isValidJPEGImageBuffer(buffer) ||
|
|
139
|
+
isValidWebPImageBuffer(buffer)
|
|
140
|
+
);
|
|
127
141
|
}
|
|
128
142
|
|
|
129
143
|
export interface ValidateScreenshotBufferOptions {
|
package/src/img/transform.ts
CHANGED
|
@@ -9,6 +9,12 @@ import type { Rect } from '../types';
|
|
|
9
9
|
import { ifInNode } from '../utils';
|
|
10
10
|
import getPhoton from './get-photon';
|
|
11
11
|
import getSharp from './get-sharp';
|
|
12
|
+
import {
|
|
13
|
+
type ScreenshotImageFormat,
|
|
14
|
+
detectScreenshotImageFormatFromBuffer,
|
|
15
|
+
inferScreenshotImageFormatFromBase64,
|
|
16
|
+
screenshotImageMimeType,
|
|
17
|
+
} from './image-format';
|
|
12
18
|
|
|
13
19
|
const imgDebug = getDebug('img');
|
|
14
20
|
|
|
@@ -175,48 +181,22 @@ export async function convertImgBufferToJpeg(
|
|
|
175
181
|
|
|
176
182
|
const base64ImageDataUrlPattern = /^data:image\/[a-zA-Z0-9.+-]+;base64,/i;
|
|
177
183
|
const supportedScreenshotDataUriPattern =
|
|
178
|
-
/^data:image\/(png|jpe?g);base64,([\s\S]*)$/i;
|
|
184
|
+
/^data:image\/(png|jpe?g|webp);base64,([\s\S]*)$/i;
|
|
179
185
|
const rawBase64BodyPattern = /^[A-Za-z0-9+/=\s]+$/;
|
|
180
186
|
|
|
181
|
-
export const inferBase64ImageFormat = (
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
return 'jpeg';
|
|
186
|
-
};
|
|
187
|
+
export const inferBase64ImageFormat = (
|
|
188
|
+
base64Body: string,
|
|
189
|
+
): ScreenshotImageFormat =>
|
|
190
|
+
inferScreenshotImageFormatFromBase64(base64Body) ?? 'jpeg';
|
|
187
191
|
|
|
188
192
|
function detectImageMimeTypeFromBuffer(buffer: Buffer): string | undefined {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
buffer[1] === 0x50 &&
|
|
193
|
-
buffer[2] === 0x4e &&
|
|
194
|
-
buffer[3] === 0x47 &&
|
|
195
|
-
buffer[4] === 0x0d &&
|
|
196
|
-
buffer[5] === 0x0a &&
|
|
197
|
-
buffer[6] === 0x1a &&
|
|
198
|
-
buffer[7] === 0x0a
|
|
199
|
-
) {
|
|
200
|
-
return 'image/png';
|
|
201
|
-
}
|
|
202
|
-
if (
|
|
203
|
-
buffer.length >= 3 &&
|
|
204
|
-
buffer[0] === 0xff &&
|
|
205
|
-
buffer[1] === 0xd8 &&
|
|
206
|
-
buffer[2] === 0xff
|
|
207
|
-
) {
|
|
208
|
-
return 'image/jpeg';
|
|
193
|
+
const screenshotFormat = detectScreenshotImageFormatFromBuffer(buffer);
|
|
194
|
+
if (screenshotFormat) {
|
|
195
|
+
return screenshotImageMimeType(screenshotFormat);
|
|
209
196
|
}
|
|
210
197
|
if (buffer.length >= 6 && buffer.subarray(0, 3).toString('ascii') === 'GIF') {
|
|
211
198
|
return 'image/gif';
|
|
212
199
|
}
|
|
213
|
-
if (
|
|
214
|
-
buffer.length >= 12 &&
|
|
215
|
-
buffer.subarray(0, 4).toString('ascii') === 'RIFF' &&
|
|
216
|
-
buffer.subarray(8, 12).toString('ascii') === 'WEBP'
|
|
217
|
-
) {
|
|
218
|
-
return 'image/webp';
|
|
219
|
-
}
|
|
220
200
|
if (buffer.length >= 2 && buffer[0] === 0x42 && buffer[1] === 0x4d) {
|
|
221
201
|
return 'image/bmp';
|
|
222
202
|
}
|
|
@@ -243,10 +223,10 @@ export const normalizeScreenshotBase64 = (
|
|
|
243
223
|
|
|
244
224
|
const dataUriMatch = trimmedBase64.match(supportedScreenshotDataUriPattern);
|
|
245
225
|
if (dataUriMatch) {
|
|
246
|
-
const imageFormat =
|
|
226
|
+
const imageFormat: ScreenshotImageFormat =
|
|
247
227
|
dataUriMatch[1].toLowerCase() === 'jpg'
|
|
248
228
|
? 'jpeg'
|
|
249
|
-
: dataUriMatch[1].toLowerCase();
|
|
229
|
+
: (dataUriMatch[1].toLowerCase() as ScreenshotImageFormat);
|
|
250
230
|
const body = dataUriMatch[2];
|
|
251
231
|
if (!normalizeBase64Body(body)) {
|
|
252
232
|
throw new Error(`${label} cannot be empty`);
|
|
@@ -256,17 +236,22 @@ export const normalizeScreenshotBase64 = (
|
|
|
256
236
|
|
|
257
237
|
if (trimmedBase64.startsWith('data:')) {
|
|
258
238
|
throw new Error(
|
|
259
|
-
`${label} must be a PNG/JPEG data URI or raw PNG base64 string`,
|
|
239
|
+
`${label} must be a PNG/JPEG/WebP data URI or raw PNG/WebP base64 string`,
|
|
260
240
|
);
|
|
261
241
|
}
|
|
262
242
|
|
|
263
243
|
if (!rawBase64BodyPattern.test(trimmedBase64)) {
|
|
264
244
|
throw new Error(
|
|
265
|
-
`${label} must be a PNG/JPEG data URI or raw PNG base64 string`,
|
|
245
|
+
`${label} must be a PNG/JPEG/WebP data URI or raw PNG/WebP base64 string`,
|
|
266
246
|
);
|
|
267
247
|
}
|
|
268
248
|
|
|
269
|
-
|
|
249
|
+
const base64Body = normalizeBase64Body(trimmedBase64);
|
|
250
|
+
const inferredFormat = inferScreenshotImageFormatFromBase64(base64Body);
|
|
251
|
+
return createImgBase64ByFormat(
|
|
252
|
+
inferredFormat === 'webp' ? 'webp' : 'png',
|
|
253
|
+
base64Body,
|
|
254
|
+
);
|
|
270
255
|
};
|
|
271
256
|
|
|
272
257
|
export const normalizeBase64Image = (base64: string) => {
|