Page to Bitmap Conversion Time Slow on Android

Rendering pages to JPEG is slow for large documents. Attached is a sample project with a 14MB .docx file. It took 52 seconds just to convert the first page to a JPEG image on a Samsung Galaxy S5 with Marshmallow. Here's the log with timestamps from the sample project:

05-18 10:58:32.669 27809-27809/company.testasposewords D/MainActivity: License is set
05-18 10:58:32.669 27809-27809/company.testasposewords D/MainActivity: Loading document
05-18 10:58:36.669 27809-27809/company.testasposewords D/MainActivity: Converting page 0 to JPEG
05-18 10:59:24.889 27809-27809/company.testasposewords D/MainActivity: Setting bitmap in ImageView
05-18 10:59:24.929 27809-27809/company.testasposewords D/MainActivity: Done

Can you please give me insight as to why it's so slow? Smaller documents don't take as long but still seem to take longer than desired, making a ViewPager solution (as shown in your sample Github project) unusable.

There is also an exception stack trace that's printed when running the sample project from the Aspose.Words library, stating that the stream is closed:

05-18 10:58:36.609 27809-27809/company.testasposewords W/System.err: java.io.IOException: The stream is closed.
05-18 10:58:36.609 27809-27809/company.testasposewords W/System.err: at asposewobfuscated.zz63.zzBk(Unknown Source)
05-18 10:58:36.609 27809-27809/company.testasposewords W/System.err: at asposewobfuscated.zz63.zzD(Unknown Source)
05-18 10:58:36.609 27809-27809/company.testasposewords W/System.err: at asposewobfuscated.zzY0.zzT(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at asposewobfuscated.zzY0.zzX(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at asposewobfuscated.zzY0.(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at asposewobfuscated.zzY0.(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.zzZJ0.zzZd(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.zzZJ0.zzu(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.zz4J.zzY(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.zz4J.zzE(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.zz4J.visitShapeStart(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.Shape.zzZ(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.CompositeNode.acceptCore(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.Shape.accept(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.CompositeNode.acceptChildren(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.CompositeNode.acceptCore(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.Paragraph.accept(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.CompositeNode.acceptChildren(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.CompositeNode.acceptCore(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.Body.accept(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.CompositeNode.acceptChildren(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.CompositeNode.acceptCore(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.Section.accept(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.CompositeNode.acceptChildren(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.CompositeNode.acceptCore(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.Document.accept(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.zz4J.zzZ(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.Document.zzY(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.Document.zzZ(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.Document.(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.Document.(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.aspose.words.Document.(Unknown Source)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at company.testasposewords.MainActivity.onCreate(MainActivity.java:69)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at android.app.Activity.performCreate(Activity.java:6876)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1135)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3206)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3349)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at android.app.ActivityThread.access$1100(ActivityThread.java:221)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at android.os.Handler.dispatchMessage(Handler.java:102)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at android.os.Looper.loop(Looper.java:158)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at android.app.ActivityThread.main(ActivityThread.java:7224)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at java.lang.reflect.Method.invoke(Native Method)
05-18 10:58:36.619 27809-27809/company.testasposewords W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
05-18 10:58:36.629 27809-27809/company.testasposewords W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)

Hi Per,


Thanks for your inquiry. Please upgrade to Aspose.Words for Android via Java 17.5 version and try running the following code on your end.
<span style=“background-color: rgb(255, 255, 255); font-family: “Courier New”; font-size: 9pt;”>
<span style=“background-color: rgb(255, 255, 255); font-family: “Courier New”; font-size: 9pt;”>Runtime runtime = Runtime.<span style=“font-family: “Courier New”; font-size: 9pt; font-style: italic;”>getRuntime<span style=“background-color: rgb(255, 255, 255); font-family: “Courier New”; font-size: 9pt;”>();
<pre style=“font-family: “Courier New”; font-size: 9pt;”>long startTime = System.currentTimeMillis();

Document doc =
new Document(Environment.getExternalStorageDirectory().getAbsolutePath() + “/Large document.docx”);

long endTime = System.currentTimeMillis();
String times =
“Document Load time: " + (endTime - startTime) + " ms\n;

startTime = System.
currentTimeMillis();

ImageSaveOptions options =
new ImageSaveOptions(SaveFormat.JPEG);
options.setPageCount(
1);
int pageCountDoc = doc.getPageCount();
for (int pageCount = 0; pageCount < pageCountDoc; pageCount++) {
options.setPageIndex(pageCount);
doc.save(Environment.
getExternalStorageDirectory().getAbsolutePath() + “/out_” + pageCount + “.jpg”, options);

endTime = System.
currentTimeMillis();
times = times +
“Image " + pageCount + " Save Time: " + (endTime - startTime) + " ms \n;
startTime = System.
currentTimeMillis();
}

DocumentBuilder builder =
new DocumentBuilder();
builder.writeln(times);
builder.getDocument().save(Environment.
getExternalStorageDirectory().getAbsolutePath() + “/testResults.docx”);

Please see attached testResults.docx. This looks to be an expected behavior. ‘Aspose.Words for Android via Java’ has to build ‘Page Layout’ of complete Document before it can actually start exporting content to Image formats. You will notice that rendering first Page to first Image takes more time than rendering subsequent Pages to separate Images. It depends on the size and complexity of your Word document.

If we can help you with anything else, please feel free to ask.

Best regards,

Thanks for the information. Attached are my test results with Aspose.Words 17.5 when run on a Samsung Galaxy S5 with Marshmallow. It took 52 seconds to load the document and render the first page. I’ve tried several other documents that are a few megabytes in size, and they take a long time to render the first page as well.


I don’t see how this library is a solution for viewing Word documents on an Android device. It might work somewhat quickly for very small documents, but the load time for moderately sized documents makes it unusable. Users cannot wait this long to view documents, and therefore I don’t see the project on GitHub being a solution (GitHub - AsposeShowcase/Document_Viewer_and_Converter_for_Android: Document Viewer & Converter by Aspose for Android).

Other Android Office viewers on the app store open the “Large document.docx” file within a second or two on the S5. I assume they don’t render pages as bitmaps or parse the entire document’s page layout before displaying the first page.

Hi Per,

Thanks for your inquiry.

The results mentioned in my testResults.docx file were also produced on a real device having Android version 5.1.1. In the code shared in my previous post, I think, specifying options.setUpdateFields(false); to ImageSaveOptions class should improve time to Save your Word Document to first Image (and other remaining Images as well).

Roughly, Aspose.Words layouts 10 pages per second; so, the extra amount of time Aspose.Words takes to format a document into pages depends on the number of pages your Word document has. Also, please note that this process is not linear; it may take a minute to build layout of one page and may take a few seconds to process 100 pages. Put simply, the processing time and memory usage fully depend on your documents and their complexity.

There is another aspect i.e. Aspose.Words needs to pre-cache fonts and other resources for rendering. This only happens for the first conversion. If you want to do this pre-caching earlier then you can simply call doc.updatePageLayout() on an "empty document" before converting Word to Images and any other subsequent Word to Images conversions. The following code explains this aspect:

Runtime runtime = Runtime.getRuntime();
long startTime = System.currentTimeMillis();

Document emptyDoc = new Document();
emptyDoc.updatePageLayout();

Document doc = new Document(path + "Large document.docx");

long endTime = System.currentTimeMillis();
System.out.println("Load time:" + (endTime - startTime));
startTime = System.currentTimeMillis();

ImageSaveOptions options = new ImageSaveOptions(SaveFormat.JPEG);
options.setUpdateFields(false);

doc.save(path + "first.jpg", options);

endTime = System.currentTimeMillis();
System.out.println("Save time:" + (endTime - startTime));

And the results produced by this code on our end are:

Load time:12703
Save time:10951

Hope, this helps in meeting your requirement. Please let us know if we can be of any further assistance.

Best regards,
Thanks for providing additional clarification. While Aspose.Words page rendering quality is quite good, I don't see the library being performant enough to include as a solution for viewing Word documents on Android, particularly because of the time required to load the document and render the first page. Even with your prescribed optimizations, the test still took 23.7 seconds (on whichever device you used) just to render the first page.

I do understand that load time for Aspose.Words depends on the file size, number of pages, and document complexity. However, it doesn't seem that a good approach to document viewing in a lightweight device environment such as Android should require the entire document be parsed in some way before allowing the first page to be viewed. This approach seems a better fit for server side services or batch conversion on systems with more resources. Just my feedback as a tester and potential customer. Thanks again for your support.
Hi Per,

Thanks for your suggestions. We have passed your concerns to our product team and may consider implementing 'Building a Partial Layout of a particular Page" in future. We have logged an investigation ticket in our issue tracking system; the ID of this issue is WORDSJAND-262. Your thread has also been linked to this issue and you will be notified as soon as it is resolved/supported. Sorry for any inconvenience.

Best regards,