Reading transparent SVG files

Magick++ is an object-oriented C++ interface to ImageMagick. Use this forum to discuss, make suggestions about, or report bugs concerning Magick++.
Post Reply
mrsam
Posts: 5
Joined: 2014-03-23T20:32:08-07:00
Authentication code: 6789

Reading transparent SVG files

Post by mrsam »

I am trying to read a small SVG file with a transparent background. This is what I'm doing:

Code: Select all

Magick::Image image;

image.type(Magick::TrueColorMatteType);

image.read(Magick::Geometry(width, height), filename);

auto packet=image.getConstPixels(0, 0, width, height);
Scanning all of the pixel packets I get back, each packet's opacity value is 0, making all pixels technically transparent. If I override the opacity, and make each pixel fully opaque, I'm getting the right image.

Well, more or less. A second, minor problem, is that ImageMagick is convinced that the SVG file's dimensions are 40x40:

$ identify images/default/checkbox1.svg
images/default/checkbox1.svg SVG 40x40 40x40+0+0 16-bit sRGB 1.22KB 0.000u 0:00.009

In Inkscape, this was created as a 32x32 image, and other tools, such as eog, correctly report it as a 32x32 image (and eog correctly displays the image with its transparent background).
User avatar
dlemstra
Posts: 1570
Joined: 2013-05-04T15:28:54-07:00
Authentication code: 6789
Contact:

Re: Reading transparent SVG files

Post by dlemstra »

Can you add a link to your svg file or post the content in a code block?
.NET + ImageMagick = Magick.NET https://github.com/dlemstra/Magick.NET, @MagickNET, Donate
mrsam
Posts: 5
Joined: 2014-03-23T20:32:08-07:00
Authentication code: 6789

Re: Reading transparent SVG files

Post by mrsam »

Here's a couple of them. I wouldn't mind hacking the XML, if it meant getting the transparency right, but this is coming straight out of Inkscape.

Code: Select all

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

<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   version="1.1"
   width="32"
   height="32"
   id="svg3866">
  <defs
     id="defs3868" />
  <metadata
     id="metadata3871">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
        <dc:title></dc:title>
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <g
     id="layer1">
    <rect
       width="12"
       height="12"
       x="10"
       y="10"
       id="rect3876"
       style="fill:none;stroke:#4d4d4d" />
    <rect
       width="14"
       height="14"
       x="9"
       y="9"
       id="rect3878"
       style="fill:none;stroke:#000000;stroke-opacity:1" />
    <rect
       width="10"
       height="10"
       x="11"
       y="11"
       id="rect3880"
       style="fill:none;stroke:#000000;stroke-opacity:1" />
  </g>
</svg>

Code: Select all

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

<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   version="1.1"
   width="32"
   height="32"
   id="svg3866">
  <defs
     id="defs3868" />
  <metadata
     id="metadata3871">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
        <dc:title></dc:title>
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <g
     id="layer1">
    <rect
       width="12"
       height="12"
       x="10"
       y="10"
       id="rect3876"
       style="fill:none;stroke:#4d4d4d" />
    <rect
       width="14"
       height="14"
       x="9"
       y="9"
       id="rect3878"
       style="fill:none;stroke:#000000;stroke-opacity:1" />
    <rect
       width="10"
       height="10"
       x="11"
       y="11"
       id="rect3880"
       style="fill:none;stroke:#000000;stroke-opacity:1" />
    <path
       d="M 7,12 16,20 29,1 16,16 z"
       id="path3901"
       style="fill:#008000;stroke:#008000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
    <path
       d="m 7,13 9,8"
       id="path3903"
       style="fill:none;stroke:#004200;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
    <path
       d="M 29,2 16,21"
       id="path4413"
       style="fill:none;stroke:#004200;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
  </g>
</svg>
User avatar
dlemstra
Posts: 1570
Joined: 2013-05-04T15:28:54-07:00
Authentication code: 6789
Contact:

Re: Reading transparent SVG files

Post by dlemstra »

