1

How can I save every few seconds a canvas Image to a Folder. ­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­

I have a Basic canvas drawing function and a download function to save the image like this:

<canvas></canvas>

var link = document.createElement('a');
    link.innerHTML = 'download image';
link.addEventListener('click', function(ev) {
    link.href = canvas.toDataURL();
    link.download = "mypainting.png";
}, false);
document.body.appendChild(link);

I want to implemente a button named start / stop.

If the user clicks on that button I want to save every second the canvas Image.

Every Image shall be saved as a new file.

How would this be possible? Is it even possible?

Micheasl
  • 277
  • 1
  • 5
  • 25
  • And by saving, do you mean it updates the same file every second, or it saves it as a new file? – Ivar Mar 30 '17 at 08:23
  • @Ivar it is always a new file – Micheasl Mar 30 '17 at 08:24
  • Why do you want to save every few seconds? Is it as an undo history or what? The intended use greatly affects the solution. – Emil S. Jørgensen Mar 30 '17 at 08:31
  • @EmilS.Jørgensen another application needs to get those Image every second to show it the user ... I can not say more about – Micheasl Mar 30 '17 at 08:34
  • 1
    I'm afraid you are at a loss then. Browsers don't allow for automatic download to specific folders without user interaction. It's a security issue for browsers, to prevent site from putting virus directly into `System32` or the like. You could prompt the user every few seconds to download, but that would be terrible User Experience. Can you perhaps use some server side code to put the images where they need to go? If the folder in question could be reached by your server, then it could put the files where they need to go. – Emil S. Jørgensen Mar 30 '17 at 08:39
  • @EmilS.Jørgensen How would you built that Server side Code, I could try to use that :) I could also try to built something like a base 64 string. The other app just Needs to get the Images somehow – Micheasl Mar 30 '17 at 08:45
  • First, do you have access to a server to write the code? Second, is that server on the same network as the user and can it access the folder in question? There is no need to describe how to implement if implementation is pointless. – Emil S. Jørgensen Mar 30 '17 at 08:47
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/139471/discussion-between-emil-s-jorgensen-and-micheasl). – Emil S. Jørgensen Mar 30 '17 at 08:54
  • I would also mention the mjepg format that contains jpeg frames. So instead of downloading multiple images we could start a mjpeg stream. For start here is some link: [link](https://stackoverflow.com/a/52328525) We need the opposite direction in this case. [link2](https://stackoverflow.com/a/50683349/5770014) – minus one Aug 30 '20 at 08:24

2 Answers2

2

Yes it is possible. Browser will ask the user to allow multiple file download. It will only download multiple images if user clicks confirms that he/she want to allow multiple file download.

var canvas = document.getElementById('canvas'),
    ctx = canvas.getContext('2d');

function doCanvas() {
    ctx.fillStyle = '#f90';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = '#fff';
    ctx.font = '30px sans-serif';
    ctx.fillText('Code Project', 10, canvas.height / 2 - 15);
    ctx.font = '13px sans-serif';
    ctx.fillText('Click start to download images', 15, canvas.height / 2 + 35);
}

function downloadCanvas(link, canvasId, filename) {
  link.href = document.getElementById(canvasId).toDataURL();
  link.download = filename;
}

document.getElementById('download').addEventListener('click', function() {
    downloadCanvas(this, 'canvas', 'test.png');
}, false);

doCanvas();

$( document ).ready(function() {
  $('#start').on('click', function() {
    if( confirm('This will continue download image every 2 second, do you want to proceed?') ) {
      setInterval(function() {
          $('#download')[0].click();
        }, 2000);
    }
  });
});
body {
  background-color:#555557;
  padding:0;
  margin:0;
  overflow:hidden;
  font-family:sans-serif;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
canvas {
  border:1px solid #000;
  float:left;
  clear:both;
}
#download {
  float:left;
  cursor:pointer;
  color:#ccc;
  padding:3px;
}
#download:hover {
  color:#fff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas width="250" height="150" id="canvas">Sorry, no canvas available</canvas>
<p>Make sure you have not blocked multiple file downloads.</p>
<a id="download"> </a>
<button id="start">Start</button>

SOURCE

0

I use this script.

    function saveImageAs(canvas, filename, type, quality){      // No IE <10 support. Chrome URL bug for very large images may crash
        var anchorElement, event, blob;
        type = type ? "png" : type;

        // for IE >= 10
        if(canvas.msToBlob !== undefined && navigator.msSaveBlob !== undefined){ 
           blob = canvas.msToBlob(); 
           navigator.msSaveBlob(blob, filename + "." + type); 
           return;
        }
        anchorElement = document.createElement('a');    // Create a download link
        if(type.toLowerCase() === "jpg" || type.toLowerCase() === "jpeg"){
            quality = quality ? quality : 0.9;
            anchorElement.href = canvas.toDataURL("image/jpeg",quality);         // attach the image data URL
        }else{                
            anchorElement.href = canvas.toDataURL();         // attach the image data URL
        }
        // check for download attribute
        if ( anchorElement.download !== undefined ) {
            anchorElement.download = filename + "." + type; // set the download filename
            if (typeof MouseEvent === "function") {     // does the browser support the object MouseEvent
                event = new MouseEvent( "click", {view  : window, bubbles: true,cancelable : true} );
                anchorElement.dispatchEvent(event); // simulate a click on the download link.
            } else
            if (anchorElement.fireEvent) {          // if no MouseEvent object try fireEvent 
                anchorElement.fireEvent("onclick");
            }
        }
    }

Then a simple download timer.

var timeoutHandle;
function startDownloads(){
    saveImageAs(canvas,"snap.jpg","jpeg");
    timeoutHandle = setTimeout(startDownloads,2000);
}
function stopDownloads(){
    clearTimeout(timeoutHandle);
}

Where the file is put and what name it gets is up to the client. There is no guarantee that the file will end up on the client's drive, nor is there any way to know if the download has completed.

Note Shame that the original answer was deleted. Not everyone will agree on methods, but it does not mean the method is wrong. "Will not work" only applies to bad code, not client preferences. Or should we all remove answers because some users block Javascript and thus any javascript answer will not work..

Good to see the original answer back.

Community
  • 1
  • 1
Blindman67
  • 51,134
  • 11
  • 73
  • 136
  • So I'll take this "*quote* note" to me. When this happens, prefer a comment, rather than including it in your answer, it has nothing to do there. When I made this comment stating that people should not run this snippet, there were an alert thrown along with the "Save As" popup, in a 1 second interval. This means an infinite loop, except if you are fast enough to close this alert, avoid the popup and click on the `hide snippet` link. Then, no it won't work. It's not because **one** browser defaults to *always trust that website after I said yes once* that it does for all the browsers ... – Kaiido Mar 31 '17 at 02:37
  • ... on the market. *"We can't save on user machine without his consent"* is still the default behaviour. Not to mention that the original idea is horrible anyway (what if I leave my computer on this page for hours without noticing it is filling my HDD ?), but making it an horrible UX for 49% of the market will kill your website. So saying that *"yes it is possible"* is wrong, and not displaying a note about the **huge caveats** is also wrong. – Kaiido Mar 31 '17 at 02:37
  • @Kaiido I completely understand and you were right that users will run the snippet and there was no alert about what they will be getting into. –  Mar 31 '17 at 05:02
  • Why -1 to this answer? Somebody explain. @Blindman67 upvoted.. respect :) –  Mar 31 '17 at 05:03
  • 2
    @roundAbout Who knows! Votes are given and taken for reasons that sometimes are not consistent with the content of the answer or question. BTW welcome to SO and I am glad you restored your answer, this question has attracted above average attention and your answer was a good example of how to achieve the OP's needs using jquery. Diversity keeps the answers fresh and attracting knowledgable new contributors is an important part of diversity so I try to encourage new users like you to participate and not be discouraged by differing views. – Blindman67 Mar 31 '17 at 05:49
  • Totally agree with this last comment (I'm not the one who downvoted your answer) I only did downvote the question because it lacks an important part eluded in a "*I can not say more about*" comment : the context. Good solutions could have been found, all depending on this context. Without it, we can't give correct solutions (so I didn't upvote neither of yours either), but this doesn't mean these answers deserve downvotes. I only posted a comment because there was a real problem in @roundAbout answer when I did saw it. It's kind of leveraged now so all is fine. Except this out-of-date note ;-) – Kaiido Mar 31 '17 at 06:27