@aspiresys/visor 1.3.5 → 1.4.1

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