@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/lib/index.js
CHANGED
|
@@ -1,26 +1,4 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
|
-
// src/index.ts
|
|
21
|
-
var src_exports = {};
|
|
22
|
-
__export(src_exports, {
|
|
23
|
-
default: () => src_default
|
|
24
|
-
});
|
|
25
|
-
module.exports = __toCommonJS(src_exports);
|
|
26
1
|
var src_default = {};
|
|
2
|
+
export {
|
|
3
|
+
src_default as default
|
|
4
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
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";
|
|
8
|
+
function getRunningPkgInfo(dir) {
|
|
9
|
+
if (ifInBrowser) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
const dirToCheck = dir || process.cwd();
|
|
13
|
+
if (pkgCacheMap[dirToCheck]) {
|
|
14
|
+
return pkgCacheMap[dirToCheck];
|
|
15
|
+
}
|
|
16
|
+
const pkgDir = findNearestPackageJson(dirToCheck);
|
|
17
|
+
const pkgJsonFile = pkgDir ? join(pkgDir, "package.json") : null;
|
|
18
|
+
if (pkgDir && pkgJsonFile) {
|
|
19
|
+
const { name, version } = JSON.parse(readFileSync(pkgJsonFile, "utf-8"));
|
|
20
|
+
pkgCacheMap[dirToCheck] = {
|
|
21
|
+
name: name || "midscene-unknown-package-name",
|
|
22
|
+
version: version || "0.0.0",
|
|
23
|
+
dir: pkgDir
|
|
24
|
+
};
|
|
25
|
+
return pkgCacheMap[dirToCheck];
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
name: "midscene-unknown-package-name",
|
|
29
|
+
version: "0.0.0",
|
|
30
|
+
dir: dirToCheck
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function findNearestPackageJson(dir) {
|
|
34
|
+
const packageJsonPath = join(dir, "package.json");
|
|
35
|
+
if (existsSync(packageJsonPath)) {
|
|
36
|
+
return dir;
|
|
37
|
+
}
|
|
38
|
+
const parentDir = dirname(dir);
|
|
39
|
+
if (parentDir === dir) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
return findNearestPackageJson(parentDir);
|
|
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
|
+
}
|
|
58
|
+
export {
|
|
59
|
+
findNearestPackageJson,
|
|
60
|
+
getExtraReturnLogic,
|
|
61
|
+
getRunningPkgInfo
|
|
62
|
+
};
|
|
@@ -1,32 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
|
-
// src/us-keyboard-layout.ts
|
|
21
|
-
var us_keyboard_layout_exports = {};
|
|
22
|
-
__export(us_keyboard_layout_exports, {
|
|
23
|
-
_keyDefinitions: () => _keyDefinitions,
|
|
24
|
-
getKeyDefinition: () => getKeyDefinition,
|
|
25
|
-
isMac: () => isMac,
|
|
26
|
-
transformHotkeyInput: () => transformHotkeyInput
|
|
27
|
-
});
|
|
28
|
-
module.exports = __toCommonJS(us_keyboard_layout_exports);
|
|
29
|
-
var _keyDefinitions = {
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2017 Google Inc.
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
const _keyDefinitions = {
|
|
30
7
|
"0": { keyCode: 48, key: "0", code: "Digit0" },
|
|
31
8
|
"1": { keyCode: 49, key: "1", code: "Digit1" },
|
|
32
9
|
"2": { keyCode: 50, key: "2", code: "Digit2" },
|
|
@@ -411,7 +388,7 @@ var _keyDefinitions = {
|
|
|
411
388
|
},
|
|
412
389
|
VolumeUp: { keyCode: 183, key: "VolumeUp", code: "VolumeUp", location: 4 }
|
|
413
390
|
};
|
|
414
|
-
|
|
391
|
+
const lowerCaseKeyDefinitions = Object.entries(_keyDefinitions).reduce(
|
|
415
392
|
(acc, [key, definition]) => {
|
|
416
393
|
const lowerKey = key.toLowerCase();
|
|
417
394
|
if (lowerKey !== key) {
|
|
@@ -421,15 +398,15 @@ var lowerCaseKeyDefinitions = Object.entries(_keyDefinitions).reduce(
|
|
|
421
398
|
},
|
|
422
399
|
{}
|
|
423
400
|
);
|
|
424
|
-
|
|
401
|
+
const getKeyDefinition = (key) => {
|
|
425
402
|
const lowerKey = key.toLowerCase();
|
|
426
403
|
if (lowerCaseKeyDefinitions[lowerKey]) {
|
|
427
404
|
return lowerCaseKeyDefinitions[lowerKey].key;
|
|
428
405
|
}
|
|
429
406
|
return key;
|
|
430
407
|
};
|
|
431
|
-
|
|
432
|
-
|
|
408
|
+
const isMac = typeof window !== "undefined" ? /Mac|iPod|iPhone|iPad/.test(window.navigator.platform) : process.platform === "darwin";
|
|
409
|
+
const keyMap = {
|
|
433
410
|
return: _keyDefinitions.Enter.key,
|
|
434
411
|
enter: _keyDefinitions.Enter.key,
|
|
435
412
|
ctrl: isMac ? _keyDefinitions.Meta.key : _keyDefinitions.Control.key,
|
|
@@ -449,15 +426,9 @@ function transformHotkeyInput(keyInput) {
|
|
|
449
426
|
return getKeyDefinition(keyMap[key.toLowerCase()] || key);
|
|
450
427
|
});
|
|
451
428
|
}
|
|
452
|
-
|
|
453
|
-
0 && (module.exports = {
|
|
429
|
+
export {
|
|
454
430
|
_keyDefinitions,
|
|
455
431
|
getKeyDefinition,
|
|
456
432
|
isMac,
|
|
457
433
|
transformHotkeyInput
|
|
458
|
-
}
|
|
459
|
-
/**
|
|
460
|
-
* @license
|
|
461
|
-
* Copyright 2017 Google Inc.
|
|
462
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
463
|
-
*/
|
|
434
|
+
};
|