{"componentChunkName":"component---src-templates-tags-js","path":"/tags/imagecaptureapi/","result":{"data":{"allMarkdownRemark":{"totalCount":1,"edges":[{"node":{"id":"311de7ae-f9be-5da6-b42d-e979c22a3b3e","html":"<p>It’s been a while since I last wrote about Intersection Observer V2, partly because I had a lot on my plate and I was feeling exhausted and partly because I was working on my first <a href=\"app.pluralsight.com/library/courses/web-performance-progressive-web-apps\">PluralSight course on web performance for PWAs</a>.</p>\n<p>But I am back, and this time we’re going to review how to take a selfie from your webcam using <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/MediaStream_Image_Capture_API\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Image Capture API</a>.</p>\n<!--more-->\n<h2 id=\"image-capture-api\" style=\"position:relative;\"><a href=\"#image-capture-api\" aria-label=\"image capture api permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Image Capture API</h2>\n<p>There are some really useful APIs which allow us to work with media like audio, video, etc. I will write about those too, but this time I wanted to show you how you can extract a frame from your video feed such as your webcam with a few lines of code.</p>\n<p><a href=\"https://developer.mozilla.org/en-US/docs/Web/API/MediaStream_Image_Capture_API\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Image Capture API</a> enables us to capture an image or frame from video devices. In addition to capturing data, it also allows you to retrieve information about device capability such as image size, red-eye detection and whether or not there is flash turned on.</p>\n<h2 id=\"usage\" style=\"position:relative;\"><a href=\"#usage\" aria-label=\"usage permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Usage</h2>\n<p>We need to take some actions to be able to work with media devices. First thing first we need to get a reference of the device:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"30174315677986742000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied to clipboard ✅\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`navigator.mediaDevices.getUserMedia({ video: true })\r\n  .then(mediaStream => {\r\n    // Do something with the stream.\r\n  })`, `30174315677986742000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                Copy<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-js line-numbers\"><code class=\"language-js\">navigator<span class=\"token punctuation\">.</span>mediaDevices<span class=\"token punctuation\">.</span><span class=\"token function\">getUserMedia</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">video</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\r\n  <span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">mediaStream</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\r\n    <span class=\"token comment\">// Do something with the stream.</span>\r\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span></span></pre></div>\n<p>Next we need to get the visual parts of the media stream by calling <code class=\"language-text\">getVideoTracks</code> method of the <code class=\"language-text\">mediaStream</code> object:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"76983858953704200000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied to clipboard ✅\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`const track = mediaStream.getVideoTracks()[0];`, `76983858953704200000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                Copy<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-js line-numbers\"><code class=\"language-js\"><span class=\"token keyword\">const</span> track <span class=\"token operator\">=</span> mediaStream<span class=\"token punctuation\">.</span><span class=\"token function\">getVideoTracks</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span></span></pre></div>\n<p>Of course we’re assuming that the first item in the array is the one you want to use, but don’t worry if not, you can loop through all the tracks, find the one you need and either get it with its right index, or by calling <code class=\"language-text\">getTrackById</code> method.</p>\n<p>After we’ve got our track, it’s time to capture our image. If you wanted to configure some of the settings on your media device such as zoom level, you need to do it now before capturing our image:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"54809987753683110000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied to clipboard ✅\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`const capabilities = track.getCapabilities();\r\n// Check whether zoom is supported or not.\r\nif(!capabilities.zoom) {\r\n  return;\r\n}\r\n\r\nconst zoom = capabilities.zoom.max - capabilities.zoom.min;\r\n\r\ntrack.applyConstraints({ advanced : [{ zoom: zoom }] });`, `54809987753683110000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                Copy<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-js line-numbers\"><code class=\"language-js\"><span class=\"token keyword\">const</span> capabilities <span class=\"token operator\">=</span> track<span class=\"token punctuation\">.</span><span class=\"token function\">getCapabilities</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\r\n<span class=\"token comment\">// Check whether zoom is supported or not.</span>\r\n<span class=\"token keyword\">if</span><span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>capabilities<span class=\"token punctuation\">.</span>zoom<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\r\n  <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\r\n<span class=\"token punctuation\">}</span>\r\n\r\n<span class=\"token keyword\">const</span> zoom <span class=\"token operator\">=</span> capabilities<span class=\"token punctuation\">.</span>zoom<span class=\"token punctuation\">.</span>max <span class=\"token operator\">-</span> capabilities<span class=\"token punctuation\">.</span>zoom<span class=\"token punctuation\">.</span>min<span class=\"token punctuation\">;</span>\r\n\r\ntrack<span class=\"token punctuation\">.</span><span class=\"token function\">applyConstraints</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">advanced</span> <span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">zoom</span><span class=\"token operator\">:</span> zoom <span class=\"token punctuation\">}</span><span class=\"token punctuation\">]</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<p>When we’re done with settings, we can then create an instance of the <code class=\"language-text\">ImageCapture</code> object:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"17388920753778358000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied to clipboard ✅\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`let imageCapture = new ImageCapture(track);`, `17388920753778358000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                Copy<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-js line-numbers\"><code class=\"language-js\"><span class=\"token keyword\">let</span> imageCapture <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">ImageCapture</span><span class=\"token punctuation\">(</span>track<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span></span></pre></div>\n<p>Once that’s done, you can capture an image from your video feed by calling the <code class=\"language-text\">takePhoto</code> method:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"12082815144094839000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied to clipboard ✅\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`imageCapture.takePhoto()\r\n  .then(blob => createImageBitmap(blob))\r\n  .then(imageBitmap => {\r\n    // do something with the photo\r\n  })\r\n  .catch(error => console.error(error));`, `12082815144094839000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                Copy<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-js line-numbers\"><code class=\"language-js\">imageCapture<span class=\"token punctuation\">.</span><span class=\"token function\">takePhoto</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\r\n  <span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">blob</span> <span class=\"token operator\">=></span> <span class=\"token function\">createImageBitmap</span><span class=\"token punctuation\">(</span>blob<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\r\n  <span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">imageBitmap</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\r\n    <span class=\"token comment\">// do something with the photo</span>\r\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\r\n  <span class=\"token punctuation\">.</span><span class=\"token function\">catch</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">error</span> <span class=\"token operator\">=></span> console<span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<h2 id=\"permissions\" style=\"position:relative;\"><a href=\"#permissions\" aria-label=\"permissions permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Permissions</h2>\n<p>Similar to other APIs you would need permission to be able to access the webcam on devices. If you didn’t see any pop up, make sure you give the camera permission to the site on your browser to be able to get your code working properly. You can try that with below demo.</p>\n<h2 id=\"demo\" style=\"position:relative;\"><a href=\"#demo\" aria-label=\"demo permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Demo</h2>\n<p>You can see a working example of this in my CodePen below:</p>\n<iframe height=\"265\" style=\"width: 100%;\" scrolling=\"no\" title=\"Image Capture API\" src=\"https://codepen.io/yashints/embed/preview/bGpaWKY?height=265&theme-id=light&default-tab=result\" frameborder=\"no\" loading=\"lazy\" allowtransparency=\"true\" allowfullscreen=\"true\">\r\n  See the Pen <a href='https://codepen.io/yashints/pen/bGpaWKY'>Image Capture API</a> by Yaser Adel Mehraban\r\n  (<a href='https://codepen.io/yashints'>@yashints</a>) on <a href='https://codepen.io'>CodePen</a>.\r\n</iframe>\n<p>I hope you’ve learnt a new thing or two and till next time 👋🏽.</p>","timeToRead":2,"frontmatter":{"title":"Take a selfie 🤳 using Image Capture API and a few lines of code","unformattedDate":"2020-09-06T00:00:00.000Z","date":"Sep 06, 2020","path":"/image-capture-api/","author":"Yaser Adel Mehraban","tags":["showdev","webdev","javascript","imagecaptureapi"],"thumbnail":null}}}]}},"pageContext":{"tag":"imagecaptureapi"}},"staticQueryHashes":[],"slicesMap":{}}