@aspiresys/visor 1.3.4 → 1.4.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/app.js +2 -2
- package/dist/config.js +2 -2
- package/dist/dialog.js +4 -4
- package/dist/display.js +21 -7
- package/dist/index.d.ts +156 -139
- package/dist/index.js +197 -163
- package/dist/inspector/index.js +10 -8
- package/dist/matcher.d.ts +2 -2
- package/dist/matcher.js +50 -25
- package/dist/mouse.d.ts +1 -1
- package/dist/mouse.js +4 -4
- package/dist/ocr.d.ts +2 -1
- package/dist/ocr.js +15 -15
- package/dist/path.js +1 -1
- package/dist/region.js +3 -4
- package/dist/screen.js +5 -5
- package/dist/src/index.js +15 -16
- package/dist/src/matcher.d.ts +1 -1
- package/dist/src/matcher.js +13 -12
- package/dist/src/mouse.d.ts +1 -1
- package/dist/src/mouse.js +9 -11
- package/dist/src/screen.js +12 -10
- package/dist/src/types.js +2 -2
- package/dist/templateMetadata.d.ts +1 -0
- package/dist/templateMetadata.js +20 -0
- package/dist/text.d.ts +1 -1
- package/dist/text.js +8 -8
- package/dist/types.d.ts +249 -159
- package/dist/types.js +330 -170
- package/dist/version.d.ts +1 -0
- package/dist/version.js +18 -0
- package/inspector/index.html +82 -55
- package/inspector/main.js +135 -189
- package/inspector/src/preload.js +10 -15
- package/inspector/src/renderer.js +177 -235
- package/inspector/start.js +8 -16
- package/inspector/styles.css +456 -458
- package/package.json +57 -51
- package/readme.md +790 -799
package/inspector/index.html
CHANGED
|
@@ -1,55 +1,82 @@
|
|
|
1
|
-
<!
|
|
2
|
-
<html>
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
</
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>VISOR INSPECTOR</title>
|
|
5
|
+
<link rel="stylesheet" href="styles.css" />
|
|
6
|
+
</head>
|
|
7
|
+
<body>
|
|
8
|
+
<div id="imageModal" class="image-modal">
|
|
9
|
+
<img id="modalImage" />
|
|
10
|
+
</div>
|
|
11
|
+
<div class="container">
|
|
12
|
+
<header class="header">
|
|
13
|
+
<h3>VISOR INSPECTOR</h3>
|
|
14
|
+
</header>
|
|
15
|
+
<section class="controls-section">
|
|
16
|
+
<div class="toolbar">
|
|
17
|
+
<button id="captureBtn" class="btn btn-primary">
|
|
18
|
+
<span class="btn-icon">📸</span> Capture Screen
|
|
19
|
+
</button>
|
|
20
|
+
<button id="saveBtn" class="btn btn-secondary">
|
|
21
|
+
<span class="btn-icon">💾</span> Save Template
|
|
22
|
+
</button>
|
|
23
|
+
<button id="loadTemplateBtn" class="btn btn-secondary">
|
|
24
|
+
<span class="btn-icon">📂</span> Load Template
|
|
25
|
+
</button>
|
|
26
|
+
<button id="testMatchBtn" class="btn btn-accent"><span class="btn-icon">✓</span> Test Match</button>
|
|
27
|
+
<div class="controls-grid">
|
|
28
|
+
<div class="control-group">
|
|
29
|
+
<div class="input-wrapper">
|
|
30
|
+
<span class="input-hint" title="Range [0, 1]">Confidence</span>
|
|
31
|
+
<input
|
|
32
|
+
type="range"
|
|
33
|
+
id="confRange"
|
|
34
|
+
min="0"
|
|
35
|
+
max="1"
|
|
36
|
+
value="0.8"
|
|
37
|
+
step="0.01"
|
|
38
|
+
oninput="document.getElementById('confidenceInput').value = this.value"
|
|
39
|
+
/>
|
|
40
|
+
<input
|
|
41
|
+
id="confidenceInput"
|
|
42
|
+
type="number"
|
|
43
|
+
min="0"
|
|
44
|
+
max="1"
|
|
45
|
+
step="0.01"
|
|
46
|
+
value="0.8"
|
|
47
|
+
onchange="document.getElementById('confRange').value = this.value"
|
|
48
|
+
/>
|
|
49
|
+
<!--<span class="input-hint">Multi Sacle Match:</span><input id="multiScaleCheck" type="checkbox" value="false"/>-->
|
|
50
|
+
<span class="input-hint">Current Template:</span
|
|
51
|
+
><span id="currentTemplate" class="template-status">None</span>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</section>
|
|
57
|
+
<div class="capture-layout">
|
|
58
|
+
<div class="capture-panel">
|
|
59
|
+
<h3 class="section-title">
|
|
60
|
+
Current Capture (X:<span id="mousex"></span>, Y:<span id="mousey"></span>, Width:<span
|
|
61
|
+
id="mousew"
|
|
62
|
+
></span
|
|
63
|
+
>, Height:<span id="mouseh"></span>)
|
|
64
|
+
</h3>
|
|
65
|
+
<canvas id="screenCanvas" class="canvas"></canvas>
|
|
66
|
+
</div>
|
|
67
|
+
<div class="result-panel">
|
|
68
|
+
<h3 class="section-title">Template</h3>
|
|
69
|
+
<img
|
|
70
|
+
id="templatePreview"
|
|
71
|
+
class="template-preview"
|
|
72
|
+
alt="No Template Loaded"
|
|
73
|
+
src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs="
|
|
74
|
+
/>
|
|
75
|
+
<h3 class="section-title">Match Result</h3>
|
|
76
|
+
<div id="matchResult">No Match Tested</div>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
<script src="./src/renderer.js"></script>
|
|
81
|
+
</body>
|
|
82
|
+
</html>
|
package/inspector/main.js
CHANGED
|
@@ -1,189 +1,135 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
const screen = await visorMatcher.loadScreen(capturePath);
|
|
137
|
-
const template = await visorMatcher.loadScreen(data.templatePath);
|
|
138
|
-
const result = visorMatcher.findAllInspectorMatches(
|
|
139
|
-
screen,
|
|
140
|
-
template,
|
|
141
|
-
data.confidence
|
|
142
|
-
);
|
|
143
|
-
` const result = visorMatcher.matchInspectorTemplate(
|
|
144
|
-
screen,
|
|
145
|
-
template,
|
|
146
|
-
data.confidence,
|
|
147
|
-
data.isMultiMatch
|
|
148
|
-
);`
|
|
149
|
-
console.log("match Result:", result);
|
|
150
|
-
screen.delete();
|
|
151
|
-
template.delete();
|
|
152
|
-
return result;
|
|
153
|
-
}
|
|
154
|
-
);
|
|
155
|
-
ipcMain.handle("select-template",
|
|
156
|
-
async () => {
|
|
157
|
-
const result = await dialog.showOpenDialog({
|
|
158
|
-
properties: ["openFile"],
|
|
159
|
-
filters: [{
|
|
160
|
-
name: "PNG Images",
|
|
161
|
-
extensions: [
|
|
162
|
-
"png"
|
|
163
|
-
]
|
|
164
|
-
}]
|
|
165
|
-
});
|
|
166
|
-
if (result.canceled || result.filePaths.length === 0) {
|
|
167
|
-
return null;
|
|
168
|
-
}
|
|
169
|
-
return result.filePaths[0];
|
|
170
|
-
}
|
|
171
|
-
);
|
|
172
|
-
ipcMain.handle("save-template-dialog",
|
|
173
|
-
async (event, selection) => {
|
|
174
|
-
const saveResult = await dialog.showSaveDialog({
|
|
175
|
-
title: "Save Template",
|
|
176
|
-
defaultPath: "template.png",
|
|
177
|
-
filters: [{
|
|
178
|
-
name: "PNG Images",
|
|
179
|
-
extensions: [
|
|
180
|
-
"png"
|
|
181
|
-
]
|
|
182
|
-
}]
|
|
183
|
-
});
|
|
184
|
-
if (saveResult.canceled) {
|
|
185
|
-
return null;
|
|
186
|
-
}
|
|
187
|
-
return saveResult.filePath;
|
|
188
|
-
}
|
|
189
|
-
);
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { app, BrowserWindow, ipcMain, dialog, screen } = require('electron');
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const sharp = require('sharp');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
let mainWindow;
|
|
9
|
+
const visorScreen = require('../dist/screen.js');
|
|
10
|
+
const visorMatcher = require('../dist/matcher.js');
|
|
11
|
+
function createWindow() {
|
|
12
|
+
mainWindow = new BrowserWindow({
|
|
13
|
+
width: 1400,
|
|
14
|
+
height: 900,
|
|
15
|
+
webPreferences: {
|
|
16
|
+
preload: path.join(__dirname, 'src', 'preload.js'),
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
mainWindow.loadFile('index.html');
|
|
20
|
+
}
|
|
21
|
+
app.whenReady().then(createWindow);
|
|
22
|
+
ipcMain.handle('capture-screen', async () => {
|
|
23
|
+
const screenshot = require('screenshot-desktop');
|
|
24
|
+
mainWindow.hide();
|
|
25
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
26
|
+
const image = await screenshot({ format: 'png' });
|
|
27
|
+
mainWindow.show();
|
|
28
|
+
mainWindow.focus();
|
|
29
|
+
const filePath = path.join(__dirname, 'assets', 'capture.png');
|
|
30
|
+
fs.writeFileSync(filePath, image);
|
|
31
|
+
return filePath;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
ipcMain.handle('save-template', async (event, selection) => {
|
|
35
|
+
const source = path.join(__dirname, 'assets', 'capture.png');
|
|
36
|
+
const output = selection.outputPath;
|
|
37
|
+
await sharp(source)
|
|
38
|
+
.extract({
|
|
39
|
+
left: Math.round(selection.x),
|
|
40
|
+
top: Math.round(selection.y),
|
|
41
|
+
width: Math.round(selection.width),
|
|
42
|
+
height: Math.round(selection.height),
|
|
43
|
+
})
|
|
44
|
+
.toFile(output);
|
|
45
|
+
const templateDir = path.join(__dirname, 'templates');
|
|
46
|
+
fs.mkdirSync(templateDir, {
|
|
47
|
+
recursive: true,
|
|
48
|
+
});
|
|
49
|
+
const inspectorCopy = path.join(templateDir, path.basename(output));
|
|
50
|
+
|
|
51
|
+
await sharp(source)
|
|
52
|
+
.extract({
|
|
53
|
+
left: Math.round(selection.x),
|
|
54
|
+
top: Math.round(selection.y),
|
|
55
|
+
width: Math.round(selection.width),
|
|
56
|
+
height: Math.round(selection.height),
|
|
57
|
+
})
|
|
58
|
+
.toFile(inspectorCopy);
|
|
59
|
+
const display = screen.getPrimaryDisplay();
|
|
60
|
+
const metadata = {
|
|
61
|
+
capturedResolution: {
|
|
62
|
+
width: Math.round(display.size.width * display.scaleFactor),
|
|
63
|
+
height: Math.round(display.size.height * display.scaleFactor),
|
|
64
|
+
},
|
|
65
|
+
templateSize: {
|
|
66
|
+
width: Math.round(selection.width),
|
|
67
|
+
height: Math.round(selection.height),
|
|
68
|
+
},
|
|
69
|
+
capturedScaleFactor: display.scaleFactor,
|
|
70
|
+
capturedAt: new Date().toISOString(),
|
|
71
|
+
};
|
|
72
|
+
const outputMetadataPath = output.replace(/\.png$/i, '.properties.json');
|
|
73
|
+
fs.writeFileSync(outputMetadataPath, JSON.stringify(metadata, null, 2));
|
|
74
|
+
const metadataPath = inspectorCopy.replace(/\.png$/i, '.properties.json');
|
|
75
|
+
fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));
|
|
76
|
+
return output;
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
ipcMain.handle('get-latest-template', async () => {
|
|
80
|
+
const templatesDir = path.join(__dirname, 'templates');
|
|
81
|
+
if (!fs.existsSync(templatesDir)) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
const files = fs.readdirSync(templatesDir);
|
|
85
|
+
const pngs = files
|
|
86
|
+
.filter((f) => f.endsWith('.png'))
|
|
87
|
+
.sort()
|
|
88
|
+
.reverse();
|
|
89
|
+
if (pngs.length === 0) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
return path.join(templatesDir, pngs[0]);
|
|
93
|
+
});
|
|
94
|
+
ipcMain.handle('test-match', async (event, data) => {
|
|
95
|
+
console.log('Test Match IPC', data);
|
|
96
|
+
const capturePath = path.join(__dirname, 'assets', 'capture.png');
|
|
97
|
+
const screen = await visorMatcher.loadScreen(capturePath);
|
|
98
|
+
const template = await visorMatcher.loadScreen(data.templatePath);
|
|
99
|
+
const result = visorMatcher.findAllInspectorMatches(screen, template, data.confidence);
|
|
100
|
+
console.log('match Result:', result);
|
|
101
|
+
screen.delete();
|
|
102
|
+
template.delete();
|
|
103
|
+
return result;
|
|
104
|
+
});
|
|
105
|
+
ipcMain.handle('select-template', async () => {
|
|
106
|
+
const result = await dialog.showOpenDialog({
|
|
107
|
+
properties: ['openFile'],
|
|
108
|
+
filters: [
|
|
109
|
+
{
|
|
110
|
+
name: 'PNG Images',
|
|
111
|
+
extensions: ['png'],
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
});
|
|
115
|
+
if (result.canceled || result.filePaths.length === 0) {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
return result.filePaths[0];
|
|
119
|
+
});
|
|
120
|
+
ipcMain.handle('save-template-dialog', async (event, selection) => {
|
|
121
|
+
const saveResult = await dialog.showSaveDialog({
|
|
122
|
+
title: 'Save Template',
|
|
123
|
+
defaultPath: 'template.png',
|
|
124
|
+
filters: [
|
|
125
|
+
{
|
|
126
|
+
name: 'PNG Images',
|
|
127
|
+
extensions: ['png'],
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
});
|
|
131
|
+
if (saveResult.canceled) {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
return saveResult.filePath;
|
|
135
|
+
});
|
package/inspector/src/preload.js
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
const {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
testMatch: (data) => ipcRenderer.invoke("test-match", data),
|
|
12
|
-
selectTemplate: () => ipcRenderer.invoke("select-template"),
|
|
13
|
-
saveTemplateDialog: (selection) => ipcRenderer.invoke("save-template-dialog", selection)
|
|
14
|
-
}
|
|
15
|
-
);
|
|
1
|
+
const { contextBridge, ipcRenderer } = require('electron');
|
|
2
|
+
|
|
3
|
+
contextBridge.exposeInMainWorld('visor', {
|
|
4
|
+
capture: () => ipcRenderer.invoke('capture-screen'),
|
|
5
|
+
saveTemplate: (selection) => ipcRenderer.invoke('save-template', selection),
|
|
6
|
+
getLatestTemplate: () => ipcRenderer.invoke('get-latest-template'),
|
|
7
|
+
testMatch: (data) => ipcRenderer.invoke('test-match', data),
|
|
8
|
+
selectTemplate: () => ipcRenderer.invoke('select-template'),
|
|
9
|
+
saveTemplateDialog: (selection) => ipcRenderer.invoke('save-template-dialog', selection),
|
|
10
|
+
});
|