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


260

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

  • 생성 알고리즘을 사용하여 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입니다. 그러나 여전히 열 수 없으며 이미지로 형식화되지 않은 것 같습니다.


귀하가 제공 한 ajax.send(canvasData );것과 같은 첫 번째 블로그 게시물 ajax.send("imgData="+canvasData);입니다. 따라서 $GLOBALS["HTTP_RAW_POST_DATA"]당신이 기대하는 것이 아닐 것 $_POST['imgData']입니다.
Matteus Hemström


Diodeus : 나는 이미 그 스레드에서 제안 된 기술을 사용하고 있습니다; 그러나 그들은 구현에 대한 추가 세부 정보를 제공하지 못했고 그 시점에서 문제가 발생했습니다.
nathan lachenmyer

파일 정보 ( $data두 번째 PHP 코드에서)를 반향하면 빈 줄만 반환됩니다. 왜 그런가요? 아마도 데이터가 전송되는 경우에하는 것은 정확하지 않은 것처럼 보인다, 그러나 나는 ... 예를 보여처럼 그것을 보내고있다 나타납니다
나단 lachenmyer

PHP 코드는 구성 요소 와 함께 PHP-FileUpload 를 사용하여 단순화되고 더욱 강력해질 수 있습니다 DataUriUpload. 여기에 문서화되어 있으며 유효성을 검사하고 보안을 강화하는 몇 가지 추가 수단이 제공됩니다.
caw

답변:


241

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

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의 서버 측은 여기에서 찾을 수 있습니다 ).


1
파일이 있지만 다운로드하면 브라우저 또는 이미지 뷰어에서 열리지 않습니다.
nathan lachenmyer

You send it to your server as an ajax request이 방법은 사용자의 확인이 필요합니까? 아니면 캔버스에서 서버로 이미지를 자동으로 보낼 수 있습니까?
MyTitle

웹 콘솔에 오류가 있습니다. [16 : 53 : 43.227] SecurityError : 작업이 안전하지 않습니다. @ sharevi.com/staging/canvas.html:43 the이 연결은 안전하지 않습니다. 해야 할 일이 있습니까? /// 업데이트 도메인 간 이미지를 사용하고있는 이유를 알고 있다고 생각합니다.
Nikolaos Vassos

1
그러나 알파는 0으로 채워 지므로 완전히 투명합니다. 처음 세 값이 무엇이든 상관 없습니다.
Abel D

68

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

1
canvas.toDataURL ()을 사용하면 괜찮습니까? jpeg, png, gif와 같은 동적 파일 확장자가 있습니다. canvas.toDataURL ( 'image / jpg')을 시도했지만 작동하지 않습니다. 뭐가 문제 야?
Ivo San

AJAX가 캔버스에서 이미지를 보내려고 할 때 413 (요청이 너무 큼) 오류가 발생했습니다. 그런 다음이 접근법은 이미지를 얻는 데 도움이되었습니다.
Raiyan

1
이것이 0kb png 파일을주는 이유는 무엇입니까?
prismspecs

3
jpg의 경우 canvas.toDataURL ( 'image / jpeg') 을 수행해야합니다 . 적어도 Chrome에서 저에게 도움이 된 것입니다.
Chris

고마워, 그것이 내가 필요한 것 : D
FosAvance

21

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에 붙여 넣으십시오.


12

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

9

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

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

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


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

4

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

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

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.