12

I am trying to use html2canvas to render a DOM element as a .png image, which I then want to upload to the server. Here is my code:

import React, { Component, PropTypes } from 'react';
import html2canvas from 'html2canvas';
import axios from 'axios';


const sendScreenshot = (img) => {
  const config = {
      headers: {
          'content-type': 'multipart/form-data'
      }
  }
  let data = new FormData();
  data.append('screenshot', img);      
  return axios.post('/api/upload', data)
}

export default class Export extends Component {

  printDocument() {
    const input = document.getElementById('divToPrint');
    html2canvas(input).then(canvas => {
      document.body.appendChild(canvas);
      const imgData = canvas.toDataURL('image/png');
      sendScreenshot(imgData)
    });
  }

  ...

I can see that the DOM element is being converted to an image properly because I can see it appended to the page.

On the node.js server end, I can see that the form is coming through, but 'screenshot' is being received as a text field, not as a file. I am using multer and I confirmed that I can properly receive and save file uploads, at least when I use Postman.

So I guess the basic problem is that I need to indicate that the item I am appending to FormData is a file, not a text field. But I can't figure out how to do that. I tried using append with three arguments, and I tried converting the imgData into a blob like so:

const blob = new Blob([img], {type: 'image/png'});

But the results did not put me any closer to what I wanted.

wbruntra
  • 1,021
  • 1
  • 10
  • 18

1 Answers1

37

To send binary data in a POST request, you want to use a Blob. A Blob represents raw binary data. To get a Blob of a Canvas, you can use the toBlob method.

Once you have the Blob instance, you can add the Blob to the FormData using the append method. The append method accepts Blob instances as the second argument. You can even pass an optional third argument to append to specify the filename to send with the Blob to the server.

The blob will be received on the server as file data.

An example of this in action:

const canvas = document.getElementById('my-canvas');
canvas.toBlob(function(blob) {
  const formData = new FormData();
  formData.append('my-file', blob, 'filename.png');

  // Post via axios or other transport method
  axios.post('/api/upload', formData);
});
Wazner
  • 2,962
  • 1
  • 18
  • 24
  • 1
    A small code snippet showing this in action would go a long way. – Steven Jeffries Aug 04 '19 at 02:24
  • @StevenJeffries Thx for the tip. I added an example. – Wazner Aug 04 '19 at 20:36
  • @TamaghnaBanerjee In what way doesn't it work? What errors do you get? Perhaps I could assist you. – Wazner Aug 13 '20 at 14:28
  • 2
    The form-data is not sending like how file upload works, I actually create an API which accepts and expects file upload as form-data like traditional file upload we do through upload button. I want to use same process just converting the canvas data to that format. Is it feasible? – Tamaghna Banerjee Aug 19 '20 at 07:42
  • @TamaghnaBanerjee Facing the same issue, have you found a solution ? – ht006 Feb 06 '23 at 10:41
  • 1
    @ht006 This should send it like normal file upload. What error are you receiving? – Wazner Feb 06 '23 at 20:35
  • Well, after some tinkering, I got it working, I figured out lately that to receive files on node.js backend I have to use 'mutler' because 'body-parser' doesn't support form-data in req – ht006 Feb 07 '23 at 07:25
  • @Wazner I think you should edit the answer to include changes needed to be done in backend. – ht006 Feb 07 '23 at 07:27
  • 1
    @ht006 I think that would be out-of-scope for the answer. The question was about how to send it to the server, not how to receive it. There are many different backend languages. A new question like "How do I receive uploaded files in a node.js server" would be better suited for such an answer. – Wazner Feb 07 '23 at 08:46