How to save an HTML5 Canvas as an image on a server?

后端 未结 8 2233
走了就别回头了
走了就别回头了 2020-11-21 23:50

I\'m working on a generative art project where I would like to allow users to save the resulting images from an algorithm. The general idea is:

  • Create an image
相关标签:
8条回答
  • 2020-11-22 00:23

    I played with this two weeks ago, it's very simple. The only problem is that all the tutorials just talk about saving the image locally. This is how I did it:

    1) I set up a form so I can use a POST method.

    2) When the user is done drawing, he can click the "Save" button.

    3) When the button is clicked I take the image data and put it into a hidden field. After that I submit the form.

    document.getElementById('my_hidden').value = canvas.toDataURL('image/png');
    document.forms["form1"].submit();
    

    4) When the form is submited I have this small php script:

    <?php 
    $upload_dir = somehow_get_upload_dir();  //implement this function yourself
    $img = $_POST['my_hidden'];
    $img = str_replace('data:image/png;base64,', '', $img);
    $img = str_replace(' ', '+', $img);
    $data = base64_decode($img);
    $file = $upload_dir."image_name.png";
    $success = file_put_contents($file, $data);
    header('Location: '.$_POST['return_url']);
    ?>
    
    0 讨论(0)
  • 2020-11-22 00:26

    Here is an example of how to achieve what you need:

    1. Draw something (taken from canvas tutorial)

    <canvas id="myCanvas" width="578" height="200"></canvas>
    <script>
      var canvas = document.getElementById('myCanvas');
      var context = canvas.getContext('2d');
    
      // begin custom shape
      context.beginPath();
      context.moveTo(170, 80);
      context.bezierCurveTo(130, 100, 130, 150, 230, 150);
      context.bezierCurveTo(250, 180, 320, 180, 340, 150);
      context.bezierCurveTo(420, 150, 420, 120, 390, 100);
      context.bezierCurveTo(430, 40, 370, 30, 340, 50);
      context.bezierCurveTo(320, 5, 250, 20, 250, 50);
      context.bezierCurveTo(200, 5, 150, 20, 170, 80);
    
      // complete custom shape
      context.closePath();
      context.lineWidth = 5;
      context.fillStyle = '#8ED6FF';
      context.fill();
      context.strokeStyle = 'blue';
      context.stroke();
    </script>

    1. Convert canvas image to URL format (base64)

      var dataURL = canvas.toDataURL();

    2. Send it to your server via Ajax

        $.ajax({
          type: "POST",
          url: "script.php",
          data: { 
             imgBase64: dataURL
          }
        }).done(function(o) {
          console.log('saved'); 
          // If you want the file to be visible in the browser 
          // - please modify the callback in javascript. All you
          // need is to return the url to the file, you just saved 
          // and than put the image in your browser.
        });

    1. Save base64 on your server as an image (here is how to do this in PHP, the same ideas is in every language. Server side in PHP can be found here):
    0 讨论(0)
  • 2020-11-22 00:31

    If you want to save data that is derived from a Javascript canvas.toDataURL() function, you have to convert blanks into plusses. If you do not do that, the decoded data is corrupted:

    <?php
      $encodedData = str_replace(' ','+',$encodedData);
      $decocedData = base64_decode($encodedData);
    ?>
    

    http://php.net/manual/ro/function.base64-decode.php

    0 讨论(0)
  • 2020-11-22 00:31

    I've worked on something similar. Had to convert canvas Base64-encoded image to Uint8Array Blob.

    function b64ToUint8Array(b64Image) {
       var img = atob(b64Image.split(',')[1]);
       var img_buffer = [];
       var i = 0;
       while (i < img.length) {
          img_buffer.push(img.charCodeAt(i));
          i++;
       }
       return new Uint8Array(img_buffer);
    }
    
    var b64Image = canvas.toDataURL('image/jpeg');
    var u8Image  = b64ToUint8Array(b64Image);
    
    var formData = new FormData();
    formData.append("image", new Blob([ u8Image ], {type: "image/jpg"}));
    
    var xhr = new XMLHttpRequest();
    xhr.open("POST", "/api/upload", true);
    xhr.send(formData);
    
    0 讨论(0)
  • 2020-11-22 00:35

    In addition to Salvador Dali's answer:

    on the server side don't forget that the data comes in base64 string format. It's important because in some programming languages you need to explisitely say that this string should be regarded as bytes not simple Unicode string.

    Otherwise decoding won't work: the image will be saved but it will be an unreadable file.

    0 讨论(0)
  • 2020-11-22 00:37

    I just made an imageCrop and Upload feature with

    https://www.npmjs.com/package/react-image-crop

    to get the ImagePreview ( the cropped image rendering in a canvas)

    https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob

    canvas.toBlob(function(blob){...}, 'image/jpeg', 0.95);
    

    I prefer sending data in blob with content type image/jpeg rather than toDataURL ( a huge base64 string`

    My implementation for uploading to Azure Blob using SAS URL

    axios.post(azure_sas_url, image_in_blob, {
       headers: {
          'x-ms-blob-type': 'BlockBlob',
          'Content-Type': 'image/jpeg'
       }
    })
    
    0 讨论(0)
提交回复
热议问题