개발/Python

[파이썬] SVG를 PNG로 변환

MinorMan 2022. 10. 7. 08:36
반응형

<질문>

어떻게 변환합니까svg 에게png, 파이썬에서? 보관하고 있습니다svg 의 경우StringIO. pyCairo 라이브러리를 사용해야 합니까? 그 코드를 어떻게 작성합니까?


<답변1>

다음은 내가 사용한 것입니다.cairosvg:

from cairosvg import svg2png

svg_code = """
    
        
        
        
    
"""

svg2png(bytestring=svg_code,write_to='output.png')

그리고 그것은 매력처럼 작동합니다!

더보기:cairosvg document


<답변2>

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

우분투가 있다python-rsvg package 제공합니다. 소스 코드가 "gnome-python-desktop" Gnome 프로젝트 GIT 저장소에 포함되어 있기 때문에 Google에서 이름을 검색하는 것은 좋지 않습니다.

SVG를 카이로로 렌더링하는 미니멀리스트 "hello world"를 만들었습니다. 표면을 만들고 디스크에 씁니다.

import cairo
import rsvg

img = cairo.ImageSurface(cairo.FORMAT_ARGB32, 640,480)

ctx = cairo.Context(img)

## handle = rsvg.Handle()
# or, for in memory SVG data:
handle= rsvg.Handle(None, str())

handle.render_cairo(ctx)

img.write_to_png("svg.png")

업데이트: 2014년 기준 Fedora Linux 배포에 필요한 패키지는 다음과 같습니다.gnome-python2-rsvg. 위의 스니펫 목록은 여전히 있는 그대로 작동합니다.


<답변3>

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에서 설정한 개체 ID로. 그것은 다른 모든 것을 숨깁니다.

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

<답변4>

나는 사용하고있다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)

<답변5>

만족스러운 답변을 찾지 못했습니다. 언급된 모든 라이브러리에는 Python 3.6에 대한 지원을 중단하는 Cairo와 같은 문제가 있습니다(약 3년 전에 Python 2 지원이 중단되었습니다!). 또한 언급된 라이브러리를 Mac에 설치하는 것은 고통스러운 일이었습니다.

마지막으로 가장 좋은 해결책은svglib +보고서 연구실. 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")

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


<답변6>

이 시도:http://cairosvg.org/

사이트는 다음과 같이 말합니다.

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

업데이트 November 25, 2016:

2.0.0은 새로운 주요 버전이며 변경 로그에는 다음이 포함됩니다. Python 2 지원 중단


<답변7>

방금 여기에서 찾은 또 다른 솔루션How to render a scaled SVG to a 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 파서/렌더러가 아닐 수도 있습니다.


<답변8>

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)

<답변9>

다음은 rsvg(현재 Windows에서는 사용할 수 없음)를 사용하지 않는 다른 솔루션입니다. 다음을 사용하여 cairosvg만 설치하십시오.pip install CairoSVG

from cairosvg import svg2png
svg_code = open("input.svg", 'rt').read()
svg2png(bytestring=svg_code,write_to='output.png')

<답변10>

사용pycairo 그리고librsvg SVG 스케일링 및 비트맵 렌더링을 달성할 수 있었습니다. SVG가 원하는 출력인 정확히 256x256 픽셀이 아니라고 가정하면 rsvg를 사용하여 SVG를 Cairo 컨텍스트로 읽은 다음 크기를 조정하고 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 웹사이트에서 약간의 수정을 가했습니다. 또한 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)

<답변11>

다음은 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픽셀이었습니다.)


<답변12>

이 파이썬 스크립트를 사용해보십시오:

cairosvg를 설치하는 것을 잊지 마십시오:pip3 install cairosvg

#!/usr/bin/env python3
import os
import cairosvg

for file in os.listdir('.'):
    if os.path.isfile(file) and file.endswith(".svg"):
        name = file.split('.svg')[0]
        cairosvg.svg2png(url=name+'.svg',write_to=name+'.png')


<답변13>

Gtk.Image 및 Gdk.Pixbuf를 사용해보십시오.

import gi
gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0')

from gi.repository import Gdk, Gtk
from PIL import Image

image = Gtk.Image()
image.set_from_file("path/to/image.svg")
pb = image.get_pixbuf()
pb.savev("path/to/convented/image.jpeg","jpeg",[],[])
im = Image.open("path/to/convented/image.jpeg")
pix = im.load()
print(pix[1,1])

<답변14>

사실 저는 파이썬(Cairo, Ink.. 등) 외에 다른 것에 의존하고 싶지 않았습니다. 내 요구 사항은 가능한 한 간단하고 기껏해야 단순해야했습니다.pip install "savior" 충분할 것이므로 위의 항목 중 하나가 저에게 적합하지 않은 이유입니다.

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

지금까지는 좋아보입니다. 그래서 혹시 저와 같은 상황에 처하신 분이 계실까 해서 공유합니다.


<답변15>

여기에 있는 모든 답변은 훌륭하지만 SVG 파일을 내보낼 수 있는 베개 이미지 인스턴스로 로드하는 간단한 라이브러리를 만들었다고 언급하겠습니다. blj의 답변과 같이 잉크스케이프를 사용하지만 임시 파일이 만들어지지 않도록 stdout으로 렌더링합니다. README에 몇 가지 기본적인 사용법이 있습니다.

https://github.com/jlwoolf/pillow-svg

편집하다:
링크가 무효화될 수 있으므로 제안된 대로 다음은 간략한 설명입니다.

라이브러리는 잉크스케이프의 명령줄 인터페이스를 사용하여 python 하위 프로세스 라이브러리를 사용하여 이미지를 특정 크기 또는 dpi의 png로 변환합니다. 설정하여--export-filename 에게-, 잉크스케이프는 출력을 stdout으로 리디렉션합니다. 처음 두 줄은 버리고 나머지 출력은 다음으로 전달됩니다.PIL.Image.open, 베개 이미지 인스턴스로 변환합니다.

import subprocess
from PIL import Image

options = ["inkscape", "--export-filename=-", "--export-type=png", "file.svg"]

pipe = subprocess.Popen(options, stdout=subprocess.PIPE)

pipe.stdout.readline()
pipe.stdout.readline()

img = Image.open(pipe.stdout)

거기에서 필요한 베개 이미지 작업(jpg로 내보내기, 크기 조정, 자르기 등)을 수행할 수 있습니다.

편집 2:
에 대한 지원이 추가되었습니다.skia-python (완전히 테스트하지는 않았지만 지금까지 작동하는 것 같습니다). 이렇게 하면 단 한 번의 pip 설치로 svg를 png로 변환할 수 있습니다(inkscape를 사용할 필요 없음).

다음은 라이브러리가 skia-python을 사용하는 방법에 대한 설명입니다.

먼저 svg 파일이skia.SVGDOM. 거기에서 다음을 사용하여 SVGDOM의 치수를 가져올 수 있습니다.containerSize. 그 다음에skia.Surface 원하는 이미지 출력 크기로 만들어집니다. svg가 표면에 맞도록 캔버스 크기가 조정된 다음 svg가 렌더링됩니다. 거기에서 이미지 스냅샷을 만들어 다음으로 제공할 수 있습니다.PIL.Image.open.

import skia
from PIL import Image

skia_stream = skia.Stream.MakeFromFile("file.svg")
skia_svg = skia.SVGDOM.MakeFromStream(skia_stream)

svg_width, svg_height = skia_svg.containerSize()
surface_width, surface_height = 512, 512

surface = skia.Surface(surface_width, surface_height)
with surface as canvas:
    canvas.scale(surface_width / svg_width, surface_height / svg_height)
    skia_svg.render(canvas)

with io.BytesIO(surface.makeImageSnapshot().encodeToData()) as f:
            img = Image.open(f)
            img.load()

편집 3:
나는 훨씬 더 많은 라이브러리에 살을 붙였다. 이제 쉬운 svg 변환을 위한 명령줄 유틸리티와 사용법을 설명하는 추가 문서가 있습니다. 도움이 되기를 바랍니다!

반응형