एक सर्वर पर एक छवि के रूप में एचटीएमएल 5 कैनवस को कैसे बचाया जाए?


260

मैं एक जेनरिक आर्ट प्रोजेक्ट पर काम कर रहा हूँ जहाँ मैं उपयोगकर्ताओं को एल्गोरिदम से परिणामी छवियों को सहेजने की अनुमति देना चाहूँगा। सामान्य विचार है:

  • एक जेनरेटर एल्गोरिथ्म का उपयोग करके HTML5 कैनवस पर एक छवि बनाएं
  • जब छवि पूरी हो जाती है, तो उपयोगकर्ताओं को सर्वर पर छवि फ़ाइल के रूप में कैनवास को बचाने की अनुमति दें
  • उपयोगकर्ता को छवि को डाउनलोड करने की अनुमति दें या एल्गोरिथ्म का उपयोग करके उत्पादित टुकड़ों के गैलरी में जोड़ें।

हालाँकि, मैं दूसरे कदम पर अटक गया हूँ। Google की कुछ मदद के बाद, मुझे यह ब्लॉग पोस्ट मिला , जो मुझे ठीक वही लग रहा था जो मैं चाहता था:

जिसके कारण जावास्क्रिप्ट कोड:

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से छवि डेटा भेजने की अनुमति मिलती है।

कंसोल बेस 64 कोड का (बल्कि बड़ा) स्ट्रिंग लौटाता है और डेटाफाइल ~ 140 kB है। हालाँकि, मैं अभी भी इसे नहीं खोल सकता हूँ और यह एक छवि के रूप में स्वरूपित नहीं किया जा रहा है।


ajax.send(canvasData );जब आप इसका उपयोग करते हैं तो पहला ब्लॉग आपके द्वारा प्रदान किए गए उपयोगों को पोस्ट करता है ajax.send("imgData="+canvasData);। इसलिए $GLOBALS["HTTP_RAW_POST_DATA"]वह नहीं होगा जो आप उम्मीद करते हैं, आपको शायद उपयोग करना चाहिए $_POST['imgData']
मैटियस हेमस्ट्रॉम


डायोडस: मैं पहले से ही उस धागे में सुझाई गई तकनीक का उपयोग कर रहा हूं; हालाँकि, वे कार्यान्वयन के बारे में कोई और विवरण देने में असफल रहे और यही वह जगह है जहाँ मैं फंस रहा हूँ।
नथन लाचेनमीयर

जब मैं फ़ाइल जानकारी ( $dataदूसरे php कोड में) गूँजता हूँ तो मुझे जो भी मिलता है वह एक खाली लाइन है। ऐसा क्यों होगा? ऐसा लगता है कि शायद भेजा जा रहा डेटा सही नहीं है, लेकिन ऐसा लगता है कि मैं इसे उदाहरण के शो की तरह भेज रहा हूं ...
nathan lachenmyer

इसके बजाय इसके घटक के साथ PHP-FileUpload का उपयोग करके PHP कोड को सरल और अधिक मजबूत बनाया जा सकता है 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 प्रारूप (बेस 64) में बदलें

var dataURL = canvas.toDataURL();

3) इसे अजाक्स के माध्यम से अपने सर्वर पर भेजें

$.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) एक छवि के रूप में अपने सर्वर पर बेस 64 को सहेजें (यहां PHP में यह कैसे करना है , यही विचार हर भाषा में है। PHP में सर्वर साइड यहां पाया जा सकता है ):


1
मेरा मतलब है कि फ़ाइल वहाँ है, लेकिन अगर मैं इसे डाउनलोड करता हूं तो यह मेरे ब्राउज़र या किसी भी छवि दर्शक में नहीं खुलती है।
नथन लाचेनमीयर

You send it to your server as an ajax requestक्या इस विधि के लिए उपयोगकर्ता की पुष्टि की आवश्यकता है? या मैं चुपचाप कैनवास से सर्वर पर छवि भेज सकता हूं?
MyTitle

