Converti un'immagine SVG in PNG con PHP


111

Sto lavorando a un progetto web che coinvolge una mappa generata dinamicamente degli Stati Uniti che colorano stati diversi sulla base di un insieme di dati.

Questo file SVG mi dà una buona mappa vuota degli Stati Uniti ed è molto facile cambiare il colore di ogni stato. La difficoltà è che i browser IE non supportano SVG, quindi per poter utilizzare la comoda sintassi offerta da svg, dovrò convertirlo in JPG.

Idealmente, mi piacerebbe farlo solo con la libreria GD2, ma potrei anche usare ImageMagick. Non ho assolutamente idea di come farlo.

Verrà presa in considerazione qualsiasi soluzione che mi consenta di cambiare dinamicamente i colori degli stati su una mappa degli Stati Uniti. La chiave è che è facile cambiare i colori al volo e che è cross browser. Solo soluzioni PHP / Apache, per favore.


ci sono classi progettate per portare SVG su VML? in questo modo potresti ancora avere una soluzione di tipo "HTML5"
Patrick

dai un'occhiata alla mia risposta. esattamente quello che ti serve

Risposte:


142

È divertente che tu l'abbia chiesto, l'ho appena fatto di recente per il sito del mio lavoro e stavo pensando di scrivere un tutorial ... Ecco come farlo con PHP / Imagick, che usa 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();

i passaggi regex sostituzione del colore possono variare a seconda del percorso svg xml e di come vengono memorizzati i valori di id e colore. Se non vuoi memorizzare un file sul server, puoi produrre l'immagine come 64 base come

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

(prima di usare cancella / distruggi) ma ha problemi con PNG come base64 quindi probabilmente dovresti generare base64 come jpeg

puoi vedere un esempio qui che ho fatto per la mappa del territorio di vendita di un ex datore di lavoro:

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

Finire: inserisci qui la descrizione dell'immagine

modificare

Da quando ho scritto quanto sopra, ho escogitato 2 tecniche migliorate:

1) invece di un ciclo regex per cambiare lo stato di riempimento, usa i CSS per creare regole di stile come

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

e poi puoi fare una singola sostituzione del testo per iniettare le tue regole CSS nell'SVG prima di procedere con la creazione di imagick jpeg / png. Se i colori non cambiano, assicurati di non avere stili di riempimento in linea nei tag del percorso che sovrascrivono il css.

2) Se non è necessario creare effettivamente un file immagine jpeg / png (e non è necessario supportare browser obsoleti), è possibile manipolare lo svg direttamente con jQuery. Non puoi accedere ai percorsi svg quando incorpori il file svg utilizzando i tag img o object, quindi dovrai includere direttamente l'xml svg nella tua pagina web html come:

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

quindi cambiare i colori è facile come:

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

1
Grazie per il tutorial molto preciso e utile su come farlo. Userò sicuramente la tua soluzione come backup, ma non vedo l'ora di provare e ottenere la compatibilità con svg su tutti i principali browser.
Michael Berkompas

1
SVG non è supportato in ie8 o versioni precedenti senza richiedere all'utente di installare un plug-in per il visualizzatore SVG - dalla pagina di Wikipedia SVG: "Tutti i principali browser Web moderni, supportano e rendono il markup SVG direttamente con la notevole eccezione di Microsoft Internet Explorer (IE) [ 3] La versione beta di Internet Explorer 9 supporta il set di funzionalità SVG di base. [4] Attualmente, anche il supporto per i browser con Android è limitato. "
WebChemist

1
Sì, ma svgweb sembra appianare tutte le incompatibilità usando un po 'di js e flash. Questa è la soluzione che ho scelto.
Michael Berkompas

2
Mi piace la tua soluzione pulita e veloce. Personalmente, quando interagisco con file xml, preferisco usare un parser dom per sentirmi più sicuro che con regex. Sth like:$dom = new DOMDocument(); $dom->loadXML( $svg ); $dom->getElementsByTagName('image')->item(0)->setAttribute('id', $state); $svg = $dom->saveXML();
Tapper

un parser xml sarebbe una soluzione più sicura, anche se leggermente più lenta, con qualsiasi altro svg ... in questo caso la regex è sicura perché mi sono assicurato che gli attributi di ogni stato fossero formattati esattamente come (id = "XX" style = "fill: # XXXXXX ").
WebChemist

11

Hai detto che lo stai facendo perché IE non supporta SVG.

La notizia buona è che IE fa la grafica support vector. Va bene, quindi è nella forma di un linguaggio chiamato VML che supporta solo IE, piuttosto che SVG, ma è lì e puoi usarlo.

Google Maps, tra gli altri, rileverà le capacità del browser per determinare se servire SVG o VML.

Poi c'è la libreria Raphael , che è una libreria grafica basata su browser Javascript, che supporta SVG o VML, sempre a seconda del browser.

Un altro che può aiutare: SVGWeb .

Tutto ciò significa che puoi supportare i tuoi utenti IE senza dover ricorrere alla grafica bitmap.

Vedi anche la risposta principale a questa domanda, ad esempio: XSL Trasforma SVG in VML


+1 per aver menzionato raphael, che è sicuramente una buona soluzione e vale la pena indagare per la sua eccellente implementazione della grafica vettoriale cross browser.
dmp

10

Quando converti SVG in PNG trasparente, non dimenticare di metterlo PRIMA $imagick->readImageBlob():

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

Com'è possibile chiamare quel metodo prima di leggere l'immagine, ricevo un errore "Impossibile elaborare un oggetto Imagick vuoto". E sì, la mia estensione imagick è installata mentre funziona e converte le immagini.
Denis2310

6

Questo è molto semplice, ci ho lavorato nelle ultime settimane.

Hai bisogno del Batik SVG Toolkit . Scarica e posiziona i file nella stessa directory dell'SVG che desideri convertire in JPEG , assicurati anche di decomprimerlo prima.

Apri il terminale ed esegui questo comando:

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

Questo dovrebbe produrre un JPEG del file SVG. Davvero facile. Puoi anche semplicemente inserirlo in un loop e convertire un sacco di 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')

Questo è fantastico. Grazie per il consiglio. Lo userò insieme a perl per processare in batch carichi di file SVG che ho creato da un modello.
simbabque

2

Non conosco una soluzione PHP / Apache standalone, poiché richiederebbe una libreria PHP in grado di leggere e visualizzare immagini SVG. Non sono sicuro che esista una libreria del genere, non ne conosco nessuna.

ImageMagick è in grado di rasterizzare i file SVG, tramite la riga di comando o l'associazione PHP, IMagick , ma sembra avere una serie di stranezze e dipendenze esterne come mostrato ad esempio in questo thread del forum . Penso che sia ancora la strada più promettente, è la prima cosa che esaminerei se fossi in te.


2

Questo è un metodo per convertire un'immagine SVG in GIF utilizzando gli strumenti GD standard di php

1) Metti l'immagine in un elemento canvas nel browser:

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

E poi convertilo sul server (ProcessPicture.php) da (predefinito) png a gif e salvalo. (potresti aver salvato anche come png, quindi usa imagepng invece di image 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);

o usando: potrace demo: Tool4dev.com

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.