為打印預覽對話框 PrintPreviewDialog 添加保存到 PDF 文件按鈕源代碼詳解

  • 前言
  • 1、創建自定義打印預覽對話框 CustomPrintPreviewDialog
  • 2、自定義打印預覽對話框內部按鈕和事件
  • 2.1、自定義打印預覽對話框內部按鈕和事件
  • 2.2、公共靜態類和打印預覽分類枚舉
  • 2.3、主窗調用自定義打印預覽對話框
  • 3、自定義打印預覽對話框外部按鈕
  • 3.1、自定義打印預覽對話框外部按鈕
  • 3.2、公共靜態類和打印預覽分類枚舉
  • 3.3、主窗調用自定義打印預覽對話框
  • 4、Adobe PDF 與 Microsoft Print to PDF 的轉換特點
  • 4.1、Microsoft Print to PDF 轉換 PDF
  • 4.2、Adobe PDF 轉換 PDF
  • 4.3、轉換中解決的其它問題
  • 4.4、整理後的完整靜態函數:
  • 4.4.1、Adobe PS 轉換為 PDF 函數過程:
  • 4.4.2、Adobe Acrobat Pro 虛擬打印機註冊表設置

前言

以 Windows 平台 Visual Studio 2017 C# 為開發工具,Windows Forms(.Net FrameWork 4.0)為框架,創建創建自定義打印預覽對話框,並添加自定義按鈕,以將打印文檔內容保存到 PDF 文件。

1、創建自定義打印預覽對話框 CustomPrintPreviewDialog

在項目中添加類,命名為 CustomPrintPreviewDialog : PrintPreviewDialog

using System;
using System.Drawing;
using System.Drawing.Printing;
using System.Windows.Forms;
namespace 命名空間
{
    public partial class CustomPrintPreviewDialog : PrintPreviewDialog//以原始打印預覽為基類
    {
    }
}

2、自定義打印預覽對話框內部按鈕和事件

2.1、自定義打印預覽對話框內部按鈕和事件

using static 命名空間.PublicStaticClass;

namespace 命名空間
{
    public partial class CustomPrintPreviewDialog : PrintPreviewDialog
    {
        /// <summary>頁面設置</summary>
        private PageSetupDialog pageSetupDialog = new PageSetupDialog();
        /// <summary>當前打印文檔</summary>
        private PrintDocument CurrentDocument;
        /// <summary>獲取和設置當前打印文檔</summary>
        public new PrintDocument Document
        {
            get => CurrentDocument;
            set
            {
                CurrentDocument = value;
                base.Document = value;
            }
        }
       
        /// <summary>自定義打印預覽對話框</summary>
        public CustomPrintPreviewDialog()
        {
            // 獲取打印預覽對話框原生工具欄
            if (!(this.Controls["toolStrip1"] is ToolStrip toolStrip)) return;

            //初始化頁面設置
            pageSetupDialog = new PageSetupDialog
            {
                EnableMetric = true//打開毫米為單位,否則為1/100英寸
            };
            
            // 添加頁面設置按鈕,和內部單擊事件
            ToolStripButton PrintSettingsButton = new ToolStripButton("頁面設置", null, (s, e) => PrintSettingsButton_Click())
            {
                DisplayStyle = ToolStripItemDisplayStyle.ImageAndText,// 顯示樣式
                Image = Properties.Resources.PageSetup,//自定義按鈕圖標圖像
                ImageScaling = ToolStripItemImageScaling.SizeToFit,
                Size = new Size(120, 40),// 設置按鈕大小
                Margin = new Padding(20, 2, 5, 2),// 設置邊距控制位置
                Alignment = ToolStripItemAlignment.Left,//.Right// 設置對齊方式
            };
            toolStrip.Items.Insert(0, PrintSettingsButton);//插入到PrintPreviewDialog工具欄最前面

            // 添加保存為PDF文件按鈕,和內部單擊事件
            ToolStripButton SavePDFButton = new ToolStripButton("保存為 PDF", null, (s, e) => PrintToPDF())
            {
                DisplayStyle = ToolStripItemDisplayStyle.ImageAndText,
                Image = Properties.Resources.PDFFile,
                ImageScaling = ToolStripItemImageScaling.SizeToFit,
                ToolTipText = "保存為 PDF 文件"
            };
            toolStrip.Items.Insert(10, SavePDFButton);//插入第10個圖標位置
        }
        
