복붙노트

HTML5 Canvas를 서버에 이미지로 저장하는 방법은 무엇입니까?

PHP

HTML5 Canvas를 서버에 이미지로 저장하는 방법은 무엇입니까?

나는 사용자가 알고리즘의 결과 이미지를 저장할 수있게 해주는 생성 예술 프로젝트에서 일하고있다. 일반적인 아이디어는 다음과 같습니다.

그러나 나는 두 번째 단계에 머물러있다. Google의 도움을 받아서이 블로그 게시물을 발견했습니다.이 게시물은 내가 원했던 것 같습니다.

자바 스크립트 코드가 생성되었습니다.

function saveImage() {
  var canvasData = canvas.toDataURL("image/png");
  var ajax = new XMLHttpRequest();

  ajax.open("POST", "testSave.php", false);
  ajax.onreadystatechange = function() {
    console.log(ajax.responseText);
  }
  ajax.setRequestHeader("Content-Type", "application/upload");
  ajax.send("imgData=" + canvasData);
}

해당 PHP (testSave.php) :

<?php
if (isset($GLOBALS["HTTP_RAW_POST_DATA"])) {
  $imageData = $GLOBALS['HTTP_RAW_POST_DATA'];
  $filteredData = substr($imageData, strpos($imageData, ",") + 1);
  $unencodedData = base64_decode($filteredData);
  $fp = fopen('/path/to/file.png', 'wb');

  fwrite($fp, $unencodedData);
  fclose($fp);
}
?>

그러나 이것은 전혀 아무것도하지 않는 것처럼 보입니다.

더 많은 인터넷 검색은 이전 자습서에 기반한이 블로그 게시물을 나타냅니다. 매우 다르지는 않지만 아마도 시도할만한 가치가 있습니다.

$data = $_POST['imgData'];
$file = "/path/to/file.png";
$uri = substr($data,strpos($data, ",") + 1);

file_put_contents($file, base64_decode($uri));
echo $file;

이 파일은 (예) 파일을 생성하지만 손상되어 아무 것도 포함하지 않는 것 같습니다. 또한 비어 있습니다 (파일 크기가 0).

내가 잘못하고있는 것이 정말 명백한가요? 내 파일을 저장하는 경로는 쓰기 가능하므로 문제는 아니지만 아무 일도 일어나지 않는 것 같아서 이것을 디버깅하는 방법을 모르겠습니다.

Salvador Dali의 링크를 따라 AJAX 요청을 다음과 같이 변경합니다.

function saveImage() {
  var canvasData = canvas.toDataURL("image/png");
  var xmlHttpReq = false;

  if (window.XMLHttpRequest) {
    ajax = new XMLHttpRequest();
  }
  else if (window.ActiveXObject) {
    ajax = new ActiveXObject("Microsoft.XMLHTTP");
  }

  ajax.open("POST", "testSave.php", false);
  ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  ajax.onreadystatechange = function() {
    console.log(ajax.responseText);
  }
  ajax.send("imgData=" + canvasData);
}

이제 이미지 파일이 생성되고 비어 있지 않습니다! 콘텐츠 유형이 중요하고 x-www-form-urlencoded로 변경하면 이미지 데이터를 보낼 수있는 것처럼 보입니다.

콘솔은 base64 코드의 (다소 큰) 문자열을 반환하고 데이터 파일은 ~ 140kB입니다. 그러나 여전히 열 수 없으며 이미지 형식으로 표시되지 않는 것으로 보입니다.

