Перетворення SVG-зображення в PNG за допомогою PHP


111

Я працюю над веб-проектом, який передбачає динамічно генеровану карту розфарбовування США різних станів на основі набору даних.

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

В ідеалі я хотів би зробити це лише з бібліотекою GD2, але також міг би використовувати ImageMagick. У мене абсолютно немає поняття, як це зробити.

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


чи існують класи, призначені для перенесення SVG на VML? таким чином у вас все ще може бути рішення типу HTML5
Патрік

погляньте на мою відповідь. саме те, що вам потрібно

Відповіді:


142

Це смішно, що ви це запитували, я недавно це робив для сайту своєї роботи, і я думав, що слід написати підручник ... Ось як це зробити за допомогою 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 та того, як зберігаються значення id & color. Якщо ви не хочете зберігати файл на сервері, ви можете вивести зображення як базове 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

Фініш: введіть тут опис зображення

Редагувати

З моменту написання вищесказаного я придумав 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>

1
Дякуємо за дуже точний та корисний підручник, як це зробити. Я, звичайно, буду використовувати ваше рішення в якості резервної копії, але я хочу спробувати і просто отримати сумісність svg у всіх основних браузерах.
Майкл Беркомпас

1
SVG не підтримується в ie8 або нижче, не вимагаючи від користувача встановлення плагіна для перегляду svg - із сторінки SVG Wikipedia: "Усі основні сучасні веб-браузери підтримують та надають розмітку SVG безпосередньо за дуже помітним винятком Microsoft Internet Explorer (IE) [ 3] Бета-версія Internet Explorer 9 підтримує основний набір функцій SVG. [4] Наразі підтримка браузерів, що працюють під управлінням Android, також обмежена ".
WebChemist

1
Так, але, схоже, svgweb видаляє всі несумісності, використовуючи трохи js та flash. Це рішення, з яким я пішов.
Майкл Беркомпас

2
Мені подобається ваше чисте і швидке рішення. Особисто під час взаємодії з xml-файлами я вважаю за краще використовувати dom parser, щоб відчувати себе безпечніше, ніж з регулярним виразом. Sth like:$dom = new DOMDocument(); $dom->loadXML( $svg ); $dom->getElementsByTagName('image')->item(0)->setAttribute('id', $state); $svg = $dom->saveXML();
Tapper

аналізатор xml був би більш безпечним, хоча і дещо повільнішим, рішенням з будь-яким іншим svg ... в цьому випадку регулярний вимір є безпечним, оскільки я переконався, що атрибути кожного стану були відформатовані саме так (id = "XX" style = "fill: # XXXXXX ").
WebChemist

11

Ви згадуєте, що це робите, тому що IE не підтримує SVG.

Гарна новина полягає в тому, що IE робить підтримку векторної графіки. Гаразд, значить, це у формі мови під назвою VML, яка підтримує лише IE, а не SVG, але вона є, і ви можете нею користуватися.

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

Потім є бібліотека Raphael , що є графічною бібліотекою на основі браузера Javascript, яка підтримує або SVG, або VML, знову залежно від браузера.

Ще один, який може допомогти: SVGWeb .

Все це означає, що ви можете підтримувати своїх користувачів IE, не вдаючись до растрової графіки.

Дивіться також верхню відповідь на це питання, наприклад: XSL Перетворіть SVG у VML


+1 для згадки про рафаелі, що, безумовно, є хорошим рішенням і варто вивчити його на відмінну реалізацію крос-браузерної векторної графіки.
dmp

10

Перетворюючи SVG в прозорий PNG, не забудьте поставити це ДО ПЕРЕД $imagick->readImageBlob():

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

Як це можливо викликати цим методом перед читанням зображення, я отримую помилку "Не можу обробити порожній об'єкт Imagick". І так, моє розширення imagick встановлено як воно працює, так і перетворює зображення.
Denis2310

6

Це легко, останні кілька тижнів роблять роботу над цим.

Вам потрібен інструментарій Batik SVG . Завантажте та розмістіть файли у тому самому каталозі, що і 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')

Це чудово. Дякую за пораду. Я буду використовувати його спільно з perl для пакетного завантаження файлів SVG, створених із шаблону.
simbabque

2

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

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


2

Це спосіб перетворення SVG-картинки в gif за допомогою стандартних інструментів php GD

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


-1
$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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.