I maintain a library of learning modules which are constantly under development and revision. Our users often want PDFs to print out or view off-line, but we can’t maintain up-to-date PDF’s of each module manually. We needed a way to make on-demand PDFs of whatever the current state of the module is when the pdf is requested.

After looking at many pdf solutions I settled on “ABCpdf ASP 6.0” by WebSuperGoo.com.

ABCpdf has the advantages of fairly low cost (about $400.00 for one server, or FREE if you link back to them), a better HTML-rendering engine than most, and an easy to learn API, so you can write custom dynamic PDF applications.

To dynamically generate our frameset-based modules, I needed a way to send the current page-list to the ASP script that would do the interfacing with ABCpdf.

A typical module is shown below.

In the toolbar at the top of each module, there is a PDF button.


Clicking the button submits a form with fields containing a list of all the pages in the module, and the path to the module. ABCpdf uses this information to generate an image for every page. It does a very good job of rendering the HTML, complete with all the styles.

The HTML for the form containing the PDF button is shown below. The form field containing the list of pages is populated by a javascript that runs when the page loads so that it always contains the most current list, since the list can change while the module is being read depending on user interactions.

<form id="pdfForm" action="http://myserver.com/abcpdf.asp" method="post" target="_blank" name="pdfForm">
<a id="headerPDF" title="Create a printable PDF of this entire module. (takes time, please wait)" onclick="document.pdfForm.submit();" href="#">
<img id="pdfBtn" width="46" height="44" border="0" onmouseover="MM_swapImage('pdfBtn','','images/header/over/pdf_btn.jpg',1)" onmouseout="MM_swapImgRestore()" name="pdfBtn" alt="Download a Printable PDF of this module" src="http://thedesignspace.net/master/template/images/header/up/pdf_btn.jpg"/>
<input type="hidden" value="http://myserver.com/learningmodule/page01.htm" name="uPath"/>
<input type="hidden" value="page01.htm;page02.htm;page03.htm;page04.htm;page05.htm;page06.htm;page07.htm;page08.htm;page09.htm;page10.htm;page11.htm;page12.htm;page13.htm;page14.htm;page15.htm;page16.htm;page17.htm;page18.htm;page19.htm;page20.htm;page21.htm;scorePage.htm;" name="uUrl"/>

The code for the receiving page “abcpdf.asp” is shown below.

<% @Language="VBScript" %> <% Option Explicit Server.ScriptTimeout =500 %> <html> <body>

<% 'function to randomize a number Function RandomNumber(intHighestNumber) Randomize RandomNumber = Int(Rnd * intHighestNumber) + 1 End Function

Dim theDoc, i, theID, theData Dim theURLs() Dim inti Dim x, w, h, l, b Dim strPath Dim strValue dim intFind dim id Set theDoc = Server.CreateObject("ABCpdf6.Doc") theDoc.HtmlOptions.BrowserWidth = 1300 ' apply a rotation transform w = theDoc.MediaBox.Width h = theDoc.MediaBox.Height l = theDoc.MediaBox.Left b = theDoc.MediaBox.Bottom theDoc.Transform.Rotate 90, l, b theDoc.Transform.Translate w, 0

' rotate our rectangle theDoc.Rect.Width = h theDoc.Rect.Height = w

inti=0 i=1 'loop thru' the form elements and assign the url to the array elements and increment array each time for each x in request.form 'look for the field with the url in it concatenated if left(x, 4) = "uUrl" then strValue=request.form(x) intfind = instr(strValue,";") 'each url is separated by a ; look for that while intfind>0 'parse each item in the url redim preserve theURLs(i+1)'save the array theURLs(i) = strPath & left(strValue,intfind-1) & "?lll=" & RandomNumber(10) strValue=right(strValue,len(strValue)-intfind) 'new string is old string cut off intfind = instr(strValue,";") i=i+1 'increment array index wend elseif x="uPath" then strPath=request.form(x) intFind = instrrev(strPath,"/") 'look backwords..from end of string strPath=left(strpath,intFind) end if next


For i = (LBound(theURLs)+1) To (UBound(theURLs)-1) theDoc.Page = theDoc.AddPage() id = theDoc.AddImageUrl(theURLs(i)) Do While theDoc.Chainable(id) theDoc.Page = theDoc.AddPage() id = theDoc.AddImageToChain(id) Loop Next theID = theDoc.GetInfo(theDoc.Root, "Pages") theDoc.SetInfo theID, "/Rotate", "90"

For i = 1 To theDoc.PageCount theDoc.PageNumber = i theDoc.Flatten Next

theData = theDoc.GetData() Response.Clear Response.ContentType = "application/pdf" Response.AddHeader "content-length", UBound(theData) - LBound(theData) + 1 Response.AddHeader "content-disposition", "attachment; filename=MLearning.PDF" Response.BinaryWrite theData theDoc.Clear %>

</body> </html>

The resulting PDF of the module looks like this.

We chose to have ABCpdf render the HTML pages into landscape orientation (11″ wide), since webpages can be a little wider than 8-1/2 x 11, and we got better results from this size.