Click here to Skip to main content
Email Password   helpLost your password?

Background

In my workplace, it is common for people to want documents in PDF format. The problem I was running into was that programming a PDF is no simple task. That, and I already had the documents in another format (Excel). Knowing that there were PDF print drivers, I decided to figure out how they worked. I noticed that almost all of them used Ghostscript, a program to convert PostScript to PDF format. The only problem with these print drivers was that it required user interaction. I couldn't allow this as I have to bulk print about 100 reports a month and having an end user specify where to save a file would just be too cumbersome... and I didn't like the nagging shareware graphics.

After eventually putting two and two together, I discovered that .NET could call GhostScript with the appropriate commands to generate a PDF. But my problem still lay in the fact that I didn't want to create my own printer driver. Enter virtual printers and file ports. In order for this code to work, you must create a virtual printer.

First you will want to download Ghostscript and install it.

Continue by adding a local printer and uncheck "Automatically detect and install my Plug and Play printer".

Create a new local port and enter "C:\output.ps" for the port name.

In order for GhostScript to correctly parse the PostScript, it must be set as the printer driver. You can find the printer driver for GhostScript in the GhostScript installation directory in the lib folder.

For the attached code to work, name the printer Ghostscript.

Using the Code

The attached application puts all the puzzles in place. First the application stores the current default printer. This will be used later to set the printer back.

public static string GetDefaultPrinterName(){
    PrintDocument pd = new PrintDocument();
    return pd.PrinterSettings.PrinterName;
}

Second, the Ghostscript printer that we set up earlier is set as the default so the user doesn't have to select a printer.

public static long SetDefaultPrinterName(string name){
    return SetDefaultPrinter(name);
}

Third, we call the print command on a file. The trick here for me was detecting when an Excel file was printed. I work primarily with Excel documents and needed a quick way to print out the entire workbook and not just the opened worksheet.

public static void CreatePdf(string action, string file, string directory){
    if (file.EndsWith("xls")){
        Excel.ApplicationClass excel = new Excel.ApplicationClass();
        excel.Visible = false;

        Excel.Workbook workbook = excel.Workbooks.Open(Path.Combine(directory, file),
			Type.Missing, Type.Missing, Type.Missing, Type.Missing,
            Type.Missing, Type.Missing, Type.Missing, Type.Missing,
            Type.Missing, Type.Missing, Type.Missing, Type.Missing,
            Type.Missing, Type.Missing);

        workbook.PrintOut(Type.Missing, Type.Missing, 1, false, Type.Missing, 
			false, Type.Missing, Type.Missing);

        excel.Quit();
    }else{
        Process p = new Process();
                
        p.StartInfo.FileName = file;
        p.StartInfo.Verb = action;
        p.StartInfo.WorkingDirectory = directory;
        p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
        p.StartInfo.CreateNoWindow = true;
        Console.WriteLine("Starting process");
        p.Start();
        //p.Kill();
    }
    Console.WriteLine("Creating Pdf");
    CreatePdf(file);
}

Finally, we call the GhostScript executable, giving it the filename we want it outputted to and where to find the PostScript. In order to pass the executable a statement, we just redirect the input to a command we create and we also grab the output.

private static string CreatePdf(string fileName){
    string command = "gswin32c -q -dNOPAUSE -sDEVICE=pdfwrite -sOutputFile=\"" + 
			fileName + ".pdf\"  -fc:\\output.ps";

    Console.WriteLine(command);
    Process p = new Process();

    StreamWriter sw;
    StreamReader sr;
            
    ProcessStartInfo info = new ProcessStartInfo("cmd");
    info.WorkingDirectory = System.AppDomain.CurrentDomain.BaseDirectory;
    Console.WriteLine("Current directory: " + info.WorkingDirectory);
    info.CreateNoWindow = true;
    info.UseShellExecute = false;
            
    info.RedirectStandardInput = true;
    info.RedirectStandardOutput = true;
            
    p.StartInfo = info;
    p.Start();
            
    sw = p.StandardInput;
    sr = p.StandardOutput;
    sw.AutoFlush = true;
            
    sw.WriteLine(command);
            
    sw.Close();
            
    string ret = sr.ReadToEnd();

    Console.WriteLine(ret);
    return ret;
}

After GhostScript runs, we just set the printer back to the previous default and the user is none the wiser.

try{
    Printers.SetDefaultPrinterName(currentPrinterName);
}catch{}

This application can be used for quick PDF creation, but mostly it is for developers looking for an example of quickly creating PDFs without the hassle of programming in the PDF SDK. When running this application, place the gswin32c executable in the same directory. For further information on optimizing PDFs and doing all sorts of other crazy things, look into the GhostScript documentation and change the parameters specified. Have fun!

Points of Interest

The neat thing about this application is that it requires no extra work for the developer to format the document into a PDF. The way the document appears on the screen in its native application is how it is printed to PDF.

