Imagick doesn't render svg opacity properly - php

I need same output from Inkscape and Imagick.
This is the expected result, exported from Inkscape.
However, the PHP code below outputs the following faulty result.
PHP code:
<?php
$im = new Imagick();
$im->setResolution(400,400);
$im->setBackgroundColor(new ImagickPixel('transparent'));
$im->readImageBlob(str_replace(array("color1", "color2"), array("yellow", "blue"), file_get_contents("img.svg")));
$im->setImageFormat("png");
header("Content-type: image/png");
echo $im;
?>
SVG code:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="400" height="400">
<rect width="100%" height="100%" fill="green" />
<path d="M250 150 L150 350 L350 350 Z" opacity="0.9" fill="color1" />
<path d="M150 50 L50 250 L250 250 Z" opacity="0.9" fill="color2" />
</svg>

What version of PHP and ImageMagick are you running? Please share the relevant output of phpinfo(). Could this ImageMagick bug be affecting you? Or if you're not up to date, could another ImageMagic bug be affecting you?
EDIT: I don't have easy access to a server with PHP's ImageMagick libraries installed at the moment, but if I find one, I'll test the code provided and post my results.
EDIT2: Looks like others have the same issue, unless that forum post was also yours...
According to this forum post, you could try:
$im->setImageFormat("png32");
One person reported that worked, but another said it did not...

Inkscape uses the not ubiquitously supported opacity property. Use fill-opacity and stroke-opacity instead.

This is already fixed in current version of Imagick.

Related

ImageMagick conversion of SVG to PNG/JPG doesn't work with image element

I'm trying to convert an inline SVG to JPG using ImageMagick. I get a JPG back from the server but the remote image defined in the xlink is always blank. I tested with a SVG with some basic vector shapes and I do see those in the resulting JPEG but this example referencing an external image does not work.
<?php
$mySVG = '<?xml version="1.0" encoding="utf-8"?><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" viewBox="0 0 500 700" style="enable-background:new 0 0 500 700;" xml:space="preserve" width="500"><image style="overflow:visible;" width="500" height="700" xlink:href="http://www.sportsupplygroup.com/SVG_POC/lifter.jpg" transform="matrix(0.948 0 0 0.948 11 36.4)"></image></svg>';
$svg = $mySVG;
$jpeg = new Imagick();
$jpeg->readImageBlob($svg);
$jpeg->setImageFormat("JPEG");
header("Content-Type: image/jpeg");
echo $jpeg;
?>
Being able to load different images into layers of the SVG gives us the ability to deliver some dynamic content. We want to use this in a HTML email but since SVG is not really supported, I want to convert to something that is like a JPG. Email would call a script like this.
<img src="createImage.php"> <!-- call php to get the image -->
Where the script could create the SVG with it's layers and send back a JPG. Is there a better way to convert SVG to JPG/PNG server side?

ImageMagick/IMagick renders groups in SVGs offset

I've got an app that takes an SVG as input and converts to a PNG as output. I've run into a problem where if the SVG has grouped items using the tag, that content gets rendered way off to the right and down on the SVG.
This only happens using IMagick. If I open the SVG in Illustrator or Inkscape for PC, it looks fine. Here's what the SVG code looks like:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="2400px" height="3200px" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="SvgjsG1048" transform="rotate(0 1200 1600) translate(30.927835051559143 41.23711340207863) scale(0.9742268041237008 0.9742268041237009) " x="30.927835051559143" y="41.23711340207863">
<image id="SvgjsImage1049" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="aerosmith.png" width="2400" height="3200"></image>
</g>
</svg>
and here's the code I'm using to pull in and render:
// setup the SVG
$svg_front = new Imagick();
$svg_front->setBackgroundColor(new ImagickPixel('transparent'));
$svg_front->readImage($json->imageFront); // pull in the SVG image
// convert the SVG to PNG # 200 dpi - yes, it works!
$svg_front->setImageUnits(imagick::RESOLUTION_PIXELSPERINCH);
$svg_front->setImageResolution(200,200);
// set image format
$svg_front->setImageFormat('png');
// render the SVG
echo $svg_front;
Nothing out of the ordinary here. Removing the code to set the resolution doesn't make any difference, and I've tried resetPage to no effect as well.
Now, if I remove the tag and leave the image in there, then the SVG renders with no issue. However, I can't control whether the app sends grouped items or not, and IMagick needs to render it no matter what.
Here's the image when it gets rendered to PNG with a tag in the SVG: http://brainboxinteractive.com/bad-svg.png
And here's what is should look like: http://brainboxinteractive.com/what-it-should-look-like.png
Inkscape is installed on the server, so IMagick/ImageMagick is using it so I'm not sure where to start debugging and fixing this issue. Any help would be appreciated!

ImageMagick and imagick_type_gen don't recognize added fonts

