Here today, gone tomorrow

Flash AS3 PrintJob: Problems printing from Flash

Flash has a feature called PrintJob that allows you to print MovieClips – either by creating PDFs or simply sending them directly to a printer. Unfortunately, PrintJob has a poorly documented bug that can cause a lot of headaches. Sometimes, it will print blank pages. Other times, it will scale the pages incorrectly. The behavior is seemingly random and it is different on different computers. I had a lot of trouble printing from Flash with a recent project at work, but there is a remarkably simple solution. Read on…

In my project, I allowed a user to save PDFs to a print queue for printing at a later time. This was done by simply pushing the MovieClips onto an array. When a user hit the print button, I created a PrintJob and then looped through the array of MovieClips, scaling each one as needed to fill the page and then sending them to the printer. The actionscript code looked like this:

//-prints all saved pdfs:
public function printAllPages():void {
	if (savedPdfsArray.length > 0) { //if there are pdfs to print...
		var pj:PrintJob = new PrintJob(); //create printjob
		if(pj.start()) {
			for (var i:int=0; i < savedPdfsArray.length; i++) {            
				//scale it to fill the page (portrait orientation):
				var myScale:Number;
				myScale = Math.min(pj.pageWidth/savedPdfsArray[i].width, pj.pageHeight/savedPdfsArray[i].height);
				savedPdfsArray[i].scaleX = savedPdfsArray[i].scaleY = myScale;
				var printArea:Rectangle = new Rectangle(0, 0, pj.pageWidth/myScale, pj.pageHeight/myScale);

				pj.addPage(savedPdfsArray[i], printArea); //add page to print job
			}
			pj.send(); //send to printer
		}
		pj = null;
	}
	else { //if there are no pdfs in the queue...
		errorPopup.openMe("You do not have any pdfs saved in your queue.");
	}
}

This code worked perfectly on my PC, but occasionally gave me problems on an old iMac in the office. I had someone else test it on a newer Mac and it seemed fine, so I wrote it off as an outdated printer driver.

Then, when we sent it to the client, there were all sorts of problems. On some computers, it printed blank pages. On others, it scaled the pages incorrectly, so that the MovieClips didn't fill the page. It happened on both Macs and PCs. After a lot of Googling around without much success, I found this thread on Kirupa forum. One of the responders suggested that the MovieClips must be added to the stage or they won't print. I gave this a try and IT WORKED! It fixed all of the weird, unpredictable PrintJob behavior in my application. I quickly updated my code and the client was happy:

//-prints all saved pdfs:
public function printAllPages():void {
	if (savedPdfsArray.length > 0) { //if there are pdfs to print...
		var pj:PrintJob = new PrintJob(); //create printjob
		if(pj.start()) {
			for (var i:int=0; i < savedPdfsArray.length; i++) {
            
            			//========== printjob bug fix - prevent blank pages: ==========
                		savedPdfsArray[i].x = 2000; //keep it hidden to the side of the stage
                		stage.addChild(savedPdfsArray[i]); //add to stage - prevents blank pages
                		//=============================================================
                
				//scale it to fill the page (portrait orientation):
				var myScale:Number;
				myScale = Math.min(pj.pageWidth/savedPdfsArray[i].width, pj.pageHeight/savedPdfsArray[i].height);
				savedPdfsArray[i].scaleX = savedPdfsArray[i].scaleY = myScale;
				var printArea:Rectangle = new Rectangle(0, 0, pj.pageWidth/myScale, pj.pageHeight/myScale);

				pj.addPage(savedPdfsArray[i], printArea); //add page to print job
			}
			pj.send(); //send to printer
		}
        
        	//========== printjob bug fix - prevent blank pages: ==========
        	for (var j:int=0; j < savedPdfsArray.length; j++) {
        	    stage.removeChild(savedPdfsArray[j]); //don't forget to remove them from the stage
        	}
        	//=============================================================
        
		pj = null;
	}
	else { //if there are no pdfs in the queue...
		errorPopup.openMe("You do not have any pdfs saved in your queue.");
	}
}

I hope this post saves someone else a lot of hair-pulling. Thank you "orangehaze" and Kirupa forum!

Previous

Papervision3D: Max3DS vs. Collada performance

Next

Flash AS3: Why can’t I extend my AS3 class?