Things to Remember

Make sure to set up a virtual printer. If you modify where the file port goes, make sure to update the code.

Make sure to place the gswin32c in the same directory as the executing application.

It also looks like GhostScript needs to be installed on the machine. Find the 8.54 version here.

History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
Questiongenerates Output.ps file
Lekha_J
10:25 27 Mar '09  
Hello j, Thanks for this post. There are very few examples of this in the internet. I followed example. I am working in Vista and used Ghostscript 8.54. I believe I should get a pdf but instead the output is Output.ps file, a PostScript file. I don't know what I am missing here. Please let me know.
Thanks, Lekha
GeneralXLVIEW executes but no PS File generated
Member 3045884
14:38 12 Mar '09  
Would you have ny idea why XLVIEW.EXE runs (I see it in Task Manager on the server) but does not create a PS file and if I let the CreatPDF code run, I get an empty PDF page. If I run a .TXT file through both processes in your code I get both a PS and PDF file. I'm running WIN Server 2003, Excel Viewer 2007 (I tried 2003 also), ASP.Net 2.0, C#, Ghostscript 8.54. Your insight would be appreciated.
GeneralRe: XLVIEW executes but no PS File generated
jkandiko
4:29 13 Mar '09  
I've never used the XLView tool before, so I'm not sure if the events fire the same or if the coding is the same. Sorry, not much help here.
GeneralThanks
thohoff
3:36 4 Feb '09  
Thanks for your solution Wink I will have to solve some minor problems for my application, but looking for such a solution I have already gone through different pdf-libraries not solving the problem, and not in this simple and acceptable and cheap way for creating PDF's of any document.
Here in code project is a solution with FreePDF, but I had problems with limited rights on my domain account.
GeneralHow to pass the arguments to the console application
geetha naidu
19:27 9 Jul '08  
How to pass the arguments to the console application
GeneralURgent: Pdf generation
geetha naidu
20:20 8 Jul '08  
Hi in the string Commandline i am not able to generate a pdf file. Jow do i go about doing this. Please explain me about the command line
Questionwhat kind of manufacturer and printer I must chose in step "Install Printer Software" of "Add Printer Wizad"?
taihip
18:16 22 Nov '07  
Hi,
I can't test "DragNDropPDF" because:
what kind of manufacturer and printer I must chose in step "Install Printer Software" of "Add Printer Wizard"?
what is "output.ps" file? where can I get it?

thank.

hello
AnswerRe: what kind of manufacturer and printer I must chose in step "Install Printer Software" of "Add Printer Wizad"?
jkandiko
4:52 27 Nov '07  
You need to use the printer driver supplied by GhostScript. Output.ps is the local port I set the created printer to print to.

Thanks
Josh
QuestionRe: what kind of manufacturer and printer I must chose in step "Install Printer Software" of "Add Printer Wizad"?
taihip
15:24 27 Nov '07  
thank Josh,
sorry, my English's too bab.
I still have a question:

How do I know what printer driver is supplied by GhostScript. in "C:\Program Files\gs\gs8.54\lib", I can't find anythink about "the printer driver supplied by GhostScript" (that folder have too many files).

Regards,
Tai
AnswerRe: what kind of manufacturer and printer I must chose in step "Install Printer Software" of "Add Printer Wizad"?
jkandiko
4:32 28 Nov '07  
The file ghostpdf.inf under the bin directory is the printer driver.

Thanks
Josh
GeneralRe: what kind of manufacturer and printer I must chose in step "Install Printer Software" of "Add Printer Wizad"?
taihip
15:27 28 Nov '07  
hello Josh,

I found out file ghostpdf.inf under "gs\gs8.54\lib" (ghostscript version 8.54)

Thanks a lot Josh,
Tai
Questionproblem with the executions the aplication
radkeck2
12:35 4 Sep '07  
Hello I need a bit from help, with his(her,your) application I have a problem on having ordered a file to stamp(print) the application is not executed I have followed(continued) his(her,your) steps and there does not work, that version of ghostscript have to use??

hooooooooolllllllllla

AnswerRe: problem with the executions the aplication
jkandiko
12:37 4 Sep '07  
I think if I am understanding what you are saying, I am using 8.54 of ghostscript.
GeneralRe: problem with the executions the aplication
radkeck2
12:44 4 Sep '07  
My problem is:
To join the (printing) to the application, how I do it??

thank's for all

hooooooooolllllllllla

GeneralRe: problem with the executions the aplication
radkeck2
12:45 4 Sep '07  
is a library problem??

hooooooooolllllllllla

GeneralRe: problem with the executions the aplication
jkandiko
12:47 4 Sep '07  
There are two concepts to understand. You print from your application using the ghostscript printer you set up. Then you feed the ghostscript application the .ps file that was created during the printing. Ghostscript will convert the .ps file to a pdf.
GeneralRe: problem with the executions the aplication
radkeck2
12:55 4 Sep '07  
When you stamp(print) with the printer ghostscript, his(her,your) program executes.
It the one that does not happen with my application.

