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

미구엘 카사스-산체스
프랑수아 보포르
프랑수아 보포르

이미지 캡처는 스틸 이미지를 캡처하고 카메라 하드웨어 설정을 구성하는 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를 반환합니다. 이 결과는 다운로드하여 브라우저에서 저장하거나 <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는 이미지 캡처와 함께 잘 작동합니다. grabFrame()를 반복적으로 호출하여 ImageBitmapFaceDetector 또는 BarcodeDetector에 피드할 수 있습니다. API에 대한 자세한 내용은 폴 킨란의 블로그 게시물을 참조하세요.

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

데모 및 코드 샘플

지원

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

자세히 알아보기