        /// <summary>打印設置按鈕單擊</summary>
        private void PrintSettingsButton_Click()
        {
            pageSetupDialog.Document = this.PrintPreviewControl.Document;
            pageSetupDialog.PageSettings = this.PrintPreviewControl.Document.DefaultPageSettings;

            if (pageSetupDialog.ShowDialog() == DialogResult.OK)
            {
                this.Document.DefaultPageSettings = pageSetupDialog.PageSettings;
                this.PrintPreviewControl.InvalidatePreview();//刷新預覽
            }
        }

        /// <summary>打印到PDF文件</summary>
        private void PrintToPDF()
        {
            if (CurrentDocument == null)
            {
                MessageBox.Show("沒有可打印的文檔", "提示",MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }
            string PDFFilePath = string.Empty;
            switch (printResultTableType)
            {
                case PrintResultTableType.AdcpDischargeMeasureResults:
                    PDFFilePath = SiteMeasureResultsFile.Replace(".SRF", "_ADCP流量測驗記載表.PDF");
                    break;
                case PrintResultTableType.AdcpVelocityDirectionResults:
                    PDFFilePath = SiteMeasureResultsFile.Replace(".SRF", "_ADCP流速流向成果表.PDF");
                    break;
                case PrintResultTableType.PrintPreviewFormGraphics:
                    if (string.IsNullOrEmpty(ProjectDirectory))
                    {
                        PDFFilePath = Application.StartupPath + $"\\{ActiveFormName}窗體圖形.PDF";
                    }
                    else
                    {
                        PDFFilePath = ProjectDirectory + $"\\{ActiveFormName}窗體圖形.PDF";
                    }
                    break;
                case PrintResultTableType.PrintPreviewGraphics:
                    if (string.IsNullOrEmpty(ProjectDirectory))
                    {
                        PDFFilePath = Application.StartupPath + $"\\{ActiveFormName}圖形.PDF";
                    }
                    else
                    {
                        PDFFilePath = ProjectDirectory + $"\\{ActiveFormName}圖形.PDF";
                    }
                    break;
            }
            string PrinterString = string.Empty;
            if (CheckPdfPrinterExists(out PrinterString))
            {
                using (PrintDialog printDialog = new PrintDialog())
                {
                    // 配置打印設置
                    PrinterSettings printerSettings = new PrinterSettings
                    {
                        PrinterName = PrinterString,//PDF 虛擬打印機名稱
                        PrintToFile = true,//打開打印到文件
                        PrintFileName = PDFFilePath//打印的PDF文件路徑名稱
                    };

                    printDialog.Document = CurrentDocument;
                    printDialog.PrinterSettings = printerSettings;
                   // printDialog.UseEXDialog = true;

                    // 執行打印
                    CurrentDocument.PrinterSettings = printerSettings;
                    CurrentDocument.Print();

                    MessageBox.Show($"PDF文件已成功保存到:\r\n\r\n{PDFFilePath}", "導出成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
            else
            {
                MessageBox.Show("未找到 Adobe 或微軟 PDF 打印機","提示", MessageBoxButtons.OK, MessageBoxIcon.Information); 
            }
        }


        /// <summary>檢查 PDF虛擬打印機</summary>
        /// <param name="PrinterString">輸出 PDF 打印機名稱</param>
        /// <returns>返回是否存在 PDF 虛擬打印機</returns>
        private bool CheckPdfPrinterExists(out string PrinterString)
        {
            foreach (string printer in PrinterSettings.InstalledPrinters)
            {
                if (printer.Contains("Microsoft Print to PDF") || printer.Contains("Adobe PDF") || printer.Contains("Acrobat Distiller"))
                {
                    PrinterString = printer;
                    return true;
                }
            }
            PrinterString = string.Empty;
            return false;
        }
    }
}

2.2、公共靜態類和打印預覽分類枚舉

namespace 命名空間
{
    /// <summary>公共靜態類</summary>
    public static class PublicStaticClass
    {
        /// <summary>打印表類型</summary>
        public static PrintResultTableType printResultTableType;
        ///<summary>活動窗體名稱</summary>
        public static string ActiveFormName = string.Empty;
    }
    /// <summary>打印成果表類型</summary>
    public enum PrintResultTableType
    {
        /// <summary>打印預覽ADCP流量測驗成果表</summary>
        AdcpDischargeMeasureResults = 0,
        /// <summary>打印預覽ADCP流速流向成果表</summary>
        AdcpVelocityDirectionResults = 1,
        /// <summary>打印預覽圖形</summary>
        PrintPreviewGraphics = 2,
        /// <summary>打印預覽窗體圖形</summary>
        PrintPreviewFormGraphics = 3,
    }
}

2.3、主窗調用自定義打印預覽對話框

主窗體為MDI,以打印子窗體圖像為例。

using static 命名空間.PublicStaticClass;
namespace 命名空間
{
   public partial class AdcpProcesMainForm : Form
   {
        /// <summary>打印文檔</summary>
        private PrintDocument PrintDocument = null;

        public AdcpProcesMainForm()
        {
            InitializeComponent();
            this.MdiChildActivate += OnMdiChildActivated;
        }
        
        /// <summary>當前活動子窗口</summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnMdiChildActivated(object sender, EventArgs e)
        {
            var activeChild = this.ActiveMdiChild;
            if (activeChild != null)
            {
                ActiveFormName =activeChild.Text;
            }
        }
        
        private void PrintPreviewFormGraphicsMenu_Click(object sender, EventArgs e)
        {
            var activeChild = this.ActiveMdiChild;
            if (this.ActiveMdiChild != null)
            {
                printResultTableType = PrintResultTableType.PrintPreviewFormGraphics;
                
                //this.Hide();//隱藏主窗,配合Preview.FormClosed。

                PrintDocument = new PrintDocument();
                // 自定義打印預覽
                CustomPrintPreviewDialog Preview = new CustomPrintPreviewDialog
                {
                    // ShowIcon = false,
                    StartPosition = FormStartPosition.CenterScreen,
                    WindowState = FormWindowState.Maximized,
                    Icon = Properties.Resources.AdcpTable, // 設置自定義打印預覽圖標
                    Text = "窗體打印預覽",            // 設置窗口標題
                    Height = Screen.PrimaryScreen.Bounds.Height,
                    Width = Screen.PrimaryScreen.Bounds.Width,
                    FormBorderStyle = FormBorderStyle.FixedDialog,
                };

                // 捕獲子窗體的圖形區域
                Bitmap FormImage = new Bitmap(activeChild.Width, activeChild.Height);

                activeChild.DrawToBitmap(FormImage, new Rectangle(0, 0, FormImage.Width, FormImage.Height));

                PrintDocument.PrintPage += (s, args) =>
                {
                    // 計算居中打印位置
                    Rectangle printArea = args.MarginBounds;
                    if (FormImage.Width > printArea.Width || FormImage.Height > printArea.Height)
                    {
                        // 按比例縮放
                        Size newSize = FitSize(FormImage.Size, printArea.Size);
                        int x = printArea.X + (printArea.Width - newSize.Width) / 2;
                        int y = printArea.Y + (printArea.Height - newSize.Height) / 2;

                        args.Graphics.DrawImage(FormImage,
                            new Rectangle(x, y, newSize.Width, newSize.Height));
                    }
                    else
                    {
                        // 居中打印
                        int x = printArea.X + (printArea.Width - FormImage.Width) / 2;
                        int y = printArea.Y + (printArea.Height - FormImage.Height) / 2;
                        args.Graphics.DrawImage(FormImage, x, y);
                    }
                };

                /// <summary>打印預覽窗體關閉後,恢復主窗顯示</summary>
                //Preview.FormClosed += (s, args) =>
                // {
                //     this.Show(); // 預覽關閉時重新顯示主窗體
                //     this.Activate(); // 激活主窗體獲得焦點
                // };

                Preview.Document = PrintDocument;

                if (FormImage.Width > FormImage.Height)
                {
                    Preview.Document.DefaultPageSettings.Landscape = true;
                    Preview.Landscape = true;
                }
                else
                {
                    Preview.Document.DefaultPageSettings.Landscape = false;
                    Preview.Landscape = false;
                }

                Preview.ShowDialog(this);
            }
        }
    }    
}

3、自定義打印預覽對話框外部按鈕

3.1、自定義打印預覽對話框外部按鈕

namespace 命名空間
{
    public partial class CustomPrintPreviewDialog : PrintPreviewDialog
    {
        /// <summary>頁面設置</summary>
        private PageSetupDialog pageSetupDialog = new PageSetupDialog();
        /// <summary>保存到PDF按鈕事件</summary>
        public event EventHandler SavePDFButtonClick;
        
        /// <summary>自定義打印預覽對話框</summary>
        public CustomPrintPreviewDialog()
        {
            // 獲取打印預覽對話框原生工具欄
            if (!(this.Controls["toolStrip1"] is ToolStrip toolStrip)) return;

            //初始化頁面設置
            pageSetupDialog = new PageSetupDialog
            {
                EnableMetric = true//打開毫米為單位,否則為1/100英寸
            };
            
            // 添加頁面設置按鈕,和內部單擊事件
            ToolStripButton PrintSettingsButton = new ToolStripButton("頁面設置", null, (s, e) => PrintSettingsButton_Click())
            {
                DisplayStyle = ToolStripItemDisplayStyle.ImageAndText,// 顯示樣式
                Image = Properties.Resources.PageSetup,//自定義按鈕圖標圖像
                ImageScaling = ToolStripItemImageScaling.SizeToFit,
                Size = new Size(120, 40),// 設置按鈕大小
                Margin = new Padding(20, 2, 5, 2),// 設置邊距控制位置
                Alignment = ToolStripItemAlignment.Left,//.Right// 設置對齊方式
            };
            toolStrip.Items.Insert(0, PrintSettingsButton);//插入到PrintPreviewDialog工具欄最前面

            // 添加保存為PDF文件按鈕,和外部單擊事件
            ToolStripButton SavePDFButton = new ToolStripButton("保存為 PDF", null, (s, e) => SavePDFButtonClick?.Invoke(this, e))
            {
                DisplayStyle = ToolStripItemDisplayStyle.ImageAndText,
                Image = Properties.Resources.PDFFile,
                ImageScaling = ToolStripItemImageScaling.SizeToFit,
                ToolTipText = "保存為 PDF 文件"
            };
            toolStrip.Items.Insert(10, SavePDFButton);//插入第10個圖標位置
        }
        
        /// <summary>打印設置按鈕單擊</summary>
        private void PrintSettingsButton_Click()
        {
            pageSetupDialog.Document = this.PrintPreviewControl.Document;
            pageSetupDialog.PageSettings = this.PrintPreviewControl.Document.DefaultPageSettings;

            if (pageSetupDialog.ShowDialog() == DialogResult.OK)
            {
                this.Document.DefaultPageSettings = pageSetupDialog.PageSettings;
                this.PrintPreviewControl.InvalidatePreview();//刷新預覽
            }
        }
    }
}

3.2、公共靜態類和打印預覽分類枚舉

namespace 命名空間
{
    /// <summary>公共靜態類</summary>
    public static class PublicStaticClass
    {
        /// <summary>打印表類型</summary>
        public static PrintResultTableType printResultTableType;
        ///<summary>活動窗體名稱</summary>
        public static string ActiveFormName = string.Empty;
    }
    /// <summary>打印成果表類型</summary>
    public enum PrintResultTableType
    {
        /// <summary>打印預覽ADCP流量測驗成果表</summary>
        AdcpDischargeMeasureResults = 0,
        /// <summary>打印預覽ADCP流速流向成果表</summary>
        AdcpVelocityDirectionResults = 1,
        /// <summary>打印預覽圖形</summary>
        PrintPreviewGraphics = 2,
        /// <summary>打印預覽窗體圖形</summary>
        PrintPreviewFormGraphics = 3,
    }
}

3.3、主窗調用自定義打印預覽對話框

namespace 命名空間
{
   public partial class AdcpProcesMainForm : Form
   {
        /// <summary>打印文檔</summary>
        private PrintDocument PrintDocument = null;
        
        public AdcpProcesMainForm()
        {
            InitializeComponent();
            this.MdiChildActivate += OnMdiChildActivated;
        }
        /// <summary>當前活動子窗口</summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnMdiChildActivated(object sender, EventArgs e)
        {
            var activeChild = this.ActiveMdiChild;
            if (activeChild != null)
            {
                ActiveFormName =activeChild.Text;
            }
        }

  private void PrintPreviewFormGraphicsMenu_Click(object sender, EventArgs e)
        {
            var activeChild = this.ActiveMdiChild;
            if (this.ActiveMdiChild != null)
            {
                printResultTableType = PrintResultTableType.PrintPreviewFormGraphics;
                //this.Hide();

                PrintDocument = new PrintDocument();
                // 打印預覽
                CustomPrintPreviewDialog Preview = new CustomPrintPreviewDialog
                {
                    // ShowIcon = false,
                    StartPosition = FormStartPosition.CenterScreen,
                    WindowState = FormWindowState.Maximized,
                    Icon = Properties.Resources.AdcpTable, // 設置系統信息圖標
                    Text = "窗體打印預覽",            // 設置窗口標題
                    Height = Screen.PrimaryScreen.Bounds.Height,
                    Width = Screen.PrimaryScreen.Bounds.Width,
                    FormBorderStyle = FormBorderStyle.FixedDialog,
                };

                // 捕獲子窗體的圖形區域
                Bitmap FormImage = new Bitmap(activeChild.Width, activeChild.Height);
                //Bitmap FormImage = new Bitmap(activeChild.ClientSize.Width, activeChild.ClientSize.Height );

                activeChild.DrawToBitmap(FormImage, new Rectangle(0, 0, FormImage.Width, FormImage.Height));

                PrintDocument.PrintPage += (s, args) =>
                {

                    // 計算居中打印位置
                    Rectangle printArea = args.MarginBounds;
                    if (FormImage.Width > printArea.Width || FormImage.Height > printArea.Height)
                    {
                        // 按比例縮放
                        Size newSize = FitSize(FormImage.Size, printArea.Size);
                        int x = printArea.X + (printArea.Width - newSize.Width) / 2;
                        int y = printArea.Y + (printArea.Height - newSize.Height) / 2;

                        args.Graphics.DrawImage(FormImage,
                            new Rectangle(x, y, newSize.Width, newSize.Height));
                    }
                    else
                    {
                        // 居中打印
                        int x = printArea.X + (printArea.Width - FormImage.Width) / 2;
                        int y = printArea.Y + (printArea.Height - FormImage.Height) / 2;
                        args.Graphics.DrawImage(FormImage, x, y);
                    }
                };

                //Preview.FormClosed += (s, args) =>
                // {
                //     this.Show(); // 預覽關閉時重新顯示主窗體
                //     this.Activate(); // 激活主窗體獲得焦點
                // };

                Preview.Document = PrintDocument;

                if (FormImage.Width > FormImage.Height)
                {
                    Preview.Document.DefaultPageSettings.Landscape = true;
                    Preview.Landscape = true;
                }
                else
                {
                    Preview.Document.DefaultPageSettings.Landscape = false;
                    Preview.Landscape = false;
                }

                Preview.SavePDFButtonClick += SavePDFButton_Click;//按鈕事件
                Preview.ShowDialog(this);//
            }
        }

        /// <summary>保存為PDF文件</summary>
        /// <param name="sender"></param>
        /// <param name="e">事件基類</param>
        private void SavePDFButton_Click(object sender, EventArgs e)
        {
            string PrinterString = string.Empty;
            if (CheckPdfPrinterExists(out PrinterString))//檢查和獲取PDF虛擬打印機名稱
            {
                string PDFFilePath = string.Empty;

                switch (printResultTableType)
                {
                    case PrintResultTableType.AdcpDischargeMeasureResults:
                        PDFFilePath = SiteMeasureResultsFile.Replace(".SRF", "_ADCP流量測驗記載表.PDF");
                        break;
                    case PrintResultTableType.AdcpVelocityDirectionResults:
                        PDFFilePath = SiteMeasureResultsFile.Replace(".SRF", "_ADCP流速流向成果表.PDF");
                        break;
                    case PrintResultTableType.PrintPreviewFormGraphics:
                        if (string.IsNullOrEmpty(ProjectDirectory))
                        {
                            PDFFilePath = Application.StartupPath + $"\\{ActiveFormName}窗體圖形.PDF";
                        }
                        else
                        {
                            PDFFilePath = ProjectDirectory + $"\\{ActiveFormName}窗體圖形.PDF";
                        }
                        break;
                    case PrintResultTableType.PrintPreviewGraphics:
                        if (string.IsNullOrEmpty(ProjectDirectory))
                        {
                            PDFFilePath = Application.StartupPath + $"\\{ActiveFormName}圖形.PDF";
                        }
                        else
                        {
                            PDFFilePath = ProjectDirectory + $"\\{ActiveFormName}圖形.PDF";
                        }
                        break;
                }

                if (PrintDocument != null)
                {
                    using (PrintDialog printDialog = new PrintDialog())
                    {
                        // 配置打印設置
                        PrinterSettings printerSettings = new PrinterSettings
                        {
                            PrinterName = PrinterString,//PDF 虛擬打印機名稱
                            PrintToFile = true,//打開打印到文件
                            PrintFileName = PDFFilePath//打印的PDF文件路徑名稱
                        };

                        printDialog.Document = PrintDocument;
                        printDialog.PrinterSettings = printerSettings;
                        // printDialog.UseEXDialog = true;

                        // 執行打印
                        PrintDocument.PrinterSettings = printerSettings;
                        PrintDocument.Print();

                        MessageBox.Show($"PDF文件已成功保存到:\r\n\r\n{PDFFilePath}", "導出成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }
                }
            }
            else
            {
                //throw new Exception("未找到 Adobe 或微軟 PDF 打印機");
                MessageBox.Show("未找到 Adobe 或微軟 PDF 打印機", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        /// <summary>檢查 PDF虛擬打印機</summary>
        /// <param name="PrinterString">輸出 PDF 打印機名稱</param>
        /// <returns>返回是否存在 PDF 虛擬打印機</returns>
        private bool CheckPdfPrinterExists(out string PrinterString)
        {
            foreach (string printer in PrinterSettings.InstalledPrinters)
            {
                if (printer.Contains("Microsoft Print to PDF") || printer.Contains("Adobe PDF") || printer.Contains("Acrobat Distiller"))
                {
                    PrinterString = printer;
                    return true;
                }
            }
            PrinterString = string.Empty;
            return false;
        }
     }   
}

4、Adobe PDF 與 Microsoft Print to PDF 的轉換特點

4.1、Microsoft Print to PDF 轉換 PDF

採用 Microsoft Print to PDF 虛擬打印機轉換 PDF 文件,如果是窗體或圖像,像素沒有 Adobe PDF 虛擬打印機轉換 PDF 清晰。

Microsoft Print to PDF 虛擬打印設置,可以設置 PrintToFile = true 直接指定文件輸出:

PrinterSettings printerSettings = new PrinterSettings
         {
             PrinterName = PrinterString,//PDF 虛擬打印機名稱
             PrintToFile = true,//打開打印到文件
             PrintFileName = PDFFilePath//打印的PDF文件路徑名稱
         };

4.2、Adobe PDF 轉換 PDF

採用 Adobe PDF 虛擬打印機轉換 PDF 文件,圖像像素明顯清晰。設置 PrintToFile = true 直接指定文件輸出,輸出的文件類型為 PostScript,文件擴展名為 PS,需要再轉換為 PDF 文件,原創説明網絡上很難搜索到這方面的詳細描敍。設置 PrintToFile = false 直接可以輸出 PDF 文件,默認輸出到系統文檔目錄 Document\document.pdf 輸出,不能直接定義文件名和目錄。

需要指定輸出 PDF 文件可以採用輸出先輸出 *.PS,再轉換為 *.PDF。

轉換關鍵,計算機必須安裝有 Adobo Acrobat Pro ,在項目中引用 COM 類庫 Acrobat Distiller 或 Acrobat。

引用 COM 類庫 Acrobat Distiller 後聲明:

using ACRODISTXLib;
String PSFile = PDFFilePath.Replace(".PDF", ".PS");
         PrinterSettings printerSettings = new PrinterSettings
         {
             PrinterName = PrinterString,//PDF 虛擬打印機名稱
             PrintToFile = true,//打開打印到文件
             PrintFileName = PSFilePath//打印的PS文件路徑名稱
         };
         CurrentPrintDocument.PrintController = new StandardPrintController();

         CurrentPrintDocument.PrinterSettings = printerSettings;
         CurrentPrintDocument.DefaultPageSettings.Landscape = Landscape;

         CurrentPrintDocument.Print();

         System.Threading.Thread.Sleep(200);
         
         if (File.Exists(PSFilePath))
         {
             PdfDistiller PdfDistiller = new PdfDistiller();
             PdfDistiller.FileToPDF(PSFile, PDFFilePath, "Standard");

             if (File.Exists(PDFFilePath))
             {
                String LOGFile = PDFFilePath.Replace(".PDF", ".LOG");
                File.Delete(PSFile);//刪除轉換過程文件
                File.Delete(LOGFile);//刪除轉換日誌文件
                MessageBox.Show($"PDF文件已成功保存到:\r\n\r\n{PDFFilePath}", "導出成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
             }

             Marshal.ReleaseComObject(PdfDistiller);//卸載 Distiller 進程
             PdfDistiller = null;
        }

轉換結果:

c# 頁面打印預覽 並保存為PDF_#1024程序員節

4.3、轉換中解決的其它問題

1、首先提示,上述代碼中沒有處理錯誤消息!
  2、使用 PrintToFile = true 打印到 PS 文件,必須取消勾選**僅依靠系統字體;不使用文檔字體**,否則程序彈出錯誤。

c# 頁面打印預覽 並保存為PDF_自定義_02

通過程序修改註冊表可以取消勾選僅依靠系統字體;不使用文檔字體
信息位置:\HKEY_CURRENT_USER\Printers\DevModePerUser\Adobe PDF
主鍵:HKEY_CURRENT_USER
子健:Printers\DevModePerUser
鍵名:Adobe PDF
鍵值:二進制 Binary 第 1164 個數設置為 0

SubKey = "Printers\\DevModePerUser\\";
      object AdobePDFobject = null;
      PdfRegKey(RegDomain.CurrentUser, SubKey, "Adobe PDF", ref AdobePDFobject, RegValueKind.Binary);//讀註冊表

      byte[] AdobePDFArray = (byte[])AdobePDFobject;
      AdobePDFArray[1164] = 0;
      AdobePDFobject = AdobePDFArray;

      PdfRegKey(RegDomain.CurrentUser, SubKey, "Adobe PDF", ref AdobePDFobject, RegValueKind.Binary,true );//寫註冊表

該設置值寫入了很多地方:

  • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers\Adobe PDF\PrinterDriverData\DistillerHostFontHasMostFonts
  • HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Print\Printers\Adobe PDF\PrinterDriverData\DistillerHostFontHasMostFonts
  • HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Print\Printers\Adobe PDF\PrinterDriverData\DistillerHostFontHasMostFonts
  • HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Printers\Adobe PDF\PrinterDriverData\DistillerHostFontHasMostFonts
  • HKEY_CURRENT_USER\Printers\DevModePerUser\Adobe PDF
  • HKEY_CURRENT_USER\Printers\DevModes2\Adobe PDF

只有使用用户權限修改 HKEY_CURRENT_USER\Printers\DevModePerUser\Adobe PDF 即可。

3、PS 轉換為 PDF 默認彈出安全性確定

c# 頁面打印預覽 並保存為PDF_#保存為PDF文件_03


可以運行 Acrobat Distiller 勾選信任通過所有文件:

c# 頁面打印預覽 並保存為PDF_#PDF虛擬打印機_04


通過程序修改註冊表可以勾選信任通過所有文件:

SubKey = "Software\\Adobe\\Acrobat Distiller\\DC\\Preferences\\";  //通過所有輸入文件的安全性,不彈出安全性對話框
  object bTrustAllFiles =new byte[] {0};
  PdfRegKey(RegDomain.CurrentUser, SubKey, "bTrustAllFiles", ref bTrustAllFiles, RegValueKind.Binary, true);

4.4、整理後的完整靜態函數:

引用 COM 類庫 Acrobat Distiller 後,在模塊進行如下聲明:

using System;
using System.IO;
using System.Runtime.InteropServices;
using ACRODISTXLib;

4.4.1、Adobe PS 轉換為 PDF 函數過程:

/// <summary>Adobe PS 轉換為 PDF</summary>
        /// <param name="PSFile">輸入PS文件</param>
        public static void PSConvertToPDF(string PSFile)
        {
            try
            {
                Process[] processes = Process.GetProcessesByName("acrodist");
                foreach (Process process in processes)
                {
                    process.Kill();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("無法關閉進程:" + ex.Message);
            }

            System.Threading.Thread.Sleep(100);
            PdfDistiller PdfDistiller =null;
            try
            {
                if (File.Exists(PSFile))
                {
                    string PDFFile = Path.GetDirectoryName(PSFile) + "\\" + Path.GetFileNameWithoutExtension(PSFile) + ".PDF";
                    PdfDistiller = new PdfDistiller
                    {
                        bShowWindow = 0
                    };
                    short Info = PdfDistiller.FileToPDF(PSFile, PDFFile, "Standard");
                    switch (Info)
                    {
                        case -1:
                            MessageBox.Show($"PS創建轉換PDF失敗!", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            break;
                        case 0:
                            MessageBox.Show($"PS創建轉換PDF參數無效!", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            break;
                        case 1:
                            if (File.Exists(PDFFile))
                            {
                                String LOGFile = PSFile.Replace(".PS", ".LOG");
                                File.Delete(PSFile);
                                File.Delete(LOGFile);
                                MessageBox.Show($"PDF文件已成功保存到:\r\n\r\n{PDFFile}", "導出成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
                            }
                            break;
                        default:
                            MessageBox.Show($"PS創建轉換PDF其它錯誤!", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            break;
                    }
                    Marshal.ReleaseComObject(PdfDistiller);
                    PdfDistiller = null;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"Adobe Distiller 初始化失敗: \r\n沒有安裝 Adobe Acrobat Pro ?\r\n{ex.Message}\r\n{ex.StackTrace}", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                // 確保PdfDistiller被正確關閉和釋放
                if (PdfDistiller != null)
                {
                    try
                    {
                        // 釋放COM對象資源
                        Marshal.ReleaseComObject(PdfDistiller);
                        PdfDistiller = null;
                    }
                    catch (Exception disposeEx)
                    {
                        Console.WriteLine($"釋放資源時出現錯誤:{disposeEx.Message}");
                    }
                }
            }

        }

4.4.2、Adobe Acrobat Pro 虛擬打印機註冊表設置

/// <summary>Adobe 虛擬打印機註冊表設置</summary>
        public static void AdobeRegRW()
        {
            object AdobePDFobject = null;
            string SubKey = "Printers\\DevModePerUser\\";
            RegKey(RegDomain.CurrentUser, SubKey, "Adobe PDF", ref AdobePDFobject, RegValueKind.Binary);//讀註冊表二進制值

            byte[] AdobePDFArray = (byte[])AdobePDFobject;
            AdobePDFArray[1164] = 0;//修改二進制值設置
            AdobePDFobject = AdobePDFArray;

            RegKey(RegDomain.CurrentUser, SubKey, "Adobe PDF", ref AdobePDFobject, RegValueKind.Binary, true);//寫取消勾選僅依靠系統字體;不使用文檔字體

            SubKey = "Software\\Adobe\\Acrobat Distiller\\DC\\Preferences\\";

            object bTrustAllFiles = new byte[] { 1 };
            RegKey(RegDomain.CurrentUser, SubKey, "bTrustAllFiles", ref bTrustAllFiles, RegValueKind.Binary, true);//通過所有輸入文件的安全性,不彈出安全性對話框
        }

以上針對 Adobo Acrobat Pro 2023 版本。