screenshot.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import { ipcMain } from 'electron';
  2. import { exec } from 'child_process';
  3. import { promisify } from 'util';
  4. import { getCachedAdbPath } from '../config.js';
  5. const execAsync = promisify(exec);
  6. // 截图缓存:存储最后一次截图的设备和数据
  7. const screenshotCache = {
  8. device: null,
  9. data: null,
  10. timestamp: null,
  11. options: null,
  12. };
  13. // 获取缓存的截图数据
  14. export function getCachedScreenshot(ipPort) {
  15. // 如果缓存存在且设备匹配,且缓存时间在 5 秒内,返回缓存数据
  16. if (screenshotCache.device === ipPort && screenshotCache.data && screenshotCache.timestamp) {
  17. const now = Date.now();
  18. const cacheAge = now - screenshotCache.timestamp;
  19. // 缓存有效期:5 秒(可以根据需要调整)
  20. if (cacheAge < 5000) {
  21. return {
  22. success: true,
  23. data: screenshotCache.data,
  24. fromCache: true,
  25. };
  26. }
  27. }
  28. return null;
  29. }
  30. // 更新截图缓存
  31. function updateScreenshotCache(ipPort, data, options) {
  32. screenshotCache.device = ipPort;
  33. screenshotCache.data = data;
  34. screenshotCache.timestamp = Date.now();
  35. screenshotCache.options = options;
  36. }
  37. // 抓取设备截屏(返回 base64 PNG/JPEG)
  38. export async function captureScreenshot(ipPort, options = {}) {
  39. if (!ipPort) {
  40. return { success: false, error: '缺少设备 ID' };
  41. }
  42. try {
  43. const adbPath = getCachedAdbPath();
  44. // 从选项或默认值获取参数
  45. const format = options.format || 'png'; // 'png' 或 'jpeg'
  46. const quality = options.quality || 80; // JPEG 质量 1-100
  47. const scale = options.scale || 1.0; // 缩放比例 0.1-1.0
  48. // 构建 screencap 命令
  49. let command = `${adbPath} -s ${ipPort} exec-out screencap`;
  50. // 根据格式选择参数
  51. if (format === 'jpeg') {
  52. // JPEG 格式(更小,延迟更低)
  53. command += ` -j ${quality}`;
  54. } else {
  55. // PNG 格式(默认)
  56. command += ' -p';
  57. }
  58. // 如果缩放比例不是 1.0,需要通过 shell 命令处理
  59. // 注意:screencap 本身不支持缩放,需要通过其他方式实现
  60. // 这里先实现基本功能,缩放可以在后续优化
  61. const { stdout } = await execAsync(command, {
  62. encoding: 'buffer',
  63. maxBuffer: 25 * 1024 * 1024,
  64. });
  65. const base64Data = stdout.toString('base64');
  66. // 更新缓存
  67. updateScreenshotCache(ipPort, base64Data, options);
  68. return { success: true, data: base64Data };
  69. } catch (error) {
  70. return { success: false, error: error.message };
  71. }
  72. }
  73. // 注册 IPC 处理器
  74. export function registerIpcHandlers() {
  75. // IPC 处理程序:抓取设备截屏(返回 base64 PNG/JPEG)
  76. ipcMain.handle('capture-screenshot', async (event, ipPort, options = {}) => {
  77. return await captureScreenshot(ipPort, options);
  78. });
  79. // IPC 处理程序:获取缓存的截图(如果存在且未过期)
  80. ipcMain.handle('get-cached-screenshot', async (event, ipPort) => {
  81. const cached = getCachedScreenshot(ipPort);
  82. if (cached) {
  83. return cached;
  84. }
  85. return { success: false, error: '缓存不存在或已过期' };
  86. });
  87. }