1

I followed the instructions (with some additional detail from other sources) from How do I superimpose one SVG image onto another using Apache Batik?

Things are working perfectly most of the time, until now. Now, however, each of my individual svg documents (images) have clip paths. When I place 2 or more images, only the second path is saved in the output. I lose all other clip paths. Is there something I need to do to preserve the clip paths of each image? I looked at the SVG output, and see only one clip path. My code looks like this:

public void PlaceSVGImage(SVGDocument a, Point C)
{       
    String xatt = String.format("%f", C.X);
    String yatt = String.format("%f", C.Y);

    org.w3c.dom.Node ae = SVGC.SVGD.importNode(a.getDocumentElement(), true);

    ((Element) ae).removeAttribute("viewBox");
    ((Element) ae).setAttribute("x", xatt);
    ((Element) ae).setAttribute("y", yatt);

    if (FIRSTCHILD)
    {
        SVGC.SVGD.getDocumentElement().appendChild(ae);
        FIRSTCHILD = false;
        NullNode = ae;
    }
    else
    {
        SVGC.SVGD.getDocumentElement().insertBefore(ae, NullNode);
    }
}

I then use some standard code to display the SVGC.SVGD.

Any insight would be appreciated.

Community
  • 1
  • 1

2 Answers2

1

Based on the comments received, we were able to solve the issue as follows: (a) convert the svg document generated by Batik to a string; then, (b) change the default assignment of clip-path names (Batik names them clippath1, clippath2, etc) to something unique using a simple string-replace. Then, when such svg documents are put together in a (bigger) svg document, the clip-path names will all be different and this issue is solved. For those who might benefit from our code see below. If there is a better way, pl let us know.

public static SVGDocument clipReplacer(SVGDocument SVGD, String S_OLD, String S_NEW)
{
    String SVGString = SVGLib.getString(SVGD);
    SVGDocument doc = null;
    SVGString = SVGString.replaceAll(S_OLD, S_NEW);
    StringReader reader = new StringReader(SVGString);

    //System.out.println(SVGString);

    try
    {
        String parser = XMLResourceDescriptor.getXMLParserClassName();
        SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser);
        doc = f.createSVGDocument("http://www.w3.org/2000/svg", reader);
    }
    catch (Exception ex)
    {
    }
    finally
    {
        reader.close();
    }

    return doc;
}

public static String getString(SVGDocument SVGD)
{
    /*
     * Converts a given SVGDocument to String
     */

    Writer stringWriter = new StringWriter();
    TranscoderInput input = new TranscoderInput(SVGD);
    TranscoderOutput output = new TranscoderOutput(stringWriter);

    SVGTranscoder X = new SVGTranscoder();
    try
    {
        X.addTranscodingHint(SVGTranscoder.KEY_FORMAT,
                SVGTranscoder.VALUE_FORMAT_ON);
        output.setOutputStream(System.out);
        X.transcode(input, output);
    }
    catch (TranscoderException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return stringWriter.toString();
}
0

Clip path elements are referenced by their id attribute.

<clipPath id="clipPath1">
    ...
</clipPAth>

So check that your SVGs don't have duplicate clipPath id attributes. If your SVG files have been made with an SVG editor - such as Illustrator for example - chances are extremely high that they have clip paths elements with the same ids.

Obviously, all the ids in an SVG must be unique. Otherwise the renderer will have no idea which of the identically named <clipPaths> it should be using.

Paul LeBeau
  • 97,474
  • 9
  • 154
  • 181
  • Thanks for the answer. You are right. First of all the as you look at the svg Batik transcoder produces, within the outer group, there are two groups one corresponding to each image. I wonder if this is OK. Secondly, each innner group has a clip path named clipPath1. I was hoping that each of these would be local (and therefore no conflict). As you say, they are not local but global. Is there a way in Batik to actually name the clipPaths so I can make them unique (I can generate unique names)? I currently use a simple g.setClip(generalPath P) to set the clips. – Dr. Parasolian Feb 07 '16 at 12:18
  • `` elements are allowed to have nested `` inside them. It is maybe not common, but it is useful in certain circumstances. `id` attribute values *must* be unique within a document. I haven't used Batik, but I expect you will need to add a `` element manually via the DOM methods. Set its `id`. Then reference that. – Paul LeBeau Feb 07 '16 at 16:49