"데스크톱 캡처는 화면 녹화, 스크린샷, 화상 회의 앱의 핵심 기능" — Electron의 desktopCapturer는 Chromium의 미디어 캡처 기능을 활용합니다.


desktopCapturer 기본 사용

Electron 17+부터 desktopCapturer는 메인 프로세스에서만 사용합니다.

JAVASCRIPT
// main.js
const { desktopCapturer, ipcMain } = require('electron');

ipcMain.handle('capture:getSources', async () => {
  const sources = await desktopCapturer.getSources({
    types: ['window', 'screen'],
    thumbnailSize: { width: 320, height: 180 },
  });

  return sources.map(source => ({
    id: source.id,
    name: source.name,
    thumbnail: source.thumbnail.toDataURL(),
    appIcon: source.appIcon?.toDataURL() || null,
  }));
});

특정 윈도우/화면 캡처

JAVASCRIPT
// preload.js
contextBridge.exposeInMainWorld('electronAPI', {
  getSources: () => ipcRenderer.invoke('capture:getSources'),
  captureScreen: (sourceId) => ipcRenderer.invoke('capture:screen', sourceId),
});
JAVASCRIPT
// renderer.js — 소스 선택 후 캡처
async function startCapture() {
  const sources = await window.electronAPI.getSources();

  // 소스 선택 UI 표시
  const sourceList = document.getElementById('source-list');
  sources.forEach(source => {
    const item = document.createElement('div');
    item.innerHTML = `
      <img src="${source.thumbnail}" />
      <span>${source.name}</span>
    `;
    item.onclick = () => captureSource(source.id);
    sourceList.appendChild(item);
  });
}

async function captureSource(sourceId) {
  try {
    const stream = await navigator.mediaDevices.getUserMedia({
      audio: false,
      video: {
        mandatory: {
          chromeMediaSource: 'desktop',
          chromeMediaSourceId: sourceId,
        },
      },
    });

    // 비디오 스트림에서 프레임 캡처
    const video = document.createElement('video');
    video.srcObject = stream;
    await video.play();

    const canvas = document.createElement('canvas');
    canvas.width = video.videoWidth;
    canvas.height = video.videoHeight;
    canvas.getContext('2d').drawImage(video, 0, 0);

    // 스트림 정리
    stream.getTracks().forEach(track => track.stop());

    // PNG로 저장
    const dataUrl = canvas.toDataURL('image/png');
    return dataUrl;
  } catch (error) {
    console.error('캡처 실패:', error);
  }
}

webContents 캡처 (앱 자체 캡처)

JAVASCRIPT
// main.js — 현재 앱 윈도우의 스크린샷
ipcMain.handle('capture:window', async (event) => {
  const win = BrowserWindow.fromWebContents(event.sender);
  const image = await win.webContents.capturePage();
  return image.toPNG().toString('base64');
});

// 특정 영역만 캡처
ipcMain.handle('capture:region', async (event, rect) => {
  const win = BrowserWindow.fromWebContents(event.sender);
  const image = await win.webContents.capturePage({
    x: rect.x,
    y: rect.y,
    width: rect.width,
    height: rect.height,
  });
  return image.toPNG().toString('base64');
});

스크린샷 저장

JAVASCRIPT
ipcMain.handle('capture:save', async (event) => {
  const win = BrowserWindow.fromWebContents(event.sender);
  const image = await win.webContents.capturePage();

  const { filePath } = await dialog.showSaveDialog(win, {
    defaultPath: `screenshot-${Date.now()}.png`,
    filters: [{ name: 'PNG', extensions: ['png'] }],
  });

  if (filePath) {
    await fs.promises.writeFile(filePath, image.toPNG());
    return filePath;
  }
  return null;
});

면접 포인트 정리

  • desktopCapturer는 메인 프로세스 전용 (Electron 17+)
  • webContents.capturePage()로 앱 자체 윈도우 캡처 가능
  • 미디어 스트림은 사용 후 반드시 track.stop()으로 정리
  • 화면 캡처에는 OS별 권한 설정이 필요할 수 있음 (macOS: 화면 기록 권한)

화면 캡처를 다뤘으면, 다음은 네이티브 모듈 사용법을 살펴봅시다.

댓글 로딩 중...