2011-01-26 159 views
92

Estoy trabajando en un proyecto web que involucra un mapa generado dinámicamente de los Estados Unidos para colorear diferentes estados según un conjunto de datos.Convertir imagen SVG a PNG con PHP

Este archivo SVG me da 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 son compatibles con SVG, así que para poder usar la útil sintaxis que svg ofrece, 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 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 EE. UU. La clave es que es fácil cambiar los colores sobre la marcha y que es un navegador cruzado. Solo soluciones PHP/Apache, por favor.

+0

¿existen clases diseñadas para puerto de SVG a VML? de esa manera, aún podría tener una solución tipo 'HTML5' – Patrick

+0

eche un vistazo a mi respuesta. exactamente lo que necesita –

Respuesta

115

Que gracioso que hizo esta, que 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 ImageMagick: sustitución de color

$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(); 

la expresión regular pasos puede variar dependiendo de la ruta SVG XML y cómo se almacenan los valores de color le Identificación &.Si no desea almacenar un archivo en el servidor, puede enviar la imagen como base 64 como

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

(antes de utilizar claro/destruir), pero es decir, tiene problemas con el PNG como base 64 por lo que tendría probablemente tendrá que base 64 de salida como JPEG

se puede ver un ejemplo aquí que hice para un mapa del territorio de ventas un empleador anterior:

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

Acabado: enter image description here

Edición

Después de haber escrito lo anterior, se me ha ocurrido con 2 técnicas mejoradas:

1) en lugar de un bucle de expresiones regulares para cambiar el relleno en el estado , 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 texto reemplazar inyecto Sigue tus reglas de CSS en svg antes de continuar con la creación de imagick jpeg/png. Si los colores no cambian, verifique que no haya ningún estilo de relleno en línea en las etiquetas de su ruta que sobrescriban el CSS.

2) Si no tiene que crear realmente un archivo de imagen jpeg/png (y no necesita admitir navegadores desactualizados), puede manipular el svg directamente con jQuery. No se puede acceder a los caminos SVG al incrustar el SVG usando las etiquetas img u objeto, por lo que tendrá que incluir directamente el XML SVG en su página web HTML como:

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

a continuación, 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> 
+1

Gracias por el tutorial muy exacto y útil sobre cómo hacer esto. Ciertamente utilizaré su solución como respaldo, pero estoy ansioso por probar y obtener la compatibilidad svg en todos los principales navegadores. –

+1

SVG no es compatible en ie8 o inferior sin requerir que el usuario instale un plugin svg viewer - desde la página de SVG Wikipedia: "Todos los principales navegadores web modernos, admiten y renderizan SVG directamente con la notable excepción de Microsoft Internet Explorer (IE) [3] Internet Explorer 9 beta es compatible con el conjunto de características básicas de SVG. [4] Actualmente, la compatibilidad con los navegadores que se ejecutan en Android también es limitada ". – WebChemist

+1

Sí, pero svgweb parece eliminar todas las incompatibilidades usando un poco de js y flash. Esa es la solución con la que fui. –

2

No conozco una solución PHP/Apache independiente, ya que esto requeriría una biblioteca PHP que pueda leer y representar imágenes SVG. No estoy seguro de que exista tal biblioteca, no sé ninguna.

ImageMagick es capaz de rasterizar los archivos SVG, ya sea a través de la línea de comandos o el PHP unión, IMagick, pero parece tener una serie de peculiaridades y dependencias externas como se muestra, por ejemplo, en this forum thread. Creo que todavía es la forma más prometedora de ir, es lo primero que vería si fuera tú.

+0

+1 Esta sería la respuesta simple y la mejor. –

11

Menciona que está haciendo esto porque IE no es compatible con SVG.

La buena noticia es que IE hace gráficos vectoriales de soporte. Está bien, así que está en la forma de un lenguaje llamado VML que solo IE soporta, en lugar de SVG, pero está ahí, y puedes usarlo.

Google Maps, entre otros, detectará las capacidades del navegador para determinar si sirve SVG o VML.

Luego está el Raphael library, que es una biblioteca de gráficos basada en browswer de Javascript, que admite SVG o VML, nuevamente 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.

Véase también la respuesta más común a esta pregunta, por ejemplo: XSL Transform SVG to VML

+0

+1 por mencionar a Rafael, que definitivamente es una buena solución y vale la pena investigar por su excelente implementación de gráficos vectoriales cruzados. – dmp

5

Esto es v. Fácil, he 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.

abrir el terminal, y ejecute este comando:

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

Eso debería devolver un archivo JPEG del archivo SVG. Realmente fácil. Puede incluso sólo lo coloca en un bucle y convertir cargas de IVS,

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') 
+0

Esto es genial. Gracias por el consejo. Voy a usarlo junto con perl para procesar por lotes cargas de archivos SVG que he creado a partir de una plantilla. – simbabque

16

Otra & opción precisa muy rápido es el PhantomJS navegador sin cabeza (WebKit)

http://phantomjs.org/

+1

Después de probar Batik, Imagemagick y algunas soluciones basadas en web, phantomjs fue la única forma de corregir lo siguiente: recorte, enmascaramiento, efectos de filtro, foreignObject (e incluso el contenido html que se colocó delante de svg). Realmente puedo recomendar esto! –

3

podría utilizar canvg js biblioteca para convertir el SVG en PNG, más información aquí http://paksula.users.cs.helsinki.fi/svg_open_2010/demo.xhtml compatible con todos los navegadores más importantes!

lo estoy usando en mi proyecto y, de hecho convierte el SVG en PNG (con la ayuda de PHP para guardar el archivo, por supuesto)

+1

enlace roto :-( –

+1

Creo que este violín debe hacer el trabajo http://jsfiddle.net/plaliberte/HAXyd/ y aquí está la página de código fuente de canvg https://code.google.com/p/canvg/ – razor7

6

Al convertir SVG a PNG transparente, no se olvide de poner esto ANTES $ imagick-> readImageBlob():

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

puede utilizar Raphaël—JavaScript Library y alcanzar fácilmente. Funcionará en IE también.

+2

Agregar detalles presentes en el enlace. El enlace puede romperse en cualquier momento –

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