如何将HTML5 Canvas作为图像保存在服务器上?

我正在创作一个生成艺术项目,我想让用户从algorithm中保存所得到的图像。 总体思路是:

  • 使用生成algorithm在HTML5 Canvas上创build图像
  • 图像完成后,允许用户将canvas作为图像文件保存到服务器
  • 允许用户下载图像或将其添加到使用algorithm生成的图片库中。

但是,我被困在第二步。 在Google的一些帮助之后,我发现了这个博客post ,这个博客似乎正是我想要的:

这导致了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); } ?> 

但是这似乎并没有做任何事情。

更多谷歌search变成这个博客文章是基于上一个教程。 不是很不一样,但也许值得一试:

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

这个创build一个文件(耶),但它已经损坏,似乎并不包含任何东西。 它也似乎是空的(文件大小为0)。

有没有什么明显的我做错了? 我存储我的文件的path是可写的,所以这不是一个问题,但似乎没有发生,我真的不知道如何debugging这个。

编辑

遵循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); } 

现在图像文件被创build并且不是空的! 看起来内容types似乎很重要,并将其更改为x-www-form-urlencoded允许发送图像数据。

控制台返回(相当大的)base64代码的string,数据文件是〜140 kB。 但是,我仍然无法打开它,它似乎不被格式化为图像。

这里是一个例子如何实现你所需要的:

1) 画一些东西 (取自canvas教程 )

 <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) 将canvas图像转换为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中的服务器端可以在这里find ):

我两周前玩过这个,很简单。 唯一的问题是,所有的教程只是在本地保存图像。 这是我做到的:

1)我设置了一个表单,所以我可以使用POST方法。

2)当用户完成绘图时,可以点击“保存”button。

3)单击button时,将图像数据放入隐藏字段。 之后我提交表格。

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

4)当表单submited我有这个小的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']); ?> 

如果要保存从Javascript canvas.toDataURL()函数派生的数据,则必须将空白转换为加号。 如果你不这样做,解码的数据是损坏的:

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

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

我认为你应该用base64将图像转换为blob图像,因为当你使用base64图像时,需要很多的日志行或者很多行会发送到服务器。 用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代码在这里:

 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语法。

除了萨尔瓦多·达利的回答:

在服务器端不要忘记,数据以base64 string格式。 这很重要,因为在一些编程语言中,你需要明确地说这个string应该被认为是字节而不是简单的Unicodestring。

否则,解码将不起作用:图像将被保存,但它将是一个不可读的文件。

发送canvas图像到PHP:

 var photo = canvas.toDataURL('image/jpeg'); $.ajax({ method: 'POST', url: 'photo_upload.php', data: { photo: photo } }); Here's PHP Script 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; ?>