Custom Printing with Flex, Part 3: Printing Data

In the first article of this series, I discussed how to prevent users from printing directly from Flash’s default context menu. In the second article, I wrote about using the AlivePDF library to create PDFs from your application for printing or saving. Today I will be covering how to print application data from Flex.

The Flex framework comes with several classes to assist you in printing; however, they don’t tend to produce the greatest results. The PrintDataGrid class is probably your best option when it comes to printing data, but whenever I’ve worked with it in the past I’ve always ended up disappointed. Even after formatting, there are always issues; like rows getting cut off and pages breaks in weird places.

There have been talks about AlivePDF offering a Grid class to the library, which may be interesting, but it hasn’t been released and would probably only handle DataGrid data. So the best option I’ve found for printing data is to allow a server to generate a PDF, which can then be sent back to Flex and output however you want.

A great benefit of this option is the ability to easily format the print results. You can use simple HTML and CSS to customize the printout much easier than you could using ActionScript. You can also add custom styles, letterheads, and footers to fit your needs.

Here is an example, you can view the source here.

Get Adobe Flash player

This will work with any server-side script that can generate PDF content. In this demo I am using a ColdFusion script which simply generates an HTML table and returns it in PDF format. You can view the ColdFusion code along with the rest of the source code here.

The data from the server is returned to Flex as a ByteArray. You can take that ByteArray and output it to the user in several different ways:

Using the Browser

Similar to the last article in this series, you can send the results to a server-side script to either display the PDF in the browser or prompt the user to open or save the document. This time, however, the AlivePDF library is no longer necessary since the PDF binary has already been created.

private function generatePDF(pdfBinary:ByteArray, method:String):void{

//result comes back as binary, create a new URL request and pass it back to the server
var header:URLRequestHeader = new URLRequestHeader("Content-type", "application/octet-stream");
var urlString:String = "http://kalengibbons.com/assets/pages/pdfCreator.cfm";
if(method == "inline")

urlString += "?method=inline";

else

urlString += "?method=attachment&name=dataPrintSample.pdf";

var sendRequest:URLRequest = new URLRequest(urlString);
sendRequest.requestHeaders.push(header);
sendRequest.method = URLRequestMethod.POST;
sendRequest.data = pdfBinary;
navigateToURL(sendRequest, "_blank");

}

Save locally from Flash

Thanks to new capabilities in Flash Player 10, you can also provide users the option to save the PDF directly from Flash. This eliminates the need for the second server-side script.

private function savePDF(pdfBinary:ByteArray):void{

var fileRef:FileReference = new FileReference();
fileRef.save(pdfBinary, "yourPrintout.pdf");

}

If you plan to use the save functionality you’ll need to set the “Required Flash Player version” in your project preferences to 10.0.0 or higher or else Flex Builder will complain. You have to remember that only users with Flash Player 10 or above will be able to use this functionality, so some type of version validation is a necessity.

Another caveat is that the save method must be triggered by some type of user interaction, that’s why the sample application prompts for system access before saving. Although the user has clicked the “Print Data” button, that event is lost when the server call is made, so we need another interaction from the user.


Tags: , ,

