From 7136666fdada371222ca66cdb9be7a492e16dc30 Mon Sep 17 00:00:00 2001 From: will wade Date: Fri, 1 Nov 2024 10:31:27 +0000 Subject: [PATCH 01/22] init for this work --- nodejs/sender-monitor/main.js | 30 +++++++++++++++++++++++++++ nodejs/sender-monitor/overlay.html | 25 ++++++++++++++++++++++ nodejs/sender-monitor/overlay.js | 33 ++++++++++++++++++++++++++++++ nodejs/sender-monitor/package.json | 4 +++- 4 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 nodejs/sender-monitor/overlay.html create mode 100644 nodejs/sender-monitor/overlay.js diff --git a/nodejs/sender-monitor/main.js b/nodejs/sender-monitor/main.js index a29a0dd..6ce5e1b 100644 --- a/nodejs/sender-monitor/main.js +++ b/nodejs/sender-monitor/main.js @@ -38,6 +38,32 @@ ipcMain.on("close-qr-window", () => { } }); +function createOverlayWindow() { + const overlayWindow = new BrowserWindow({ + fullscreen: true, + frame: false, + transparent: true, + alwaysOnTop: true, + resizable: false, + webPreferences: { + contextIsolation: true, + preload: path.join(__dirname, "overlay-preload.js"), + }, + }); + + overlayWindow.loadURL(`file://${__dirname}/overlay.html`); + overlayWindow.on("closed", () => { + overlayWindow = null; + }); +} + +ipcMain.on("set-ocr-boundaries", (event, bounds) => { + config.captureArea = bounds; + logMessage(`Updated OCR boundaries: ${JSON.stringify(bounds)}`); + // Save config if needed, to persist changes + fs.writeFileSync(configFilePath, JSON.stringify(config, null, 2), "utf-8"); +}); + async function createQRWindow(qrDataUrl) { if (qrWindow) { qrWindow.close(); @@ -238,6 +264,10 @@ function updateTrayMenu() { click: () => shell.openPath(configFilePath) .catch(err => console.error("Failed to open config file:", err)) }, + { + label: "Define OCR Area", // New option to define OCR area + click: createOverlayWindow, + }, { label: "Reload Config", click: reloadConfig, diff --git a/nodejs/sender-monitor/overlay.html b/nodejs/sender-monitor/overlay.html new file mode 100644 index 0000000..17a12e3 --- /dev/null +++ b/nodejs/sender-monitor/overlay.html @@ -0,0 +1,25 @@ + + + + + + Select OCR Area + + + + + + + + + \ No newline at end of file diff --git a/nodejs/sender-monitor/overlay.js b/nodejs/sender-monitor/overlay.js new file mode 100644 index 0000000..6761243 --- /dev/null +++ b/nodejs/sender-monitor/overlay.js @@ -0,0 +1,33 @@ +const { ipcRenderer } = require("electron"); + +const canvas = document.getElementById("selectionCanvas"); +const ctx = canvas.getContext("2d"); + +let startX, startY, isDrawing = false; + +canvas.addEventListener("mousedown", (e) => { + startX = e.clientX; + startY = e.clientY; + isDrawing = true; +}); + +canvas.addEventListener("mousemove", (e) => { + if (!isDrawing) return; + ctx.clearRect(0, 0, canvas.width, canvas.height); + const width = e.clientX - startX; + const height = e.clientY - startY; + ctx.strokeStyle = "red"; + ctx.lineWidth = 2; + ctx.strokeRect(startX, startY, width, height); +}); + +canvas.addEventListener("mouseup", (e) => { + if (!isDrawing) return; + isDrawing = false; + const width = e.clientX - startX; + const height = e.clientY - startY; + + // Send coordinates to main process and close the overlay + ipcRenderer.send("set-ocr-boundaries", { x: startX, y: startY, width, height }); + window.close(); +}); \ No newline at end of file diff --git a/nodejs/sender-monitor/package.json b/nodejs/sender-monitor/package.json index 7cf1dc8..6551db8 100644 --- a/nodejs/sender-monitor/package.json +++ b/nodejs/sender-monitor/package.json @@ -24,6 +24,8 @@ "files": [ "main.js", "webrtc.js", + "overlay.html", + "overlay.js", "ocr.js", "iceServers.js", "preload.js", @@ -64,4 +66,4 @@ "electron": "^32.0.0", "electron-builder": "^25.1.8" } -} +} \ No newline at end of file From 5c7b25b6a4200e5c61d6405053e31de05d5e52ac Mon Sep 17 00:00:00 2001 From: will wade Date: Fri, 1 Nov 2024 10:33:59 +0000 Subject: [PATCH 02/22] rework of html to rid of scroll --- nodejs/sender-monitor/overlay.html | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/nodejs/sender-monitor/overlay.html b/nodejs/sender-monitor/overlay.html index 17a12e3..9f5602d 100644 --- a/nodejs/sender-monitor/overlay.html +++ b/nodejs/sender-monitor/overlay.html @@ -6,12 +6,18 @@ Select OCR Area From 067349d0bed5db5c0e8bad2a9cdfa227f446e033 Mon Sep 17 00:00:00 2001 From: will wade Date: Fri, 1 Nov 2024 10:35:37 +0000 Subject: [PATCH 03/22] trying to fix box drawing --- nodejs/sender-monitor/overlay.js | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/nodejs/sender-monitor/overlay.js b/nodejs/sender-monitor/overlay.js index 6761243..f25df56 100644 --- a/nodejs/sender-monitor/overlay.js +++ b/nodejs/sender-monitor/overlay.js @@ -3,31 +3,54 @@ const { ipcRenderer } = require("electron"); const canvas = document.getElementById("selectionCanvas"); const ctx = canvas.getContext("2d"); +// Ensure canvas dimensions match the window size +canvas.width = window.innerWidth; +canvas.height = window.innerHeight; + let startX, startY, isDrawing = false; canvas.addEventListener("mousedown", (e) => { + // Start drawing startX = e.clientX; startY = e.clientY; isDrawing = true; }); canvas.addEventListener("mousemove", (e) => { + // Only draw if the mouse is pressed down if (!isDrawing) return; + + // Clear the canvas before redrawing the rectangle ctx.clearRect(0, 0, canvas.width, canvas.height); + + // Calculate width and height from start to current mouse position const width = e.clientX - startX; const height = e.clientY - startY; + + // Draw the rectangle ctx.strokeStyle = "red"; ctx.lineWidth = 2; ctx.strokeRect(startX, startY, width, height); }); canvas.addEventListener("mouseup", (e) => { + // Stop drawing if (!isDrawing) return; isDrawing = false; + + // Finalize width and height calculations const width = e.clientX - startX; const height = e.clientY - startY; - // Send coordinates to main process and close the overlay + // Send the coordinates to the main process ipcRenderer.send("set-ocr-boundaries", { x: startX, y: startY, width, height }); + + // Close the window after drawing is complete window.close(); +}); + +// Resize the canvas to keep it fullscreen if the window resizes +window.addEventListener("resize", () => { + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; }); \ No newline at end of file From 97e89040e61d29ac38dbbc1791edd6c98b4c1ce3 Mon Sep 17 00:00:00 2001 From: will wade Date: Fri, 1 Nov 2024 10:38:54 +0000 Subject: [PATCH 04/22] let not const --- nodejs/sender-monitor/main.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nodejs/sender-monitor/main.js b/nodejs/sender-monitor/main.js index 6ce5e1b..a68e4e7 100644 --- a/nodejs/sender-monitor/main.js +++ b/nodejs/sender-monitor/main.js @@ -39,7 +39,7 @@ ipcMain.on("close-qr-window", () => { }); function createOverlayWindow() { - const overlayWindow = new BrowserWindow({ + let overlayWindow = new BrowserWindow({ // Changed from const to let fullscreen: true, frame: false, transparent: true, @@ -60,7 +60,7 @@ function createOverlayWindow() { ipcMain.on("set-ocr-boundaries", (event, bounds) => { config.captureArea = bounds; logMessage(`Updated OCR boundaries: ${JSON.stringify(bounds)}`); - // Save config if needed, to persist changes + // Save updated config if persistence is needed fs.writeFileSync(configFilePath, JSON.stringify(config, null, 2), "utf-8"); }); From e9dfc389b229ca44267d7f84900a722dbac2b208 Mon Sep 17 00:00:00 2001 From: will wade Date: Fri, 1 Nov 2024 11:13:24 +0000 Subject: [PATCH 05/22] add logging --- nodejs/sender-monitor/main.js | 3 ++- nodejs/sender-monitor/overlay.js | 25 +++++++++++++++---------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/nodejs/sender-monitor/main.js b/nodejs/sender-monitor/main.js index a68e4e7..c1f26dd 100644 --- a/nodejs/sender-monitor/main.js +++ b/nodejs/sender-monitor/main.js @@ -39,7 +39,7 @@ ipcMain.on("close-qr-window", () => { }); function createOverlayWindow() { - let overlayWindow = new BrowserWindow({ // Changed from const to let + let overlayWindow = new BrowserWindow({ fullscreen: true, frame: false, transparent: true, @@ -52,6 +52,7 @@ function createOverlayWindow() { }); overlayWindow.loadURL(`file://${__dirname}/overlay.html`); + overlayWindow.webContents.openDevTools(); // Open DevTools for debugging overlayWindow.on("closed", () => { overlayWindow = null; }); diff --git a/nodejs/sender-monitor/overlay.js b/nodejs/sender-monitor/overlay.js index f25df56..49eda9d 100644 --- a/nodejs/sender-monitor/overlay.js +++ b/nodejs/sender-monitor/overlay.js @@ -3,27 +3,31 @@ const { ipcRenderer } = require("electron"); const canvas = document.getElementById("selectionCanvas"); const ctx = canvas.getContext("2d"); -// Ensure canvas dimensions match the window size +// Set canvas dimensions to match the window canvas.width = window.innerWidth; canvas.height = window.innerHeight; let startX, startY, isDrawing = false; +// Logging function for debugging +function logMessage(message) { + console.log(`[Overlay] ${message}`); +} + canvas.addEventListener("mousedown", (e) => { - // Start drawing + logMessage("Mouse down event detected."); startX = e.clientX; startY = e.clientY; isDrawing = true; }); canvas.addEventListener("mousemove", (e) => { - // Only draw if the mouse is pressed down if (!isDrawing) return; + logMessage(`Mouse move: ${e.clientX}, ${e.clientY}`); - // Clear the canvas before redrawing the rectangle + // Clear the canvas before drawing a new rectangle ctx.clearRect(0, 0, canvas.width, canvas.height); - // Calculate width and height from start to current mouse position const width = e.clientX - startX; const height = e.clientY - startY; @@ -34,23 +38,24 @@ canvas.addEventListener("mousemove", (e) => { }); canvas.addEventListener("mouseup", (e) => { - // Stop drawing + logMessage("Mouse up event detected."); if (!isDrawing) return; isDrawing = false; - // Finalize width and height calculations const width = e.clientX - startX; const height = e.clientY - startY; + // Log the final rectangle coordinates for debugging + logMessage(`Final rectangle: x=${startX}, y=${startY}, width=${width}, height=${height}`); + // Send the coordinates to the main process ipcRenderer.send("set-ocr-boundaries", { x: startX, y: startY, width, height }); - - // Close the window after drawing is complete window.close(); }); -// Resize the canvas to keep it fullscreen if the window resizes +// Ensure the canvas resizes correctly if the window size changes window.addEventListener("resize", () => { canvas.width = window.innerWidth; canvas.height = window.innerHeight; + logMessage("Canvas resized to fit window."); }); \ No newline at end of file From 0b9d66730d9f56f92e4da41048e1b787a3d402f5 Mon Sep 17 00:00:00 2001 From: will wade Date: Fri, 1 Nov 2024 11:19:39 +0000 Subject: [PATCH 06/22] preload overlay --- nodejs/sender-monitor/overlay-preload.js | 8 ++++++++ nodejs/sender-monitor/overlay.js | 18 ++++-------------- 2 files changed, 12 insertions(+), 14 deletions(-) create mode 100644 nodejs/sender-monitor/overlay-preload.js diff --git a/nodejs/sender-monitor/overlay-preload.js b/nodejs/sender-monitor/overlay-preload.js new file mode 100644 index 0000000..ee2ba1b --- /dev/null +++ b/nodejs/sender-monitor/overlay-preload.js @@ -0,0 +1,8 @@ +// overlay-preload.js + +const { contextBridge, ipcRenderer } = require("electron"); + +// Expose only the necessary Electron APIs to the renderer +contextBridge.exposeInMainWorld("electronAPI", { + sendOCRBounds: (bounds) => ipcRenderer.send("set-ocr-boundaries", bounds) +}); \ No newline at end of file diff --git a/nodejs/sender-monitor/overlay.js b/nodejs/sender-monitor/overlay.js index 49eda9d..acdf442 100644 --- a/nodejs/sender-monitor/overlay.js +++ b/nodejs/sender-monitor/overlay.js @@ -1,4 +1,4 @@ -const { ipcRenderer } = require("electron"); +// overlay.js const canvas = document.getElementById("selectionCanvas"); const ctx = canvas.getContext("2d"); @@ -9,13 +9,7 @@ canvas.height = window.innerHeight; let startX, startY, isDrawing = false; -// Logging function for debugging -function logMessage(message) { - console.log(`[Overlay] ${message}`); -} - canvas.addEventListener("mousedown", (e) => { - logMessage("Mouse down event detected."); startX = e.clientX; startY = e.clientY; isDrawing = true; @@ -23,7 +17,6 @@ canvas.addEventListener("mousedown", (e) => { canvas.addEventListener("mousemove", (e) => { if (!isDrawing) return; - logMessage(`Mouse move: ${e.clientX}, ${e.clientY}`); // Clear the canvas before drawing a new rectangle ctx.clearRect(0, 0, canvas.width, canvas.height); @@ -38,18 +31,16 @@ canvas.addEventListener("mousemove", (e) => { }); canvas.addEventListener("mouseup", (e) => { - logMessage("Mouse up event detected."); if (!isDrawing) return; isDrawing = false; const width = e.clientX - startX; const height = e.clientY - startY; - // Log the final rectangle coordinates for debugging - logMessage(`Final rectangle: x=${startX}, y=${startY}, width=${width}, height=${height}`); + // Send the coordinates to the main process via electronAPI + window.electronAPI.sendOCRBounds({ x: startX, y: startY, width, height }); - // Send the coordinates to the main process - ipcRenderer.send("set-ocr-boundaries", { x: startX, y: startY, width, height }); + // Close the overlay window after sending the data window.close(); }); @@ -57,5 +48,4 @@ canvas.addEventListener("mouseup", (e) => { window.addEventListener("resize", () => { canvas.width = window.innerWidth; canvas.height = window.innerHeight; - logMessage("Canvas resized to fit window."); }); \ No newline at end of file From 770b621b05dd4cabb4d1b1cc759eb57936af2212 Mon Sep 17 00:00:00 2001 From: will wade Date: Fri, 1 Nov 2024 11:21:44 +0000 Subject: [PATCH 07/22] turn dev tools off --- nodejs/sender-monitor/main.js | 1 - 1 file changed, 1 deletion(-) diff --git a/nodejs/sender-monitor/main.js b/nodejs/sender-monitor/main.js index c1f26dd..1845a1b 100644 --- a/nodejs/sender-monitor/main.js +++ b/nodejs/sender-monitor/main.js @@ -52,7 +52,6 @@ function createOverlayWindow() { }); overlayWindow.loadURL(`file://${__dirname}/overlay.html`); - overlayWindow.webContents.openDevTools(); // Open DevTools for debugging overlayWindow.on("closed", () => { overlayWindow = null; }); From 1b6ee6536db32a977fb4b2c2a673e0ee228deb4b Mon Sep 17 00:00:00 2001 From: will wade Date: Fri, 1 Nov 2024 11:23:41 +0000 Subject: [PATCH 08/22] add this to package --- nodejs/sender-monitor/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/nodejs/sender-monitor/package.json b/nodejs/sender-monitor/package.json index 6551db8..ecc5c3b 100644 --- a/nodejs/sender-monitor/package.json +++ b/nodejs/sender-monitor/package.json @@ -26,6 +26,7 @@ "webrtc.js", "overlay.html", "overlay.js", + "overlay-preload.js", "ocr.js", "iceServers.js", "preload.js", From 3a45560539fa6b026d3c8ac40d3cc9b9dc597e39 Mon Sep 17 00:00:00 2001 From: will wade Date: Fri, 1 Nov 2024 11:32:08 +0000 Subject: [PATCH 09/22] correct reloading of config and app --- nodejs/sender-monitor/main.js | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/nodejs/sender-monitor/main.js b/nodejs/sender-monitor/main.js index 1845a1b..7563f78 100644 --- a/nodejs/sender-monitor/main.js +++ b/nodejs/sender-monitor/main.js @@ -108,7 +108,34 @@ function reloadConfig() { config = JSON.parse(fs.readFileSync(configFilePath, "utf-8")); console.log("Configuration reloaded."); logMessage("Configuration reloaded from config.json."); - // You may want to reinitialize any settings here that depend on the config + + // Stop any existing monitoring intervals + if (clipboardMonitorInterval) { + clearInterval(clipboardMonitorInterval); + clipboardMonitorInterval = null; + } + if (ocrMonitorInterval) { + clearInterval(ocrMonitorInterval); + ocrMonitorInterval = null; + } + + // Start the appropriate monitoring based on the reloaded config + if (config.monitorMode === "clipboard") { + clipboardMonitorInterval = setInterval(() => { + const currentText = clipboard.readText(); + processAndSendText(currentText); + }, config.captureInterval); + console.log("Switched to clipboard monitoring mode."); + logMessage("Switched to clipboard monitoring mode."); + } else if (config.monitorMode === "ocr") { + ocrMonitorInterval = setInterval(async () => { + const recognizedText = await captureAndProcessScreen(); + processAndSendText(recognizedText); + }, config.captureInterval); + console.log("Switched to OCR monitoring mode."); + logMessage("Switched to OCR monitoring mode."); + } + } catch (error) { console.error("Failed to reload config:", error); logMessage("Failed to reload config."); From 3b796ce2b0749bfac925244bf27d3ba013213578 Mon Sep 17 00:00:00 2001 From: will wade Date: Fri, 1 Nov 2024 11:33:22 +0000 Subject: [PATCH 10/22] add translation to reload --- nodejs/sender-monitor/main.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nodejs/sender-monitor/main.js b/nodejs/sender-monitor/main.js index 7563f78..4b85aa4 100644 --- a/nodejs/sender-monitor/main.js +++ b/nodejs/sender-monitor/main.js @@ -136,6 +136,11 @@ function reloadConfig() { logMessage("Switched to OCR monitoring mode."); } + // Update translation settings based on the reloaded config + const isTranslationEnabled = config.translation?.enabled || false; + console.log(`Translation enabled: ${isTranslationEnabled}`); + logMessage(`Translation enabled: ${isTranslationEnabled}`); + } catch (error) { console.error("Failed to reload config:", error); logMessage("Failed to reload config."); From c4276f7b60e7d4dfb3663f80d93bd4db163ed0f9 Mon Sep 17 00:00:00 2001 From: will wade Date: Fri, 1 Nov 2024 11:38:34 +0000 Subject: [PATCH 11/22] add logging --- nodejs/sender-monitor/main.js | 5 ++++- nodejs/sender-monitor/ocr.js | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/nodejs/sender-monitor/main.js b/nodejs/sender-monitor/main.js index 4b85aa4..c947ba4 100644 --- a/nodejs/sender-monitor/main.js +++ b/nodejs/sender-monitor/main.js @@ -165,10 +165,13 @@ async function captureAndProcessScreen() { return ""; // Exit early if file creation failed } + // Call performOCR with the useEdgeForOCR flag const recognizedText = await performOCR(filePath, useEdgeForOCR); + + // Log recognized text console.log("OCR completed, recognized text:", recognizedText); - // Clean up the temp file only after OCR completes + // Clean up the temp file after OCR completes fs.unlinkSync(filePath); return recognizedText || ""; // Return the OCR text or an empty string diff --git a/nodejs/sender-monitor/ocr.js b/nodejs/sender-monitor/ocr.js index de2acea..b4c8d10 100644 --- a/nodejs/sender-monitor/ocr.js +++ b/nodejs/sender-monitor/ocr.js @@ -47,6 +47,8 @@ const ocrImageEdge = edge.func({ // Main OCR function that switches based on config async function performOCR(filePath, useEdgeForOCR) { + console.log("performOCR called with useEdgeForOCR:", useEdgeForOCR); // Debug log + if (useEdgeForOCR) { try { const text = await ocrImageEdge(filePath); From d14994b343984a1881040b7d334ede7a42b06d9e Mon Sep 17 00:00:00 2001 From: will wade Date: Fri, 1 Nov 2024 11:47:39 +0000 Subject: [PATCH 12/22] whoops wrong config method --- nodejs/sender-monitor/main.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nodejs/sender-monitor/main.js b/nodejs/sender-monitor/main.js index c947ba4..29b5f5d 100644 --- a/nodejs/sender-monitor/main.js +++ b/nodejs/sender-monitor/main.js @@ -149,7 +149,8 @@ function reloadConfig() { // Capture and OCR function with return of recognized text async function captureAndProcessScreen() { - const { x, y, width, height, useEdgeForOCR } = config.captureArea; + const { x, y, width, height } = config.captureArea; + const useEdgeForOCR = config.useEdgeForOCR; try { const monitor = Monitor.all().find(m => m.isPrimary); From 3881ad6256ba5f7e0c3340783ac9b107bfa3da9b Mon Sep 17 00:00:00 2001 From: will wade Date: Fri, 1 Nov 2024 12:23:53 +0000 Subject: [PATCH 13/22] try this refactor --- nodejs/sender-monitor/ocr.js | 39 ++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/nodejs/sender-monitor/ocr.js b/nodejs/sender-monitor/ocr.js index b4c8d10..a6af70d 100644 --- a/nodejs/sender-monitor/ocr.js +++ b/nodejs/sender-monitor/ocr.js @@ -20,18 +20,35 @@ const ocrImageEdge = edge.func({ { public async Task Invoke(dynamic input) { - string filePath = (string)input; - var storageFile = await StorageFile.GetFileFromPathAsync(filePath); - - using (IRandomAccessStream stream = await storageFile.OpenAsync(FileAccessMode.Read)) + try { - var decoder = await BitmapDecoder.CreateAsync(stream); - var bitmap = await decoder.GetSoftwareBitmapAsync(); + // Load image file from the provided path + string filePath = (string)input; + var storageFile = await StorageFile.GetFileFromPathAsync(filePath); + + using (IRandomAccessStream stream = await storageFile.OpenAsync(FileAccessMode.Read)) + { + var decoder = await BitmapDecoder.CreateAsync(stream); + var bitmap = await decoder.GetSoftwareBitmapAsync(); + + // Check if bitmap was successfully created + if (bitmap == null) return "Bitmap loading failed"; + + // Create OCR engine and ensure it was initialized + var ocrEngine = OcrEngine.TryCreateFromUserProfileLanguages(); + if (ocrEngine == null) return "OCR Engine creation failed"; - var ocrEngine = OcrEngine.TryCreateFromUserProfileLanguages(); - var ocrResult = await ocrEngine.RecognizeAsync(bitmap); + // Perform OCR and check if result is valid + var ocrResult = await ocrEngine.RecognizeAsync(bitmap); + if (ocrResult == null || ocrResult.Text == null) return "OCR result is empty or null"; - return ocrResult.Text; + return ocrResult.Text; + } + } + catch (Exception ex) + { + // Return any exception message for debugging + return $"Error: {ex.Message}"; } } } @@ -47,13 +64,13 @@ const ocrImageEdge = edge.func({ // Main OCR function that switches based on config async function performOCR(filePath, useEdgeForOCR) { - console.log("performOCR called with useEdgeForOCR:", useEdgeForOCR); // Debug log + console.log("performOCR called with useEdgeForOCR:", useEdgeForOCR); if (useEdgeForOCR) { try { const text = await ocrImageEdge(filePath); console.log("Recognized text (Windows.Media.Ocr):", text); - return text; + return text || ""; // Return text or an empty string if text is undefined } catch (error) { console.error("Windows.Media.Ocr failed:", error); return null; From 5368d1a857605c023d0d9f7649dd45970240c59b Mon Sep 17 00:00:00 2001 From: will wade Date: Fri, 1 Nov 2024 12:25:18 +0000 Subject: [PATCH 14/22] remove $ --- nodejs/sender-monitor/ocr.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/nodejs/sender-monitor/ocr.js b/nodejs/sender-monitor/ocr.js index a6af70d..c70275e 100644 --- a/nodejs/sender-monitor/ocr.js +++ b/nodejs/sender-monitor/ocr.js @@ -22,7 +22,6 @@ const ocrImageEdge = edge.func({ { try { - // Load image file from the provided path string filePath = (string)input; var storageFile = await StorageFile.GetFileFromPathAsync(filePath); @@ -31,14 +30,11 @@ const ocrImageEdge = edge.func({ var decoder = await BitmapDecoder.CreateAsync(stream); var bitmap = await decoder.GetSoftwareBitmapAsync(); - // Check if bitmap was successfully created if (bitmap == null) return "Bitmap loading failed"; - // Create OCR engine and ensure it was initialized var ocrEngine = OcrEngine.TryCreateFromUserProfileLanguages(); if (ocrEngine == null) return "OCR Engine creation failed"; - // Perform OCR and check if result is valid var ocrResult = await ocrEngine.RecognizeAsync(bitmap); if (ocrResult == null || ocrResult.Text == null) return "OCR result is empty or null"; @@ -47,8 +43,7 @@ const ocrImageEdge = edge.func({ } catch (Exception ex) { - // Return any exception message for debugging - return $"Error: {ex.Message}"; + return "Error: " + ex.Message; } } } From 7f824959902073e94fc88c10f1dd62e6b70bc392 Mon Sep 17 00:00:00 2001 From: will wade Date: Fri, 1 Nov 2024 12:27:11 +0000 Subject: [PATCH 15/22] adding more error catching --- nodejs/sender-monitor/ocr.js | 88 +++++++++++++++++++++++++++--------- 1 file changed, 66 insertions(+), 22 deletions(-) diff --git a/nodejs/sender-monitor/ocr.js b/nodejs/sender-monitor/ocr.js index c70275e..d3a7456 100644 --- a/nodejs/sender-monitor/ocr.js +++ b/nodejs/sender-monitor/ocr.js @@ -58,29 +58,73 @@ const ocrImageEdge = edge.func({ // Main OCR function that switches based on config -async function performOCR(filePath, useEdgeForOCR) { - console.log("performOCR called with useEdgeForOCR:", useEdgeForOCR); - - if (useEdgeForOCR) { - try { - const text = await ocrImageEdge(filePath); - console.log("Recognized text (Windows.Media.Ocr):", text); - return text || ""; // Return text or an empty string if text is undefined - } catch (error) { - console.error("Windows.Media.Ocr failed:", error); - return null; - } - } else { - try { - const { data: { text } } = await Tesseract.recognize(filePath, "eng"); - console.log("Recognized text (Tesseract.js):", text); - return text; - } catch (error) { - console.error("Tesseract.js OCR failed:", error); - return null; +const ocrImageEdge = edge.func({ + source: function () {/* + using System; + using System.Threading.Tasks; + using Windows.Graphics.Imaging; + using Windows.Media.Ocr; + using Windows.Storage; + using Windows.Storage.Streams; + + public class Startup + { + public async Task Invoke(dynamic input) + { + try + { + string filePath = (string)input; + var storageFile = await StorageFile.GetFileFromPathAsync(filePath); + + // Confirm if the file exists and is accessible + if (storageFile == null) + { + return "Error: Unable to access file at path: " + filePath; + } + + using (IRandomAccessStream stream = await storageFile.OpenAsync(FileAccessMode.Read)) + { + var decoder = await BitmapDecoder.CreateAsync(stream); + var bitmap = await decoder.GetSoftwareBitmapAsync(); + + // Confirm if bitmap is loaded + if (bitmap == null) + { + return "Error: Failed to load bitmap from file."; + } + + var ocrEngine = OcrEngine.TryCreateFromUserProfileLanguages(); + if (ocrEngine == null) + { + return "Error: OCR Engine creation failed."; + } + + var ocrResult = await ocrEngine.RecognizeAsync(bitmap); + + // Check if OCR result is null or empty + if (ocrResult == null || ocrResult.Text == null) + { + return "Error: OCR processing resulted in an empty or null text."; + } + + return ocrResult.Text; + } + } + catch (Exception ex) + { + // Return any exception message for debugging + return "Error: " + ex.Message; + } + } } - } -} + */}, + references: [ + path.join(libsPath, "System.Runtime.dll"), + path.join(libsPath, "System.Threading.Tasks.dll"), + path.join(libsPath, "System.Runtime.WindowsRuntime.dll"), + path.join(libsPath, "Windows.winmd") + ] +}); module.exports = { performOCR From cfeb634d88122baac2e675469b5f7a3f2eedc7f3 Mon Sep 17 00:00:00 2001 From: will wade Date: Fri, 1 Nov 2024 12:36:41 +0000 Subject: [PATCH 16/22] oops duplicated method --- nodejs/sender-monitor/ocr.js | 67 ------------------------------------ 1 file changed, 67 deletions(-) diff --git a/nodejs/sender-monitor/ocr.js b/nodejs/sender-monitor/ocr.js index d3a7456..5fcaafd 100644 --- a/nodejs/sender-monitor/ocr.js +++ b/nodejs/sender-monitor/ocr.js @@ -58,73 +58,6 @@ const ocrImageEdge = edge.func({ // Main OCR function that switches based on config -const ocrImageEdge = edge.func({ - source: function () {/* - using System; - using System.Threading.Tasks; - using Windows.Graphics.Imaging; - using Windows.Media.Ocr; - using Windows.Storage; - using Windows.Storage.Streams; - - public class Startup - { - public async Task Invoke(dynamic input) - { - try - { - string filePath = (string)input; - var storageFile = await StorageFile.GetFileFromPathAsync(filePath); - - // Confirm if the file exists and is accessible - if (storageFile == null) - { - return "Error: Unable to access file at path: " + filePath; - } - - using (IRandomAccessStream stream = await storageFile.OpenAsync(FileAccessMode.Read)) - { - var decoder = await BitmapDecoder.CreateAsync(stream); - var bitmap = await decoder.GetSoftwareBitmapAsync(); - - // Confirm if bitmap is loaded - if (bitmap == null) - { - return "Error: Failed to load bitmap from file."; - } - - var ocrEngine = OcrEngine.TryCreateFromUserProfileLanguages(); - if (ocrEngine == null) - { - return "Error: OCR Engine creation failed."; - } - - var ocrResult = await ocrEngine.RecognizeAsync(bitmap); - - // Check if OCR result is null or empty - if (ocrResult == null || ocrResult.Text == null) - { - return "Error: OCR processing resulted in an empty or null text."; - } - - return ocrResult.Text; - } - } - catch (Exception ex) - { - // Return any exception message for debugging - return "Error: " + ex.Message; - } - } - } - */}, - references: [ - path.join(libsPath, "System.Runtime.dll"), - path.join(libsPath, "System.Threading.Tasks.dll"), - path.join(libsPath, "System.Runtime.WindowsRuntime.dll"), - path.join(libsPath, "Windows.winmd") - ] -}); module.exports = { performOCR From 526d35c76a142b52a8517289deb62af5ec3031b3 Mon Sep 17 00:00:00 2001 From: will wade Date: Fri, 1 Nov 2024 12:38:10 +0000 Subject: [PATCH 17/22] add back in perform method --- nodejs/sender-monitor/ocr.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/nodejs/sender-monitor/ocr.js b/nodejs/sender-monitor/ocr.js index 5fcaafd..c70275e 100644 --- a/nodejs/sender-monitor/ocr.js +++ b/nodejs/sender-monitor/ocr.js @@ -58,6 +58,29 @@ const ocrImageEdge = edge.func({ // Main OCR function that switches based on config +async function performOCR(filePath, useEdgeForOCR) { + console.log("performOCR called with useEdgeForOCR:", useEdgeForOCR); + + if (useEdgeForOCR) { + try { + const text = await ocrImageEdge(filePath); + console.log("Recognized text (Windows.Media.Ocr):", text); + return text || ""; // Return text or an empty string if text is undefined + } catch (error) { + console.error("Windows.Media.Ocr failed:", error); + return null; + } + } else { + try { + const { data: { text } } = await Tesseract.recognize(filePath, "eng"); + console.log("Recognized text (Tesseract.js):", text); + return text; + } catch (error) { + console.error("Tesseract.js OCR failed:", error); + return null; + } + } +} module.exports = { performOCR From 448e4d4bf7c067203d89559dc9a7a14001966ae1 Mon Sep 17 00:00:00 2001 From: will wade Date: Fri, 1 Nov 2024 12:40:55 +0000 Subject: [PATCH 18/22] add check of file scapture --- nodejs/sender-monitor/main.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nodejs/sender-monitor/main.js b/nodejs/sender-monitor/main.js index 29b5f5d..9c47601 100644 --- a/nodejs/sender-monitor/main.js +++ b/nodejs/sender-monitor/main.js @@ -158,6 +158,10 @@ async function captureAndProcessScreen() { const croppedImage = await fullImage.crop(x, y, width, height); const filePath = path.join(app.getPath("temp"), "ocr-capture.png"); + if (!fs.existsSync(filePath)) { + console.error("File does not exist at", filePath); + return ""; + } // Write the cropped image to the temp path and ensure it exists fs.writeFileSync(filePath, await croppedImage.toPng()); From 69b9a841a09eae718efbad006266897c2c8b80fe Mon Sep 17 00:00:00 2001 From: will wade Date: Fri, 1 Nov 2024 20:29:18 +0000 Subject: [PATCH 19/22] Add finally block to avoid deleting too early --- nodejs/sender-monitor/main.js | 39 +++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/nodejs/sender-monitor/main.js b/nodejs/sender-monitor/main.js index 9c47601..da9bc6f 100644 --- a/nodejs/sender-monitor/main.js +++ b/nodejs/sender-monitor/main.js @@ -152,38 +152,59 @@ async function captureAndProcessScreen() { const { x, y, width, height } = config.captureArea; const useEdgeForOCR = config.useEdgeForOCR; + const filePath = path.join(app.getPath("temp"), "ocr-capture.png"); + try { const monitor = Monitor.all().find(m => m.isPrimary); + if (!monitor) { + console.error("No primary monitor found."); + return ""; + } + + // Capture the full image const fullImage = await monitor.captureImage(); + if (!fullImage) { + console.error("Image capture failed."); + return ""; + } + + // Crop the image to the specified capture area const croppedImage = await fullImage.crop(x, y, width, height); - - const filePath = path.join(app.getPath("temp"), "ocr-capture.png"); - if (!fs.existsSync(filePath)) { - console.error("File does not exist at", filePath); + if (!croppedImage) { + console.error("Image cropping failed."); return ""; } - // Write the cropped image to the temp path and ensure it exists - fs.writeFileSync(filePath, await croppedImage.toPng()); + // Write the cropped image to the temp path + const imageBuffer = await croppedImage.toPng(); + fs.writeFileSync(filePath, imageBuffer); + + // Confirm file existence if (!fs.existsSync(filePath)) { - console.error("Image file not created as expected at", filePath); + console.error("File does not exist at", filePath); return ""; // Exit early if file creation failed } + console.log("Image successfully saved at", filePath); + // Call performOCR with the useEdgeForOCR flag const recognizedText = await performOCR(filePath, useEdgeForOCR); // Log recognized text console.log("OCR completed, recognized text:", recognizedText); - // Clean up the temp file after OCR completes - fs.unlinkSync(filePath); return recognizedText || ""; // Return the OCR text or an empty string } catch (error) { console.error("Screen capture or OCR failed:", error); logMessage("Error during screen capture or OCR"); return ""; + } finally { + // Clean up the temp file after everything is done + if (fs.existsSync(filePath)) { + fs.unlinkSync(filePath); + console.log("Temporary OCR file cleaned up:", filePath); + } } } From 15caed5a777ce479f94abdf03b1e0e609095b0f1 Mon Sep 17 00:00:00 2001 From: will wade Date: Fri, 1 Nov 2024 22:06:10 +0000 Subject: [PATCH 20/22] add a delay --- nodejs/sender-monitor/main.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nodejs/sender-monitor/main.js b/nodejs/sender-monitor/main.js index da9bc6f..0fc04ac 100644 --- a/nodejs/sender-monitor/main.js +++ b/nodejs/sender-monitor/main.js @@ -167,7 +167,7 @@ async function captureAndProcessScreen() { console.error("Image capture failed."); return ""; } - + // Crop the image to the specified capture area const croppedImage = await fullImage.crop(x, y, width, height); if (!croppedImage) { @@ -177,7 +177,8 @@ async function captureAndProcessScreen() { // Write the cropped image to the temp path const imageBuffer = await croppedImage.toPng(); - fs.writeFileSync(filePath, imageBuffer); + await fs.promises.writeFile(filePath, imageBuffer); + await new Promise(resolve => setTimeout(resolve, 500)); // Confirm file existence if (!fs.existsSync(filePath)) { From aad54845d01e26cf6250e7d2c13d738e3a96bd51 Mon Sep 17 00:00:00 2001 From: will wade Date: Fri, 1 Nov 2024 22:11:09 +0000 Subject: [PATCH 21/22] adding some debug --- nodejs/sender-monitor/main.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/nodejs/sender-monitor/main.js b/nodejs/sender-monitor/main.js index 0fc04ac..4e42d30 100644 --- a/nodejs/sender-monitor/main.js +++ b/nodejs/sender-monitor/main.js @@ -151,7 +151,6 @@ function reloadConfig() { async function captureAndProcessScreen() { const { x, y, width, height } = config.captureArea; const useEdgeForOCR = config.useEdgeForOCR; - const filePath = path.join(app.getPath("temp"), "ocr-capture.png"); try { @@ -161,26 +160,22 @@ async function captureAndProcessScreen() { return ""; } - // Capture the full image const fullImage = await monitor.captureImage(); if (!fullImage) { console.error("Image capture failed."); return ""; } - // Crop the image to the specified capture area const croppedImage = await fullImage.crop(x, y, width, height); if (!croppedImage) { console.error("Image cropping failed."); return ""; } - // Write the cropped image to the temp path const imageBuffer = await croppedImage.toPng(); await fs.promises.writeFile(filePath, imageBuffer); await new Promise(resolve => setTimeout(resolve, 500)); - // Confirm file existence if (!fs.existsSync(filePath)) { console.error("File does not exist at", filePath); return ""; // Exit early if file creation failed @@ -188,11 +183,15 @@ async function captureAndProcessScreen() { console.log("Image successfully saved at", filePath); - // Call performOCR with the useEdgeForOCR flag const recognizedText = await performOCR(filePath, useEdgeForOCR); - // Log recognized text - console.log("OCR completed, recognized text:", recognizedText); + if (recognizedText === undefined) { + console.log("OCR result was undefined. Opening image directory for inspection..."); + await shell.openPath(path.dirname(filePath)); // Opens the temp directory in file explorer + await shell.openPath(filePath); // Opens the actual image for viewing + } else { + console.log("OCR completed, recognized text:", recognizedText); + } return recognizedText || ""; // Return the OCR text or an empty string @@ -201,7 +200,6 @@ async function captureAndProcessScreen() { logMessage("Error during screen capture or OCR"); return ""; } finally { - // Clean up the temp file after everything is done if (fs.existsSync(filePath)) { fs.unlinkSync(filePath); console.log("Temporary OCR file cleaned up:", filePath); From 39f6c644cd784488e6d15d61fe6edf43c136131a Mon Sep 17 00:00:00 2001 From: will wade Date: Tue, 5 Nov 2024 23:02:45 +0000 Subject: [PATCH 22/22] add sharp technique of getting crop dimensions --- nodejs/sender-monitor/main.js | 190 +++++---- nodejs/sender-monitor/overlay-preload.js | 46 ++- nodejs/sender-monitor/package-lock.json | 468 +++++++++++++++++++++++ nodejs/sender-monitor/package.json | 3 +- 4 files changed, 633 insertions(+), 74 deletions(-) diff --git a/nodejs/sender-monitor/main.js b/nodejs/sender-monitor/main.js index 4e42d30..b3b2d64 100644 --- a/nodejs/sender-monitor/main.js +++ b/nodejs/sender-monitor/main.js @@ -1,4 +1,4 @@ -const { app, Tray, Menu, shell, clipboard, BrowserWindow, ipcMain } = require("electron"); +const { app, Tray, Menu, shell, clipboard, BrowserWindow, ipcMain, screen} = require("electron"); const path = require("path"); const fs = require("fs"); const webrtc = require("./webrtc"); @@ -6,6 +6,7 @@ const QRCode = require("qrcode"); const { Monitor } = require("node-screenshots"); const { performOCR } = require("./ocr"); const { Translator } = require("google-translate-api-x"); +const sharp = require("sharp"); let tray; let qrWindow; @@ -18,6 +19,7 @@ let clipboardMonitorInterval; let ocrMonitorInterval; const maxRetries = 10; const retryInterval = 3000; +let overlayWindow = null; const logFilePath = path.join(app.getPath("userData"), "log.txt"); @@ -39,31 +41,44 @@ ipcMain.on("close-qr-window", () => { }); function createOverlayWindow() { - let overlayWindow = new BrowserWindow({ - fullscreen: true, - frame: false, - transparent: true, - alwaysOnTop: true, - resizable: false, - webPreferences: { - contextIsolation: true, - preload: path.join(__dirname, "overlay-preload.js"), - }, - }); - - overlayWindow.loadURL(`file://${__dirname}/overlay.html`); - overlayWindow.on("closed", () => { - overlayWindow = null; - }); + overlayWindow = new BrowserWindow({ + fullscreen: true, + frame: false, + transparent: true, + alwaysOnTop: true, + resizable: false, + webPreferences: { + contextIsolation: true, + preload: path.join(__dirname, "overlay-preload.js"), + }, + }); + + overlayWindow.loadURL(`file://${__dirname}/overlay.html`); + overlayWindow.on("closed", () => { + overlayWindow = null; + console.log("Overlay window closed"); + }); } -ipcMain.on("set-ocr-boundaries", (event, bounds) => { - config.captureArea = bounds; - logMessage(`Updated OCR boundaries: ${JSON.stringify(bounds)}`); - // Save updated config if persistence is needed - fs.writeFileSync(configFilePath, JSON.stringify(config, null, 2), "utf-8"); +// Updated `set-capture-area` handler +ipcMain.on("set-capture-area", (event, bounds) => { + console.log("Received capture area bounds from overlay:", bounds); + if (!bounds || !bounds.width || !bounds.height) { + console.error("Invalid capture area bounds received:", bounds); + return; + } + + config.captureArea = bounds; + fs.writeFileSync(configFilePath, JSON.stringify(config, null, 2), "utf-8"); + console.log(`Updated capture area to new values: ${JSON.stringify(bounds)}`); + + // Close the overlay window after capturing bounds + if (overlayWindow) { + overlayWindow.close(); + } }); + async function createQRWindow(qrDataUrl) { if (qrWindow) { qrWindow.close(); @@ -149,64 +164,105 @@ function reloadConfig() { // Capture and OCR function with return of recognized text async function captureAndProcessScreen() { - const { x, y, width, height } = config.captureArea; - const useEdgeForOCR = config.useEdgeForOCR; - const filePath = path.join(app.getPath("temp"), "ocr-capture.png"); + const { x, y, width, height } = config.captureArea; + const useEdgeForOCR = config.useEdgeForOCR; + const fullImagePath = path.join(app.getPath("temp"), "full-image.png"); + const croppedImagePath = path.join(app.getPath("temp"), "cropped-image.png"); + + try { + console.log("Starting screen capture and cropping process..."); + + const monitor = Monitor.all().find(m => m.isPrimary); + if (!monitor) { + console.error("No primary monitor found."); + return; + } - try { - const monitor = Monitor.all().find(m => m.isPrimary); - if (!monitor) { - console.error("No primary monitor found."); - return ""; - } + const fullImage = await monitor.captureImage(); + if (!fullImage) { + console.error("Image capture failed."); + return; + } - const fullImage = await monitor.captureImage(); - if (!fullImage) { - console.error("Image capture failed."); - return ""; - } + // Convert the full captured image to a PNG buffer + const fullImageBuffer = await fullImage.toPng().catch(err => { + console.error("Failed to create fullImageBuffer:", err); + throw err; + }); - const croppedImage = await fullImage.crop(x, y, width, height); - if (!croppedImage) { - console.error("Image cropping failed."); - return ""; - } + // Save the full image + await fs.promises.writeFile(fullImagePath, fullImageBuffer); + console.log("Full screenshot saved at", fullImagePath); - const imageBuffer = await croppedImage.toPng(); - await fs.promises.writeFile(filePath, imageBuffer); - await new Promise(resolve => setTimeout(resolve, 500)); + if (!fs.existsSync(fullImagePath)) { + console.error("Full screenshot file does not exist at", fullImagePath); + return; + } - if (!fs.existsSync(filePath)) { - console.error("File does not exist at", filePath); - return ""; // Exit early if file creation failed - } + // Get image dimensions using sharp to verify metadata + const imageMetadata = await sharp(fullImagePath).metadata(); + console.log("Full image dimensions:", imageMetadata); - console.log("Image successfully saved at", filePath); + // Get the primary display's scaling factor + const primaryDisplay = screen.getPrimaryDisplay(); + const scaleFactor = primaryDisplay.scaleFactor; + console.log("Primary display scale factor:", scaleFactor); - const recognizedText = await performOCR(filePath, useEdgeForOCR); + // Adjust bounds to account for scaling + const scaledX = Math.round(x * scaleFactor); + const scaledY = Math.round(y * scaleFactor); + const scaledWidth = Math.round(width * scaleFactor); + const scaledHeight = Math.round(height * scaleFactor); - if (recognizedText === undefined) { - console.log("OCR result was undefined. Opening image directory for inspection..."); - await shell.openPath(path.dirname(filePath)); // Opens the temp directory in file explorer - await shell.openPath(filePath); // Opens the actual image for viewing - } else { - console.log("OCR completed, recognized text:", recognizedText); - } + console.log(`Scaled crop bounds: x=${scaledX}, y=${scaledY}, width=${scaledWidth}, height=${scaledHeight}`); - return recognizedText || ""; // Return the OCR text or an empty string + // Adjust bounds to ensure they are within the image dimensions + const adjustedX = Math.min(Math.max(scaledX, 0), imageMetadata.width); + const adjustedY = Math.min(Math.max(scaledY, 0), imageMetadata.height); + const adjustedWidth = Math.min(scaledWidth, imageMetadata.width - adjustedX); + const adjustedHeight = Math.min(scaledHeight, imageMetadata.height - adjustedY); - } catch (error) { - console.error("Screen capture or OCR failed:", error); - logMessage("Error during screen capture or OCR"); - return ""; - } finally { - if (fs.existsSync(filePath)) { - fs.unlinkSync(filePath); - console.log("Temporary OCR file cleaned up:", filePath); - } + console.log(`Adjusted crop bounds for the image: x=${adjustedX}, y=${adjustedY}, width=${adjustedWidth}, height=${adjustedHeight}`); + + // Now proceed to crop the image using sharp with the adjusted dimensions + await sharp(fullImagePath) + .extract({ left: adjustedX, top: adjustedY, width: adjustedWidth, height: adjustedHeight }) + .toFile(croppedImagePath); + + console.log("Cropped image successfully saved at", croppedImagePath); + + if (!fs.existsSync(croppedImagePath)) { + console.error("Cropped image file does not exist at", croppedImagePath); + return; } + + const recognizedText = await performOCR(croppedImagePath, useEdgeForOCR); + + if (recognizedText === undefined) { + console.log("OCR result was undefined. Opening image directory for inspection..."); + } else { + console.log("OCR completed, recognized text:", recognizedText); + } + + return recognizedText || ""; + + } catch (error) { + console.error("Error occurred during capture or cropping process:", error); + } finally { + // Clean up temporary files if they exist + if (fs.existsSync(croppedImagePath)) { + fs.unlinkSync(croppedImagePath); + console.log("Temporary OCR file cleaned up:", croppedImagePath); + } + + if (fs.existsSync(fullImagePath)) { + fs.unlinkSync(fullImagePath); + console.log("Temporary OCR file cleaned up of screen:", fullImagePath); + } + } } + const translator = new Translator({ from: config.translation?.sourceLang || "en", to: config.translation?.targetLang || "es", diff --git a/nodejs/sender-monitor/overlay-preload.js b/nodejs/sender-monitor/overlay-preload.js index ee2ba1b..85d3a60 100644 --- a/nodejs/sender-monitor/overlay-preload.js +++ b/nodejs/sender-monitor/overlay-preload.js @@ -1,8 +1,42 @@ -// overlay-preload.js +const { ipcRenderer } = require('electron'); -const { contextBridge, ipcRenderer } = require("electron"); +let isSelecting = false; +let startX, startY, endX, endY; -// Expose only the necessary Electron APIs to the renderer -contextBridge.exposeInMainWorld("electronAPI", { - sendOCRBounds: (bounds) => ipcRenderer.send("set-ocr-boundaries", bounds) -}); \ No newline at end of file +// This listens for the mouse events to capture the coordinates +window.addEventListener('mousedown', (event) => { + isSelecting = true; + startX = event.clientX; + startY = event.clientY; + console.log('Selection started at:', { x: startX, y: startY }); +}); + +window.addEventListener('mousemove', (event) => { + if (isSelecting) { + endX = event.clientX; + endY = event.clientY; + console.log('Selection moving:', { endX, endY }); + } +}); + +window.addEventListener('mouseup', (event) => { + if (isSelecting) { + isSelecting = false; + endX = event.clientX; + endY = event.clientY; + console.log('Selection ended at:', { x: endX, y: endY }); + + // Calculate the bounds + const bounds = { + x: Math.min(startX, endX), + y: Math.min(startY, endY), + width: Math.abs(endX - startX), + height: Math.abs(endY - startY) + }; + + console.log('Bounds calculated:', bounds); + + // Send bounds to the main process + ipcRenderer.send('set-capture-area', bounds); + } +}); diff --git a/nodejs/sender-monitor/package-lock.json b/nodejs/sender-monitor/package-lock.json index be525dc..ebdf7e2 100644 --- a/nodejs/sender-monitor/package-lock.json +++ b/nodejs/sender-monitor/package-lock.json @@ -14,6 +14,7 @@ "google-translate-api-x": "^10.7.1", "node-screenshots": "^0.2.2", "qrcode": "^1.5.4", + "sharp": "^0.33.5", "socket.io-client": "^4.8.1", "tesseract.js": "^5.1.1", "wrtc": "^0.4.7" @@ -384,6 +385,16 @@ "node": ">= 10.0.0" } }, + "node_modules/@emnapi/runtime": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz", + "integrity": "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@faker-js/faker": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.1.0.tgz", @@ -406,6 +417,367 @@ "dev": true, "license": "MIT" }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", + "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", + "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", + "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", + "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", + "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", + "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", + "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", + "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", + "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", + "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", + "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.0.5" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", + "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", + "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", + "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", + "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", + "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", + "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.2.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", + "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", + "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -1885,6 +2257,19 @@ "node": ">=0.10.0" } }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1903,6 +2288,16 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "license": "MIT" }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, "node_modules/color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", @@ -3506,6 +3901,12 @@ "node": ">= 12" } }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "license": "MIT" + }, "node_modules/is-ci": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", @@ -5568,11 +5969,71 @@ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "license": "ISC" }, + "node_modules/sharp": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", + "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.3", + "semver": "^7.6.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.33.5", + "@img/sharp-darwin-x64": "0.33.5", + "@img/sharp-libvips-darwin-arm64": "1.0.4", + "@img/sharp-libvips-darwin-x64": "1.0.4", + "@img/sharp-libvips-linux-arm": "1.0.5", + "@img/sharp-libvips-linux-arm64": "1.0.4", + "@img/sharp-libvips-linux-s390x": "1.0.4", + "@img/sharp-libvips-linux-x64": "1.0.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", + "@img/sharp-libvips-linuxmusl-x64": "1.0.4", + "@img/sharp-linux-arm": "0.33.5", + "@img/sharp-linux-arm64": "0.33.5", + "@img/sharp-linux-s390x": "0.33.5", + "@img/sharp-linux-x64": "0.33.5", + "@img/sharp-linuxmusl-arm64": "0.33.5", + "@img/sharp-linuxmusl-x64": "0.33.5", + "@img/sharp-wasm32": "0.33.5", + "@img/sharp-win32-ia32": "0.33.5", + "@img/sharp-win32-x64": "0.33.5" + } + }, + "node_modules/sharp/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, "node_modules/simple-update-notifier": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", @@ -5998,6 +6459,13 @@ "utf8-byte-length": "^1.0.1" } }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true + }, "node_modules/type-fest": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", diff --git a/nodejs/sender-monitor/package.json b/nodejs/sender-monitor/package.json index ecc5c3b..b435ddb 100644 --- a/nodejs/sender-monitor/package.json +++ b/nodejs/sender-monitor/package.json @@ -59,6 +59,7 @@ "google-translate-api-x": "^10.7.1", "node-screenshots": "^0.2.2", "qrcode": "^1.5.4", + "sharp": "^0.33.5", "socket.io-client": "^4.8.1", "tesseract.js": "^5.1.1", "wrtc": "^0.4.7" @@ -67,4 +68,4 @@ "electron": "^32.0.0", "electron-builder": "^25.1.8" } -} \ No newline at end of file +}