Sending canvas.toDataURL() as FormData
Asked Answered
C

1

15

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.

Citral answered 10/1, 2018 at 20:23 Comment(2)
You don't want to use toDataURL. Instead, you want to use the canvas.toBlob method. Then add the blob to the FormData.Hazem
It worked, thank you.Citral
H
41

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);
});
Hazem answered 10/1, 2018 at 20:38 Comment(9)
A small code snippet showing this in action would go a long way.Ovenware
@StevenJeffries Thx for the tip. I added an example.Hazem
@TamaghnaBanerjee In what way doesn't it work? What errors do you get? Perhaps I could assist you.Hazem
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?Banquet
@TamaghnaBanerjee Facing the same issue, have you found a solution ?Abstriction
@Abstriction This should send it like normal file upload. What error are you receiving?Hazem
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 reqAbstriction
@Hazem I think you should edit the answer to include changes needed to be done in backend.Abstriction
@Abstriction 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.Hazem

© 2022 - 2024 — McMap. All rights reserved.