CairoSVG icon indicating copy to clipboard operation
CairoSVG copied to clipboard

Pattern fill not scaled correctly

Open mike632t opened this issue 4 years ago • 2 comments

When attempting to convert the SVG below to a PNG image in python the background grid created by filling a rectangle with a defined pattern is not being scaled correctly.

<svg width="500" height="250" style="background:lightgrey">
    
  <svg width="401" height="201" x="50" y="25">
 
    <!-- https://stackoverflow.com/questions/14208673 -->
 
    <defs> <!-- grig pattern definition -->
      <pattern id="smallGrid" width="10" height="10" patternUnits="userSpaceOnUse">
        <path d="M 10 0 L 0 0 0 10" fill="none" stroke="gray" stroke-width="0.5"/>
      </pattern>
      <pattern id="grid" width="100" height="100" patternUnits="userSpaceOnUse">
        <rect width="100" height="100" fill="url(#smallGrid)"/>
        <path d="M 100 0 L 0 0 0 100" fill="none" stroke="gray" stroke-width="1"/>
      </pattern>
    </defs>
    <rect width="100%" height="100%" fill="url(#grid)"/> <!-- Draw grid -->
    <rect width="10" height="0" x="-5" y="200" style="fill:white"/>
    <rect width="10" height="5" x="5" y="195" style="fill:darkviolet"/>
    <rect width="10" height="10" x="15" y="190" style="fill:blue"/>
    <rect width="10" height="20" x="25" y="180" style="fill:darkturquoise"/>
    <rect width="10" height="30" x="35" y="170" style="fill:limegreen"/>
    <rect width="10" height="50" x="45" y="150" style="fill:mediumseagreen"/>
    <rect width="10" height="90" x="55" y="110" style="fill:yellowgreen"/>
    <rect width="10" height="150" x="65" y="50" style="fill:gold"/>
    <rect width="10" height="180" x="75" y="20" style="fill:orange"/>
    <rect width="10" height="195" x="85" y="5" style="fill:darkorange"/>
    <rect width="10" height="200" x="95" y="0" style="fill:red"/>
    <rect width="10" height="195" x="105" y="5" style="fill:darkorange"/>
    <rect width="10" height="180" x="115" y="20" style="fill:orange"/>
    <rect width="10" height="150" x="125" y="50" style="fill:gold"/>
    <rect width="10" height="90" x="135" y="110" style="fill:yellowgreen"/>
    <rect width="10" height="50" x="145" y="150" style="fill:mediumseagreen"/>
    <rect width="10" height="30" x="155" y="170" style="fill:limegreen"/>
    <rect width="10" height="20" x="165" y="180" style="fill:darkturquoise"/>
    <rect width="10" height="10" x="175" y="190" style="fill:blue"/>
    <rect width="10" height="5" x="185" y="195" style="fill:darkviolet"/>
    <rect width="10" height="0" x="195" y="200" style="fill:white"/>
    <rect width="10" height="5" x="205" y="195" style="fill:darkviolet"/>
    <rect width="10" height="10" x="215" y="190" style="fill:blue"/>
    <rect width="10" height="20" x="225" y="180" style="fill:darkturquoise"/>
    <rect width="10" height="30" x="235" y="170" style="fill:limegreen"/>
    <rect width="10" height="50" x="245" y="150" style="fill:mediumseagreen"/>
    <rect width="10" height="90" x="255" y="110" style="fill:yellowgreen"/>
    <rect width="10" height="150" x="265" y="50" style="fill:gold"/>
    <rect width="10" height="180" x="275" y="20" style="fill:orange"/>
    <rect width="10" height="195" x="285" y="5" style="fill:darkorange"/>
    <rect width="10" height="200" x="295" y="0" style="fill:red"/>
    <rect width="10" height="195" x="305" y="5" style="fill:darkorange"/>
    <rect width="10" height="180" x="315" y="20" style="fill:orange"/>
    <rect width="10" height="150" x="325" y="50" style="fill:gold"/>
    <rect width="10" height="90" x="335" y="110" style="fill:yellowgreen"/>
    <rect width="10" height="50" x="345" y="150" style="fill:mediumseagreen"/>
    <rect width="10" height="30" x="355" y="170" style="fill:limegreen"/>
    <rect width="10" height="20" x="365" y="180" style="fill:darkturquoise"/>
    <rect width="10" height="10" x="375" y="190" style="fill:blue"/>
    <rect width="10" height="5" x="385" y="195" style="fill:darkviolet"/>
    
  </svg>
 
  <defs> <!-- arrowhead marker definition -->
    <marker id="arrow" viewBox="0 0 10 10" refX="5" refY="5"
        markerWidth="6" markerHeight="10"
        orient="auto-start-reverse">
      <path d="M 0 0 L 10 5 L 0 10" />
    </marker>
  </defs>
  
  <line x1="50" x2="460" y1="225" y2="225" marker-end="url(#arrow)" style="stroke-width:1;stroke:black;"/>
  <line x1="50" x2="50" y1="225" y2="15" style="stroke-width:1;stroke:black;"/>
  
  <text x="45"  y="25"   style="font-size:10;fill:black;text-anchor:end;dominant-baseline:middle">p</text>
  <text x="450"  y="235"  style="font-size:10;fill:black;text-anchor:middle;dominant-baseline:hanging">t</text>
  
</svg>  

It should be rendered as shown in the image below.

svg-graph-1a

Note are that all the vertical bars, except the violet and dark orange ones, line up with the grid lines as expected and the major and minor graduations are aligned):

The function I'm using to convert the contents of the SVG file to a image is shown below:

def render_svg(_svg):
    _bytes = cairosvg.svg2png(_svg)
    byte_io = io.BytesIO(_bytes)
    return pygame.image.load(byte_io)

This results in the following image:

svg-graph-1b

This shows that that the grid pattern does not align with the vertical bars in the bar chart as expected, and the major and the major and minor graduations are also misaligned.

I'm using Debian Buster with python3.7 (3.7.3-2+deb10u2), python3-pygame (1.9.4.post1+dfsg-3), and (python3-cairosvg 1.0.20-1) installed using apt-get.

Drawing the grid lines one line at a time works as expected.

Hope this is helpful!

Thank you.

mike632t avatar Feb 23 '21 22:02 mike632t

I just encountered the same problem while trying to generate a checkered pattern. In the browser everything looks exactly as calculated and expected but in the created PDF small spacings appear between repetitions of the SVG pattern. Here is a comparison between the two:

vector-comparison

So it doesn’t seem to be an issue with scaling of the tile but rather the start coordinates of each repetition. These extra spacings add up leading to an unusable output – at least if you require mathematically exact results like in the cases presented.

Is there any known workaround for this? I ran into this while using WeasyPrint which utilizes CairoSVG. It seems like this component is soon to be replaced by a new implementation but for now a way to get the expected output would be great.

I’m using WeasyPrint 52.4 with CairoSVG 2.5.2 under Python 3.9.2 on Windows 10.

Thanks!

m2u-84 avatar Mar 14 '21 21:03 m2u-84

I found the same problem. Has anyone found a solution?

luiscastro193 avatar Feb 15 '22 07:02 luiscastro193