Bagaimana saya mengkonversi svg
ke png
, di Python? Saya menyimpan svg
dalam sebuah contoh StringIO
. Haruskah saya menggunakan pustaka pyCairo? Bagaimana cara menulis kode itu?
Bagaimana saya mengkonversi svg
ke png
, di Python? Saya menyimpan svg
dalam sebuah contoh StringIO
. Haruskah saya menggunakan pustaka pyCairo? Bagaimana cara menulis kode itu?
Jawaban:
Jawabannya adalah " pyrsvg " - pengikatan Python untuk librsvg .
Ada paket Ubuntu python-rsvg yang menyediakannya. Mencari namanya di Google buruk karena kode sumbernya tampaknya terdapat di dalam repositori GIT proyek Gnome "gnome-python-desktop".
Saya membuat "hello world" minimalis yang merender SVG ke permukaan Kairo dan menulisnya ke disk:
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")
Update : sebagai 2014 paket yang diperlukan untuk distribusi Fedora Linux adalah: gnome-python2-rsvg
. Daftar potongan di atas masih berfungsi apa adanya.
cairo
menentukan TINGGI dan LEBAR gambar itu sendiri? Saya telah melihat ke dalam *.svg
file tersebut, untuk mengekstrak HEIGHT dan WIDTH dari sana, tetapi keduanya diatur ke 100%
. Tentu saja, saya dapat melihat properti gambar, tetapi karena ini hanya satu langkah dalam pemrosesan gambar, ini bukan yang saya inginkan.
.get_dimension_data()
metode yang bekerja untuk file contoh saya (SVG yang berperilaku baik) - cobalah.
Inilah yang saya lakukan menggunakan 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')
Dan itu bekerja seperti pesona!
Lihat lebih lanjut: dokumen cairosvg
svg2png
mengambil stream
objek di write_to
parameter, dan ini bisa menjadi objek Respons HTTP Anda (yang kebanyakan kerangka kerja adalah objek seperti file) atau aliran lain, yang kemudian Anda tayangkan ke browser menggunakan Content-Disposition
tajuk. lihat di sini: stackoverflow.com/questions/1012437/…
bytestring
menerima byte, jadi konversikan string terlebih dahulu dengan bytestring=bytes(svg,'UTF-8')
2). mode file harus biner, jadiopen('output.png','wb')
svg2png
untuk saya, saya harus menggunakan cairosvg.surface.PNGSurface.convert(svg_str, write_to='output.png')
.
Instal Inkscape dan sebut sebagai baris perintah:
${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -j -e ${dest_png}
Anda juga dapat mengambil area persegi panjang tertentu hanya menggunakan parameter -j
, misalnya koordinat "0: 125: 451: 217"
${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -j -a ${coordinates} -e ${dest_png}
Jika Anda hanya ingin menampilkan satu objek di file SVG, Anda dapat menentukan parameter -i
dengan id objek yang telah Anda siapkan di SVG. Itu menyembunyikan yang lainnya.
${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -i ${object} -j -a ${coordinates} -e ${dest_png}
Saya menggunakan Wand-py (implementasi pembungkus Wand di sekitar ImageMagick) untuk mengimpor beberapa SVG yang cukup canggih dan sejauh ini telah melihat hasil yang bagus! Ini semua kode yang dibutuhkan:
with wand.image.Image( blob=svg_file.read(), format="svg" ) as image:
png_image = image.make_blob("png")
Saya baru saja menemukan ini hari ini, dan merasa layak untuk dibagikan kepada siapa pun yang mungkin kesulitan menemukan jawaban ini karena sudah lama sejak sebagian besar pertanyaan ini dijawab.
CATATAN: Secara teknis dalam pengujian saya menemukan Anda bahkan tidak benar-benar harus mengirimkan parameter format untuk ImageMagick, jadi with wand.image.Image( blob=svg_file.read() ) as image:
hanya itu yang benar-benar dibutuhkan.
EDIT: Dari percobaan pengeditan oleh qris, berikut beberapa kode berguna yang memungkinkan Anda menggunakan ImageMagick dengan SVG yang memiliki latar belakang transparan:
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)
image.read(blob=svg_file.read(), format="svg") NameError: name 'svg_file' is not defined
svg_file
diasumsikan sebagai objek "file" dalam contoh ini, pengaturan svg_file
akan terlihat seperti:svg_file = File.open(file_name, "r")
cairo
dan rsvg
metode 'diterima' tidak berfungsi untuk PDF saya. pip install wand
dan cuplikan Anda berhasil;)
str
maka Anda harus terlebih dahulu encode ke biner seperti ini: svg_blob = svg_str.encode('utf-8')
. Sekarang Anda dapat menggunakan metode di atas dengan mengganti blob=svg_file.read()
dengan blob=svg_blob
.
Coba ini: http://cairosvg.org/
Situs itu mengatakan:
CairoSVG ditulis dengan python murni dan hanya bergantung pada Pycairo. Ia dikenal bekerja pada Python 2.6 dan 2.7.
Pembaruan 25 November 2016 :
2.0.0 adalah versi mayor baru, log perubahannya meliputi:
- Jatuhkan dukungan Python 2
<clipPath><rect ... /></clipPath>
. Kedua, itu tidak mengambil opsi -d (DPI).
Solusi lain yang baru saya temukan di sini Bagaimana cara merender SVG skala ke 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 mudah diinstal dari paket biner di Windows (dan saya menggunakannya untuk hal lain, jadi mudah bagi saya).
Namun, saya melihat beberapa masalah saat mengonversi bendera negara dari Wikimedia, jadi mungkin bukan pengurai / penyaji svg yang paling kuat.
Sedikit tambahan untuk jawaban 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)
Saya tidak menemukan jawaban yang memuaskan. Semua pustaka yang disebutkan memiliki beberapa masalah atau yang lainnya seperti Kairo yang menjatuhkan dukungan untuk python 3.6 (mereka menjatuhkan dukungan Python 2 sekitar 3 tahun yang lalu!). Juga, menginstal pustaka yang disebutkan di Mac sangat menyebalkan.
Akhirnya, saya menemukan solusi terbaik adalah svglib + reportlab . Keduanya diinstal tanpa hambatan menggunakan pip dan panggilan pertama untuk mengonversi dari svg ke png bekerja dengan baik! Sangat senang dengan solusinya.
Hanya 2 perintah yang melakukan trik:
from svglib.svglib import svg2rlg
from reportlab.graphics import renderPM
drawing = svg2rlg("my.svg")
renderPM.drawToFile(drawing, "my.png", fmt="PNG")
Apakah ada batasan dengan ini yang harus saya waspadai?
Menggunakan pycairo dan librsvg saya bisa mencapai penskalaan SVG dan rendering ke bitmap. Dengan asumsi SVG Anda tidak persis 256x256 piksel, keluaran yang diinginkan, Anda dapat membaca dalam konteks SVG ke Kairo menggunakan rsvg dan kemudian menskalakannya dan menulis ke PNG.
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')
Dari situs Cario dengan sedikit modifikasi. Juga contoh yang baik tentang bagaimana memanggil pustaka-C dari 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)
Handle.get_dimension_data
tidak berhasil untuk saya. Saya harus menggantinya dengan pengambilan sederhana dari self.props.width
dan self.props.height
. Saya pertama kali mencoba mendefinisikan RsvgDimensionData
Struktur seperti yang dijelaskan di situs web Kairo, tetapi tidak berhasil.
Berikut adalah pendekatan dimana Inkscape dipanggil oleh Python.
Perhatikan bahwa ini menekan output crufty tertentu yang ditulis Inkscape ke konsol (khususnya, stderr dan stdout) selama operasi normal bebas kesalahan. Outputnya ditangkap dalam dua variabel string, out
dan 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 '?') )
Misalnya, saat menjalankan pekerjaan tertentu di sistem Mac OS saya, out
akhirnya menjadi:
Background RRGGBBAA: ffffff00
Area 0:0:339:339 exported to 100 x 100 pixels (72.4584 dpi)
Bitmap saved as: /path/to/output.png
(File svg masukan berukuran 339 kali 339 piksel.)
Sebenarnya, saya tidak ingin bergantung pada apa pun selain Python (Kairo, Ink .., dll.) Persyaratan saya adalah sesederhana mungkin, paling-paling, yang sederhana pip install "savior"
sudah cukup, itulah mengapa yang di atas tidak ' t cocok untukku.
Saya berhasil melewati ini (melangkah lebih jauh dari Stackoverflow dalam penelitian). https://www.tutorialexample.com/best-practice-to-python-convert-svg-to-png-with-svglib-python-tutorial/
Tampak bagus, sejauh ini. Jadi saya membagikannya jika ada yang berada dalam situasi yang sama.