it-swarm.com.de

Wie speichere ich einen HTML5 Canvas als Bild auf einem Server?

Ich arbeite an einem generativen Kunstprojekt, in dem ich Benutzern erlauben möchte, die resultierenden Bilder von einem Algorithmus zu speichern. Die allgemeine Idee ist:

  • Erstellen Sie ein Bild auf einem HTML5-Canvas mit einem generativen Algorithmus
  • Wenn das Bild fertig ist, können Benutzer die Zeichenfläche als Bilddatei auf dem Server speichern
  • Ermöglichen Sie dem Benutzer, das Bild entweder herunterzuladen oder es einer Galerie von Stücken hinzuzufügen, die mit dem Algorithmus erstellt wurden.

Ich stecke jedoch beim zweiten Schritt fest. Nach etwas Hilfe von Google fand ich diesen Blog-Beitrag , der genau das zu sein schien, was ich wollte:

Was zum JavaScript-Code geführt hat:

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

und entsprechendes 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);
}
?>

Dies scheint jedoch überhaupt nichts zu bewirken.

Weiteres Googeln taucht in diesem Blog-Beitrag auf, der auf dem vorherigen Tutorial basiert. Nicht sehr unterschiedlich, aber vielleicht einen Versuch wert:

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

file_put_contents($file, base64_decode($uri));
echo $file;

Dieser erstellt eine Datei (yay), die jedoch beschädigt ist und anscheinend nichts enthält. Es scheint auch leer zu sein (Dateigröße 0).

Gibt es wirklich etwas, was ich falsch mache? Der Pfad, in dem ich meine Datei speichere, ist beschreibbar. Dies ist also kein Problem, aber es scheint nichts zu passieren, und ich bin nicht sicher, wie ich das debuggen soll.

Bearbeiten

Aufgrund des Links von Salvidor Dalí habe ich die AJAX Anfrage geändert:

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

Und jetzt wird die Bilddatei erstellt und ist nicht leer! Es scheint so, als ob der Inhaltstyp eine Rolle spielt und das Ändern in x-www-form-urlencoded das Senden der Bilddaten ermöglichte.

Die Konsole gibt die (ziemlich große) Zeichenfolge von base64-Code zurück und die Datendatei ist ~ 140 kB groß. Ich kann es jedoch immer noch nicht öffnen und es scheint nicht als Bild formatiert zu sein.

232

Hier ist ein Beispiel, wie Sie das erreichen, was Sie brauchen:

1) Zeichne etwas (entnommen aus Canvas Tutorial )

<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) Leinwandbild in URL-Format konvertieren (base64)

var dataURL = canvas.toDataURL();

3) Sende es über Ajax an deinen Server

$.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) Speichern Sie base64 auf Ihrem Server als Bild (hier ist , wie dies in PHP gemacht wird, Die gleichen Ideen gibt es in jeder Sprache. Die Serverseite in PHP kann hier gefunden werden ):

224
Salvador Dali

Ich habe damit vor zwei Wochen gespielt, es ist sehr einfach. Das einzige Problem ist, dass in allen Tutorials nur über das lokale Speichern des Bildes gesprochen wird. So habe ich es gemacht:

1) Ich habe ein Formular eingerichtet, damit ich eine POST -Methode verwenden kann.

2) Wenn der Benutzer mit dem Zeichnen fertig ist, kann er auf die Schaltfläche "Speichern" klicken.

3) Wenn die Schaltfläche angeklickt wird, nehme ich die Bilddaten und lege sie in ein verstecktes Feld. Danach reiche ich das Formular ein.

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

4) Wenn das Formular eingereicht wird, habe ich dieses kleine PHP-Skript:

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

Ich denke, Sie sollten das Image in Base64 auf das Image mit Blob übertragen, da bei Verwendung von Base64-Image viele Protokollzeilen erforderlich sind oder viele Zeilen an den Server gesendet werden. Mit blob gibt es nur die datei. Sie können diesen Code unten verwenden:

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

Und Canvas-Code hier:

canvas = document.getElementById('canvas')
file = dataURLtoBlob(canvas.toDataURL())

Danach können Sie Ajax mit Form verwenden:

  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

Dieser Code verwendet die CoffeeScript-Syntax.

wenn Sie Javascript verwenden möchten, fügen Sie den Code bitte in http://js2.coffee ein

13
ThienSuBS

Leinwandbild an PHP senden:

var photo = canvas.toDataURL('image/jpeg');                
$.ajax({
  method: 'POST',
  url: 'photo_upload.php',
  data: {
    photo: photo
  }
});

Hier ist das PHP Skript:
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;
?>
10

Wenn Sie Daten speichern möchten, die von einer Javascript canvas.toDataURL() -Funktion abgeleitet sind, müssen Sie Leerzeichen in Plusses konvertieren. Wenn Sie das nicht tun, sind die dekodierten Daten beschädigt:

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

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

7
MaloMax

Zusätzlich zu Salvador Dalis Antwort:

auf der Serverseite vergessen Sie nicht, dass die Daten im base64 string Format vorliegen. Dies ist wichtig, da Sie in einigen Programmiersprachen explizit angeben müssen, dass diese Zeichenfolge als Bytes nicht als einfache Unicode-Zeichenfolge betrachtet werden soll.

Andernfalls funktioniert die Dekodierung nicht: Das Bild wird gespeichert, es handelt sich jedoch um eine nicht lesbare Datei.

4
Ardine

Ich habe an etwas Ähnlichem gearbeitet. Musste canvas Base64-codiert image in Uint8Array Blob konvertieren.

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
Joseph D.