用 HTML 的 capture 屬性，開啟手機鏡頭進行拍照、錄影
Tags: webdev, beginners, tutorial, html
Published: 2022-11-05 10:03:18

## 本篇要解決的問題

以前研究過一下怎麼用 JavaScript 打開手機的鏡頭，進行拍照或錄影，當時做出了 Demo 後，然後就……突然一陣子忙，就忘記寫文章了 XD。

直到昨天看到一篇文章，才知道原來 HTML 本身就有 attribute 讓使用者開啟鏡頭，進行拍照或錄影，而且寫起來 Hen~ 簡單，就決定製作一個小 Demo，並寫出這篇筆記文。

參考的文章及 MDN 的說明連結在這：

- [You Can Access A User’s Camera with Just HTML](https://austingil.com/html-capture-attribute/)
- [HTML attribute: capture](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/capture)

製作出來的 Demo 在這，只能用手機操作，用桌機的話無法使用。

<https://letswritetw.github.io/letswrite-html-capture/>

---

## HTML 屬性開啟鏡頭

這邊直接提供開啟手機鏡頭的 HTML 屬性是什麼：

- capture：`user` 前鏡頭、`environment` 後鏡頭
- accept：`audio` 聲音檔、`video` 影片檔、`image` 圖檔

這二個屬性是寫在 `input type="file"` 裡的，範例如下：

```html
<!-- 開啟 前鏡頭 錄影、拍照 -->
<input type="file" capture="user" accept="video/*"/>
<input type="file" capture="user" accept="image/*"/>

<!-- 開啟 後鏡頭 錄影、拍照 -->
<input type="file" capture="environment" accept="video/*"/>
<input type="file" capture="environment" accept="image/*"/>
```

想看效果的朋友可以進到 Demo 裡去玩一玩，Demo 頁不會把大家的照片或影片給存下來，一切都是在頁面上操作而已 ~~（因為沒有酷錢錢買空間存）~~。

另外，August 用 iPhone 實測時，前鏡頭預設會打開閃光燈，拍照前記得關掉，不然會被閃到看見人生的跑馬燈。

---

## 把使用者照片、影片放到頁面上預覽

在 Demo 頁上如果大家有試玩拍照跟錄影，會看見 August 有把拍照的照片跟錄影的影片給放在結果顯示區，這個不用擔心，並不是先存到某台主機上後，再把路徑丟回給頁面，而是直接用 [FileReader](https://developer.mozilla.org/zh-TW/docs/Web/API/FileReader) 把各位當下的檔案給塞到頁面上 `img`、`video` 的 `src` 裡。

這段是要寫怎麼把照片、影片給轉成網頁可讀的 `src`~~（買不起空間啊廣告還不點起來讓本站賺個微簿的酷錢錢）~~。

### 轉圖片

最簡單的方式，先在 HTML 上放個不寫 `src` 的 `img`，之後抓到 Base64 後再寫進 `src` 裡。

```html
<img id="Im_image">
```

```javascript
const input = document.getElementById('xxx');
input1.addEventListener('change', handleFilesImage, false);

function handleFilesImage() {
  const fileData = this.files;
  const reader = new FileReader();
  reader.addEventListener('load', file => {
    const img = document.getElementById('Im_image');
    img.src = file.target.result;
  });
  reader.readAsDataURL(fileData[0]);
}
```

### 轉影片

一樣用最簡單的方式，先在 HTML 上放個不寫 `src` 的 `video`，之後抓到 Blob 後再寫進 `src` 裡。

轉影片的 JavaScript 主要參考這篇：[How to read large video files in JavaScript using FileReader?](https://stackoverflow.com/questions/61012790/how-to-read-large-video-files-in-javascript-using-filereader)

```html
<video id="Im_video" controls="controls"></video>
```

```javascript
const input = document.getElementById('xxx');
input1.addEventListener('change', handleFilesVideo, false);

function handleFilesVideo() {
  const fileData = this.files;
  const reader = new FileReader();
  reader.readAsArrayBuffer(fileData[0]);
  reader.addEventListener('load', file => {
    const buffer = file.target.result;
    const videoBlob = new Blob([new Uint8Array(buffer)], { type: 'video/mp4' });
    const url = window.URL.createObjectURL(videoBlob);
    const video = document.getElementById('Im_video');
    video.src = url;
  });
}
```

---

## 關於客製 input file

如果直接用 `input type="file"`，預設會長的像這樣：

![一般的 input file 樣子](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nu8kdt7p9rs1dq9bhyce.png)

但因為這邊我們讓使用者做的動作是「打開鏡頭」，如果顯示的像預設那樣是寫「選擇檔案」，使用者會感到疑惑，所以 Demo 上有客製了 input file 的樣子成一個按鈕，上面可以寫上我們想要的文字：

![客製 input file](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1zim6zpjbg416wf7109r.png)

客製 input file 的方式本站以前有寫過，這邊就不再重複寫，有興趣的朋友可以點連結觀看：

[File API 客製上傳檔案按鈕 / input file](https://www.letswrite.tw/file-api-custom-input/)

---

## 支援度、安全性

HTML `capture` 這個 attribute 的支援度，在 [Can I use](https://caniuse.com/html-media-capture) 上是這樣：

![HTML capture 的支援度](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/53dmc4rwfzowlph2gb30.png)

可以看到支援的部份全在手機，這也正常，現在大家都手機不離身了，要拍照或錄影也不會用電腦來使用。

關於安全性，這邊要寫的並不是說用這個 HTML 的屬性安不安全，而是像參考連結裡第一篇文章提到的，用 `capture` 這個方式，並不會像用 App 那樣，會先詢問使用者能不能授權開啟相機功能，而是直接就打開了，這對使用者來說會有安全的疑慮。

但就像參考文章中說的，這最後的產出是一個 input 裡的檔案，當我們逛網頁時，如果自己點擊了 input，打開相機，又自己按下了拍照或錄影，然後又按下了確定使用照片或影片，這都是我們自己決定的，而且至少要 3 次的點擊才會把照片傳到網頁上，這中間的過程，目前只能說，在瀏覽器並未限制使用者點擊了帶有 `capture` 屬性的 `input` 的當下，大家逛網站真的是不要亂點不信任的網站任何按鈕或連結，看到點了某個按鈕時突然打開了鏡頭時，更要當心。