צילום תמונות ושליטה בהגדרות המצלמה

מיגל קאסאס-סאנצ'ז
פרנסואה בופורט
פרנסואה בופורט

התכונה 'צילום תמונות' היא API לצילום תמונות סטילס ולקביעת הגדרות החומרה של המצלמה. ה-API הזה זמין ב-Chrome 59 ב-Android ובמחשבים. פרסמנו גם ספריית polyfill של ImageCapture.

ה-API מאפשר לשלוט בתכונות של המצלמה כמו זום, בהירות, ניגודיות, ISO ואיזון לבן. והכי חשוב, צילום תמונות מאפשר לכם לגשת ליכולות הרזולוציה המלאה של כל מצלמת המכשיר או מצלמת האינטרנט הזמינים. בשיטות הקודמות לצילום תמונות באינטרנט נעשה שימוש בצילומי וידאו, שהרזולוציה שלהם נמוכה יותר מהרזולוציה הזמינה לתמונות סטילס.

אובייקט ImageCapture נוצר עם MediaStreamTrack כמקור. ל-API יש שתי שיטות צילום: takePhoto() ו-grabFrame(), ודרכים שונות לאחזור היכולות וההגדרות של המצלמה ולשנות את ההגדרות.

אתר בנייה

ה-Image Capture API מקבל גישה למצלמה באמצעות MediaStreamTrack שהתקבל מ-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);
}

אפשר לנסות את הקוד הזה ממסוף כלי הפיתוח.

צילום

ניתן לבצע צילום בשתי דרכים: פריים מלא ותמונת מצב מהירה. 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));

מתבצעת הגדרה

ניתן לקבוע את הגדרות המצלמה "שידור חי" דרך התצוגה המקדימה MediaStreamTrack's applyConstraints() מגבלות , לדוגמה:

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() רק משתמש בVideoFrame הזמין הבא ב-MediaStreamTrack בתוך תהליך הרינדור, ואילו takePhoto() קוטע את MediaStream, מגדיר מחדש את המצלמה, מצלם את התמונה (בדרך כלל בפורמט דחוס, ומכאן Blob) ואז ממשיך את MediaStreamTrack. בעיקרון, זה אומר ש-takePhoto() נותן גישה ליכולות המלאות של רזולוציית תמונת הסטילס של המצלמה. בעבר, היה אפשר לצלם תמונה רק על ידי קריאה ל-drawImage() ברכיב canvas, תוך שימוש בסרטון כמקור (כמו בדוגמה כאן).

מידע נוסף זמין בקטע README.md.

בהדגמה הזו, המידות של <canvas> נקבעות לרזולוציה של שידור הווידאו, בעוד שהגודל הטבעי של <img> הוא הרזולוציה המרבית של תמונת הסטילס של המצלמה. ניתן להשתמש ב-CSS, כמובן, כדי להגדיר את גודל התצוגה של שניהם.

אפשר להשיג את הטווח המלא של רזולוציות המצלמה לתמונות סטילס ולהגדיר אותן באמצעות הערכים MediaSettingsRange של PhotoCapabilities.imageHeight ו-imageWidth. שימו לב שמגבלות הרוחב והגובה המינימליות והמקסימליות של getUserMedia() מתייחסות לווידאו, כפי שהן (כפי שמתואר) עשויות להיות שונות מיכולות המצלמה לגבי תמונות סטילס. כלומר, יכול להיות שלא תהיה לך אפשרות לגשת ליכולות הרזולוציה המלאות של המכשיר שלך כששומרים קובץ מ-getUserMedia() על קנבס. הדגמת אילוצים של רזולוציה של WebRTC מדגימה איך להגדיר אילוצים של getUserMedia() לפתרון הבעיה.

עוד משהו?

  • Configure Detection API פועל היטב עם צילום תמונה: אפשר לקרוא ל-grabFrame() שוב ושוב כדי לעדכן ImageBitmaps ל-FaceDetector או ל-BarcodeDetector. ראו מידע נוסף על ה-API בפוסט בבלוג של פול קינלן.

  • ניתן לגשת אל הפלאש של המצלמה (הפלאש של המכשיר) דרך FillLightMode בPhotoCapabilities, אבל מצב הפנס (הפלאש פועל כל הזמן) נמצא בMediaTrackCapabilities.

הדגמות ודוגמאות קוד

תמיכה

  • Chrome 59 ב-Android ובמחשב.
  • Chrome Canary ב-Android ובמחשב שולחני לפני 59 שנים, שבהן הופעלו תכונות של פלטפורמת אינטרנט ניסיונית.

למידע נוסף