Преобразование svg-объекта в png Python [duplicate]

Вы можете добиться эффекта каменной кладки в соответствии с вашим снимком экрана, но вы установили высоту внешнего div динамически

html {
  box-sizing: border-box;
}
*,
*:before,
*:after {
  box-sizing: inherit;
}
.item-list {
  max-width: 400px;
  border: 1px solid red;
  display: -ms-flexbox;
	-ms-flex-direction: column;
	-ms-flex-wrap: wrap;
	display: flex;
	flex-direction: column;
	flex-wrap: wrap;
	height: 100vw;
}
.item-list__item {
  border: 1px solid green;
  width: 50%;
}
<div class="item-list" >
  <div class="item-list__item">
    Is we miles ready he might going. Own books built put civil fully blind fanny. Projection appearance at of admiration no. As he totally cousins warrant besides ashamed do. Therefore by applauded acuteness supported affection it. Except had sex limits
    county enough the figure former add. Do sang my he next mr soon. It merely waited do unable.
  </div>
  <div class="item-list__item">
    Is we miles ready he might going. Own books built put civil fully blind fanny. Projection appearance at of admiration no. As he totally cousins warrant besides ashamed do.
  </div>
  <div class="item-list__item">
    Is we miles ready he might going. Own books built put civil fully blind fanny. Projection appearance at of admiration no. As he totally cousins warrant besides ashamed do. Therefore by applauded acuteness supported affection it. Except had sex limits
  </div>
  <div class="item-list__item">
    Is we miles ready he might going. Own books built put civil fully blind fanny. Projection appearance at of admiration no. As he totally cousins warrant besides ashamed do.
  </div>
  <div class="item-list__item">
    Is we miles ready he might going. Own books built put civil fully blind fanny. Projection appearance at of admiration no. As he totally cousins warrant besides ashamed do. Therefore by applauded acuteness supported affection it. Except had sex limits
  </div>
</div>

76
задан jsbueno 4 January 2013 в 05:39
поделиться

9 ответов

Ответ: « pyrsvg » - связка Python для librsvg .

Существует пакет Ubuntu python-rsvg . Поиск Google для его имени неудовлетворительный, потому что его исходный код, кажется, содержится внутри «Gnome-python-desktop» Gn-репозитория GIT-проекта.

Я сделал минималистский «мир привет», который отображает 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. Вышеприведенный список фрагментов все еще работает как есть.

51
ответ дан jsbueno 21 August 2018 в 02:46
поделиться
  • 1
    Отлично, работает красиво. Но есть ли способ позволить cairo самостоятельно определить высоту и ширину изображения? Я просмотрел файл *.svg, чтобы извлечь HEIGHT и WIDTH оттуда, но он установлен в 100%. Конечно, я могу изучить свойства изображения, но поскольку это всего лишь один шаг в обработке изображений, это не то, что я хочу. – quapka 9 June 2014 в 10:19
  • 2
    Если "ширина" и "высота" ваших файлов установлены на 100%, нет волшебства Cairo или rsvg, чтобы угадать размер: такие файлы SVG были оставлены независимо от программного обеспечения для создателя (/ person). Окружающий HTML-код для импорта SVG-файла будет обеспечивать физический размер. Однако "Ручка" У объекта rsvg есть метод .get_dimension_data(), который работал для моего файла примера (хорошо выполненный SVG) - попробуйте. – jsbueno 12 June 2014 в 06:50
  • 3
    с 2014 года, для ubuntu, вы можете использовать: apt-get install python-rsvg – t1m0 23 September 2014 в 15:11
  • 4
    Есть ли быстрая команда для добавления белого фона к изображению, если его текущий фон прозрачен? – fiatjaf 7 January 2015 в 04:23
  • 5
    @jsbueno Я использую Windows 8.1 и python 2.7.11 Как установить cairo и rsvg и заставить его работать. Я изо всех сил старался сделать эту работу. BTW +1 для вашего подробного объяснения. – Marlon Abeykoon 9 September 2016 в 10:24

Установите 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}
35
ответ дан bignose 21 August 2018 в 02:46
поделиться

SVG-масштабирование и рендеринг PNG

Используя pycairo и librsvg , я смог добиться масштабирования и рендеринга SVG в растровое изображение. Предполагая, что ваш SVG не соответствует 256x256 пикселям, желаемый результат, вы можете прочитать в SVG в контексте Cairo с помощью rsvg, а затем масштабировать его и записать в 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 с некоторыми незначительными изменениями. Также хороший пример того, как вызвать C-библиотеку из 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)
1
ответ дан Cameron Lowell Palmer 21 August 2018 в 02:46
поделиться

Другое решение, которое я только что нашел здесь Как отобразить масштабированный 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 (и Я использую его для других вещей, так легко для меня).

