2004. augusztus 22., vasárnap

Create PDF files from your QReports with Adobe Acrobat


Problem/Question/Abstract:

How to print programmatically from my Delphi app to my PDFWriter driver, setting the correct filename?

Answer:

Overview

Last week we have seen how to create programmatically a report with a PDF report engine. Now let's try to use the original solution from Adobe for the same purpose and how to leverage the existing reports without having to recode them (the main drawback of a pdf-engine based solution).

If you want to print a report (e.g. QReport) directly to PDF without annoying "Save as..." pop up windows, you've got to face 2 different problems.

First of all, you must set programmatically the printer inside the exe and force the Report Engine to print directly. The difficulty and the technique depends on the report engine you have choosen.

Then, PDFWriter wasn't designed for automation of simple tasks, for use by developers or for unattended operations, like the ones that occur on servers and batch processing systems, so you will have to use some workarounds.

Worst of all, although there are some techniques to print to a specific filename with Acrobat, these techniques change from version to version of Adove Acrobat and even depending on the Operating System you use (pls note that I haven't tested yet the new Acrobat 5.0 version).

Solution

Let's start with the first problem. Every Report Engine has its own rules, however I will use for my example QR, the most commonly used VCL solution.
You can set the printer with the PrinterSettings.PrinterIndex property; if set to -1 QRprints directly tothe default printer. Pls note that you aren't forced to show the form with QR (but, of course, you have to create it, which can be a problema in some kind of applications who don't admit forms)

QRLabelForm.QuickRep1.PrinterSettings.PrinterIndex := -1; // use the default printer
QRLabelForm.QuickRep1.Print; // print

(Please note that depending on the reporting engine and the PDF Driver, a progression windows could appear)

We have solved the first little problem, let's look for the second.
Pay attention: you must act differently whether you use WinNT/2K or Win9x.

If you have Acrobat 3.0x or + on Win9x the solution is to modify from your delphi exe/dll the Win.ini as follows:

[Acrobat PDFWriter]
PDFFileName=C:\WINDOWS\TEMP\TMP.PDF // your favourite path...
bDocInfo=0

To print to a particular filename, you should take care to modify the win.ini file every time, being sure that no one else is using the Printer Driver in the same moment (should it happen, abnormal errors, wrong filnames and other problems will surely arise). Of course, as web applications are multithreaded by nature, you must also prepare a lock/unlock system to avoid concurrent requests in this case. (I think that only a mad would use a printer driver in a web app, but "never say never")

If you have Acrobat 4.0 or + and WinNT/2K things are slightly different.
Though the Adobe documentation affirms that concurrent printing is supported in this combination od Product/OS, my tests have showed that after a 3/4 users a multithreaded server app would crash or behave erratically; I would suggest to use this solution on a Server, but it is almost theoretically possible.

If you your OS is WinNT/2K you have to modify registry settings instead of .ini files.
In brief: you should look for the key "HKEY_CURRENT_USER\Software\Adobe\Acrobat PDFWriter" and adding/modifying a key like this (second parameter is a string value of course):

"PDFFileName", "c:\typethefilenameyoupreferhere.pdf"; pay attention, please: if you don't use the asterisk as last character, the string could be killed in regedit!

Now add a second key pair, which will be "bDocInfo", "0" (again string value)

As I don't think you're going to modify the registry programmatically, I would suggest to make these changes to obtain a default file destination, and after every pdf file creation I would rename the file. (Of course, if you want to feel new sensations and love risk, there are some VCL components which permits you to modify the registry; just don' use this on your web server or your boss' PC!)

Recently heard of the possibility to change via ini file the dest PDFFileName in WinNT, too. It uses the file
"c:\winnt\system32\spool\drivers\w32x86\2\__pdf.ini" and uses the same syntax used for W9x. Haven't tried yet, but looks interesting.

Conclusions

Using the PDFWriter driver gives you the best quality available and leverages your investiments on report engines, but remember that the solution lacks in programmatical control and can be a risk in unattended operations and/or multithreaded/multiuser environments.
Also, keep in mind that the cost of the driver is high; if you want to use a printer driver based soution, yoou should consider to substitute the Adobe one with other ones, like the shareware from Dane Prairie (only Win2K) or Zeon (also Win9x), which are more affordable and have a similar behaviour in front of developer's needs.
Another similar solution could be the use of Ghostscript, but remember that it ***isn't free for commercial use*** (many people infringe the licence thinking of it as a free product).

Reference

From Adobe's KB:
  http://www.adobe.com/support/techdocs/66ca.htm

From West Wind Technologies
  http://www.west-wind.com/presentations/pdfwriter/pdfwriter.htm
  (example with FoxPro and ASP, with semaphore system to avoid concurrency problems)

Nincsenek megjegyzések:

Megjegyzés küldése