Python'da anı ' svg
ye nasıl dönüştürürüm png
? svg
Bir örneğinde depoluyorum StringIO
. PyCairo kütüphanesini kullanmalı mıyım? Bu kodu nasıl yazarım?
Python'da anı ' svg
ye nasıl dönüştürürüm png
? svg
Bir örneğinde depoluyorum StringIO
. PyCairo kütüphanesini kullanmalı mıyım? Bu kodu nasıl yazarım?
Yanıtlar:
Cevap " pyrsvg " - librsvg için bir Python bağlantısı .
Bunu sağlayan bir Ubuntu python-rsvg paketi var. Google'da adını aramak yetersiz çünkü kaynak kodu "gnome-python-desktop" Gnome projesi GIT deposunda bulunuyor gibi görünüyor.
SVG'yi kahire yüzeyine dönüştüren ve diske yazan minimalist bir "merhaba dünya" yaptım:
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")
Güncelleme : 2014 tarihi itibariyle Fedora Linux dağıtımı için gerekli bir pakettir: gnome-python2-rsvg
. Yukarıdaki pasaj listesi hala olduğu gibi çalışıyor.
cairo
resmin YÜKSEKLİĞİ ve GENİŞLİĞİNİ kendi başına belirlemenin bir yolu var mı? *.svg
HEIGHT ve WIDTH değerlerini oradan çıkarmak için dosyaya baktım , ancak her ikisi de olarak ayarlandı 100%
. Tabii ki, resmin özelliklerine bakabilirim, ancak bu görüntü işlemede sadece bir adım olduğu için istediğim bu değil.
.get_dimension_data()
yöntemi var (iyi davranan bir SVG) - bir deneyin.
İşte cairosvg kullanarak yaptığım şey :
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')
Ve bir cazibe gibi çalışıyor!
Daha fazlasını görün: cairosvg document
svg2png
bir stream
nesneyi write_to
almaktır ve bu sizin HTTP Yanıt nesneniz olabilir (hangisi çoğu çerçeve dosya benzeri bir nesnedir) veya başka bir akıştır, daha sonra Content-Disposition
başlığı kullanarak tarayıcıya sunarsınız. buraya bakın: stackoverflow.com/questions/1012437/…
bytestring
baytları kabul eder, bu nedenle dizeyi önce bytestring=bytes(svg,'UTF-8')
2 ile dönüştürün ). dosya modu ikili olmalıdır, bu nedenleopen('output.png','wb')
svg2png
Benim için bir yoktu, kullanmak zorunda kaldım cairosvg.surface.PNGSurface.convert(svg_str, write_to='output.png')
.
Inkscape'i yükleyin ve komut satırı olarak adlandırın:
${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -j -e ${dest_png}
Ayrıca belirli dikdörtgen alanı yalnızca parametre kullanarak -j
, örneğin "0: 125: 451: 217" koordinatını kullanarak tutturabilirsiniz.
${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -j -a ${coordinates} -e ${dest_png}
SVG dosyasında yalnızca bir nesneyi göstermek istiyorsanız, parametreyi -i
SVG'de ayarladığınız nesne kimliğiyle belirtebilirsiniz . Diğer her şeyi gizler.
${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -i ${object} -j -a ${coordinates} -e ${dest_png}
Oldukça gelişmiş SVG'leri içe aktarmak için Wand-py (ImageMagick çevresindeki Wand sargısının bir uygulaması) kullanıyorum ve şu ana kadar harika sonuçlar aldım! Aldığı tüm kod bu:
with wand.image.Image( blob=svg_file.read(), format="svg" ) as image:
png_image = image.make_blob("png")
Bunu bugün yeni keşfettim ve bu soruların çoğunun yanıtlanmasının üzerinden bir süre geçtiği için bu yanıtı paylaşmaya değer olduğunu hissettim.
NOT: Teknik olarak test ederken aslında ImageMagick için format parametresini geçmek zorunda olmadığınızı keşfettim, bu yüzden with wand.image.Image( blob=svg_file.read() ) as image:
gerçekten gerekli olan tek şeydi.
DÜZENLEME: qris tarafından yapılan bir düzenleme denemesinden, ImageMagick'i şeffaf bir arka plana sahip bir SVG ile kullanmanıza izin veren bazı yararlı kodlar:
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
bu örnekte bir "dosya" nesnesi olduğu varsayılırsa, ayar svg_file
şuna benzer bir şeye benzeyecektir:svg_file = File.open(file_name, "r")
cairo
ve rsvg
'kabul edildi' yöntemi PDF'mde işe yaramadı. pip install wand
ve pasajınız hile yaptı;)
str
o zaman ilk önce bu gibi ikili içine kodlamak gerekir: svg_blob = svg_str.encode('utf-8')
. Şimdi blob=svg_file.read()
ile değiştirerek yukarıdaki yöntemi kullanabilirsiniz blob=svg_blob
.
Şunu deneyin: http://cairosvg.org/
Site diyor ki:
CairoSVG saf python ile yazılmıştır ve sadece Pycairo'ya bağlıdır. Python 2.6 ve 2.7 üzerinde çalıştığı bilinmektedir.
Güncelleme 25 Kasım 2016 :
2.0.0 yeni bir ana sürümdür ve değişiklik günlüğü şunları içerir:
- Python 2 desteğini bırak
<clipPath><rect ... /></clipPath>
,. İkincisi, -d (DPI) seçeneğini almaz.
Burada bulduğum başka bir çözüm Ölçekli bir SVG'yi bir QImage'a nasıl işleyebilirim?
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'ta ikili bir paketten kolayca kurulur (ve bunu başka şeyler için kullanıyorum, bu yüzden benim için kolay).
Bununla birlikte, ülke bayraklarını Wikimedia'dan dönüştürürken birkaç sorun olduğunu fark ettim, bu nedenle belki de en sağlam svg ayrıştırıcı / oluşturucu değil.
Jsbueno'nun cevabına küçük bir uzantı:
#!/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)
Cevapların hiçbirini tatmin edici bulmadım. Bahsedilen tüm kitaplıkların bir sorunu var veya diğerleri, Cairo'nun python 3.6 desteğini düşürmesi gibi (Python 2 desteğini yaklaşık 3 yıl önce bıraktılar!). Ayrıca, bahsi geçen kitaplıkları Mac'e yüklemek de bir acı oldu.
Son olarak, en iyi çözüm olduğunu bulduk svglib + reportlab . Her ikisi de pip kullanılarak sorunsuz bir şekilde kurulur ve svg'den png'ye dönüştürmek için ilk çağrı çok güzel çalıştı! Çözümden çok memnunum.
Sadece 2 komut hile yapar:
from svglib.svglib import svg2rlg
from reportlab.graphics import renderPM
drawing = svg2rlg("my.svg")
renderPM.drawToFile(drawing, "my.png", fmt="PNG")
Bunlarla ilgili bilmem gereken herhangi bir sınırlama var mı?
Pycairo ve librsvg kullanarak SVG ölçeklendirmesini ve bir bitmap'e dönüştürülmesini sağlayabildim. SVG'nizin tam olarak 256x256 piksel olmadığını varsayarsak, istenen çıktı, rsvg kullanarak SVG'de bir Kahire bağlamında okuyabilir ve ardından ölçekleyebilir ve bir PNG'ye yazabilirsiniz.
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')
Cario web sitesinden bazı küçük değişikliklerle. Ayrıca Python'dan bir C kütüphanesinin nasıl çağrılacağına dair iyi bir örnek
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
benim için çalışmadı. Bunu basit bir self.props.width
ve getirme ile değiştirmek zorunda kaldım self.props.height
. Yapıyı ilk önce RsvgDimensionData
kahire web sitesinde anlatıldığı gibi tanımlamayı denedim , ancak başarılı olamadım.
İşte Inkscape'in Python tarafından çağrıldığı bir yaklaşım.
Normal hatasız işlem sırasında Inkscape'in konsola yazdığı belirli crufty çıktılarını (özellikle stderr ve stdout) bastırdığını unutmayın. Çıktı iki dize değişkeninde yakalanır out
ve 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 '?') )
Örneğin, Mac OS sistemimde belirli bir işi çalıştırırken şu out
sonuç çıktı:
Background RRGGBBAA: ffffff00
Area 0:0:339:339 exported to 100 x 100 pixels (72.4584 dpi)
Bitmap saved as: /path/to/output.png
(Giriş svg dosyasının boyutu 339'a 339 pikseldir.)
Aslında, Python dışında başka bir şeye bağımlı olmak istemedim (Kahire, Mürekkep ... vb.) Gereksinimlerim olabildiğince basit olmalıydı, en fazla basit bir pip install "savior"
yeterli olurdu, bu yüzden yukarıdakilerden herhangi biri yapmadı ' benim için uygun.
Bunu aştım (araştırmada Stackoverflow'dan daha ileri gidiyorum). https://www.tutorialexample.com/best-practice-to-python-convert-svg-to-png-with-svglib-python-tutorial/
Şimdiye kadar iyi görünüyor. Bu yüzden aynı durumda olan biri olması durumunda bunu paylaşıyorum.