Apache FOP in a Java Applet - No ImagePreloader found for data - java

I'm looking at an issue in a mature commercial product.
In a nutshell, we are using part of the Apache POI library to read in a Word .DOC or .DOCX file, and convert it into XSL-FO so that we can do token replacements. We then use FOP – embedded into the Java program - to convert the FO data into a PDF for printing. The catch is, all this is being done on the client inside a Java applet running inside Internet Explorer.
Originally we were using FOP 0.93, which worked reasonably well. However, it was not able to utilise the fonts inside the DOC file when generating the PDF and would map everything to Times, which one of the customers did not like. In theory it could be made to work by adding some kind of font metrics data, but that would require a relatively complex definition for every font it was likely to encounter and we can’t predict what the client is liable to use outside of the MS core fonts set.
To fix this, FOP was upgraded to 1.0, which added support for autodetecting the fonts from the operating system. This worked, but we noticed that the image processing had stopped working and the letterheads had disappeared.
What appears to have happened is that the image loader inside FOP was rewritten at some point between 0.93 and 0.95 so that instead of using Jimi and JAI it now uses ImageIO. The earlier implementation worked fine, but the new code doesn’t like being run as an applet.
Images are embedded in URIs in the FO data so we get an error like this:
2014-09-30 17:00:10,607 ERROR [org.apache.fop.apps.FOUserAgent] Image not available. URI:
data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAALQAAABSCAIAAABysmn6AAA...
...ggg==. Reason: org.apache.xmlgraphics.image.loader.ImageException: The file format is not supported. No ImagePreloader found for data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAALQAAABSCAIAAABysmn6AAAA...
When run through a test harness, the correct output is generated, but when run as an applet inside the browser we get the above error which makes me suspect that the browser applet security is jamming the ImageIO plugin loader somehow.
The guts of the FOP transformation, i.e. the bit which is triggering the error is this:
// Step 4: Setup JAXP using identity transformer
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(); // identity transformer
transformer.transform(src, res);
...which is all being run inside a PrivilegedAction block since in FOP 1.0 it needed file I/O access to manage the font cache.
Running the standalone FOP 0.93 and 1.0 programs under linux and using strace shows that it is writing out temporary files for the image data, but both 0.93 and 1.0 do similar things, so it shouldn’t be that by itself, especially since it should have permission to create temp files already.
I've tried different versions of the JRE since some builds a few years back apparently had security issues with the ImageIO library, but to no avail.
Any ideas?
Thanks,

In case anyone else has something similar, this turned out to be caused by the way the project was being built in Maven.
Fop 1.0 and above use the xml-graphics-commons library to facilitate the image rendering. As mentioned in the question, this uses a plugin registry which is configured using the following files inside the JAR:
META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImageConverter
META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImageLoaderFactory
META-INF/services/org.apache.xmlgraphics.image.loader.spi.ImagePreloader
...each of these contains a list of the image decoders which will be supported.
The problem is that xml-graphics-common ships these files with a sensible list of defaults, while FOP also has a conflicting set of defaults, which for some weird reason disable all of the image decoders, and that one was taking priority.
To solve the problem, I made sure that my maven pom.xml file imported xml-graphics-common before FOP, so that its defaults took precedence, and at that point everything sprang to life.
I am still not sure why the code was working correctly as a standalone test program, but I suspect it was the way the classpath was being handled being different to it running in plugin mode.

In my case the plugin registry loaded ImagePreloaders from both the plugin files and mixed them together. Yet the error still appeared. I was inserting an SVG file into a PDF file. The root cause was incorrect version of org.apache.xmlgraphics:batik-svg-dom. The 1.7 version was required by the org.apache.xmlgraphics:fop:1.1, however, the 1.8 version was on the classpath.
There is a key difference between the two versions: the org.apache.fop.image.loader.batik.PreloaderSVG class needs org.apache.batik.dom.svg.SAXSVGDocumentFactory from the version 1.7 on the classpath. If it gets org.apache.batik.anim.dom.SAXSVGDocumentFactory from the 1.8 version it does not work as expected.
This SO question: Where has org.apache.batik.dom.svg.SVGDOMImplementation gone? was helpful to me when resolving this issue.