मुझे वेब कंसोल पर एक त्रुटि मिलती है। [१६: ५३: ४३.२२ 43] सुरक्षा सुरक्षा: ऑपरेशन असुरक्षित है। @ sharevi.com/staging/canvas.html:43 यह कनेक्शन असुरक्षित है। क्या ऐसा कुछ है जिसे करने की आवश्यकता है? /// अद्यतन मुझे लगता है कि मुझे पता है क्यों, मैं क्रॉस डोमेन छवियों का उपयोग कर रहा था
Nikolaos Vassos

1
लेकिन अल्फा 0 है जो इसे नो-फिल बनाता है, जो पूरी तरह से पारदर्शी है। कोई फर्क नहीं पड़ता कि पहले तीन मूल्य क्या है।
एबेल डी

68

मैंने इसके साथ दो सप्ताह पहले खेला था, यह बहुत सरल है। एकमात्र समस्या यह है कि सभी ट्यूटोरियल केवल स्थानीय रूप से छवि को बचाने के बारे में बात करते हैं। मैंने इस तरह से इसे किया:

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
क्या यह ठीक है अगर मैं कैनवास का उपयोग करता हूं ।toDataURL ()? मेरे पास डायनामिक फ़ाइल एक्सटेंशन है, जैसे jpeg, png, gif। मैंने कैनवास की कोशिश की ।toDataURL ('छवि / jpg') लेकिन यह काम नहीं कर रहा है। क्या गलत है?
इवो ​​सैन

मैं AJAX द्वारा कैनवास से छवि भेजने की कोशिश में 413 (बहुत बड़ी अनुरोध) त्रुटि प्राप्त कर रहा था। तब इस दृष्टिकोण ने मुझे छवियों को प्राप्त करने में मदद की।
रायन

1
किसी भी कारण से यह मुझे 0kb png फ़ाइल दे रहा है?
प्रिज्मपेकस

3
Jpg के लिए आपको कैनवास करना होगा ।toDataURL ('image / jpeg') - कम से कम मैंने इसे Chrome के लिए क्या किया है।
क्रिस

धन्यवाद, मुझे यही चाहिए: D
FosAvance

21

मुझे लगता है कि आपको बेस 64 में छवि को ब्लॉब के साथ बदल देना चाहिए, क्योंकि जब आप बेस 64 इमेज का उपयोग करते हैं, तो यह बहुत सारी लॉग लाइन लेता है या बहुत सी लाइन सर्वर को भेजेगा। बूँद के साथ, यह केवल फ़ाइल है। आप इस कोड का उपयोग कर सकते हैं:

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

कॉफी कोड सिंटैक्स का उपयोग कर यह कोड।

यदि आप जावास्क्रिप्ट का उपयोग करना चाहते हैं, तो कृपया कोड को http://js2.cfish पर चिपकाएँ


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

यदि आप जावास्क्रिप्ट canvas.toDataURL()फ़ंक्शन से प्राप्त डेटा को सहेजना चाहते हैं , तो आपको रिक्त स्थान को प्लेसेस में बदलना होगा। यदि आप ऐसा नहीं करते हैं, तो डीकोड किया गया डेटा दूषित है:

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

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


7

मैंने कुछ इसी तरह काम किया है। कैनवास को बेस 64-एनकोडेड छवि में बदलना था 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

सल्वाडोर डाली के जवाब के अलावा:

सर्वर की ओर से यह मत भूलो कि डेटा बेस 64 स्ट्रिंग प्रारूप में आता है । यह महत्वपूर्ण है क्योंकि कुछ प्रोग्रामिंग भाषाओं में आपको यह कहने की आवश्यकता है कि इस स्ट्रिंग को बाइट्स के रूप में माना जाना चाहिए न कि यूनिकोड स्ट्रिंग।

अन्यथा डिकोडिंग काम नहीं करेगी: छवि सहेज ली जाएगी लेकिन यह एक अपठनीय फ़ाइल होगी।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.