Тем не менее, я заметил несколько проблем при преобразовании флагов страны из Викимедиа, поэтому, возможно, не самый надежный svg-парсер / рендеринг.

6
ответ дан Community 21 August 2018 в 02:46
поделиться

Попробуйте следующее: http://cairosvg.org/

Сайт говорит:

CairoSVG написан на чистом питоне и только зависит от Pycairo. Известно, что он работает с Python 2.6 и 2.7.

Обновление 25 ноября 2016 г. :

2.0.0 является новая основная версия, ее журнал изменений:

  • Поддержка Drop Python 2
11
ответ дан Daniel F 21 August 2018 в 02:46
поделиться
  • 1
    К сожалению, есть две проблемы. Во-первых, он не обрабатывает <clipPath><rect ... /></clipPath>. Во-вторых, он не принимает параметр -d (DPI). – Ray 20 November 2012 в 11:58
  • 2
    @Ray, пожалуйста, отправьте отчеты об ошибках / запросы функций на трекер CairoSVG ! – Simon Sapin 22 January 2013 в 14:49
  • 3
  • 4
    @Ray, на самом деле опция -d / --dpi существует некоторое время, и мне говорят, что поддержка & lt; clippath & gt; был добавлен несколько недель назад в версии git. – Simon Sapin 23 January 2013 в 00:13
  • 5
    @Simon, хорошо! Спасибо! :) – Ray 23 January 2013 в 14:52

Вот что я использовал 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 document

41
ответ дан duan 21 August 2018 в 02:46
поделиться
  • 1
    Здравствуй. Вы знаете, как я могу сделать то же самое, но не писать в файл? Мне нужно вывести png-контент в браузер с веб-сервера, чтобы пользователь мог загрузить изображение. Сохранение файла png не является допустимым вариантом в нашем проекте, поэтому мне это нужно. благодаря – estemendoza 25 February 2013 в 20:11
  • 2
    Я делал это сам. В основном это зависит от того, какие инструменты или фреймворки у вас под рукой при работе с вашими веб-запросами, но что бы это ни было, основная идея заключается в том, что svg2png принимает объект stream в параметре write_to, и это может либо ваш объект HTTP Response (который в большинстве фреймворков является файлоподобным объектом), либо какой-либо другой поток, который затем служит в браузере с помощью заголовка Content-Disposition. см. здесь: stackoverflow.com/questions/1012437/… – nemesisfixx 26 February 2013 в 08:59
  • 3
    Да, спасибо, теперь я смог заставить его работать. – estemendoza 26 February 2013 в 18:50
  • 4
    Для тех, кто испытывает проблемы с этим кодом, так же, как и я: 1). bytestring принимает байты, поэтому сначала конвертируйте строку с bytestring=bytes(svg,'UTF-8') 2). файл должен быть двоичным, поэтому open('output.png','wb') – Serj Zaharchenko 19 October 2014 в 14:28
  • 5
    cairosvg поддерживает только Python 3.4+. Они отказались от поддержки Python 2 – Marlon Abeykoon 9 September 2016 в 10:32
  • 6

Ниже приведен пример конца Python.

Обратите внимание, что он подавляет некоторый выход жестокости, который 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 на 339 пикселей.)

0
ответ дан Iron Pillow 21 August 2018 в 02:46
поделиться

Небольшое расширение ответа 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)
4
ответ дан Martin Thoma 21 August 2018 в 02:46
поделиться
  • 1
    Я использовал выделение ширины и высоты svg. Я не уверен в стандарте svg, но в некоторых моих SVG-файлах ширина или высота сопровождалась не числовой строкой, такой как «мм» или «px» (например: «250 мм»). Int ('250mm') выдает исключение, и я должен был сделать некоторые дополнительные настройки. – WigglyWorld 15 February 2015 в 12:12

Я использую Wand-py (реализация оболочки Wand вокруг 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)
24
ответ дан streetlogics 21 August 2018 в 02:46
поделиться
  • 1
    вау это действительно самое простое решение. Ницца =) – Robin Winslow 28 April 2014 в 21:33
  • 2
    Жезл работал лот лучше, чем Каир для моих PNG. – qris 9 May 2014 в 17:41
  • 3
    Спасибо @qris - добавили ваш прозрачный код визуализации SVG в свой ответ. – streetlogics 12 May 2014 в 15:40
  • 4
    Я получаю ошибку image.read(blob=svg_file.read(), format="svg") NameError: name 'svg_file' is not defined – adrienlucca.wordpress.com 15 July 2016 в 11:56
  • 5
    svg_file считается «файлом», объект в этом примере, установка svg_file будет выглядеть примерно так: svg_file = File.open(file_name, "r") – streetlogics 15 July 2016 в 18:04
Другие вопросы по тегам:

Похожие вопросы: