13

I'd like to print PDF file(s) on windows' network printer via GhostScript.
(I dont want to use Adobe Reader)

I've read gswin32c.exe which can do the job.
I experimented with many commands and coudn't find the way how to force gs to print PDF on my (windows default) network drive.

I don't need point exact network printer- default can be used. But if there is no such option I'm happy to pass printer name as well. (I've tried with param -SDevice="\server_IP\printer_name" but this didnt work as well...)

Command working under Windows cmd:

gswin32c -dPrinted -dBATCH -dNOPAUSE -dNOSAFER -q -dNumCopies=1 -sDEVICE=ljet4 -sOutputFile="\\spool\\\Server_Name\Printer_name" "C:\test.pdf"

Method created base on above - doesnt work and thorws exception. (Error code = 1)

    /// <summary>
    /// Prints the PDF.
    /// </summary>
    /// <param name="ghostScriptPath">The ghost script path. Eg "C:\Program Files\gs\gs8.71\bin\gswin32c.exe"</param>
    /// <param name="numberOfCopies">The number of copies.</param>
    /// <param name="printerName">Name of the printer. Eg \\server_name\printer_name</param>
    /// <param name="pdfFileName">Name of the PDF file.</param>
    /// <returns></returns>
    public bool PrintPDF (string ghostScriptPath, int numberOfCopies, string printerName, string pdfFileName) {
        ProcessStartInfo startInfo  = new ProcessStartInfo();
        startInfo.Arguments         = " -dPrinted -dBATCH -dNOPAUSE -dNOSAFER -q -dNumCopies=" + Convert.ToString(numberOfCopies) + " -sDEVICE=ljet4 -sOutputFile=\"\\\\spool\\" + printerName + "\" \"" + pdfFileName + "\"";
        startInfo.FileName          = ghostScriptPath; 
        startInfo.UseShellExecute   = false;

        Process process = Process.Start(startInfo);

        return process.ExitCode == 0;
    }

Any idea how to make it working under C#?

Maciej
  • 10,423
  • 17
  • 64
  • 97
  • 1
    Sorry but just because you are planning to call this from your C# app doesn't make it a programming problem, I'd suggest SuperUser for this Ghostscript question and have voted for this question to be moved there for you. – Lazarus Apr 08 '10 at 12:55
  • I've edited post to be more C# specific now – Maciej Apr 08 '10 at 13:17
  • @Lazarus, again, you are misinterpreting programming, basing on the format of a command. Calling a function is the basic programming concept. The syntax and way do not matter at all as they are related to implementation. This concept is based on a module, its function and passing arguments. `gswin32c -dPrinted ...` is fully satisfies this concept. The basic concept of using is inherited by the numerous use cases. And please stop treating wrongly any program or software usage as out of SOF scope. **The clues and pearls of programming lay in the way of using available operations as API.** – Aleksey F. Sep 12 '21 at 18:47
  • @AlekseyF. I in no way disagree that calling a function is a basic programming construct nor have I implied that in the comment that I made. I suspect your comment is very much based on the edited question revised *after* my comment that now includes some C# code but have completely missed the context of the question which is, how to make GhostScript output to a network location and has literally nothing to do with how it's called. It doesn't work for the OP even from the command line. – Lazarus Nov 11 '21 at 15:02

4 Answers4

16

I've finally made it working and easy for debugging.
My final method code for those interested:

    /// <summary>
    /// Prints the PDF.
    /// </summary>
    /// <param name="ghostScriptPath">The ghost script path. Eg "C:\Program Files\gs\gs8.71\bin\gswin32c.exe"</param>
    /// <param name="numberOfCopies">The number of copies.</param>
    /// <param name="printerName">Name of the printer. Eg \\server_name\printer_name</param>
    /// <param name="pdfFileName">Name of the PDF file.</param>
    /// <returns></returns>
    public bool PrintPDF (string ghostScriptPath, int numberOfCopies, string printerName, string pdfFileName) {
        ProcessStartInfo startInfo  = new ProcessStartInfo();
        startInfo.Arguments         = " -dPrinted -dBATCH -dNOPAUSE -dNOSAFER -q -dNumCopies=" + Convert.ToString(numberOfCopies) + " -sDEVICE=ljet4 -sOutputFile=\"\\\\spool\\" + printerName + "\" \"" + pdfFileName + "\" ";
        startInfo.FileName          = ghostScriptPath; 
        startInfo.UseShellExecute = false;

        startInfo.RedirectStandardError = true;
        startInfo.RedirectStandardOutput = true;

        Process process = Process.Start(startInfo);

        Console.WriteLine( process.StandardError.ReadToEnd() + process.StandardOutput.ReadToEnd() );

        process.WaitForExit(30000);
        if (process.HasExited == false) process.Kill();


        return process.ExitCode == 0;
    }
Maciej
  • 10,423
  • 17
  • 64
  • 97
  • 1
    You should call process.Close() as well, after you get the exit code. – Fiona - myaccessible.website Apr 08 '10 at 14:21
  • Only issue I have with above method is page margins. I coudnt find solution how to set them up. SO my top page content is often cut. I wonder if someone knows how to resolve that? – Maciej Apr 19 '10 at 12:02
  • I've resolved fitting page to specified paper size by passing options via external cfg file. – Maciej Jun 07 '10 at 08:48
  • This code work fine on local machine, when i deploy on server 2008, it's not printing pdf file?. Is that any way you(@Maciej) can saw me how to do that. I am using asp.net mvc – dev Nov 06 '12 at 21:39
  • 1
    As for calling process.Close(), what if I wrapped process in a "using" statement?: "using(Process process = Process.Start(startInfo))" – Vincent Vancalbergh Mar 04 '13 at 13:05
  • Is there a way to print the document without sharing the printer ? – user3079364 Jan 31 '18 at 20:05
4

Not sure if it helps anyone, but to add the printing documents to a queue instead of immediately printing make changes to the above section with

startInfo.Arguments = " -dPrinted -dNoCancel=true -dBATCH -dNOPAUSE -dNOSAFER -q -dNumCopies=" + Convert.ToString(numberOfCopies) + " -sDEVICE=mswinpr2 -sOutputFile=%printer%" + printerName + " \"" + pdfFullFileName + "\"";

Pre-requisites: Configure your printer's job type to "Hold Print": In our case we have a Rico Aficio MP 4000 Printer and our usage is to run a nightly job to print a bunch of PDF files generated through SSRS.

Chirag Parmar
  • 833
  • 11
  • 26
Kiran Xyz
  • 63
  • 1
  • 6
3

You should test your options from the command line first, and then translate the successes into your code.

A PDF file usually does already include page margins. You "often cut" page content may result from a PDF which is meant for A4 page size printed on Letter format.

PDF also uses some internal boxes which organize the page (and object) content: MediaBox, TrimBox, CropBox, Bleedbox.

There are various options to control for which "media size" Ghostscript renders a given input:

-dPDFFitPage  
-dUseTrimBox  
-dUseCropBox 

With PDFFitPage Ghostscript will render to the current page device size (usually the default page size).

With UseTrimBox it will use the TrimBox (and it will at the same time set the PageSize to that value).

With UseCropBox it will use the CropBox (and it will at the same time set the PageSize to that value).

By default (give no parameter), Ghostscript will render using the MediaBox.

Note, you can additionally control the overall size of your output by using -sPAPERSIZE (select amongst all pre-defined values Ghostscript knows) or (for more flexibility) use -dDEVICEWIDTHPOINTS=NNN -dDEVICEHEIGHTPOINTS=NNN to set up custom page sizes.

Kurt Pfeifle
  • 86,724
  • 23
  • 248
  • 345
2

Adding only -dPDFFitPage to my arguments fixed the same issue with the "top page content is often cut."

zoom
  • 43
  • 4