Home  • Download  • Register Now!  • Benefits  • Help  • Testimonials  • Samples  • Screenshots  • Awards  • Forum  • Convert Documents Online  • Print2Flash APIs  • Print2Flash vs. FlashPaper  • Contact Us
 Help Contents

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:

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)));
When the document file starts loading and document settings become available, init event is fired on the loader object. You need to process this event in order to retrieve settings from it and start loading additional document parts (if any). In the sample above we specified the onDocInit function as a listener of init event (discussed below).

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;
}
Then you may use the declared GetSetting function to retrieve a setting value passing it the setting name as a parameter. However, before this you need to load settings into settings variable as described below. For example, to get the resolution of the document, you may use this code:
 
var resolution:Number=parseInt(GetSetting("Resolution"));
Note that all values are returned by GetSetting function as strings so you may need to convert them to other types as demonstrated in the previous sample with the standard parseInt function.
 

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:

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:

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));
Then to retrieve information on document parts, you need to use ChunkPageNums parameter like this:

var pageChunkLimits=GetSetting("ChunkPageNums").split(/,/);
It will create an array of values representing a number of pages in each document part. The number of values in this array correspond to the number of parts in the document. For example, for the sample document mentioned above, the array will contain three values: 102, 98 and 40.

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])
}
You need to store each created loader object in an array (ChunkLoaders array in this example) for later usage for attachment of page movies. Also, you need to determine each part URL by appending _partXXX string to the main document URL. You may also calculate the total number of pages in the document by summing the values of the pageChunkLimits array and put the result in a totalPages variable which may appear useful later. See the SDK sample for full details.

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;
}
The function accepts three parameters:

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); 
}
This code assumes that parent variable is set to a reference to the parent movie. After successful attachment you may process the page instance: scale, position it, etc. as indicated in the code comment. See the SDK sample for full details.