首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

Windows 服務實作 PDF 轉圖片自動化:基於 Acrobat COM 元件與定時掃描

     編輯:關於.NET

前言

企業常需將大量 PDF 自動轉為圖片(如預覽、OCR 前處理)。本文示範建立 Windows Service,每 2 秒掃描指定資料夾,偵測新增/變更 PDF,呼叫 Adobe Acrobat COM 元件逐頁轉檔為 JPG,並透過剪貼簿中轉取得 Bitmap 存檔。完整包含服務架構、Installer、Setup 專案與 App.config 設定。

一、專案結構

  • PDFConverterService:Windows Service 專案
  • InstallerClass:服務安裝邏輯(設定 `Type` 登錄值啟用互動桌面)
  • Setup Project:產生 `.msi` 部署套件

二、核心服務程式碼

public partial class PDFConverter : ServiceBase
{
    private System.Timers.Timer _timer;

    public PDFConverter() { InitializeComponent(); }

    protected override void OnStart(string[] args)
    {
        _timer = new System.Timers.Timer(2000); // 2 秒
        _timer.Elapsed += Timer_Elapsed;
        _timer.Start();
    }

    private void Timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        // 必須在 STA 執行緒呼叫 COM
        var thread = new Thread(Process) { ApartmentState = ApartmentState.STA };
        thread.Start();
    }

    protected override void OnStop() { _timer.Stop(); }

    [STAThread]
    private void Process()
    {
        string pdfDir = ConfigurationManager.AppSettings["pdfFilepath"];
        string imgDir = ConfigurationManager.AppSettings["imageFilepath"];

        if (!Directory.Exists(pdfDir)) return;
        if (!Directory.Exists(imgDir)) Directory.CreateDirectory(imgDir);

        var pdfFiles = new DirectoryInfo(pdfDir).GetFiles("*.pdf");
        foreach (var file in pdfFiles)
        {
            string destPdf = Path.Combine(imgDir, file.Name);
            // 僅處理新檔或已更新檔
            if (File.Exists(destPdf) && File.GetCreationTime(destPdf) >= file.CreationTime)
                continue;

            // 備份剪貼簿
            var oldData = Clipboard.GetDataObject();
            File.Copy(file.FullName, destPdf, true);

            var doc = new AcroPDDoc();
            doc.Open(file.FullName);
            int pageCount = doc.GetNumPages();

            for (int i = 0; i < pageCount; i++)
            {
                var page = (AcroPDPage)doc.AcquirePage(i);
                var point = (AcroPoint)page.GetSize();
                var rect = new AcroRectClass
                {
                    Left = 0, Top = 0,
                    right = point.x, bottom = point.y
                };

                try
                {
                    if (page.CopyToClipboard(rect, 0, 0, 100)) // 100% 解析度
                    {
                        var pdfData = Clipboard.GetDataObject();
                        var bmp = (Bitmap)pdfData.GetData(DataFormats.Bitmap);
                        if (bmp != null)
                        {
                            string outPath = Path.Combine(imgDir,
                                $"{Path.GetFileNameWithoutExtension(file.Name)}_{i}.jpg");
                            bmp.Save(outPath, ImageFormat.Jpeg);
                            bmp.Dispose();
                        }
                    }
                }
                finally
                {
                    Marshal.ReleaseComObject(page);
                    Marshal.ReleaseComObject(point);
                }
            }

            Clipboard.Clear();
            Marshal.ReleaseComObject(doc);
            if (oldData != null) Clipboard.SetDataObject(oldData);
        }
    }
}

三、關鍵技術細節

項目說明
STA 執行緒Acrobat COM 需單一執行緒單元,`Thread.ApartmentState = STA` + `[STAThread]`
剪貼簿中轉`page.CopyToClipboard` → `Clipboard.GetDataObject().GetData(DataFormats.Bitmap)`
解析度控制`CopyToClipboard` 最後參數 100 代表 100%,可調整品質/大小
COM 物件釋放`Marshal.ReleaseComObject` 逐層釋放,避免 Acrobat 殭屍進程
剪貼簿還原處理前備份、處理後還原,不干擾使用者操作
增量處理比對 `CreationTime` 只轉新檔/異動檔

四、Installer 設定互動桌面權限

[RunInstaller(true)]
public partial class ProjectInstaller : Installer
{
    public ProjectInstaller() { InitializeComponent(); }

    private void ProjectInstaller_AfterInstall(object sender, InstallEventArgs e)
    {
        using (var rk = Registry.LocalMachine)
        using (var sub = rk.CreateSubKey($@"SYSTEM\CurrentControlSet\Services\{serviceInstaller1.ServiceName}"))
        {
            int val = (int)sub.GetValue("Type", 0);
            sub.SetValue("Type", val | 0x100); // 256 = SERVICE_INTERACTIVE_PROCESS
        }
    }
}
  • 設定註冊表 `Type` 第 8 位(0x100),允許服務存取桌面/剪貼簿
  • 否則 `CopyToClipboard` 於 Session 0 隔離環境失敗

五、App.config 部署設定

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <appSettings>
    <add key="pdfFilepath" value="D:\PDFPath\" />
    <add key="imageFilepath" value="D:\ImagePath\" />
  </appSettings>
</configuration>
  • 安裝後修改 `PDFConverterService.exe.config` 即可調整路徑,無需重新編譯

六、部署與驗證步驟

  1. 建置 Setup 專案產生 `Setup.msi`
  2. 目標機器執行安裝(需預裝 Adobe Acrobat Pro,Reader 版無 COM)
  3. 服務管理器啟動「PDFConverter」
  4. 將 PDF 放入 `D:\PDFPath\`,2 秒內 `D:\ImagePath\` 出現同名 JPG
  5. 事件檢視器 → Applications and Services Logs 確認無錯誤

七、已知限制與替代方案

  • 相依 Acrobat Pro:授權成本高、需互動桌面、Server 核心版不支援
  • 替代:Ghostscript (gswin64c.exe)、Pdfium、MuPDF、Aspose.PDF、iTextSharp + PDFRenderer 等無相依庫
  • 現代 .NET Core/5+ 建議改用跨平台庫,避免 COM 與 Windows Service 架構綁定

結語

此方案在「已具 Acrobat Pro 授權、Windows Server 環境、低頻轉檔」場景下快速落地。若追求高併發、跨平台、無授權成本,請評估上述開源/商業庫替代。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved