Chụp ảnh và kiểm soát chế độ cài đặt của máy ảnh

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

Chụp ảnh là một API để chụp ảnh tĩnh và định cấu hình các chế độ cài đặt phần cứng của máy ảnh. API này có trong Chrome 59 trên Android và máy tính. Chúng tôi cũng đã phát hành thư viện polyfill ImageCapture.

API này cho phép kiểm soát các tính năng của máy ảnh như thu phóng, độ sáng, độ tương phản, ISO và cân bằng trắng. Quan trọng nhất, tính năng Chụp ảnh cho phép bạn sử dụng toàn bộ chức năng độ phân giải của mọi máy ảnh hoặc webcam có sẵn trên thiết bị. Các kỹ thuật chụp ảnh trên Web trước đây đã sử dụng ảnh chụp nhanh video, có độ phân giải thấp hơn so với độ phân giải có sẵn cho ảnh tĩnh.

Đối tượng ImageCapture được tạo bằng MediaStreamTrack làm nguồn. Sau đó, API có hai phương thức chụp takePhoto()grabFrame() cũng như các cách truy xuất chức năng và chế độ cài đặt của máy ảnh, cũng như thay đổi các chế độ cài đặt đó.

Xây dựng

API Chụp ảnh có quyền truy cập vào máy ảnh thông qua MediaStreamTrack nhận được từ getUserMedia():

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);
}

Bạn có thể thử mã này trong bảng điều khiển DevTools.

Quay hình

Bạn có thể chụp theo hai cách: toàn khung hình và ảnh chụp nhanh. takePhoto() trả về một Blob, kết quả của một lần phơi sáng ảnh. Trình duyệt có thể tải xuống, lưu trữ hoặc hiển thị kết quả này trong một phần tử <img>. Phương thức này sử dụng độ phân giải máy ảnh chụp ảnh cao nhất có sẵn. Ví dụ:

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() trả về một đối tượng ImageBitmap, ảnh chụp nhanh của video trực tiếp, có thể (ví dụ) được vẽ trên <canvas>, sau đó được xử lý sau để thay đổi giá trị màu một cách có chọn lọc. Xin lưu ý rằng ImageBitmap sẽ chỉ có độ phân giải của nguồn video – thường thấp hơn khả năng chụp ảnh tĩnh của máy ảnh. Ví dụ:

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));

Chế độ cài đặt và chức năng

Có một số cách để thao tác với chế độ cài đặt chụp, tuỳ thuộc vào việc các thay đổi có được phản ánh trong MediaStreamTrack hay chỉ có thể được thấy sau takePhoto(). Ví dụ: thay đổi về cấp zoom sẽ được truyền ngay lập tức đến MediaStreamTrack, trong khi tính năng giảm mắt đỏ (khi được đặt) chỉ được áp dụng khi chụp ảnh.

Các tính năng và chế độ cài đặt của máy ảnh "Trực tiếp" được thao tác thông qua bản xem trước MediaStreamTrack: MediaStreamTrack.getCapabilities() trả về một từ điển MediaTrackCapabilities có các tính năng được hỗ trợ cụ thể và các phạm vi hoặc giá trị được phép, ví dụ: phạm vi thu phóng được hỗ trợ hoặc chế độ cân bằng trắng được phép. Tương ứng, MediaStreamTrack.getSettings() trả về một MediaTrackSettings với các chế độ cài đặt hiện tại cụ thể. Chế độ thu phóng, độ sáng và đèn pin thuộc danh mục này, ví dụ:

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;
}

Các tính năng và chế độ cài đặt của máy ảnh "Không trực tiếp" được thao tác thông qua đối tượng ImageCapture: ImageCapture.getPhotoCapabilities() trả về đối tượng PhotoCapabilities cung cấp quyền truy cập vào các tính năng máy ảnh "Không trực tiếp" hiện có. Tương ứng, bắt đầu từ Chrome 61, ImageCapture.getPhotoSettings() sẽ trả về một đối tượng PhotoSettings có các chế độ cài đặt hiện tại cụ thể. Độ phân giải ảnh, tính năng giảm mắt đỏ và chế độ đèn flash (ngoại trừ đèn pin) thuộc phần này, ví dụ:

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));

