Text Rotation not taken into account by getBBox

Michael Harris <[email protected]> Thu, 26 May 2016 05:25:07 +0000
Newsgroups gmane.text.xml.batik.user
Message-ID <[email protected]>
Hi,

First a little background about what I am trying to do. I have a Javascript=
 / D3 based charting engine being used in one of our projects, and this cha=
rting engine is required to work both in a web browser and in an offline ba=
ckend to prepare static chart images.

For the latter case I am using node.js as the JS execution environment and =
Batik (with node-java bridge) to provide the DOM implementation.

For the most part it is working well, but I have a few strange anomalies.

The chart engine uses the getBBox method to determine the size of various i=
tems and adjust margins etc accordingly. What I am finding is that batik do=
es not take into account rotation of text when calculating the bounding box=
, while browser DOM engines do.

To illustrate this, consider the following svg:

<?xml version=3D"1.0" standalone=3D"no"?>
<svg width=3D"1000" height=3D"1000" version=3D"1.1" xmlns=3D"http://www.w3.=
org/2000/svg">
   =20
    <g id=3D"one">
        <g transform=3D"translate(0,100)">
            <line x1=3D"0" y1=3D"0" x2=3D"100" y2=3D"0" style=3D"stroke: bl=
ack;"/>
            <text y=3D"1em" x=3D"0">Hello</text>
        </g>
        <g transform=3D"translate(200,100)">
            <line x1=3D"0" y1=3D"0" x2=3D"100" y2=3D"0" style=3D"stroke: bl=
ack;"/>
            <text y=3D"1em" x=3D"0">Hello</text>
        </g>
    </g>
   =20
    <g id=3D"two">
        <g transform=3D"translate(0,500)">
            <line x1=3D"0" y1=3D"0" x2=3D"100" y2=3D"0" style=3D"stroke: bl=
ack;"/>
            <text y=3D"1em" x=3D"0" transform=3D"rotate(-90)">Hello</text>
        </g>
        <g transform=3D"translate(200,500)">
            <line x1=3D"0" y1=3D"0" x2=3D"100" y2=3D"0" style=3D"stroke: bl=
ack;"/>
            <text y=3D"1em" x=3D"0" transform=3D"rotate(-90)">Hello</text>
        </g>
    </g>

</svg>

and the following little java program:

import java.io.IOException;

import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
import org.apache.batik.util.XMLResourceDescriptor;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import java.io.FileOutputStream;

import org.w3c.dom.Document;
import org.w3c.dom.svg.SVGGElement;
import org.w3c.dom.svg.SVGRect;

class BatikBboxTest {

    public static void main(String [ ] args) {
       =20
        try {
           =20
            String parser =3D XMLResourceDescriptor.getXMLParserClassName()=
;
            SAXSVGDocumentFactory f =3D new SAXSVGDocumentFactory(parser);
            String uri =3D "file:test.svg";
            Document document =3D f.createSVGDocument(uri);

            PNGTranscoder transcoder =3D new PNGTranscoder();
            TranscoderInput input =3D new TranscoderInput(document);
            FileOutputStream ostream =3D new FileOutputStream("test.png");
            TranscoderOutput output =3D new TranscoderOutput(ostream);
           =20
            transcoder.transcode(input, output);
            ostream.flush();
            ostream.close();
           =20
            SVGGElement g1 =3D (SVGGElement)document.getElementById("one");
            SVGRect box1 =3D g1.getBBox();
            System.out.printf("getBBox =3D x=3D%f,y=3D%f - w=3D%f,h=3D%f\n"=
, box1.getX(), box1.getY(), box1.getWidth(), box1.getHeight());
           =20
            SVGGElement g2 =3D (SVGGElement)document.getElementById("two");
            SVGRect box2 =3D g2.getBBox();
            System.out.printf("getBBox =3D x=3D%f,y=3D%f - w=3D%f,h=3D%f\n"=
, box2.getX(), box2.getY(), box2.getWidth(), box2.getHeight());

        } catch (Exception ex) {
            System.err.println("Error: "+ex);
        }
       =20
    }
  =20
}

The output I get from this is:

getBBox =3D x=3D0.000000,y=3D-29.761719 - w=3D100.000000,h=3D29.761719
getBBox =3D x=3D0.000000,y=3D-29.761719 - w=3D100.000000,h=3D29.761719

I have an equivalent in-browser version here: https://rawgit.com/harmic/a57=
f37bd6d3773f3a6e900779cdc7941/raw/909c3222abf8627c34ae9ac24ca8c3572fad7222/=
test_bbox_textrot.html

In this version you get the output:

getBBox =3D x=3D0,y=3D100 - w=3D300,h=3D19
getBBox =3D x=3D0,y=3D464 - w=3D300,h=3D35

Note that the height is different for the first and second <g>, because the=
 text in the second <g> is rotated.

That is what I was expecting, but Batik does not do it.

Another strange thing is that batik gives the X and Y coordinates of the <g=
>'s as being the same, even though they clearly are not. The browsers get i=
t right.

I am using Java 1.8 & Batik 1.7. The HTML/JS equivalent works OK with Chrom=
e 50 and FF 45.

Thanks for any insights!

Regards
Mike