Forcing Landscape Printing in Flex 2 & 3

I’ve been working on a Flex app where I needed to force landscape printing to ensure it would print out well.  Relying on the user to choose landscape won’t work.  Steven Sacks had the original solution in AS2/AS1. Darron Schall had some additional advice for Flex 1.5 built upon from Lin Lin’s advice.  I’m using Flex 3 with AS3, so had to build upon their work.  There were also some additional things I needed to do that they didn’t mention.  The additional items are embedding fonts, forcing validation, and making the right choice between vector & bitmap printing.

 Steven’s code makes the assumption you can rotate your content without any design repercussions.  The Flex SDK utilizes device fonts by default in all of its components.  What this means is when you rotate your Flex components, your text will disappear.  To allow the Flex components, and thus your entire Flex app to be rotated 90 degrees to ensure landscape printing is forced if the user hasn’t set it, you’ll need to embed fonts.  If you assign the font family you’ve embedded to the global style in your style sheet, you’re good to go.  In my case, I utilized Flash to embed the fonts, compiled the SWF, and used that in the Flex style sheet.  If you’re a rocket scientist, or don’t have a copy of Flash, you can utilize Flex only instead.  Remember, some components, like the Button, utilize bold so you have to embed a bold version of your font as well.   

@font-face
{
        src: url("assets/flash/Fonts.swf");
        fontFamily: "Trebuchet MS";
}       

@font-face
{
        src: url("assets/flash/Fonts.swf");
        fontFamily: "Trebuchet MS";
        font-weight: bold;
}

global
{
        font-family: "Trebuchet MS";
        font-anti-alias-type: "advanced";
}

 

The second thing to add is forced validation.  When you change properties in Flex, they typically don’t change immediately.  This is to ensure you only make visual changes once per frame.  No point redrawing more than 30 times per second in a 30 frame per second Flash Movie.  However, printing in Flex is currently not an asynchronous operation; it’s actually one of the only blocking calls I know of in Flash Player.  So, you need to ensure if you utilize a modified version of Steven’s code that you validate before actually calling PrintJob.addPage.  Here’s my modified version of Steven’s code for use in my Flex app.  I had to print the entire thing, AND return it back to the way it was so utilize a make shift Memento pattern in addition to a different application state.  Since the Memento HAS to be re-applied in the exact opposite order the Flex app was changed, I just handle changing the Flex app back to normal in the printing code.

protected function onPrint():void
{
        // shrinks the app basically to powerpoint size
        currentState = "print_state";   

        var pj:PrintJob = new PrintJob();
        if(pj.start() == true)
        {
                var memento:Object;
                var xScale:Number;
                var yScale:Number;
                memento = this.getMemento();
                if(pj.orientation != PrintJobOrientation.LANDSCAPE)
                {
                        this.rotation 	= 90;
                        this.x 			= this.width;
                        xScale 	= (pj.pageWidth / memento.height);
                        yScale 	= (pj.pageHeight / memento.width);
                }
                else
                {
                        xScale 	= (pj.pageWidth / memento.width);
                        yScale 	= (pj.pageHeight / memento.height);
                }
                // ensure the app doesn't get clipped; was happening on various computers
                // whist working on others
                xScale -= .01;
                yScale -= .01;
                this.scaleX 		= this.scaleY = Math.min(xScale, yScale);
                // now that you've made a bunch of transformations, ensure they are applied immediately before printing
                validateNow();
                // I have bitmaps with alpha, and some of the gradients in Flex' default components don't
                // print well on older printers
                var options:PrintJobOptions = new PrintJobOptions(true);
                pj.addPage(this, new Rectangle(0, 0, memento.width, memento.height), options)
        }
        pj.send();

        // change the app back to normal
        if(memento != null)
        {
                this.scaleX 	= this.scaleY = 1;
                this.x 			= memento.x;
                this.rotation 	= 0;
                this.width		= memento.width;
                this.height		= memento.height;
        }

        currentState = "main_state";
}

public function getMemento():Object
{
        var obj:Object = {};
        obj.x = x;
        obj.y = y;
        obj.width = width;
        obj.height = height;
        return obj;
}

 

Finally, you’ll notice I forego the powerful, and default, vector printing.  I had to do this for 2 reasons.  First, I had utilized some bitmaps, 32 bit PNG’s with alpha channels, that didn’t print well on older printers.  The alpha channels would print solid black.  Secondly, some of the gradients in the default Flex components do not print well as vector either on older printers.  While this results in less than perfect quality printing, it ensures that it prints right.

Lastly, and optionally, I wanted no background.  So, I set the Application’s background-alpha property to 0, and then set the default application color in the Flex Builder compiler properties to white.

Application
{
        background-alpha: 0;
}

-default-background-color=#FFFFFF

Unfortunately, Flash Player is cross browser, cross OS, but not necessarily cross printer.  To this day, printers are the bane of many people’s existence, and Flash Player is not immune.  Unlike most software challenges which can be surmounted by intelligence, luck, or sheer will power, printing in Flash is usually solved by trial and error… which takes a long time to resolve with no clue how much longer you need to keep trying.  While you could technically print to PDF on Mac to help save tree’s, it’s not really a true test.  Good luck!

3 Replies to “Forcing Landscape Printing in Flex 2 & 3”

  1. Too much work for the same looking result. Doing a BitmapData.draw of the app resulted in the same quality printing… only it took more code to do.

Comments are closed.