Làm cách nào để chuyển đổi một svg
sang png
, trong Python? Tôi đang lưu trữ svg
trong một ví dụ của StringIO
. Tôi có nên sử dụng thư viện pyCairo không? Làm cách nào để viết mã đó?
Làm cách nào để chuyển đổi một svg
sang png
, trong Python? Tôi đang lưu trữ svg
trong một ví dụ của StringIO
. Tôi có nên sử dụng thư viện pyCairo không? Làm cách nào để viết mã đó?
Câu trả lời:
Câu trả lời là " pyrsvg " - một liên kết Python cho librsvg .
Có một gói Ubuntu python-rsvg cung cấp nó. Việc tìm kiếm tên của Google không tốt vì mã nguồn của nó dường như được chứa bên trong kho lưu trữ GIT của dự án Gnome "gnome-python-desktop".
Tôi đã tạo một "hello world" tối giản kết xuất SVG lên bề mặt cairo và ghi nó vào đĩa:
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")
Cập nhật : như năm 2014 các gói cần thiết để phân phối Fedora Linux là: gnome-python2-rsvg
. Danh sách đoạn mã trên vẫn hoạt động như hiện tại.
cairo
xác định CHIỀU CAO và CHIỀU RỘNG của bức tranh không? Tôi đã xem xét *.svg
tệp, để trích xuất CHIỀU CAO và CHIỀU RỘNG từ đó, nhưng cả hai đều được đặt thành 100%
. Tất nhiên, tôi có thể xem xét các thuộc tính của hình ảnh, nhưng vì đây chỉ là một bước trong xử lý hình ảnh nên đây không phải là điều tôi muốn.
.get_dimension_data()
phương thức hoạt động với tệp ví dụ của tôi (SVG hoạt động tốt) - hãy thử.
Đây là những gì tôi đã làm bằng cách sử dụng 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')
Và nó hoạt động như một sự quyến rũ!
Xem thêm: tài liệu cairosvg
svg2png
đưa vào một stream
đối tượng trong write_to
tham số và đây có thể là đối tượng HTTP Response của bạn (trong đó hầu hết các khuôn khổ là một đối tượng giống như tệp) hoặc một số luồng khác, mà sau đó bạn phân phát cho trình duyệt bằng cách sử dụng Content-Disposition
tiêu đề. xem ở đây: stackoverflow.com/questions/1012437/…
bytestring
chấp nhận byte, vì vậy hãy chuyển đổi chuỗi đầu tiên bằng bytestring=bytes(svg,'UTF-8')
2). chế độ tập tin nên nhị phân, vì vậyopen('output.png','wb')
svg2png
cho tôi, tôi phải sử dụng cairosvg.surface.PNGSurface.convert(svg_str, write_to='output.png')
.
Cài đặt Inkscape và gọi nó dưới dạng dòng lệnh:
${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -j -e ${dest_png}
Bạn cũng có thể chụp khu vực hình chữ nhật cụ thể chỉ bằng cách sử dụng tham số -j
, ví dụ: tọa độ "0: 125: 451: 217"
${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -j -a ${coordinates} -e ${dest_png}
Nếu bạn chỉ muốn hiển thị một đối tượng trong tệp SVG, bạn có thể chỉ định tham số -i
với id đối tượng mà bạn đã thiết lập trong SVG. Nó ẩn mọi thứ khác.
${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -i ${object} -j -a ${coordinates} -e ${dest_png}
Tôi đang sử dụng Wand-py (một triển khai của Wand wrapper xung quanh ImageMagick) để nhập một số SVG khá nâng cao và cho đến nay đã thấy kết quả tuyệt vời! Đây là tất cả mã mà nó cần:
with wand.image.Image( blob=svg_file.read(), format="svg" ) as image:
png_image = image.make_blob("png")
Tôi mới phát hiện ra điều này hôm nay và cảm thấy nó đáng để chia sẻ cho bất kỳ ai khác có thể băn khoăn về câu trả lời này vì đã lâu rồi vì hầu hết các câu hỏi này đã được trả lời.
LƯU Ý: Về mặt kỹ thuật, trong quá trình thử nghiệm, tôi phát hiện ra rằng bạn thậm chí không thực sự phải chuyển tham số định dạng cho ImageMagick, vì vậy with wand.image.Image( blob=svg_file.read() ) as image:
tất cả những gì thực sự cần thiết.
CHỈNH SỬA: Từ một chỉnh sửa đã cố gắng của qris, đây là một số mã hữu ích cho phép bạn sử dụng ImageMagick với SVG có nền trong suốt:
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
được giả định là một "tập tin" đối tượng trong ví dụ này, thiết lập svg_file
sẽ giống như thế:svg_file = File.open(file_name, "r")
cairo
và rsvg
'được chấp nhận' không hoạt động với tệp PDF của tôi. pip install wand
và đoạn mã của bạn đã làm các trick;)
str
thì trước tiên bạn cần phải mã hóa thành nhị phân như thế này: svg_blob = svg_str.encode('utf-8')
. Bây giờ bạn có thể sử dụng phương pháp trên bằng cách thay thế blob=svg_file.read()
bằng blob=svg_blob
.
Hãy thử cái này: http://cairosvg.org/
Trang web cho biết:
CairoSVG được viết bằng python thuần túy và chỉ phụ thuộc vào Pycairo. Nó được biết là hoạt động trên Python 2.6 và 2.7.
Cập nhật ngày 25 tháng 11 năm 2016 :
2.0.0 là một phiên bản chính mới, bảng thay đổi của nó bao gồm:
- Bỏ hỗ trợ Python 2
<clipPath><rect ... /></clipPath>
. Thứ hai, nó không sử dụng tùy chọn -d (DPI).
Một giải pháp khác mà tôi vừa tìm thấy ở đây Làm thế nào để hiển thị SVG được chia tỷ lệ thành 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 được cài đặt dễ dàng từ một gói nhị phân trong Windows (và tôi sử dụng nó cho những việc khác nên rất dễ dàng đối với tôi).
Tuy nhiên, tôi nhận thấy một số vấn đề khi chuyển đổi cờ quốc gia từ Wikimedia, vì vậy có lẽ không phải là trình phân tích / kết xuất svg mạnh mẽ nhất.
Một chút mở rộng về câu trả lời của 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)
Tôi không tìm thấy bất kỳ câu trả lời nào thỏa đáng. Tất cả các thư viện được đề cập đều có một số vấn đề hoặc vấn đề khác như Cairo đã bỏ hỗ trợ cho python 3.6 (họ đã bỏ hỗ trợ Python 2 khoảng 3 năm trước!). Ngoài ra, việc cài đặt các thư viện được đề cập trên Mac cũng là một vấn đề khó khăn.
Cuối cùng, tôi tìm thấy giải pháp tốt nhất là svglib + reportlab . Cả hai đều được cài đặt mà không gặp khó khăn bằng cách sử dụng pip và lệnh gọi đầu tiên để chuyển đổi từ svg sang png đều hoạt động tốt! Rất hài lòng với giải pháp.
Chỉ cần 2 lệnh thực hiện thủ thuật:
from svglib.svglib import svg2rlg
from reportlab.graphics import renderPM
drawing = svg2rlg("my.svg")
renderPM.drawToFile(drawing, "my.png", fmt="PNG")
Có bất kỳ hạn chế nào với những điều này tôi nên biết không?
Sử dụng pycairo và librsvg tôi có thể đạt được tỷ lệ SVG và hiển thị thành một bitmap. Giả sử SVG của bạn không chính xác là 256x256 pixel, đầu ra mong muốn, bạn có thể đọc trong SVG sang ngữ cảnh Cairo bằng cách sử dụng rsvg, sau đó chia tỷ lệ và ghi thành 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')
Từ trang web Cario với một số sửa đổi nhỏ. Cũng là một ví dụ điển hình về cách gọi thư viện C từ 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
không làm việc cho tôi. Tôi đã phải thay thế nó bằng cách tìm nạp đơn giản self.props.width
và self.props.height
. Lần đầu tiên tôi đã thử xác định RsvgDimensionData
Cấu trúc như được mô tả trên trang web cairo, nhưng không thành công.
Đây là một cách tiếp cận mà Inkscape được gọi bằng Python.
Lưu ý rằng nó ngăn chặn một số đầu ra quan trọng nhất định mà Inkscape ghi vào bảng điều khiển (cụ thể là stderr và stdout) trong quá trình hoạt động bình thường không có lỗi. Đầu ra được ghi lại trong hai biến chuỗi, out
và 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 '?') )
Ví dụ: khi chạy một công việc cụ thể trên hệ thống Mac OS của tôi, out
kết quả là:
Background RRGGBBAA: ffffff00
Area 0:0:339:339 exported to 100 x 100 pixels (72.4584 dpi)
Bitmap saved as: /path/to/output.png
(Tệp svg đầu vào có kích thước 339 x 339 pixel.)
Thực ra, tôi không muốn bị phụ thuộc vào bất cứ thứ gì khác ngoài Python (Cairo, Ink .., v.v.) Yêu cầu của tôi là càng đơn giản càng tốt, tối đa, đơn giản là pip install "savior"
đủ, đó là lý do tại sao bất kỳ cái nào ở trên đều không ' t phù hợp với tôi.
Tôi đã vượt qua điều này (đi xa hơn Stackoverflow về nghiên cứu). https://www.tutorialexample.com/best-practice-to-python-convert-svg-to-png-with-svglib-python-tutorial/
Nhìn có vẻ ổn. Vì vậy, tôi chia sẻ nó để đề phòng những ai cùng cảnh ngộ.