cairosvg python svg rendering cairo

python - cairosvg install ubuntu



Convierte SVG a PNG en Python (9)

Escalado SVG y representación PNG

Usando pycairo y librsvg pude lograr escalar SVG y renderizar en un mapa de bits. Suponiendo que su SVG no sea exactamente 256x256 píxeles, el resultado deseado, puede leer en el SVG a un contexto de El Cairo utilizando rsvg y luego escalarlo y escribir en un archivo PNG.

main.py

import cairo import rsvg width = 256 height = 256 svg = rsvg.Handle(''cool.svg'') unscaled_width = svg.props.width unscaled_height = svg.props.height svg_surface = cairo.SVGSurface(None, width, height) svg_context = cairo.Context(svg_surface) svg_context.save() svg_context.scale(width/unscaled_width, height/unscaled_height) svg.render_cairo(svg_context) svg_context.restore() svg_surface.write_to_png(''cool.png'')

Enlace RSVG C

Desde el sitio web de Cario con algunas modificaciones menores. También es un buen ejemplo de cómo llamar a una biblioteca C desde Python

from ctypes import CDLL, POINTER, Structure, byref, util from ctypes import c_bool, c_byte, c_void_p, c_int, c_double, c_uint32, c_char_p class _PycairoContext(Structure): _fields_ = [("PyObject_HEAD", c_byte * object.__basicsize__), ("ctx", c_void_p), ("base", c_void_p)] class _RsvgProps(Structure): _fields_ = [("width", c_int), ("height", c_int), ("em", c_double), ("ex", c_double)] class _GError(Structure): _fields_ = [("domain", c_uint32), ("code", c_int), ("message", c_char_p)] def _load_rsvg(rsvg_lib_path=None, gobject_lib_path=None): if rsvg_lib_path is None: rsvg_lib_path = util.find_library(''rsvg-2'') if gobject_lib_path is None: gobject_lib_path = util.find_library(''gobject-2.0'') l = CDLL(rsvg_lib_path) g = CDLL(gobject_lib_path) g.g_type_init() l.rsvg_handle_new_from_file.argtypes = [c_char_p, POINTER(POINTER(_GError))] l.rsvg_handle_new_from_file.restype = c_void_p l.rsvg_handle_render_cairo.argtypes = [c_void_p, c_void_p] l.rsvg_handle_render_cairo.restype = c_bool l.rsvg_handle_get_dimensions.argtypes = [c_void_p, POINTER(_RsvgProps)] return l _librsvg = _load_rsvg() class Handle(object): def __init__(self, path): lib = _librsvg err = POINTER(_GError)() self.handle = lib.rsvg_handle_new_from_file(path.encode(), byref(err)) if self.handle is None: gerr = err.contents raise Exception(gerr.message) self.props = _RsvgProps() lib.rsvg_handle_get_dimensions(self.handle, byref(self.props)) def get_dimension_data(self): svgDim = self.RsvgDimensionData() _librsvg.rsvg_handle_get_dimensions(self.handle, byref(svgDim)) return (svgDim.width, svgDim.height) def render_cairo(self, ctx): """Returns True is drawing succeeded.""" z = _PycairoContext.from_address(id(ctx)) return _librsvg.rsvg_handle_render_cairo(self.handle, z.ctx)

¿Cómo convierto un svg a png en Python? Estoy almacenando el svg en una instancia de StringIO . ¿Debería usar la biblioteca pyCairo? ¿Cómo escribo ese código?


Aquí hay un ejemplo de Python de extremo a extremo.

Tenga en cuenta que suprime ciertos resultados crudos que Inkscape escribe en la consola (específicamente, stderr y stdout) durante el funcionamiento normal sin errores. La salida se captura en dos variables de cadena, out y err .

import subprocess # May want to use subprocess32 instead cmd_list = [ ''/full/path/to/inkscape'', ''-z'', ''--export-png'', ''/path/to/output.png'', ''--export-width'', 100, ''--export-height'', 100, ''/path/to/input.svg'' ] # Invoke the command. Divert output that normally goes to stdout or stderr. p = subprocess.Popen( cmd_list, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) # Below, < out > and < err > are strings or < None >, derived from stdout and stderr. out, err = p.communicate() # Waits for process to terminate # Maybe do something with stdout output that is in < out > # Maybe do something with stderr output that is in < err > if p.returncode: raise Exception( ''Inkscape error: '' + (err or ''?'') )

Por ejemplo, cuando ejecuté un trabajo en particular en mi sistema Mac OS, terminé siendo:

Background RRGGBBAA: ffffff00 Area 0:0:339:339 exported to 100 x 100 pixels (72.4584 dpi) Bitmap saved as: /path/to/output.png

(El archivo svg de entrada tenía un tamaño de 339 por 339 píxeles).


Esto es lo que hice usando cairosvg :

from cairosvg import svg2png svg_code = """ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="10"/> <line x1="12" y1="8" x2="12" y2="12"/> <line x1="12" y1="16" x2="12" y2="16"/> </svg> """ svg2png(bytestring=svg_code,write_to=''output.png'')

¡Y funciona como un encanto!

Ver más: documento de cairosvg


Estoy usando Wand-py (una implementación de Wand wrapper alrededor de ImageMagick) para importar algunos SVG bastante avanzados y ¡hasta ahora hemos visto excelentes resultados! Este es todo el código que toma:

with wand.image.Image( blob=svg_file.read(), format="svg" ) as image: png_image = image.make_blob("png")

Acabo de descubrir esto hoy, y sentí que valía la pena compartirlo con cualquier otra persona que pudiera regatear esta respuesta, ya que ha pasado un tiempo desde que se respondieron la mayoría de estas preguntas.

NOTA: Técnicamente en las pruebas descubrí que ni siquiera tiene que pasar el parámetro de formato para ImageMagick, por lo que with wand.image.Image( blob=svg_file.read() ) as image: era todo lo que realmente se necesitaba.

EDITAR: A partir de un intento de edición por qris, aquí hay un código útil que le permite usar ImageMagick con un SVG que tiene un fondo transparente:

from wand.api import library import wand.color import wand.image with wand.image.Image() as image: with wand.color.Color(''transparent'') as background_color: library.MagickSetBackgroundColor(image.wand, background_color.resource) image.read(blob=svg_file.read(), format="svg") png_image = image.make_blob("png32") with open(output_filename, "wb") as out: out.write(png_image)


Instala Inkscape y llámalo como línea de comando:

${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -j -e ${dest_png}

También puede ajustar el área rectangular específica solo usando el parámetro -j , por ejemplo, la coordenada "0: 125: 451: 217"

${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -j -a ${coordinates} -e ${dest_png}

Si desea mostrar solo un objeto en el archivo SVG, puede especificar el parámetro -i con el ID del objeto que ha configurado en el SVG. Oculta todo lo demás.

${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -i ${object} -j -a ${coordinates} -e ${dest_png}


La respuesta es " pyrsvg " - un enlace de Python para librsvg .

Existe un paquete Ubuntu python-rsvg que lo proporciona. Buscar su nombre en Google es pobre porque su código fuente parece estar contenido dentro del repositorio GIT del proyecto Gnome "gnome-python-desktop".

Hice un "mundo de hola" minimalista que convierte a SVG en una superficie de cairo y lo escribe en el disco:

import cairo import rsvg img = cairo.ImageSurface(cairo.FORMAT_ARGB32, 640,480) ctx = cairo.Context(img) ## handle = rsvg.Handle(<svg filename>) # or, for in memory SVG data: handle= rsvg.Handle(None, str(<svg data>)) handle.render_cairo(ctx) img.write_to_png("svg.png")

Actualización : a partir de 2014, el paquete necesario para la distribución de Fedora Linux es: gnome-python2-rsvg . El listado de fragmentos anterior todavía funciona tal como está.


Otra solución que acabo de encontrar aquí ¿Cómo renderizar un SVG escalado a una QImage?

from PySide.QtSvg import * from PySide.QtGui import * def convertSvgToPng(svgFilepath,pngFilepath,width): r=QSvgRenderer(svgFilepath) height=r.defaultSize().height()*width/r.defaultSize().width() i=QImage(width,height,QImage.Format_ARGB32) p=QPainter(i) r.render(p) i.save(pngFilepath) p.end()

PySide se instala fácilmente desde un paquete binario en Windows (y lo uso para otras cosas, así que es fácil para mí).

Sin embargo, noté algunos problemas al convertir banderas de países de Wikimedia, por lo que quizás no sea el analizador / procesador de svg más robusto.


Pruebe esto: cairosvg

El sitio dice:

CairoSVG está escrito en python puro y solo depende de Pycairo. Se sabe que funciona en Python 2.6 y 2.7.

Actualización 25 de noviembre de 2016 :

2.0.0 es una nueva versión principal, su registro de cambios incluye:

  • Soporte de Drop Python 2

Una pequeña extensión sobre la respuesta de jsbueno:

#!/usr/bin/env python import cairo import rsvg from xml.dom import minidom def convert_svg_to_png(svg_file, output_file): # Get the svg files content with open(svg_file) as f: svg_data = f.read() # Get the width / height inside of the SVG doc = minidom.parse(svg_file) width = int([path.getAttribute(''width'') for path in doc.getElementsByTagName(''svg'')][0]) height = int([path.getAttribute(''height'') for path in doc.getElementsByTagName(''svg'')][0]) doc.unlink() # create the png img = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) ctx = cairo.Context(img) handler = rsvg.Handle(None, str(svg_data)) handler.render_cairo(ctx) img.write_to_png(output_file) if __name__ == ''__main__'': from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument("-f", "--file", dest="svg_file", help="SVG input file", metavar="FILE") parser.add_argument("-o", "--output", dest="output", default="svg.png", help="PNG output file", metavar="FILE") args = parser.parse_args() convert_svg_to_png(args.svg_file, args.output)