1

I'm struggling with saving my canvas image to server using JavaScript and PHP. I've tried multiple examples for both JS and PHP and it always fails. There's conflicting advice on how to send image data to PHP script (base64, blob, FormData) and I'm not sure how best to communicate back to JS. Currently, zero bytes PNG files are being saved to server and I'm not sure why. I'd like to save generated canvas as a PNG on server and execute a command in JS on success. How best to approach it?

JS:

var off_canvas = document.createElement('canvas');
off_canvas.width = 1080;
off_canvas.height= 1080;
var ctx = off_canvas.getContext("2d");
var brick = new Image();
brick.src = '../img/brick-white.jpg'; 
brick.onload = function(){
    var pattern = ctx.createPattern(this, "repeat");
    ctx.fillStyle = pattern;
    ctx.fill();
};
var base64img = off_canvas.toDataURL("image/jpeg");

fetch("../php/save_image.php", {
    method: "POST",
    image: base64img
})  .then(response => response.text())
    .then(success => console.log(success)) //execute command
    .catch(error => console.log(error));

PHP:

<?php
    $img = $_POST['image'];
    $img = str_replace('data:image/png;base64,', '', $img);
    $img = str_replace(' ', '+', $img);
    $data = base64_decode($img);
    
    if (!file_exists($_SERVER['DOCUMENT_ROOT'] . "/img")) {
        mkdir($_SERVER['DOCUMENT_ROOT'] . "/img", 0777, true);
    }
    
    $file = $_SERVER['DOCUMENT_ROOT'] . "/img/".time().'.png';
    
    $success = file_put_contents($file, $data);
    print $success ? $file.' saved.' : 'Unable to save the file.';
?>
ALx
  • 611
  • 9
  • 24
  • This [GeeksForGeeks](https://www.geeksforgeeks.org/how-to-save-an-html-5-canvas-as-an-image-on-the-server/) article seems to explain the process clearly. (This [older SO question](https://stackoverflow.com/questions/19032406/convert-html5-canvas-into-file-to-be-uploaded), and the "canvas project" chapter of [Eloquent JavaScript](https://eloquentjavascript.net/19_paint.html#h_7eec4RKHJi) might also interest you.) – Cat May 04 '21 at 09:43

2 Answers2

1

After some fiddling with multiple options on both JS and PHP, this is what finally worked:

JS

var off_canvas = document.createElement('canvas');
off_canvas.width = 1080;
off_canvas.height = 1080;
var off_ctx = off_canvas.getContext("2d");

off_ctx.beginPath();
off_ctx.rect(20, 20, 150, 800);
off_ctx.fillStyle = "red";
off_ctx.fill();

var brick = new Image();
brick.src =  "img/brick-white.jpg";
brick.onload = function(){
    var pattern = off_ctx.createPattern(brick, "repeat");
    off_ctx.fillStyle = pattern;
    off_ctx.fillRect(500, 0, 1000, 1000);
    
    // needs delay to fully render to canvas
    var timer = window.setTimeout(save_canvas(off_canvas), 500);
};

function save_canvas(c) {
    var b64Image = c.toDataURL("image/png");
    
    fetch("../php/save_image_b64.php", {
        method: "POST",
        mode: "no-cors",
        headers: {"Content-Type": "application/x-www-form-urlencoded"},
        body: b64Image
    })  .then(response => response.text())
        .then(success => console.log(success))
        .catch(error => console.log(error));
}

PHP

<?php
    $img = file_get_contents("php://input"); // $_POST didn't work
    $img = str_replace('data:image/png;base64,', '', $img);
    $img = str_replace(' ', '+', $img);
    $data = base64_decode($img);
    
    if (!file_exists($_SERVER['DOCUMENT_ROOT'] . "/img")) {
        mkdir($_SERVER['DOCUMENT_ROOT'] . "/img", 0777, true);
    }
    
    $file = $_SERVER['DOCUMENT_ROOT'] . "/img/".time().'.png';
    
    $success = file_put_contents($file, $data);
    print $success ? $file.' saved.' : 'Unable to save the file.';
?>
ALx
  • 611
  • 9
  • 24
0

in your js page add console.log(base64img);

in your browser console, copy object. i use firefox, if you use something else, then from there copy console message.

the message will be data:image/jpeg;base64,/9j/4AAQSk......

in your php page;

$img = "data:image/jpeg;base64,/9j/4AAQSk.....";
echo "<img src='$data' />"; exit;

now you will know the image is coming or not.

if image is not showing you are not implementing the fetch method correctly

if image is showing, see if you are able to create dir/file. that is, apache has permission to create dir/file. if you are able

csaw
  • 172
  • 11
  • Thank you. I've put the base64 string to PHP script and it saved the image, so it means `fetch` is not sending it properly (and/or PHP receiving it). Not sure how to debug it further. – ALx May 04 '21 at 10:20