24 Comments

  1. david doull

    thanks – it helped me

  2. Thanks. it works for me also.

  3. Thanks I will give her a try! And another thing to note – sometimes you’ll get errors like filters will not render at that size or 3d will not render. Even though you arent using them!

  4. admin

    @Elliot Geno
    Filtering large movieclips is always an issue in Flash. I created a workaround for the filtering problem on a project a few months ago that I have been meaning to post, so maybe I’ll do that next. Thanks.

  5. Adam Chromicz

    Awesome, Thanks so much, just add it to the stage, move it out of the way using an exagerated x or y value and bam, clients happy!!!!

  6. Hugo

    I have clients with a different problem printing from flash on Macs.
    It prints, but the fonts are all HUGE!!!
    It seems to only happen with text generated on dynamic text boxes…
    any ideas?

  7. admin

    @Hugo
    I haven’t seen that problem before. Are you creating the dynamic text with actionscript or is the textbox already on the stage? Here are a few things to try:
    – Make sure your fonts are embedded. Otherwise, it may be trying to substitute a font.
    – Are you scaling the Movieclip before printing? Maybe your font isn’t scaling for some reason.
    – Add the movieclips to the stage where you can view them to see if the fonts look correct on stage (or not).
    – Try a different font (embedding it of course)
    – Check the version of Flash you are using. I prefer working in Flash 9 (CS3) most of the time, but it had a few weird bugs that seem to be fixed in Flash 10.
    – Another trick I have for printing from Flash is to use the Bitmap.draw() method to essentially create a screenshot of a movieclip and then print that bitmap. Flash sometimes has problems with transparent PNGs and masks, but using the screenshot method fixes them.

    I hope that helps. If you leave a comment when you find the solution to your problem, it may help save other people some frustration.
    Andy

  8. Vladox

    Hi
    I was trying to print the Stage and stumbled with a lot of problems getting the stage to resize properly so I use a combination of solutions, that involved converting the stage to a bitmap.

    Here my source:

    function PrintStage(evt:MouseEvent) {
    var printJob:PrintJob = new PrintJob();
    var options:PrintJobOptions = new PrintJobOptions();
    options.printAsBitmap = true;
    trace(“print called!”);
    if (printJob.start()) {
    var printSprite = new Sprite();

    var bitmapData:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight);
    bitmapData.draw(stage);
    var screenShot:Bitmap = new Bitmap(bitmapData);

    printSprite.addChild(screenShot);

    //========== printjob bug fix – prevent blank pages: ==========
    printSprite.x = 2000; //keep it hidden to the side of the stage
    stage.addChild(printSprite); //add to stage – prevents blank pages
    //=============================================================

    trace(“before printSprite width: ” + printSprite.width + ” printJob.pageWidth: ” + printJob.pageWidth);

    //scale it to fill the page (portrait orientation):
    var myScale:Number;
    myScale = Math.min(printJob.pageWidth/printSprite.width, printJob.pageHeight/printSprite.height);
    printSprite.scaleX = printSprite.scaleY = myScale;
    var printArea:Rectangle = new Rectangle(0, 0, printJob.pageWidth/myScale, printJob.pageHeight/myScale);

    trace(“after printSprite width: ” + printSprite.width + ” printJob.pageWidth: ” + printJob.pageWidth);

    printJob.addPage(printSprite,printArea,options);
    printJob.send();

    stage.removeChild(printSprite);
    printSprite = null;
    }
    }

    Hope it helps someone….

  9. admin

    @Vladox
    Thanks for the solution! That reminds me that there is another “bug” in Printjob: if you have several PNGs or masked items on top of each other, they don’t always print correctly. The solution is similar to what you did here – create a Bitmap and do a Bitmap.draw() of your MovieClip, then print the Bitmap (after adding it to the stage of course).

    Thanks for posting your solution here!
    -Andy

  10. Thanks a lot! I was having this problem with blank space and adding item on stage fixed the problem!

    Actually the problem was that when I had a mask applied to one of the printable sprites, it is then that a blank area was being shown.

    Adding it to stage fixed the problem with the mask applied!

    Thanks a lot! 🙂

  11. Steve

    Wow, sometimes you find a snippit that saves your entire day.

  12. Tom

    Vladox,
    Your example is exactly what I was looking for. Thanks a thousand times over.

  13. Thanx for this. It is very useful!

  14. Anicham

    Hi,

    your example is very helpful for us. Actually you are using flash rite.
    Shall i try the same functionality in flex – Air application.if we can means . could you please tell me , how can i proceed to get the exact result as yours..

    waiting for ur reply.. its my urgent requirement….

  15. admin

    I don’t use Air or Flex much, but the code should be the same, since they all use AS3.

  16. Patricio

    Hi andy! Thanks for this article, it was helpful!

    Can I make you a question? How did you manage to print the PDFs? I’ve searched *a lot* for that but didn’t find anything useful, so I ended up generating the document itself in flash.

    Thank you!

    Patricio

  17. admin

    Ahh… The Print to PDF feature on this project was handled externally – using a plugin from Adobe that gives you a printer option of “PDF” when you print anything. Since this particular application was used by a limited group of salespeople, we were able to specify that they had to have the Print to PDF plugin installed on their computers.

    If I had to create PDFs for a publicly available application, I would probably send the info to a php script that would generate the PDF. There are several good PHP libraries that can do this.

  18. Patricio

    Thank you very much for your answer! I misunderstood you, and thought that you where printing server-generated PDFs from flash into paper, which seems not to be feasible with current AS3 PDF libs.

    Thanks again for answering =)

    Paricio

  19. What’s the meaning of variable:savedPdfsArray? Is it the paths of Pdf files? I do not known how to use it.Please clarify.

  20. admin

    savedPdfsArray is just an array of movieclips that I print. In this application, a user can save multiple PDFs to a “print queue” (the savedPdfsArray) and then print them all at once.

  21. @admin
    Thanks for your help. Another question: Can AS3 convert pdf files to movieclips objects? I have no idea about it. Any suggestion or comments are welcomed.

  22. Michael

    admin,

    I have the same question as bencenche. I understand that you creating a queue of movieclips, which “contain” PDFs. Can you help with understanding how you loaded the PDFs into the movieclips?

    Thanks you

  23. admin

    Michael,
    Flash does not load or display PDFs. What I’m doing is creating MovieClips that look like PDFs, then sending them to a user’s printer. If you have ever downloaded Adobe Acrobat, it probably installed “Adobe PDF” as a printer on your machine. So, when Flash sends the MovieClips to your printer, you can save them as PDFs instead of printing them. Flash is not loading, displaying, creating, saving or printing a PDF. It is simply printing a MovieClip. Your computer has to do the PDF printing.

    If this solution isn’t workable, you could probably create an image and send it to a PHP script to generate the PDF. There are several PHP libraries that can generate PDFs dynamically.

  24. Thomas

    Thank you for this! I was having problem with the flash not publishing when scaling a sprite before printing it. Adding said Sprite to stage solved the problems 🙂

Powered by WordPress & Theme by Anders Norén