Custom Printing with Flex, Part 2: Generating PDFs with AlivePDF
In the first article of this series, Overriding Flash’s Built-In Print Option, I discussed how to prevent users from printing directly from Flash, by replacing the default context menu. I demonstrated how poorly Flash handles printing directly, and now we will start discussing what alternatives are available to developers.
In this article I will demonstrate how to print and save any part of your application by utilizing the AlivePDF library. AlivePDF is an ActionScript 3 open-source PDF library that easily creates PDF documents from your Flex application. The library is pretty robust and offers much more functionality than I will be able to cover here. In this article I want to demonstrate how simple it is to dynamically generate PDF documents using ActionScript and AlivePDF.
To give you a better understanding of what can be done with AlivePDF, let’s revisit one of the printing examples that was used in part 1 of the series. The two images below are printouts of the The Flex Store – one printed with Flash’s default print option and the other with AlivePDF.
Flex Store printed using Flash’s default print option
|
Flex Store printed using AlivePDF
|
In addition, here is a sample application for you to play with some of AlivePDF’s options. You can view the source here.
So now that you’ve had a taste of what AlivePDF can do, lets look at how it works:
Adding AlivePDF to your project
First, download the library from www.AlivePDF.org, and then add it to your project in one of two ways. The easiest way is to copy the AlivePDF.swc into your project’s lib folder. Flex Builder should automatically detect the swc and add it to the compile settings. The second approach is to add it manually in Flex Builder, by clicking Project >> Properties >> Flex Build Path >> Library Path >> Add SWC… and selecting the swc from the file system.
Displaying PDFs in the Browser
After the swc has been added to your project you can begin working with the AlivePDF library. The sample code below could be used to generate a PDF document from any UI component in your application. We simply turn it into an image (think of it as a screenshot) and publish it to a PDF for the user to save or print.
The code is fairly simple, we start by creating a new instance of the PDF class and adding a page to it. Then we add our UIComponent to the document as an image. Finally, we tell AlivePDF how we want to generate the PDF with the save() method. In this example, the third argument of the method, Download.INLINE, specifies that we want the PDF to be displayed in the browser instead of prompting the user to save (that will be covered in the next section).
import mx.core.UIComponent;
import org.alivepdf.display.Display;
import org.alivepdf.images.ResizeMode;
import org.alivepdf.layout.Layout;
import org.alivepdf.layout.Orientation;
import org.alivepdf.layout.Size;
import org.alivepdf.layout.Unit;
import org.alivepdf.pdf.PDF;
import org.alivepdf.saving.Download;
import org.alivepdf.saving.Method;
private function doPrint(whatToPrint:UIComponent):void{
printPDF.setDisplayMode( Display.FULL_PAGE, Layout.SINGLE_PAGE );
printPDF.addPage();
printPDF.addImage( whatToPrint, 0, 0, 0, 0, ‘PNG’, 100, 1, ResizeMode.FIT_TO_PAGE );
printPDF.save( Method.REMOTE, "/includes/pdfCreator.cfm", Download.INLINE, "test.pdf" );
}
Prompting Users to Save
Now that works great and all… but what if you want to prompt the user to save or open in Adobe Reader? Fortunately, AlivePDF makes that easy; all you have have to do is change Download.INLINE to Download.ATTACHMENT.
Using AlivePDF with ColdFusion
A PHP script is provided with the download of the AlivePDF library, but if you don’t like PHP you can use any other server-side language that can generate PDF content. For those of you who are ColdFusion fans, like myself, here is a basic example of a ColdFusion script that can be used.
<!––– establish parameters –––>
<cfparam name="URL.method" default="" />
<cfparam name="URL.name" default="" />
<––– get the content from the http data –––>
<cfset httpContent = GetHttpRequestData()>
<!––– make sure content was passed in –––>
<cfif len(httpContent.content) gt 0>
<cfheader name="Content-Disposition" value="#URL.method#; filename=#URL.name#" />
<cfcontent type="application/pdf" variable="#httpContent.content#">
<cfelse>
<cflocation url="/" />
</cfif>
AlivePDF has a wide range of capabilities and we’ve barely scratched the surface here. I encourage you to take a good look at the library and utilize it to its full potential.
In the next article in this serious we will discuss how to print data from Flex. See you soon!
Tags: AlivePDF, Custom Printing with Flex, series
Thanks Kalen. I suppose when using AIR there’s no need for the server side stuff, right?
I will look into it further. Thanks again!
Hi Mark,
you are correct. When using Adobe AIR, the simplest approach would be to write the PDF to disk. If you change Method.REMOTE to Method.LOCAL when calling the save() method, it will return a byteArray of the PDF. You can then use the FileStream class, and call its writeBytes() method to save the file.
In addition, an enhancement in Flash Player 10 now allows us local disk access. This means that even on the web, we can do away with the server-side scripts and save directly to the user’s machine. How to do this will be covered in my next article in this series, which will focus on formatting and printing application data.
Thanks,
Kalen Gibbons
Wow, Excellent article Kalen !
Happy you like AlivePDF
Thanks Kalen for the great demo.
I have created a demo app for generating pdf from a VBox with dynamic child….it
doesn’t work. Take a look. I am using Flex4 SDK to save the PDF locally in FP 10.
<![CDATA[
import org.alivepdf.images.ResizeMode;
import org.alivepdf.saving.Method;
import org.alivepdf.images.ImageFormat;
import org.alivepdf.pages.Page;
import org.alivepdf.display.*;
import org.alivepdf.layout.*
import org.alivepdf.pdf.PDF;
private var mPDF:PDF;
private function onPDFCreate():void
{
mPDF = new PDF(Orientation.PORTRAIT, Unit.MM, Size.A4 );
mPDF.setDisplayMode( Display.FULL_PAGE, Layout.SINGLE_PAGE );
mPDF.setTitle(‘Module’);
for(var i:int=0; i
Need a quick solution…please help!!
Hi SunPatel,
I would love to help but it looks like we only got a bit of your code. Could you please try reposting your code in HTML format or email it to me directly: kalen.gibbons[at]gmail[dot]com
Thanks,
Kalen Gibbons
<![CDATA[
import org.alivepdf.images.ResizeMode;
import org.alivepdf.saving.Method;
import org.alivepdf.images.ImageFormat;
import org.alivepdf.pages.Page;
import org.alivepdf.display.*;
import org.alivepdf.layout.*
import org.alivepdf.pdf.PDF;
private var mPDF:PDF;
private function onPDFCreate():void
{
mPDF = new PDF(Orientation.PORTRAIT, Unit.MM, Size.A4 );
mPDF.setDisplayMode( Display.FULL_PAGE, Layout.SINGLE_PAGE );
mPDF.setTitle(‘Module’);
for(var i:int=0; i
Nope doesnt work posting it here so I sent via email.
Thanks again
Awesome dude this is really helpful. Looking forward to figuring out how to print the listing of data
Kalen, awesome stuff… I’m limited to an internal IIS server that I don’t have a lot of control over. The webserver doesn’t support php or coldfusion and I’ve been racking my head to get it to work in an asp script instead. I’ve changed the option to asp and pointed it to the directory of where my file is but keep getting page not found errors.
Here’s what I have in my .asp page.
Anyone have a clue on what I’m doing wrong?
some reason the script wouldn’t copy over on the first post.
dim method
dim name
method = Request.QueryString(“method”)
name = Request.QueryString(“name”)
dim a,b
a=Request.TotalBytes
data=Request.BinaryRead(a)
Response.ContentType = “application/pdf”
Response.AddHeader “Content-Length”, data.Length.ToString()
Response.AddHeader “Content-disposition”, method + “; filename=” + name
Response.BinaryWrite(data)
Response.End()
Hi Bill,
I’m not familiar with ASP so I can’t help you with your code much, but since you’re getting a “page not found” error it doesn’t sound like a problem with your code at all. Have you tried hitting the file URI directly?
Make sure that you are passing a valid “method” type, and you should probably validate the content of the Request to make sure your binary data is being passed properly.
Alternatively, if your internal users have Flash Player 10 installed, you can save the PDF directly from Flash and skip the server. I will explain how to do that in my next article in this series but you can find more information here in the meantime:
http://blog.everythingflex.com/2008/10/01/filereferencesave-in-flash-player-10/
Very interesting article.
Looking forward to the actual printing blogpost.
Thank you!
Arend
where did you get the pdfCreator.cfm file?
Where did I find the pdfCreator.cfm file?
I didn’t, I wrote it myself.
Where can you find the pdfCreator.cfm file?
It’s shown in its entirety in the example, but if you just want a simple download you can find it here:
http://www.kalengibbons.com/assets/files/pdfCreator.zip
Next time I’ll have to include it in my source view
HI, very nice project..!!, but I couldn’t get it work becouse 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..
Hi Victor,
I believe your question is in regards to the next article in this series “Print Data”: http://www.kalengibbons.com/blog/index.php/2009/04/custom-printing-with-flex-part-3-printing-data/
As such, I have moved your comment to that post.
First, does anyone know why the alivepdf.bytearray.org links are all broken? I am trying to look at examples without little success.
Next, I am trying to figure out multiple page generation. When I put everything in a single page , everything afte the first page is correupted, with eac line on its own page. Any suggestions will be much appreciated.
The API docs are “barebones” and not much help for beginners.
TIA!
Bill, here is an ASP.net script that works in vb. There is also a c# version included with the latest version of AlivePDF.
Dim method As String = Request.QueryString(“method”)
Dim name As String = Request.QueryString(“name”)
Dim bdata = Request.BinaryRead(Request.TotalBytes)
Response.ContentType = “application/pdf”
Response.AddHeader(“Content-Length”, bdata.Length.ToString())
Response.AddHeader(“Content-disposition”, method + “; filename=” + name)
Response.BinaryWrite(bdata)
Response.End()
Hey Bill, here is my .asp script. It works great. I did not use name because it is used for other things in .asp, so I used docname
dim data
data = Request.BinaryRead(Request.TotalBytes)
dim docname
docname = Request.QueryString(“name”)
dim method
method = Request.QueryString(“method”)
Response.AddHeader “Content-Type”, “application/pdf”
Response.AddHeader “Content-Disposition”, + method + “;filename=” + docname
Response.BinaryWrite(data)
Response.End()
Hi, could you mind let me know how to display the chinese word/UTF8 in alivepdf ? Thank you very much!
Hi mate, very goog project
where can i download pdfCreator.pdf file from?
cheers
Brad
had a shocker with my last msg, found it 2 secs after writing msg
A PHP script is provided with the download of the AlivePDF library – Duh!\\
is there a way to save a copy of the .pdf on the server with a unique filename?
How do we print a grid with multiple pages with the addImage API? If I use mx:PrintGrid, the Image comes up as empty for the Grid.
Thanks
-Kumar.
Hi
I was pleasured with AlivePDF.. It works Fine for me if i follow the way as in sample.That is the dataprovider of datagrid has xml file separetely the problem occurs if i had a XML variable and bind that to datagrid it doesn’t print in Correct format.It just Prints the same XMLData in a single Column with all the xml tags. Could you please tell me about this issue as soon as possible..
Karthik,
How are you printing your DataGrid, are you using AlivePDF’s Grid class? If so, it requires an Array as its dataprovider and you need to make sure that your XML is getting properly converted. Since you are getting only a single column it sounds like it’s not. Let me know if you need help getting the conversion to work.
I’ve worked with mx:PrintGrid in the past and have always been disappointed. I would recommend ditching the PrintGrid and let your server do the printing, as described in the next post in this serious: http://www.kalengibbons.com/blog/index.php/2009/04/custom-printing-with-flex-part-3-printing-data/.
Hi Kalen
Thanks for the help..After converting to array it worked properly.I have another problem in changing only header text to bold.Second thing I tried with cfm file in my server but it doesn’t return anything.i dont have any idea about coldfusion can u please tell me how to do that..?
Thanks
karthik
Hi Kalen
I have tried with your Custom Printing with Flex, Part 3: Printing Data but it gives me error Not able to connect to the server.
could you please help me..
Thanks
Karthink
Hi Karthik,
You said earlier that you were new to ColdFusion. Well… first you need to make sure that you have ColdFusion installed on your server. Make sure that you can run .cfm pages.
You don’t have to use ColdFusion however, if you’re familiar with another server language. I simply used ColdFusion because it’s my preference; pretty much all server languages can do the same thing.
If you want to stick with ColdFusion, you can sent me the .cfm file that you are using as well as the URL to the file on your server and I will see if I can diagnose the problem. kalen[dot]gibbons[at]gmail[dot]com
Hi,
I have tried the above method to convert a page to pdf, but its simply showing the contents of the pdfCreator.swf file, I tried to integrate in flash developer 3, please help me out regarding this problem….
Hi Bharath,
Can you provide more info? What is pdfCreator.swf and what do you mean by flash developer 3? If you’d like to send me your source code I can take a look at it for you: kalen[dot]gibbons[at]gmail[dot]com
Hi Kalen
Thanks. Will u please tell me what process has done in that .cfm file so that i can try in java as server side and let u know..
Thanks
Karthink
Well, the ColdFusion that actually does the work is only three lines long. First I pull the data out of the HTTP POST that contains the ByteArray comprising the PDF content.
<cfset httpContent = GetHttpRequestData()>
Then I tell ColdFusion to display that data as a PDF by setting some values in the header and calling ColdFusion’s cfContent tag.
<cfheader name="Content-Disposition" value="#URL.method#; filename=#URL.name#" />
<cfcontent type="application/pdf" variable="#httpContent.content#">
I found this tutorial, I think it should help:
http://alivepdf.bytearray.org/?p=8
hi kalen Thanks for the great help.will try with that …
Greetings! I am trying to use Alive Pdf the same way as presented here. It was working wonderfully fine. Thanks a lot. But as represented here, I am getting only the data I am seeing is exported as PDF. If I need the entire Data Grid to be exported to PDF, Could you please suggest me how I should go about? I was really happy that this code helped me in capturing the screen as-is as my report is highly interactive . But I need to capture the entire DataGrid ( The items hidden by scrolling as well. ) . Could you please suggest me how to go about?
Thanks and Regards,
Harini.P..
Hi Harini,
The next article in this series cover that exact topic.
http://www.kalengibbons.com/blog/index.php/2009/04/custom-printing-with-flex-part-3-printing-data/
I hope it helps.
The site for AlivePDF seems to be down. Have you had any communication with the developers?
@Nicolas, I’m sorry I haven’t. It looks like the server is down! I would guess it’ll be back up in a day or two.
Hi Kalen!
I am currently developing an application where several pdf’s should be generated dynamically and i want to give the user the option to select one of these pdf’s to print it seperate from the others due to the fact that the pdf’s should be printed on labels that could differ from PDF to PDF. In the first step i tried to use alivePDF for creating the PDF’s and saving them using filereference.save() locally to be independend from the server side (using flashplayer10). But i think it is not possible to prevent the dialogbox from being displayed for determining the location where the files should be stored. Do you have any idea how to implement this scenario?
Thanks in advance!
Nils
Hi Nils,
I’m not quite sure what you are trying to do. Are you trying to create a preview of the PDFs inside the Flash player? You could just combine multiple PDFs into a single PDF and the users could simply print the page(s) they want. You might also want to look into something like the ImageSnapshot class, that will allow you to create preview images before you convert them into PDF.
Thanks Kalen!
The hint to the ImageSnapshot class is a good one i suppose. Will focus my research on that in the first place.
Nils
Hi Kalen,
I am trying to generate pdf on a button click in flex using java. I copied code from one of your post but still I am not able to generate the pdf.
Here is the code I am using on flex side:
function generatePDF ( e:MouseEvent ){
// we create the PDF
myPDF = new PDF( Orientation.LANDSCAPE, Unit.MM, Size.LETTER );
// we set the zoom to 100%
myPDF.setDisplayMode ( Display.FULL_WIDTH );
// we add a page
myPDF.addPage();
myPDF.addText(“Kanna”, x=1, y=10);
// to save the PDF your specificy the path to the create.php script
// alivepdf takes care of the rest, if you are using AIR and want to save the PDF locally just use Method.LOCAL
// and save the returned bytes on the disk through the FileStream class
myPDF.save( Method.REMOTE, “http://localhost:8080/Demo/ViewQuotePDFServlet1″, Download.INLINE, “myPDF.pdf” );
Here is the code I am using on java side:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
int i = 0;
int k = 0;
int maxLength = request.getContentLength();
byte[] bytes = new byte[maxLength];
String method = request.getParameter(“method”);
String name = request.getParameter(“name”);
ServletInputStream si = request.getInputStream();
while (true)
{
k = si.read(bytes,i,maxLength);
i += k;
if (k <= 0)
break;
}
if (bytes != null)
{
ServletOutputStream stream = response.getOutputStream();
response.setContentType("application/pdf");
response.setContentLength(bytes.length);
response.setHeader("Content-Disposition",method + ";filename=" + name);
stream.write(bytes);
stream.flush();
stream.close();
}
else
{
response.setContentType("text");
response.getWriter().write("bytes is null");
}
}
}
I dont know where I am going wrong but can you please help me…
Thank you so much…
Aparna.
Hi Aparna,
Well first we need to figure out if the problem is Flex based or Java based. Are you getting an error message or is the request just failing? One test you can run is to switch the URL in the save() method in your Flex code from
“http://localhost:8080/Demo/ViewQuotePDFServlet1″
to
“http://kalengibbons.com/assets/pages/pdfCreator.cfm?name=alivePDFExample.pdf&method=inline”.
Pointing to my server will help you determine if your PDF is being generated properly in your ActionScript code. If it works for that URL then you know you have a problem with your Java code and I can’t help you much there.
Thanks,
Kalen
[...] ColdFusion script sample here… [...]
I have done above procedure. Instead of image, i have included addtext(“Hello”,5,5) No error is there but nothing is displayed in browser. pls help.Thanks in Advance.
Hi Shankar,
Post your code if you’d like some help, otherwise it’s hard to determine what the problem is.
Hi Kalen,
Got the output.
Hi,
In this code, instead of your server script (http://kalengibbons.com/assets/pages/) what i need to mention. I have no idea help me.Thanks in Advance.
Hi,
In this code, instead of your server script (http://kalengibbons.com/assets/pages/) what i need to mention. I have no idea help me.Thanks in Advance.
Shankar,
I’m afraid I don’t understand. Please supply more information, including the context and any source code you can provide.
In this code instead of server script what i need to mention. Because in the server script your site name is there.
Shankar,
You would need to create your own ColdFusion or PHP script to handle the upload on your own server; please do not use mine. I believe AlivePDF comes with several common server-side scripts that you can use, depending on what your web server supports.
K fine.
Hi,
first I gotta say, awesome Tutorial. Thanks for that!
I’m printing a panel and it works pretty well. There is just one little issue.
I have a header image in that panel which I’m removing before printing. After that I’m reducing the Panel size.
It kind of works, but the very bottom of the panel gets cropped in the PDF-File. So the bottom border of the panel doesn’t make it into the PDF. If I don’t reduce the size of the Panel it’s working fine.
Here is my code that is getting invoked by clicking on the print button:
private function printPDF ( ) : void
{
this.headerImage.visible = false;
for ( var i : int = 0; i < this.numChildren; i++ )
{
this.getChildAt( i ).y -= 160;
}
this.printButton.visible = false;
// Here I want to reduce the panel size
this.height -= 160;
pdf = new PDF ( Orientation.PORTRAIT, Unit.POINT, Size.A4 );
pdf.setDisplayMode( Display.FULL_PAGE, Layout.SINGLE_PAGE );
pdf.addPage();
pdf.addImage( this, new Resize ( Mode.FIT_TO_PAGE, Position.CENTERED ),0, 0, 0, 0, 0, 1);
pdf.save( Method.REMOTE, "http://kalengibbons.com/assets/pages/pdfCreator.cfm?name=alivePDFExample.pdf&method=inline", Download.INLINE, "test.pdf" );
}
So why is the panel getting cropped ?
I can upload a picture if u want me to.
Any help is highly appreciated!!
Thanks,
Dan
Hi again,
does your pdfCreator.cfm script do something special? I uploaded it on my server and the only thing happening, is that the coldfusion code is shown in the browser.
I’m sure I have to add Code to it or so… Could you please give me an advice?
Thanks a lot.
Dan
Hi Dan,
If the ColdFusion code displayed in the browser I would assume that you’re not running a ColdFusion server. Your web server needs to support ColdFusion for it to run.
dear all,
i will be very thankfull to you, if any body can tell me how to use alivePDF with flash , starting from which release i should download from http://www.alivepdf.org and how to setup this with flash, please it very urgent if somebody can do it i will pay for it as a gift.
Your solution si great. However, when it comes to releasing an AIR standalone application, you must do all the job clientside. So, a solution that does’t include server scripts would be wonderful.
Check out the section “Save locally from Flash” in the next article in this series. It briefly demonstrates how to save your PDF locally without any server interaction.
http://www.kalengibbons.com/blog/index.php/tag/custom-printing-with-flex/
i have a question…somebody could try this code but in asp ?? … i need it but in asp, if aby can help me please…
thanks in advance…
Hi all,
Just got started with AlivePDF and I got stuck in less than 5 min.! (must be a WW record!)
I’m trying to set custom WIDTH x HEIGHT using Size() class. My code:
[code]
var customsize:Size = new Size([150,87], "custom", [150/25.4,87/25.4], [150,87]); // 150/25.4 = inches
var pdf:PDF = new PDF(Orientation.PORTRAIT,Unit.MM,customsize);
pdf.addPage();
pdf.save(Method.REMOTE,'lib/engine/display_pdf.php',Download.INLINE,_get_hash + '.pdf');
[/code]
I got the PDF on browser but it displays a wrong size (52,9X30,7 mm).
I’m sure I’m screwing something up here but I’m not sure exactly what….
Any help would be appreciated! (admin@beyondmaster.com)
Thanks!
Hi Kalen,
Im using flexbuilder3.I have two vboxes in my application.Im trying to generate pdf from first Vbox which has a grid.It works fine with the visible data.But the problem is, it s not displaying all pages.Plz help me with tis problem.Im attaching my code with this.
import org.alivepdf.images.ResizeMode;
import mx.effects.Resize;
import org.alivepdf.fonts.Style;
import org.alivepdf.colors.RGBColor;
import org.alivepdf.fonts.FontFamily;
import mx.core.IFontContextComponent;
import org.alivepdf.saving.Method;
import org.alivepdf.layout.Layout;
import org.alivepdf.display.Display;
import org.alivepdf.layout.Size;
import org.alivepdf.layout.Unit;
import org.alivepdf.layout.Orientation;
import org.alivepdf.pdf.PDF;
import org.mart3.pdfGeneration.CreatePDF;
public function doGeneratePDF():void
{
var myPDF : PDF = new PDF ( Orientation.PORTRAIT, Unit.MM, Size.A4 );
myPDF.setDisplayMode( Display.FULL_PAGE, Layout.SINGLE_PAGE );
myPDF.addPage();
// add a background image
myPDF.addImage(idScreen1,0,0,0,0,”PNG”,100,1,ResizeMode.RESIZE_PAGE,BlendMode.NORMAL);
//myPDF.addImage (, 1 , null, null, false, ImageFormat.JPG, 100, 0, 0, 0, 0);
var f:FileStream = new FileStream();
var file:File = File.desktopDirectory.resolvePath(“MyPDF.pdf”);
f.open(file, FileMode.WRITE);
var bytes : ByteArray = myPDF.save(Method.LOCAL);
f.writeBytes(bytes);
f.close();
}
Chitra,
AlivePDF basically takes a screenshot of your application and uses that for the PDF. So if you (the user) cannot see part of your application or it’s data, then AlivePDF won’t be able to print it. If you have a large dataset that you’d like to print, I would suggest reading the next article in this series.
http://www.kalengibbons.com/blog/index.php/2009/04/custom-printing-with-flex-part-3-printing-data/
Ok, here is an odd question but does anyone know if it’s possible to print the PDF that is generated with AlivePDF and AS3. I mean instead of writing the PDF to disc and then print it, is it possible to send it directly as a print job?
Anders,
No, as far as I know, there is no way to skip the PDF generation process and push directly to the printer.