Python에서 SVG를 PNG로 변환


99

파이썬에서 svg를 로 어떻게 변환 png합니까? svg의 인스턴스 에을 저장하고 StringIO있습니다. pyCairo 라이브러리를 사용해야합니까? 코드를 어떻게 작성합니까?



2
그 스레드는 문제를 해결하지 못한 채로 남았습니다. 받아 들여진 대답은 실패한 코드 시도를 공유 한 질문자로부터 나왔습니다. 다른 답변은 ImageMagick을 제안했지만 한 논평자는 ImageMagick이 "SVG를 해석하는 끔찍한 일"을한다고 말했습니다. 나는 내 png가 끔찍하게 보이기를 원하지 않으므로 질문을 다시하고 있습니다.
ram1 2011-07-05


해당 링크의 예는 Win32에만 해당됩니다. 나는 리눅스를 실행하고 있습니다.
ram1

블로그 게시물을 살펴보십시오 . 필요한 것 같습니다.
giodamelio

답변:


60

대답은 " pyrsvg "- 파이썬은 바인딩 librsvg .

그것을 제공 하는 Ubuntu python-rsvg 패키지가 있습니다. 소스 코드가 "gnome-python-desktop"Gnome 프로젝트 GIT 저장소에 포함 된 것처럼 보이기 때문에 Google에서 이름을 검색하는 것은 좋지 않습니다.

SVG를 cairo 표면에 렌더링하고 디스크에 쓰는 미니멀 한 "hello world"를 만들었습니다.

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. 위의 스 니펫 목록은 그대로 작동합니다.


1
좋아, 잘 작동합니다. 그러나 cairo사진의 높이와 너비 를 스스로 결정할 수있는 방법이 있습니까? 나는 *.svg거기에서 HEIGHT와 WIDTH를 추출하기 위해 파일을 조사 했지만 둘 다 100%. 물론 사진의 속성을 살펴볼 수는 있지만 이것은 이미지 처리의 한 단계 일 뿐이므로 원하는 것이 아닙니다.
quapka

1
파일의 "너비"와 "높이"가 100 %로 설정된 경우 Cairo 또는 rsvg가 크기를 추측 할 수있는 마법은 없습니다. 이러한 SVG 파일은 제작자 소프트웨어 (/ person)에 의해 크기가 독립적으로 남아 있습니다. SVG 파일을 가져 오기위한 주변 HTML 코드는 실제 크기를 제공합니다. 그러나 rsvg의 "Handle"개체에는 .get_dimension_data()내 예제 파일 (잘 작동하는 SVG)에서 작동 하는 방법이 있습니다. 한 번 사용해보십시오.
jsbueno

1
2014 년부터 우분투의 경우 다음을 사용할 수 있습니다. apt-get install python-rsvg
t1m0

1
현재 배경이 투명한 경우 이미지에 흰색 배경을 추가하는 빠른 명령이 있습니까?
fiatjaf

@jsbueno 저는 Windows 8.1과 python 2.7.11을 사용합니다. cairo와 rsvg를 어떻게 설치하고 작동하게 만들 수 있습니까? 나는이 일을하기 위해 고군분투하고 있었다. 자세한 설명은 BTW +1.
Marlon Abeykoon 2016 년

88

다음은 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 문서


5
안녕하세요. 파일에 쓰지 않고 똑같이 할 수있는 방법을 아십니까? 사용자가 이미지를 다운로드 할 수 있도록 웹 서버에서 브라우저로 png 콘텐츠를 푸시해야합니다. png 파일을 저장하는 것은 우리 프로젝트에서 유효한 옵션이 아니기 때문에 그렇게해야합니다. 감사합니다
estemendoza 2013

4
나는 이것을 직접 해왔다. 기본적으로 웹 요청을 처리 할 때 어떤 도구 나 프레임 워크를 가지고 있는지에 따라 다르지만, 그것이 무엇이든간에 기본 아이디어는 매개 변수 svg2pngstream객체를 받아들이는 write_to것이며 이것은 HTTP 응답 객체 일 수 있습니다. 대부분의 프레임 워크는 파일과 같은 객체) 또는 다른 스트림으로, Content-Disposition헤더를 사용하여 브라우저에 제공합니다 . 여기를 참조하십시오 : stackoverflow.com/questions/1012437/…
nemesisfixx 2013

4
내가 그랬던 것처럼 그 코드에 문제가있는 사람들을 위해 : 1). bytestring바이트를 허용하므로 먼저 문자열을 bytestring=bytes(svg,'UTF-8') 2 로 변환하십시오 . 파일 모드는 너무 진해야한다open('output.png','wb')
Serj Zaharchenko

3
cairosvg는 Python 3.4 이상 만 지원합니다. 그들은 Python 2 지원을 중단했습니다
Marlon Abeykoon 2016 년

1
svg2png나를위한 것이 아니라 cairosvg.surface.PNGSurface.convert(svg_str, write_to='output.png').
tobltobs

39

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 파일에서 하나의 개체 만 표시하려면 SVG -i에서 설정 한 개체 ID로 매개 변수 를 지정할 수 있습니다 . 다른 모든 것을 숨 깁니다.

${INKSCAPE_PATH} -z -f ${source_svg} -w ${width} -i ${object} -j -a ${coordinates} -e ${dest_png}

2
+1은 쉘 스크립팅에도 매우 편리하기 때문입니다. Inkscape의 명령 줄에 대한 전체 문서는 inkscape.org/doc/inkscape-man.html 을 참조하십시오 .
프라임

감사합니다. 이것이 제가이 작업을 수행하는 가장 쉬운 방법이었습니다. Windows에서 매번 Inkscape의 전체 경로를 입력 할 필요가 없도록하려면 환경 변수의 경로에 추가 할 수 있습니다 .
Alex S

3
이것은 대답이 아닙니다. 해결 방법입니다. OP는 Python 솔루션을 요청했습니다.
lamino

31

저는 Wand-py (ImageMagick 주변의 Wand 래퍼 구현)를 사용하여 꽤 고급 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가 시도한 편집에서 투명한 배경을 가진 SVG와 함께 ImageMagick을 사용할 수있는 몇 가지 유용한 코드가 있습니다.

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에 대해 Cairo보다 훨씬 잘 작동했습니다 .
qris

3
나는 오류 얻을 image.read(blob=svg_file.read(), format="svg") NameError: name 'svg_file' is not defined
adrienlucca.wordpress.com

2
svg_file이 예에서는 "파일"객체로 가정되며 설정 svg_file은 다음과 같습니다.svg_file = File.open(file_name, "r")
streetlogics

2
감사합니다. cairorsvg'수락 됨'방법이 내 PDF에서 작동하지 않았습니다. pip install wand) 당신의 조각은 트릭했다
nmz787

5
svg가있는 경우 str먼저 다음과 같이 바이너리로 인코딩해야합니다 svg_blob = svg_str.encode('utf-8').. 이제 위의 방법 blob=svg_file.read()blob=svg_blob.
asherbar

12

이것을 시도하십시오 : http://cairosvg.org/

사이트 내용 :

CairoSVG는 순수한 파이썬으로 작성되었으며 Pycairo에만 의존합니다. Python 2.6 및 2.7에서 작동하는 것으로 알려져 있습니다.

2016 년 11 월 25 일 업데이트 :

2.0.0은 새로운 주요 버전이며 변경 로그에는 다음이 포함됩니다.

  • Python 2 지원 중단

불행히도 두 가지 문제가 있습니다. 첫째, 그것은 처리하지 않습니다<clipPath><rect ... /></clipPath> . 둘째, -d (DPI) 옵션을 사용하지 않습니다.
레이

2
@Ray, CairoSVG 추적기 에 버그 보고서 / 기능 요청을 보내주세요 !
Simon Sapin

@Simon, 제발 할 수 있습니까? 너무 바빠서 다음 1 ~ 2 개월이 될 것입니다.
Ray

2
@Ray, 실제로 -d / --dpi 옵션은 잠시 동안 거기에 있었고 <clippath>에 대한 지원이 몇 주 전에 git 버전에 추가되었다고 들었습니다.
사이먼 사팽

@Simon, 멋지다! 감사합니다! :)
레이

6

방금 찾은 또 다른 솔루션 스케일링 된 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 파서 / 렌더러가 아닐 것입니다.


5

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)

나는 svg 너비와 높이 추출을 사용했습니다. svg 표준에 대해 잘 모르겠지만 일부 svg 파일에서 너비 또는 높이 뒤에 'mm'또는 'px'(예 : '250mm')와 같은 숫자가 아닌 문자열이옵니다. int ( '250mm')는 예외를 던지고 몇 가지 추가 조정을해야했습니다.
WigglyWorld

3

만족스러운 답변을 찾지 못했습니다. 언급 된 모든 라이브러리에는 몇 가지 문제가 있거나 Cairo가 Python 3.6 지원을 중단하는 것과 같은 문제가 있습니다 (약 3 년 전에 Python 2 지원을 중단했습니다!). 또한 언급 된 라이브러리를 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")

내가 알아야 할 제한 사항이 있습니까?


예, 마커 엔드는 지원되지 않으며 지원되지 않습니다. github.com/deeplook/svglib/issues/177
Rainald62

2

SVG 스케일링 및 PNG 렌더링

pycairolibrsvg를 사용하여 SVG 크기 조정 및 비트 맵 렌더링을 수행 할 수있었습니다. SVG가 원하는 출력 인 정확히 256x256 픽셀이 아니라고 가정하면 rsvg를 사용하여 SVG에서 Cairo 컨텍스트로 읽은 다음 크기를 조정하고 PNG에 쓸 수 있습니다.

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 바인딩

약간의 수정이있는 Cario 웹 사이트에서. 또한 Python에서 C 라이브러리를 호출하는 방법에 대한 좋은 예입니다.

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.widthself.props.height. 처음 RsvgDimensionData에는 카이로 웹 사이트에 설명 된대로 구조 정의를 시도 했지만 성공하지 못했습니다.
JeanOlivier

내 프로젝트에서 이것을 사용하려고합니다. 필요한 dll 파일은 어떻게 얻습니까?
Andoo

0

다음은 Python에서 Inkscape를 호출하는 방법입니다.

정상적인 오류없는 작동 중에 Inkscape가 콘솔 (특히, stderr 및 stdout)에 쓰는 특정 크 러프 티 출력을 억제합니다. 출력은 두 개의 문자열 변수 outerr.

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 픽셀입니다.)


Inkscape에 의존하는 경우 종단 간 Python이 아닙니다.
Joel 19

1
@Joel : 이의를 극복하기 위해 첫 번째 줄이 수정되었습니다. 그러나 물론 "순수한"Python 솔루션조차도 핵심 언어 외부의 요소에 의존하고 궁극적으로 기계 언어로 실행됩니다. 따라서 엔드 투 엔드 같은 것은 없을 것입니다!
Iron Pillow

0

사실, 저는 파이썬 (Cairo, Ink .. 등) 외에 다른 것에 의존하고 싶지 않았습니다. 제 요구 사항은 가능한 한 간단해야했고, 기껏해야 간단한 것만으로 pip install "savior"도 충분했습니다. 그래서 위의 어떤 것도 그렇지 않았습니다. ' 나에게 어울린다.

나는 이것을 통해 왔습니다 (연구에서 Stackoverflow보다 더 나아갑니다). https://www.tutorialexample.com/best-practice-to-python-convert-svg-to-png-with-svglib-python-tutorial/

지금까지 좋아 보인다. 그래서 같은 상황에 처한 사람을 위해 공유합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.