Ok, I'm running a CentOS server, PHP 5.4.440 and ImageMagick 6.5.4 and I'm trying to add additional fonts, as an example let's say Lobster. Here's what I've done so far:
Uploaded Lobster.ttf to /home/myusername/fonts/
From SSH, ran "perl imagick_type_gen > fonts.xml". This resulted in a large font file, but contained NO references to either Lobster.otf or Lobster.ttf
Instead, I generated my own type.xml and saved it to /home/myusername/.magick/. Here's the markup:
<?xml version="1.0"?>
<typemap>
<type format="otf" name="Lobster" fullname="Lobster" family="Lobster" glyphs="/home/myusername/fonts/Lobster.otf" />
</typemap>
Via SSH, I edited /user/lib64/ImageMagick-6.5.4/config/type.xml and inserted the node that references the custom type.xml:
<typemap>
<include file="type-ghostscript.xml" />
<include file="/home/myusername/.magick/type.xml" />
</typemap>
Rebooted the server.
At this point, I can list the fonts using this:
$image = new Imagick();
$fonts = $image->queryfonts();
foreach($fonts as $font) {
echo $font . '<br />';
}
And Lobster shows up in the list. However, converting an SVG to PNG isn't using the Lobster font. I've seen other questions in here similar to mine and they seem to work. What do I need to do to get the system to recognize the added font?
Here's the code I'm using to render what should be an image using Lobster as the font:
//Setup SVG to be read by Imagick.
$SVG = '<?xml version="1.0" encoding="utf-8"?>';
$SVG .= '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">';
$SVG .= '<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="158px" height="92px" viewBox="0 0 158 92" enable-background="new 0 0 158 92" xml:space="preserve">';
$SVG .= '<text transform="matrix(1 0 0 1 32 58)" font-family="Lobster" font-style="normal" font-size="20px" font-weight="400">Lobster</text>';
$SVG .= '</svg>';
$image = new Imagick();
//Convert SVG to JPG
$image->readImageBlob($SVG);
$image->setImageFormat("jpeg");
//Save the thumbnail.
$save_path = 'lobster-test.jpg';
$image->writeImage($save_path);
echo '<img src="'.$save_path.'">';
I'm at a complete loss here. Help!
A full solution is discussed here:
http://www.multipole.org/discourse-server/viewtopic.php?t=25630
But here's the short version:
Make a directory for your custom uploaded fonts in
/usr/share/fonts/default - I created a directory called "custom".
Copy the fonts you want to install to /usr/share/fonts/default/custom
Run the command fc-cache -v /usr/share/fonts
After this, ImageMagick will use the fonts in the SVG. The one Caveat is that you MUST use the font-family declaration embeded in the font. For example, Lobster.otf actually lists "Lobster 1.4".
If you've got the font installed and use the proper font-family name, you'll get your fonts rendered!
You need to install the fonts on your server, that's the only way I managed to resolve this issue.
You can check Eric Green's answer on this.

Convert SVG image with filters to PNG /PDF

I have the following svg image to the png image & pdf image with 300 DPI.
<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Created with SVG-edit - http://svg-edit.googlecode.com/ -->
<defs>
<filter height="200%" width="200%" y="-50%" x="-50%" id="svg_1_blur">
<feGaussianBlur stdDeviation="10" in="SourceGraphic"/>
</filter>
</defs>
<g>
<title>Layer 1</title>
<image filter="url(#svg_1_blur)" xlink:href="images/logo.png" id="svg_1" height="162.999996" width="223.999992" y="99" x="185"/>
<text xml:space="preserve" text-anchor="middle" font-family="serif" font-size="24" id="svg_2" y="210" x="289" stroke-width="0" stroke="#000000" fill="#000000">sdfdsdsfsdf</text>
</g>
</svg>
I want to do this using PHP and I have applied filters to the blur filter to the image and I want to retain that.
Also I have problem in viewing this image in the IE, because it doesn't show the blur effect on IE9. Any suggestions?
You can produce something like that with GD's imagefilter:
imagefilter($image_res, IMG_FILTER_GAUSSIAN_BLUR);
or
imagefilter($image_res, IMG_FILTER_SMOOTH, (int) $levelOfSmoothness);
But, for a more complex svg, you will need an SVG renderer.
Edit:
Or, if you know enough about convolution matrices:
$gaussian = array(array(1.0, 2.0, 1.0), array(2.0, 4.0, 2.0), array(1.0, 2.0, 1.0));
imageconvolution($image, $gaussian, 16, 0);
If you have the possibility of executing scripts (exec, popen, etc.), phantomjs uses webkit (same as Chrome/Safari) and is available on all major platforms. You can't get closer than this to what a browser would render. Try something like this:
exec("phantomjs rasterize.js http://ariya.github.com/svg/tiger.svg tiger.png)";
Don't forget to sanitize (escape paths and characters not allowed in a file name or path) the params you are passing to phantomjs (file paths).

SVG to PNG with imagick

I have a svg which has some images embedded into it. Something like:
<?xml version='1.0' encoding='UTF-8'?>
<svg
width="483" height="710"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<g>
<title>Layer 1</title>
<image
id="svg_1"
y="0" x="0"
height="199" width="176"
xlink:href="http://192.168.3.2/images/1341920552_test.png"/>
</g>
</svg>
So when I do a convert via command line as my regular linux user it converts it to PNG just fine. But if I do the same with the user www-data then it does convert but the images dont showup in the resulting PNG other things like lines etc do showup.
The very same problem exists if I convert with the PHP imagick library. The attached images dont showup. Any sort of help is appreciated.
After a lot of experimentation's noticed that all users have this problem if they are logged in via ssh. The normal desktop user who is logged into the GUI session can convert without any issues.
I solved the issue by removing the http URL referring the embedded image and adding the local file system path. This slows down my app with the current design. But anyway this is solved for the time being.
I would like to know the reason though as to why this is like this.

Categories