Search code examples
phpsvgimagick

Issues to convert SVG to PNG using Imagick


I am trying to convert svg to png image using imagick.This is the code i am using.

<?php
$usmap = 'http://yatnam.com/demo/vh/card2_1.svg';
$svg = file_get_contents($usmap);
$im = new Imagick();
//$im->setBackgroundColor(new ImagickPixel('transparent'));
$im->readImageBlob($svg);
$im->setImageFormat("png32");
$im->setImageCompressionQuality(100);
$im->resizeImage(720, 445, imagick::FILTER_LANCZOS, 1);
$base64=base64_encode($im);
$im->clear();
$im->destroy();
?>
<img src="<?php echo 'data:image/jpg;base64,' . $base64;?>" />

My SVG images contain many other base64 encoded images..These images will not convert properly if it is not in png format.

To understand the issue exactly, please browse svg url directly.It is a image with Pink background.Now run my code. See same image in white background ..

Please help me to fix this issue..Thanks a lot in advance.


Solution

  • Do you have the access to the SVG file? Or are you able to download/save it locally, then change

    xlink:href="data:image/jpeg;base64
    

    in the 1st <image>

    xlink:href="data:image/png;base64
    

    and reference your local downloaded and changed copy?

    The other way to show what you need to change is here:

    enter image description here

    I'm getting then the following:

    enter image description here

    UPDATE: I'd like to say once more that the SVG file you provided as example has the pink background as <image> with wrong MIME type, as I said in the comments. The problem you describe occurs because of that, no matter how reliable the image source is. You can check it by copying the base64 value of the first <image> in the SVG, decode it and save and then open it with any editor, you will see this:

    enter image description here

    which is a PNG, not JPEG signature. However, the first <image> in the SVG has image/jpeg - check it.

    Now back to your claim that you can't change all the files. What I can propose is parsing SVG's XML in your script and replacing all MIME types with the correct ones. Be aware that this will require quite a lot memory as SVG's may be large. Note the new code between MODIFY THE MALFORMED SVG comments

    $usmap = 'http://yatnam.com/demo/vh/card2_1.svg';
    $svg = file_get_contents($usmap);
    
    /////////////////// MODIFY THE MALFORMED SVG ///////////////////////
    
    $dom = new DomDocument();
    $dom->loadXML($svg);
    foreach($dom->getElementsByTagName('image') as $image) {
        $encoded = $image->attributes->getNamedItem('href')->value;
        if(!empty($encoded)) {
            $binary = base64_decode(substr($encoded,strpos($encoded,'base64,') + 7));
            $info = getimagesizefromstring ($binary);
    
            $image->setAttributeNS('http://www.w3.org/1999/xlink','xlink:href','data:'.$info['mime'].';base64,' . base64_encode($binary));
        }
    }
    
    $svg = $dom->saveXML();
    
    /////////////////// MODIFY THE MALFORMED SVG ///////////////////////
    
    $im = new Imagick();
    //$im->setBackgroundColor(new ImagickPixel('transparent'));
    $im->readImageBlob($svg);
    $im->setImageFormat("png32");
    $im->setImageCompressionQuality(100);
    $im->resizeImage(720, 445, imagick::FILTER_LANCZOS, 1);
    $base64=base64_encode($im);
    $im->clear();
    $im->destroy();