前端:
<!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]; // R
imageData.data[idx + 1] = pixelBuffer[pixelIdx + 1]; // G
imageData.data[idx + 2] = pixelBuffer[pixelIdx]; // B
imageData.data[idx + 3] = 255; // A(不透明)
}
}
// 3. 将 ImageData 绘制到 Canvas
ctx.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 已被占用,请关闭其他程序或更换端口。');
}
});
效果: