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

사용자가 알고리즘에서 결과 이미지를 저장할 수 있도록하는 생성 아트 프로젝트를 진행 중입니다. 일반적인 아이디어는 다음과 같습니다.

  • 생성 알고리즘을 사용하여 HTML5 Canvas에서 이미지 만들기
  • 이미지가 완료되면 사용자가 캔버스를 이미지 파일로 서버에 저장하도록 허용
  • 사용자가 이미지를 다운로드하거나 알고리즘을 사용하여 제작 된 갤러리에 이미지를 추가 할 수 있습니다.

그러나 나는 두 번째 단계에 붙어 있습니다. Google의 도움을 받아이 블로그 게시물을 찾았 습니다.

이것은 JavaScript 코드로 이어졌습니다.

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;

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

내가 잘못하고 있다는 것이 분명합니까? 내 파일을 저장하는 경로는 쓰기 가능하므로 문제가되지 않지만 아무 일도 일어나지 않는 것으로 보이며 실제로 이것을 디버깅하는 방법을 잘 모르겠습니다.

편집하다

Salvidor 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 코드의 문자열을 반환하고 데이터 파일은 ~ 140 kB입니다. 그러나 여전히 열 수 없으며 이미지로 형식화되지 않은 것 같습니다.



답변

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

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 주 전에이 게임을했는데 매우 간단합니다. 유일한 문제는 모든 튜토리얼이 이미지를 로컬에 저장하는 것에 대해 이야기한다는 것입니다. 이것이 내가 한 방법입니다.

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


답변

base64 이미지를 사용할 때 많은 로그 행이 필요하거나 많은 행이 서버로 전송되기 때문에 base64의 이미지를 blob이있는 이미지로 변환해야한다고 생각합니다. Blob에서는 파일 만 있습니다. 이 코드를 다음과 같이 사용할 수 있습니다.

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

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

  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 구문을 사용합니다.

자바 스크립트를 사용하려면 코드를 http://js2.coffee에 붙여 넣으십시오.


답변

캔버스 이미지를 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;
?>


답변

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

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

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


답변

나는 비슷한 일을 해왔다. 캔버스 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);


답변

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

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

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