Как преобразовать svg
в png
в Python? Я сохраняю svg
в экземпляре StringIO
. Должен ли я использовать библиотеку pyCairo? Как написать этот код?
Ответ: pyrsvg "- привязка Python для librsvg.
Существует пакет Ubuntu python-rsvg, предоставляющий его. Поиск Google для его имени является плохим, потому что его исходный код, похоже, содержится внутри репозитория проекта gnome-python-desktop Gnome GIT.
Я сделал минималистский "мир привет", который превращает SVG в каир и записывает его на диск:
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")
Обновить: с 2014 года необходимый пакет для дистрибутива Fedora Linux: gnome-python2-rsvg
. Вышеприведенный список фрагментов все еще работает как есть.
cairo
самостоятельно определять высоту и ширину изображения? Я заглянул в файл *.svg
, чтобы извлечь оттуда ВЫСОТУ и ШИРИНУ, но оба значения установлены на 100%
. Конечно, я могу посмотреть на свойства картинки, но так как это только один шаг в обработке изображений, это не то, что я хочу.
.get_dimension_data()
который работал для моего файла примера (SVG с хорошим поведением) - попробуйте.
Вот что я использовал 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')
И это работает как шарм!
Подробнее: cairosvg document
svg2png
принимает объект stream
в параметре write_to
, и это может быть как ваш объект HTTP Response. (который в большинстве фреймворков является объектоподобным объектом) или какой-то другой поток, который вы затем передаете в браузер с помощью заголовка Content-Disposition
. смотрите здесь: stackoverflow.com/questions/1012437/…
Установите Inkscape и вызовите его как командную строку:
${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -j -e ${dest_png}
Вы также можете привязать определенную прямоугольную область только с помощью параметра -j
, например. координировать "0: 125: 451: 217"
${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -j -a ${coordinates} -e ${dest_png}
Если вы хотите показать только один объект в SVG файле, вы можете указать параметр -i
с идентификатором объекта, который вы установили в SVG. Он скрывает все остальное.
${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -i ${object} -j -a ${coordinates} -e ${dest_png}
Я использую Wand-py (реализация оболочки Wand вокруг ImageMagick) для импорта некоторых довольно продвинутых SVG и до сих пор видел отличные результаты! Это все код, который требуется:
with wand.image.Image( blob=svg_file.read(), format="svg" ) as image:
png_image = image.make_blob("png")
Я только что обнаружил это сегодня и почувствовал, что стоит поделиться тем, кто может прорваться через этот ответ, поскольку это было какое-то время, поскольку на большинство этих вопросов был дан ответ.
ПРИМЕЧАНИЕ. Технически при тестировании я обнаружил, что вам даже не нужно передавать параметр формата для ImageMagick, поэтому with wand.image.Image( blob=svg_file.read() ) as image:
- это все, что действительно нужно.
РЕДАКТИРОВАТЬ: Из попытки отредактировать qris вот какой-то полезный код, который позволяет использовать ImageMagick с SVG с прозрачным фоном:
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)
Попробуйте следующее: http://cairosvg.org/
Сайт говорит:
CairoSVG написан на чистом питоне и зависит только от Pycairo. это которые, как известно, работают на Python 2.6 и 2.7.
Обновить 25 ноября 2016 г.:
2.0.0 - новая крупная версия, в ее журнал изменений:
- Поддержка Drop Python 2
<clipPath><rect ... /></clipPath>
. Во-вторых, он не принимает опцию -d (DPI).
Другое решение, которое я только что нашел здесь Как отобразить масштабированный SVG в 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 легко устанавливается из двоичного пакета в Windows (и я использую его для других вещей, поэтому это легко для меня).
Тем не менее, я заметил несколько проблем при преобразовании флагов страны из Викимедиа, поэтому, возможно, это не самый надежный svg-парсер/рендеринг.
Небольшое расширение ответа 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)
Вот пример конца Python.
Обратите внимание, что он подавляет некоторый выход жестокости, который Inkscape записывает на консоль (в частности, stderr и stdout) во время нормальной безошибочной работы. Выход записывается двумя строковыми переменными out
и 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 '?') )
Например, при запуске определенного задания в моей системе Mac OS out
закончилось:
Background RRGGBBAA: ffffff00
Area 0:0:339:339 exported to 100 x 100 pixels (72.4584 dpi)
Bitmap saved as: /path/to/output.png
(Входной файл svg имел размер 339 на 339 пикселей.)