Node.js实时截屏实现方案
前端:
<!DOCTYPE html>
<html lang="zh"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>实时截屏</title><style>html,body {margin: 0;overflow: hidden;width: 100%;height: 100%;}img {width: 100%;height: 100%;}</style></head><body><img id="screen" alt="Screen Feed" /><script>const img = document.getElementById('screen');const ws = new WebSocket('ws://localhost:8080'); // 改成服务器 IP 如果跨机ws.onmessage = (event) => {// event.data 是 base64 图片const img = document.getElementById('screen');img.src = event.data;// 计算合适的宽度和高度const containerWidth = document.body.clientWidth; // 容器宽度const aspectRatio = img.naturalWidth / img.naturalHeight; // 原始宽高比if (img.naturalWidth > containerWidth) {img.style.width = `${containerWidth}px`;img.style.height = `${containerWidth / aspectRatio}px`;} else {img.style.width = `${img.naturalWidth}px`;img.style.height = `${img.naturalHeight}px`;}img.src = event.data;};ws.onopen = () => {console.log('Connected to screen capture server');};ws.onclose = () => {console.log('Disconnected');img.src = '';};ws.onerror = (err) => {console.error('WebSocket error:', err);};</script></body>
</html>
服务端:
注意:
robotjs:用于截屏(仅支持桌面环境:Windows/macOS/Linux)
canvas:Node.js 中处理图像(需安装 node-canvas,可能需要系统依赖)
Ubuntu:
sudo apt-get install build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev
macOS:
brew install pkg-config cairo pango libpng jpeg giflib librsvg
Windows: 推荐使用 windows-build-tools(Node 14+ 可能不需要)
初始化项目
npm init -y
npm install ws robotjs canvas
// server.js
const WebSocket = require('ws');
const robot = require('robotjs');
const { createCanvas } = require('canvas');// 创建 WebSocket 服务器
const wss = new WebSocket.Server({ port: 8080 });
console.log('WebSocket server running on ws://localhost:8080');// 获取屏幕尺寸
const screen = robot.getScreenSize();
let width = screen.width;
let height = screen.height;
width = 1920;
height = 1080;
// 创建与屏幕大小相同的 Canvas
const canvas = createCanvas(width, height);
const ctx = canvas.getContext('2d');wss.on('connection', (ws) => {console.log('Client connected');// 每 100ms 截屏一次(约 10 FPS)const interval = setInterval(() => {try {// 1. 使用 robotjs 截取屏幕const img = robot.screen.capture(0, 0, width, height);if (!img) {console.error('Failed to capture screen: no image data');return;}// 2. 创建 ImageData 并填充像素const imageData = ctx.createImageData(width, height);const pixelBuffer = img.image; // 原始像素数据(BGR 格式)for (let y = 0; y < height; y++) {for (let x = 0; x < width; x++) {const idx = (y * width + x) * 4; // ImageData 索引(RGBA)const pixelIdx = (y * width + x) * 4; // robotjs 像素索引(BGR + 未使用)// robotjs 返回的是 BGR + 未使用字节,顺序为 [B, G, R, ?]imageData.data[idx] = pixelBuffer[pixelIdx + 2]; // RimageData.data[idx + 1] = pixelBuffer[pixelIdx + 1]; // GimageData.data[idx + 2] = pixelBuffer[pixelIdx]; // BimageData.data[idx + 3] = 255; // A(不透明)}}// 3. 将 ImageData 绘制到 Canvasctx.putImageData(imageData, 0, 0);// 4. 转为 JPEG Base64(压缩,质量 50%)const dataUrl = canvas.toDataURL('image/jpeg', 1.0);// 5. 发送给客户端ws.send(dataUrl);} catch (err) {console.error('Capture error:', err.message || err);}}, 100); // 100ms = 10 FPS// 客户端断开时清理ws.on('close', () => {console.log('Client disconnected');clearInterval(interval);});// 处理错误ws.on('error', (err) => {console.error('WebSocket error:', err);});
});// 错误处理
wss.on('error', (err) => {console.error('WebSocket Server error:', err);if (err.code === 'EADDRINUSE') {console.error('端口 8080 已被占用,请关闭其他程序或更换端口。');}
});
效果: