Imagick can't write SVG files - php

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.

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?

png with transparency and png-derived blob are rendering black on canvas element instead of transparent

I am letting users preview images using URL.createObjectURL() (which represents the image as a blob). This has worked great, but now I am using the plugin jCrop to let users crop said images and I have encountered a minor issue.
jCrop has worked fine for blobs derived from jpg files and png files w/o transparency, but blobs derived from png files with transparency are rendering transparent pixels (on the canvas) as black (the same effect was happening with these images when resized and uploaded to the backend (php) but this was corrected using imagealphablending()).
jCrop is called as followed:
jQuery(function($) {
$("#myImageContainer").Jcrop({
onChange: myFunction
}, function () {
jcrop_api = this;
});
});
The "black" images on canvas are uploaded and saved properly with transparency, so this is a front end effect only. Additionally, the same effect is observed when the source png is used to preview instead of the png-derived blob. Is their any way to correct for this effect on the canvas instead of the backend?
UPDATE: The transparent image is black from the start...I am assuming the author of the plugin set the canvas background to be black. I will try and change this.

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!

Using 'convert interlace -line' on animated .gif breaks image

Before I explain, you may want to take a quick look at my thumbnail generation code: http://pastebin.com/XAPPcUyZ
I pass several image types through this script: jpeg,jpg,gif,png
All types create a 220px wide thumbnail like they should, the problem arrises when the script runs into an animated .gif image - when attempting to make a thumbnail for the gif it outputs something like this: http://i.imgur.com/oh50z.gif where the image appears tiled when a proper thumbnail should look more like this: http://whatimg.com/i/mhsnf4_thumb.gif.
If I remove 'interlace -line' the animated gif's generate thumbnails without any issue, however I would like to leave this in so that the other file formats are interlaced for faster loading. Is there a way to run interlace without breaking animated gifs like this? If there isn't how can I go about detecting if a gif is animated and running a non-interlaced convert on it instead?

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