Do I need help please, is a driver problem??

hooooooooolllllllllla

GeneralRe: problem with the executions the aplication
radkeck2
22:11 4 Sep '07  
hello, firstly thank's for all, i have a question --> it's the
following, Should I install ghostscript in the same directory of my application, so that when I prints with GS printer
my application is executed and captured path of the file to print?


thank´s for all, PACO

hooooooooolllllllllla

GeneralRe: problem with the executions the aplication
jkandiko
4:48 5 Sep '07  
The Ghostscript executable needs to be in the same directory as your executable. Otherwise, code would need to be added to point to the GS executable.
GeneralHi, Urgent. I want to save excel sheets as PDF Files
pravin parmar
8:54 1 Sep '07  
Hi, I am very badly need this requirement. I want to save the excel sheets as PDF File.

For exa, I have Book1.xls, which have Sheet1, Sheet2 inside it. Then i want Sheet1.PDF and Sheet2.PDF saved as separate PDF Files. Is this possible? How many modifications it requires? Please reply. Thanks in Advance.

Pravin Parmar,
PravinParmar.ce@gmail.com

GeneralRe: Hi, Urgent. I want to save excel sheets as PDF Files
jkandiko
4:36 4 Sep '07  
The modifications you would need to make would be to use the Excel application model to iterate the worksheets, sending a print command for each worksheet. You would then need to subscribe to a finished printing event, or watch the locks on the output.ps file to make sure that you are allowing the printer to create the postscript. Other than those two things, it should be the same process, take output.ps and feed to the ghostscript command line.
GeneralWord Document Extension
skeynan
8:19 24 Mar '07  
SmileHi I tried to add section to print word document without major success Can you help?
if (file.EndsWith("doc"))
{
Microsoft.Office.Interop.Word.ApplicationClass WordApp;
WordApp = new Microsoft.Office.Interop.Word.ApplicationClass();
WordApp.Visible = false;
object fileName = Path.Combine(directory, file);
object missingValue = System.Reflection.Missing.Value;
object isVisible = false;
object isFalse = false;
object isTrue = true;

Microsoft.Office.Interop.Word.Document worddoc =
WordApp.Documents.Open(ref fileName, ref missingValue,
ref isTrue, ref isFalse, ref missingValue,
ref missingValue, ref missingValue, ref missingValue,
ref missingValue, ref missingValue, ref missingValue,
ref isVisible, ref missingValue, ref missingValue,
ref missingValue, ref missingValue);




Object background = missingValue;
Object append = missingValue;
Object range = missingValue;
Object outputFileName = missingValue;//
Object from = missingValue;
Object to = missingValue;
Object item = missingValue;
Object copies = missingValue;
Object pages = missingValue;
Object pageType = missingValue;
Object printToFile = missingValue;//true;//
Object collate = missingValue;
Object NewfileName = missingValue;
Object activePrinterMacGX = missingValue;
Object manualDuplexPrint = missingValue;
Object printZoomColumn = missingValue;
Object printZoomRow = missingValue;
Object printZoomPaperWidth = missingValue;
Object printZoomPaperHeight = missingValue;

try
{

worddoc.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 activePrinterMacGX,
ref manualDuplexPrint, ref printZoomColumn, ref printZoomRow,
ref printZoomPaperWidth, ref printZoomPaperHeight);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message + ex.StackTrace);
}

finally
{
try
{

WordApp.Quit(ref isFalse, ref missingValue, ref missingValue);
}
catch { }


}

GeneralRe: Word Document Extension
jkandiko
5:30 26 Mar '07  
I wouldn't even bother with the Office extensions. The only reason I used the Office library was to print out all worksheets in an Excel file. The default print settings only print the first worksheet. The verb that you send to the Process start command prints Word documents fine. I believe the code that is up there now allows you to drag a document over the executable icon and if Word is installed on your computer and it is set up as the default program to use when opening a .doc file, it should print fine.
GeneralHow can we give file to be converted
akjal
19:20 5 Mar '07  
Hi,
When I run this application, it just shows a command prompt telling 'press any key to continue...' . When hitting any key, application stops. How can I give an input to this application? Please help....I am using 2005 edition of Visual studio. When building a warning is shown as "COM reference Office confilcts with Microsoft.Office.Core....Ignoring Office refernce".

Can you suggest a solution...

Thanks in advance...

GeneralRe: How can we give file to be converted
jkandiko
4:37 6 Mar '07  
The code supplied is looking for a string argument containing the location of a file. I typically build this application and then drag a file over the application's executable in the debug directory. This converter starts up, sends a print verb to the file and outputs a PDF in the same directory as the executable. You could modify the code to directly look for a file. That modification would take place in the Class1.cs file.


Last Updated 9 Feb 2007 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010