Конвертировать SVG изображение в PNG с PHP
Я работаю над веб-проектом, который включает в себя динамически генерируемую карту США, раскрашивающую разные штаты на основе набора данных.
Этот файл SVG дает мне хорошую пустую карту США и очень легко изменить цвет каждого штата. Сложность в том, что браузеры IE не поддерживают SVG, поэтому для того, чтобы я использовал удобный синтаксис, предлагаемый svg, мне нужно преобразовать его в JPG.
В идеале я хотел бы сделать это только с библиотекой GD2, но также мог бы использовать ImageMagick. Я понятия не имею, как это сделать.
Будет рассмотрено любое решение, которое позволило бы мне динамически изменять цвета штатов на карте США. Ключевым моментом является то, что это легко изменить цвета на лету, и это кросс-браузер. Только PHP/Apache, пожалуйста.
11 ответов
Забавно, что вы спросили об этом, я недавно сделал это для сайта своей работы и подумал, что мне следует написать учебник... Вот как это сделать с помощью 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();
Замена цвета шагов регулярного выражения может варьироваться в зависимости от XML-пути SVG и того, как хранятся ваши значения идентификатора и цвета. Если вы не хотите хранить файл на сервере, вы можете вывести изображение в формате base 64, например
<?php echo '<img src="data:image/jpg;base64,' . base64_encode($im) . '" />';?>
(до того, как вы используете clear/destroy), но есть проблемы с 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>
и затем вы можете сделать одну замену текста, чтобы внедрить ваши правила CSS в SVG, прежде чем приступить к созданию imagick jpeg/png. Если цвета не меняются, убедитесь, что у вас нет встроенных стилей заливки в ваших тегах пути, перекрывающих CSS.
2) Если вам не нужно создавать файл изображения в формате jpeg/png (и вам не нужно поддерживать устаревшие браузеры), вы можете напрямую управлять svg с помощью jQuery. Вы не можете получить доступ к путям svg при встраивании svg с помощью img или тегов объекта, поэтому вам нужно будет напрямую включить svg xml в html вашей веб-страницы, например:
<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 в прозрачный PNG, не забудьте поставить это ДО $imagick->readImageBlob():
$imagick->setBackgroundColor(new ImagickPixel('transparent'));
Еще одна очень быстрая и точная опция - браузер без головок PhantomJS (webkit)
Вы упоминаете, что делаете это, потому что IE не поддерживает SVG.
Хорошей новостью является то, что IE поддерживает векторную графику. Итак, это в форме языка VML, который поддерживает только IE, а не SVG, но он есть, и вы можете использовать его.
Карты Google, среди прочего, обнаружат возможности браузера, чтобы определить, обслуживать ли SVG или VML.
Кроме того, есть библиотека Raphael, представляющая собой графическую библиотеку на основе браузера Javascript, которая поддерживает SVG или VML, опять же, в зависимости от браузера.
Еще один, который может помочь: SVGWeb.
Все это означает, что вы можете поддерживать своих пользователей IE без необходимости прибегать к растровой графике.
Смотрите также главный ответ на этот вопрос, например: XSL Transform SVG to VML
Это очень просто, я работал над этим уже несколько недель.
Вам нужен Batik SVG Toolkit. Загрузите и разместите файлы в том же каталоге, что и SVG, который вы хотите преобразовать в JPEG, также сначала убедитесь, что вы распаковали его.
Откройте терминал и выполните эту команду:
java -jar batik-rasterizer.jar -m image/jpeg -q 0.8 NAME_OF_SVG_FILE.svg
Это должно вывести JPEG файла SVG. Действительно легко. Вы даже можете просто поместить его в цикл и конвертировать множество 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 в GIF с использованием стандартных инструментов PHP GD
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);
Вы можете использовать библиотеку canvg js для преобразования SVG в PNG, более подробную информацию можно получить здесь http://paksula.users.cs.helsinki.fi/svg_open_2010/demo.xhtml совместимой со всеми основными браузерами!
Я использую его в своем проекте и фактически конвертирую SVG в PNG (конечно, с помощью PHP для сохранения файла)
Я тоже хотел бы поделиться своим ответом, это может помочь кому-то.
Это больше для простого случая, когда ваша доза 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();
}
Я не знаю отдельного решения PHP / Apache, так как для этого потребовалась бы библиотека PHP, которая может считывать и отображать изображения SVG. Я не уверен, что такая библиотека существует - я не знаю ни одной.
ImageMagick может растеризовать файлы SVG либо через командную строку, либо через привязку PHP, IMagick, но, похоже, имеет ряд особенностей и внешних зависимостей, как показано, например, в этой ветке форума. Я думаю, что это все еще самый многообещающий путь, это первое, на что я бы посмотрел, если бы я был тобой.
$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
Вы можете использовать Raphaël—JavaScript Library и легко добиться этого. Это будет работать и в IE.