@midscene/shared 0.12.4 → 0.12.5-beta-20250306111616.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/{constants.js → constants/index.js} +4 -5
- package/dist/es/extractor/client-extractor.js +161 -0
- package/dist/es/extractor/constants.js +10 -0
- package/dist/es/extractor/debug.js +9 -0
- package/dist/es/extractor/dom-util.js +73 -0
- package/dist/es/extractor/index.js +14 -0
- package/dist/es/extractor/tree.js +126 -0
- package/dist/es/extractor/util.js +344 -0
- package/dist/es/extractor/web-extractor.js +317 -0
- package/dist/es/img/box-select.js +187 -0
- package/dist/es/img/draw-box.js +43 -0
- package/dist/es/img/get-jimp.js +11 -0
- package/dist/es/img/index.js +34 -0
- package/dist/es/img/info.js +50 -0
- package/dist/es/img/transform.js +128 -0
- package/dist/es/index.js +0 -1
- package/dist/es/{fs.js → node/fs.js} +22 -5
- package/dist/es/types/index.js +5 -0
- package/dist/es/us-keyboard-layout.js +10 -11
- package/dist/es/utils.js +10 -569
- package/dist/lib/constants/index.js +20 -0
- package/dist/lib/extractor/client-extractor.js +161 -0
- package/dist/lib/extractor/constants.js +10 -0
- package/dist/lib/extractor/debug.js +9 -0
- package/dist/lib/extractor/dom-util.js +73 -0
- package/dist/lib/extractor/index.js +14 -0
- package/dist/lib/extractor/tree.js +126 -0
- package/dist/lib/extractor/util.js +344 -0
- package/dist/lib/extractor/web-extractor.js +317 -0
- package/dist/lib/img/box-select.js +187 -0
- package/dist/lib/img/draw-box.js +43 -0
- package/dist/lib/img/get-jimp.js +11 -0
- package/dist/lib/img/index.js +34 -0
- package/dist/lib/img/info.js +50 -0
- package/dist/lib/img/transform.js +128 -0
- package/dist/lib/index.js +3 -25
- package/dist/lib/node/fs.js +62 -0
- package/dist/lib/types/index.js +5 -0
- package/dist/lib/us-keyboard-layout.js +12 -41
- package/dist/lib/utils.js +12 -578
- package/dist/types/constants/index.d.ts +12 -0
- package/dist/types/extractor/client-extractor.d.ts +2 -0
- package/dist/types/extractor/constants.d.ts +1 -0
- package/dist/types/extractor/debug.d.ts +1 -0
- package/dist/types/extractor/dom-util.d.ts +5 -0
- package/dist/types/extractor/index.d.ts +29 -0
- package/dist/types/extractor/tree.d.ts +9 -0
- package/dist/types/extractor/util.d.ts +40 -0
- package/dist/types/extractor/web-extractor.d.ts +14 -0
- package/dist/types/img/box-select.d.ts +31 -0
- package/dist/types/img/draw-box.d.ts +15 -0
- package/dist/types/img/get-jimp.d.ts +2 -0
- package/dist/types/img/index.d.ts +4 -0
- package/dist/types/img/info.d.ts +40 -0
- package/dist/types/img/transform.d.ts +68 -0
- package/dist/types/index.d.ts +1 -2
- package/dist/{lib → types/node}/fs.d.ts +4 -4
- package/dist/{lib/index-305e7a7e.d.ts → types/types/index.d.ts} +6 -9
- package/dist/types/us-keyboard-layout.d.ts +32 -0
- package/dist/types/utils.d.ts +11 -0
- package/package.json +39 -39
- package/src/img/box-select.ts +17 -11
- package/src/img/draw-box.ts +5 -5
- package/src/img/get-jimp.ts +3 -0
- package/src/{fs/index.ts → node/fs.ts} +20 -0
- package/src/utils.ts +13 -0
- package/dist/browser/constants.d.ts +0 -14
- package/dist/browser/constants.js +0 -42
- package/dist/browser/extractor-debug.d.ts +0 -2
- package/dist/browser/extractor-debug.js +0 -1269
- package/dist/browser/extractor.d.ts +0 -47
- package/dist/browser/extractor.js +0 -1557
- package/dist/browser/fs.d.ts +0 -14
- package/dist/browser/fs.js +0 -66
- package/dist/browser/img.d.ts +0 -152
- package/dist/browser/img.js +0 -483
- package/dist/browser/index-305e7a7e.d.ts +0 -32
- package/dist/browser/index.d.ts +0 -3
- package/dist/browser/index.js +0 -26
- package/dist/browser/us-keyboard-layout.d.ts +0 -34
- package/dist/browser/us-keyboard-layout.js +0 -456
- package/dist/browser/utils.d.ts +0 -5
- package/dist/browser/utils.js +0 -611
- package/dist/es/constants.d.ts +0 -14
- package/dist/es/extractor-debug.d.ts +0 -2
- package/dist/es/extractor-debug.js +0 -1267
- package/dist/es/extractor.d.ts +0 -47
- package/dist/es/extractor.js +0 -1546
- package/dist/es/fs.d.ts +0 -14
- package/dist/es/img.d.ts +0 -152
- package/dist/es/img.js +0 -451
- package/dist/es/index-305e7a7e.d.ts +0 -32
- package/dist/es/index.d.ts +0 -3
- package/dist/es/us-keyboard-layout.d.ts +0 -34
- package/dist/es/utils.d.ts +0 -5
- package/dist/lib/constants.d.ts +0 -14
- package/dist/lib/constants.js +0 -50
- package/dist/lib/extractor-debug.d.ts +0 -2
- package/dist/lib/extractor-debug.js +0 -1261
- package/dist/lib/extractor.d.ts +0 -47
- package/dist/lib/extractor.js +0 -1559
- package/dist/lib/fs.js +0 -71
- package/dist/lib/img.d.ts +0 -152
- package/dist/lib/img.js +0 -501
- package/dist/lib/index.d.ts +0 -3
- package/dist/lib/us-keyboard-layout.d.ts +0 -34
- package/dist/lib/utils.d.ts +0 -5
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import getJimp from "./get-jimp";
|
|
3
|
+
import { bufferFromBase64, imageInfoOfBase64 } from "./index";
|
|
4
|
+
let cachedFont = null;
|
|
5
|
+
const createSvgOverlay = async (elements, imageWidth, imageHeight, boxPadding = 5) => {
|
|
6
|
+
const Jimp = await getJimp();
|
|
7
|
+
const image = new Jimp(imageWidth, imageHeight, 0);
|
|
8
|
+
const colors = [
|
|
9
|
+
{ rect: 3324182783, text: 4294967295 },
|
|
10
|
+
// red, white
|
|
11
|
+
{ rect: 65535, text: 4294967295 },
|
|
12
|
+
// blue, white
|
|
13
|
+
{ rect: 2336560127, text: 4294967295 },
|
|
14
|
+
// brown, white
|
|
15
|
+
{ rect: 1048258559, text: 4294967295 },
|
|
16
|
+
// green, white
|
|
17
|
+
{ rect: 1342206975, text: 4294967295 }
|
|
18
|
+
// purple, white
|
|
19
|
+
];
|
|
20
|
+
for (let index = 0; index < elements.length; index++) {
|
|
21
|
+
const element = elements[index];
|
|
22
|
+
const color = colors[index % colors.length];
|
|
23
|
+
const paddedRect = {
|
|
24
|
+
left: Math.max(0, element.rect.left - boxPadding),
|
|
25
|
+
top: Math.max(0, element.rect.top - boxPadding),
|
|
26
|
+
width: Math.min(
|
|
27
|
+
imageWidth - element.rect.left,
|
|
28
|
+
element.rect.width + boxPadding * 2
|
|
29
|
+
),
|
|
30
|
+
height: Math.min(
|
|
31
|
+
imageHeight - element.rect.top,
|
|
32
|
+
element.rect.height + boxPadding * 2
|
|
33
|
+
)
|
|
34
|
+
};
|
|
35
|
+
image.scan(
|
|
36
|
+
paddedRect.left,
|
|
37
|
+
paddedRect.top,
|
|
38
|
+
paddedRect.width,
|
|
39
|
+
paddedRect.height,
|
|
40
|
+
(x, y, idx) => {
|
|
41
|
+
if (x === paddedRect.left || x === paddedRect.left + paddedRect.width - 1 || y === paddedRect.top || y === paddedRect.top + paddedRect.height - 1) {
|
|
42
|
+
image.bitmap.data[idx + 0] = color.rect >> 24 & 255;
|
|
43
|
+
image.bitmap.data[idx + 1] = color.rect >> 16 & 255;
|
|
44
|
+
image.bitmap.data[idx + 2] = color.rect >> 8 & 255;
|
|
45
|
+
image.bitmap.data[idx + 3] = color.rect & 255;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
);
|
|
49
|
+
const textWidth = element.indexId.toString().length * 8;
|
|
50
|
+
const textHeight = 12;
|
|
51
|
+
const rectWidth = textWidth + 5;
|
|
52
|
+
const rectHeight = textHeight + 4;
|
|
53
|
+
let rectX = paddedRect.left - rectWidth;
|
|
54
|
+
let rectY = paddedRect.top + paddedRect.height / 2 - textHeight / 2 - 2;
|
|
55
|
+
const checkOverlap = (x, y) => {
|
|
56
|
+
return elements.slice(0, index).some((otherElement) => {
|
|
57
|
+
return x < otherElement.rect.left + otherElement.rect.width && x + rectWidth > otherElement.rect.left && y < otherElement.rect.top + otherElement.rect.height && y + rectHeight > otherElement.rect.top;
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
const isWithinBounds = (x, y) => {
|
|
61
|
+
return x >= 0 && x + rectWidth <= imageWidth && y >= 0 && y + rectHeight <= imageHeight;
|
|
62
|
+
};
|
|
63
|
+
if (checkOverlap(rectX, rectY) || !isWithinBounds(rectX, rectY)) {
|
|
64
|
+
if (!checkOverlap(paddedRect.left, paddedRect.top - rectHeight - 2) && isWithinBounds(paddedRect.left, paddedRect.top - rectHeight - 2)) {
|
|
65
|
+
rectX = paddedRect.left;
|
|
66
|
+
rectY = paddedRect.top - rectHeight - 2;
|
|
67
|
+
} else if (!checkOverlap(
|
|
68
|
+
paddedRect.left,
|
|
69
|
+
paddedRect.top + paddedRect.height + 2
|
|
70
|
+
) && isWithinBounds(paddedRect.left, paddedRect.top + paddedRect.height + 2)) {
|
|
71
|
+
rectX = paddedRect.left;
|
|
72
|
+
rectY = paddedRect.top + paddedRect.height + 2;
|
|
73
|
+
} else if (!checkOverlap(paddedRect.left + paddedRect.width + 2, paddedRect.top) && isWithinBounds(paddedRect.left + paddedRect.width + 2, paddedRect.top)) {
|
|
74
|
+
rectX = paddedRect.left + paddedRect.width + 2;
|
|
75
|
+
rectY = paddedRect.top;
|
|
76
|
+
} else {
|
|
77
|
+
rectX = paddedRect.left;
|
|
78
|
+
rectY = paddedRect.top + 2;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
image.scan(
|
|
82
|
+
rectX,
|
|
83
|
+
rectY,
|
|
84
|
+
rectWidth,
|
|
85
|
+
rectHeight,
|
|
86
|
+
(x, y, idx) => {
|
|
87
|
+
image.bitmap.data[idx + 0] = color.rect >> 24 & 255;
|
|
88
|
+
image.bitmap.data[idx + 1] = color.rect >> 16 & 255;
|
|
89
|
+
image.bitmap.data[idx + 2] = color.rect >> 8 & 255;
|
|
90
|
+
image.bitmap.data[idx + 3] = color.rect & 255;
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
try {
|
|
94
|
+
cachedFont = cachedFont || await Jimp.loadFont(Jimp.FONT_SANS_16_WHITE);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error("Error loading font", error);
|
|
97
|
+
}
|
|
98
|
+
image.print(
|
|
99
|
+
cachedFont,
|
|
100
|
+
rectX,
|
|
101
|
+
rectY,
|
|
102
|
+
{
|
|
103
|
+
text: element.indexId.toString(),
|
|
104
|
+
alignmentX: Jimp.HORIZONTAL_ALIGN_CENTER,
|
|
105
|
+
alignmentY: Jimp.VERTICAL_ALIGN_MIDDLE
|
|
106
|
+
},
|
|
107
|
+
rectWidth,
|
|
108
|
+
rectHeight
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
return image;
|
|
112
|
+
};
|
|
113
|
+
const compositeElementInfoImg = async (options) => {
|
|
114
|
+
assert(options.inputImgBase64, "inputImgBase64 is required");
|
|
115
|
+
let width = 0;
|
|
116
|
+
let height = 0;
|
|
117
|
+
let jimpImage;
|
|
118
|
+
const Jimp = await getJimp();
|
|
119
|
+
if (options.size) {
|
|
120
|
+
width = options.size.width;
|
|
121
|
+
height = options.size.height;
|
|
122
|
+
}
|
|
123
|
+
if (!width || !height) {
|
|
124
|
+
const info = await imageInfoOfBase64(options.inputImgBase64);
|
|
125
|
+
width = info.width;
|
|
126
|
+
height = info.height;
|
|
127
|
+
jimpImage = info.jimpImage;
|
|
128
|
+
} else {
|
|
129
|
+
const imageBuffer = await bufferFromBase64(options.inputImgBase64);
|
|
130
|
+
jimpImage = await Jimp.read(imageBuffer);
|
|
131
|
+
const imageBitmap = jimpImage.bitmap;
|
|
132
|
+
if (imageBitmap.width !== width || imageBitmap.height !== height) {
|
|
133
|
+
jimpImage.resize(width, height, Jimp.RESIZE_NEAREST_NEIGHBOR);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (!width || !height) {
|
|
137
|
+
throw Error("Image processing failed because width or height is undefined");
|
|
138
|
+
}
|
|
139
|
+
const { elementsPositionInfo } = options;
|
|
140
|
+
const result = await Promise.resolve(jimpImage).then(async (image) => {
|
|
141
|
+
const svgOverlay = await createSvgOverlay(
|
|
142
|
+
elementsPositionInfo,
|
|
143
|
+
width,
|
|
144
|
+
height,
|
|
145
|
+
options.annotationPadding
|
|
146
|
+
);
|
|
147
|
+
const svgImage = await Jimp.read(svgOverlay);
|
|
148
|
+
const compositeImage = await image.composite(svgImage, 0, 0, {
|
|
149
|
+
mode: Jimp.BLEND_SOURCE_OVER,
|
|
150
|
+
opacitySource: 1,
|
|
151
|
+
opacityDest: 1
|
|
152
|
+
});
|
|
153
|
+
return compositeImage;
|
|
154
|
+
}).then(async (compositeImage) => {
|
|
155
|
+
compositeImage.quality(90);
|
|
156
|
+
const base64 = await compositeImage.getBase64Async(Jimp.MIME_JPEG);
|
|
157
|
+
return base64;
|
|
158
|
+
}).catch((error) => {
|
|
159
|
+
throw error;
|
|
160
|
+
});
|
|
161
|
+
return result;
|
|
162
|
+
};
|
|
163
|
+
const processImageElementInfo = async (options) => {
|
|
164
|
+
const base64Image = options.inputImgBase64.split(";base64,").pop();
|
|
165
|
+
assert(base64Image, "base64Image is undefined");
|
|
166
|
+
const [
|
|
167
|
+
compositeElementInfoImgBase64,
|
|
168
|
+
compositeElementInfoImgWithoutTextBase64
|
|
169
|
+
] = await Promise.all([
|
|
170
|
+
compositeElementInfoImg({
|
|
171
|
+
inputImgBase64: options.inputImgBase64,
|
|
172
|
+
elementsPositionInfo: options.elementsPositionInfo
|
|
173
|
+
}),
|
|
174
|
+
compositeElementInfoImg({
|
|
175
|
+
inputImgBase64: options.inputImgBase64,
|
|
176
|
+
elementsPositionInfo: options.elementsPositionInfoWithoutText
|
|
177
|
+
})
|
|
178
|
+
]);
|
|
179
|
+
return {
|
|
180
|
+
compositeElementInfoImgBase64,
|
|
181
|
+
compositeElementInfoImgWithoutTextBase64
|
|
182
|
+
};
|
|
183
|
+
};
|
|
184
|
+
export {
|
|
185
|
+
compositeElementInfoImg,
|
|
186
|
+
processImageElementInfo
|
|
187
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import getJimp from "./get-jimp";
|
|
2
|
+
import { bufferFromBase64 } from "./info";
|
|
3
|
+
import { saveBase64Image } from "./transform";
|
|
4
|
+
async function drawBoxOnImage(options) {
|
|
5
|
+
const { inputImgBase64, rect } = options;
|
|
6
|
+
const color = { r: 255, g: 0, b: 0, a: 255 };
|
|
7
|
+
const Jimp = await getJimp();
|
|
8
|
+
const imageBuffer = await bufferFromBase64(inputImgBase64);
|
|
9
|
+
const image = await Jimp.read(imageBuffer);
|
|
10
|
+
const centerX = rect.x;
|
|
11
|
+
const centerY = rect.y;
|
|
12
|
+
const radius = 5;
|
|
13
|
+
image.scan(
|
|
14
|
+
Math.floor(centerX - radius),
|
|
15
|
+
Math.floor(centerY - radius),
|
|
16
|
+
radius * 2,
|
|
17
|
+
radius * 2,
|
|
18
|
+
(x, y, idx) => {
|
|
19
|
+
const distance = Math.sqrt((x - centerX) ** 2 + (y - centerY) ** 2);
|
|
20
|
+
if (distance <= radius) {
|
|
21
|
+
image.bitmap.data[idx + 0] = color.r;
|
|
22
|
+
image.bitmap.data[idx + 1] = color.g;
|
|
23
|
+
image.bitmap.data[idx + 2] = color.b;
|
|
24
|
+
image.bitmap.data[idx + 3] = color.a;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
image.quality(90);
|
|
29
|
+
const resultBase64 = await image.getBase64Async(Jimp.MIME_JPEG);
|
|
30
|
+
return resultBase64;
|
|
31
|
+
}
|
|
32
|
+
async function savePositionImg(options) {
|
|
33
|
+
const { inputImgBase64, rect, outputPath } = options;
|
|
34
|
+
const imgBase64 = await drawBoxOnImage({ inputImgBase64, rect });
|
|
35
|
+
await saveBase64Image({
|
|
36
|
+
base64Data: imgBase64,
|
|
37
|
+
outputPath
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
export {
|
|
41
|
+
drawBoxOnImage,
|
|
42
|
+
savePositionImg
|
|
43
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import {
|
|
2
|
+
imageInfo,
|
|
3
|
+
imageInfoOfBase64,
|
|
4
|
+
bufferFromBase64,
|
|
5
|
+
base64Encoded
|
|
6
|
+
} from "./info";
|
|
7
|
+
import {
|
|
8
|
+
trimImage,
|
|
9
|
+
resizeImg,
|
|
10
|
+
resizeImgBase64,
|
|
11
|
+
transformImgPathToBase64,
|
|
12
|
+
zoomForGPT4o,
|
|
13
|
+
saveBase64Image,
|
|
14
|
+
paddingToMatchBlock
|
|
15
|
+
} from "./transform";
|
|
16
|
+
import { processImageElementInfo, compositeElementInfoImg } from "./box-select";
|
|
17
|
+
import { drawBoxOnImage, savePositionImg } from "./draw-box";
|
|
18
|
+
export {
|
|
19
|
+
base64Encoded,
|
|
20
|
+
bufferFromBase64,
|
|
21
|
+
compositeElementInfoImg,
|
|
22
|
+
drawBoxOnImage,
|
|
23
|
+
imageInfo,
|
|
24
|
+
imageInfoOfBase64,
|
|
25
|
+
paddingToMatchBlock,
|
|
26
|
+
processImageElementInfo,
|
|
27
|
+
resizeImg,
|
|
28
|
+
resizeImgBase64,
|
|
29
|
+
saveBase64Image,
|
|
30
|
+
savePositionImg,
|
|
31
|
+
transformImgPathToBase64,
|
|
32
|
+
trimImage,
|
|
33
|
+
zoomForGPT4o
|
|
34
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { Buffer } from "node:buffer";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import getJimp from "./get-jimp";
|
|
5
|
+
async function imageInfo(image) {
|
|
6
|
+
const Jimp = await getJimp();
|
|
7
|
+
let jimpImage;
|
|
8
|
+
if (typeof image === "string") {
|
|
9
|
+
jimpImage = await Jimp.read(image);
|
|
10
|
+
} else if (Buffer.isBuffer(image)) {
|
|
11
|
+
jimpImage = await Jimp.read(image);
|
|
12
|
+
} else if (image instanceof Jimp) {
|
|
13
|
+
jimpImage = image;
|
|
14
|
+
} else {
|
|
15
|
+
throw new Error("Invalid image input: must be a string path or a Buffer");
|
|
16
|
+
}
|
|
17
|
+
const { width, height } = jimpImage.bitmap;
|
|
18
|
+
assert(
|
|
19
|
+
width && height,
|
|
20
|
+
`Invalid image: ${typeof image === "string" ? image : "Buffer"}`
|
|
21
|
+
);
|
|
22
|
+
return { width, height, jimpImage };
|
|
23
|
+
}
|
|
24
|
+
async function imageInfoOfBase64(imageBase64) {
|
|
25
|
+
const buffer = await bufferFromBase64(imageBase64);
|
|
26
|
+
return imageInfo(buffer);
|
|
27
|
+
}
|
|
28
|
+
async function bufferFromBase64(imageBase64) {
|
|
29
|
+
const base64Data = imageBase64.replace(/^data:image\/\w+;base64,/, "");
|
|
30
|
+
return Buffer.from(base64Data, "base64");
|
|
31
|
+
}
|
|
32
|
+
function base64Encoded(image, withHeader = true) {
|
|
33
|
+
const imageBuffer = readFileSync(image);
|
|
34
|
+
if (!withHeader) {
|
|
35
|
+
return imageBuffer.toString("base64");
|
|
36
|
+
}
|
|
37
|
+
if (image.endsWith("png")) {
|
|
38
|
+
return `data:image/png;base64,${imageBuffer.toString("base64")}`;
|
|
39
|
+
}
|
|
40
|
+
if (image.endsWith("jpg") || image.endsWith("jpeg")) {
|
|
41
|
+
return `data:image/jpeg;base64,${imageBuffer.toString("base64")}`;
|
|
42
|
+
}
|
|
43
|
+
throw new Error("unsupported image type");
|
|
44
|
+
}
|
|
45
|
+
export {
|
|
46
|
+
base64Encoded,
|
|
47
|
+
bufferFromBase64,
|
|
48
|
+
imageInfo,
|
|
49
|
+
imageInfoOfBase64
|
|
50
|
+
};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { Buffer } from "node:buffer";
|
|
3
|
+
import getJimp from "./get-jimp";
|
|
4
|
+
async function saveBase64Image(options) {
|
|
5
|
+
const { base64Data, outputPath } = options;
|
|
6
|
+
const base64Image = base64Data.split(";base64,").pop() || base64Data;
|
|
7
|
+
const imageBuffer = Buffer.from(base64Image, "base64");
|
|
8
|
+
const Jimp = await getJimp();
|
|
9
|
+
const image = await Jimp.read(imageBuffer);
|
|
10
|
+
await image.writeAsync(outputPath);
|
|
11
|
+
}
|
|
12
|
+
async function transformImgPathToBase64(inputPath) {
|
|
13
|
+
const Jimp = await getJimp();
|
|
14
|
+
const image = await Jimp.read(inputPath);
|
|
15
|
+
const buffer = await image.getBufferAsync(Jimp.MIME_JPEG);
|
|
16
|
+
return buffer.toString("base64");
|
|
17
|
+
}
|
|
18
|
+
async function resizeImg(inputData, newSize) {
|
|
19
|
+
if (typeof inputData === "string")
|
|
20
|
+
throw Error("inputData is base64, use resizeImgBase64 instead");
|
|
21
|
+
assert(
|
|
22
|
+
newSize && newSize.width > 0 && newSize.height > 0,
|
|
23
|
+
"newSize must be positive"
|
|
24
|
+
);
|
|
25
|
+
const Jimp = await getJimp();
|
|
26
|
+
const image = await Jimp.read(inputData);
|
|
27
|
+
const { width, height } = image.bitmap;
|
|
28
|
+
if (!width || !height) {
|
|
29
|
+
throw Error("Undefined width or height from the input image.");
|
|
30
|
+
}
|
|
31
|
+
if (newSize.width === width && newSize.height === height) {
|
|
32
|
+
return inputData;
|
|
33
|
+
}
|
|
34
|
+
image.resize(newSize.width, newSize.height, Jimp.RESIZE_NEAREST_NEIGHBOR);
|
|
35
|
+
image.quality(90);
|
|
36
|
+
const resizedBuffer = await image.getBufferAsync(Jimp.MIME_JPEG);
|
|
37
|
+
return resizedBuffer;
|
|
38
|
+
}
|
|
39
|
+
async function bufferFromBase64(base64) {
|
|
40
|
+
const splitFlag = ";base64,";
|
|
41
|
+
const dataSplitted = base64.split(splitFlag);
|
|
42
|
+
if (dataSplitted.length !== 2) {
|
|
43
|
+
throw Error("Invalid base64 data");
|
|
44
|
+
}
|
|
45
|
+
return Buffer.from(dataSplitted[1], "base64");
|
|
46
|
+
}
|
|
47
|
+
async function resizeImgBase64(inputBase64, newSize) {
|
|
48
|
+
const splitFlag = ";base64,";
|
|
49
|
+
const dataSplitted = inputBase64.split(splitFlag);
|
|
50
|
+
if (dataSplitted.length !== 2) {
|
|
51
|
+
throw Error("Invalid base64 data");
|
|
52
|
+
}
|
|
53
|
+
const imageBuffer = Buffer.from(dataSplitted[1], "base64");
|
|
54
|
+
const buffer = await resizeImg(imageBuffer, newSize);
|
|
55
|
+
const content = buffer.toString("base64");
|
|
56
|
+
return `${dataSplitted[0]}${splitFlag}${content}`;
|
|
57
|
+
}
|
|
58
|
+
function zoomForGPT4o(originalWidth, originalHeight) {
|
|
59
|
+
const maxWidth = 2048;
|
|
60
|
+
const maxHeight = 768;
|
|
61
|
+
let newWidth = originalWidth;
|
|
62
|
+
let newHeight = originalHeight;
|
|
63
|
+
const aspectRatio = originalWidth / originalHeight;
|
|
64
|
+
if (originalWidth > maxWidth) {
|
|
65
|
+
newWidth = maxWidth;
|
|
66
|
+
newHeight = newWidth / aspectRatio;
|
|
67
|
+
}
|
|
68
|
+
if (newHeight > maxHeight) {
|
|
69
|
+
newHeight = maxHeight;
|
|
70
|
+
newWidth = newHeight * aspectRatio;
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
width: Math.round(newWidth),
|
|
74
|
+
height: Math.round(newHeight)
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
async function trimImage(image) {
|
|
78
|
+
const Jimp = await getJimp();
|
|
79
|
+
const jimpImage = await Jimp.read(
|
|
80
|
+
Buffer.isBuffer(image) ? image : Buffer.from(image)
|
|
81
|
+
);
|
|
82
|
+
const { width, height } = jimpImage.bitmap;
|
|
83
|
+
if (width <= 3 || height <= 3) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
const trimmedImage = jimpImage.autocrop();
|
|
87
|
+
const { width: trimmedWidth, height: trimmedHeight } = trimmedImage.bitmap;
|
|
88
|
+
const trimOffsetLeft = (width - trimmedWidth) / 2;
|
|
89
|
+
const trimOffsetTop = (height - trimmedHeight) / 2;
|
|
90
|
+
if (trimOffsetLeft === 0 && trimOffsetTop === 0) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
trimOffsetLeft: -trimOffsetLeft,
|
|
95
|
+
trimOffsetTop: -trimOffsetTop,
|
|
96
|
+
width: trimmedWidth,
|
|
97
|
+
height: trimmedHeight
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function prependBase64Header(base64, mimeType = "image/png") {
|
|
101
|
+
return `data:${mimeType};base64,${base64}`;
|
|
102
|
+
}
|
|
103
|
+
async function paddingToMatchBlock(imageBase64, blockSize = 28) {
|
|
104
|
+
const Jimp = await getJimp();
|
|
105
|
+
const imageBuffer = await bufferFromBase64(imageBase64);
|
|
106
|
+
const image = await Jimp.read(imageBuffer);
|
|
107
|
+
const { width, height } = image.bitmap;
|
|
108
|
+
const targetWidth = Math.ceil(width / blockSize) * blockSize;
|
|
109
|
+
const targetHeight = Math.ceil(height / blockSize) * blockSize;
|
|
110
|
+
if (targetWidth === width && targetHeight === height) {
|
|
111
|
+
return imageBase64;
|
|
112
|
+
}
|
|
113
|
+
const paddedImage = new Jimp(targetWidth, targetHeight, 4294967295);
|
|
114
|
+
paddedImage.composite(image, 0, 0);
|
|
115
|
+
const base64 = await paddedImage.getBase64Async(Jimp.MIME_JPEG);
|
|
116
|
+
return base64;
|
|
117
|
+
}
|
|
118
|
+
export {
|
|
119
|
+
bufferFromBase64,
|
|
120
|
+
paddingToMatchBlock,
|
|
121
|
+
prependBase64Header,
|
|
122
|
+
resizeImg,
|
|
123
|
+
resizeImgBase64,
|
|
124
|
+
saveBase64Image,
|
|
125
|
+
transformImgPathToBase64,
|
|
126
|
+
trimImage,
|
|
127
|
+
zoomForGPT4o
|
|
128
|
+
};
|
package/dist/es/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { assert } from "../utils";
|
|
6
|
+
const pkgCacheMap = {};
|
|
7
|
+
const ifInBrowser = typeof window !== "undefined";
|
|
6
8
|
function getRunningPkgInfo(dir) {
|
|
7
9
|
if (ifInBrowser) {
|
|
8
10
|
return null;
|
|
@@ -39,7 +41,22 @@ function findNearestPackageJson(dir) {
|
|
|
39
41
|
}
|
|
40
42
|
return findNearestPackageJson(parentDir);
|
|
41
43
|
}
|
|
44
|
+
async function getExtraReturnLogic(tree = false) {
|
|
45
|
+
if (ifInBrowser) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
const filename = fileURLToPath(import.meta.url);
|
|
49
|
+
const pathDir = findNearestPackageJson(dirname(filename));
|
|
50
|
+
assert(pathDir, `can't find pathDir, with ${dirname}`);
|
|
51
|
+
const scriptPath = path.join(pathDir, "./dist/script/htmlElement.js");
|
|
52
|
+
const elementInfosScriptContent = readFileSync(scriptPath, "utf-8");
|
|
53
|
+
if (tree) {
|
|
54
|
+
return `${elementInfosScriptContent}midscene_element_inspector.webExtractNodeTree()`;
|
|
55
|
+
}
|
|
56
|
+
return `${elementInfosScriptContent}midscene_element_inspector.webExtractTextWithPosition()`;
|
|
57
|
+
}
|
|
42
58
|
export {
|
|
43
59
|
findNearestPackageJson,
|
|
60
|
+
getExtraReturnLogic,
|
|
44
61
|
getRunningPkgInfo
|
|
45
62
|
};
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2017 Google Inc.
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
const _keyDefinitions = {
|
|
3
7
|
"0": { keyCode: 48, key: "0", code: "Digit0" },
|
|
4
8
|
"1": { keyCode: 49, key: "1", code: "Digit1" },
|
|
5
9
|
"2": { keyCode: 50, key: "2", code: "Digit2" },
|
|
@@ -384,7 +388,7 @@ var _keyDefinitions = {
|
|
|
384
388
|
},
|
|
385
389
|
VolumeUp: { keyCode: 183, key: "VolumeUp", code: "VolumeUp", location: 4 }
|
|
386
390
|
};
|
|
387
|
-
|
|
391
|
+
const lowerCaseKeyDefinitions = Object.entries(_keyDefinitions).reduce(
|
|
388
392
|
(acc, [key, definition]) => {
|
|
389
393
|
const lowerKey = key.toLowerCase();
|
|
390
394
|
if (lowerKey !== key) {
|
|
@@ -394,15 +398,15 @@ var lowerCaseKeyDefinitions = Object.entries(_keyDefinitions).reduce(
|
|
|
394
398
|
},
|
|
395
399
|
{}
|
|
396
400
|
);
|
|
397
|
-
|
|
401
|
+
const getKeyDefinition = (key) => {
|
|
398
402
|
const lowerKey = key.toLowerCase();
|
|
399
403
|
if (lowerCaseKeyDefinitions[lowerKey]) {
|
|
400
404
|
return lowerCaseKeyDefinitions[lowerKey].key;
|
|
401
405
|
}
|
|
402
406
|
return key;
|
|
403
407
|
};
|
|
404
|
-
|
|
405
|
-
|
|
408
|
+
const isMac = typeof window !== "undefined" ? /Mac|iPod|iPhone|iPad/.test(window.navigator.platform) : process.platform === "darwin";
|
|
409
|
+
const keyMap = {
|
|
406
410
|
return: _keyDefinitions.Enter.key,
|
|
407
411
|
enter: _keyDefinitions.Enter.key,
|
|
408
412
|
ctrl: isMac ? _keyDefinitions.Meta.key : _keyDefinitions.Control.key,
|
|
@@ -428,8 +432,3 @@ export {
|
|
|
428
432
|
isMac,
|
|
429
433
|
transformHotkeyInput
|
|
430
434
|
};
|
|
431
|
-
/**
|
|
432
|
-
* @license
|
|
433
|
-
* Copyright 2017 Google Inc.
|
|
434
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
435
|
-
*/
|