# Taking snapshot from video stream and save to a directory

**URL:** <https://forum.inductiveautomation.com/t/taking-snapshot-from-video-stream-and-save-to-a-directory/70195>\
**Category:** Ignition\
**Tags:** perspective, scripting\
**Created:** [February 23, 2023, 1:20am UTC](https://forum.inductiveautomation.com/t/taking-snapshot-from-video-stream-and-save-to-a-directory/70195 "2023-02-23T01:20:49Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![J\_Ch77](https://avatars.discourse-cdn.com/v4/letter/j/85f322/32.png) [@J\_Ch77](https://forum.inductiveautomation.com/u/J_Ch77)\
**Post date:** [February 23, 2023, 1:20am UTC](https://forum.inductiveautomation.com/t/taking-snapshot-from-video-stream-and-save-to-a-directory/70195/1 "2023-02-23T01:20:49Z")

</div>

Hi,

I'm using the video player component to stream video from a url created by streaming a webcam through VLC player. I tried binding the following to a button press but it doesn't work.

```auto
	videoPlayer = event.source.parent.getComponent('VideoPlayer')
	
	snapshot = videoPlayer.takeSnapshot()
	
	filePath = 'C:/Users/EngineeringVM/Documents/Images/snapshot.jpg'
	system.file.writeFile(filePath, snapshot)

```

What's the correct approach to do so?

---

<div class="post-metadata">

**Author:** ![justinedwards.jle](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justinedwards.jle/32/37854_2.png) [@justinedwards.jle](https://forum.inductiveautomation.com/u/justinedwards.jle)\
**Post date:** [February 23, 2023, 7:33am UTC](https://forum.inductiveautomation.com/t/taking-snapshot-from-video-stream-and-save-to-a-directory/70195/2 "2023-02-23T07:33:49Z")

</div>

In perspective, `system.file.writeFile` is gateway scoped, so if the file is getting written. you'll find it there. Perspective does not have access to the local file structure.

Here are a couple of related threads that could be of use here:

> [@System.file.writeFile issue with Perspective](https://forum.inductiveautomation.com/t/system-file-writefile-issue-with-perspective/24229/3):
>
> To add onto @pturmel’s response, please look at the available scopes for the functions you’re attempting to use; saveFile() is only available in Vision Client scripting - not Perspective Sessions. The writeFile() function IS available in Perspective, but ALL functions in Perspective run on the Gateway (so that’s where the file is written to), so you will never see a file on your local machine as a result of using writeFile(). There’s no mechanism in Perspective as of today that allows for expo…

> [@system.file.writeFile in perspective](https://forum.inductiveautomation.com/t/system-file-writefile-in-perspective/23664):
>
> Does writeFile() work in perspective for the session? I’m able to get a file to write from a gateway message relative to the gateway folder structure, but when I try to use the session with a static file path I don’t get an error in the log but I also don’t get the file.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [February 23, 2023, 12:34pm UTC](https://forum.inductiveautomation.com/t/taking-snapshot-from-video-stream-and-save-to-a-directory/70195/3 "2023-02-23T12:34:22Z")

</div>

Since when does Perspective use `event.source` ??

---

<div class="post-metadata">

**Author:** ![justinedwards.jle](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justinedwards.jle/32/37854_2.png) [@justinedwards.jle](https://forum.inductiveautomation.com/u/justinedwards.jle)\
**Post date:** [February 23, 2023, 12:45pm UTC](https://forum.inductiveautomation.com/t/taking-snapshot-from-video-stream-and-save-to-a-directory/70195/4 "2023-02-23T12:45:33Z")

</div>

@J_Ch77: This post is tagged as Perspective; did you buy chance mean Vision? If so, that's a completely different answer.

---

<div class="post-metadata">

**Author:** ![J\_Ch77](https://avatars.discourse-cdn.com/v4/letter/j/85f322/32.png) [@J\_Ch77](https://forum.inductiveautomation.com/u/J_Ch77)\
**Post date:** [February 23, 2023, 4:32pm UTC](https://forum.inductiveautomation.com/t/taking-snapshot-from-video-stream-and-save-to-a-directory/70195/5 "2023-02-23T16:32:11Z")

</div>

No, I mean Perspective.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [February 23, 2023, 5:25pm UTC](https://forum.inductiveautomation.com/t/taking-snapshot-from-video-stream-and-save-to-a-directory/70195/6 "2023-02-23T17:25:40Z")

</div>

So:

1. The video player does not have a method `takeSnapshot`.
2. You can't directly write files on the user's behalf even if it did, because browsers won't let you (as mentioned).
3. You don't use `event.source` in Perspective (as mentioned).

What you're asking for is fundamentally not possible at the moment. If we were to _add_ a 'snapshot' functionality to the video player, it would have to return a byte array that you could then _prompt_ the user to download using `system.perspective.download`. But without us introducing that function first party, you don't have many options. Perhaps @victordcq could come up with a way to 'inject' a button via the markdown component that opened the videoplayer with a dedicated print stylesheet; that's the trick the power chart uses to "print" itself.

---

<div class="post-metadata">

**Author:** ![victordcq](https://avatars.discourse-cdn.com/v4/letter/v/f6c823/32.png) [@victordcq](https://forum.inductiveautomation.com/u/victordcq)\
**Post date:** [February 24, 2023, 9:09am UTC](https://forum.inductiveautomation.com/t/taking-snapshot-from-video-stream-and-save-to-a-directory/70195/7 "2023-02-24T09:09:54Z")

</div>

i'll take a look next week, shouldnt be to hard i think

---

<div class="post-metadata">

**Author:** ![J\_Ch77](https://avatars.discourse-cdn.com/v4/letter/j/85f322/32.png) [@J\_Ch77](https://forum.inductiveautomation.com/u/J_Ch77)\
**Post date:** [March 6, 2023, 4:50pm UTC](https://forum.inductiveautomation.com/t/taking-snapshot-from-video-stream-and-save-to-a-directory/70195/8 "2023-03-06T16:50:13Z")

</div>

Any updates on this?

---

<div class="post-metadata">

**Author:** ![victordcq](https://avatars.discourse-cdn.com/v4/letter/v/f6c823/32.png) [@victordcq](https://forum.inductiveautomation.com/u/victordcq)\
**Post date:** [March 7, 2023, 12:56pm UTC](https://forum.inductiveautomation.com/t/taking-snapshot-from-video-stream-and-save-to-a-directory/70195/9 "2023-03-07T12:56:50Z")

</div>

right

i had somthing setup, but the resolution wasnt perfect yet, the button wasnt sizing properly...  
and my designer keeps freezing when i tried to export it so it got delayed xd

i havent maanged to fix these problems yet but i can past the code in here i guess instead of providng a demo.  
i hope its not related to the js injection, cuz if it is it might break your designer too xd **causion** is adviced if you cant wait

```auto
{
  "custom": {},
  "params": {},
  "props": {},
  "root": {
    "children": [
      {
        "meta": {
          "domId": "videoplayerId",
          "name": "VideoPlayer"
        },
        "position": {
          "height": 288,
          "width": 512,
          "x": 26,
          "y": 87
        },
        "props": {
          "source": "/main/test.mp4"
        },
        "type": "ia.display.video-player"
      },
      {
        "meta": {
          "name": "Markdown"
        },
        "position": {
          "height": 50,
          "width": 418,
          "x": 36,
          "y": 409
        },
        "propConfig": {
          "props.source": {
            "binding": {
              "config": {
                "expression": "{../VideoPlayer.meta.domId}"
              },
              "transforms": [
                {
                  "code": "\t#make the propName the key to write too in the view.custom \n\t\n\tcode \u003d \"\"\"\u003cdiv style\u003d\\\"width:100%; height:100%;\\\"\u003e\u003cbutton style\u003d\\\"width:100%; height:100%;\\\" onclick\u003d\\\" let canvas \u003d document.createElement(\u0027canvas\u0027);\n\t\tlet video \u003d document.querySelector(\u0027#\"\"\"+value+\"\"\" video\u0027);\t\n\t\tconsole.log(video);\t\n\t\tconst rect \u003d video.getBoundingClientRect();\n\t\tcanvas.width \u003d 1980;\n\t\tcanvas.height \u003d 1200;\t\t\n\t\tlet ctx \u003d canvas.getContext(\u00272d\u0027);\n\t\tctx.drawImage( video, 0,0 );\t\t\n\t\tlet imageURL \u003d canvas.toDataURL(\u0027image/png\u0027);\n\t\tconsole.log(imageURL);\n\t\tconst contentType \u003d \u0027image/png\u0027;\t\t\n\t\tconst byteCharacters \u003d atob(imageURL.substr(`data:${contentType};base64,`.length));\n\t\tconst byteArrays \u003d [];\t\t\n\t\tfor (let offset \u003d 0; offset \u003c byteCharacters.length; offset +\u003d 1024) {\n\t\t const slice \u003d byteCharacters.slice(offset, offset + 1024);\t\t\n\t\t const byteNumbers \u003d new Array(slice.length);\n\t\t for (let i \u003d 0; i \u003c slice.length; i++) {\n\t\t byteNumbers[i] \u003d slice.charCodeAt(i);\n\t\t }\t\t\n\t\t const byteArray \u003d new Uint8Array(byteNumbers);\t\t\n\t\t byteArrays.push(byteArray);\n\t\t}\n\t\tconst blob \u003d new Blob(byteArrays, {type: contentType});\n\t\tconst blobUrl \u003d window.URL.createObjectURL(blob);\t\t\n\t\twindow.open(blobUrl, \u0027_blank\u0027);\t\t \n\t\\\" \u003e screenshot \u003c/button\u003e\u003c/div\u003e\"\"\".replace(\"\\n\", \"\").replace(\"\\t\", \"\")\n\treturn code\n\t",
                  "type": "script"
                }
              ],
              "type": "expr"
            }
          }
        },
        "props": {
          "markdown": {
            "escapeHtml": false
          },
          "style": {
            "classes": "fixMarkdownElementHeight"
          }
        },
        "type": "ia.display.markdown"
      }
    ],
    "meta": {
      "name": "root"
    },
    "type": "ia.container.coord"
  }
}

```
