VirtualViewer® HTML 5 v5.1 Release Notes
Below, please find the release notes for VirtualViewer v5.1. For questions, please contact us at info@accusoft.com or by phone at (617) 607-2010.
Page Limit Configuration for .XLSX Documents
Rendering large XLSX documents is both time and memory intensive. VirtualViewer 5.0 saw significant improvements in rendering speed, but by their nature, these large documents still use a great deal of memory. If VirtualViewer is not allocated enough memory, or if many users are opening large XLSX documents, the viewer application may experience memory exceptions.
Now, a new configuration parameter allows administrators to limit how many pages of an XLSX document will be rendered. The parameter is an init-param
set in web.xml
, called xlsxMaximumPageLimit
. An example may be found in web.example.xml
.
Setting this configuration parameter will cut off XLSX documents at the given page maximum. For example, an administrator may set xlsxMaximumPageLimit
to 2. An XLSX document with one or two pages will render normally. An XLSX document with five pages will be cut off. On the client viewer, the document will only display two pages. A dialog will show to the user with a warning message that the document has been cut off. Additionally, the page count will not be displayed, but will be represented with an ellipsis: ...
.
The document itself is not affected by this limit. Opening a document will only limit what is displayed to the user; it will not modify the original document. Since viewer functionality like export, save, and save as would produce a page-limited result, these buttons and API functions are disabled if a document has been limited by this parameter.
New Configuration
The new configuration parameter is an init-param
in web.xml
:
<init-param>
<param-name>xlsxMaximumPageLimit</param-name>
<param-value>0</param-value>
</init-param>
A value of 0
is the default, which represents no page limitation. With a value of 0
set in xlsxMaximumPageLimit
, all XLSX documents will render completely. Acceptable values for the parameter are positive integers.
Performance Optimization for Document Load
VirtualViewer now displays long documents, particularly SnowDoc formats, significantly faster.
The first and simplest optimization was completely on the client. Documents with one thousand pages or more would take longer than necessary to load, and would halt all UI operations until all page thumbnails could be rendered. All other pieces of loading are asynchronous and do not lock up the UI, so this experience stood out. Now, thumbnail rendering has been optimized to quickly stub out all the necessary thumbnails, and only create the more extensive HTML structure when the thumbnail comes into view.
The more complex optimization adjusted how the client loads documents. Previously, VirtualViewer would load a document by first loading a document model with a great deal of metadata about the document, and then loading metadata about a page image, and finally loading a page image. Waiting for the document model to load is necessary for most viewer operations, but it can take a long time to create this data structure, particularly for long documents or for complex formats like docx.
With new RasterMaster development, SnowDoc formats like docx are now processed slightly differently. All of the long document processing operations are handled in a separate thread. This thread persists in the background until the document is fully processed, an error occurs, or the thread is interrupted. The servlet thread can either wait for the SnowDoc processing thread to complete, or it can retrieve individual pages while the document is still processing.
This new development allows VirtualViewer to start retrieving pages much earlier. Now, VirtualViewer requests the document model data structure at the same time as the first page. The document model data structure still needs to wait for all document processing to be complete, and users will not be able to perform several operations until that is loaded; but pages will begin loading immediately. This effect will be most dramatic with SnowDoc formats that are entering the cache.
New Callbacks
pageLoaded
will be called once page load completes. Page load is the new initial load of a page, where the viewer will receive both metadata and image data for a page. The page image may fall out of the buffer and need to be reloaded; in that case, the image alone will be loaded.pageLoaded
should be called only once for each page. The following parameters will be provided to the callback in the argument object:documentId
{String} The ID of the document whose page was loadeddisplayName
{String} If a new display name was sent with the page, this argument will store it. It will not yet be set in the viewerpaneIndex
{number} The 0-based index of the pane displaying the loaded documentloadedPageNumber
{number} The 0-indexed number of the loaded pagesearchableStatusBeforeLoad
{boolean} The document’s searchable status–whether the document has machine-parsable text–may change on page load. This sends the old value.
pageLoadError
will be called if a page load fails. Page load is the new initial load of a page, where the viewer will receive both metadata and image data for a page. If page load fails, it will be retried once. The following parameters will be provided to the callback in the argument object:documentId
{String} The ID of the document whose page was loadedfinalTry
{boolean} This will be true if the page failed on the second and final attempt to loadpaneIndex
{number} The 0-based index of the pane displaying the loaded documentpageNumber
{number} The 0-indexed number of the failed page
pageCountUpdated
will be called if the page count updates. We may load pages before the document is fully loaded; if we do, and therefore if we don’t have the correct page count yet, we update the page count as pages are loaded. The loaded page data will tell us if there’s a next page, and the page count will be updated accordingly. The following parameters will be provided to the callback in the argument object:documentId
{String} The ID of the document that is currently loadingpaneIndex
{number} The 0-based index of the pane displaying the loading documentoldPageCount
{number} The page count before the updatenewPageCount
{number} The current page count, after the update
Stuck Thread Interruption
Most server platforms have tools to monitor and interrupt long-running application threads. Thread interruption is the safest way to stop a thread from processing. Attempting to kill a thread is extremely unsafe, and can create a number of insidious bugs.
With thread interruption, the server program will request that an application thread be interrupted. The listening application must act on the interruption by returning and exiting operation cleanly. Previously, VirtualViewer was not able to respond well to these thread interruption tools–the application did not check for interruption, and exited on error and success.
Now, VirtualViewer will check for interruption, and will return early if the thread has been interrupted. On the client side, the viewer receives a status code noting that operation has timed out. If the viewer receives three of these status codes for a particular document, it will no longer attempt to load the document.
Configuration
Each server platform will have a different mechanism for monitoring threads, and interrupting possibly stuck threads. For example, Tomcat implements a class called the StuckThreadDetectionValve; with an entry into server.xml, the server will use the StuckThreadDetectionValve to monitor long-running threads.
Changes to JavaScript Initialization Hooks
On initialization, VirtualViewer calls the two functions beforeVirtualViewerInit
and afterVirtualViewerInit
, if they exist. These functions are both intended to be defined to call custom code.
Simplification of beforeVirtualViewerInit
Now, the function beforeVirtualViewerInit
is not required to return any value, and is not expected to call afterVirtualViewerInit
. However, beforeVirtualViewerInit
may return a value of true
in order to cancel the VirtualViewer initialization process. If a VirtualViewer initialization API is called in beforeVirtualViewerInit
, VirtualViewer will now detect that it has already been initialized, and will not attempt to reinitialize. VirtualViewer will call afterVirtualViewerInit
; that is no longer the responsibility of the custom code. If beforeVirtualViewerInit
has returned a value of true
, initialization returns early.
Startup of VirtualViewer JavaScript code now follows this flow:
-
A VirtualViewer instance is created and assigned to the global variable
virtualViewer
. -
beforeVirtualViewerInit
is called, if it exists and is a function. -
If
beforeVirtualViewerInit
has returned a value oftrue
, initialization is canceled. -
If the VirtualViewer instance has not yet been initialized,
virtualViewer.initViaURL()
is called. If the VirtualViewer instance has already been initialized, this step is skipped. -
afterVirtualViewerInit
is called.
Now, both beforeVirtualViewerInit
and afterVirtualViewerInit
take no parameters and are expected to return no values; beforeVirtualViewerInit
may return a value of true
to cancel initialization, but otherwise, VirtualViewer will detect whether initialization has occurred.
New Locations for Custom Code
Previously, beforeVirtualViewerInit
and afterVirtualViewerInit
could be defined within index.html
. This could clutter index.html
, and make it more difficult to upgrade.
Now, there are two new files in the user-config
directory, custom-code.js
and custom-style.css
. Both are loaded by index.html
, and are intended to hold only custom code and style. The stubs of beforeVirtualViewerInit
and afterVirtualViewerInit
have been moved from index.html
to custom-code.js
.
If definitions of beforeVirtualViewerInit
and afterVirtualViewerInit
are still in index.html
, they must be moved to custom-code.js
or must be defined before the script tag that loads custom-code.js
.
Speech Synthesis for Documents
Several browsers implement a Javascript speech synthesis API to manually provide text-to-speech controls. VirtualViewer now may use those API to read documents that contain text.
When a user opens a document that contains text, a button to toggle text-to-speech controls will appear on the toolbar. Clicking the button activates the control bar, which allows the user to play, stop and pause the text-to-speech; the user may also use this bar to skip pages with the next and previous buttons.
Configuration
To ensure that VirtualViewer can read the document text, set the enableTextExtraction
parameter in config.js
to true
.
Known Limitations
VirtualViewer’s text-to-speech functionality will not read the correct text for documents with text that have rotated pages. If the user clicks rotate while the document is open, the text-to-speech function will read the correct text; once the user saves the document, the rotation is essentially “burned in” and the text itself is rotated, meaning that the text no longer can be read left-to-right.
The text-to-speech button will also remain deactivated if OCR is performed on a document, since OCR functions often return unpronounceable text.
Screen Reader Compatibility
VirtualViewer is now compatible with screen readers. In addition to the text-to-speech button described above, all the controls and the displayed document itself have been reorganized and updated to allow most screen readers to interact smoothly with the viewer. A screen reader will now read out navigation items as a user tabs through them or mouses over them, and will read out a displayed text document when it comes into focus. The text document is treated as the main content of the viewer.
The document may come into focus by tabbing through the viewer, or by tabbing to a new “skip to main content” link added at the top of the tab order, in the top left corner of the viewer.
Configuration
To ensure that VirtualViewer can read the document text, set the enableTextExtraction
parameter in config.js
to true
.
Known Limitations
Essentially, VirtualViewer is extracting plain text from a document, and displaying it in a hidden HTML structure that a screen reader can navigate. Screen readers will therefore encounter the same limitations of the text-to-speech functionality described above, and to existing text selection, copy, and paste functionality existing in the viewer. A document may not be read if its format does not contain embedded text, if it was rotated such that the positional data of the text is no longer organized horizontally, or if OCR (Optical Character Recognition) returns poor results.
New Zooming Behavior for Document Compare
A new configuration item, vvConfig.zoomLock
, controls whether two documents open in document compare will zoom together. This configuration is on by default; in order to turn it off, the configuration item must be set to false
.
If vvConfig.zoomLock
is not set or is set to true
, zooming one document will zoom the other simultaneously. When opening a document in document compare, it will be initially set to the main document’s zoom rather than the default zoom set in User Preferences. If vvConfig.zoomLock
is set to false, VirtualViewer’s previous behavior will apply, and documents may be zoomed independently in document compare.
Two new API functions programmatically control whether zoom is locked in document compare:
-
toggleZoomLock
will set the zoom lock to the opposite of its current setting. This API takes no arguments. -
setZoomLock
allows zoom lock to be manually turned off and on.lock
{boolean} Pass intrue
to lock zoom for document compare, andfalse
to unlock zoom.
Audio Support
In addition to video, VirtualViewer can now play audio files that are supported by most browsers. There is no editing or annotation support at this time; audio can only be viewed and downloaded. Audio format support will depend on the capabilities of the web browser.
Supported formats
VirtualViewer uses the browser’s HTML5 audio player to play audio, and can play all types of audio supported by a browser’s player. Most browsers support MP3, M4A, FLAC, Ogg and WAV. This browser compatibility chart has more details: https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats
User preferences
There are two new preference options for audio. These options can be viewed and modified, along with video preferences, in the Media Preferences tab in User Preferences:
- Audio Loop: whether to start the audio again from the beginning when it has finished playing.
- Continue Audio on Tab Switch: whether to keep playing an audio file after you have opened or switched to another document. If this is enabled, you can listen to an audio file while viewing other documents in VirtualViewer.
All of these options have equivalent config.js
configuration options as defaults.
New and Changed Client-side API
setPageDisplayNames
will set text display names for thumbnails, ifvvConfig.displayThumbFooters
is set totrue
. The pages will display the given names instead of “Page 1”, “Page 2”, and so on. This API was previously available through a non-public API, and this safer version,virtualViewer.setPageDisplayNames(["A", "B"]);
, should now be used instead.displayNames
{string[]} An array of the display names to be used. This array should be the length of the document (the length returned byvirtualViewer.getPageCount()
). Any undefined or null values in the array will cause the page to display the page number.
Fixes and Changes
Updated Translations and Localization
Due to the accessibility improvements in VirtualViewer this release, many strings were updated and localization keys were shifted. VirtualViewer has significantly updated locale files as a result.
Zoom Settings in Internet Explorer
By default, VirtualViewer uses the Javascript image handling library pica
to sharpen images when they are zoomed to less than 100%. The configuration item vvConfig.useBrowserScaling
controls whether to use pica
; on older browsers, pica
can be slow. On Internet Explorer, pica
may take minutes to zoom out an image, which uses an unacceptable amount of processing power and memory, when the user will likely close the document before seeing the zoomed image. This also has consequences for certain API like invertImage
, which depend on the presence of a zoomed image.
Now, VirtualViewer disables pica
by default when running on Internet Explorer, essentially treating the process as if vvConfig.useBrowserScaling
were set to true
. Set vvConfig.serverScaling
to true
to use server scaling instead.
Miscellaneous
- The language attribute in the HTML tag is now dynamically set to reflect the settings in
vvDefines
and the browser - Bookmarks reference the correct pages after reordering or deleting pages in a document
- The annotation indicator no longer appears on thumbnails of cropped pages–annotations may not be placed on cropped pages
- When a document in an inactive tab is saved, it will update the tab name but will not erroneously display in the active tab
- The API
invertImage
now functions as expected in Internet Explorer a
Have questions, corrections, or concerns about this topic? Please let us know!