Monday, June 18, 2007

Create pdf in .NET using PDFCreator

Long time no post, was busy with office work and most of the time was searching for an open source tool that reliably prints or creates pdf from any document. It should also have ability to merge the documents or pdfs together. Finally, I found great open source tool PDFCreator which lets you create pdf, merge pdf, automatically save them to a directory, set options via code etc etc. In this article we'll see how we can use PDFCreator for printing/creating pdfs. It uses GhostScript for creating PDF which is again distributed free under GPL license.

INSTALLING PDFCREATOR:
1. Download PDFCreator from sourceforge.net (http://sourceforge.net/projects/pdfcreator)
2. If you have already installed GhostScript go for installer which doesn’t have ghost script installer embedded else go for the installer that will install ghost script also.
3. Run the installer and install PDFCreator. You can use any mode while installing (standard or server) but the server mode needs more configuration so better go for standard mode.
4. Give the name of the printer as “PDFCreator”. You can use any name but this is the name that I have used in the code. So if you are using the code as it is then you need to give this name.
5. After installation a new printer will be installed on your machines.
6. You can use this printer from any document. Open the document and say print. Choose the printer created above and ask it to print.

USE PDFCREATOR IN CODE (C#):
In this code I'll be using Word Application to convert a word document to PDF document. Code will be in C# and application will be a console application. In this example we'll also see how to create a single pdf from multiple word documents (or any documents).

1. Create new console application in C#.
2. Add reference to PDFCreator and Word object.
3. Create new instance for PDFCreator and start using the code.
clsPDFCreator creator = new clsPDFCreator();
string parameters = "/NoProcessingAtStartup";
if(!creator.cStart(parameters, false))
{
Console.WriteLine("Unable to start PDFCreator.");
}

4. If printer is started successfully set the options for the printer.
// Set parameters for saving the generating pdf automatically to a directory.
// Use auto save functionality.
opt.UseAutosave = 1;
// Use directory for saving the file.
opt.UseAutosaveDirectory = 1;
// Name of the output directory.
opt.AutosaveDirectory = @"c:\";
// Format in which file is to be saved. 0 if for pdf.
opt.AutosaveFormat = 0;
// Name of the output file name.
opt.AutosaveFilename = [Name of output file];
creator.cOptions = opt;
creator.cClearCache();

5. Create new word application object and save currently active printer. This is done because while creating PDF PDFCreator (or whatever name you have given while installation) should be active. By saving the name of currently active printer we can set that back as active after creating PDF.
// Save currently active printer.
string defaultPrinter = creator.cDefaultPrinter;
// Create new instance of word application.
ApplicationClass wordapp;
wordapp = new ApplicationClass();
Document worddoc = null;
// Set pdf creator as active printer. Name should be same as you gave while installation.
wordapp.ActivePrinter = "PDFCreator";

6. The above steps are common for either creating single pdf from single document or creating single pdf from multiple documents.

CREATE SINGLE PDF FROM SINGLE DOCUMENT
1. Open an existing word document.
Object missingValue = Type.Missing;
Object docName = [Full Path to your document];
worddoc = wordapp.Documents.Open(ref docName, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue, ref missingValue,ref missingValue);

2. Print out the document using ‘Printout’ method. As currently active printer is ‘PDFCreator’, word will use that printer for printing the document.
Object false_object = false;
Object missingValue = Type.Missing;
Object background = true;
Object append = true;
Object range = Microsoft.Office.Interop.Word.WdPrintOutRange.wdPrintAllDocument;
Object outputFileName = Type.Missing;
Object from = Type.Missing;
Object to = Type.Missing;
Object item = Microsoft.Office.Interop.Word.WdPrintOutItem.wdPrintDocumentContent;
Object copies = 1;
Object pages = Type.Missing;
Object pageType = Microsoft.Office.Interop.Word.WdPrintOutPages.wdPrintAllPages;
Object printToFile = false;
Object collate = Type.Missing;
Object fileName = Type.Missing;
Object activePrinterMacGX = Type.Missing;
Object manualDuplexPrint = Type.Missing;
Object printZoomColumn = Type.Missing;
Object printZoomRow = Type.Missing;
Object printZoomPaperWidth = Type.Missing;
Object printZoomPaperHeight = Type.Missing;
wordapp.PrintOut(ref background, ref append, ref range, ref outputFileName, ref from, ref to, ref item, ref copies, ref pages, ref pageType, ref printToFile, ref collate, ref fileName, ref activePrinterMacGX, ref manualDuplexPrint, ref printZoomColumn, ref printZoomRow, ref printZoomPaperWidth, ref printZoomPaperHeight);


3. Wait for the job to get queue up in the PDFCreator. And start the printer (PDFCreator) and then wait for the job to get finished.
// Wait till doc gets queued up.
while(creator.cCountOfPrintjobs != 1);

// Start the printer.
creator.cPrinterStop = false;

// Wait till all doc get converted to pdf.
while(creator.cCountOfPrintjobs != 0);


CREATE SINGLE PDF FROM MULTIPLE DOCUMENTS
1. Follow step 1 as described in section Creating single PDF from single document.
2. In step 2 instead of printing single document you can go from printing any number of documents. (Make sure you remember the count).
3. Now instead of waiting for one document. Wait for all the documents to get queued up and then use “combineAll()’ method of PDFCreator object to combine all the documents into single PDF.
// Wait till doc gets queued up.
while(creator.cCountOfPrintjobs != [Your COUNT of documents printed]);

// Tell PDFCreator to combine all the documents.
creator.cCombineAll();

// Start the printer.
creator.cPrinterStop = false;

// Wait till all doc get converted to pdf.
while(creator.cCountOfPrintjobs != 0);


CLOSING PRINTER AND WORD APPLICATION
// Close all the opened documents.
foreach(Document doc in wordapp.Documents)
{
doc.Close(ref false_object, ref missingValue, ref missingValue);
}

// Stop the printer.
creator.cPrinterStop = true;

// Set back the default printer.
wordapp.ActivePrinter = defaultPrinter;
wordapp.Quit(ref false_object, ref missingValue, ref missingValue);

// Close the printer
creator.cClose();
creator = null;


POINTS OF INTEREST / GOTCHA
If you PDF printer settings is not according to the following diagram then the order in which the documents will get printed is not defined. This will be a problem in case of printing multiple documents to a single PDF where order is important.