64 Responses to “Custom Printing with Flex, Part 3: Printing Data”

  1. Victor Says:

    HI, very nice project..!!, but I couldn’t get it work because i don’t have coldfusion. How can I test it with a php version of your printData.cfc. Do you have a php version..?
    Thank you..
    Regards..

  2. Kalen Gibbons Says:

    Hi Victor,
    Unfortunately, I do not know much PHP so I can’t really help you. However, I can tell you that the ColdFusion code is not doing anything that PHP can’t do.

    All that’s happening in the ColdFusion script is that it’s looping through the data to create an HTML table, which is rendered by the <cfdocument format=”pdf”> tag as a PDF. That data is then rendered to Flex.

    Check out the following tutorial about creating PDF documents in PHP:
    http://devzone.zend.com/article/1254-PDF-Generation-Using-Only-PHP—Part-1

    Good luck.

  3. Kyle Dodge Says:

    Very nice Kalen. I didn’t realize FP10 allowed you to save directly like that, that’s awesome

  4. Victor Says:

    Thanks Kalen, you are rigth there is no problem with your ColdFusion script, but as far as I know it’s not possible to pass a complex object (arrayCollection in this case from your dbgrid dataprovider) directly to php file as you do in your CF to go throw and loop it, besides I have my php server installed and I would like to avoid installing another one (…by the way I don’t know much CF and how to setup..).
    Regards…

  5. xcom Says:

    for java solucion???????? exist?????

  6. xcom Says:

    flex+weborb+java +objectremoting exist solucion???

  7. saurabh Says:

    Hi kalengibbon!!
    Thanks for such a nice tutorial on alive pdf. I do have a problem & i need your help in solving it. I want to generate PDF from flex app & i don’t want to add any server side scripting to do the same.Now as far as i have understood flash player 10 is sufficent to solve mine problem but i am unable to do so.
    var fileRef:FileReference = new FileReference();
    fileRef.save(pdfBinary, “yourPrintout.pdf”);
    above line always gives me error at fileRef.save (saying call is to a possibly undefined method)
    i have included alivepdf.swc from this location http://alivepdf.googlecode.com/files/AlivePDF%200.1.4.8.zip
    I am unable to fix this problem.Can you help me how to fix this problem & get pdf from flex app without using any server side code( i am using flex builder 3 & app is flex app & not AIR app)
    thanks & regards
    Saurabh

  8. Kalen Gibbons Says:

    Hi Saurabh,
    If Flex Builder is saying that save() is an undefined method, the likely cause is your project settings. In Flex Builder go to Project >> Properties >> Flex Compiler and make sure the “Require Flash Player version” checkbox is checked and that the value proceeding is at least 10.0.0. That should fix your problem. Good luck.

  9. saurabh Says:

    Hi Kalen,
    Thanks for prompt reply. the problem was due to old version of flex sdk (i was using sdk 3.0) now i have got 3.3 & its working perfectly.
    Thanks alot for such a prompt reply.
    You have got really a nice tutorial for alive pdf thanks for that :)

    Regards
    Saurabh

  10. Montu Says:

    Hi Kalen,

    I am preparing an application using AlivePDF, I am giving user options to get which all screens in application user wants to be in PDF.For eg user do some playaround in UI & save a page to be added in pdf. nOw he again goes on doing some changes & again add page to desiarble pdf. Now we are having 2 pages which userwants to be added to pdf.now when he clicks on a button say generate pdf ;then o/p is pdf having required 2 pages.
    Can you let me know how to proceed on same.
    Regards
    Montu

  11. Toanbk Says:

    good ! but please tell me how to print data with AlivePDF in Adobe AIR Application ?

  12. Kalen Gibbons Says:

    Here’s an example of printing from Adobe AIR, taken straight from the AlivePDF Documentation:
    http://alivepdf.bytearray.org/alivepdf-asdoc/org/alivepdf/pdf/PDF.html#save%28%29

    var f:FileStream = new FileStream();
    file = File.desktopDirectory.resolvePath(“generate.pdf”);
    f.open( file, FileMode.WRITE);
    var bytes:ByteArray = myPDF.save( Method.LOCAL );
    f.writeBytes(bytes);
    f.close();

  13. Venu Says:

    I generate pdf documents using microsoft reports.

    is there a way to send a pdf document to printer without showing windows print dialog in Flex?

    appreciate any input.

  14. blake Says:

    You might try using a client side reporting component in Flex. BentBit Report is great if your users need to view or print out reports. The website is http://www.bentbit.com/?goto=main/product.asp

  15. Aarthi Says:

    I’m getting Property save not found on flash.net.FileReference and there is no default value error for this coding in my air application

    var newfilename:string = _form.txt_rdl_name.text;
    var fname:string
    var refuploadfile:filereference = new filereference();
    if(newfilename.length > 1)
    {
    var file:file = file.desktopdirectory.resolvepath(“files/” + newfilename + “.pdf”);
    fname=file.nativepath;
    refuploadfile.save(data,fname);
    }

  16. Kalen Gibbons Says:

    Hi Aarthi,
    There are two common reasons why this error could be occurring. First, for regular Flex apps, there is a project property called “Require Flash Player version” which needs to be set to 10.0.0 or above, because System File Access wasn’t available before Flash Player 10. To change this setting you can go to Project >> Properties >> Flex Compiler and you’ll see three input boxes towards the bottom.
    Secondly, and the more likely scenario in the case of an AIR app, the Flex SDK is outdated. If you’re using the 3.0 SDK you will encounter this problem. The current version is 3.4.0 and I suggest you download and use that; everything should work properly after you update.

    http://www.adobe.com/cfusion/entitlement/index.cfm?e=flex3sdk

  17. Aarthi Says:

    i’m using 3.4 only. since its a air application i don’t have Flash Player 10 option

  18. Kalen Gibbons Says:

    I’m sorry I didn’t catch this earlier, but if you’re developing an AIR application you don’t want to use the save method of the FileReference class. You should use the FileStream class to write the data to disk. You’ll need to turn your PDF into a ByteArray using AlivePDF’s save method, and then write the ByteArray to disk using the writeBytes() method. Here is an example:

    var f:FileStream = new FileStream();
    file = File.desktopDirectory.resolvePath(“generate.pdf”);
    f.open( file, FileMode.WRITE);
    var bytes:ByteArray = myPDF.save( Method.LOCAL );
    f.writeBytes(bytes);
    f.close();

    I hope this helps. Please let me know if you still have any issues.

  19. Aarthi Says:

    I’m not using Alivepdf

  20. Aarthi Says:

    how to save the url without open save dialog box

  21. Aarthi Says:

    how save rdl file in url as pdf file without open save dialogue box in flex

  22. Mike Says:

    In your code you open the pdf in http://kalengibbons.com/assets/pages/pdfCreator.cfm. How do I get this to open on my server?

  23. Kalen Gibbons Says:

    Hi Mike,
    In the generatePDF() method, simply change the following variable to point to your server:

    var urlString:String = “http://kalengibbons.com/assets/pages/pdfCreator.cfm”;

  24. Mike Says:

    First, thanks for the quick response and your code.

    I get the following error when I point to my server:

    “HTTP Error 405 – The HTTP verb used to access this page is not allowed.
    Internet Information Services (IIS)”

    Any ideas?

  25. Kalen Gibbons Says:

    Hi Mike,
    I’ve never seen that before but I did some quick digging and found that the error is being caused by the setting on your IIS server. The Flex application is doing a POST to your server and it appears that your server will only allow posts from certain “verbs.” Here’s how to change this:

    “In IIS Manager. Right click your site and select properties. Select Home Directory. Click Configuration. Select your application extension – i.e. .HTML. Click Edit. In Verbs check and make a note of what is set in Limit to. For now set Verbs to All verbs and see if your site works.”

    from Experts-Exchange

  26. Mike Says:

    Kalen,

    There is no Executable Path for the .cfm Extension. Should there be?

  27. Kalen Gibbons Says:

    I’m not familiar with IIS, but basically, you just need to make it so that the application can do an HTTP POST to a URI pointing to your .cfm file.

  28. AndyC Says:

    I’m a bit late to the party but very useful, thanks
    Small point but is it possible to script closing the browser with the pdfCreator.cfm page

  29. Alan Martin Says:

    The code is working great in my windowed program. I am having an issue if I use #NumberFormat(arguments.dataToPrint[i].phone, “999.99″)#
    instead of #arguments.dataToPrint[i].phone# in the printdata.cfc. It will throw an error. Can you help please.

  30. Kalen Gibbons Says:

    @Alan,
    It looks like you are trying to NumberFormat() a telephone number. But a telephone number isn’t typically a valid number, it’s a string with dashes (-) or dots(.). So you can’t use the NumberFormat() method on it.

  31. abhishek Says:

    can we print all images which i’m showing in tilelist ?
    Currently only visible images r printed , i want to pring all images whithout scrolling.
    :)

  32. Kalen Gibbons Says:

    Hi Abhishek,
    AlivePDF basically creates an image of what it sees, so if the user can’t see it – AlivePDF can’t see it – so it cannot print it. So you have two basic options:

    1. You can create a “print” version of the TileList that is big enough to show all the items in the list. You can create the print TileList at runtime when it’s need to print and quickly remove it after the print it complete. This can usually happen so quickly that the user is unaware of the change. This is the same technique that is often used with the PrintDataGrid class. Check out the example at the end for more info:
    http://livedocs.adobe.com/flex/3/langref/mx/printing/PrintDataGrid.html

    2. You could pass the TileList’s dataProvider to a server-side script that can duplicate the layout and print it from the server.

  33. jerome roberts Says:

    First let me thank you for your examples and explanations. They are very good. But, of course, in the real world things just don’t always fit horizontally on one page. How does one handle the situation when there are more columns (which require a horizontal scroll bar in a flex application) that will fit on one page. I have the situation where the sum of the width of the columns exceed the width of landscape oriented page?

  34. Kalen Gibbons Says:

    Sorry Jerome, I don’t have a good answer for you. That’s one of those things you just have to play with to determine what your best option is.

  35. Kunsang Says:

    How to send the pdf created in local to printer from AIR-Flex without having to open it? Or is there a someway to sent AlivePDF’s pdf object directly to printer?

  36. Kalen Gibbons Says:

    Kunsang,
    No, as far as I know, there is no way to skip the PDF generation process and push directly to the printer.

  37. Manimaran Says:

    Hi Kalen Gibbons,

    Thanks a lot for this nice article. Can i use jsp code instead of coldfusion, if yes , can you please guide me how to proceed . I need to print all the items in the datagrid , so it is very clear that i need to send the dataprovider of the datagrid(arraycollection object) , only thing is i need to use jsp , please let me know if you could help me.

    regards,
    Manimaran.

  38. Kalen Gibbons Says:

    Hi Manimaran,
    I’m sure you could do it with JSP, just like any other server language, however, I don’t know a bit about JSP so I can’t help you out much there. Sorry.

  39. Gerry Says:

    Hello Mr. “Save a lot of Time”-Kalen Gibbons

    Thank you very nuch … gread article.
    Please … can you send me your “pdfCreator.php”-Script to my email. I just need it for example. Now I use your one from
    “http://kalengibbons.com/assets/pages/pdfCreator.php”, but I know this is not the right way. I want to change this befor me
    page is public.
    PLEASE
    Thank’s
    Greatings from Swiss

  40. Kalen Gibbons Says:

    Hi Gerry,
    The pdfCreator.php file that I used in this blog post is the same create.php file that comes with the AlivePDF download, I just renamed it.

  41. abraham Says:

    hi Kalen,
    i have an application that creates a pdf using alive pdf. i use the following line to create the pdf:
    myPDFEncoder.save( Method.REMOTE, url_download, Download.INLINE, “Project Dashboard Report.pdf” );

    it uses a java servlet to create it. It works fine and shows the user the pdf in a browser. What i want to know is that, is there a way to directly save the pdf to disk without prompting the user where to save it or showing it in the browser?

    Thanks
    Abraham.

  42. Kalen Gibbons Says:

    You could save it to disk on your server but not on the client’s machine (unless it’s an AIR app). In order to save anything on the client’s machine Flash will always prompt the user; it would be a security problem if it did not.

  43. abraham Says:

    yea i want to save it on the server….how can i do that??…can u please share the code on how to do that?

    Thanks,
    Abraham.

  44. Kalen Gibbons Says:

    Hi Abraham, it shouldn’t be too hard but, unfortunately, I don’t know a bit of Java so I can’t help you there.

  45. abraham Says:

    hey…thanks fr ur help…i found out how to save it to the disk :)

  46. rani Says:

    var printPDF:PDF;
    printPDF = new PDF(orientation, Unit.MM, Size.A4);
    printPDF.setDisplayMode(displayMode, Layout.SINGLE_PAGE);
    printPDF.addPage();
    Alert.show(‘Do u wanna pdf?’, ‘PDF Creation’, Alert.OK|Alert.CANCEL, this, alertListener, null, Alert.OK);

    private function alertListener(vEvent:CloseEvent):void

    {

    if(vEvent.detail == Alert.OK){

    var file:FileReference = new FileReference();

    file.save(printPDF.save(Method.LOCAL), “Module.pdf.pdf”);

    file.load();

    }

    This is my code. from this i can save it in pdf fomat. But i want to open the pdf whenever user clicks on the button. no need to save any where.
    plssssssssssssssssssssssss help me out….

  47. Kalen Gibbons Says:

    Rani,
    Either the user has to save the PDF before he/she can view it or you will have to send it to your sever to be displayed; as outlined in the previous article:
    http://www.kalengibbons.com/blog/index.php/2009/03/custom-printing-with-flex-part-2-generating-pdfs-with-alivepdf/

  48. rani Says:

    Kalen,

    Can we write that server script code in Action Script…?

    Thanks in Advance

  49. Kalen Gibbons Says:

    You can use AlivePDF’s Grid class or Flex’s PrintDataGrid class, but you’d still need to save the PDF somewhere before displaying it to the user.

  50. Tahir Alvi Says:

    Thanks,

    But i am stuck when PDF open in web browser, i have no cfm page , can i do with it with another method?

    Thanks.

  51. Kalen Gibbons Says:

    You don’t need ColdFusion (.cfm) to do this but typically you do need some type of server technology (PHP, .NET, ect) that can generate the PDF.

  52. Anicham Says:

    Hi,

    I am trying to print the pdf file from flex without displaying printdialog box.
    am using the below part for suppressing the print dialog box. but i want to send a file name instead of mainDataGrid.

    but the addPage will accepts sprite as a input for print content area.. so is there any way to send file instead of UI component.
    kindly reply me asap..

    flash.printing.PrintJob.addPage(sprite:Sprite, printArea:Rectangle=null, options:PrintJobOptions=null, frameNum:int=0):void

    var printJB:PrintJob = new PrintJob;
    if(printJB.start2(null,false))
    {
    printJB.addPage(mainDataGrid);
    printJB.send();
    }

  53. Harry Xu Says:

    Kalen,

    In your generatePDF(), you used var urlString:String = “http://kalengibbons.com/assets/pages/pdfCreator.cfm”, and you mentioned that in our own code, we just points to our own server. Sorry I’m very new to flex, do you mean like this: var urlString:String = “http://myownsite.com/pdfCreator.cfm”?

    And where can I find the pdfCreator.cfm file? Can you please send me yours just for demo purpose?

    Thanks a million,

    Harry

  54. Kalen Gibbons Says:

    Hi Harry,
    Yes, you are correct, you should put the upload file on your domain like you mentioned. “http://myownsite.com/pdfCreator.cfm”

    I have uploaded a .cfm (ColdFusion) and a .php (PHP) sample for you to try:
    http://www.kalengibbons.com/assets/pages/pdfCreator.zip

    Thanks,
    Kalen Gibbons

  55. Harry Xu Says:

    Kalen,

    Thank you for your quick reply. However, I just realize I don’t have a http service in my project. My situation is actually more flex side. I store my PDF as base64 string in the database and return this as a byte array all the way to the flex and store it as the “data” field of a mx.controls.Text control. The text control is hyperlinked, so when the user clicks on it, the evenhandler code immediately has access to the PDF’s byte array. My problem here really is how can I show this PDF in a popup window when this happens.

    I used your code snipplet and did this:

    private function SelectWhitePaper(event:MouseEvent):void{

    var text:Text = Text(event.currentTarget);
    var header:URLRequestHeader = new URLRequestHeader(“Content-type”, “application/octet-stream”);
    var urlString:String = “http://kalengibbons.com/assets/pages/pdfCreator.cfm”;
    urlString += “?method=inline”;

    var sendRequest:URLRequest = new URLRequest(urlString);
    sendRequest.requestHeaders.push(header);
    sendRequest.method = URLRequestMethod.POST;
    sendRequest.data = text.data;
    navigateToURL(sendRequest, “_self”);
    }

    This works fine which proves that my pdf byte stream is good. However, due to the fact we don’t have an http service and won’t be easily get one (firm policy). I’m wondering if there is another way at the FLEX side that can simply shows the PDF from the already available byte array?

    Thanks again,

    Harry

  56. Kalen Gibbons Says:

    Harry,
    If you don’t have a web server to generate the PDFs in the browser why don’t you just follow the steps mentioned in the “Save locally from Flash” section of this post? That will allow users to simply open the PDF without the browser or save it on their hard drive.

  57. Aaron Winters Says:

    Kalen,
    I have a very similar problem to what Harry is having. I have the pdf in a byteArray and want to show the pdf locally without having to save the file or ping against a web service. Basically, I can’t have the data leaving the device, but I can’t save the data on the device either, just temporarily showing the data. Is this feasible? Thanks, I really appreciate your help!

    -Aaron

  58. Kalen Gibbons Says:

    Hi Aaron,
    Wow, you can’t save the file but you can’t call the server either, that’s a predicament. I’m not quite sure what you’re trying to accomplish but one other option would be to turn the bytearray into an image that can be displayed or transferred in some way.

  59. Aaron Winters Says:

    Kalen,
    Do you know how I could turn a pdf bytearray into an image? That, or is there some wacky way to produce the response that you create in your cfm programmatically? Thanks again!

    -Aaron

  60. Aaron Winters Says:

    Or… Is there a way to run the cfm (or php) locally on the device (ex. calling http://localhost/pdfCreator.php) from within a flex mobile app?

  61. Kalen Gibbons Says:

    I believe the AlivePDF API gives you access to images. If look at the previous article in this series you can see that when I do the printing I actually create an image first, then add it to a PDF before generating the PDF. But you’d have to dig into AlivePDF a bit to see what functionality is available to you.

  62. Wally Kolcz Says:

    DUmb question, but I can’t find an answer anywhere on Google. If it possible to generate the PDF with AlivePDF but rather than generate it with Flash, send ti to a FlexPrintJob directly and print the formatted PDF? Love how AlivePDF generates a PDF without server side language and allows me to dynamically place text and images, but my animal rescues would like to send the PDF directly to print (as an option). Can you send the pdf created to a UIComponent as a DisplayObject? Thanks!

  63. Get Twitter User Data Back Says:

    Admiring the time and effort you put into your
    site and detailed information you present. It’s nice to come across a blog every once in a while that isn’t the same old
    rehashed information. Fantastic read! I’ve bookmarked your site and I’m
    including your RSS feeds to my Google account.

  64. ronald Says:

    thank you! Just What I needed……

Leave a Reply