65

Microsoft Windows 10 comes with a Microsoft Print To PDF printer which can print something to a PDF file. It prompts for the filename to download.

How can I programmatically control this from C# to not prompt for the PDF filename but save to a specific filename in some folder that I provide?

This is for batch processing of printing a lot of documents or other types of files to a PDF programmatically.

pdfman
  • 667
  • 1
  • 5
  • 3

3 Answers3

58

To print a PrintDocument object using the Microsoft Print to PDF printer without prompting for a filename, here is the pure code way to do this:

// generate a file name as the current date/time in unix timestamp format
string file = (DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds.ToString();

// the directory to store the output.
string directory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);

// initialize PrintDocument object
PrintDocument doc = new PrintDocument() {
    PrinterSettings = new PrinterSettings() {
        // set the printer to 'Microsoft Print to PDF'
        PrinterName = "Microsoft Print to PDF",

        // tell the object this document will print to file
        PrintToFile = true,

        // set the filename to whatever you like (full path)
        PrintFileName = Path.Combine(directory, file + ".pdf"),
    }
};

doc.Print();

You can also use this method for other Save as File type printers such as Microsoft XPS Printer

blue
  • 79
  • 1
  • 11
Kraang Prime
  • 9,981
  • 10
  • 58
  • 124
  • 8
    How can I use this to print an existing PDF anew with Microsoft Print To PDF, e.g. to "bake" annotations inside the PDF? – clocktown Jun 18 '17 at 23:37
  • @AndrewTruckle - The principle would be the same. Select the PDF virtual printer, then print to it as normal, although I would imagine in C++ there are likely better ways to achieve the same task. While the above code works, I do find it rather slow. – Kraang Prime Oct 11 '17 at 10:05
  • @KraangPrime How can I use this approach to convert a docx file to pdf? I don' t know if it is even possible but i am able to drag docx file to Microsoft print to PDF printer' s spool to save it as pdf manually. Can i do this programmatically using your approach(and without seeing save as dialog of course)? – Alpay Feb 26 '18 at 06:30
  • @Alpay I havn't tested anything myself, but this looks like a good start is [Programmatically provide a filepath as input file for “Microsoft Print to PDF” printer](https://stackoverflow.com/a/40840970/3504007) or [How to print word document in C#](https://stackoverflow.com/a/20803053/3504007) – Kraang Prime Feb 28 '18 at 07:58
  • @KraangPrime Where did you assign `doc` any value that shell be printed? Furthermore how could I assign just a file/filePath as the content to be printed? My intentions are to use the *Microsoft Print to PDF* printer to create ouf of a vector image e.g. `*.emf` file a scalable PDF. – L. Guthardt Mar 22 '18 at 15:43
  • @L.Guthardt See the example [here] on how to print a word doc from c#(https://social.msdn.microsoft.com/Forums/vstudio/en-US/fa0a3db8-3d3d-4536-b17e-4f0a305b123c/print-word-document-in-c?forum=csharpgeneral), and use the above information to assign the printer "Microsoft Print to PDF". – Kraang Prime Mar 22 '18 at 22:01
  • 1
    @KraangPrime, I used this approach. It has given a file, but I could not open it as Adobe Reader says the file is damaged. But if I don't use PrinterSettings, then it will pop up for browsing the destination location and file name, then I can access the file. Am I missing anything..? – user3157132 May 29 '18 at 13:39
  • 6
    Where are the files inputted here? This doesn't work unless we subscribe to `PrintPage` event and do graphics manipulations there, which seems very complicated at least to me. Maybe I'm just missing something? – Shahin Dohan Oct 23 '19 at 10:37
  • 7
    printing an empty file? i don't see where you added any contents to the file. – joym8 Jun 11 '20 at 21:39
  • 1
    @KraangPrime When you get a chance, could you please respond to users `@Shahin Dohan` and `@joym8`? I have the same question. – nam Aug 09 '20 at 15:40
  • @ShahinDohan @joym8 - Please refer to https://learn.microsoft.com/en-us/dotnet/api/system.drawing.printing.printdocument?view=dotnet-plat-ext-3.1 for how to load/create contents to send to the printer. All the above code does is show what you need to set when creating a `PrintDocument` in order to print directly to a PDF without having something popup on every print. It is up to you to build the content using the API Microsoft made available. And I agree, the .NET print API is much worse than it was in VB6 (for example). Unfortunately, it is what it is. – Kraang Prime Aug 10 '20 at 00:52
  • @Kraang Prime - Thanks for the reply, but I already solved the problem here: stackoverflow.com/a/58566537/1469494 – Shahin Dohan Aug 10 '20 at 05:58
  • Why do you give not tested, and not functional anwer? Everytime test your answer before. – bmi Feb 24 '23 at 14:58
0

I had the same question, so I tried the previous solution and ran the same problem stated in the comment. Like empty document.

in print function:

