Archive for November, 2008

No flash events after PrintJob.start()

While developing the print functionality within a framework I got stuck on the behaviour of the Flash Player print implementation.

I couldn't solve the following steps:

  1. Start the PrintJob and display the print dialog
  2. Procceed the following tasks for every print page:
    • Load dynamic data into view templates (images, text, video...)
    • Wait for the onLoadComplete event and add the displayed contents using PrintJob.addPage()
    • Repeat for next page...
  3. Call PrintJob.send()

I really thought this would be an easy task but now I think it's not possible. Several attempts later I figured out that after calling PrintJob.start() there is no way to use the flash event model! This means loading contents after calling PrintJob.start() is impossible!

WOW!

So I used a workaround: I create all the print pages like I mentioned before, but without calls on the PrintJob-API. I simply store every print page as BitmapData and afterwards I create the PrintJob within a loop.

Now I have multiple other problems:

  • Hundreds of pages use a huge amount of RAM and often crash the application.
  • The bitmap resolution sucks so printout text quality is unsatisfying and due to point 1 I have no chance to work with higher quality.
  • I must avoid skript timeouts because after preparing all the bitmaps it takes much more that 15 seconds to add all these pages to a PrintJob.

Did I slip something?

Finally I created a small example to show you the disfunctionality (PrintJobProblem.as):

Actionscript:
  1. package 
  2. {
  3.     import flash.display.Sprite;
  4.     import flash.events.Event;
  5.     import flash.geom.Rectangle;
  6.     import flash.printing.PrintJob;
  7.     import flash.text.TextField;
  8.     import flash.text.TextFieldAutoSize;
  9.     import flash.utils.getTimer;   
  10.  
  11.     /**
  12.      * @author Markus Raab - derRaab.com / superclass.de
  13.      */
  14.     public class PrintJobProblem extends Sprite
  15.     {
  16.         private var _numPrintOuts : int;
  17.         private var _printOutIndex : int;
  18.         private var _printJob : PrintJob;
  19.  
  20.         /**
  21.          * Starts a event based printout test after a loop based
  22.          * test has successfully finished.
  23.          */
  24.         public function PrintJobProblem()
  25.         {
  26.             _numPrintOuts = 2;
  27.            
  28.             runLoopBasedTest( );
  29.             runEventBasedTest( );
  30.         }
  31.  
  32.         /**
  33.          * Demonstrates and ensures the functionality.
  34.          */
  35.         private function runLoopBasedTest() : void
  36.         {
  37.             _printJob = new PrintJob();
  38.            
  39.             if ( _printJob.start() )
  40.             {   
  41.                 for ( var i : int = 0; i <_numPrintOuts; i++ )
  42.                 {
  43.                     addPage( i );
  44.                 }
  45.                
  46.                 _printJob.send();
  47.             }
  48.         }
  49.        
  50.         /**
  51.          * Demonstrates that after calling PrintJob.start() the internal
  52.          * eventmodel doesn't dispatch any events at all. Everything is blocked
  53.          * until the script times out.
  54.          */
  55.         private function runEventBasedTest() : void
  56.         {
  57.             _printJob = new PrintJob();
  58.            
  59.             if ( _printJob.start() )
  60.             {
  61.                 trace( getTimer(), "PrintJob.start() called" );
  62.                 _printOutIndex = 0;
  63.                
  64.                 startAddPagesOnEnterFrame();
  65.             }
  66.         }
  67.        
  68.         private function startAddPagesOnEnterFrame() : void
  69.         {
  70.             addEventListener( Event.ENTER_FRAME, onAddPagesOnEnterFrameEvent );
  71.         }
  72.        
  73.         private function onAddPagesOnEnterFrameEvent(event : Event) : void
  74.         {
  75.             if ( _printOutIndex == _numPrintOuts )
  76.             {
  77.                 stopAddPagesOnEnterFrame();
  78.                
  79.                 _printJob.send();
  80.                 trace( getTimer(), "PrintJob.send()" );
  81.             }
  82.             else
  83.             {
  84.                 addPage( _printOutIndex++ );
  85.             }
  86.         }
  87.        
  88.         private function stopAddPagesOnEnterFrame() : void
  89.         {
  90.             removeEventListener( Event.ENTER_FRAME, onAddPagesOnEnterFrameEvent );
  91.         }
  92.        
  93.         private function addPage( pageIndex : int ) : void
  94.         {
  95.             var page : Sprite = createPrintPage( pageIndex );
  96.            
  97.             stage.addChild( page );
  98.            
  99.             var viewWidth : Number = page.width;
  100.             var viewHeight : Number = page.height;
  101.                
  102.             var scaleX : Number = _printJob.pageWidth / viewWidth;
  103.             var scaleY : Number = _printJob.pageHeight / viewHeight;
  104.             var scale : Number = Math.min( scaleX, scaleY );
  105.                
  106.             page.scaleX = page.scaleY = scale;
  107.  
  108.             var printRect : Rectangle = new Rectangle( 0, 0, viewWidth, viewHeight );
  109.            
  110.             try
  111.             {
  112.                 _printJob.addPage( page, printRect );
  113.             }
  114.             catch( e: Error )
  115.             {
  116.                 trace( getTimer(), "PrintJob.addPage() failed" );
  117.             }
  118.            
  119.             stage.removeChild( page );
  120.         }
  121.        
  122.         private function createPrintPage( pageIndex : int) : Sprite
  123.         {
  124.             var page : Sprite = new Sprite();
  125.            
  126.             var textField : TextField = new TextField();
  127.                 textField.autoSize = TextFieldAutoSize.LEFT;
  128.                 textField.text = "Page " + pageIndex;
  129.            
  130.             page.addChild( textField )
  131.            
  132.             return page;
  133.         }
  134.     }
  135. }