Định cấu hình

Bạn có thể định cấu hình chế độ cài đặt máy ảnh "Trực tiếp" thông qua các quy tắc ràng buộc của applyConstraints() trong bản xem trước MediaStreamTrack, ví dụ:

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

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

Chế độ cài đặt máy ảnh "Không phải trực tiếp" được định cấu hình bằng từ điển PhotoSettings không bắt buộc của takePhoto(), ví dụ:

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));

Các tính năng của máy ảnh

Nếu chạy mã trên, bạn sẽ nhận thấy sự khác biệt về kích thước giữa kết quả grabFrame()takePhoto().

Phương thức takePhoto() cấp quyền truy cập vào độ phân giải tối đa của máy ảnh.

grabFrame() chỉ lấy VideoFrame tiếp theo có sẵn trong MediaStreamTrack bên trong quy trình kết xuất, trong khi takePhoto() làm gián đoạn MediaStream, định cấu hình lại máy ảnh, chụp ảnh (thường ở định dạng nén, do đó là Blob) rồi tiếp tục MediaStreamTrack. Về cơ bản, điều này có nghĩa là takePhoto() cấp quyền truy cập vào toàn bộ chức năng độ phân giải ảnh tĩnh của máy ảnh. Trước đây, bạn chỉ có thể "chụp ảnh" bằng cách gọi drawImage() trên phần tử canvas, sử dụng video làm nguồn (theo ví dụ tại đây).

Bạn có thể xem thêm thông tin trong phần README.md.

Trong bản minh hoạ này, kích thước <canvas> được đặt thành độ phân giải của luồng video, trong khi kích thước tự nhiên của <img> là độ phân giải ảnh tĩnh tối đa của máy ảnh. Tất nhiên, CSS được dùng để đặt kích thước màn hình của cả hai.

Bạn có thể lấy và đặt toàn bộ độ phân giải máy ảnh có sẵn cho ảnh tĩnh bằng cách sử dụng các giá trị MediaSettingsRange cho PhotoCapabilities.imageHeightimageWidth. Xin lưu ý rằng các giới hạn về chiều rộng và chiều cao tối thiểu và tối đa cho getUserMedia() là dành cho video (như đã thảo luận) và có thể khác với chức năng của máy ảnh đối với ảnh tĩnh. Nói cách khác, bạn có thể không thể truy cập vào toàn bộ khả năng phân giải của thiết bị khi lưu từ getUserMedia() vào canvas. Bản minh hoạ về quy tắc ràng buộc độ phân giải của WebRTC cho biết cách đặt các quy tắc ràng buộc getUserMedia() cho độ phân giải.

Còn thiết lập gì nữa không?

  • API Phát hiện hình dạng hoạt động tốt với tính năng Chụp ảnh: grabFrame() có thể được gọi nhiều lần để cung cấp ImageBitmap cho FaceDetector hoặc BarcodeDetector. Tìm hiểu thêm về API trong bài đăng trên blog của Paul Kinlan.

  • Bạn có thể truy cập vào Đèn flash của máy ảnh (đèn thiết bị) thông qua FillLightMode trong PhotoCapabilities, nhưng bạn có thể tìm thấy Chế độ đèn pin (đèn flash luôn bật) trong MediaTrackCapabilities.

Bản minh hoạ và mã mẫu

Hỗ trợ

  • Chrome 59 trên Android và máy tính.
  • Chrome Canary trên Android và máy tính trước phiên bản 59 đã bật các tính năng Nền tảng web thử nghiệm.

Tìm hiểu thêm