programing

HTML5 캔버스를 서버에 이미지로 저장하는 방법

kingscode 2022. 10. 29. 10:20
반응형

HTML5 캔버스를 서버에 이미지로 저장하는 방법

저는 사용자가 알고리즘에서 생성된 이미지를 저장할 수 있도록 하는 생성 예술 프로젝트를 진행하고 있습니다.일반적인 생각은 다음과 같습니다.

  • 생성 알고리즘을 사용하여 HTML5 캔버스에 이미지 생성
  • 이미지가 완료되면 캔버스를 이미지 파일로 서버에 저장할 수 있습니다.
  • 사용자가 이미지를 다운로드하거나 알고리즘을 사용하여 생성된 조각 갤러리에 추가할 수 있도록 합니다.

하지만, 저는 두 번째 단계에서 꼼짝할 수 없습니다.구글의 도움을 받은 후, 저는 이 블로그 포스트를 찾았습니다.그게 바로 제가 원하던 것 같았어요.

그 결과 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 코드의 (매우 큰) 문자열을 반환하며 데이터 파일은 약 140kB입니다.하지만 아직 열리지 않고 이미지 포맷이 되지 않은 것 같습니다.

필요한 것을 실현하는 방법의 예를 다음에 나타냅니다.

  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>

  1. 캔버스 이미지를 URL 형식(base64)으로 변환

        // script
    
        var dataURL = canvas.toDataURL();
    
  2. 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.
    });

  1. 서버에 base64를 이미지로 저장합니다(여기는 PHP로 하는 방법이며, 모든 언어에 동일한 아이디어가 있습니다).PHP 의 서버측은, 다음의 URL 에 있습니다.

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로 변환한 후 blob으로 변환하여 서버로 보내야 할 것 같습니다.base64 이미지를 사용하면 많은 회선이 서버로 전송됩니다.BLOB의 경우 파일뿐입니다.

아래 코드를 사용할 수 있습니다.

function dataURLtoBlob(dataURL) {
  let array, binary, i, len;
  binary = atob(dataURL.split(',')[1]);
  array = [];
  i = 0;
  len = binary.length;
  while (i < len) {
    array.push(binary.charCodeAt(i));
    i++;
  }
  return new Blob([new Uint8Array(array)], {
    type: 'image/png'
  });
};

캔버스 코드는 다음과 같습니다.

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

그런 다음 Form과 함께 ajax를 사용할 수 있습니다.

const fd = new FormData;

fd.append('image', file);

$.ajax({
  type: 'POST',
  url: '/url-to-save',
  data: fd,
  processData: false,
  contentType: false
});

커피 스크립트 구문의 코드:

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

캔버스 이미지를 PHP로 보내기:

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

PHP 크음음 php php php php php php php 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;
?>

저도 비슷한 작업을 한 적이 있어요.캔버스 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);

canvas.toDataURL()빈칸을 플러스로 변환해야 합니다.그렇게 하지 않으면 디코딩된 데이터가 손상됩니다.

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

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

Salvador Dali의 답변과 더불어:

데이터가 base64 문자열 형식으로 제공된다는 것을 잊지 마십시오.일부 프로그래밍 언어에서는 이 문자열이 단순한 유니코드 문자열이 아닌 바이트로 간주되어야 한다고 설명해야 하기 때문에 중요합니다.

그렇지 않으면 디코딩이 작동하지 않습니다.이미지는 저장되지만 읽을 수 없는 파일이 됩니다.

방금 imageCrop and Upload 기능을 만들었습니다.

https://www.npmjs.com/package/react-image-crop

ImagePreview(캔버스에서 잘라낸 이미지 렌더링)를 가져오려면

https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob

canvas.toBlob(function(blob){...}, 'image/jpeg', 0.95);

타입이 「BLOB」인합니다.image/jpegtoDataURL

SAS URL을 사용하여 Azure Blob에 업로드하기 위한 구현

axios.post(azure_sas_url, image_in_blob, {
   headers: {
      'x-ms-blob-type': 'BlockBlob',
      'Content-Type': 'image/jpeg'
   }
})

언급URL : https://stackoverflow.com/questions/13198131/how-to-save-an-html5-canvas-as-an-image-on-a-server

반응형