Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exceptions reading some SVG files and Batik #442

Closed
j-p-sequeira opened this issue Sep 17, 2018 · 23 comments
Closed

Exceptions reading some SVG files and Batik #442

j-p-sequeira opened this issue Sep 17, 2018 · 23 comments

Comments

@j-p-sequeira
Copy link

First of all, I'm really happy with this 3.4.1 release, thank you for a great job! All the problems that I've encountered had been solved, except with some SVG files.

Now, there is a very high chance that this is not a TwelveMonkey's problem, I bet it is an issue within Batik (and I do know that Batik does not support everything) or I'm doing something wrong (like missing some jar files), but I felt it was worth mentioning.

The problem happens only with some SVG images, like the one at the wikipedia page "SVG exported from KOMPAS-Graphic".

When I try to read this file, I get this:

2018-09-17 09:49:50 FINE: null
Enclosed Exception:
The current document is unable to create an element of the requested type (namespace: http://www.w3.org/2000/svg, name: drawing-type). [@meew.FileManager getCurrentImage]
javax.imageio.IIOException: null
Enclosed Exception:
The current document is unable to create an element of the requested type (namespace: http://www.w3.org/2000/svg, name: drawing-type).
	at com.twelvemonkeys.imageio.plugins.svg.SVGImageReader.getWidth(SVGImageReader.java:232)
	at com.twelvemonkeys.imageio.plugins.svg.SVGImageReader.read(SVGImageReader.java:131)
	at javax.imageio.ImageReader.read(ImageReader.java:939)
	at meew.FileManager.getCurrentImage(FileManager.java:2046)
	...
Caused by: org.apache.batik.transcoder.TranscoderException: null
Enclosed Exception:
The current document is unable to create an element of the requested type (namespace: http://www.w3.org/2000/svg, name: drawing-type).
	at org.apache.batik.transcoder.XMLAbstractTranscoder.transcode(XMLAbstractTranscoder.java:134)
	at org.apache.batik.transcoder.SVGAbstractTranscoder.transcode(SVGAbstractTranscoder.java:156)
	at com.twelvemonkeys.imageio.plugins.svg.SVGImageReader$Rasterizer.init(SVGImageReader.java:549)
	at com.twelvemonkeys.imageio.plugins.svg.SVGImageReader$Rasterizer.getDefaultWidth(SVGImageReader.java:562)
	at com.twelvemonkeys.imageio.plugins.svg.SVGImageReader.getWidth(SVGImageReader.java:229)
	... 40 more
Caused by: org.w3c.dom.DOMException: The current document is unable to create an element of the requested type (namespace: http://www.w3.org/2000/svg, name: drawing-type).
	at org.apache.batik.dom.AbstractNode.createDOMException(AbstractNode.java:407)
	at org.apache.batik.anim.dom.SVGDOMImplementation.createElementNS(SVGDOMImplementation.java:202)
	at org.apache.batik.anim.dom.SVGOMDocument.createElementNS(SVGOMDocument.java:373)
	at org.apache.batik.dom.util.SAXDocumentFactory.startElement(SAXDocumentFactory.java:651)
	at org.apache.xerces.parsers.AbstractSAXParser.startElement(Unknown Source)
	at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
	at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
	at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
	at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
	at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
	at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
	at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
	at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
	at org.apache.batik.dom.util.SAXDocumentFactory.createDocument(SAXDocumentFactory.java:453)
	at org.apache.batik.dom.util.SAXDocumentFactory.createDocument(SAXDocumentFactory.java:357)
	at org.apache.batik.anim.dom.SAXSVGDocumentFactory.createDocument(SAXSVGDocumentFactory.java:225)
	at org.apache.batik.anim.dom.SAXSVGDocumentFactory.createDocument(SAXSVGDocumentFactory.java:300)
	at org.apache.batik.transcoder.XMLAbstractTranscoder.transcode(XMLAbstractTranscoder.java:114)
	... 44 more

I can't find any info about this drawing-type tag. I edited the xml of the file to remove that tag to test it. The image is displayed exactly the same in Firefox, with or without the tag. When I try to load the image removing the <drawing-type>1</drawing-type>, the exception changes to:


java.lang.NullPointerException
	at org.apache.batik.css.engine.CSSEngine.parseStyleSheet(CSSEngine.java:1223)
	at org.apache.batik.css.engine.CSSEngine.parseStyleSheet(CSSEngine.java:1204)
	at org.apache.batik.anim.dom.SVGOMStyleElement.getCSSStyleSheet(SVGOMStyleElement.java:140)
	at org.apache.batik.css.engine.CSSEngine.getStyleSheetNodes(CSSEngine.java:923)
	at org.apache.batik.css.engine.CSSEngine.getCascadedStyleMap(CSSEngine.java:785)
	at org.apache.batik.css.engine.CSSEngine.getComputedStyle(CSSEngine.java:867)
	at org.apache.batik.bridge.CSSUtilities.getComputedStyle(CSSUtilities.java:81)
	at org.apache.batik.bridge.CSSUtilities.convertVisibility(CSSUtilities.java:578)
	at org.apache.batik.bridge.SVGSVGElementBridge.createGraphicsNode(SVGSVGElementBridge.java:141)
	at org.apache.batik.bridge.GVTBuilder.build(GVTBuilder.java:76)
	at com.twelvemonkeys.imageio.plugins.svg.SVGImageReader$Rasterizer.transcode(SVGImageReader.java:309)
	at org.apache.batik.transcoder.XMLAbstractTranscoder.transcode(XMLAbstractTranscoder.java:142)
	at org.apache.batik.transcoder.SVGAbstractTranscoder.transcode(SVGAbstractTranscoder.java:156)
	at com.twelvemonkeys.imageio.plugins.svg.SVGImageReader$Rasterizer.init(SVGImageReader.java:549)
	at com.twelvemonkeys.imageio.plugins.svg.SVGImageReader$Rasterizer.getDefaultWidth(SVGImageReader.java:562)
	at com.twelvemonkeys.imageio.plugins.svg.SVGImageReader.getWidth(SVGImageReader.java:229)
	at com.twelvemonkeys.imageio.plugins.svg.SVGImageReader.read(SVGImageReader.java:131)
	at javax.imageio.ImageReader.read(ImageReader.java:939)
	at meew.FileManager.getCurrentImage(FileManager.java:2046)
	...

Do you know anything about this? This also happened in the previous 3.3.2 version. I'm using Batik version 1.10 now but the problem happened in the 1.9 version as well. By the way, I saw in the TwelveMonkey's release notes that "Batik dependencies updated to 1.9", so is it safe if I use 1.10?

@haraldk
Copy link
Owner

haraldk commented Sep 18, 2018

Hi Hosé,

Thanks for the detailed report!

I believe this issue is a Batik problem. Have a look if you can open the SVGs in the official Batik products. If you can't, then there's nothing I can do to fix it directly (other than passing your info along to the Batik team). It would be helpful if you could test, and report the problem directly to them.

Re. Batik 1.9 vs 1.10, I think it should be pretty safe. The only thing is, I haven't run the test cases using 1.10, so there's no warranty. ;-)

Feel free to submit an issue/patch, upgrading to Batik 1.10 (it should be as easy as changing some version numbers in a POM file)!

Best regards,

--
Harald K

@j-p-sequeira
Copy link
Author

Well, now that I'm looking into it (I had only tested with half a dozen SVG files before), I'm finding more and more problems with Batik. I can't even open the SVG samples in the Batik folder with my viewer ( ; _ ; )

The problems are many:

  • References simply do not work. Example: <use xlink:href="batikLogo.svg#Batik_Tag_Box" /> says it can't find the batikLogo.svg file when the file is in the same folder as the SVG being read... Java is looking for the referenced files in the CLASSPATH, ugh... I don't know how to solve this problem...

  • When there is a doctype declaration ex:

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">

an internet connection is established and it takes forever to load the file... I mean, way too long to be acceptable.

  • Since SVGs can connect to the internet and have scripts, it raises security concerns... (wish I could disable connections... I mean, one would expect that those 4 dtd were already available locally inside the plugin, they are pretty small)

  • A single mistake in the SVG file (like the string "--" inside a comment or the "tag use" failing to find the file), causes an exception making the file impossible to be shown.

And to make me even more depressed, I can't even open the official Batik app "squiggle" as it gives the exception:

SVG Error: org/apache/batik/w3c/dom/ElementTraversal
java.lang.Exception: org/apache/batik/w3c/dom/ElementTraversal
	at org.apache.batik.swing.svg.SVGDocumentLoader.run(SVGDocumentLoader.java:104)

and gets forever stuck... (JVM task must be killed).

If you have any ideas, I'd love to hear them.

@haraldk
Copy link
Owner

haraldk commented Sep 19, 2018

Okay,

I suggest you roll back to Batik 1.9. At least that works fine for me.

For the references to work properly, you probably need to read using an SVGReadParam and set the base URI to the current folder. Unfortunately, the ImageIO API doesn't know about "files in the same directory" as we never read directly from a file. We could probably make this easier in the file case, by providing a custom ImageInputStream SPI for java.io.File, but it wouldn't work when reading from a byte array, URL or other non-file input. That's why I provided the base URI parameter, as it works for anything.

A double-hyphen inside a comment is actually illegal in SGML (and thus in XML/HTML etc), so I think Batik is correct on that part (https://www.w3.org/TR/REC-xml/#sec-comments).

I really don't think Batik should allow an SVG to start roaming the internet for random information linked from an XML file. If it does by default, that should be reported as a bug, IMHO.
You can probably find some more useful information here: https://xmlgraphics.apache.org/batik/using/scripting/security.html#externalResources

Hope that helps,

--
Harald K

@j-p-sequeira
Copy link
Author

Well, it certainly did help, thank you very much!! ( ^ _ ^ ) b
Using the SVGReadParam really did the trick when it comes to the reference problem : )

However, using both Batik 1.9 and 1.10, it still takes an eternity when the SVG has the doctype. As you can see here in my logs:

2018-09-19 17:06:44 FINEST: ProxySelector Request for http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd [@sun.net.www.protocol.http.HttpURLConnection plainConnect0]
2018-09-19 17:06:44 FINEST: Proxy used: DIRECT [@sun.net.www.protocol.http.HttpURLConnection plainConnect0]
2018-09-19 17:06:44 FINE: sun.net.www.MessageHeader@6faa60e25 pairs: {GET /TR/2001/REC-SVG-20010904/DTD/svg10.dtd HTTP/1.1: null}{User-Agent: Java/1.8.0_77}{Host: www.w3.org}{Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2}{Connection: keep-alive} [@sun.net.www.protocol.http.HttpURLConnection writeRequests]
2018-09-19 17:06:59 FINEST: KeepAlive stream used: http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd [@sun.net.www.http.HttpClient logFinest]

Doing the math, 15 seconds to load a simple image is far from ok. If I remove the doctype from the SVG file, it loads in a flash. You say that you don't have this problem when you load these SVG files? What could I be doing wrong? Maybe if I download the dtd files and place them somewhere, it helps?

About the "--" maybe that was a bad example, as firefox also complains about it and does not show the image, but for example, when a "use tag" reference fails, firefox still manages to display the image. But that's fine, now only the 15s lag is annoying me.

About the security, thanks a lot for the link, I'm much more reassured now as it says:

DefaultScriptSecurity : The script resource will only be loaded if it is embeded in the SVG document (see the description of EmbededScriptSecurity) or if it is coming from the same location as the document referencing the script. If the document comes from a network server, then any script coming from that server will be allowed. If the document comes from the file system, then only scripts under the same directory root as the SVG document will be allowed.

DefaultExternalResourceSecurity : Embeded external resources (see above) and resources coming from the same location as the document referencing them are allowed.

@haraldk
Copy link
Owner

haraldk commented Sep 20, 2018

I think using (from the link above):

NoLoadExternalResourceSecurity : No external references are allowed.

...should make sure no external requests are made. Still, I don't understand how fetching the resource could be in compliance with the default security setting, unless you actually tried to display the SVG directly from the w3.org site?

Perhaps it happens outside of Batik's control, and is a setting in the XML parser library? You might have a look, to see if there's a setting you can change, to avoid trying to resolve external resources. I used to know these things, but it's been a while since I worked with these XML APIs...

Best regards,

--
Harald K

@j-p-sequeira
Copy link
Author

Hi, thanks a lot for the tips, really appreciated 👍

The SVG files are all in my local hard drive. My viewer (Meew) can only read files in the local drives (disk, USB Pen...) or network shared folders. In fact, I want to keep it that way, I'm not too happy in having my software opening internet connections like that. So I don't know what the problem might be.

I have to admit that I'm a bit lost about setting Batik's security options (I really intend to disallow external resources), but I'll try to read everything more carefully and search google : ) Sadly, it is not helping me that I'm flooded with work until November, and I can't spend much time with this hobby of mine that is Meew.

@j-p-sequeira
Copy link
Author

j-p-sequeira commented Sep 25, 2018

With the little time I had, I managed to find that:

  • Batik will look for any doctype URL, which is very bad... Ant it does not take 15s when it fails. Example:
2018-09-25 15:09:14 FINEST: ProxySelector Request for http://www.obvious-fake-url.org/TR/2001/REC-SVG-20010904/DTD/dubious.dtd [@sun.net.www.protocol.http.HttpURLConnection plainConnect0]
2018-09-25 15:09:14 WARNING: Error obtaining SVG XML information. [@meew.FileManager loadSVGVectorInformation]
2018-09-25 15:09:14 FINE: www.obvious-fake-url.org [@meew.FileManager loadSVGVectorInformation]
java.net.UnknownHostException: www.obvious-fake-url.org
...
  • To use the NoLoadExternalResourceSecurity, etc... requires the use of JSVGCanvas (actually extending it to something like a RestrictedJSVGCanvas). That is no good for me because not only I do not use the JSVGCanvas, I would also like to keep my app as "blind" as possible to the plugins.

The only solution might be tweaking with the java.lang.SecurityManager and the policy file to block the connections. I never did this before, but I'll look into it when I have time and if I find a solution, I'll post it here, in case someone else is interested.

@haraldk
Copy link
Owner

haraldk commented Sep 25, 2018

Thanks for digging into this, and updating the issue!

If you find something that can be done, let me know here, or by creating a PR, and I'll look into it! :-)

Best regards,

--
Harald K

@j-p-sequeira
Copy link
Author

Ok, my bad. It was me not looking into it properly and being dumb (what else is new?).

The 15s lag was not caused by Batik at all. Before calling TwelveMonkeys' plugin, I use the DocumentBuilder.parse(InputStream is) to get a XML Document. This is because, in order to get a correctly sized image, I need to do some tweaking in the XML (all done in memory, not messing with the files themselves). It was this parsing that would try to (painfully slowly) download the dtd and do other expansions. I solved it this way (if anyone is interested):

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(false);
dbf.setValidating(false);
dbf.setExpandEntityReferences(false);
dbf.setCoalescing(false);
dbf.setFeature("http://xml.org/sax/features/namespaces", false);
dbf.setFeature("http://xml.org/sax/features/validation", false);
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
dbf.newDocumentBuilder().parse(...)

Still, about the security, it seems that using a policy file is the only way to run libraries inside a sandbox, though it's quite the headache for more than one reason.

Anyway, I still have a problem with the references to CSS files, even though I properly set the base URI. Here is the exception (despite that the image is still retrieved):

org.w3c.dom.DOMException: file:tests/resources/style/test.css:
Invalid CSS document.
tests\resources\style\test.css (O sistema não conseguiu localizar o caminho especificado)
	at org.apache.batik.css.engine.CSSEngine.parseStyleSheet(CSSEngine.java:1175)
	at org.apache.batik.css.engine.CSSEngine.parseStyleSheet(CSSEngine.java:1116)
	at org.apache.batik.anim.dom.SVGStyleSheetProcessingInstruction.getCSSStyleSheet(SVGStyleSheetProcessingInstruction.java:96)
	at org.apache.batik.css.engine.CSSEngine.getStyleSheetNodes(CSSEngine.java:923)
	at org.apache.batik.css.engine.CSSEngine.getCascadedStyleMap(CSSEngine.java:785)
	at org.apache.batik.css.engine.CSSEngine.getComputedStyle(CSSEngine.java:867)
	at org.apache.batik.bridge.CSSUtilities.getComputedStyle(CSSUtilities.java:81)
	at org.apache.batik.bridge.CSSUtilities.convertVisibility(CSSUtilities.java:578)
	at org.apache.batik.bridge.SVGSVGElementBridge.createGraphicsNode(SVGSVGElementBridge.java:141)
	at org.apache.batik.bridge.GVTBuilder.build(GVTBuilder.java:76)
	at com.twelvemonkeys.imageio.plugins.svg.SVGImageReader$Rasterizer.transcode(SVGImageReader.java:309)
	at org.apache.batik.transcoder.XMLAbstractTranscoder.transcode(XMLAbstractTranscoder.java:142)
	at org.apache.batik.transcoder.SVGAbstractTranscoder.transcode(SVGAbstractTranscoder.java:156)
	at com.twelvemonkeys.imageio.plugins.svg.SVGImageReader$Rasterizer.init(SVGImageReader.java:549)
	at com.twelvemonkeys.imageio.plugins.svg.SVGImageReader$Rasterizer.getDefaultWidth(SVGImageReader.java:562)
	at com.twelvemonkeys.imageio.plugins.svg.SVGImageReader.getWidth(SVGImageReader.java:229)
	at com.twelvemonkeys.imageio.plugins.svg.SVGImageReader.paramsToHints(SVGImageReader.java:169)
	at com.twelvemonkeys.imageio.plugins.svg.SVGImageReader.read(SVGImageReader.java:120)
	at meew.FileManager.getCurrentImage(FileManager.java:2058)
	...
ERROR: null
Enclosed Exception:
file:tests/resources/style/test.css:
Invalid CSS document.
tests\resources\style\test.css (O sistema não conseguiu localizar o caminho especificado)

The file is barChart.svg in Batik's samples folder. Do you have this problem as well?

@haraldk
Copy link
Owner

haraldk commented Oct 10, 2018

Hi,

Sorry for not following up on this. No I haven't seen this problem, but I'm not using the Batik plugins, so I don't do much testing apart from running the test cases. Maybe you could try adding a test case with an external CSS reference, so that we get better coverage on that? I don't think there's much I can do but if there is, I'd like to look into it!

Glad you found the fix for the timeout though! :-)

--
Harald K

@haraldk
Copy link
Owner

haraldk commented Oct 10, 2018

Okay,

So I made a test case, and it seems you are right. I am able to decode and display the document (barChart.svg) though, but I get exceptions on stdout. I've made a few changes to the code (not yet pushed) so that we no longer get the noisy output, but instead get warnings you can listen to, using the IIOWarningListener interface.

It doesn't change the fact that the CSS is not picked up, and I really don't get why. As setting the baseURI clearly does solve the problem for embedded resources...

Best regards,

--
Harald K

@j-p-sequeira
Copy link
Author

Hi, thank you for looking into this :)
It seems to be a really obscure problem, but it looks like someone else had this problem as well:
https://batik-users.xml.apache.narkive.com/VTNToVS6/how-to-associate-css-file-from-java

It seems there are several classes where we can set the base URI/URL... The guy in the link above suggests this:
((org.apache.batik.dom.svg.SVGOMDocument)doc).setURLObject(new URL("something:that/makes/sense"));

However, that class was removed and that might be where the problem is (https://stackoverflow.com/questions/30092651/where-has-org-apache-batik-dom-svg-svgdomimplementation-gone/30250306). Now there is org.apache.batik.anim.dom.SVGOMDocument.

In fact, I am converting a org.w3c.dom.Document object to bytes and passing it to the TwelveMonkeys reader. I do set the URI with the setDocumentURI method before passing it to the reader (as well as using the SVGReadParam) but it does not help. I do not use the SVGOMDocument class though, as I want to keep my code blind to plug-ins as much as possible.

@haraldk
Copy link
Owner

haraldk commented Oct 11, 2018

Hi,

If you look at the source code of the SVGImageReader, you'll see that I already pass the base URI from the SVGReadParam to setURLObject(..)... So, no I don't really have the problem in that link.

It even works, kind of. Without it, the link to the "squiggle" (batikLogo.svg#Batik_Tag_Box) crashes the rendering of barChart.svg. With it, it works fine. But you do need to have the batikLogo.svg at the same location as the base URI (ie. same directory).

Batik just doesn't use the same mechanism for loading the CSS, which is very confusing/frustrating. Using a relative or absolute URL doesn't seem to make a difference (this is up to you though, as I just pass whatever you claim to be the base URI along).

The fact that the message from Batik contains "file:style/test.css: Invalid CSS document." makes it look like it does not even attempt to resolve the URI relative to the base URI. But as it is a processing-instruction, rather than a tag, it may be a problem with the XML parser/DOM builder rather than Batik? I really don't know these things in detail, so keep looking! :-)

Best regards,

--
Harald K

@j-p-sequeira
Copy link
Author

Using an absolute link in the XML like:

<?xml-stylesheet type="text/css" href="file:///E:/myusername/Desktop/batik-bin-1.10/batik-1.10/samples/tests/resources/style/test.css" ?>

actually makes the exception go way. However, and I only noticed it just now, the style does not influence the final image, which means the text size of the legend stays the same no matter if it finds the CSS or not.

If it worked, I could make a workaround to edit the XML to get the tags <?xml-stylesheet> and get the href. If the link contains the char ":" (because even in linux without "drive:" we have "file:") it probably means that the link is already absolute, if not I would inject the baseURI. However, I'm not sure if it is this simple to check if a path is absolute, and if the CSS ends ignored anyway it is pretty much useless.

And I just wish I could have more time to spend with this, but until at least November it will be complicated.

@haraldk
Copy link
Owner

haraldk commented Oct 11, 2018

In my tests it actually does influence the image...? The only thing I make it affect though, is the font size.

Anyway, I made a fix to the problem, so that it now works. Even the CSS. It was my bad all along, because I set it too late... :-P
Will try to commit/push soon.

There's still a quirk though, that is, if you try to query the SVGImageReader about width/height/imageType etc, before invoking read with a param containing base URI, the CSS will not be read, because there is no base URI yet.

Perhaps I should add a custom setBaseURI method to the reader, or create a custom FileImageInputStream that actually carried along the file it was created from (but this again requires a custom Spi etc..). Still, other projects have done that, and it might actually be the best solution.

--
Harald K

haraldk added a commit that referenced this issue Oct 11, 2018
@haraldk
Copy link
Owner

haraldk commented Oct 11, 2018

I just pushed an improvement, feel free to try it out. It should completely remove the noisy output to System.out and instead present them as read warnings through the registered `IIOWarningListener´. Also, the base URI should work in most cases, and be a lot more robust.

Thank you for your feedback so far!

--
Harald K

@j-p-sequeira
Copy link
Author

j-p-sequeira commented Oct 15, 2018

That's great to hear!
Yes, I've tested the new version and the CSS exceptions are gone. Now relative paths do work and I only get a warning if the CSS really does not exist.

However, whatever I do, I can't see the effects of the CSS on the image. I even tried this:

.title {
  font-family: Arial, Helvetica; 
  font-size: 160pt;
  text-anchor: middle;
}
.legend {
  font-family: Arial, Helvetica; 
  font-size: 100pt;
  text-anchor: middle;
}

just in case it was me needing glasses (happens sometimes), but there is no effect on the image displayed by my application, only in firefox.

I re-checked my code, since I do call the methods getFormatName, getImageTypes, getWidth and getHeight, but I don't think I'm doing it in case of SVG images.

The only thing I call on the reader in my code when I have an SVG image is (unless I'm not looking properly):

reader.getClass();
reader.addIIOReadWarningListener(this);
reader.setInput(inputStream);
ImageReadParam parameters = reader.getDefaultReadParam(); // To set BaseURI...
image = reader.read(0, parameters);

Would any of these methods break the CSS? What could I be doing wrong?

@haraldk
Copy link
Owner

haraldk commented Oct 15, 2018

Here's what the rendering looks like in my case, using Batik 1.9.1:

Default style (as in the test case):

image

Modified to 160/100pt:

image

Clearly a difference.

And no, none of the things you do should be a problem (I do exactly the same):

ImageReader reader = readers.next();
reader.addIIOReadWarningListener(...);
reader.addIIOReadProgressListener(...);
reader.setInput(input);

try {
    ImageReadParam param = reader.getDefaultReadParam();

    // To avoid explicit dependencies....
    if (param.getClass().getName().equals("com.twelvemonkeys.imageio.plugins.svg.SVGReadParam")) {
        Method setBaseURI = param.getClass().getMethod("setBaseURI", String.class);
        String uri = file.getAbsoluteFile().toURI().toString();
        setBaseURI.invoke(param, uri);
    }

    int numImages = reader.getNumImages(true);
    for (int imageNo = 0; imageNo < numImages; imageNo++) {
        try {
            BufferedImage image = reader.read(imageNo, param);
            IIOMetadata metadata = reader.getImageMetadata(imageNo);
            // Display image/metadata...
        }
        catch (Throwable t) {
            System.err.println(file + " image " + imageNo + " can't be read:");
            t.printStackTrace();
        }
    }
}
finally {
    input.close();
    reader.dispose();
}

Is basically what I do (see TIFFImageReader.main for full code).

--
Harald K

@j-p-sequeira
Copy link
Author

Ok, then my problem must be somehow related to the fact that I first read the SVG file into a Document object and I do some tweaking in the XML before transforming everything into a byte array stream.

I'm totally unable to do something for the time being (no time at all), but now that I'm sure it must be my problem, I'll look into it more carefully in the near future.

As always, BIG THANK YOU for your work! You're a genius, twelvemonkeys is simply great ; )

@haraldk
Copy link
Owner

haraldk commented Oct 15, 2018

You're welcome! :-)

And thank you for taking the time to explain and suggest improvements! Much appreciated.

PS: It might be possible with some light tweaks to allow the SVGimageReader (and only this!) to take a pre-parsed Document instance as a parameter to setInput, so that you wouldn't have to serialize the already in-memory document. But I don't need it, so I leave that as an exercise to you, when you find the time. ;-)

Something like:

        if (imageInput != null) {
            // ...
        }
        else if (pInput instanceof Document) {
            Document document = (Document) pInput;
            TranscoderInput input = new TranscoderInput(document);
            input.setURI(document.getBaseURI());
            rasterizer.setInput(input);
        }

Anyway, I'm closing this issue for now.

Best regards,

--
Harald K

@haraldk haraldk closed this as completed Oct 15, 2018
@j-p-sequeira
Copy link
Author

Ouch, I think I found out what the problem is that is causing CSS to be ignored. When I checked the byte array of the XML I was passing to the reader, I found out that there were no line breaks before the svg tag. So, it looks something like this:

<?xml version="1.0" encoding="UTF-8"?><!-- Some comments with line breaks --><?xml-stylesheet type="text/css" href="tests/resources/style/test.css" ?><svg...

If I put the line <?xml-stylesheet type="text/css" href="tests/resources/style/test.css" ?> inside the svg tag, it gets a line on its own and all works.

Now, passing a SVG without the line breaks works well in Firefox, and I don't think there is a rule saying that line breaks are mandatory, so I don't know why Batik should have any problem with this.

And preserving the line breaks of the original XML file (or injecting them if they were missing to begin with) is, for more than one reason, not something that easy to do... : (

@haraldk
Copy link
Owner

haraldk commented Oct 19, 2018

I can't see anything in the spec about them having to be on a specific line... But you need to report that bug to the Batik guys, as I don't control the parsing.

As I mentioned above, I think a better approach (than re-serializing to a byte array) would be to just pass the pre-parsed document to the reader. Did you try that out yet?

--
Harald K

@j-p-sequeira
Copy link
Author

Not yet, but I will!! I promise to come back with the results soon.

haraldk added a commit that referenced this issue Aug 9, 2019
(cherry picked from commit cc5af01)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants