Designing Custom External Document Viewer
Designing an external document viewer requires Flash and ActionScript 3 programming skills. For developing of your viewer you may use Adobe Flash CS Professional or Adobe Flex.
Print2Flash SDK contains a sample of a simple external document viewer developed in Adobe Flash CS3 Professional. It can be imported into Adobe Flash CS4 or CS5 Professional formats as well. We recommend using this sample as a starting point when developing your own viewer. The description below deals with this sample code so refer to it for full details. If you want to develop a viewer using Flex, you may use code scraps from the sample and from below in this help topic.
Document representation
To use an external document viewer, you need to generate documents in "External Viewer" format. Documents in this format are usually represented as a single SWF file. The responsibility of your viewer is to load that document file, retrieve document pages and settings from it and display the document in your custom way. In rare cases document cannot fit a single file due to Flash format limitations. In this case Print2Flash splits a document into several parts and stores it as a set of SWF files. To account for such cases your viewer must also be able to load and process each part of the document. Additional parts are named similarly to the main SWF file name but with _partXXX appended to the file name. Here XXX is an ordinal part number which starts from 2. For example, if a document with main output file name synopsis.swf can fit into a single file, it is named synopsis.swf. However, if it has to be split into, say, three parts, three files are created:
- synopsis.swf;
- synopsis_part2.swf;
- synopsis_part3.swf.
Loading the main document file
The document loading starts from the loading of the first part of the document: the main document file. It contains document settings as well as the starting (or all) document pages. You need to communicate somehow to your viewer the URL of the main document file. For example, you may pass it from a HTML page embedding your viewer using FlashVars parameter, you may pass it from another Flash movie, etc. To load the main document file once its URL is known and put into url variable, you may use this code:
var loader:Loader=new Loader(); loader.contentLoaderInfo.addEventListener("init", onDocInit); loader.visible=false; addChild(loader); loader.load(new URLRequest(url), new LoaderContext(false,new ApplicationDomain(null))); |
Retrieving document settings
Document may have a number of settings stored in the document SWF file. These settings help the viewer in document rendering. If the document is split into several parts, settings are written into the first main document file only.
The list of common available settings is contained in Custom Document Viewer Settings help topic. To read these settings you need to declare and execute this code:
var settings:XML; function AttachBinData(id):ByteArray { var ba:ByteArray try { var AssetClass:Class = loader.contentLoaderInfo.applicationDomain.getDefinition(id) as Class; ba = new AssetClass(); } catch(e) { } return ba } function GetSetting(name){ var val=settings.attribute(name); return val; } |
var resolution:Number=parseInt(GetSetting("Resolution")); |
ChunkPageNums parameter
The most important parameter available in documents generated in "External viewer" format is ChunkPageNums parameter. It stores a comma-separated list of the number of pages contained in each document part. Using this parameter you may determine:
- the number of document parts (files);
- the number of pages in each document part;
- the total number of pages.
For example, if a document has been split into three parts, the ChunkPageNums parameter may contain, for example, this value: 102,98,40. It means that:
- the document contains three parts;
- the number of pages in the first part is 102, in the second - 98 and in the third - 40;
- the total number of pages in the document is 102+98+40=240 pages.
Processing document settings
Once the document settings are available, init event is fired on the loader object and onDocInit function is invoked because we declared it earlier as this event listener. This function should retrieve settings from the main document file and start loading of additional document parts (if any). To retrieve document settings, you need to execute this code:
var settingsArr:ByteArray=AttachBinData("Settings"); settings=new XML(settingsArr.readUTFBytes(settingsArr.length)); |
var pageChunkLimits=GetSetting("ChunkPageNums").split(/,/); |
Then you may load additional document parts (if necessary):
var ChunkLoaders:Array=new Array(); var totalPages:Number=pageChunkLimits[0]; for (var i:int=1;i<pageChunkLimits.length;i++) { var loader:Loader=new Loader(); ChunkLoaders.push(loader); loader.visible=false; addChild(loader); var url:String= ... // Determine the URL of the current document part file here loader.load(new URLRequest(url), new LoaderContext(false,new ApplicationDomain(null))); totalPages+=parseInt(pageChunkLimits[i]) } |
Attaching page movies
Each page movie is represented by an ActionScript class inherited from MovieClip class associated with a symbol of the library located in the respective document part file. To create a page movie instance, you may use this function:
function AttachPageMovie(loader:Loader, pageno:Number, parent:DisplayObjectContainer) { var id="Page"+pageno var mc try { var AssetClass:Class = loader.contentLoaderInfo.applicationDomain.getDefinition(id) as Class; mc = new AssetClass(); } catch(e:Error) { } if (mc) parent.addChild(mc); return mc; } |
- loader - an instance of Loader object which represents the document part in which the page is located;
- pageno - the number of page to create (starts from 1);
- parent - the parent movie to which to attach the created page movie as a child.
The function returns a reference to the created MovieClip instance of the page movie. If a movie cannot be created, null is returned.
Print2Flash appends page movies to the document part files in such a way so that document can be opened and viewed by users before Flash files are fully loaded. This makes user interface more responsive and allows users to start viewing the document sooner without having to wait until all document files are loaded in full. As a result of this, pages may not be available yet as soon as you started downloading document part files. They become available later as pages code is being loaded by the Flash Player. Because of this we recommend to start a timer and attach pages in timer function until all pages are loaded as demonstrated in this code:
var myTimer:Timer = new Timer(100); myTimer.addEventListener("timer", CheckLoadedPages); var loadedPages=0; myTimer.start(); function CheckLoadedPages(event:TimerEvent):void { ScanPages(loadedPages+1); if (loadedPages>=totalPages) { myTimer.stop(); myTimer=null; } } function ScanPages(startpage) { var pageno=startpage; do { var loader:Loader= ... // Determine the relevant Loader object for page #pageno var movie=AttachPageMovie(loader,pageno,parent); var validpage = movie!=null; if (validpage) { // Process page here: scale, position, etc. loadedPages=pageno; } pageno++; } while(validpage); } |