Flash bitmap & printing API
Saturday, December 30th, 2006To follow up on the first bitmap post, I’m posting some code I wrote a few weeks ago to print a movieclip. The Flash Print API is pretty mind-boggling at times I think. Although this code is in no way a general print-problemsolving formula, it does show how to use the bitmap and the print API’s combined to print a movieclip (for example a screen) sized to fit on whatever paper you are providing.
It is not a utility class, and it can certainly be improved, nevertheless it provides a good starting point. It will probably be refactored and become part of our framework. Note that it does not provide page-breaking and other formatting, its purpose is to implement a PrintScreen kind of mechanism.
var clipToPrint:MovieClip = …….;
//the bounds of clipToPrint, eg {x:clipToPrint._x, …}
var bounds:Rectangle = …….;
//reference to an offscreen clip to create print content in, eg _root.createEmptyMovieClip …
var printLayer:MovieClip = …….;
if (System.capabilities.hasPrinting) {
var my_pj:PrintJob = new PrintJob();
var pages:Number = 0;
if (my_pj.start()) {
//if factor 1, we are printing at screenresolution, if factor is 3, its 3*screenresolution
var factor:Number = 3;
//start with a bitmap image the size of our screen
var bmpContent:BitmapData = new BitmapData(bounds.width*factor, bounds.height*factor);
//and populate the bitmap with our contentpane
var matrix:Matrix = new Matrix();
matrix.scale(factor,factor);
bmpContent.draw(clipToPrint, matrix, null, null, null, true);
//create two containers, a parent and a child container. This allows us to move and scale
//the subcontainer within its parent to allow for easier placement.
var printContainer:MovieClip = printLayer.createEmptyMovieClip(“printContainer”, 0);
var printSubContainer:MovieClip = printContainer.createEmptyMovieClip(“sub”, 1);
//create a white background on the printContainer (white paper)
//use unfactored bounds since we are scaling the sub container and not the main container
var bg:TextField = printContainer.createTextField(“background”, 0,0,0, bounds.width, bounds.height);
bg.background = true;
bg.border = false;
bg.backgroundColor = 0xffffff;
bg.selectable = false;
bg.tabEnabled = false;
printContainer._visible = false; //hide it from the screen
printSubContainer.attachBitmap(bmpContent, 0); //attach the bitmap to our child
var landscape:Boolean = (my_pj.orientation == “landscape”);
//to correctly size our content, we can use the PrintJob.paperWidth/paperHeight properties
//these are in points however, not pixels, and only available after starting the printjob
//in order to relate points to pixels, we need to know two things:
//1: 1 point = 1/72 inch
//2: the screen resolution is dpi, where the dots are pixels
//So 1 point = 1/72 inch * screenDPI = x pixels
//We see if the screenDPI = 72, the conversion ratio is 1:1
//get values needed for pixel to point conversion
var screenDPI:Number = System.capabilities.screenDPI;
var point2Pixel:Number = (1/72)*screenDPI;
//declare x and y scales, since we are going to calculate
//how much we need to scale the clip to fit to the page
var xs:Number;
var ys:Number;
//there are two options (we use option 2)
//OPTION 1: rotate with the page (no matter whether we use landscape or portrait, the print is the same)
//printSubContainer._rotation = (landscape?0:-90);
//if we are landscape, we need to compare paperwidth with bounds width.
//if we are portrait, we will have rotated and need to compare paperwidth with bounds height
//xs = (landscape?bounds.width:bounds.height) / (my_pj.paperWidth * point2Pixel);
//ys = (landscape?bounds.height:bounds.width) / (my_pj.pageHeight * point2Pixel);
//OPTION 2: do not rotate with the page (a landscape sized screen will print bigger and better on a landscape paper)
//easier, compare clip width with paper width and same for height
xs = bounds.width / (my_pj.paperWidth * point2Pixel);
ys = bounds.height / (my_pj.pageHeight * point2Pixel);
//we want to keep the aspect ratio intact, so get the one we need to scale the most
//and use that value for both x and y scaling
var scale:Number = Math.max (xs, ys);
//instead of using this factor, use 90% of it, so we have some margins around the paper
printSubContainer._xscale = (1/scale)*90/factor;
printSubContainer._yscale = (1/scale)*90/factor;
//now get the size based on 100 percent and divide it in order to center the image
printSubContainer._x = (bounds.width/scale-printSubContainer._width)/2;
printSubContainer._y = (bounds.height/scale-printSubContainer._height)/2;
//refer to docs for addPage parameters
if (my_pj.addPage(printContainer, {xMin:0,xMax:bounds.width/scale,yMin:0,yMax:bounds.height/scale}, {printAsBitmap:true},1)) pages++;
if (pages == 0) {
trace(“Flash could not start the printjob.”);
} else {
my_pj.send();
trace(“Document sent to printer.”);
}
bmpContent.dispose();
bmpContent = null;
bg.removeTextField();
bg = null;
printSubContainer.removeMovieClip();
printSubContainer = null;
printContainer.removeMovieClip();
printContainer = null;
} else{
//printjob cancelled
}
} else {
trace(“Flash cannot find your printer.”);
}