Search code examples
javascriptcanvaswoocommerceinput-type-file

How I put the canvas content as a file in a input type file


After months of searching examples and answers, I can’t find anything that works for me. All help is welcome.

System --- Woocommerce -- Single product page.

I bought an add-on to attach one image when your're on <form class="cart">. This is in single product page.

Basically the plugin adds a <input type ="file"> in the form and allows you to attach images in order. I'm happy with it because it works fine and a lot of backend work is taken care of.

On the other hand, I have a <canvas> and I need yo load the <canvas> content in the <input type ="file">. Once done, the add-on is ready to do its job.

So my question is: How do I put the content of the canvas as a file in the <input>?


Solution

  • The best is still to send files through a FormData and AJAX.

    But since it seems it's for personal use, and that you already have something working with a <form>, you can probably use what is still an hack exposed in this answer of mine. Beware this still works only in latest Chromium and Geckos browsers (no Webkit support, which means no iOS support).

    So the step by step is,

    • draw on your canvas.
    • export it to a Blob using the HTMLCanvasElement.toBlob() method.
    • build a File from this Blob
    • build a DataTransfer object
    • append the File to the DataTransfer's items list
    • set the .files property of your <input type="file"> to the DataTransfer's .files

    // draw on the canvas
    const canvas = document.createElement( "canvas" );
    const ctx = canvas.getContext( "2d" );
    ctx.fillStyle = "red";
    ctx.fillRect( 20, 20, 260, 110 );
    
    // convert to Blob (async)
    canvas.toBlob( (blob) => {
      const file = new File( [ blob ], "mycanvas.png" );
      const dT = new DataTransfer();
      dT.items.add( file );
      document.querySelector( "input" ).files = dT.files;
    } );
    
    // to prove the image is there
    document.querySelector( "#test" ).onclick = (evt) => {
      const file = document.querySelector( "input" ).files[ 0 ];
      document.body.appendChild( new Image() )
        .src = URL.createObjectURL( file );
    };
    <form method="POST">
      <input type="file" name="file"><br>
      <button>submit</button> (check your dev tools network panel to see the File is sent)
    </form>
    <br>
    <button id="test">
      load input's content as image
    </button>