Python'da SVG'yi PNG'ye dönüştürme


102

Python'da anı ' svgye nasıl dönüştürürüm png? svgBir örneğinde depoluyorum StringIO. PyCairo kütüphanesini kullanmalı mıyım? Bu kodu nasıl yazarım?



3
Bu ileti dizisi sorunu çözmeden bıraktı. Kabul edilen yanıt, başarısız kod girişimini paylaşan sorudan geldi. Diğer cevap ImageMagick'i önerdi, ancak bir yorumcu ImageMagick'in "SVG'yi yorumlamak için korkunç bir iş" yaptığını söyledi. Pinlerimin korkunç görünmesini istemiyorum, bu yüzden soruyu yeniden soruyorum.
ram1


Bu bağlantıdaki örnekler Win32'ye özeldir. Linux kullanıyorum.
ram1

Bu blog gönderisine bir göz atın , ihtiyacınız olan şey bu olabilir gibi görünüyor.
giodamelio

Yanıtlar:


61

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.


1
Harika, güzel çalışıyor. Peki cairoresmin YÜKSEKLİĞİ ve GENİŞLİĞİNİ kendi başına belirlemenin bir yolu var mı? *.svgHEIGHT 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.
quapka

1
Dosyalarınızın "genişliği" ve "yüksekliği"% 100 olarak ayarlanmışsa, Kahire'nin veya rsvg'nin boyutu tahmin etmek için yapabileceği sihirli bir şey yoktur: bu tür SVG dosyaları, oluşturucu yazılım (/ kişi) tarafından boyuttan bağımsız olarak bırakılmıştır. SVG dosyasını içe aktarmak için çevreleyen HTML kodu, fiziksel boyutu sağlayacaktır. Bununla birlikte, rsvg'nin "Tutamaç" nesnesinin örnek dosyam için işe yarayan bir .get_dimension_data()yöntemi var (iyi davranan bir SVG) - bir deneyin.
jsbueno

1
2014 itibariyle, ubuntu için şunları kullanabilirsiniz: apt-get install python-rsvg
t1m0

1
Geçerli arka planı şeffafsa, görüntüye beyaz bir arka plan eklemek için hızlı bir komut var mı?
fiatjaf

@jsbueno Windows 8.1 ve python 2.7.11 kullanıyorum cairo ve rsvg'yi nasıl kurabilir ve çalışmasını sağlayabilirim. Bunun işe yaraması için mücadele ediyordum. Ayrıntılı açıklamanız için BTW +1.
Marlon Abeykoon

89

İş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


5
Selam. Aynı şeyi bir dosyaya yazmadan nasıl yapabilirim biliyor musun? PNG içeriğini tarayıcıya bir web sunucusundan göndermem gerekiyor, böylece kullanıcı resmi indirebilir. Png dosyasını kaydetmek projemizde geçerli bir seçenek değil, bu yüzden ona bu şekilde ihtiyacım var. Teşekkürler
estemendoza

4
Bunu kendim yapıyorum. Temel olarak, web isteklerinizi işlerken elinizde hangi araçlara veya çerçevelere sahip olduğunuza bağlıdır, ancak ne olursa olsun, temel fikir, parametrede svg2pngbir streamnesneyi write_toalmaktı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-Dispositionbaşlığı kullanarak tarayıcıya sunarsınız. buraya bakın: stackoverflow.com/questions/1012437/…
nemesisfixx

4
Bu kodla ilgili sorunları yaşayanlar için, benim gibi: 1). bytestringbaytları 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')
Serj Zaharchenko

3
cairosvg yalnızca Python 3.4+ sürümlerini destekler. Python 2 desteğini
düşürdüler

1
svg2pngBenim için bir yoktu, kullanmak zorunda kaldım cairosvg.surface.PNGSurface.convert(svg_str, write_to='output.png').
tobltobs

39

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 -iSVG'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}

