I'm trying to add an image to a docx file using docx4j library within Android.
I've faced to an exception:
E/AndroidRuntime(21818): java.lang.ExceptionInInitializerError
E/AndroidRuntime(21818): at org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext.newSource(AbstractImageSessionContext.java:134)
E/AndroidRuntime(21818): at org.apache.xmlgraphics.image.loader.impl.AbstractImageSessionContext.needSource(AbstractImageSessionContext.java:280)
E/AndroidRuntime(21818): at org.apache.xmlgraphics.image.loader.cache.ImageCache.needImageInfo(ImageCache.java:123)
E/AndroidRuntime(21818): at org.apache.xmlgraphics.image.loader.ImageManager.getImageInfo(ImageManager.java:122)
E/AndroidRuntime(21818): at org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage.getImageInfo(BinaryPartAbstractImage.java:696)
E/AndroidRuntime(21818): at org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage.ensureFormatIsSupported(BinaryPartAbstractImage.java:352)
E/AndroidRuntime(21818): at org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage.ensureFormatIsSupported(BinaryPartAbstractImage.java:331)
E/AndroidRuntime(21818): at org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage.createImagePart(BinaryPartAbstractImage.java:298)
E/AndroidRuntime(21818): at org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage.createImagePart(BinaryPartAbstractImage.java:158)
...
E/AndroidRuntime(21818): Caused by: java.lang.NoClassDefFoundError: sun.awt.AppContext
E/AndroidRuntime(21818): at ae.javax.imageio.spi.IIORegistry.getDefaultInstance(IIORegistry.java:155)
E/AndroidRuntime(21818): at ae.javax.imageio.ImageIO.<clinit>(ImageIO.java:65)
...
It is referring to this code:
WordprocessingMLPackage wordMLPackage;
File file;
...
BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, file);
I've already added all necessary libraries from AndroidDocxToHtml example (and ae-awt.jar
too) to libs
folder of my app.
Without images my app generates docx files perfectly.
Is there any way to solve it?
Thanks!
I got this to work but it required overriding about 8 files from ae-awt and ae-xmlgraphics-commons. And I hardcoded it to handle jpg files only.
Remove all references to sun.security.action.LoadLibraryAction and just call System.loadLibrary("jpeg")
Remove AppContext and replace it with ThreadGroup from ImageIO, like this:
private static synchronized CacheInfo getCacheInfo() {
ThreadGroup group = Thread.currentThread().getThreadGroup();
CacheInfo info = (CacheInfo) instances.get(group);
//CacheInfo info = (CacheInfo)context.get(CacheInfo.class);
if (info == null) {
info = new CacheInfo();
instances.put(group, info);
}
return info;
}
Same with imageio.spi.IIORegistry
In ae-xmlgraphics-commons, made a few changes to ImageManager.java, DefaultImageContext and BinaryPartAbstractImage. The first 2 I dont remember what I did (i can't diff them easily, maybe no changes were needed), but there were many changes to BinaryPartAbstractIMage. I hardcoded the getImageInfo() to IMAGE_JPEG because of problems with the sessionContext / Context type (that somehow tried to determine the image type and call the appropriate preloader). So I made the assumption that all images are jpegs and force it to always use the JPEG preloader.
getImageInfo()
ImageInfo info = new ImageInfo(url.toURI().toString(), ContentTypes.IMAGE_JPEG);
That got a warped image to appear in the doc. I still have to figure out the width/height formula to get it to embed correctly.
For everyone, who faced this problem too.
Here are necessary steps to make docx4j works fine with images:
- Add missed classes from OpenJDK to appropriate packages with
ae
.
- Change references to new classes, for example
sun.awt.AppContext
to ae.sun.awt.AppContext
.
In org.apache.xmlgraphics.util.Service
manually fill list with preloaders:
private static List<String> getProviderNames(Class<?> cls, ClassLoader cl) {
...
if (fillDefautsProviderNames(cls, l))
return l;
...
}
private static boolean fillDefautsProviderNames(Class<?> cls, List<String> l) {
if (cls == org.apache.xmlgraphics.image.loader.spi.ImagePreloader.class) {
l.add("org.apache.xmlgraphics.image.loader.impl.PreloaderTIFF");
l.add("org.apache.xmlgraphics.image.loader.impl.PreloaderGIF");
l.add("org.apache.xmlgraphics.image.loader.impl.PreloaderJPEG");
l.add("org.apache.xmlgraphics.image.loader.impl.PreloaderBMP");
l.add("org.apache.xmlgraphics.image.loader.impl.PreloaderEMF");
l.add("org.apache.xmlgraphics.image.loader.impl.PreloaderEPS");
l.add("org.apache.xmlgraphics.image.loader.impl.imageio.PreloaderImageIO");
return true;
}
return false;
}
Delete function displayImageInfo(ImageInfo info)
in org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage
.
I've prepared repositories with changes: ae-awt, ae-xmlgraphics-commons, docx4j-android.
You can find compiled libs here: docx4j_images_prepared_libs.zip
Enjoy!