@midscene/shared 1.10.5-beta-20260716133905.0 → 1.10.5
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/env/parse-model-config.mjs +1 -1
- package/dist/es/img/box-select.mjs +1 -46
- package/dist/es/img/get-photon.mjs +6 -3
- package/dist/es/img/index.mjs +2 -2
- package/dist/es/img/info.mjs +1 -19
- package/dist/es/img/transform.mjs +24 -57
- package/dist/es/logger.mjs +2 -23
- package/dist/lib/env/parse-model-config.js +1 -1
- package/dist/lib/img/box-select.js +0 -46
- package/dist/lib/img/get-photon.js +5 -2
- package/dist/lib/img/index.js +4 -1
- package/dist/lib/img/info.js +1 -20
- package/dist/lib/img/transform.js +29 -59
- package/dist/lib/logger.js +2 -23
- package/dist/types/img/get-photon.d.ts +13 -13
- package/dist/types/img/index.d.ts +1 -1
- package/dist/types/img/transform.d.ts +3 -1
- package/dist/types/recorder.d.ts +0 -14
- package/package.json +2 -1
- package/src/img/box-select.ts +2 -92
- package/src/img/get-photon.ts +25 -17
- package/src/img/index.ts +1 -0
- package/src/img/info.ts +1 -21
- package/src/img/transform.ts +96 -113
- package/src/logger.ts +3 -38
- package/src/recorder.ts +0 -15
|
@@ -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.5
|
|
8
|
+
const getCurrentVersion = ()=>"1.10.5";
|
|
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,9 +1,7 @@
|
|
|
1
1
|
import node_assert from "node:assert";
|
|
2
2
|
import { NodeType } from "../constants/index.mjs";
|
|
3
|
-
import { ifInNode } from "../utils.mjs";
|
|
4
3
|
import get_photon from "./get-photon.mjs";
|
|
5
|
-
import
|
|
6
|
-
import { createImgBase64ByFormat, parseBase64, photonFromBase64, photonToBase64 } from "./transform.mjs";
|
|
4
|
+
import { photonFromBase64, photonToBase64 } from "./transform.mjs";
|
|
7
5
|
const DIGIT_FONT = {
|
|
8
6
|
0: [
|
|
9
7
|
[
|
|
@@ -916,45 +914,8 @@ const createSvgOverlay = async (elements, imageWidth, imageHeight, boxPadding =
|
|
|
916
914
|
}
|
|
917
915
|
return overlayPixels;
|
|
918
916
|
};
|
|
919
|
-
async function decodeImageWithSharp(inputImgBase64, size) {
|
|
920
|
-
const { body } = parseBase64(inputImgBase64);
|
|
921
|
-
const Sharp = await get_sharp();
|
|
922
|
-
let pipeline = Sharp(Buffer.from(body, 'base64'));
|
|
923
|
-
if (size) pipeline = pipeline.resize(size.width, size.height, {
|
|
924
|
-
fit: 'fill',
|
|
925
|
-
kernel: 'nearest'
|
|
926
|
-
});
|
|
927
|
-
const { data, info } = await pipeline.ensureAlpha().raw().toBuffer({
|
|
928
|
-
resolveWithObject: true
|
|
929
|
-
});
|
|
930
|
-
if (!info.width || !info.height || 4 !== info.channels) throw new Error('Image processing failed to produce RGBA pixels');
|
|
931
|
-
return {
|
|
932
|
-
pixels: new Uint8Array(data),
|
|
933
|
-
width: info.width,
|
|
934
|
-
height: info.height
|
|
935
|
-
};
|
|
936
|
-
}
|
|
937
|
-
async function encodeRgbaWithSharp(pixels, width, height) {
|
|
938
|
-
const Sharp = await get_sharp();
|
|
939
|
-
const output = await Sharp(Buffer.from(pixels), {
|
|
940
|
-
raw: {
|
|
941
|
-
width,
|
|
942
|
-
height,
|
|
943
|
-
channels: 4
|
|
944
|
-
}
|
|
945
|
-
}).jpeg({
|
|
946
|
-
quality: 90,
|
|
947
|
-
chromaSubsampling: '4:4:4'
|
|
948
|
-
}).toBuffer();
|
|
949
|
-
return createImgBase64ByFormat('jpeg', output.toString('base64'));
|
|
950
|
-
}
|
|
951
917
|
const compositeElementInfoImg = async (options)=>{
|
|
952
918
|
node_assert(options.inputImgBase64, 'inputImgBase64 is required');
|
|
953
|
-
if (ifInNode) {
|
|
954
|
-
const { pixels, width, height } = await decodeImageWithSharp(options.inputImgBase64, options.size);
|
|
955
|
-
const overlayPixels = await createSvgOverlay(options.elementsPositionInfo, width, height, options.annotationPadding, options.borderThickness, options.prompt, options.centerPoint);
|
|
956
|
-
return encodeRgbaWithSharp(blendPixels(pixels, overlayPixels, width, height), width, height);
|
|
957
|
-
}
|
|
958
919
|
const { PhotonImage, SamplingFilter, resize } = await get_photon();
|
|
959
920
|
let width = 0;
|
|
960
921
|
let height = 0;
|
|
@@ -994,12 +955,6 @@ const compositeElementInfoImg = async (options)=>{
|
|
|
994
955
|
};
|
|
995
956
|
const compositePointMarkerImg = async (options)=>{
|
|
996
957
|
node_assert(options.inputImgBase64, 'inputImgBase64 is required');
|
|
997
|
-
if (ifInNode) {
|
|
998
|
-
const { pixels, width, height } = await decodeImageWithSharp(options.inputImgBase64, options.size);
|
|
999
|
-
const overlayPixels = new Uint8Array(width * height * 4);
|
|
1000
|
-
drawPointMarker(overlayPixels, width, height, options.point, options.radius ?? 14, options.indexId ?? 1);
|
|
1001
|
-
return encodeRgbaWithSharp(blendPixels(pixels, overlayPixels, width, height), width, height);
|
|
1002
|
-
}
|
|
1003
958
|
const { PhotonImage, SamplingFilter, resize } = await get_photon();
|
|
1004
959
|
let width = 0;
|
|
1005
960
|
let height = 0;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { getDebug } from "../logger.mjs";
|
|
2
|
-
import { ifInBrowser, ifInWorker } from "../utils.mjs";
|
|
2
|
+
import { ifInBrowser, ifInNode, ifInWorker } from "../utils.mjs";
|
|
3
3
|
const debug = getDebug('img');
|
|
4
4
|
let photonModule = null;
|
|
5
5
|
let isInitialized = false;
|
|
6
6
|
let usingCanvasFallback = false;
|
|
7
7
|
async function getPhoton() {
|
|
8
8
|
if (photonModule && isInitialized) return photonModule;
|
|
9
|
-
const env = ifInBrowser ? 'browser' : ifInWorker ? 'worker' : 'unknown';
|
|
9
|
+
const env = ifInBrowser ? 'browser' : ifInWorker ? 'worker' : ifInNode ? 'node' : 'unknown';
|
|
10
10
|
debug(`Loading photon module in ${env} environment`);
|
|
11
11
|
try {
|
|
12
12
|
if (ifInBrowser || ifInWorker) {
|
|
@@ -14,7 +14,10 @@ async function getPhoton() {
|
|
|
14
14
|
if ('function' == typeof photon.default) await photon.default();
|
|
15
15
|
debug('Photon loaded: @silvia-odwyer/photon (browser/worker)');
|
|
16
16
|
photonModule = photon;
|
|
17
|
-
} else
|
|
17
|
+
} else if (ifInNode) {
|
|
18
|
+
photonModule = await import("@silvia-odwyer/photon-node");
|
|
19
|
+
debug('Photon loaded: @silvia-odwyer/photon-node (node)');
|
|
20
|
+
}
|
|
18
21
|
if (!photonModule?.PhotonImage) throw new Error('PhotonImage is not available');
|
|
19
22
|
if (!photonModule.PhotonImage.new_from_byteslice && !photonModule.PhotonImage.new_from_base64) throw new Error('PhotonImage.new_from_byteslice or new_from_base64 is not available');
|
|
20
23
|
isInitialized = true;
|
package/dist/es/img/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { imageInfoOfBase64, isValidImageBuffer, isValidJPEGImageBuffer, isValidPNGImageBuffer, validateScreenshotBuffer } from "./info.mjs";
|
|
2
|
-
import { createImgBase64ByFormat, cropByRect, httpImg2Base64, inferBase64ImageFormat, localImg2Base64, normalizeBase64Image, normalizeScreenshotBase64, paddingToMatchBlockByBase64, parseBase64, preProcessImageUrl, resizeAndConvertImgBuffer, resizeImgBase64, saveBase64Image, scaleImage, zoomForGPT4o } from "./transform.mjs";
|
|
2
|
+
import { convertImgBufferToJpeg, createImgBase64ByFormat, cropByRect, httpImg2Base64, inferBase64ImageFormat, localImg2Base64, normalizeBase64Image, normalizeScreenshotBase64, paddingToMatchBlockByBase64, parseBase64, preProcessImageUrl, resizeAndConvertImgBuffer, resizeImgBase64, saveBase64Image, scaleImage, zoomForGPT4o } from "./transform.mjs";
|
|
3
3
|
import { annotateRects, compositeElementInfoImg, compositePointMarkerImg, processImageElementInfo } from "./box-select.mjs";
|
|
4
|
-
export { annotateRects, compositeElementInfoImg, compositePointMarkerImg, createImgBase64ByFormat, cropByRect, httpImg2Base64, imageInfoOfBase64, inferBase64ImageFormat, isValidImageBuffer, isValidJPEGImageBuffer, isValidPNGImageBuffer, localImg2Base64, normalizeBase64Image, normalizeScreenshotBase64, paddingToMatchBlockByBase64, parseBase64, preProcessImageUrl, processImageElementInfo, resizeAndConvertImgBuffer, resizeImgBase64, saveBase64Image, scaleImage, validateScreenshotBuffer, zoomForGPT4o };
|
|
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 };
|
package/dist/es/img/info.mjs
CHANGED
|
@@ -1,31 +1,13 @@
|
|
|
1
1
|
import node_assert from "node:assert";
|
|
2
2
|
import { Buffer } from "node:buffer";
|
|
3
|
-
import { ifInNode } from "../utils.mjs";
|
|
4
3
|
import get_photon from "./get-photon.mjs";
|
|
5
|
-
import get_sharp from "./get-sharp.mjs";
|
|
6
4
|
async function imageInfoOfBase64(imageBase64) {
|
|
5
|
+
const { PhotonImage } = await get_photon();
|
|
7
6
|
const base64Data = imageBase64.replace(/^data:image\/\w+;base64,/, '').replace(/\s/g, '');
|
|
8
7
|
node_assert(base64Data, 'Invalid image: empty base64 data');
|
|
9
8
|
node_assert(/^[A-Za-z0-9+/]+={0,2}$/.test(base64Data) && base64Data.length % 4 !== 1, 'Invalid image: malformed base64 data');
|
|
10
9
|
const imageBuffer = Buffer.from(base64Data, 'base64');
|
|
11
10
|
node_assert(isValidImageBuffer(imageBuffer), 'Invalid image: unsupported format');
|
|
12
|
-
if (ifInNode) {
|
|
13
|
-
let metadata;
|
|
14
|
-
try {
|
|
15
|
-
const Sharp = await get_sharp();
|
|
16
|
-
metadata = await Sharp(imageBuffer).metadata();
|
|
17
|
-
} catch (error) {
|
|
18
|
-
throw new Error(`Invalid image: failed to decode base64 data (${error instanceof Error ? error.message : String(error)})`, {
|
|
19
|
-
cause: error
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
node_assert(metadata.width && metadata.height, 'Invalid image: cannot get width or height');
|
|
23
|
-
return {
|
|
24
|
-
width: metadata.width,
|
|
25
|
-
height: metadata.height
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
const { PhotonImage } = await get_photon();
|
|
29
11
|
let result;
|
|
30
12
|
try {
|
|
31
13
|
result = PhotonImage.new_from_base64(base64Data);
|
|
@@ -19,7 +19,7 @@ async function resizeAndConvertImgBuffer(inputFormat, inputData, newSize) {
|
|
|
19
19
|
node_assert(newSize && newSize.width > 0 && newSize.height > 0, 'newSize must be positive');
|
|
20
20
|
const resizeStartTime = Date.now();
|
|
21
21
|
imgDebug(`resizeImg start, target size: ${newSize.width}x${newSize.height}`);
|
|
22
|
-
if (ifInNode) {
|
|
22
|
+
if (ifInNode) try {
|
|
23
23
|
const Sharp = await get_sharp();
|
|
24
24
|
const metadata = await Sharp(inputData).metadata();
|
|
25
25
|
const { width: originalWidth, height: originalHeight } = metadata;
|
|
@@ -37,6 +37,8 @@ async function resizeAndConvertImgBuffer(inputFormat, inputData, newSize) {
|
|
|
37
37
|
buffer: resizedBuffer,
|
|
38
38
|
format: 'jpeg'
|
|
39
39
|
};
|
|
40
|
+
} catch (error) {
|
|
41
|
+
imgDebug('Sharp failed, falling back to Photon:', error);
|
|
40
42
|
}
|
|
41
43
|
const { PhotonImage, SamplingFilter, resize } = await get_photon();
|
|
42
44
|
const inputBytes = new Uint8Array(inputData);
|
|
@@ -68,6 +70,23 @@ async function resizeAndConvertImgBuffer(inputFormat, inputData, newSize) {
|
|
|
68
70
|
};
|
|
69
71
|
}
|
|
70
72
|
const normalizeBase64Body = (body)=>body.replace(/\s/g, '');
|
|
73
|
+
async function convertImgBufferToJpeg(inputData, quality = 90) {
|
|
74
|
+
if (ifInNode) try {
|
|
75
|
+
const Sharp = await get_sharp();
|
|
76
|
+
return await Sharp(inputData).jpeg({
|
|
77
|
+
quality
|
|
78
|
+
}).toBuffer();
|
|
79
|
+
} catch (error) {
|
|
80
|
+
imgDebug('Sharp failed, falling back to Photon:', error);
|
|
81
|
+
}
|
|
82
|
+
const mimeType = detectImageMimeTypeFromBuffer(inputData) ?? 'image/png';
|
|
83
|
+
const photonImage = await photonFromBase64(`data:${mimeType};base64,${inputData.toString('base64')}`);
|
|
84
|
+
try {
|
|
85
|
+
return Buffer.from(photonImage.get_bytes_jpeg(quality));
|
|
86
|
+
} finally{
|
|
87
|
+
photonImage.free();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
71
90
|
const base64ImageDataUrlPattern = /^data:image\/[a-zA-Z0-9.+-]+;base64,/i;
|
|
72
91
|
const supportedScreenshotDataUriPattern = /^data:image\/(png|jpe?g);base64,([\s\S]*)$/i;
|
|
73
92
|
const rawBase64BodyPattern = /^[A-Za-z0-9+/=\s]+$/;
|
|
@@ -167,39 +186,6 @@ async function paddingToMatchBlock(image, blockSize = 28) {
|
|
|
167
186
|
};
|
|
168
187
|
}
|
|
169
188
|
async function paddingToMatchBlockByBase64(imageBase64, blockSize = 28) {
|
|
170
|
-
if (ifInNode) {
|
|
171
|
-
const { body } = parseBase64(imageBase64);
|
|
172
|
-
const inputBuffer = Buffer.from(body, 'base64');
|
|
173
|
-
const Sharp = await get_sharp();
|
|
174
|
-
const metadata = await Sharp(inputBuffer).metadata();
|
|
175
|
-
const width = metadata.width;
|
|
176
|
-
const height = metadata.height;
|
|
177
|
-
if (!width || !height) throw new Error('Failed to get image dimensions');
|
|
178
|
-
const targetWidth = Math.ceil(width / blockSize) * blockSize;
|
|
179
|
-
const targetHeight = Math.ceil(height / blockSize) * blockSize;
|
|
180
|
-
if (targetWidth === width && targetHeight === height) return {
|
|
181
|
-
width,
|
|
182
|
-
height,
|
|
183
|
-
imageBase64
|
|
184
|
-
};
|
|
185
|
-
const output = await Sharp(inputBuffer).extend({
|
|
186
|
-
right: targetWidth - width,
|
|
187
|
-
bottom: targetHeight - height,
|
|
188
|
-
background: {
|
|
189
|
-
r: 255,
|
|
190
|
-
g: 255,
|
|
191
|
-
b: 255,
|
|
192
|
-
alpha: 1
|
|
193
|
-
}
|
|
194
|
-
}).jpeg({
|
|
195
|
-
quality: 90
|
|
196
|
-
}).toBuffer();
|
|
197
|
-
return {
|
|
198
|
-
width: targetWidth,
|
|
199
|
-
height: targetHeight,
|
|
200
|
-
imageBase64: createImgBase64ByFormat('jpeg', output.toString('base64'))
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
189
|
const photonImage = await photonFromBase64(imageBase64);
|
|
204
190
|
try {
|
|
205
191
|
const paddedResult = await paddingToMatchBlock(photonImage, blockSize);
|
|
@@ -215,27 +201,6 @@ async function paddingToMatchBlockByBase64(imageBase64, blockSize = 28) {
|
|
|
215
201
|
}
|
|
216
202
|
}
|
|
217
203
|
async function cropByRect(imageBase64, rect) {
|
|
218
|
-
if (ifInNode) {
|
|
219
|
-
const { body } = parseBase64(imageBase64);
|
|
220
|
-
const Sharp = await get_sharp();
|
|
221
|
-
const left = Math.trunc(rect.left);
|
|
222
|
-
const top = Math.trunc(rect.top);
|
|
223
|
-
const width = Math.trunc(rect.left + rect.width) - left;
|
|
224
|
-
const height = Math.trunc(rect.top + rect.height) - top;
|
|
225
|
-
const output = await Sharp(Buffer.from(body, 'base64')).extract({
|
|
226
|
-
left,
|
|
227
|
-
top,
|
|
228
|
-
width,
|
|
229
|
-
height
|
|
230
|
-
}).jpeg({
|
|
231
|
-
quality: 90
|
|
232
|
-
}).toBuffer();
|
|
233
|
-
return {
|
|
234
|
-
width,
|
|
235
|
-
height,
|
|
236
|
-
imageBase64: createImgBase64ByFormat('jpeg', output.toString('base64'))
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
204
|
const { crop } = await get_photon();
|
|
240
205
|
const photonImage = await photonFromBase64(imageBase64);
|
|
241
206
|
const { left, top, width, height } = rect;
|
|
@@ -311,7 +276,7 @@ async function scaleImage(imageBase64, scale) {
|
|
|
311
276
|
const buffer = Buffer.from(body, 'base64');
|
|
312
277
|
const scaleStartTime = Date.now();
|
|
313
278
|
imgDebug(`scaleImage start, scale factor: ${scale}`);
|
|
314
|
-
if (ifInNode) {
|
|
279
|
+
if (ifInNode) try {
|
|
315
280
|
const Sharp = await get_sharp();
|
|
316
281
|
const metadata = await Sharp(buffer).metadata();
|
|
317
282
|
const originalWidth = metadata.width || 0;
|
|
@@ -333,6 +298,8 @@ async function scaleImage(imageBase64, scale) {
|
|
|
333
298
|
height: newHeight,
|
|
334
299
|
imageBase64: base64
|
|
335
300
|
};
|
|
301
|
+
} catch (error) {
|
|
302
|
+
imgDebug('Sharp failed, falling back to Photon:', error);
|
|
336
303
|
}
|
|
337
304
|
const { PhotonImage, SamplingFilter, resize } = await get_photon();
|
|
338
305
|
const inputBytes = new Uint8Array(buffer);
|
|
@@ -360,4 +327,4 @@ async function scaleImage(imageBase64, scale) {
|
|
|
360
327
|
imageBase64: base64
|
|
361
328
|
};
|
|
362
329
|
}
|
|
363
|
-
export { createImgBase64ByFormat, cropByRect, httpImg2Base64, inferBase64ImageFormat, localImg2Base64, normalizeBase64Body, normalizeBase64Image, normalizeScreenshotBase64, paddingToMatchBlock, paddingToMatchBlockByBase64, parseBase64, photonFromBase64, photonToBase64, preProcessImageUrl, resizeAndConvertImgBuffer, resizeImgBase64, saveBase64Image, scaleImage, zoomForGPT4o };
|
|
330
|
+
export { convertImgBufferToJpeg, createImgBase64ByFormat, cropByRect, httpImg2Base64, inferBase64ImageFormat, localImg2Base64, normalizeBase64Body, normalizeBase64Image, normalizeScreenshotBase64, paddingToMatchBlock, paddingToMatchBlockByBase64, parseBase64, photonFromBase64, photonToBase64, preProcessImageUrl, resizeAndConvertImgBuffer, resizeImgBase64, saveBase64Image, scaleImage, zoomForGPT4o };
|
package/dist/es/logger.mjs
CHANGED
|
@@ -6,32 +6,21 @@ import { getMidsceneRunSubDir } from "./common.mjs";
|
|
|
6
6
|
import { ifInNode } from "./utils.mjs";
|
|
7
7
|
const topicPrefix = 'midscene';
|
|
8
8
|
const logStreams = new Map();
|
|
9
|
-
const backpressuredLogStreams = new Set();
|
|
10
|
-
const unavailableLogStreams = new Set();
|
|
11
9
|
const debugInstances = new Map();
|
|
12
10
|
function getLogStream(topic) {
|
|
13
11
|
const topicFileName = topic.replace(/:/g, '-');
|
|
14
|
-
if (unavailableLogStreams.has(topicFileName)) return null;
|
|
15
12
|
if (!logStreams.has(topicFileName)) {
|
|
16
13
|
const logFile = node_path.join(getMidsceneRunSubDir('log'), `${topicFileName}.log`);
|
|
17
14
|
const stream = node_fs.createWriteStream(logFile, {
|
|
18
15
|
flags: 'a'
|
|
19
16
|
});
|
|
20
|
-
stream.on('error', ()=>{
|
|
21
|
-
unavailableLogStreams.add(topicFileName);
|
|
22
|
-
backpressuredLogStreams.delete(topicFileName);
|
|
23
|
-
if (logStreams.get(topicFileName) === stream) logStreams.delete(topicFileName);
|
|
24
|
-
});
|
|
25
17
|
logStreams.set(topicFileName, stream);
|
|
26
18
|
}
|
|
27
|
-
return logStreams.get(topicFileName)
|
|
19
|
+
return logStreams.get(topicFileName);
|
|
28
20
|
}
|
|
29
21
|
function writeLogToFile(topic, message) {
|
|
30
22
|
if (!ifInNode) return;
|
|
31
|
-
const topicFileName = topic.replace(/:/g, '-');
|
|
32
|
-
if (backpressuredLogStreams.has(topicFileName)) return;
|
|
33
23
|
const stream = getLogStream(topic);
|
|
34
|
-
if (!stream) return;
|
|
35
24
|
const now = new Date();
|
|
36
25
|
const isoDate = now.toLocaleDateString('sv-SE');
|
|
37
26
|
const isoTime = now.toLocaleTimeString('sv-SE');
|
|
@@ -42,17 +31,7 @@ function writeLogToFile(topic, message) {
|
|
|
42
31
|
const minutes = (Math.abs(timezoneOffsetMinutes) % 60).toString().padStart(2, '0');
|
|
43
32
|
const timezoneString = `${sign}${hours}:${minutes}`;
|
|
44
33
|
const localISOTime = `${isoDate}T${isoTime}.${milliseconds}${timezoneString}`;
|
|
45
|
-
|
|
46
|
-
if (!stream.write(`[${localISOTime}] ${message}\n`)) {
|
|
47
|
-
backpressuredLogStreams.add(topicFileName);
|
|
48
|
-
stream.once('drain', ()=>{
|
|
49
|
-
backpressuredLogStreams.delete(topicFileName);
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
} catch {
|
|
53
|
-
unavailableLogStreams.add(topicFileName);
|
|
54
|
-
backpressuredLogStreams.delete(topicFileName);
|
|
55
|
-
}
|
|
34
|
+
stream.write(`[${localISOTime}] ${message}\n`);
|
|
56
35
|
}
|
|
57
36
|
function getDebug(topic, options) {
|
|
58
37
|
const fullTopic = `${topicPrefix}:${topic}`;
|
|
@@ -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.5
|
|
40
|
+
const getCurrentVersion = ()=>"1.10.5";
|
|
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,
|
|
@@ -41,11 +41,8 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
41
41
|
const external_node_assert_namespaceObject = require("node:assert");
|
|
42
42
|
var external_node_assert_default = /*#__PURE__*/ __webpack_require__.n(external_node_assert_namespaceObject);
|
|
43
43
|
const index_js_namespaceObject = require("../constants/index.js");
|
|
44
|
-
const external_utils_js_namespaceObject = require("../utils.js");
|
|
45
44
|
const external_get_photon_js_namespaceObject = require("./get-photon.js");
|
|
46
45
|
var external_get_photon_js_default = /*#__PURE__*/ __webpack_require__.n(external_get_photon_js_namespaceObject);
|
|
47
|
-
const external_get_sharp_js_namespaceObject = require("./get-sharp.js");
|
|
48
|
-
var external_get_sharp_js_default = /*#__PURE__*/ __webpack_require__.n(external_get_sharp_js_namespaceObject);
|
|
49
46
|
const external_transform_js_namespaceObject = require("./transform.js");
|
|
50
47
|
const DIGIT_FONT = {
|
|
51
48
|
0: [
|
|
@@ -959,45 +956,8 @@ const createSvgOverlay = async (elements, imageWidth, imageHeight, boxPadding =
|
|
|
959
956
|
}
|
|
960
957
|
return overlayPixels;
|
|
961
958
|
};
|
|
962
|
-
async function decodeImageWithSharp(inputImgBase64, size) {
|
|
963
|
-
const { body } = (0, external_transform_js_namespaceObject.parseBase64)(inputImgBase64);
|
|
964
|
-
const Sharp = await external_get_sharp_js_default()();
|
|
965
|
-
let pipeline = Sharp(Buffer.from(body, 'base64'));
|
|
966
|
-
if (size) pipeline = pipeline.resize(size.width, size.height, {
|
|
967
|
-
fit: 'fill',
|
|
968
|
-
kernel: 'nearest'
|
|
969
|
-
});
|
|
970
|
-
const { data, info } = await pipeline.ensureAlpha().raw().toBuffer({
|
|
971
|
-
resolveWithObject: true
|
|
972
|
-
});
|
|
973
|
-
if (!info.width || !info.height || 4 !== info.channels) throw new Error('Image processing failed to produce RGBA pixels');
|
|
974
|
-
return {
|
|
975
|
-
pixels: new Uint8Array(data),
|
|
976
|
-
width: info.width,
|
|
977
|
-
height: info.height
|
|
978
|
-
};
|
|
979
|
-
}
|
|
980
|
-
async function encodeRgbaWithSharp(pixels, width, height) {
|
|
981
|
-
const Sharp = await external_get_sharp_js_default()();
|
|
982
|
-
const output = await Sharp(Buffer.from(pixels), {
|
|
983
|
-
raw: {
|
|
984
|
-
width,
|
|
985
|
-
height,
|
|
986
|
-
channels: 4
|
|
987
|
-
}
|
|
988
|
-
}).jpeg({
|
|
989
|
-
quality: 90,
|
|
990
|
-
chromaSubsampling: '4:4:4'
|
|
991
|
-
}).toBuffer();
|
|
992
|
-
return (0, external_transform_js_namespaceObject.createImgBase64ByFormat)('jpeg', output.toString('base64'));
|
|
993
|
-
}
|
|
994
959
|
const compositeElementInfoImg = async (options)=>{
|
|
995
960
|
external_node_assert_default()(options.inputImgBase64, 'inputImgBase64 is required');
|
|
996
|
-
if (external_utils_js_namespaceObject.ifInNode) {
|
|
997
|
-
const { pixels, width, height } = await decodeImageWithSharp(options.inputImgBase64, options.size);
|
|
998
|
-
const overlayPixels = await createSvgOverlay(options.elementsPositionInfo, width, height, options.annotationPadding, options.borderThickness, options.prompt, options.centerPoint);
|
|
999
|
-
return encodeRgbaWithSharp(blendPixels(pixels, overlayPixels, width, height), width, height);
|
|
1000
|
-
}
|
|
1001
961
|
const { PhotonImage, SamplingFilter, resize } = await external_get_photon_js_default()();
|
|
1002
962
|
let width = 0;
|
|
1003
963
|
let height = 0;
|
|
@@ -1037,12 +997,6 @@ const compositeElementInfoImg = async (options)=>{
|
|
|
1037
997
|
};
|
|
1038
998
|
const compositePointMarkerImg = async (options)=>{
|
|
1039
999
|
external_node_assert_default()(options.inputImgBase64, 'inputImgBase64 is required');
|
|
1040
|
-
if (external_utils_js_namespaceObject.ifInNode) {
|
|
1041
|
-
const { pixels, width, height } = await decodeImageWithSharp(options.inputImgBase64, options.size);
|
|
1042
|
-
const overlayPixels = new Uint8Array(width * height * 4);
|
|
1043
|
-
drawPointMarker(overlayPixels, width, height, options.point, options.radius ?? 14, options.indexId ?? 1);
|
|
1044
|
-
return encodeRgbaWithSharp(blendPixels(pixels, overlayPixels, width, height), width, height);
|
|
1045
|
-
}
|
|
1046
1000
|
const { PhotonImage, SamplingFilter, resize } = await external_get_photon_js_default()();
|
|
1047
1001
|
let width = 0;
|
|
1048
1002
|
let height = 0;
|
|
@@ -35,7 +35,7 @@ let isInitialized = false;
|
|
|
35
35
|
let usingCanvasFallback = false;
|
|
36
36
|
async function getPhoton() {
|
|
37
37
|
if (photonModule && isInitialized) return photonModule;
|
|
38
|
-
const env = external_utils_js_namespaceObject.ifInBrowser ? 'browser' : external_utils_js_namespaceObject.ifInWorker ? 'worker' : 'unknown';
|
|
38
|
+
const env = external_utils_js_namespaceObject.ifInBrowser ? 'browser' : external_utils_js_namespaceObject.ifInWorker ? 'worker' : external_utils_js_namespaceObject.ifInNode ? 'node' : 'unknown';
|
|
39
39
|
debug(`Loading photon module in ${env} environment`);
|
|
40
40
|
try {
|
|
41
41
|
if (external_utils_js_namespaceObject.ifInBrowser || external_utils_js_namespaceObject.ifInWorker) {
|
|
@@ -43,7 +43,10 @@ async function getPhoton() {
|
|
|
43
43
|
if ('function' == typeof photon.default) await photon.default();
|
|
44
44
|
debug('Photon loaded: @silvia-odwyer/photon (browser/worker)');
|
|
45
45
|
photonModule = photon;
|
|
46
|
-
} else
|
|
46
|
+
} else if (external_utils_js_namespaceObject.ifInNode) {
|
|
47
|
+
photonModule = await import("@silvia-odwyer/photon-node");
|
|
48
|
+
debug('Photon loaded: @silvia-odwyer/photon-node (node)');
|
|
49
|
+
}
|
|
47
50
|
if (!photonModule?.PhotonImage) throw new Error('PhotonImage is not available');
|
|
48
51
|
if (!photonModule.PhotonImage.new_from_byteslice && !photonModule.PhotonImage.new_from_base64) throw new Error('PhotonImage.new_from_byteslice or new_from_base64 is not available');
|
|
49
52
|
isInitialized = true;
|
package/dist/lib/img/index.js
CHANGED
|
@@ -24,9 +24,10 @@ var __webpack_require__ = {};
|
|
|
24
24
|
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
28
|
inferBase64ImageFormat: ()=>external_transform_js_namespaceObject.inferBase64ImageFormat,
|
|
29
29
|
localImg2Base64: ()=>external_transform_js_namespaceObject.localImg2Base64,
|
|
30
|
+
paddingToMatchBlockByBase64: ()=>external_transform_js_namespaceObject.paddingToMatchBlockByBase64,
|
|
30
31
|
parseBase64: ()=>external_transform_js_namespaceObject.parseBase64,
|
|
31
32
|
resizeAndConvertImgBuffer: ()=>external_transform_js_namespaceObject.resizeAndConvertImgBuffer,
|
|
32
33
|
resizeImgBase64: ()=>external_transform_js_namespaceObject.resizeImgBase64,
|
|
@@ -55,6 +56,7 @@ const external_box_select_js_namespaceObject = require("./box-select.js");
|
|
|
55
56
|
exports.annotateRects = __webpack_exports__.annotateRects;
|
|
56
57
|
exports.compositeElementInfoImg = __webpack_exports__.compositeElementInfoImg;
|
|
57
58
|
exports.compositePointMarkerImg = __webpack_exports__.compositePointMarkerImg;
|
|
59
|
+
exports.convertImgBufferToJpeg = __webpack_exports__.convertImgBufferToJpeg;
|
|
58
60
|
exports.createImgBase64ByFormat = __webpack_exports__.createImgBase64ByFormat;
|
|
59
61
|
exports.cropByRect = __webpack_exports__.cropByRect;
|
|
60
62
|
exports.httpImg2Base64 = __webpack_exports__.httpImg2Base64;
|
|
@@ -80,6 +82,7 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
|
80
82
|
"annotateRects",
|
|
81
83
|
"compositeElementInfoImg",
|
|
82
84
|
"compositePointMarkerImg",
|
|
85
|
+
"convertImgBufferToJpeg",
|
|
83
86
|
"createImgBase64ByFormat",
|
|
84
87
|
"cropByRect",
|
|
85
88
|
"httpImg2Base64",
|
package/dist/lib/img/info.js
CHANGED
|
@@ -42,34 +42,15 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
42
42
|
const external_node_assert_namespaceObject = require("node:assert");
|
|
43
43
|
var external_node_assert_default = /*#__PURE__*/ __webpack_require__.n(external_node_assert_namespaceObject);
|
|
44
44
|
const external_node_buffer_namespaceObject = require("node:buffer");
|
|
45
|
-
const external_utils_js_namespaceObject = require("../utils.js");
|
|
46
45
|
const external_get_photon_js_namespaceObject = require("./get-photon.js");
|
|
47
46
|
var external_get_photon_js_default = /*#__PURE__*/ __webpack_require__.n(external_get_photon_js_namespaceObject);
|
|
48
|
-
const external_get_sharp_js_namespaceObject = require("./get-sharp.js");
|
|
49
|
-
var external_get_sharp_js_default = /*#__PURE__*/ __webpack_require__.n(external_get_sharp_js_namespaceObject);
|
|
50
47
|
async function imageInfoOfBase64(imageBase64) {
|
|
48
|
+
const { PhotonImage } = await external_get_photon_js_default()();
|
|
51
49
|
const base64Data = imageBase64.replace(/^data:image\/\w+;base64,/, '').replace(/\s/g, '');
|
|
52
50
|
external_node_assert_default()(base64Data, 'Invalid image: empty base64 data');
|
|
53
51
|
external_node_assert_default()(/^[A-Za-z0-9+/]+={0,2}$/.test(base64Data) && base64Data.length % 4 !== 1, 'Invalid image: malformed base64 data');
|
|
54
52
|
const imageBuffer = external_node_buffer_namespaceObject.Buffer.from(base64Data, 'base64');
|
|
55
53
|
external_node_assert_default()(isValidImageBuffer(imageBuffer), 'Invalid image: unsupported format');
|
|
56
|
-
if (external_utils_js_namespaceObject.ifInNode) {
|
|
57
|
-
let metadata;
|
|
58
|
-
try {
|
|
59
|
-
const Sharp = await external_get_sharp_js_default()();
|
|
60
|
-
metadata = await Sharp(imageBuffer).metadata();
|
|
61
|
-
} catch (error) {
|
|
62
|
-
throw new Error(`Invalid image: failed to decode base64 data (${error instanceof Error ? error.message : String(error)})`, {
|
|
63
|
-
cause: error
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
external_node_assert_default()(metadata.width && metadata.height, 'Invalid image: cannot get width or height');
|
|
67
|
-
return {
|
|
68
|
-
width: metadata.width,
|
|
69
|
-
height: metadata.height
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
const { PhotonImage } = await external_get_photon_js_default()();
|
|
73
54
|
let result;
|
|
74
55
|
try {
|
|
75
56
|
result = PhotonImage.new_from_base64(base64Data);
|