Convertir una imagen SVG a PNG con PHP
Estoy trabajando en un proyecto web que involucra un mapa generado dinámicamente de los EE. UU. coloreando diferentes estados en función de un conjunto de datos.
Este archivo SVG me brinda un buen mapa en blanco de los EE. UU. y es muy fácil cambiar el color de cada estado. La dificultad es que los navegadores IE no admiten SVG, por lo que para poder utilizar la práctica sintaxis que ofrece SVG, tendré que convertirlo a JPG.
Idealmente, me gustaría hacer esto solo con la biblioteca GD2 pero también podría usar ImageMagick. No tengo absolutamente ninguna idea de cómo hacer esto.
Se considerará cualquier solución que me permita cambiar dinámicamente los colores de los estados en un mapa de EE. UU. La clave es que es fácil cambiar los colores sobre la marcha y que es compatible con varios navegadores. Sólo soluciones PHP/Apache, por favor.
Es curioso que hayas preguntado esto, acabo de hacer esto recientemente para el sitio de mi trabajo y estaba pensando que debería escribir un tutorial... Aquí se explica cómo hacerlo con PHP/Imagick, que 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();
Los pasos para reemplazar el color de expresiones regulares pueden variar según el xml de la ruta svg y cómo se almacenan los valores de identificación y color. Si no desea almacenar un archivo en el servidor, puede generar la imagen como base 64 como
<?php echo '<img src="data:image/jpg;base64,' . base64_encode($im) . '" />';?>
(antes de usar borrar/destruir), pero es decir, tiene problemas con PNG como base64, por lo que probablemente tendría que generar base64 como jpeg.
Puedes ver un ejemplo aquí que hice para el mapa del territorio de ventas de un antiguo empleador:
Inicio: https://upload.wikimedia.org/wikipedia/commons/1/1a/Blank_US_Map_(states_only).svg
Finalizar:
Editar
Desde que escribí lo anterior, se me ocurrieron 2 técnicas mejoradas:
1) en lugar de un bucle de expresiones regulares para cambiar el estado de relleno, use CSS para crear reglas de estilo como
<style type="text/css">
#CA,#FL,HI{
fill:blue;
}
#Al, #NY, #NM{
fill:#cc6699;
}
/*etc..*/
</style>
y luego puede hacer un reemplazo de texto único para inyectar sus reglas CSS en el svg antes de continuar con la creación de imagick jpeg/png. Si los colores no cambian, verifique que no tenga ningún estilo de relleno en línea en las etiquetas de ruta que anule el CSS.
2) Si no tiene que crear un archivo de imagen jpeg/png (y no necesita admitir navegadores obsoletos), puede manipular el svg directamente con jQuery. No puede acceder a las rutas de svg al incrustar el svg usando etiquetas img o de objeto, por lo que tendrá que incluir directamente el svg xml en el html de su página web como:
<div>
<?php echo file_get_contents('/path/to/blank/us-map.svg');?>
</div>
entonces cambiar los colores es tan fácil como:
<script type="text/javascript" src="/path/to/jquery.js"></script>
<script type="text/javascript">
$('#CA').css('fill', 'blue');
$('#NY').css('fill', '#ff0000');
</script>
Al convertir SVG a PNG transparente, no olvides poner esto ANTES $imagick->readImageBlob()
:
$imagick->setBackgroundColor(new ImagickPixel('transparent'));
Mencionas que estás haciendo esto porque IE no es compatible con SVG.
La buena noticia es que IE admite gráficos vectoriales. Bien, está en forma de un lenguaje llamado VML que sólo admite IE, en lugar de SVG, pero está ahí y puedes usarlo.
Google Maps, entre otros, detectará las capacidades del navegador para determinar si debe servir SVG o VML.
Luego está la biblioteca Raphael , que es una biblioteca de gráficos basada en navegador Javascript, que admite SVG o VML, nuevamente dependiendo del navegador.
Otro que puede ayudar: SVGWeb .
Todo lo cual significa que puede brindar soporte a sus usuarios de IE sin tener que recurrir a gráficos de mapa de bits.
Consulte también la respuesta principal a esta pregunta, por ejemplo: XSL Transformar SVG a VML
Este es un método para convertir una imagen svg a un gif usando herramientas estándar de PHP GD
1) Colocas la imagen en un elemento de lienzo en el navegador:
<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>
Y luego conviértalo en el servidor (ProcessPicture.php) de png (predeterminado) a gif y guárdelo. (también podrías haber guardado como png y luego usar imagepng en lugar de imagen 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);