Convert SVG image to PNG with PHP

I'm working on a web project that involves a dynamically generated map of the US coloring different states based on a set of data.

This SVG file gives me a good blank map of the US and is very easy to change the color of each state. The difficulty is that IE browsers don't support SVG so in order for me to use the handy syntax the svg offers, I'll need to convert it to a JPG.

Ideally, I'd like to do this with only the GD2 library but could also use ImageMagick. I have absolutely no clue how to do this.

Any solution that would allow me to dynamically change the colors of states on a map of the US will be considered. The key is that it is easy to change the colors on the fly and that it is cross browser. PHP/Apache solutions only, please.

162971 次浏览

我不知道有什么独立的 PHP/Apache 解决方案,因为这需要一个可以读取和呈现 SVG 图像的 PHP 库。我不确定这样的图书馆是否存在——我不知道有这样的图书馆。

ImageMagick is able to rasterize SVG files, either through the command line or the PHP binding, IMagick, but seems to have a number of quirks and external dependencies as shown e.g. in 这个论坛帖子. I think it's still the most promising way to go, it's the first thing I would look into if I were you.

您提到这样做是因为 IE 不支持 SVG。

好消息是 IEdoes支持矢量图形。好的,它是一种叫做 VML 的语言,只有 IE 支持,而不是 SVG,但是它确实存在,你可以使用它。

除了其他功能之外,GoogleMaps 将检测浏览器的功能,以确定是服务于 SVG 还是 VML。

然后是基于 Javascript 浏览器的图形库 Raphael library,它支持 SVG 或 VML,同样取决于浏览器。

另一个可能有帮助的方法: SVGWeb

所有这些意味着你可以支持你的 IE 用户而不必求助于位图图形。

另请参阅这个问题的顶部答案,例如: 将 SVG 转换为 VML

你问这个问题很有趣,我最近刚刚为我的工作站点做了这个,我想我应该写一个教程... 下面是如何使用 PHP/Imagick,它使用 ImageMagick:

$usmap = '/path/to/blank/us-map.svg';
$im = new Imagick();
$svg = file_get_contents($usmap);


/*loop to color each state as needed, something like*/
$idColorArray = array(
"AL" => "339966"
,"AK" => "0099FF"
...
,"WI" => "FF4B00"
,"WY" => "A3609B"
);


foreach($idColorArray as $state => $color){
//Where $color is a RRGGBB hex value
$svg = preg_replace(
'/id="'.$state.'" style="fill:#([0-9a-f]{6})/'
, 'id="'.$state.'" style="fill:#'.$color
, $svg
);
}


$im->readImageBlob($svg);


/*png settings*/
$im->setImageFormat("png24");
$im->resizeImage(720, 445, imagick::FILTER_LANCZOS, 1);  /*Optional, if you need to resize*/


/*jpeg*/
$im->setImageFormat("jpeg");
$im->adaptiveResizeImage(720, 445); /*Optional, if you need to resize*/


$im->writeImage('/path/to/colored/us-map.png');/*(or .jpg)*/
$im->clear();
$im->destroy();

根据 svg 路径 xml 和 id & color 值的存储方式,regex 颜色替换步骤可能会有所不同。如果不想在服务器上存储文件,可以像下面这样输出以64为基数的图像

<?php echo '<img src="data:image/jpg;base64,' . base64_encode($im) . '"  />';?>

(before you use clear/destroy) but ie has issues with PNG as base64 so you'd probably have to output base64 as jpeg

你可以在这里看到一个我为前雇主制作的销售区域地图的例子:

开始: https://upload.wikimedia.org/wikipedia/commons/1/1a/Blank_US_Map_(states_only).svg

完成时间:enter image description here

剪辑

自从写了上面的文章,我想出了两个改进的技巧:

1)不要使用正则表达式循环来更改状态的填充,而是使用 CSS 来创建如下样式规则

<style type="text/css">
#CA,#FL,HI{
fill:blue;
}
#Al, #NY, #NM{
fill:#cc6699;
}
/*etc..*/
</style>

然后,在继续创建 Imagick jpeg/png 之前,可以进行单个文本替换,将 css 规则注入到 svg 中。如果颜色没有改变,请检查确保路径标签中没有覆盖 css 的内联填充样式。

2) If you don't have to actually create a jpeg/png image file (and don't need to support outdated browsers), you can manipulate the svg directly with jQuery. You can't access the svg paths when embedding the svg using img or object tags, so you'll have to directly include the svg xml in your webpage html like:

<div>
<?php echo file_get_contents('/path/to/blank/us-map.svg');?>
</div>

then changing the colors is as easy as:

<script type="text/javascript" src="/path/to/jquery.js"></script>
<script type="text/javascript">
$('#CA').css('fill', 'blue');
$('#NY').css('fill', '#ff0000');
</script>

This is v. easy, have been doing work on this for the past few weeks.

您需要 Batik SVG 工具包.Download 和 将文件放置在您想要转换为 JPEG 的 SVG 所在的同一目录中,还要确保首先解压缩它。

Open the terminal, and run this command:

java -jar batik-rasterizer.jar -m image/jpeg -q 0.8 NAME_OF_SVG_FILE.svg

这应该可以输出 SVG 文件的 JPEG 格式,非常简单。 您甚至可以将它放在一个循环中并转换大量 SVG,

import os


svgs = ('test1.svg', 'test2.svg', 'etc.svg')
for svg in svgs:
os.system('java -jar batik-rasterizer.jar -m image/jpeg -q 0.8 '+str(svg)+'.svg')

当将 SVG 转换为透明 PNG 时,不要忘记在 $imagick->readImageBlob()之前写下:

$imagick->setBackgroundColor(new ImagickPixel('transparent'));

你可以使用 Raphaël ー JavaScript 库,并很容易实现它。它也将在 IE 中工作。

$command = 'convert -density 300 ';
if(Input::Post('height')!='' && Input::Post('width')!=''){
$command.='-resize '.Input::Post('width').'x'.Input::Post('height').' ';
}
$command.=$svg.' '.$source;
exec($command);
@unlink($svg);

或使用: potrace demo :Tool4dev.com

这是一种使用标准 php GD 工具将 svg 图片转换为 gif 的方法

1)在浏览器中将图像放入画布元素:

<canvas id=myCanvas></canvas>


<script>
var Key='picturename'
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
base_image = new Image();
base_image.src = myimage.svg;
base_image.onload = function(){


//get the image info as base64 text string


var dataURL = canvas.toDataURL();
//Post the image (dataURL) to the server using jQuery post method
$.post('ProcessPicture.php',{'TheKey':Key,'image': dataURL ,'h': canvas.height,'w':canvas.width,"stemme":stemme } ,function(data,status){ alert(data+' '+status) });
}
</script>

And then convert it at the server (ProcessPicture.php) from (default) png to gif and save it. (you could have saved as png too then use imagepng instead of image gif):

//receive the posted data in php
$pic=$_POST['image'];
$Key=$_POST['TheKey'];
$height=$_POST['h'];
$width=$_POST['w'];
$dir='../gif/'
$gifName=$dir.$Key.'.gif';
$pngName=$dir.$Key.'.png';


//split the generated base64 string before the comma. to remove the 'data:image/png;base64, header  created by and get the image data
$data = explode(',', $pic);
$base64img = base64_decode($data[1]);
$dimg=imagecreatefromstring($base64img);


//in order to avoid copying a black figure into a (default) black background you must create a white background


$im_out = ImageCreateTrueColor($width,$height);
$bgfill = imagecolorallocate( $im_out, 255, 255, 255 );
imagefill( $im_out, 0,0, $bgfill );


//Copy the uploaded picture in on the white background
ImageCopyResampled($im_out, $dimg ,0, 0, 0, 0, $width, $height,$width, $height);


//Make the gif and png file
imagegif($im_out, $gifName);
imagepng($im_out, $pngName);

I would like to share my answer too it might help someone.

这是更为简单的情况下,当您的 svg 剂量不包含填充样式,默认为黑色,您想要转换为 png,并添加颜色的结果 png。

function convertSvgToPng($svgPath, $fillColor, $outPath)
{
$im = new Imagick();
$svg = file_get_contents($svgPath);
    

// !!! THIS is the trick part - just appending to all <path fill color
$svg = str_replace('<path ', '<path style="fill:'.$fillColor.'" ', $svg);
    

$im->readImageBlob($svg);
$im->setImageFormat("png24");


$im->writeImage($outPath);
$im->clear();
$im->destroy();
}