0

I want to export an HTML canvas as an image on click of a button. My approach so far is to wrap the button in an anchor and onclick, send a request to my API to generate the save as dialog by setting the content-disposition to attachment for the response. Honestly I don't really need nor want to go to my server-side API for this because the canvas is in my client side code, but the only way I know of generating a 'save file' dialog is through setting the response header's content-disposition to attachment. The example here suggests using saveAs() from FileSaver.js but our prof doesn't let us use any external libraries. Is there a way to generate the 'Save File' dialog from the front-end code similarly to saveAs() using pure JS. If not, what would be cleanest alternative to sending the canvas blob with my request and packaging it in an image in my back-end?

Thanks

UPDATE:

I managed to get it to the point where I'm able to download image files using various resources. The problem now is that the files I download are corrupt and I'm not sure what the problem might be. Here's some code:

Frontend:

editjs.downloadCanvas = function(fileBlob,filename){
  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function() {
    if (this.readyState === XMLHttpRequest.DONE){
      console.log(this.status);

      if(this.status === 200){
         var a = document.createElement('a');
        document.getElementById('export_annotation').parentNode.appendChild(a);
         console.log("created anchor - trying to trigger download");
         a.href = "/export/pdfs/"+filename+"/canvases/page/"+filename+"-pg-"+pageNum;
         a.click();
      }
    }
  };
  var formData = new FormData();
  formData.append("file", fileBlob);
  formData.append("name", filename+"-pg-"+pageNum);

  var url = "/export/pdfs/"+filename+"/canvases/"+pageNum;
  xhr.open("POST",url,true);
  console.log("sending export data");
  xhr.send(formData);
}


editjs.getContent = function(dataURL,filename,callback){

  var req = new XMLHttpRequest;

  req.open( 'GET', dataURL );
  req.responseType = 'arraybuffer';
  req.onload = function fileLoaded(e)
  {
      var mime = this.getResponseHeader('content-type');
      callback(new Blob([this.response], {type:mime}),filename) ;
  };

  req.send();
}

BACKEND:

        app.post('/export/pdfs/:fname/canvases/:page',upload.single("file"), function(req,res){
    console.log("Creating export file!");
    console.log(req.body.name);
    if (req.session.user){
      MongoClient.connect("mongodb://localhost:27017/test", function(err, db) {
        if(err) res.status(500).end("Database error");
        console.log("Connected to Database");
        var tmp_file = {filename: req.body.name, file_path: req.file.path};
        db.collection('canvases').save(tmp_file, function(err, record) {
           if (err) res.status(500).end("Database error");
            db.close();
            return res.send();
         });
       });
      console.log("exporting to:");
      console.log(req.file.path);
    }
    else{return res.status(403).end("Forbidden");}
  });





  app.get('/export/pdfs/:fname/canvases/page/:storedfname', function(req,res){
    if (req.session.user){
      console.log("reading");
      console.log(req.params.storedfname);
      MongoClient.connect("mongodb://localhost:27017/test", function(err, db) {
        if(err) res.status(500).end("Database error");

        db.collection('canvases').findOne({filename: req.params.storedfname}, function(err, record) {
           if (err) res.status(500).end("Database error");
           console.log(record);
           if (record){
            db.close();
            console.log("record found");
            res.setHeader('Content-type','image/png');
            res.setHeader('Content-disposition', "attachment; filename=" +req.params.storedfname+".png");
            fs.createReadStream(record.file_path).pipe(res);
          }
         });
       });
    }
    else{return res.status(403).end("Forbidden");}
  });
ribarcheto94
  • 436
  • 11
  • 25

1 Answers1

0

You can create an

<a> 

element with href attribute set to Blob URL by passing Blob to

URL.createObjectURL()

download 

attribute set to suggested file name; append

<a> 

element to document, call

.click()

on a element.

See also How to download a file without using <a> element with download attribute or a server?

Community
  • 1
  • 1
guest271314
  • 1
  • 15
  • 104
  • 177
  • I don't think the download attribute is supported by many browsers currently. It's a good solution but I'm looking for some something that will work in more browsers. Thanks. – ribarcheto94 Mar 25 '17 at 16:20
  • You can use data URI or Blob with MIME type set to application/octet-stream and window.open(). See also form approach at linked Question/Answer – guest271314 Mar 25 '17 at 18:11
  • I made some progress thanks to some resources online, but now I have a new problem as the file I download is corrupt. Can you please look a the code I posted and give me some guidance on what might be wrong? Thanks – ribarcheto94 Mar 25 '17 at 18:40