public void PrintFunction() {

    string outputPath = @"D:\Output\Folder\FileName.pdf";

    PrintDocument pd = new PrintDocument();
    pd.PrintPage += PrintPageHandler;

    pd.PrinterSettings.PrintToFile = true;
    pd.PrinterSettings.PrintFileName = outputPath;

    pd.PrintController = new StandardPrintController();
    pd.Print();

}

The PrintPageHandler function: (To handle the Print page events)

private void PrintPageHandler(object sender, PrintPageEventArgs e) {

     // put your contents here for printing 

    e.Graphics.DrawString("Hello World!",
                     new Font("Arial", 12),
                     Brushes.Black,
                     100,   // x-axis
                     100);  // y-axis
}

if you want to force create directory if directory not found:
(put it under declaration of outputPath)

    string directory = Path.GetDirectoryName(outputPath);
    if (!Directory.Exists(directory))
    {
        Directory.CreateDirectory(directory);
    }
kiLLua
  • 443
  • 1
  • 6
  • 17
-1

You can print to the Windows 10 PDF printer, by using the PrintOut method and specifying the fourth output file name parameter, as in the following example:

/// <summary>
/// Convert a file to PDF using office _Document object
/// </summary>
/// <param name="InputFile">Full path and filename with extension of the file you want to convert from</param>
/// <returns></returns>
public void PrintFile(string InputFile)
{
    // convert input filename to new pdf name
    object OutputFileName = Path.Combine(
        Path.GetDirectoryName(InputFile),
        Path.GetFileNameWithoutExtension(InputFile)+".pdf"
    );


    // Set an object so there is less typing for values not needed
    object missing = System.Reflection.Missing.Value;

    // `doc` is of type `_Document`
    doc.PrintOut(
        ref missing,    // Background
        ref missing,    // Append
        ref missing,    // Range
        OutputFileName, // OutputFileName
        ref missing,    // From
        ref missing,    // To
        ref missing,    // Item
        ref missing,    // Copies
        ref missing,    // Pages
        ref missing,    // PageType
        ref missing,    // PrintToFile
        ref missing,    // Collate
        ref missing,    // ActivePrinterMacGX
        ref missing,    // ManualDuplexPrint
        ref missing,    // PrintZoomColumn
        ref missing,    // PrintZoomRow
        ref missing,    // PrintZoomPaperWidth
        ref missing,    // PrintZoomPaperHeight
    );
}

The OutputFile is a full path string of the input document you would like to convert, and the doc is a regular document object. For more info about the doc please see the following MSDN links for _Document.PrintOut()

The PrintOut in the example results a silent print, when you print through the specified inputFile to the OutputFileName, which will be placed in the same folder as the original document, but it will be in PDF format with the .pdf extension.

Kraang Prime
  • 9,981
  • 10
  • 58
  • 124
dodo
  • 459
  • 2
  • 8
  • 21
  • 9
    There's no indication in the question that the poster is using an Office product. – Ken White Apr 05 '16 at 16:59
  • @KenWhite, it was only through research, and the original link that I discovered this. Updated it by adding the current link, and reformatting some of the code so it is readily understood without having to go to the link(s). links are supplied for reference only. – Kraang Prime Apr 05 '16 at 17:01
  • 3
    @SanuelJackson: I didn't say anything about the links or your edit. My point is that this entire answer is based on the premise that the OP is using Word or Excel or automation, and there is zero indication in the question that that is the case. – Ken White Apr 05 '16 at 17:04
  • 1
    @KenWhite - ya, I noticed. Just posted a solution which addresses the OP's question since I was in the area anyway :) . Cleaned it up anyway as it wasn't clear in the answer that it was an Office solution to a non-office question. Since it was still c# related, and it does work, felt it could be preserved but needed a bit of love to clean it up and make it clear it is for office. :) – Kraang Prime Apr 05 '16 at 17:09
  • 1
    Microsoft.Office.Tools.Word.Document.PrintOut https://learn.microsoft.com/en-us/dotnet/api/microsoft.office.tools.word.document.printout?view=vsto-2017 – Stefan Steiger Nov 09 '18 at 13:20
  • Your solution is only for Microsoft Word document. – SHIN JaeGuk Feb 11 '19 at 07:19
  • I upvoted this. When you hover over the button, the tooltip says "This answer was useful". It is useful! The OP never specified what they were trying to print. This poster answered the very question asked for one possible source insofar as the OP's question lacked critical information. Someone like me who was actually looking for this answer to this question would definitely find this response useful. Just because the OP's question and this answer didn't satisfy a given reader's particular needs does not make it unworthy of a vote. So, +11 @dodo! – Mitselplik Jul 19 '22 at 21:52
  • 2
    An answer that misses the point is clutter and therefore absolutely not useful. In contrary. I am searching for a very specific question and it's made so much harde by people answering a different question, like: oh, did you try this dll or that library? you could also use a different language! – Xan-Kun Clark-Davis Jan 25 '23 at 01:50