使用 PHP 将 SVG 图像转换为 jpg

发布于 2024-10-14 14:13:25 字数 295 浏览 9 评论 0原文

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

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

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

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

三生路 2024-10-21 14:13:26

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

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

When converting SVG to transparent PNG, don't forget to put this BEFORE $imagick->readImageBlob():

$imagick->setBackgroundColor(new ImagickPixel('transparent'));
绮烟 2024-10-21 14:13:26

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

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

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

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

另一个可能有帮助的:SVGWeb

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

另请参阅此问题的最佳答案,例如:XSL 将 SVG 转换为 VML

You mention that you are doing this because IE doesn't support SVG.

The good news is that IE does support vector graphics. Okay, so it's in the form of a language called VML which only IE supports, rather than SVG, but it is there, and you can use it.

Google Maps, among others, will detect the browser capabilities to determine whether to serve SVG or VML.

Then there's the Raphael library, which is a Javascript browswer-based graphics library, which supports either SVG or VML, again depending on the browser.

Another one which may help: SVGWeb.

All of which means that you can support your IE users without having to resort to bitmap graphics.

See also the top answer to this question, for example: XSL Transform SVG to VML

只为一人 2024-10-21 14:13:26

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

1) 将图像放入浏览器中的 canvas 元素中:

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

This is a method for converting a svg picture to a gif using standard php GD tools

1) You put the image into a canvas element in the browser:

<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);
゛时过境迁 2024-10-21 14:13:26

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

您需要Batik SVG 工具包。下载并将文件放在与要转换为 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')

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

You need the Batik SVG Toolkit. Download, and place the files in the same directory as the SVG you want to convert to a JPEG, also make sure you unzip it first.

Open the terminal, and run this command:

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

That should output a JPEG of the SVG file. Really easy.
You can even just place it in a loop and convert loads of SVGs,

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')
酒废 2024-10-21 14:13:26

我也想分享我的答案,它可能会对某人有所帮助。

这更适合简单的情况,当您的 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();
}

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

This it is more for simple case when your svg dose not contain fill style and by default black and you want to convert it to png and add color to result 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();
}
如日中天 2024-10-21 14:13:26

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

ImageMagick 能够通过命令行或 PHP 绑定来光栅化 SVG 文件,IMagick,但似乎有许多怪癖和外部依赖项,如 此论坛主题。我认为这仍然是最有希望的方法,如果我是你,这是我首先要考虑的事情。

I do not know of a standalone PHP / Apache solution, as this would require a PHP library that can read and render SVG images. I'm not sure such a library exists - I don't know any.

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 this forum thread. I think it's still the most promising way to go, it's the first thing I would look into if I were you.

笑饮青盏花 2024-10-21 14:13:26

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

You can use Raphaël—JavaScript Library and achieve it easily. It will work in IE also.

放手` 2024-10-21 14:13:26
$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

$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);

or using : potrace
demo :Tool4dev.com

梦萦几度 2024-10-21 14:13:25

你问这个问题很有趣,我最近刚刚为我的工作网站做了这个,我想我应该写一个教程...以下是如何使用 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 &颜色值被存储。如果您不想在服务器上存储文件,您可以将图像输出为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

完成:在此处输入图像描述

编辑

自从写完上面的内容后,我提出了 2 种改进的技术:

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)如果您不需要实际创建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>

That's funny you asked this, I just did this recently for my work's site and I was thinking I should write a tutorial... Here is how to do it with PHP/Imagick, which uses 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();

the steps regex color replacement may vary depending on the svg path xml and how you id & color values are stored. If you don't want to store a file on the server, you can output the image as base 64 like

<?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

you can see an example here I did for a former employer's sales territory map:

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

Finish: enter image description here

Edit

Since writing the above, I've come up with 2 improved techniques:

1) instead of a regex loop to change the fill on state , use CSS to make style rules like

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

and then you can do a single text replace to inject your css rules into the svg before proceeding with the imagick jpeg/png creation. If the colors don't change, check to make sure you don't have any inline fill styles in your path tags overriding the 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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文