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.

Author: Willi Mentzel, 2011-01-26

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: introduzca la descripción de la imagen aquí

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>
 120
Author: WebChemist,
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)

Http://phantomjs.org/

 17
Author: atomicjeep,
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

 11
Author: Spudley,
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'));
 6
Author: psycho brm,
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')
 5
Author: Willi Mentzel,
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)

 3
Author: razor7,
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ú.

 2
Author: Pekka 웃,
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

 0
Author: Thành NV,
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);
 0
Author: oleviolin,
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.

 -1
Author: Lokesh Kumar Ravi,
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