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!
To all of you out there, who are trying to generate a docx file from android studio, please do not try the apache poi library. I lost too many days trying to integrate apache poi and xwpfdocument in my app. You can generate some text, but if you want to add pictures, then it is not possible to do it with apache poi, you will get at the end in the doxc file a rectangle instead of your picture saying the the picture can't be displayed.
I switched than to doxc4j I was having there also issues becuase android is not java, and you need to customize some libs and dependecies as #kirik88 mentioned.
What you need to do is you need to insert all jars of this repo: https://github.com/plutext/AndroidDocxToHtml/tree/master/libs to your android project as local libs. You import all of them except the three jars mentioned in the kirik88's comment: https://stackoverflow.com/a/23710079/20718567, there you download the zip folder with the three jars: ae-awt, ae-xmlgraphics-commons, docx4j-android and you insert then these three jars also in you android project, maybe you need to still do some small changes in these jars if android complains, but yeah this thing is working, and after too many days this is the only solution that is working to create doxc file from android with text+images. Thank you #kirik88 and #Jason Harrop(plutext).
Related
I use the randomforest estimator, implemented in tensorflow, to predict if a text is english or not. I saved my model (A dataset with 2k samples and 2 class labels 0/1 (Not English/English)) using the following code (train_input_fn function return features and class labels):
model_path='test/'
TensorForestEstimator(params, model_dir='model/')
estimator.fit(input_fn=train_input_fn, max_steps=1)
After running the above code, the graph.pbtxt and checkpoints are saved in the model folder. Now I want to use it on Android. I have 2 problems:
As the first step, I need to freeze the graph and checkpoints to a .pb file to use it on Android. I tried freeze_graph (I used the code here: https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/tools/freeze_graph.py). When I call the freeze_graph in my mode, I get the following error and the code cannot create the final .pb graph:
File "/Users/XXXXXXX/freeze_graph.py", line 105, in freeze_graph
_ = tf.import_graph_def(input_graph_def, name="")
File "/anaconda/envs/tensorflow/lib/python2.7/site-packages/tensorflow/python/framework/importer.py", line 258, in import_graph_def
op_def = op_dict[node.op]
KeyError: u'CountExtremelyRandomStats'
this is how I call freeze_graph:
def save_model_android():
checkpoint_state_name = "model.ckpt-1"
input_graph_name = "graph.pbtxt"
output_graph_name = "output_graph.pb"
checkpoint_path = os.path.join(model_path, checkpoint_state_name)
input_graph_path = os.path.join(model_path, input_graph_name)
input_saver_def_path = None
input_binary = False
output_node_names = "output"
restore_op_name = "save/restore_all"
filename_tensor_name = "save/Const:0"
output_graph_path = os.path.join(model_path, output_graph_name)
clear_devices = True
freeze_graph.freeze_graph(input_graph_path, input_saver_def_path,
input_binary, checkpoint_path,
output_node_names, restore_op_name,
filename_tensor_name, output_graph_path,
clear_devices, "")
I also tried the freezing on the iris dataset in "tf.contrib.learn.datasets.load_iris". I get the same error. So I believe it is not related to the dataset.
As a second step, I need to use the .pb file on the phone to predict a text. I found the camera demo example by google and it contains a lot of code. I wonder if there is a step by step tutorial how to use a Tensorflow model on Android by passing a feature vector and get the class label.
Thanks, in advance!
UPDATE
By using the recent version of tensorflow (0.12), the problem is solved. However, now, the problem is that what I should pass to output_node_names ??? How can I get what are the output nodes in the graph ?
Re (1) it looks like you are running freeze_graph on a build of tensorflow which does not have access to contrib ops. Maybe try explicitly importing tensorforest before calling freeze_graph?
Re (2) I don't know of a simpler example.
CountExtremelyRandomStats is one of TensorForest's custom ops, and exists in tensorflow/contrib. As was pointed out, TF switched to including contrib ops by default at some point. I don't think there's an easy way to include the contrib custom ops in the global registry in the previous releases, because TensorForest uses the method of building a .so file that is included as a data file which is loaded at runtime (a method that was the standard when TensorForest was created, but may not be any longer). So there are no easily-included python build rules that will properly link in the C++ custom ops. You can try including tensorflow/contrib/tensor_forest:ops_lib as a dep in your build rule, but I don't think it will work.
In any case, you can try installing the nightly build of tensorflow. The alternative includes modifying how tensorforest custom ops are built, which is pretty nasty.
When I attempt to deploy my app using Eclipse it throws FileNotFoundException on my font, which I've now copied to both the assets/src and assets directory to be doubly sure.
I had this problem before, after succesfully integrating SDL_ttf into my Visual C++ build of the same app and transferring across to Eclipse for Android. Now I'm facing it again I thought I better write about it. The SDL_ttf source comes with a freetype folder already in place and referenced by android as external/freetype-2.4.12. DinoMage states I need to download this separately although he refers to freetype-2.4.11 being the latest. That's the only obvious difference from my VC build, apart from minor compiler intolerances.
I've got it working a bit now. I can sign the app (unsigned didn't work), disable USB debugging, and it will load the font and display a menu. From there it breaks, again, so I can't see how I'm supposed to debug it further. I'm sure I'll fix it somehow. But I'll also forget the obscura if I don't post here.
I don't know much about using the debugger with Android, but I can make suggestions otherwise.
Is your assets path really named "assetts"? If possible, I'm not sure how one would get Android and SDL to look there instead of "assets".
SDL and it's friend libs like SDL_ttf search for files local to the assets directory first and then search relative to the root directory. So I would expect that your "res/stubbornFont.ttf" will never load because it is in the resources "res" directory and SDL_ttf will not look there.
Maybe you can specify it relative to assets/, like "../res/stubbornFont.ttf", but I haven't tested that. It would work if you put the font in assets/ and loaded it as "stubbornFont.ttf".
I've think I've got closure on this.
It is possible to debug the app. By continuing it will trap several times trying to load one font. I think it stops eventually, I'm not sure. I've stepped through it from where it lands me at the throw stage. However single stepping from there begins from the synchronized statement, sorry it's Java but from my quick reference to What does 'synchronized' mean? I think this is a race condition
public final AssetFileDescriptor openFd(String fileName)
throws IOException {
synchronized (this) {
if (!mOpen) {
throw new RuntimeException("Assetmanager has been closed");
}
ParcelFileDescriptor pfd = openAssetFd(fileName, mOffsets);
if (pfd != null) {
return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]);
}
}
throw new FileNotFoundException("Asset file: " + fileName);//DEBUGGER traps here
}
You might be there all day single stepping that! It appears to perform all steps required of it and finally I land in:
public static ReadableByteChannel newChannel(InputStream inputStream) {
return new InputStreamChannel(inputStream);
}
No, not finally, lastly, there is
public static Context getContext() {
return mSingleton;
}
In the SDLActivity I extend.
That has a bunch of members I don't want to know about:
Luckily I discovered I can selectively "Disconnect" using a button in eclipse two along from debug/run. It has no keyboard shortcut and I'm not sure why but it will reconnect when I next trigger an exception. This is debugging as I know and love it in Android and Eclipse, still probably easier than GDB.
For arguments sake I've even replaced:
//TTF_Font *gFont = TTF_OpenFont( "res/stubbornFont.ttf", 160 );
with
TTF_Font *font=TTF_OpenFontRW(SDL_RWFromFile("res/stubbornFont.ttf", "rb"), 1, 160);//Same difference
UPDATE/EDIT
Here is the solution I was really looking for,
turning off uncaught exceptions in eclipse, it really is just that, Window->Preferences->Java->Debug and it's the very first box at the top for me.
I just started working on Google Tag Manager. I got it worked. But I faced one issue. That is, each time I edit or add some new macros, I need to create new version and publish it. Unless I am not downloading the new version and saving inside assets/tagmanager and also unless I refer with the new version name of the downloaded file, I am not able to see my updates.
Is it so? If so, I didn't understand why this is useful. Is anything done by me went wrong?
I got it worked.The issue was when we keep the json or binary inside assets folder, then on openContainer() call, Google Tag Manager will check for the saved file first. Then only it will goto the network and search. This caused issue to me. So I removed the file kept inside assets/tagmanager folder.
Also I called container.refresh() before we set value inside the singleton class.
Sample code:
ContainerOpener.openContainer(tagManager, CONTAINER_ID, OpenType.PREFER_NON_DEFAULT,
TIMEOUT_FOR_CONTAINER_OPEN_MILLISECONDS, new ContainerOpener.Notifier() {
#Override
public void containerAvailable(Container container) {
container.refresh();
// Save container for use by any other activities in the app.
WPContainerHolder.setContainer(container);
//perform your other functionalities
}
});
I'm porting a simple tetris-like XNA app to Android, using Mono For Android and MonoGame; I have followed the suggested steps in this link and so far, everything compiles well, and no relevant warnings fire up. However, upon loading the contents, a null parameter exception breaks the program at the point below in my program:
protected override void LoadContent() {
// ...
_font = Content.Load<Microsoft.Xna.Framework.Graphics.SpriteFont>("SpriteFont1");
// ...
}
The content root directory is set in the game constructor class:
public Game2 (){
Content.RootDirectory = "Content";
Content.RootDirectory = "Assets/Content"; // TEST.
//...}
And I have tried several combinations, all to no avail.
I have also tried setting the xnb files as Content as well as Android Assets in the Build Action property; having the linked, copied always, copied only if newer... etc.
Either way, my problem is that I don't really understand WHY and HOW should I do this. I'm rather new to the platform and to XNA as well, so this may very well be a newbie question, but the truth is after several hours banging my head and fists against the monitor/keyboard I feel stuck and need your help.
I have a library that supports variable-width fonts (generated by BMFont) on MonoGame. Unfortunately it is a renderer and so has other code around it. However, the basic idea is very simple. You can take a look at the loader here and the mesh builder (given a string) here. This builder supports fonts that spread characters across multiple pages, too.
Hope this helps!
MonoGame (2.5.1) throws NotImplementedException in ContentManager.Load for SpriteFont type. Have the same not resolved problem. I'm trying not to use DrawString.
For loading textures in Win32 application I use:
Content.RootDirectory = #"../../Content";
var sampleTexture = Content.Load<Texture2D>("Sample.png");
You even must not add it to solution.
For Andoind (MonoDroid) application you must add "Content" folder to your solution and set "Andtoid Asset" in "Sample.png" properties.
Content.RootDirectory = "Content";
var sampleTexture = Content.Load<Texture2D>("Sample.png");
See also:
http://monogame.codeplex.com/discussions/360468
http://monogame.codeplex.com/discussions/267900
I have an android application with different flavours.What I mean by flavours is that they differ only in their application name,icon and a url that webview in the application uses.
What I have now:
Application 1 with app_name1 and icon1:
{
Code...
myWebview.loadUrl(url1);
code..
}
Application 2 with app_name2 and icon2:
{
SameCode...
myWebview.loadUrl(url2)
Samecode..
}
What I would like to have :
Application(pick the application name and icon from build parameter):
{
Code ..
myWebview.loadUrl(pick the url from build parameter)
Code..
}
Is this possible?
This would be so good to have as I am manually copying any change that i do in either of the projects to the other and I am scared about how I would handle more than 2 "flavours".
You probably want to take a look at Library Projects. See for instance this blog post:
Library Projects allow you to share some whole parts of your applications, resources included.
The main and immediate use is to create several versions of the same application.
You should in any case be using resources to refer to these things. So e.g
<application android:label="#string:app_name" android:icon="#drawable:icon">
in your AndroidManifest.xml, and
String rl = getString(R.string.url);
in your code.
Then you simply have to swap in the right res/values/strings.xml and res/drawable/icon.png, and change the name of your final apk.