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):

package  
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Rectangle;
	import flash.printing.PrintJob;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.utils.getTimer;	
 
	/**
	 * @author Markus Raab - derRaab.com / superclass.de
	 */
	public class PrintJobProblem extends Sprite 
	{
		private var _numPrintOuts : int;
		private var _printOutIndex : int;
		private var _printJob : PrintJob;
 
		/**
		 * Starts a event based printout test after a loop based
		 * test has successfully finished.
		 */
		public function PrintJobProblem()
		{
			_numPrintOuts = 2;
 
			runLoopBasedTest( );
			runEventBasedTest( );
		}
 
		/**
		 * Demonstrates and ensures the functionality.
		 */
		private function runLoopBasedTest() : void
		{
			_printJob = new PrintJob();
 
			if ( _printJob.start() )
			{	
				for ( var i : int = 0; i < _numPrintOuts; i++ )
				{
					addPage( i );
				}
 
				_printJob.send();
			}
		}
 
		/**
		 * Demonstrates that after calling PrintJob.start() the internal
		 * eventmodel doesn't dispatch any events at all. Everything is blocked
		 * until the script times out.
		 */
		private function runEventBasedTest() : void
		{
			_printJob = new PrintJob();
 
			if ( _printJob.start() )
			{
				trace( getTimer(), "PrintJob.start() called" );
				_printOutIndex = 0;
 
				startAddPagesOnEnterFrame();
			}
		}
 
		private function startAddPagesOnEnterFrame() : void
		{
			addEventListener( Event.ENTER_FRAME, onAddPagesOnEnterFrameEvent );
		}
 
		private function onAddPagesOnEnterFrameEvent(event : Event) : void
		{
			if ( _printOutIndex == _numPrintOuts )
			{
				stopAddPagesOnEnterFrame();
 
				_printJob.send();
				trace( getTimer(), "PrintJob.send()" );
			}
			else
			{
				addPage( _printOutIndex++ );
			}
		}
 
		private function stopAddPagesOnEnterFrame() : void
		{
			removeEventListener( Event.ENTER_FRAME, onAddPagesOnEnterFrameEvent );
		}
 
		private function addPage( pageIndex : int ) : void
		{
			var page : Sprite = createPrintPage( pageIndex );
 
			stage.addChild( page );
 
			var viewWidth : Number = page.width;
			var viewHeight : Number = page.height;
 
			var scaleX : Number = _printJob.pageWidth / viewWidth;
			var scaleY : Number = _printJob.pageHeight / viewHeight;
			var scale : Number = Math.min( scaleX, scaleY );
 
			page.scaleX = page.scaleY = scale;
 
			var printRect : Rectangle = new Rectangle( 0, 0, viewWidth, viewHeight );
 
			try
			{
				_printJob.addPage( page, printRect );
			}
			catch( e: Error )
			{
				trace( getTimer(), "PrintJob.addPage() failed" );
			}
 
			stage.removeChild( page );
		}
 
		private function createPrintPage( pageIndex : int) : Sprite
		{
			var page : Sprite = new Sprite();
 
			var textField : TextField = new TextField();
				textField.autoSize = TextFieldAutoSize.LEFT;
				textField.text = "Page " + pageIndex;
 
			page.addChild( textField );	
 
			return page;
		}
	}
}

5 thoughts on “No flash events after PrintJob.start()”

  1. You could create and print a smaller number of pages at a time. That would solve crashing and timeout issues, not much I could recommend about quality.

  2. Hello! This is an excellent post. It is good to co-miserate with others having the same problem.

    I would like to know if you were able to find a solution to this problem.

    1) Avoiding Script-Timeouts
    2) Use the flash event model. Specifically, adding pages on EnterFrame and not having the printJob close the spool upon leaving a frame.

    Thanks.

    Have a nice day.

  3. We ran into this exact same issue. We also used a template based system for our reports and would utilize databinding which would cause the templates to sometimes load images. We moved away from templates to rendering every page in advance and making sure all images were fully loaded and then printing. Depending on the number of reports and records they selected it could eat up to a gig of ram (which we found the OS never fully reclaimed even though Flex Builder profiler didn’t indicate any instances hanging around). We now settled on a solution to load all images up before printing (array of Loader objects) and then create images from the binary image data as we move through the template/record combination’s. The good thing about this (even though we should never have had to do it) is we probably will never hit the 15 second timeout on addPage with a print job as all images (or external resources) will be 100% loaded. Hope this helps!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.