사진 촬영 및 카메라 설정 제어

Miguel Casas-Sanchez
François Beaufort
François Beaufort

Image Capture는 스틸 이미지를 캡처하고 카메라 하드웨어 설정을 구성하는 API입니다. 이 API는 Android 및 데스크톱의 Chrome 59에서 사용할 수 있습니다. ImageCapture polyfill 라이브러리도 게시되었습니다.

이 API를 사용하면 확대/축소, 밝기, 대비, ISO, 화이트 밸런스와 같은 카메라 기능을 제어할 수 있습니다. 무엇보다도 이미지 캡처를 사용하면 사용 가능한 기기 카메라 또는 웹캠의 전체 해상도 기능에 액세스할 수 있습니다. 이전의 웹 사진 촬영 기법은 정지 이미지에 사용할 수 있는 해상도보다 낮은 동영상 스냅샷을 사용했습니다.

ImageCapture 객체는 MediaStreamTrack를 소스로 사용하여 구성됩니다. 그러면 API에는 두 가지 캡처 메서드 takePhoto()grabFrame()와 카메라의 기능 및 설정을 가져오고 이러한 설정을 변경하는 방법이 있습니다.

공사

Image Capture API는 getUserMedia()에서 가져온 MediaStreamTrack를 통해 카메라에 액세스합니다.

navigator.mediaDevices.getUserMedia({video: true})
    .then(gotMedia)
    .catch(error => console.error('getUserMedia() error:', error));

function gotMedia(mediaStream) {
    const mediaStreamTrack = mediaStream.getVideoTracks()[0];
    const imageCapture = new ImageCapture(mediaStreamTrack);
    console.log(imageCapture);
}

DevTools 콘솔에서 이 코드를 사용해 볼 수 있습니다.

캡처

캡처는 전체 프레임과 빠른 스냅샷이라는 두 가지 방법으로 할 수 있습니다. takePhoto()단일 사진 노출의 결과Blob를 반환합니다. 이 Blob는 브라우저에서 다운로드하거나 저장하거나 <img> 요소에 표시할 수 있습니다. 이 방법은 사용 가능한 가장 높은 사진 카메라 해상도를 사용합니다. 예를 들면 다음과 같습니다.

const img = document.querySelector('img');
// ...
imageCapture.takePhoto()
    .then(blob => {
    img.src = URL.createObjectURL(blob);
    img.onload = () => { URL.revokeObjectURL(this.src); }
    })
    .catch(error => console.error('takePhoto() error:', error));

grabFrame()ImageBitmap 객체 (실시간 동영상의 스냅샷)를 반환합니다. 이 객체는 예를 들어 <canvas에 그려진 후 색상 값을 선택적으로 변경하도록 후처리할 수 있습니다. ImageBitmap에는 동영상 소스의 해상도만 포함되며, 이는 일반적으로 카메라의 정지 이미지 기능보다 낮습니다. 예를 들면 다음과 같습니다.

const canvas = document.querySelector('canvas');
// ...
imageCapture.grabFrame()
    .then(imageBitmap => {
    canvas.width = imageBitmap.width;
    canvas.height = imageBitmap.height;
    canvas.getContext('2d').drawImage(imageBitmap, 0, 0);
    })
    .catch(error => console.error('grabFrame() error:', error));

기능 및 설정

변경사항이 MediaStreamTrack에 반영되는지 아니면 takePhoto() 후에만 볼 수 있는지에 따라 캡처 설정을 조작하는 방법에는 여러 가지가 있습니다. 예를 들어 zoom 수준의 변경사항은 MediaStreamTrack에 즉시 전파되지만, 적목 감소는 설정된 경우 사진이 촬영될 때만 적용됩니다.

'실시간' 카메라 기능 및 설정은 미리보기 MediaStreamTrack를 통해 조작됩니다. MediaStreamTrack.getCapabilities()는 지원되는 구체적인 기능과 범위 또는 허용되는 값(예: 지원되는 확대/축소 범위 또는 허용되는 화이트 밸런스 모드)이 포함된 MediaTrackCapabilities 사전을 반환합니다. 이에 따라 MediaStreamTrack.getSettings()는 구체적인 현재 설정과 함께 MediaTrackSettings를 반환합니다. 확대/축소, 밝기, 손전등 모드가 이 카테고리에 속합니다. 예를 들면 다음과 같습니다.

var zoomSlider = document.querySelector('input[type=range]');
// ...
const capabilities = mediaStreamTrack.getCapabilities();
const settings = mediaStreamTrack.getSettings();
if (capabilities.zoom) {
    zoomSlider.min = capabilities.zoom.min;
    zoomSlider.max = capabilities.zoom.max;
    zoomSlider.step = capabilities.zoom.step;
    zoomSlider.value = settings.zoom;
}