Just been struggling with this one. If you're using the maven-shade-plugin to create an uber jar, use the ServicesResourceTransformer to merge all the services configuration:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<!-- snip -->
<configuration>
<transformers>
<!-- snip -->
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
</configuration>
</execution>
</executions>
</plugin>

thanks for the post!
I can assert that this also works by changing ordering in Eclipse!
in my case, under Windows it was working fine, but same JAR file in RHEL raised an error

Related

Cannot generate C# proxy dll with JNI4NET tool, running batch file as trusted assembly?

I am working on getting the tool JNI4NET working so that I can use some Java code I have within my C# application. As a simple initial test I have created a simple Java class library with a single class Person with one method public String GetName() { return "NoBody"; }. From here I have been following along with the samples given in the JNI download to edit the generateProxies.cmd to create the DLL wrapper of the jar.
I didn't have much luck with this so I decided to try to perform the same action but with the sample, specifically the sample entitled myJavaDemoCalc. When executed generateProxies.cmd in the sample folder an error is thrown.
(I will transcribe this picture if need be)
I have followed the link in the exception though while I somewhat understand what it means I am not sure if it is necessarily safe to enable loading from remote sources as it suggests at the end of the linked article.
I am also confused why the exception is being thrown seeing that the generateProxies.cmd and thus ProxyGen.exe is being run from my C: drive.
Anyone have an idea of what I could try next or know the issue here?
For reference here is the generateProxies.cmd source from myJavaDemoCalc
#echo off
copy ..\..\lib\*.* work
..\..\bin\proxygen.exe work\myJavaDemoCalc.jar -wd work
cd work
call build.cmd
cd ..
echo compiling usage
csc.exe /nologo /warn:0 /reference:work\jni4net.n-0.8.8.0.dll /reference:work\myJavaDemoCalc.j4n.dll /out:work\demo.exe /target:exe MyCalcUsageInDotnet.cs
I assume you downloaded that zip file and then immediately Extracted all files.
However, because that zipfile did originate from an untrusted zone, being the internet, the files in it will also remain untrusted. It contains an alternate data stream with a zone identifier.
When those assemblies get loaded by the framework, it checks if they can be trusted. Assemblies with that zone identfier still present don't get loaded. That is the exception you get:
System.IO.FileLoadException: Could not load file or assembly 'file:///jni4net.n-0.8.8.0.dll' or one of its dependencies. Operation is not supported. (Exception from HRESULT: 0x80131515) --->
System.NotSupportedException: An attempt was made to load an assembly from a network location which would have caused the assembly to be sandboxed in previous versions of the .NET Framework. This release of the .NET Framework does not enable CAS policy by default, so this load may be dangerous. If this load is not intended to sandbox the assembly, please enable the loadFromRemoteSources switch.
The quickest solution to resolve this is to open the properties window of the downloaded zip file and tick unblock before you extract all files:
If you already extracted all the files to a folder you can use the powershell command unblock-file
Get-ChildItem -Path 'c:\path\to\files' -Recurse | Unblock-File
But if you're sure that you will always run proxygen.exe with trusted assemblies, you can add the suggestion offered in the MSDN article by adding the loadFromRemoteSources element in the existing proxygen.exe.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
<supportedRuntime version="v2.0.50727"/>
</startup>
<!-- trust all the thingz -->
<runtime>
<loadFromRemoteSources enabled="true"/>
</runtime>
</configuration>

Why would a Saxon Report run correctly on a Mac but not on Windows?

