使用 PHP 将 SVG 图像转换为 PNG

Posted

技术标签:

【中文标题】使用 PHP 将 SVG 图像转换为 PNG【英文标题】:Convert SVG image to PNG with PHP 【发布时间】:2011-06-16 02:28:17 【问题描述】:

我正在开展一个网络项目,该项目涉及根据一组数据为不同州着色的美国动态生成地图。

这个 SVG 文件给了我一张很好的美国空白地图,并且很容易改变每个州的颜色。困难在于 IE 浏览器不支持 SVG,所以为了让我使用 svg 提供的方便语法,我需要将其转换为 JPG。

理想情况下,我希望只使用 GD2 库,但也可以使用 ImageMagick。我完全不知道如何做到这一点。

将考虑任何允许我动态更改美国地图上各州颜色的解决方案。关键是它很容易动态更改颜色并且它是跨浏览器的。请仅使用 php/Apache 解决方案。

【问题讨论】:

是否有任何类旨在将 SVG 移植到 VML?这样你仍然可以有一个“html5”类型的解决方案 看看我的回答。正是你需要的 【参考方案1】:

你问这个很有趣,我最近刚刚为我的工作网站做了这个,我想我应该写一个教程......这是使用 ImageMagick 的 PHP/Imagick 的方法:

$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 和颜色值的存储方式。如果您不想在服务器上存储文件,可以将图像输出为 base 64 之类的

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

(在你使用 clear/destroy 之前)但是 ie 存在将 PNG 作为 base64 的问题,所以你可能不得不将 base64 输出为 jpeg

您可以在这里查看我为前雇主的销售区域地图所做的示例:

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

完成:

编辑

自从写了上面的内容后,我想出了两个改进的技术:

1) 代替正则表达式循环来更改 state 的填充,使用 CSS 来制作样式规则,如

<style type="text/css">
#CA,#FL,HI
    fill:blue;

#Al, #NY, #NM
    fill:#cc6699;

/*etc..*/
</style>

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

2) 如果您不必实际创建 jpeg/png 图像文件(并且不需要支持过时的浏览器),您可以直接使用 jQuery 操作 svg。使用 img 或 object 标签嵌入 svg 时,您无法访问 svg 路径,因此您必须直接在网页 html 中包含 svg xml,例如:

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

那么改变颜色就这么简单:

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

【讨论】:

感谢您提供有关如何执行此操作的非常准确和有用的教程。我当然会使用您的解决方案作为备份,但我渴望尝试并在所有主要浏览器中获得 svg 兼容性。 在 ie8 或更低版本中不支持 SVG,无需用户安装 svg 查看器插件 - 来自 SVG ***页面:“所有主要的现代 Web 浏览器都支持和直接呈现 SVG 标记,但非常明显的例外Microsoft Internet Explorer (IE)[3] Internet Explorer 9 beta 支持基本的 SVG 功能集。[4] 目前,对在 android 下运行的浏览器的支持也受到限制。” 是的,但是 svgweb 似乎使用一点 js 和 flash 解决了所有的不兼容问题。这就是我采用的解决方案。 我喜欢你干净快速的解决方案。就个人而言,在与 xml 文件交互时,我更喜欢使用 dom 解析器来感觉比使用正则表达式更安全。点赞:$dom = new DOMDocument(); $dom-&gt;loadXML( $svg ); $dom-&gt;getElementsByTagName('image')-&gt;item(0)-&gt;setAttribute('id', $state); $svg = $dom-&gt;saveXML(); 一个 xml 解析器将是一个更安全的解决方案,虽然速度稍慢,但与任何其他 svg 的解决方案......在这种情况下,正则表达式是安全的,因为我确保每个状态的属性都被格式化为 (id=" XX" style="fill:#XXXXXX").【参考方案2】:

在将 SVG 转换为透明 PNG 时,不要忘记将这个放在 $imagick-&gt;readImageBlob() 之前:

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

【讨论】:

如何在读取图像之前调用该方法,我收到错误“无法处理空的 Imagick 对象”。是的,我的 imagick 扩展程序在工作和转换图像时已安装。 你是个好人,我的朋友。这没有被问到,但主要答案非常需要。祝你有美好的一天。 这应该包含在选择的答案中。【参考方案3】:

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

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

Google 地图等会检测浏览器功能以确定是提供 SVG 还是 VML。

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

另一个可能有帮助的:SVGWeb。

所有这些都意味着您可以支持您的 IE 用户,而无需求助于位图图形。

另请参阅此问题的最佳答案,例如:XSL Transform SVG to VML

【讨论】:

+1 提到了 raphael,这绝对是一个很好的解决方案,值得研究,因为它出色地实现了跨浏览器矢量图形。【参考方案4】:

这很简单,过去几周一直在做这方面的工作。

您需要Batik SVG Toolkit。下载并将文件放在与要转换为 JPEG 的 SVG 相同的目录中,同时确保先将其解压缩。

打开终端,运行以下命令:

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')

【讨论】:

这很棒。谢谢你的提示。我将结合 perl 使用它来批处理我从模板创建的 SVG 文件的加载。【参考方案5】:

这是一种使用标准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>    

然后在服务器(ProcessPicture.php)将其从(默认)png转换为gif并保存。 (您也可以保存为 png,然后使用 imagepng 而不是图像 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);

【讨论】:

我支持这个答案,因为它是唯一真正适用于更复杂的 SVG 图像的 PHP 解决方案。所有图书馆包括。 Imagick 因渲染错误而失败。这个解决方案很复杂,但它可以自动化并且效果最好。【参考方案6】:

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

ImageMagick 能够通过命令行或 PHP 绑定 IMagick 光栅化 SVG 文件,但似乎有一些怪癖和外部依赖项,例如在this forum thread。我认为这仍然是最有前途的方法,如果我是你,这是我首先要研究的。

【讨论】:

【参考方案7】:

您可以使用Raphaël—JavaScript Library 轻松实现。它也适用于 IE。

【讨论】:

添加链接中的详细信息。链接可能随时断开【参考方案8】:
$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 演示:Tool4dev.com

【讨论】:

以上是关于使用 PHP 将 SVG 图像转换为 PNG的主要内容,如果未能解决你的问题,请参考以下文章

如何将 PNG 图像转换为 SVG? [关闭]

在 PHP 中使用 Imagick 将 svg 转换为 png 时出现奇怪的裁剪问题

在浏览器中将 SVG 转换为图像(JPEG、PNG 等)

使用 Batik 将 svg 转换为图像时出现 TranscoderException

在使用canvas api在浏览器中将svg转换为png时,svg中的嵌入图像在Safari中随机空白

如何从PNG图像制作字体图标?