Преобразование SVG изображения в PNG с помощью PHP

Я работаю над веб-проектом, который включает динамически сгенерированную карту США, окрашивающую разные состояния на основе набора данных.

этой SVG файл дает мне хорошую пустую карту США и очень легко изменить цвет каждого государства. Сложность в том, что браузеры IE не поддерживают SVG, поэтому для того, чтобы я мог использовать удобный синтаксис, который предлагает svg, мне нужно будет преобразовать его в JPG.

В идеале, я хотел бы сделать это только с GD2 библиотеки, но также может использовать ImageMagick. Я понятия не имею, как это сделать.

будет рассмотрено любое решение, которое позволит мне динамически изменять цвета государств на карте США. Ключ в том, что легко изменить цвета на лету и что это кросс-браузер. Только решения PHP / Apache, пожалуйста.

10 ответов


забавно, что вы спросили об этом, я недавно сделал это для сайта моей работы, и я думал, что должен написать учебник... Вот как это сделать с 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();

шаги regex замена цвета может варьироваться в зависимости от пути svg xml и как вы id & цвет значения хранятся. Если вы не хотите хранить файл на сервере, вы можете вывести изображение как базовый 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

отделка: enter image description here

редактировать

С момента написания выше, я придумал 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>

еще один очень быстрый и точный вариант-это безголовый браузер PhantomJS (webkit)

http://phantomjs.org/


вы упоминаете, что делаете это, потому что IE не поддерживает SVG.

хорошая новость в том, что IE тут поддержка векторной графики. Хорошо, это в форме языка под названием VML, который поддерживает только IE, а не SVG, но он есть, и вы можете его использовать.

Google Maps, среди прочего, обнаружит возможности браузера, чтобы определить, следует ли обслуживать SVG или VML.

тут Рафаил библиотека, который является Javascript браузерная графическая библиотека, которая поддерживает SVG или VML, опять же в зависимости от браузера.

еще один, который может помочь: SVGWeb.

все это означает, что вы можете поддерживать своих пользователей IE без необходимости прибегать к растровой графике.

см. также верхний ответ на этот вопрос, например:xsl преобразование SVG в VML


при преобразовании SVG в прозрачный PNG не забудьте поставить это перед $imagick - >readImageBlob ():

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

Это В. легко, делали работу над этим в течение последних нескольких недель.

вам нужно Batik SVG Toolkit. Скачать, и поместите файлы в тот же каталог, что и SVG, который вы хотите преобразовать в JPEG, также убедитесь, что вы распаковать сначала.

откройте терминал и выполните следующую команду:

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

это должно вывести JPEG файла SVG. Действительно простой. Вы даже можете просто поместить его в цикл и конвертировать нагрузки 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')

вы можете использовать библиотеку canvg js для преобразования SVG в PNG, больше информации здесь http://paksula.users.cs.helsinki.fi/svg_open_2010/demo.xhtml совместимость со всеми основными браузерами!

Я использую его в своем проекте и фактически преобразую SVG в PNG (с помощью PHP, чтобы сохранить файл, конечно)


Я не знаю автономного решения 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 демо :Tool4dev.com


Это метод преобразования изображения 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);

можно использовать Raphaël-Библиотека JavaScript и легко достигает ее. Он также будет работать в IE.