【C#】PDF 應用(輸出圖檔、合併圖片)

最近遇到一個需求,比較沒涉略。

因應無紙化作業,要將數位簽名的圖檔合併到PDF中,並且轉成圖檔留存。

PDF加入圖檔使用:itextsharp

PDF轉圖檔有找出兩種方案:

先處理數位簽名檔合併到PDF中。

參考了 [itextsharp][006]加入image到pdf(add image to pdf)  作者:kevinya

蠻完整的寫出了三種方式加入。

這次需求只需要固定在左下角固定位置簽入簽名檔,所以我們採用絕對位置來設計。

        /// <summary>
        ///     將PDF檔與簽名檔合併
        /// </summary>
        /// <param name="outPdfPath">PDF輸出的檔案路徑</param>
        /// <param name="oriPdfFullPath">原始PDF檔案完整路徑</param>
        /// <param name="signFileFullPath">簽名檔檔案完整路徑</param>
        /// <param name="outPdfFileName">合併後輸出的檔案名稱</param>
        private static void MergeSign(string outPdfPath, string oriPdfFullPath, string signFileFullPath,
            out string outPdfFileName)
        {
            outPdfFileName = GetUniqueFileName(".pdf", outPdfPath);

            using (var reader = new PdfReader(oriPdfFullPath))
            using (var stamper = new PdfStamper(reader,
                new FileStream(Path.Combine(outPdfPath, outPdfFileName), FileMode.Create)))
            {
                var pageCount = reader.NumberOfPages;

                for (var i = 1; i <= pageCount; i++)
                {
                    var content = stamper.GetOverContent(i);

                    var image = iTextSharp.text.Image.GetInstance(signFileFullPath);
                    image.ScaleAbsolute(100, 100);
                    image.SetAbsolutePosition(70, 10);
                    content.AddImage(image);
                }
            }
        }

GetUniqueFileName 就是一個取得檔名的Function,這邊就不贅述。

這次需求是一份PDF可能是N頁的簽收單,所以,我們需要跑一個迴圈來處理。

再來,我們處理PDF匯出圖檔,這部分說真的卡比較久,沒想到參考資源一直找錯方向。

一開始因為找的解決方案,都會要求要先安裝東西在主機上,這不是我想使用的方案。

當時就有看到 Ghostscript 但沒採用。

試用了 NReco.PdfRenderer ,官方Demo只要短短4行就解決了。

var pdfFile = "Sample1.pdf";
var pdfToImg = new NReco.PdfRenderer.PdfToImageConverter();
pdfToImg.ScaleTo = 200; // fit 200x200 box
pdfToImg.GenerateImage( pdfFile, 1, ImageFormat.Jpeg, "Sample1.jpg" );

原本卡要刷下去了,但又回頭看了一下Gostscript。

NuGet搜尋Gostscript,跳出來了 Ghostscript.NET

直覺這東西肯定可以打救我。

果然,符合我想要的,雖然他依賴著Gostscript,但是主機不一定要先安裝。

只需要擁有Dll檔。

        private static GhostscriptVersionInfo GetGhostscriptVersionInfo()
        {
            var path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);

            var vesion = new GhostscriptVersionInfo(new Version(0, 0, 0), path + @"\gsdll32.dll", string.Empty,
                GhostscriptLicense.GPL);

            return vesion;
        }

之後透過 GhostscriptRasterizer 來達成。

        private static void PdfToImage(string outPdfTempImagePath, string outPdfImagePath, string file,
            out string outImageFileName)
        {
            var tempFiles = new List<string>();

            using (var rasterizer = new GhostscriptRasterizer())
            {
                rasterizer.Open(file, GhostScriptVersion, false);

                for (var i = 1; i <= rasterizer.PageCount; i++)
                {
                    var fileName = Path.Combine(outPdfTempImagePath, GetUniqueFileName(".png", outPdfTempImagePath));
                    tempFiles.Add(fileName);

                    var img = rasterizer.GetPage(DesiredXDpi, DesiredYDpi, i);

                    if (i == 1)
                        img.Save(fileName, ImageFormat.Png);
                    else
                    {
                        img.RotateFlip(RotateFlipType.Rotate90FlipNone);
                        img.Save(fileName, ImageFormat.Png);
                    }
                }
                rasterizer.Close();
            }

            outImageFileName = GetUniqueFileName(".png", outPdfImagePath);
            MergeImages(tempFiles).Save(Path.Combine(outPdfImagePath, outImageFileName));
        }

這邊也是一頁一頁的匯出圖檔,又很特別轉圖檔第二張之後會變成橫向,所以,我們還要再轉個角度。(這部分還沒驗證是否為來源PDF的問題)。

一頁一頁匯出後,我在自己做合併的動作。

完整程式放在:GitHub