【问题标题】:Differences while rendering SVG with librsvg and Python使用 librsvg 和 Python 渲染 SVG 时的差异
【发布时间】:2021-08-26 02:53:57
【问题描述】:

根据将 SVG 渲染为整个文档还是作为单个元素显示渲染的差异。

我使用 Inkscape 创建了一个简单的 SVG 图形,并希望使用 Python 对其进行渲染。我决定 librsvg 是要走的路。这是我的 SVG,从 Inkscape 保存为“普通 SVG”(没有 Inkscape 特定的扩展)。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
   width="23.105469mm"
   height="23.10545mm"
   viewBox="0 0 23.105469 23.10545"
   version="1.1"
   id="svg1380"
   xmlns:xlink="http://www.w3.org/1999/xlink"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:svg="http://www.w3.org/2000/svg">
  <defs
     id="defs1377">
    <radialGradient
       xlink:href="#SphereBlueGlow"
       id="radialGradient17266-1-5-3"
       cx="206.91444"
       cy="205.5472"
       fx="206.91444"
       fy="205.5472"
       r="11.552734"
       gradientTransform="translate(-188.33616,-3.103272)"
       gradientUnits="userSpaceOnUse" />
    <linearGradient
       id="SphereBlueGlow">
      <stop
         style="stop-color:#ffffff;stop-opacity:1"
         offset="0"
         id="stop954-7" />
      <stop
         style="stop-color:#44ccff;stop-opacity:0"
         offset="0.69538838"
         id="stop956-4" />
      <stop
         style="stop-color:#000000;stop-opacity:0"
         offset="1"
         id="stop958-1" />
    </linearGradient>
    <radialGradient
       xlink:href="#SphereSpecularReflection"
       id="radialGradient868-5-1-3-3-5-3-5-8-5-2-9-0-9-3-9-2-0-2"
       gradientUnits="userSpaceOnUse"
       gradientTransform="matrix(0.11379011,0.15082671,-0.14646196,0.11049697,33.91806,171.06396)"
       cx="60.713989"
       cy="169.90594"
       fx="60.713989"
       fy="169.90594"
       r="37.436264" />
    <linearGradient
       id="SphereSpecularReflection">
      <stop
         style="stop-color:#e6e6e6;stop-opacity:1"
         offset="0"
         id="stop944" />
      <stop
         style="stop-color:#8e8e8e;stop-opacity:0"
         offset="0.37699515"
         id="stop946" />
      <stop
         style="stop-color:#000000;stop-opacity:0.02313977"
         offset="1"
         id="stop948" />
    </linearGradient>
  </defs>
  <g
     id="layer1"
     transform="translate(3.4848234,-128.62724)">
    <g
       id="zauberplatzPassiv"
       transform="translate(-10.51038,-62.263795)">
      <ellipse
         style="mix-blend-mode:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.155336;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.529412"
         id="path833-3-7-9-8-0-7-1-4-0-2-1-9-9-7-6-44-5-9"
         cx="18.578291"
         cy="202.44376"
         rx="11.552734"
         ry="11.552725" />
      <ellipse
         style="mix-blend-mode:normal;fill:url(#radialGradient17266-1-5-3);fill-opacity:1;stroke:none;stroke-width:0.155336;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.529412"
         id="path833-3-7-9-8-0-7-1-4-0-2-1-9-9-7-6-4-6-5-2"
         cx="18.578291"
         cy="202.44376"
         rx="11.552734"
         ry="11.552725" />
      <ellipse
         style="mix-blend-mode:hard-light;fill:url(#radialGradient868-5-1-3-3-5-3-5-8-5-2-9-0-9-3-9-2-0-2);fill-opacity:1;stroke:none;stroke-width:0.155336;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.529412"
         id="path833-1-7-1-6-8-3-7-2-0-6-1-8-0-8-4-0-9-0"
         cx="18.578291"
         cy="202.44376"
         rx="11.552734"
         ry="11.552725" />
    </g>
  </g>
</svg>

我用于渲染的 Python 代码(希望它能在这个问题的减少中幸存下来):

import gi
gi.require_version('Rsvg', '2.0')
from gi.repository import Rsvg
import cairo

def render_image(svg):
    ratio = svg.props.em / svg.props.dpi_x
    svg.set_dpi(160 / ratio)

    dim = svg.get_dimensions()
    # create the cairo context
    surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, dim.width, dim.height)
    context = cairo.Context(surface)
    svg.render_cairo(context)
    surface.write_to_png('sphere_used.image.png')

def render_elements (svg):
    rect = Rsvg.Rectangle()
    rect.x = 0
    rect.y = 0
    rect.width = 160
    rect.height = 160
    # create the cairo context
    surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(rect.width), int(rect.height))
    context = cairo.Context(surface)
    svg.render_element(context, '#zauberplatzPassiv', rect)
    surface.write_to_png('sphere_used.element.png')

if __name__ == '__main__':
    # use rsvg to render the cairo context
    svg = Rsvg.Handle().new_from_file(INPUTFILE)
    render_image(svg)
    render_elements(svg)

render_image(svg) 的输出似乎与我在 Inkscape 中所做的相同:

相比之下,render_element(svg) 的输出错过了镜面反射:

显然,librsvg 支持所有使用的 SVG 功能,并且能够正确显示图像。但是在选择一个元素时,出现了一些问题。 我可以在 SVG 或 Python 方面做些什么来让它们看起来相同吗?

我可以想象在这两种情况下应用不同 SVG 转换的顺序是不同的,导致反射被渲染到屏幕外。但我对 SVG 的了解还不够。

【问题讨论】:

    标签: python svg cairo librsvg rsvg


    【解决方案1】:

    罪魁祸首是mix-blend-mode:hard-light;

    我清理了 SVG,重置了所有的翻译,但高亮仍然丢失。只有在将mix-blend-modehard-light 设置为normal 后它才重新出现。

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <!-- Created with Inkscape (http://www.inkscape.org/) -->
    
    <svg
       width="160px"
       height="160px"
       viewBox="0 0 160 160"
       version="1.1"
       id="svg1380"
       xmlns:xlink="http://www.w3.org/1999/xlink"
       xmlns="http://www.w3.org/2000/svg"
       xmlns:svg="http://www.w3.org/2000/svg">
      <defs
         id="defs1377">
        <radialGradient
           xlink:href="#SphereBlueGlow"
           id="circular_glow"
           cx="80"
           cy="80"
           fx="80"
           fy="80"
           r="80"
           gradientUnits="userSpaceOnUse" />
        <linearGradient
           id="SphereBlueGlow">
          <stop
             style="stop-color:#ffffff;stop-opacity:1"
             offset="0"
             id="stop954-7" />
          <stop
             style="stop-color:#44ccff;stop-opacity:0"
             offset="0.69538838"
             id="stop956-4" />
          <stop
             style="stop-color:#000000;stop-opacity:0"
             offset="1"
             id="stop958-1" />
        </linearGradient>
        <radialGradient
           xlink:href="#SphereSpecularReflection"
           id="circular_specular_reflection"
           gradientUnits="userSpaceOnUse"
           gradientTransform="matrix(0.65,0,0,0.65,10,5)"
           cx="80"
           cy="80"
           fx="80"
           fy="80"
           r="80" />
        <linearGradient
           id="SphereSpecularReflection">
          <stop
             style="stop-color:#e6e6e6;stop-opacity:1"
             offset="0"
             id="stop000" />
         <stop
             style="stop-color:#e6e6e6;stop-opacity:1"
             offset="0.05"
             id="stop040" />
          <stop
             style="stop-color:#e6e6e6;stop-opacity:0.5"
             offset="0.14"
             id="stop060" />
          <stop
             style="stop-color:#e6e6e6;stop-opacity:0.1"
             offset="0.2"
             id="stop080" />
          <stop
             style="stop-color:#e6e6e6;stop-opacity:0"
             offset="0.3"
             id="stop020" />
          <stop
             style="stop-color:#e6e6e6;stop-opacity:0"
             offset="1"
             id="stop100" />
        </linearGradient>
      </defs>
      <g
         id="layer1">
        <g
           id="zauberplatzPassiv">
          <ellipse
             style="mix-blend-mode:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.155336;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.529412"
             id="black-ellipse"
             cx="80"
             cy="80"
             rx="80"
             ry="80" />
          <ellipse
             style="mix-blend-mode:normal;fill:url(#circular_glow);fill-opacity:1;stroke:none;stroke-width:0.155336;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.529412"
             id="glow-ellipse"
             cx="80"
             cy="80"
             rx="80"
             ry="80" />
          <ellipse
             style="mix-blend-mode:normal;fill:url(#circular_specular_reflection);fill-opacity:1;stroke:none;stroke-width:0.155336;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.529412"
             id="highlight-ellipse"
             cx="80"
             cy="80"
             rx="80"
             ry="80" />
        </g>
      </g>
    </svg>
    

    我必须编辑渐变以使其更适合这种混合模式,但结果对我来说已经足够好了:

    我仍然很好奇 hard-light 有什么特别之处,所以如果有任何 librsvg 专家出现,他们可能会对此有所了解。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-10
      • 2015-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-03
      • 2014-07-09
      • 2012-04-24
      相关资源
      最近更新 更多