ฉันจะแปลงsvg
ไปpng
ในงูใหญ่? ฉันกำลังจัดเก็บsvg
ในตัวอย่างของStringIO
. ฉันควรใช้ไลบรารี pyCairo หรือไม่? ฉันจะเขียนโค้ดนั้นได้อย่างไร?
ฉันจะแปลงsvg
ไปpng
ในงูใหญ่? ฉันกำลังจัดเก็บsvg
ในตัวอย่างของStringIO
. ฉันควรใช้ไลบรารี pyCairo หรือไม่? ฉันจะเขียนโค้ดนั้นได้อย่างไร?
คำตอบ:
คำตอบคือ " pyrsvg " - หลามผูกพันlibrsvg
มีแพ็คเกจ Ubuntu python-rsvgให้ การค้นหาชื่อ Google ไม่ดีเนื่องจากซอร์สโค้ดดูเหมือนว่าจะอยู่ในที่เก็บ GIT โปรเจ็กต์ Gnome "gnome-python-desktop"
ฉันสร้าง "สวัสดีชาวโลก" แบบเรียบง่ายที่แสดง 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
ไฟล์เพื่อแยก HEIGHT และ WIDTH จากที่นั่น แต่ทั้งสองตั้งค่าเป็น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
svg2png
ใช้ในstream
ออบเจ็กต์ในwrite_to
พารามิเตอร์และสิ่งนี้อาจเป็นอ็อบเจ็กต์การตอบสนอง HTTP ของคุณ (ซึ่งใน เฟรมเวิร์กส่วนใหญ่เป็นอ็อบเจ็กต์ที่มีลักษณะคล้ายไฟล์) หรือสตรีมอื่น ๆ ซึ่งคุณจะใช้กับเบราว์เซอร์โดยใช้Content-Disposition
ส่วนหัว ดูที่นี่: stackoverflow.com/questions/1012437/…
bytestring
ยอมรับไบต์ดังนั้นให้แปลงสตริงก่อนด้วยbytestring=bytes(svg,'UTF-8')
2) โหมดไฟล์ควรเป็นไบนารีดังนั้นopen('output.png','wb')
svg2png
cairosvg.surface.PNGSurface.convert(svg_str, write_to='output.png')
ติดตั้ง 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 wrapper รอบ ๆ 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)
image.read(blob=svg_file.read(), format="svg") NameError: name 'svg_file' is not defined
svg_file
ถือว่าเป็นวัตถุ "ไฟล์" ในตัวอย่างนี้การตั้งค่าsvg_file
จะมีลักษณะดังนี้:svg_file = File.open(file_name, "r")
cairo
และrsvg
'ยอมรับ' ใช้ไม่ได้กับ PDF ของฉัน pip install wand
และตัวอย่างข้อมูลของคุณก็ใช้เคล็ดลับ;)
str
svg_blob = svg_str.encode('utf-8')
ตอนนี้คุณสามารถใช้วิธีการด้านบนโดยแทนที่blob=svg_file.read()
ด้วยblob=svg_blob
.
ลองสิ่งนี้: http://cairosvg.org/
เว็บไซต์กล่าวว่า:
CairoSVG เขียนด้วย python บริสุทธิ์และขึ้นอยู่กับ Pycairo เท่านั้น เป็นที่ทราบกันดีว่าทำงานบน Python 2.6 และ 2.7
อัปเดต 25 พฤศจิกายน 2559 :
2.0.0 เป็นเวอร์ชันหลักใหม่บันทึกการเปลี่ยนแปลงประกอบด้วย:
- วางการสนับสนุน 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 (และฉันใช้มันเพื่อสิ่งอื่น ๆ มันง่ายสำหรับฉัน)
อย่างไรก็ตามฉันสังเกตเห็นปัญหาเล็กน้อยเมื่อแปลงธงประเทศจาก Wikimedia ดังนั้นอาจไม่ใช่ตัวแยกวิเคราะห์ / ตัวแสดงผล 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 3.6 (พวกเขาทิ้ง Python 2 รองรับเมื่อ 3 ปีก่อน!) นอกจากนี้การติดตั้งไลบรารีที่กล่าวถึงบน Mac ก็เป็นความเจ็บปวด
สุดท้ายผมพบว่าวิธีการแก้ปัญหาที่ดีที่สุดคือsvglib + ReportLab ทั้งสองติดตั้งโดยไม่มีปัญหาโดยใช้ pip และการโทรครั้งแรกเพื่อแปลงจาก svg เป็น png ทำงานได้อย่างสวยงาม มีความสุขมากกับการแก้ปัญหา
เพียง 2 คำสั่งทำเคล็ดลับ:
from svglib.svglib import svg2rlg
from reportlab.graphics import renderPM
drawing = svg2rlg("my.svg")
renderPM.drawToFile(drawing, "my.png", fmt="PNG")
มีข้อ จำกัด ใด ๆ ที่ฉันควรทราบหรือไม่?
การใช้pycairoและlibrsvgฉันสามารถปรับขนาด SVG และแสดงผลเป็นบิตแมปได้ สมมติว่า SVG ของคุณไม่ใช่ 256x256 พิกเซลซึ่งเป็นผลลัพธ์ที่ต้องการคุณสามารถอ่านใน SVG เป็นบริบทไคโรโดยใช้ rsvg จากนั้นปรับขนาดและเขียนเป็น 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')
จากเว็บไซต์ Cario ที่มีการปรับเปลี่ยนเล็กน้อย นอกจากนี้ยังเป็นตัวอย่างที่ดีในการเรียก C-library จาก 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
ไม่ได้ผลสำหรับฉัน ฉันต้องแทนที่ด้วยการดึงself.props.width
และself.props.height
. ครั้งแรกฉันพยายามกำหนดRsvgDimensionData
โครงสร้างตามที่อธิบายไว้ในเว็บไซต์ cairo แต่ไม่ประสบความสำเร็จ
นี่คือวิธีการที่ Python เรียก Inkscape
โปรดทราบว่าจะระงับเอาต์พุตที่สำคัญบางอย่างที่ 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 x 339 พิกเซล)
อันที่จริงฉันไม่ต้องการพึ่งพาสิ่งอื่นใดนอกจาก Python (Cairo, Ink .. ฯลฯ ) ความต้องการของฉันคือต้องเรียบง่ายที่สุดเท่าที่pip install "savior"
จะทำได้ง่ายที่สุดก็พอเพียงนั่นคือเหตุผลที่ข้อใดข้อหนึ่งข้างต้นไม่ t เหมาะสำหรับฉัน
ฉันมาถึงสิ่งนี้ (ไปไกลกว่า Stackoverflow ในการวิจัย) https://www.tutorialexample.com/best-practice-to-python-convert-svg-to-png-with-svglib-python-tutorial/
ดูดีจังเลย เลยเอามาแบ่งปันเผื่อว่าใครอยู่ในสถานการณ์เดียวกัน