'실시간이 아닌' 카메라 기능 및 설정은 ImageCapture 객체를 통해 조작됩니다. ImageCapture.getPhotoCapabilities()는 '실시간이 아닌' 사용 가능한 카메라 기능에 대한 액세스를 제공하는 PhotoCapabilities 객체를 반환합니다. 이에 따라 Chrome 61부터 ImageCapture.getPhotoSettings()는 구체적인 현재 설정이 포함된 PhotoSettings 객체를 반환합니다. 사진 해상도, 적목 감소, 플래시 모드 (손전등 제외)가 이 섹션에 속합니다. 예를 들면 다음과 같습니다.

var widthSlider = document.querySelector('input[type=range]');
// ...
imageCapture.getPhotoCapabilities()
    .then(function(photoCapabilities) {
    widthSlider.min = photoCapabilities.imageWidth.min;
    widthSlider.max = photoCapabilities.imageWidth.max;
    widthSlider.step = photoCapabilities.imageWidth.step;
    return imageCapture.getPhotoSettings();
    })
    .then(function(photoSettings) {
    widthSlider.value = photoSettings.imageWidth;
    })
    .catch(error => console.error('Error getting camera capabilities and settings:', error));

구성

'실시간' 카메라 설정은 미리보기 MediaStreamTrackapplyConstraints() 제약 조건을 통해 구성할 수 있습니다. 예를 들면 다음과 같습니다.

var zoomSlider = document.querySelector('input[type=range]');

mediaStreamTrack.applyConstraints({ advanced: [{ zoom: zoomSlider.value }]})
    .catch(error => console.error('Uh, oh, applyConstraints() error:', error));

'비실시간' 카메라 설정은 takePhoto()의 선택적 PhotoSettings 사전으로 구성됩니다. 예를 들면 다음과 같습니다.

var widthSlider = document.querySelector('input[type=range]');
imageCapture.takePhoto({ imageWidth : widthSlider.value })
    .then(blob => {
    img.src = URL.createObjectURL(blob);
    img.onload = () => { URL.revokeObjectURL(this.src); }
    })
    .catch(error => console.error('Uh, oh, takePhoto() error:', error));

카메라 기능

위의 코드를 실행하면 grabFrame() 결과와 takePhoto() 결과 간에 측정기준의 차이가 있음을 알 수 있습니다.

takePhoto() 메서드는 카메라의 최대 해상도에 액세스할 수 있도록 합니다.

grabFrame()는 렌더러 프로세스 내의 MediaStreamTrack에서 사용 가능한 다음 VideoFrame를 가져오는 반면 takePhoto()MediaStream를 중단하고 카메라를 재구성하고 사진을 찍은 후 (일반적으로 압축된 형식이므로 Blob) MediaStreamTrack를 재개합니다. 즉, takePhoto()는 카메라의 전체 정지 이미지 해상도 기능에 액세스할 수 있습니다. 이전에는 동영상을 소스로 사용하여 canvas 요소에서 drawImage()를 호출하여 '사진을 찍을 수' 있었습니다 (여기의 예 참고).

자세한 내용은 README.md 섹션을 참고하세요.

이 데모에서 <canvas> 크기는 동영상 스트림의 해상도로 설정되지만 <img>의 실제 크기는 카메라의 최대 정지 이미지 해상도입니다. 물론 CSS는 둘 다의 디스플레이 크기를 설정하는 데 사용됩니다.

PhotoCapabilities.imageHeightimageWidthMediaSettingsRange 값을 사용하여 정지 이미지에 사용할 수 있는 모든 카메라 해상도를 가져오고 설정할 수 있습니다. getUserMedia()의 최소 및 최대 너비와 높이 제약 조건은 동영상용이며, 앞서 설명한 대로 정적 이미지의 카메라 기능과 다를 수 있습니다. 즉, getUserMedia()에서 캔버스로 저장할 때 기기의 전체 해상도 기능에 액세스하지 못할 수 있습니다. WebRTC 해상도 제약 조건 데모에서는 해상도에 getUserMedia() 제약 조건을 설정하는 방법을 보여줍니다.

기타 설정

  • Shape Detection API는 Image Capture와 잘 작동합니다. grabFrame()를 반복적으로 호출하여 ImageBitmapFaceDetector 또는 BarcodeDetector에 제공할 수 있습니다. Paul Kinlan의 블로그 게시물에서 API에 대해 자세히 알아보세요.

  • 카메라 플래시 (기기 조명)는 PhotoCapabilitiesFillLightMode를 통해 액세스할 수 있지만 토치 모드 (플래시가 계속 켜짐)는 MediaTrackCapabilities에서 찾을 수 있습니다.

데모 및 코드 샘플

지원

  • Android 및 데스크톱의 Chrome 59
  • 실험용 웹 플랫폼 기능이 사용 설정된 Android 및 데스크톱의 Chrome Canary(59 이전 버전)

자세히 알아보기