Convertir imagen SVG a PNG con PHP
Estoy trabajando en un proyecto web que implica un mapa generado dinámicamente de los Estados Unidos coloreando diferentes estados basados en un conjunto de datos.
Este archivo SVG me da un buen mapa en blanco de los Estados Unidos y es muy fácil cambiar el color de cada estado. La dificultad es que los navegadores IE no son compatibles con SVG, por lo que para usar la sintaxis práctica que ofrece el svg, tendré que convertirlo a un JPG.
Idealmente, me gustaría hacer esto solo con la biblioteca GD2, pero también podría usar ImageMagick. No tengo ni 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 los Estados Unidos. La clave es que es fácil cambiar los colores sobre la marcha y que es cross browser. Solo soluciones PHP / Apache, por favor.
10 answers
Es gracioso 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í está 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 de reemplazo de color regex pueden variar dependiendo del xml de ruta svg y de cómo se almacenen los valores de id 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 clear / destroy) pero ie 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
Finish:
Editar
Desde que escribí lo anterior, se me han ocurrido 2 técnicas mejoradas:
1) en lugar de un bucle regex 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 solo reemplazo de texto para inyectar sus reglas css en el svg antes de continuar con la creación de imagick jpeg/png. Si los colores no cambian, asegúrate de no tener estilos de relleno en línea en tus etiquetas de ruta que anulen el css.
2) Si no tiene que crear realmente un archivo de imagen jpeg/png (y no necesita admitir navegadores obsoletos), puede manipular el svg directamente con jQuery. No se puede acceder a las rutas svg al incrustar el svg usando img o etiquetas de objeto, por lo que tendrá que incluir directamente el xml svg 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>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-31 16:34:44
Otra opción muy rápida y precisa es el navegador sin cabeza PhantomJS (webkit)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-31 02:18:13
Mencionas que estás haciendo esto porque IE no soporta SVG.
La buena noticia es que IE soporta gráficos vectoriales. Está bien, por lo que es en la forma de un lenguaje llamado VML que sólo IE soporta, en lugar de SVG, pero está allí, y se puede utilizar.
Google Maps, entre otros, detectará las capacidades del navegador para determinar si servir SVG o VML.
Luego está la biblioteca Raphael, que es una gráfica basada en browswer Javascript biblioteca, que soporta SVG o VML, de nuevo dependiendo del navegador.
Otro que puede ayudar: SVGWeb.
Todo lo cual significa que puede apoyar a sus usuarios de IE sin tener que recurrir a gráficos de mapa de bits.
Vea también la respuesta principal a esta pregunta, por ejemplo: XSL Transformar SVG a VML
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:42
Al convertir SVG a PNG transparente, no olvide poner esto ANTES DE imag imagick - >readImageBlob ():
$imagick->setBackgroundColor(new ImagickPixel('transparent'));
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-20 21:25:37
Este es v. easy, han estado trabajando en esto durante las últimas semanas.
Necesita el Batik SVG Toolkit. Descargue, y coloque los archivos en el mismo directorio que el SVG que desea convertir a JPEG , también asegúrese de descomprimirlo primero.
Abra la terminal y ejecute este comando:
java -jar batik-rasterizer.jar -m image/jpeg -q 0.8 NAME_OF_SVG_FILE.svg
Que debería generar un JPEG del archivo SVG. Muy fácil. Incluso puede simplemente colocarlo en un bucle y convertir cargas de SVGs,
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')
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-12 23:28:59
Puede usar la biblioteca canvg js para convertir el SVG a PNG, más información aquí http://paksula.users.cs.helsinki.fi/svg_open_2010/demo.xhtml compatible con todos los principales navegadores!
Lo estoy usando en mi proyecto y realmente convierte el SVG en PNG (con la ayuda de PHP para guardar el archivo, por supuesto)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-27 01:13:26
No conozco una solución PHP / Apache independiente, ya que esto requeriría una biblioteca PHP que pueda leer y renderizar imágenes SVG. No estoy seguro de que exista tal biblioteca - no conozco ninguna.
ImageMagick es capaz de rasterizar archivos SVG, ya sea a través de la línea de comandos o el enlace PHP, IMagick , pero parece tener una serie de peculiaridades y dependencias externas como se muestra, por ejemplo, en este hilo del foro . Creo que sigue siendo el camino más prometedor a seguir, es el primero cosa que yo investigaría si fuera tú.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-26 19:47: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);
O usando: potrace demo: Tool4dev.com
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-07 05:46:50
Este es un método para convertir una imagen svg a un gif utilizando herramientas estándar de php GD
1) Pones la imagen en un elemento canvas 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 convertirlo en el servidor (ProcessPicture.php) desde (por defecto) png a gif y guardarlo. (también podría haber guardado como png y luego usar imagepng en lugar de 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);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-31 11:58:24
Puedes usar Raphaël-JavaScript Library y lograrlo fácilmente. También funcionará en IE.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-26 11:59:57