ImageMagick/IMagick renders groups in SVGs offset - php

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!

Related

Dynamically insert SVG with php?

I am trying to reference/insert a dynamically uploaded svg file (image) from a products database using PHP. So far uploading the images work fine, as I can use them with an image tag and they show up fine.
<img src="image.svg" />
The XML also shows up correctly when I open them on my computer (using a text editor for example).
The problem is I can't seem to get them to be displayed inline so I can use styles like fill.
Here is my PHP code that dynamically displays the image:
<svg id="svg-image" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" >
<image id="main-image" xlink:href="<?php echo tep_href_link('images/' . $product_info['products_image']); ?>" />
</svg>
I tried changing image to path in the above code to get it to work, and the image just disappears on reload. Any help is greatly appreciated.

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?

Imagick can't write SVG files

I use Imagick to open an image, resize it, set an image format (if it's needed) and write in another folder the result. It works with ICO and PNG, but can't write SVG files, saying that
ImagickException: Unable to write the file: C:\Sites\devdesktop\test\sites\default\files\tempimages\abstract-spiral-striped-background-100.svg in Imagick->writeimage() (line 44 of C:\Sites\devdesktop\test\sites\all\modules\testmodule\testmodule.module).
It was an error message from Drupal 7.
Here is my code:
$file = file_load($form_state['values']['fid']);
$image = new Imagick(drupal_realpath($file->uri));
$image->setImageFormat($type[$type_num]);
$image->resizeImage($size[$size_num], $size[$size_num], Imagick::FILTER_UNDEFINED, 1);
$destination = 'public://tempimages/'.substr($file->filename, 0, -4).'-'.$size[$size_num].'.'.$type[$type_num];
$image->writeImage(drupal_realpath($destination)); //<---problem
drupal_goto(base_path().'/sites/default/files/tempimages/'.substr($file->filename, 0, -4).'-'.$size[$size_num].'.'.$type[$type_num]);
This code snippet works perfectly with ICO and PNG, but don't write a file in SVG format except a little peace of code
<?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="200" height="200">
<g style="</svg>
Why so?
SVG isn't an image in the same way that JPG or PNG are.
It's just an xml with plotted points in most cases, and is typically void of dimension and resolution.
The width and height of 200 are just the size in px at which it was saved. So you should never need to 'resize' an svg, as it will scale infinitely.
If you put an SVG in an img tag and define the dimensions, like:
<img src="myawesome.svg" width="500" height="500" />
Even though it's defined in the SVG as having a dimensions of 200, it should scale larger or smaller with no change in the quality of appearance.
Because of this complete difference in structure, it will not follow the same rules in some cases as jpg or png will as they are rendered images.
If this is being done in Drupal; make an exception for SVG that just stores the file without resizing, and add the dimensions where ever it is printed for all images. It won't hurt the rendered images, and it should show the SVG as the same size as them.
TL;DR SVG is an xml file, not really an image, resizing it is pointless since it carries no real resolution or size and can scale infinitely. They only appear to be similar since they are both visual elements. Make an exception for SVG so it just stores the file, and when either the rendered images or the SVG is printed, add the resized dimensions to the img output.

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.

Rotate an image in clockwise & Anti Clockwise direction

I have used http://raphaeljs.com/image-rotation.html raphel's script but. How how can v save this rotated image.
It's an SVG, not really an image per-se.
You'll have to save the generated SVG via AJAX onto your server and render it with an external SVG-rendering library.
You could try librsvg2-bin, as I've heard that it works.
As mentioned it's an SVG element and it uses a source image to change it's angle upon clicking the rotate buttons. By inspecting the rotated image you'll see the SVG element like:
<image x="160" y="120" width="320" height="240" preserveAspectRatio="none" href="http://raphaeljs.com/bd.jpg" transform="rotate(-90, 320, 240)"/>
You'll notice that there's a tranform attribute that contains the rotate(angle, x, y) function. If you can find a way to get that angle value you can use it to manipulate the image source to generate a new image using PHP by using the imagerotate function.
By doing this I got the transform attribute value:
document.getElementById('holder').getElementsByTagName('image')[0].getAttribute('transform')
This returns "rotate(-90, 320, 240)"
Of course this is a hack ;p

Categories