2

I used C# to print a file to PDF using Microsoft Print to PDF printer. The file was successfully generated. But I am not able to open that because Adobe Reader says that the file is damaged. This is the code

PrintDocument pd = new PrintDocument
{
    PrinterSettings = new PrinterSettings
    {
        PrinterName = "Microsoft Print to PDF (redirected 2)",
        PrintToFile = true,
        PrintFileName = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "/test.pdf"
    }
};
pd.PrintPage += new PrintPageEventHandler(pd_PrintPage);
pd.Print();

But if I use the same code, without PrinterSettings, then it prompts for the destination location and filename. If I specify both, then it generates a pdf file. This, I am able to open using Adobe Reader. Code is shown below

PrintDocument pd = new PrintDocument(); 
pd.PrintPage += new PrintPageEventHandler(pd_PrintPage);
pd.Print();

Not sure what am I missing in the first approach. Please help. The below part is the implementation for pd_PrintPage

private void pd_PrintPage(object sender, PrintPageEventArgs ev)
{
    float linesPerPage = 0;
    float yPos = 0;
    int count = 0;
    float leftMargin = ev.MarginBounds.Left;
    float topMargin = ev.MarginBounds.Top;
    String line = null;

    // Calculate the number of lines per page.
    linesPerPage = ev.MarginBounds.Height /
       printFont.GetHeight(ev.Graphics);

    // Iterate over the file, printing each line.
    while (count < linesPerPage &&
       ((line = streamToPrint.ReadLine()) != null))
    {
        yPos = topMargin + (count * printFont.GetHeight(ev.Graphics));
        ev.Graphics.DrawString(line, printFont, Brushes.Black,
           leftMargin, yPos, new StringFormat());
        count++;
    }

    // If more lines exist, print another page.
    if (line != null)
        ev.HasMorePages = true;
    else
        ev.HasMorePages = false;
}

PS: I referred to How to programmatically print to PDF file without prompting for filename in C# using the Microsoft Print To PDF printer that comes with Windows 10 for the code.

user3157132
  • 167
  • 2
  • 11
  • Can you open the file in Notepad and verify it is a good PDF? Make sure that no extraneous bytes appear before %PDF at the head of the file. – L0uis May 29 '18 at 14:34
  • The file started with PK ê2½L [Content_Types].xml/[0].piece]. No %PDF is seen in the entire document. – user3157132 May 29 '18 at 14:39
  • Are you missing some parenthesys there? `PrinterSettings = new PrinterSettings` has none for example – k1dev May 29 '18 at 14:49
  • @k1dev, same result after including them. – user3157132 May 29 '18 at 14:52
  • where is pd_PrintPage. Would you include the code for this method? – Raikol Amaro May 29 '18 at 14:54
  • 1
    @k1dev When using an [object initializer](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/object-and-collection-initializers), the parens are not necessary. – mason May 29 '18 at 14:55
  • 2
    A file starting with PK is not a PDF file. That looks to me like its an XPS file instead, because XPS files are renamed Zip archives, and PK is the magic number for Zip. Not sure why that's happening though. Note that XPS is the internal format used by Microsoft in the print pipeline these days. Any other kind of output needs to have a printer device driver to take the XPS and convert it to 'something else'. – KenS May 29 '18 at 14:59
  • @mason good one, wasn't aware of that – k1dev May 29 '18 at 19:25
  • @RaikolAmaro, added pd_PrintPage implementation – user3157132 May 30 '18 at 04:57
  • @user3157132 where does the streamToPrint variable come from – Raikol Amaro May 30 '18 at 12:28
  • @user3157132 I tested your code and it prints the PDF just fine. The only difference is that I used 'Microsoft Print to PDF' instead of your 'Microsoft Print to PDF (redirected 2)'. Do you have any try-catch blocks that may be hiding an exception while printing is in progress? Perhaps something related to the StreamReader? – Raikol Amaro May 30 '18 at 13:11
  • @RaikolAmaro, can you please post your complete code as an answer. I will see if there is any difference and give it a try. – user3157132 May 31 '18 at 13:13
  • @user3157132 did it work for you? – Raikol Amaro Jun 04 '18 at 13:30
  • @RaikolAmaro, unfortunately no :( As I mentioned, if I take out the PrinterSettings, it works. Not able to figure out why. – user3157132 Jun 05 '18 at 18:22

1 Answers1

0

Here's the code I have which runs ok. I hope it helps.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing.Printing;
using System.IO;
using System.Drawing;

namespace ConsoleApp1
{
    class Program
    {
        private static Font printFont;
        private static StreamReader streamToPrint;

        static void Main(string[] args)
        {
            // generate a file name as the current date/time in unix timestamp format
            string fileName = (string)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds.ToString();

            // the directory to store the output.
            string directory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            printFont = new Font("Arial", 10);

            try
            {
                streamToPrint = new StreamReader
                    ("C:\\Users\\RaikolAmaro\\Desktop\\lachy.txt");

                // 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, fileName + ".pdf"),
                    }
                };

                doc.PrintPage += new PrintPageEventHandler(pd_PrintPage);
                doc.Print();
            }
            finally
            {
                streamToPrint.Close();
            }
        }

        private static void pd_PrintPage(object sender, PrintPageEventArgs ev)
        {
            float linesPerPage = 0;
            float yPos = 0;
            int count = 0;
            float leftMargin = ev.MarginBounds.Left;
            float topMargin = ev.MarginBounds.Top;
            String line = null;

            // Calculate the number of lines per page.
            linesPerPage = ev.MarginBounds.Height /
                           printFont.GetHeight(ev.Graphics);

            // Iterate over the file, printing each line.
            while (count < linesPerPage &&
                   ((line = streamToPrint.ReadLine()) != null))
            {
                yPos = topMargin + (count * printFont.GetHeight(ev.Graphics));
                ev.Graphics.DrawString(line, printFont, Brushes.Black,
                    leftMargin, yPos, new StringFormat());
                count++;
            }

            // If more lines exist, print another page.
            if (line != null)
                ev.HasMorePages = true;
            else
                ev.HasMorePages = false;
        }
    }
}
Raikol Amaro
  • 419
  • 4
  • 12