I’m trying to use Node to capture a screenshot of the user’s screen on all displays and save everything in just one image, so far everything works fine if I call it the first time, but if I try to call it a second time without restarting the server, An error appears saying that the file cannot be opened.
Because I wanted to be able to make several requests to the screenshot, any ideas what I can do?
I’m still integrating with Node and JS so I don’t know how it works very well.
Code:
const express = require('express');
const app = express();
const port = 3000;
const fs = require('fs');
app.get('/', (req, res) => {
hello = 'Hello World!';
console.log(hello);
res.send(hello);
});
app.get('/screenshot', (req, res) => {
const screenshot = require('screenshot-desktop');
const sharp = require('sharp');
screenshot.listDisplays().then((displays) => {
let screenshots = [];
displays.forEach((display, i) => {
const screenshotPath = `screenshot${i}.png`;
screenshot({ screen: display.id }).then((imgBuffer) => {
fs.writeFile(screenshotPath, imgBuffer, (err) => {
if (err) throw err;
console.log('Screenshot salvo!');
screenshots.push(screenshotPath);
if (screenshots.length === displays.length) {
// Todas as screenshots foram salvas, agora junte-as
Promise.all([
sharp(screenshots[1]).metadata(),
sharp(screenshots[0]).metadata()
]).then(([metadata1, metadata2]) => {
sharp(screenshots[1])
.extend({
top: 0,
bottom: 0,
left: 0,
right: metadata2.width,
background: { r: 0, g: 0, b: 0, alpha: 0 }
})
.composite([{ input: screenshots[0], left: metadata1.width, top: 0 }])
.toBuffer()
.then((buffer) => {
let base64Image = `data:image/png;base64,${buffer.toString('base64')}`;
res.send(base64Image);
})
.catch((err) => console.error(err));
}).catch(err => console.error(err));
}
});
}, (err) => {
console.error(err);
});
});
});
});
app.listen(port, () => {
console.log(`Servidor rodando em http://localhost:${port}`);
});
Error im getting and Log:
Servidor rodando em http://localhost:3000
Screenshot salvo!
Screenshot salvo!
F:Andresk-access-control-aifacialRecogserver.js:23
if (err) throw err;
^
[Error: UNKNOWN: unknown error, open 'facialRecogscreenshot0.png'] {
errno: -4094,
code: 'UNKNOWN',
syscall: 'open',
path: 'facialRecog\screenshot0.png'
}
Node.js v20.12.2
I tried to create it like this, but instead of replacing the file, I would delete it and create a new one, but it would give me the error error eperm operation not permitted unlink
saying that I can’t delete a file, but I’m not using it nowhere, and I can only delete it when I close the localhost:3000 server
2
Answers
I rewrite your code used async/await and it worked as expect. But it still has some issue to fixed.
(1) when user only has one display and
screenshots[1]
will get index out of bound error.(2) file name with
screenshot${i}.png
will duplicate when user call api concurrently.The error you’re encountering suggests that the file you’re trying to open or write to (screenshot0.png) is being locked or is still in use when the second request to your screenshot endpoint is made. This is a common issue when working with file I/O operations where the file is not properly released or is still being processed when subsequent attempts to access it are made.
Here are a few approaches to resolve this issue:
1. Use Unique File Names for Each Screenshot
Instead of writing to the same file name every time, you can generate unique file names based on timestamps or UUIDs. This prevents conflicts with files being locked or still in use.
2. Checking File Access Before Writing
3. Proper Error Handling
For an example: