Я работаю над генеративным арт-проектом, где я хотел бы разрешить пользователям сохранять полученные изображения из алгоритма. Общая идея:
Тем не менее, я застрял на втором шаге. После некоторой помощи от 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); } ?>
Но это, похоже, ничего не делает.
Больше Googling превращает это сообщение в блоге , основанное на предыдущем уроке. Не совсем по-другому, но, возможно, стоит попробовать:
$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).
Есть ли что-то действительно очевидное, что я делаю неправильно? Путь, где я храню свой файл, доступен для записи, поэтому это не проблема, но ничего похожего не происходит, и я не уверен, как отлаживать это.
После ссылки Сальвидора Дали я изменил запрос 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 кБ. Тем не менее, я все еще не могу открыть его и, похоже, не отформатирован как изображение.
Вот пример того, как добиться того, что вам нужно:
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) Я создал форму, чтобы использовать метод 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']); ?>
Если вы хотите сохранить данные, полученные из функции canvas.toDataURL()
Javascript, вам нужно преобразовать пробелы в плюсы. Если вы этого не сделаете, декодированные данные будут повреждены:
<?php $encodedData = str_replace(' ','+',$encodedData); $decocedData = base64_decode($encodedData); ?>
Я думаю, вы должны преобразовать изображение в 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 = document.getElementById('canvas') file = dataURLtoBlob(canvas.toDataURL())
После этого вы можете использовать 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.
В дополнение к ответу Сальвадора Дали:
на стороне сервера не забывайте, что данные поступают в формате base64. Это важно, потому что на некоторых языках программирования вам нужно сказать, что эту строку следует считать байтами, а не простой строкой Unicode.
В противном случае декодирование не будет работать: изображение будет сохранено, но это будет нечитаемый файл.
Отправить изображение холста в 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; ?>