2

I have extracted data from a database to create an HTML table which I want to be able to save as a PNG on the server.

When I save the PNG to the server using PHP, it is blank.

I have created static code (i.e. not from database) to illustrate my example.

If I manually right click on the image, and SAVE AS then the image is saved correctly, it is only when I try to automate it that the image is blank. I have tried in both Chrome and Firefox, both with the same results.

If anyone can help me correct whatever I am doing wrong, I would be grateful. Thank you.

I am using:

  • PHP 7.3.4
  • jQuery 3.4.1
  • Chrome 76.0.3809.100
  • Firefox 68.01

index.php

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <script src="jquery-3.4.1.min.js" type="text/javascript"></script>
</head>

<body>
    <div id="invoicetable">
        <div xmlns="http://www.w3.org/1999/xhtml">
            <style>
        body        {font-family: courier new; font-size: 13px; }
        td      {padding: 2px 5px 2px 5px; }
        .headerTD   {font-weight: bold; }
        .w60        {width: 60px; }
        .w80        {width: 80px; }
        .w100       {width: 100px; }
        .w120       {width: 120px; }
        .w160       {width: 160px; }
            </style>

<table class='' border='01' style='border-collapse: collapse; font-size: 14px; font-family: trebuchet ms; '><tr><td class='headerTD w100'>Date</td><td class='headerTD w60'>Type</td><td class='headerTD w160'>Detail</td><td class='headerTD w120'>Username</td><td class='headerTD w100'>Line</td><td class='headerTD w100'>Start Date</td><td class='headerTD w100'>End Date</td><td class='headerTD w80'>Subtotal</td></tr><tr><td>23/07/2019</td><td>Credit</td><td>Business Fibre 1</td><td>abc@def.com</td><td>011122223333</td><td>23/07/2019</td><td>21/08/2019</td><td>&pound; <div style='float: right'>-7.74</div></td></tr><tr><td>04/08/2019</td><td>Charge</td><td>Business Fibre 1</td><td>ghi@jkl.com</td><td>01234567890</td><td>04/08/2019</td><td>03/09/2019</td><td>&pound; <div style='float: right'>22.50</div></td></tr><tr><td>04/08/2019</td><td>Charge</td><td>Line Rental</td><td></td><td>01234567890</td><td>04/08/2019</td><td>03/09/2019</td><td>&pound; <div style='float: right'>15.66</div></td></tr><tr><td>04/08/2019</td><td>Charge</td><td>Line Rental</td><td></td><td>01234567890</td><td>04/07/2019</td><td>03/08/2019</td><td>&pound; <div style='float: right'>0.00</div></td></tr><tr><td colspan='7'></td><td>&pound; <div style='float: right'>30.42</div></td></tr></table>

        </div>
    </div>
    <br>
    <br>

    <canvas id="canvas" width="930" height="150"></canvas>

    <script>
        $(function() {
            var canvas = document.getElementById("canvas");
            var ctx = canvas.getContext("2d");
            var imgW = 930;
            var imgH = 150;
            ctx.fillStyle = "white";
            ctx.fillRect(0, 0, imgW, imgH);

            var data = "<svg xmlns='http://www.w3.org/2000/svg' width='" + imgW + "' height='" + imgH + "'>" + "<foreignObject width='100%' height='100%'>" + $("#invoicetable").html() + "</foreignObject>" + "</svg>";
            var DOMURL = self.URL || self.webkitURL || self;
            var img = new Image();
            var svg = new Blob([data], {
                type: "image/svg+xml;charset=utf-8"
            });
            var url = DOMURL.createObjectURL(svg);
            img.onload = function() {
                ctx.drawImage(img, 0, 0);
                DOMURL.revokeObjectURL(url);
            };
            img.src = url;

            var canvas = document.getElementById("canvas");
            var pngData = canvas.toDataURL("image/png");
            $.post("savepng.php", {
                pngData: pngData
            }, function(data) {});

        });
    </script>
</body>

</html>


savepng.php

<?php
$aaa = explode(",", $_POST['pngData']);
file_put_contents("invoicedata.png", base64_decode($aaa[1]));
?>

This is the expected image output:
The expected image output

gre_gor
  • 6,669
  • 9
  • 47
  • 52

1 Answers1

2

Your code has three problems:

  1. You are trying to save the image before you even draw your SVG image onto the canvas.
    Save the image inside the onload callback.

  2. Seems you took the code from this question without fixing the problem, so you get an error about a tainted canvas when you call toDataURL.

  3. There seems to be a problem rendering the pound sign, if you use the fix from the previous problem. This seem to be a problem with the encoding and the fix is here.

To fix those issues use this code:

var img = new Image();
img.onload = function() {
    ctx.drawImage(img, 0, 0);

    var canvas = document.getElementById("canvas");
    var pngData = canvas.toDataURL("image/png");
    $.post("savepng.php", {
        pngData: pngData
    }, function(data) {});
};
function buildSvgImageUrl(svg) {
    var b64 = window.btoa(unescape(encodeURIComponent(svg)));
    return "data:image/svg+xml;base64," + b64;
}
img.src = buildSvgImageUrl(data);
gre_gor
  • 6,669
  • 9
  • 47
  • 52