Reputation: 2599
I have a php script that generates icons, and returns them in a variety of formats, using ImageMagick. The bitmap formats like JPG, PNG, and even ICO work like a charm, but the SVG output does some weird things. Here is a minimal script to illustrate te case:
<?php
$format = 'jpg';
$im = new Imagick;
$im->newImage(300, 300, new ImagickPixel('#ffffff'));
$im->setImageFormat($format);
$draw = new ImagickDraw();
$draw->setStrokeWidth(0);
$draw->setFillColor(new ImagickPixel('#ff0000'));
$draw->setFillOpacity(.5);
$draw->rectangle(50, 50, 249, 249);
$im->drawImage($draw);
header('Content-Type: ' . $im->getImageMimeType());
echo $im->getImageBlob();
Sample output:
If I change the value of $format
to png
or ico
, the image still works fine, and gets send with the proper MIME type header. When I switch the format to svg
, the correct MIME type header is sent, and it does return some sort of SVG, but it appears to be malformed. This is the output of the sample script above:
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg width="300" height="300">
stroke-width:0;fill:#FFFF00000000;fill-opacity:0.5; <rect x="50" y="50" width="199" height="199"/>
</svg>
Notably, the xmlns
attribute on the svg
element is missing. Perhaps weirder, the rectangle attributes are not actually applied to the rectangle, but dumped as some sort of inline CSS (without the proper context for it to act as such).
Output that would work (and that I sort of expected) would be:
<?xml version="1.0" standalone="no"?>
<svg width="300" height="300" xmlns="http://www.w3.org/2000/svg">
<rect x="50" y="50" width="199" height="199" stroke-width="0" fill="#FF0000" fill-opacity="0.5"/>
</svg>
Also, a viewBox
property with the correct dimensions would be nice, but that is not a deal-breaker.
Am I missing something? Perhaps some operation that needs to be applied before rendering as a vector format? Maybe it’s a bug? I can’t find any information on it, and any pointers in the right direction would be greatly appreciated.
Plot twist. I hadn’t noticed this before, but when I omit the drawImage
step in my example, I get different output altogether:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="300px" height="300px" viewBox="0 0 300 300" enable-background="new 0 0 300 300" xml:space="preserve"> <image id="image0" width="300" height="300" x="0" y="0"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsAQAAAABRBrPYAAAABGdBTUEAALGPC/xhBQAAACBjSFJN
AAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QAAd2KE6QAAAA+SURB
VGje7coxAQAACAOg9U9rA1dBf7jJXkw0TdM0TdM0TdM0TdM0TdM0TdM0TdM0TdM0TdM0TdM0TdO0
fytHkUx5BCDW7AAAAABJRU5ErkJggg==" />
</svg>
It now creates a PNG background image that it parses inline for some reason, but it also introduces aspects that were missing before; notably xmlns
and viewBox
.
The whole markup looks the same as something that Inkscape would produce. Which probably makes sense, as I read somewhere that this is one of the libraries that ImageMagick can use to render SVGs.
It’s almost as if the drawImage
method breaks the Inkscape parser, and it falls back to some inferior engine or something. I hope this narrows the path to a solution.
Upvotes: 3
Views: 451
Reputation: 534
According to this ImageMagic board, export to SVG is rather problematic as the library is intended for raster images, not vector graphics. From what I understand SVG output will always be an image tag with base64 encoded binary data. The workaround for your requirement might look like this:
$im = new Imagick;
$im->newImage(300, 300, new ImagickPixel('#ffffff'));
$im->setImageFormat('svg');
$im1 = new Imagick();
$im1->newImage(300, 300, new ImagickPixel('#ffffff'));
$im1->setImageFormat('png');
$fillColor = new ImagickPixel('#ff0000');
$draw = new ImagickDraw();
$draw->setFillColor($fillColor);
$draw->setStrokeWidth(0);
$draw->setFillOpacity(.5);
$draw->rectangle(50, 50, 249, 249);
$im1->drawImage($draw);
$im->compositeImage($im1->getimage(), Imagick::COMPOSITE_COPY, 0, 0);
header('Content-Type: image/svg+xml');
echo $im->getImageBlob();
Upvotes: 1