Search code examples
phpsvgimagickphp-5.3php-5.6

PHP Imagick breaks SVG on conversion to PNG


I'm updating a super legacy app and I'm trying to move from PHP 5.3 to PHP 5.6. Everything is going smoothly except for Imagick.

On old server we were using Imagick 3.0.0 and now on newer server with PHP 5.6 we tried using Imagick 3.6 and 3.7 but same problem occures. While trying to convert SVG graph to PNG it gets distorted.

Distorted graph

Code used for testing is very simple:

$image = new Imagick();
$svg = 'GENERATED SVG';
$image->readImageBlob('<?xml version="1.0" encoding="UTF-8" standalone="no"?>'.$svg);
$image->setImageFormat('png24');
$image->writeImage('test.png');

I'm quite positive that SVG itself is fine, because I couldn't replicate this outcome on docker machine running similar config (PHP 5.6 and Imagick 3.7). Docker machine managed to covert SVG to PNG no problem. Chrome and other online SVG preview tools display the SVG correctly. enter image description here

My SVG file:

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="2704" height="1330" viewBox="0 0 2704 1330"><rect fill="#FFFFFF" x="0" y="0" width="2704" height="1330"></rect><text transform="rotate(270 35.357142857143,1086.742)" text-anchor="end" x="35.357142857143" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">1</text><text transform="rotate(270 80.357142857143,1086.742)" text-anchor="end" x="80.357142857143" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">10</text><text transform="rotate(270 125.35714285714,1086.742)" text-anchor="end" x="125.35714285714" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">11</text><text transform="rotate(270 170.35714285714,1086.742)" text-anchor="end" x="170.35714285714" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">12</text><text transform="rotate(270 215.35714285714,1086.742)" text-anchor="end" x="215.35714285714" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">13</text><text transform="rotate(270 260.35714285714,1086.742)" text-anchor="end" x="260.35714285714" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">14</text><text transform="rotate(270 305.35714285714,1086.742)" text-anchor="end" x="305.35714285714" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">15</text><text transform="rotate(270 350.35714285714,1086.742)" text-anchor="end" x="350.35714285714" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">16</text><text transform="rotate(270 395.35714285714,1086.742)" text-anchor="end" x="395.35714285714" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">17</text><text transform="rotate(270 440.35714285714,1086.742)" text-anchor="end" x="440.35714285714" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">18</text><text transform="rotate(270 485.35714285714,1086.742)" text-anchor="end" x="485.35714285714" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">2</text><text transform="rotate(270 530.35714285714,1086.742)" text-anchor="end" x="530.35714285714" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">3</text><text transform="rotate(270 575.35714285714,1086.742)" text-anchor="end" x="575.35714285714" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">3</text><text transform="rotate(270 620.35714285714,1086.742)" text-anchor="end" x="620.35714285714" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">4</text><text transform="rotate(270 665.35714285714,1086.742)" text-anchor="end" x="665.35714285714" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">6</text><text transform="rotate(270 710.35714285714,1086.742)" text-anchor="end" x="710.35714285714" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">7</text><text transform="rotate(270 755.35714285714,1086.742)" text-anchor="end" x="755.35714285714" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">8</text><text transform="rotate(270 800.35714285714,1086.742)" text-anchor="end" x="800.35714285714" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">9</text><text transform="rotate(270 845.35714285714,1086.742)" text-anchor="end" x="845.35714285714" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">SEB</text><text transform="rotate(270 890.35714285714,1086.742)" text-anchor="end" x="890.35714285714" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">Swedbank</text><text text-anchor="middle" x="442" y="1326" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">Savaitė</text><text transform="rotate(270 935.35714285714,1086.742)" text-anchor="end" x="935.35714285714" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">1</text><text transform="rotate(270 980.35714285714,1086.742)" text-anchor="end" x="980.35714285714" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">10</text><text transform="rotate(270 1025.3571428571,1086.742)" text-anchor="end" x="1025.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">11</text><text transform="rotate(270 1070.3571428571,1086.742)" text-anchor="end" x="1070.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">12</text><text transform="rotate(270 1115.3571428571,1086.742)" text-anchor="end" x="1115.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">13</text><text transform="rotate(270 1160.3571428571,1086.742)" text-anchor="end" x="1160.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">14</text><text transform="rotate(270 1205.3571428571,1086.742)" text-anchor="end" x="1205.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">15</text><text transform="rotate(270 1250.3571428571,1086.742)" text-anchor="end" x="1250.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">16</text><text transform="rotate(270 1295.3571428571,1086.742)" text-anchor="end" x="1295.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">17</text><text transform="rotate(270 1340.3571428571,1086.742)" text-anchor="end" x="1340.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">18</text><text transform="rotate(270 1385.3571428571,1086.742)" text-anchor="end" x="1385.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">2</text><text transform="rotate(270 1430.3571428571,1086.742)" text-anchor="end" x="1430.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">3</text><text transform="rotate(270 1475.3571428571,1086.742)" text-anchor="end" x="1475.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">3</text><text transform="rotate(270 1520.3571428571,1086.742)" text-anchor="end" x="1520.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">4</text><text transform="rotate(270 1565.3571428571,1086.742)" text-anchor="end" x="1565.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">6</text><text transform="rotate(270 1610.3571428571,1086.742)" text-anchor="end" x="1610.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">7</text><text transform="rotate(270 1655.3571428571,1086.742)" text-anchor="end" x="1655.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">8</text><text transform="rotate(270 1700.3571428571,1086.742)" text-anchor="end" x="1700.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">9</text><text transform="rotate(270 1745.3571428571,1086.742)" text-anchor="end" x="1745.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">SEB</text><text transform="rotate(270 1790.3571428571,1086.742)" text-anchor="end" x="1790.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">Swedbank</text><text text-anchor="middle" x="1342" y="1326" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">Delfi.lt</text><rect fill="#f7911e" x="1805" y="46" width="40" height="1027.742"></rect><text text-anchor="middle" x="1825" y="33" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">1</text><text transform="rotate(270 1835.3571428571,1086.742)" text-anchor="end" x="1835.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">Swedbank</text><text transform="rotate(270 1880.3571428571,1086.742)" text-anchor="end" x="1880.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">1</text><text transform="rotate(270 1925.3571428571,1086.742)" text-anchor="end" x="1925.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">10</text><text transform="rotate(270 1970.3571428571,1086.742)" text-anchor="end" x="1970.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">11</text><text transform="rotate(270 2015.3571428571,1086.742)" text-anchor="end" x="2015.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">12</text><text transform="rotate(270 2060.3571428571,1086.742)" text-anchor="end" x="2060.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">13</text><text transform="rotate(270 2105.3571428571,1086.742)" text-anchor="end" x="2105.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">14</text><text transform="rotate(270 2150.3571428571,1086.742)" text-anchor="end" x="2150.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">15</text><text transform="rotate(270 2195.3571428571,1086.742)" text-anchor="end" x="2195.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">16</text><text transform="rotate(270 2240.3571428571,1086.742)" text-anchor="end" x="2240.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">17</text><text transform="rotate(270 2285.3571428571,1086.742)" text-anchor="end" x="2285.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">18</text><text transform="rotate(270 2330.3571428571,1086.742)" text-anchor="end" x="2330.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">2</text><text transform="rotate(270 2375.3571428571,1086.742)" text-anchor="end" x="2375.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">3</text><text transform="rotate(270 2420.3571428571,1086.742)" text-anchor="end" x="2420.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">3</text><text transform="rotate(270 2465.3571428571,1086.742)" text-anchor="end" x="2465.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">4</text><text transform="rotate(270 2510.3571428571,1086.742)" text-anchor="end" x="2510.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">6</text><text transform="rotate(270 2555.3571428571,1086.742)" text-anchor="end" x="2555.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">7</text><text transform="rotate(270 2600.3571428571,1086.742)" text-anchor="end" x="2600.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">8</text><text transform="rotate(270 2645.3571428571,1086.742)" text-anchor="end" x="2645.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">9</text><text transform="rotate(270 2690.3571428571,1086.742)" text-anchor="end" x="2690.3571428571" y="1086.742" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">SEB</text><text text-anchor="middle" x="2242" y="1326" style="font-family:Verdana;font-size:29px;font-weight:bold;color:#000000;">15min.lt</text><line x1="2" y1="1073.742" x2="2702" y2="1073.742" style="stroke:#333333;stroke-width:1"></line><line x1="2" y1="1073.742" x2="2" y2="1313.5" style="stroke:#333333;stroke-width:1"></line><line x1="49" y1="1073.742" x2="49" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="94" y1="1073.742" x2="94" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="139" y1="1073.742" x2="139" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="184" y1="1073.742" x2="184" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="229" y1="1073.742" x2="229" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="274" y1="1073.742" x2="274" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="319" y1="1073.742" x2="319" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="364" y1="1073.742" x2="364" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="409" y1="1073.742" x2="409" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="454" y1="1073.742" x2="454" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="499" y1="1073.742" x2="499" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="544" y1="1073.742" x2="544" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="589" y1="1073.742" x2="589" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="634" y1="1073.742" x2="634" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="679" y1="1073.742" x2="679" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="724" y1="1073.742" x2="724" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="769" y1="1073.742" x2="769" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="814" y1="1073.742" x2="814" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="859" y1="1073.742" x2="859" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="902" y1="1073.742" x2="902" y2="1313.5" style="stroke:#333333;stroke-width:1"></line><line x1="949" y1="1073.742" x2="949" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="994" y1="1073.742" x2="994" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="1039" y1="1073.742" x2="1039" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="1084" y1="1073.742" x2="1084" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="1129" y1="1073.742" x2="1129" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="1174" y1="1073.742" x2="1174" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="1219" y1="1073.742" x2="1219" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="1264" y1="1073.742" x2="1264" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="1309" y1="1073.742" x2="1309" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="1354" y1="1073.742" x2="1354" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="1399" y1="1073.742" x2="1399" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="1444" y1="1073.742" x2="1444" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="1489" y1="1073.742" x2="1489" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="1534" y1="1073.742" x2="1534" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="1579" y1="1073.742" x2="1579" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="1624" y1="1073.742" x2="1624" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="1669" y1="1073.742" x2="1669" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="1714" y1="1073.742" x2="1714" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="1759" y1="1073.742" x2="1759" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="1802" y1="1073.742" x2="1802" y2="1313.5" style="stroke:#333333;stroke-width:1"></line><line x1="1849" y1="1073.742" x2="1849" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="1894" y1="1073.742" x2="1894" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="1939" y1="1073.742" x2="1939" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="1984" y1="1073.742" x2="1984" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="2029" y1="1073.742" x2="2029" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="2074" y1="1073.742" x2="2074" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="2119" y1="1073.742" x2="2119" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="2164" y1="1073.742" x2="2164" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="2209" y1="1073.742" x2="2209" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="2254" y1="1073.742" x2="2254" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="2299" y1="1073.742" x2="2299" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="2344" y1="1073.742" x2="2344" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="2389" y1="1073.742" x2="2389" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="2434" y1="1073.742" x2="2434" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="2479" y1="1073.742" x2="2479" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="2524" y1="1073.742" x2="2524" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="2569" y1="1073.742" x2="2569" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="2614" y1="1073.742" x2="2614" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="2659" y1="1073.742" x2="2659" y2="1284" style="stroke:#333333;stroke-width:1"></line><line x1="2704" y1="1073.742" x2="2704" y2="1313.5" style="stroke:#333333;stroke-width:1"></line></svg>

I can't think of any reason why our server fails to convert this SVG to PNG.


Solution

  • It is the transform/rotate that annoys ImageMagic. If you wrap the <text> into a <g> and then transform/translate the <g> with the x,y position of the <text> and remove the x,y parameters form rotate it behaves.

    I didn't test this, but you should probably replace the style attribute with the corresponding SVG attributes on <text>.

    <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="2704" height="1330" viewBox="0 0 2704 1330">
      <rect fill="#FFF" x="0" y="0" width="2704" height="1330"></rect>
      <g transform="translate(35.357142857143 1086.742)">
        <text transform="rotate(270)" text-anchor="end" font-family="Verdana" font-size="29" font-weight="bold" fill="#000000">1</text>
      </g>
      <g transform="translate(80.357142857143 1086.742)">
        <text transform="rotate(270)" text-anchor="end" font-family="Verdana" font-size="29" font-weight="bold" fill="#000000">10</text>
      </g>
    </svg>