I am using Saxon 4.4.2 to convert DocBook to various formats (e.g. HTML, PDF, ePub). I am doing development on a MacBook Pro using Eclipse. Everything is written in Java. On my Mac, everything works fine. When I use Eclipse to generate a deployable plug-in, copy the plug-in and drop it into my Eclipse installation on Windows 7, and run the conversion from DocBook to HTML, Saxon reports "Failed to compile stylesheet. 1 error detected."
The error comes from
com.icl.saxon.TransformerFactoryImpl, method newTemplates line 120.
called by
com.icl.saxon.TransformerFactoryImpl, method newTransformer, line 72.
My calling line of code is:
Transformer transformer = tfactory.newTransformer(xsl);
The setting of xsl is done via this line:
StreamSource xsl = new StreamSource(DocBookTransformer.class.getResourceAsStream("/lib/docbook-xsl-1.76.1/xhtml/docbook.xsl");
Why would Saxon process the stylesheet without error on a Mac, but fail to parse it on Windows, when it is the same Saxon Jars and the same stylesheet file being processed on both machines?
Saxon 4.4.2? Where on earth did you get hold of that? Perhaps a CD in the back of a book published around 1998? It predates the first release on SourceForge in 2001, and was probably designed to run on Java 1.1.8.
So your first step should be to see if the problem still occurs on a more modern release. The current release is 9.5.
The other thing is to find out what the error is that Saxon says it reported. It will have been sent to the JAXP ErrorListener, and unless you changed anything, the default ErrorListener will have written the message to System.err.
The things that are most likely to work on one platform and fail on another are the URIs in xsl:include and xsl:import, so you try checking those.

Image won't display in PDF using FOP 1.1 and Java

I've searched Google through and through and can't seem to find the solution to my issue...
I'm using Apache FOP 1.1 and Java to generate a PDF file from Java classes. This Java project runs from a JAR file. I am using an image that is external to the JAR itself. The XSL file that is used to generate the PDF contains this:
<fo:external-graphic src="file:///C:/images/image.jpg" width="7.5in" />
Based on much searching/reading, I've tried many different variations of the src attribute:
src="file:///C:/images/image.jpg"
src="C:/images/image.jpg"
src="url('file:///C:/images/image.jpg')"
src="url('C:/images/image.jpg')"
all without success...
Now, here's the confusing part. I am doing my development from Eclipse IDE and when using the variations of src attribute:
src="C:/images/image.jpg"
src="url('C:/images/image.jpg')"
The PDF is created properly with the images embedded.
I can not figure out what is keeping the image from being displayed when running from the JAR file...
Thanks in advance! (hopefully)
Devin
The syntax
<fo:external-graphic src="url('C:/images/image.jpg')" content-height="100%" content-width="100%"/>
works perfectly fine for me, both from Eclipse or from a JAR. Have figured out what the problem was?
I know this is an old thread but I had a similar problem and eventually figured out a partial fix. It was a combo of 2 things:
Difference between JVMs in dev and deployed environments (for me raw sun ... err oracle vs. ibm websphere bundled java)
IBM JVM doesn't like indexed PNG files. As soon as I converted it to RGB it worked.
Here is the error message I got when I manually ran the fop.bat file with websphere jvm:
SEVERE: Image not available. URI: /tmp/image.png. Reason: org.apache.xmlgraphics.image.loader.ImageException: I/O error while extracting image metadata: Error reading PNG metadata (See position 30:182)
btw, i was using fop 1.0 + java 1.6 + WAS 7.0 (java 1.6)
Hope this helps someone else!

SVN revision number accessible in compiled GWT package

I have a GWT project which has its source managed in SVN, is packaged using Maven and has its builds managed via Hudson. I want to get the SVN revision number of the latest check-in/build to be visible in a comment at the bottom of the application root HTML file. I don't care where in the development process this happens!
Here are the options I've Googled for so far, with no success:
Can I get Hudson to, after building, write the build/revision number
to one of its build output files (namely the application root HTML
file)? I've seen no way to do this.
Can I get Maven to write the SVN revision number to one of its build
output files (namely the application root HTML file)? I've seen ways
of Maven writing this to a JAR/WAR manifest file (which can then be
accessed in the Java code), but I'm not sure that this works in GWT
(I'm not particularly knowledgeable about the internals of GWT).
Can I get SubVersion to, as a pre-commit hook, write the version number to a particular file? I know it's easy to write the version number to the file you're editing, but not so sure about writing to a totally separate file (so that it's updated on every commit, regardless of whether it was changed in that commit).
Does anyone have a complete, end-to-end example of how to get any of these working? I keep finding little snippets of code/config which do one part of the job, but not anything that is exactly what I'm looking for.
Thanks!
You can achieve what you're looking for with a combination of Maven and Hudson. In this example let's imagine you want the file version.txt at the root of your web app to contain the revision.
version.txt:
${SVN_REVISION}
In your project's pom.xml enable filtering in the maven-war-plugin:
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.1</version>
<configuration>
<webResources>
<webResource>
<directory>src/main/webapp</directory>
<filtering>true</filtering>
<includes>
<include>version.txt</include>
</includes>
</webResource>
</webResources>
</configuration>
</plugin>
Make sure that Hudson is building your project via. Subversion checkout and it will set the SVN_REVISION environment variable for every build and Maven will fill it in.
This solution is for those who keep getting {SVN_REVISION} instead of the actual SVN_REVISION value inside the target file.
My solution was to also use filtering. However since I wanted the SVN_REVISION to appear inside my gwt app's main html page (as a means of "fighting" the user's cache, making sure that if we carry out a new build, then the user downloads the latest html file), I wasn't able to use Jason Terk's solution. The html file simply printed {SVN_REVISION} instead of the actual SVN_REVISION value.
So I defined a property inside <properties>:
<properties>
...
<buildVersion>${SVN_REVISION}</buildVersion>
...
</properties>
I then made sure I was filtering the appropriate html file (like described in Jason's solution), and then "extracted" the SVN_REVISION in the html file like so:
<script type="text/javascript">
...
var versionIdSuffix = '?v=${buildVersion}';
....
</script>
In a nutshell - I wasn't able to directly reference the {SVN_REVISION} property from inside the html file, so I "wrapped" it through <properties>, letting maven reference it instead.

generating javadoc as a word document

How can we generate javadoc as a word document instead of the traditional html pages?
look into doclets, http://doclet.com which have plenty of examples of custom javadoc rendering (i.e into PDF's etc...) and also look into Apache POI (http://poi.apache.org/) for the generation of MS Office files
If you could live with pdf instead of word, you should give PDFDoclet a chance. I discovered it on doclet.com (thanks to Mark for the link). It works quite well, is easy use and allows some configuration. For my purpose, pdf is better suited than word because a pdf document is better suited for reading than a word in regard to the needed viewer application.
Here is my small windows batch file:
echo OFF
set JAVA_HOME=C:/program files/Java/jdk1.6.0_23
set PATH=%JAVA_HOME%/bin;%PATH%
set VERSION=1.0.2
set DOCLET=com.tarsec.javadoc.pdfdoclet.PDFDoclet
set JARS=jar/pdfdoclet-%VERSION%-all.jar
set PACKAGE="cvu.html"
javadoc -doclet %DOCLET% -docletpath %JARS% -pdf html.pdf -config example/html/config_html.properties -private -sourcepath example/html -subpackges %PACKAGE%
http://doclet.com/ links an RTF Doclet ("RTF Doclet generates RTF format documentation.")
The resulting RTF opens in Word and Open Office Writer.
You can use maven to run the pdfdoclet. Though I did not find any "official" maven repository the following seems more clear to me, opposed to fiddling with shell scripts or using ant-commands in maven as proposed on their website:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<configuration>
<doclet>com.tarsec.javadoc.pdfdoclet.PDFDoclet</doclet>
<docletPath>path/to/pdfdoclet-1.0.2-all.jar</docletPath>
<useStandardDocletOptions>false</useStandardDocletOptions>
</configuration>
</plugin>
Note the disabling of the standard options, otherwise javadoc complains of unknown options (apparently not supported by the pdfdoclet)
From there you can start customizing, using the ever-concise maven documentation

Categories