You should set the image.backgroundColor to transparent before you read the image.

Which delegate are you using for SVG? With RSVG on windows I get the correct dimensions:

Code: Select all

convert -list format
SVG  SVG       rw+   Scalable Vector Graphics (RSVG 2.40.1)
.NET + ImageMagick = Magick.NET https://github.com/dlemstra/Magick.NET, @MagickNET, Donate
mrsam
Posts: 5
Joined: 2014-03-23T20:32:08-07:00
Authentication code: 6789

Re: Reading transparent SVG files

Post by mrsam »

So now I have:

Code: Select all

image.type(Magick::TrueColorMatteType);
image.backgroundColor(Magick::Color(0, 0, 0, 0));
After loading the image, the opacity of every pixel is still 0. It's not really that I'm not seeing the transparent background. With opacity 0, all pixels are transparent. There is one difference, though. After loading the image, the red, green, and blue components of transparent pixels are all 0. Without the backgroundColor() call, they're all QUANTUM_MAX. So, the SVG data is getting rendered into the image, but the rendered pixels remain at opacity 0.

I'm running 6.8.6.3 on Linux.

$ convert -list format | grep SVG
MSVG SVG rw+ ImageMagick's own SVG internal renderer
SVG SVG rw+ Scalable Vector Graphics (RSVG 2.37.0)
SVGZ SVG rw+ Compressed Scalable Vector Graphics (RSVG 2.37.0)

And, despite what the XML says:

$ identify images/default/checkbox2.svg
images/default/checkbox2.svg SVG 40x40 40x40+0+0 16-bit sRGB 1.76KB 0.000u 0:00.000

Do you also get the 40x40 dimensions?
mrsam
Posts: 5
Joined: 2014-03-23T20:32:08-07:00
Authentication code: 6789

Re: Reading transparent SVG files

Post by mrsam »

Maybe I'm not interpreting the opacity value correctly. I thought that the pixel's opacity value of 0 means total transparency, and QUANTUM_MAX is solid color, the same way X RENDER interprets the alpha channel.

If I set backgroundColor to Color(0, 0, 0, QUANTUM_MAX), then after loading the SVG image the transparent pixels still have a QUANTUM_MAX opacity value, but the solid color pixels loaded from the SVG file have an opacity of 0. So, by doing that and subtracting each pixels opacity from QUANTUM_MAX, I end up with the correct alpha channel value. That feels wrong, though, and doesn't explain why a 32x32 image is seen as a 40x40 image. Haven't yet analyzed where the extra pixels are...
User avatar
dlemstra
Posts: 1570
Joined: 2013-05-04T15:28:54-07:00
Authentication code: 6789
Contact:

Re: Reading transparent SVG files

Post by dlemstra »

My output image is 32x32, you should probably upgrade librsvg. And yes ImageMagick is handling transparency incorrectly, we will fix this in IM7.
.NET + ImageMagick = Magick.NET https://github.com/dlemstra/Magick.NET, @MagickNET, Donate
mrsam
Posts: 5
Joined: 2014-03-23T20:32:08-07:00
Authentication code: 6789

Re: Reading transparent SVG files

Post by mrsam »

Actually it turns out that I do have the updated librsvg2 2.40, it was updated after ImageMagick was built, and -list format was just reporting the old version. Rebuilding ImageMagick made it report 2.40, but resulted in no change in identity's output.

To make sure which library was getting loaded, I straced it and confirmed this. But it turns out that the first thing that was happening was the library trying to fork and exec inkscape, for the apparent purpose of converting the SVG file to PNG, before loading it.

That was failing since inkscape was not installed on that particular box; and afterwards that the incorrect size of 40x40 was getting reported back to me. After installing inkscape, identity started showing the correct size. So that answers that -- well, not really. Tried a test program using librsvg2 directly. Calling rsvg_handle_new_from_file(), followed by rsvg_handle_get_dimensions(). This was returning the correct 32x32 dimension, so librsvg2 was getting it right. The breakdown, when inkscape was not installed, was happening somewhere else.
Post Reply