2
+1 çünkü bu aynı zamanda kabuk komut dosyası oluşturma için son derece kullanışlı. Inkscape'in komut satırıyla ilgili tam belgeler için inkscape.org/doc/inkscape-man.html adresine bakın .
Prime

Teşekkürler, bunu yapmanın en kolay yolu buydu. Windows'ta, her seferinde Inkscape'e giden tam yolu yazmak zorunda kalmamak için bunu Çevresel Değişkenler'deki Yolunuza ekleyebilirsiniz .
Alex S

3
Bu bir cevap değil. Bu bir geçici çözüm. OP, bir Python çözümü istedi.
lamino

31

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)

2
Wand, PNG'lerim için Kahire'den çok daha iyi çalıştı .
qris

3
Hatayı alıyorum image.read(blob=svg_file.read(), format="svg") NameError: name 'svg_file' is not defined
adrienlucca.wordpress.com

2
svg_filebu örnekte bir "dosya" nesnesi olduğu varsayılırsa, ayar svg_fileşuna benzer bir şeye benzeyecektir:svg_file = File.open(file_name, "r")
streetlogics

2
Teşekkürler, cairove rsvg'kabul edildi' yöntemi PDF'mde işe yaramadı. pip install wandve pasajınız hile yaptı;)
nmz787

5
Bir svg varsa stro 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.
asherbar

12

Ş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

Ne yazık ki bununla ilgili iki sorun var. İlk olarak <clipPath><rect ... /></clipPath>,. İkincisi, -d (DPI) seçeneğini almaz.
Ray

2
@Ray, lütfen CairoSVG izleyicide hata raporları / özellik istekleri gönderin !
Simon Sapin

@ Simon, lütfen yapabilir misin? Çok meşgulüm ve önümüzdeki 1-2 ay içinde olacağım.
Ray

2
@Ray, aslında -d / --dpi seçeneği bir süredir oradaydı ve <clippath> desteğinin git sürümüne birkaç hafta önce eklendiği söylendi.
Simon Sapin

@Simon, güzel! Teşekkür ederim! :)
Ray

6

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.


5

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)

Svg genişlik ve yükseklik çıkarımını kullandım. Svg standardından emin değilim, ancak bazı svg dosyalarımda genişlik veya yüksekliğin ardından 'mm' veya 'px' (ör: '250mm') gibi sayısal olmayan bir dize geliyordu. İnt ('250mm') bir istisna atıyor ve bazı ek ayarlamalar yapmak zorunda kaldım.
WigglyWorld

5

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ı?


Evet, işaretçi ucu desteklenmiyor ve desteklenmeyecek, github.com/deeplook/svglib/issues/177
Rainald62

2

SVG ölçekleme ve PNG oluşturma

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.

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

RSVG C bağlama

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)

Bunun için teşekkürler, benim bir projemde çok faydalı oldu. Her ne kadar Handle.get_dimension_databenim için çalışmadı. Bunu basit bir self.props.widthve getirme ile değiştirmek zorunda kaldım self.props.height. Yapıyı ilk önce RsvgDimensionDatakahire web sitesinde anlatıldığı gibi tanımlamayı denedim , ancak başarılı olamadım.
JeanOlivier

Bunu bir projemde kullanmaya çalışıyorum. Gerekli dll dosyalarını nasıl edinebilirim?
Andoo

0

İş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 outve 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 outsonuç çı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.)


Inkscape'e güveniyorsanız, uçtan uca Python değil.
Joel

1
@Joel: İtirazınızın üstesinden gelmek için ilk satır değiştirildi. Ama elbette, "saf" bir Python çözümü bile çekirdek dilin dışındaki unsurlara dayanır ve nihayetinde makine diliyle çalışır, bu nedenle belki de uçtan uca hiçbir şey yoktur!
Demir Yastık

0

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.


Cevabınıza bu makalenin ilgili kısmını ekleyebilir misiniz?
Ciprian Tomoiagă

ona bakarak, özdeş görünmektedir Sarang cevabı
Ciprian Tomoiagă
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.