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

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

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

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

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

Ответ 1

Забавно, что вы спросили об этом, я недавно сделал это для своего рабочего сайта и подумал, что должен написать учебник... Вот как это сделать с помощью 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) . '"  />';?>

(прежде чем использовать очистку/уничтожение), но есть проблемы с PNG в качестве base64, поэтому вам, вероятно, придется выводить base64 в виде jpeg

Вы можете увидеть пример, который я сделал для карты территории бывшего работодателя:

Начало: https://upload.wikimedia.org/wikipedia/commons/1/1a/Blank_US_Map_(states_only).svg

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>

Ответ 2

Другим очень быстрым и точным вариантом является безголовый браузер PhantomJS (webkit)

http://phantomjs.org/

Ответ 3

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

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

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

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

Другой, который может помочь: SVGWeb.

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

См. также главный ответ на этот вопрос, например: XSL Преобразование SVG в VML

Ответ 4

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

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

Ответ 5

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

Вам нужен 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')

Ответ 6

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

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

Ответ 7

Я не знаю отдельного решения PHP/Apache, поскольку для этого потребуется библиотека PHP, которая может читать и отображать SVG-изображения. Я не уверен, что такая библиотека существует - я не знаю.

ImageMagick способен растеризовать файлы SVG либо через командную строку, либо через привязку PHP, IMagick, но, похоже, имеет ряд причуд и внешних зависимостей, как показано, например в этот форум. Я думаю, что это все еще самый многообещающий путь, это первое, на что я бы посмотрел, если бы я был вами.

Ответ 8

Это метод преобразования svg-изображения в gif с использованием стандартных инструментов gp php

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

Ответ 9

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

Ответ 10

$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