해결법

  1. ==============================

    1.

    다음은 필요한 것을 달성하는 방법의 예입니다.

    1) 무언가 그리기 (캔버스 튜토리얼에서 가져옴)

    <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>
    

    2) 캔버스 이미지를 URL 형식으로 변환 (base64)

    var dataURL = canvas.toDataURL();
    

    3) 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.
    });
    

    3) Base64를 이미지로 서버에 저장하십시오 (PHP에서이 작업을 수행하는 방법은 모든 언어에서 같은 아이디어입니다). PHP의 서버 측은 여기에서 찾을 수 있습니다.

  2. ==============================

    2.

    나는 2 주 전에 이걸 가지고 놀았습니다. 아주 간단합니다. 유일한 문제는 모든 자습서가 이미지를 로컬에 저장하는 것에 관한 것입니다. 이것이 내가 그랬던 방법이다 :

    1) POST 메서드를 사용할 수 있도록 양식을 설정했습니다.

    2) 그리기가 끝나면 "저장"버튼을 클릭 할 수 있습니다.

    3) 버튼을 클릭하면 이미지 데이터를 가져 와서 숨겨진 필드에 넣습니다. 그 후 양식을 제출합니다.

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

    4) 양식이 제출되면 나는이 작은 PHP 스크립트가 :

    <?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']);
    ?>
    
  3. ==============================

    3.

    Base64 이미지를 BLOB로 이미지를 전송해야한다고 생각합니다. 왜냐하면 base64 이미지를 사용하면 많은 로그 라인이 필요하거나 많은 라인이 서버로 전송되기 때문입니다. 방울이 있으면 파일 만 나타납니다. 이 코드는 다음과 같이 사용할 수 있습니다.

    dataURLtoBlob = (dataURL) ->
      # Decode the dataURL
      binary = atob(dataURL.split(',')[1])
      # Create 8-bit unsigned array
      array = []
      i = 0
      while i < binary.length
        array.push binary.charCodeAt(i)
        i++
      # Return our Blob object
    new Blob([ new Uint8Array(array) ], type: 'image/png')
    

    캔버스 코드는 여기에 있습니다.

    canvas = document.getElementById('canvas')
    file = dataURLtoBlob(canvas.toDataURL())
    

    그 후 ajax를 Form과 함께 사용할 수 있습니다.

      fd = new FormData
      # Append our Canvas image file to the form data
      fd.append 'image', file
      $.ajax
        type: 'POST'
        url: '/url-to-save'
        data: fd
        processData: false
        contentType: false
    

    이 코드는 CoffeeScript 구문을 사용합니다.

  4. ==============================

    4.

    Javascript canvas.toDataURL () 함수에서 파생 된 데이터를 저장하려면 공백을 pluss로 변환해야합니다. 그렇게하지 않으면 디코딩 된 데이터가 손상됩니다.

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

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

  5. ==============================

    5.

    살바도르 달리의 대답 외에도 :

    서버 측에서는 데이터가 base64 문자열 형식으로 제공된다는 사실을 잊지 마십시오. 어떤 프로그래밍 언어에서는이 문자열을 단순한 유니 코드 문자열이 아닌 바이트로 간주해야한다고 분명히 말하기 때문에 중요합니다.

    그렇지 않으면 디코딩이 작동하지 않습니다. 이미지는 저장되지만 읽을 수없는 파일이됩니다.

  6. ==============================

    6.

    캔버스 이미지를 PHP로 보내기 :

    var photo = canvas.toDataURL('image/jpeg');                
    $.ajax({
      method: 'POST',
      url: 'photo_upload.php',
      data: {
        photo: photo
      }
    });
    

    PHP 스크립트는 다음과 같습니다. photo_upload.php

    <?php
    
        $data = $_POST['photo'];
        list($type, $data) = explode(';', $data);
        list(, $data)      = explode(',', $data);
        $data = base64_decode($data);
    
        mkdir($_SERVER['DOCUMENT_ROOT'] . "/photos");
    
        file_put_contents($_SERVER['DOCUMENT_ROOT'] . "/photos/".time().'.png', $data);
        die;
    ?>
    
  7. ==============================

    7.

    비슷한 일을했습니다. 캔버스 Base64로 인코딩 된 이미지를 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);
    
  8. from https://stackoverflow.com/questions/13198131/how-to-save-an-html5-canvas-as-an-image-on-a-server by cc-by-sa and MIT lisence