web-dev-qa-db-fra.com

Convertir une image SVG en PNG avec PHP

Je travaille sur un projet Web qui implique une carte générée dynamiquement des États-Unis coloriant différents états en fonction d'un ensemble de données. 

Ce fichier SVG me donne une bonne carte vierge des États-Unis et permet très facilement de changer la couleur de chaque état. La difficulté est que les navigateurs IE ne supportent pas le SVG, donc pour que je puisse utiliser la syntaxe pratique que propose svg, je devrai le convertir en JPG. 

Idéalement, j'aimerais faire cela uniquement avec la bibliothèque Gd2, mais je pourrais aussi utiliser ImageMagick. Je n'ai absolument aucune idée de comment faire cela. 

Toute solution qui me permettrait de changer dynamiquement les couleurs des États sur une carte des États-Unis sera considérée. La clé est qu'il est facile de changer les couleurs à la volée et que c'est un navigateur croisé. Solutions PHP/Apache uniquement, s'il vous plaît.

98
Michael Berkompas

C'est marrant que vous demandiez ceci, je viens de le faire récemment pour le site de mon travail et je pensais que je devrais écrire un tutoriel ... Voici comment le faire avec PHP/Imagick, qui utilise 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();

les étapes de remplacement de la couleur regex peuvent varier en fonction du chemin svg xml et de la façon dont vous stockez les valeurs id & color. Si vous ne voulez pas stocker de fichier sur le serveur, vous pouvez sortir l’image en base 64 comme

<?php echo '<img src="data:image/jpg;base64,' . base64_encode($im) . '"  />';?>

(avant d’utiliser clear/destroy) mais c’est-à-dire qu’il a des problèmes avec PNG en tant que base64, vous devrez donc probablement générer une sortie en base64 en jpeg

vous pouvez voir un exemple ici que j'ai fait pour la carte du territoire de vente d'un ancien employeur:

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

Terminer: enter image description here

Modifier

Depuis que j'ai écrit ce qui précède, j'ai mis au point deux techniques améliorées:

1) Au lieu d’une boucle regex pour changer l’état de remplissage, utilisez CSS pour créer des règles de style telles que 

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

et ensuite vous pouvez remplacer un texte par un simple texte afin d’injecter vos règles CSS dans le svg avant de procéder à la création d’Imagick jpeg/png. Si les couleurs ne changent pas, assurez-vous de ne pas avoir de styles de remplissage en ligne dans vos balises de chemin remplaçant le css.

2) Si vous n'avez pas besoin de créer un fichier image jpeg/png (et n'avez pas besoin de prendre en charge des navigateurs obsolètes), vous pouvez manipuler le svg directement avec jQuery. Vous ne pouvez pas accéder aux chemins svg lors de l'incorporation de svg à l'aide de balises img ou object. Vous devez donc inclure directement le xml svg dans votre page Web html, comme:

<div>
<?php echo file_get_contents('/path/to/blank/us-map.svg');?>
</div>

puis changer les couleurs est aussi simple que:

<script type="text/javascript" src="/path/to/jquery.js"></script>
<script type="text/javascript">
    $('#CA').css('fill', 'blue');
    $('#NY').css('fill', '#ff0000');
</script>
128
WebChemist

Le navigateur sans tête PhantomJS (Webkit) est une autre option très rapide et précise.

http://phantomjs.org/

17
atomicjeep

Vous dites que vous le faites parce que IE ne prend pas en charge SVG.

La bonne nouvelle est que IE ne prend en charge les graphiques vectoriels. D'accord, c'est donc sous la forme d'un langage appelé VML que seul IE prend en charge, plutôt que SVG, mais il est là et vous pouvez l'utiliser.

Google Maps, entre autres, détectera les capacités du navigateur pour déterminer s'il convient de servir du SVG ou du VML.

Ensuite, il y a la bibliothèque Raphael , qui est une bibliothèque graphique basée sur un navigateur Javascript, qui prend en charge SVG ou VML, toujours selon le navigateur.

Un autre qui peut aider: SVGWeb .

Cela signifie que vous pouvez prendre en charge vos utilisateurs IE sans avoir à recourir aux graphiques bitmap.

Voir aussi la réponse principale à cette question, par exemple: XSL Transformer SVG en VML

11
Spudley

Lors de la conversion de SVG en PNG transparent, n'oubliez pas de mettre ceci AVANT $ imagick-> readImageBlob ():

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

C’est très facile, nous travaillons dans ce domaine depuis quelques semaines. 

Vous avez besoin du Batik SVG Toolkit . Téléchargez et placez les fichiers dans le même répertoire que le fichier SVG que vous souhaitez convertir en JPEG. Assurez-vous également de le décompresser.

Ouvrez le terminal et lancez cette commande:

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

Cela devrait générer un fichier JPEG du fichier SVG. Vraiment facile. Vous pouvez même simplement le placer dans une boucle et convertir des charges de 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
user179169

vous pouvez utiliser la bibliothèque canvg js pour convertir le fichier SVG en fichier PNG. Pour plus d'informations, cliquez ici http://paksula.users.cs.helsinki.fi/svg_open_2010/demo.xhtml compatible avec tous les principaux navigateurs!

Je l'utilise dans mon projet et convertit le SVG en PNG (avec l'aide de PHP pour sauvegarder le fichier bien sûr)

3
razor7

Je ne connais pas de solution autonome PHP/Apache, car cela nécessiterait une bibliothèque PHP capable de lire et de restituer des images SVG. Je ne suis pas sûr qu'une telle bibliothèque existe - je n'en connais aucune.

ImageMagick est capable de rastériser les fichiers SVG, via la ligne de commande ou la liaison PHP, IMagick , mais semble avoir un certain nombre de bizarreries et de dépendances externes, comme le montre l'exemple dans ce fil de discussion . Je pense que c'est toujours la voie la plus prometteuse, c'est la première chose que je vérifierais si j'étais toi. 

2
Pekka 웃

Ceci est une méthode pour convertir une image svg en gif en utilisant les outils php Gd standard

1) Vous mettez l'image dans un élément de la toile dans le navigateur:

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

Puis convertissez-le sur le serveur (ProcessPicture.php) de png (par défaut) en gif et enregistrez-le. (vous auriez aussi pu enregistrer en png, puis utilisez imagepng au lieu de 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);
0
oleviolin