[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);
?>
답변
나는 비슷한 일을 해왔다. 캔버스 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 문자열 형식으로 제공된다는 것을 잊지 마십시오 . 일부 프로그래밍 언어에서는이 문자열을 바이트 로 간주해야한다고 명시 적으로 말해야하기 때문에 중요 합니다. 단순한 유니 코드 문자열이 아닌 합니다.
그렇지 않으면 디코딩이 작동하지 않습니다. 이미지는 저장되지만 읽을 수없는 파일이됩니다.