【问题标题】:How to convert PDF files to images如何将 PDF 文件转换为图像
【发布时间】:2014-07-17 07:06:10
【问题描述】:

我需要将 PDF 文件转换为 图像。如果PDF文件是多页,我只需要一张包含所有PDF页面的图片。

有没有像 Acrobat 产品一样不收费的开源解决方案?

【问题讨论】:

    标签: c# image pdf


    【解决方案1】:

    线程converting PDF file to a JPEG image适合你的要求。

    一种解决方案是使用第三方库。 ImageMagick 非常受欢迎,也可以免费获得。你可以得到一个 .NET 包装器here。 ImageMagick 原始下载页面为here

    你也可以看看线程 How to open a page from a pdf file in pictureBox in C#.

    如果你使用this process to convert a PDF to tiff,你可以使用这个类从TIFF检索位图。

    public class TiffImage
    {
        private string myPath;
        private Guid myGuid;
        private FrameDimension myDimension;
        public ArrayList myImages = new ArrayList();
        private int myPageCount;
        private Bitmap myBMP;
    
        public TiffImage(string path)
        {
            MemoryStream ms;
            Image myImage;
    
            myPath = path;
            FileStream fs = new FileStream(myPath, FileMode.Open);
            myImage = Image.FromStream(fs);
            myGuid = myImage.FrameDimensionsList[0];
            myDimension = new FrameDimension(myGuid);
            myPageCount = myImage.GetFrameCount(myDimension);
            for (int i = 0; i < myPageCount; i++)
            {
                ms = new MemoryStream();
                myImage.SelectActiveFrame(myDimension, i);
                myImage.Save(ms, ImageFormat.Bmp);
                myBMP = new Bitmap(ms);
                myImages.Add(myBMP);
                ms.Close();
            }
            fs.Close();
        }
    }
    

    像这样使用它:

    private void button1_Click(object sender, EventArgs e)
    {
        TiffImage myTiff = new TiffImage("D:\\Some.tif");
        //imageBox is a PictureBox control, and the [] operators pass back
        //the Bitmap stored at that position in the myImages ArrayList in the TiffImage
        this.pictureBox1.Image = (Bitmap)myTiff.myImages[0];
        this.pictureBox2.Image = (Bitmap)myTiff.myImages[1];
        this.pictureBox3.Image = (Bitmap)myTiff.myImages[2];
    }
    

    【讨论】:

    • .NET Wrapper 也有一个 Nuget 包
    【解决方案2】:

    您可以使用Ghostscript 将 PDF 转换为图像。

    要使用 .NET 中的 Ghostscript,您可以查看 Ghostscript.NET 库(Ghostscript 库的托管包装器)。

    要使用 Ghostscript.NETPDF 生成 图像,请查看 RasterizerSample

    要将多张图片合并为一张图片,请查看此示例:http://www.niteshluharuka.com/2012/08/combine-several-images-to-form-a-single-image-using-c/#

    【讨论】:

    • +1 这是最好的方法。但是,仅使用 jpeg 无法完成一个 Jpeg 中的多个页面。 Tiff 可能是解决方案。
    • +1 迄今为止我发现的将 PDF 转换为图像格式的最佳解决方案。 RasterizerSample1 类真的很有帮助。我使用了 Sample1() 方法,该方法立即生效。您发布的 RasterizerSample 链接已损坏,这是我使用的课程的链接:github.com/jhabjan/Ghostscript.NET/blob/master/…
    • 请注意,Ghostscript 本身是在 AGPL 下授权的,不能免费用于商业项目。我可能会建议使用 Poppler 工具代替(GPL 许可)和 C# 包装器。
    • 打开 pdf 后,页数为“0”。可能是什么原因?
    • @SachinthaNayanajith - 看起来像一个未解决的问题:github.com/jhabjan/Ghostscript.NET/issues/62
    【解决方案3】:

    至于 2018 年,如何在 C# 中将 PDF 文档转换为图像的问题仍然没有一个简单的答案;许多图书馆使用Ghostscript licensed under AGPL,在大多数情况下,生产使用需要昂贵的商业许可。

    一个不错的选择可能是使用具有GPL 许可证的流行“pdftoppm”实用程序;它可以从 C# 中用作使用 System.Diagnostics.Process 执行的命令行工具。流行的工具在 Linux 世界中是众所周知的,但也可以使用 a windows build

    如果你不想自己集成 pdftoppm,可以使用我的PdfRenderer popular wrapper(同时支持经典 .NET Framework 和.NET Core)——它不是免费的,但价格非常实惠。

    【讨论】:

    • 由于 poppler 本身是 GPL,我不明白使用商业包装器(无论其技术质量/功能如何)如何能够在商业(非 GPL)产品中使用 poppler?
    • PdfRenderer 使用 poppler 工具作为独立的命令行程序(使用 System.Diagnostics.Process 执行),而不是作为库。 GPL 允许这种用法:gnu.org/licenses/gpl-faq.html#GPLInProprietarySystem - 当您使用 PdfRenderer 时,您应该明确说明您的程序为某些功能执行 GPL poppler,并且用户可以在没有您的程序的情况下使用 poppler 实用程序作为免费软件。对于网络应用程序,您是最终用户,您可以在您的服务器上安装/使用 GPL 程序(因为您不会重新分发它)。
    【解决方案4】:

    我在.NET Standard 2.1 类库中使用了PDFiumSharpImageSharp

    /// <summary>
    /// Saves a thumbnail (jpg) to the same folder as the PDF file, using dimensions 300x423,
    /// which corresponds to the aspect ratio of 'A' paper sizes like A4 (ratio h/w=sqrt(2))
    /// </summary>
    /// <param name="pdfPath">Source path of the pdf file.</param>
    /// <param name="thumbnailPath">Target path of the thumbnail file.</param>
    /// <param name="width"></param>
    /// <param name="height"></param>
    public static void SaveThumbnail(string pdfPath, string thumbnailPath = "", int width = 300, int height = 423)
    {
        using var pdfDocument = new PdfDocument(pdfPath);
        var firstPage = pdfDocument.Pages[0];
    
        using var pageBitmap = new PDFiumBitmap(width, height, true);
    
        firstPage.Render(pageBitmap);
    
        var imageJpgPath = string.IsNullOrWhiteSpace(thumbnailPath)
            ? Path.ChangeExtension(pdfPath, "jpg")
            : thumbnailPath;
        var image = Image.Load(pageBitmap.AsBmpStream());
    
        // Set the background to white, otherwise it's black. https://github.com/SixLabors/ImageSharp/issues/355#issuecomment-333133991
        image.Mutate(x => x.BackgroundColor(Rgba32.White));
    
        image.Save(imageJpgPath, new JpegEncoder());
    }
    

    【讨论】:

      【解决方案5】:

      Google Chrome 中使用的 PDF 引擎,名为 PDFium,在“BSD 3-clause”许可下是开源的。我相信这允许在商业产品中使用时重新分发。

      它有一个名为PdfiumViewer (NuGet) 的.NET 包装器,在我尝试过的范围内效果很好。它在 Apache 许可下也允许重新分发。

      (请注意,这与需要商业许可证的https://pdfium.patagames.com/ 的“包装器”不同*)

      (还有另一个 PDFium .NET 包装器,PDFiumSharp,但我没有评估它。)

      在我看来,到目前为止,这可能是开源(像啤酒一样免费)PDF 库的最佳选择来完成对封闭源代码/使用它们的软件的商业性质。据我所知,我认为这里的答案中没有任何其他内容符合该标准。

      【讨论】:

      • 注意:PdfiumViewer 项目已存档,尚未积极开发。 :-( gethub/nuget 存储库/包仍然可供下载。
      • PdfiumCore 可以替代 PdfiumViewer。请参阅下面的答案。
      【解决方案6】:

      关于PDFiumSharp:经过详细阐述,我能够从 PDF 解决方案创建 PNG 文件。

      这是我的代码:

      using PDFiumSharp;
      using System.Collections.Generic;
      using System.Drawing;
      using System.IO;
      
      public class Program
      {
          static public void Main(String[] args)
          {
              var renderfoo = new Renderfoo()
              renderfoo.RenderPDFAsImages(@"C:\Temp\example.pdf", @"C:\temp");
          }
      }
      
      
      
      public class Renderfoo
      {
      
          public void RenderPDFAsImages(string Inputfile, string OutputFolder)
          {
              string fileName = Path.GetFileNameWithoutExtension(Inputfile);
      
              using (PDFiumSharp.PdfDocument doc = new PDFiumSharp.PdfDocument(Inputfile))
              {
                  for (int i = 0; i < doc.Pages.Count; i++)
                  {
                      var page = doc.Pages[i];
                      using (var bitmap = new System.Drawing.Bitmap((int)page.Width, (int)page.Height))
                      {
                          var grahpics = Graphics.FromImage(bitmap);
                          grahpics.Clear(Color.White);
                          page.Render(bitmap);
                          var targetFile = Path.Combine(OutputFolder, fileName + "_" + i + ".png");
                          bitmap.Save(targetFile);
                      }
                  }
              }
          }
      
      }
      

      对于初学者,您需要执行以下步骤来启动和运行 PDFium 包装器:

      • 在 Visual Studio 中通过右键单击为两个 tt 文件运行 自定义代码 工具
      • 编译 GDIPlus 项目
      • 将已编译的程序集(从 GDIPlus 项目中)复制到您的项目中
      • 在您的项目中同时引用 PDFiumSharpPDFiumsharp.GdiPlus 程序集

      • 确保 pdfium_x64.dll 和/或 pdfium_x86.dll 都在您的项目输出目录中。

      【讨论】:

      • 无法将此行从“System.Drawing.Bitmap”转换为“PDFiumSharp.PDFiumBitmap:page.Render(bitmap);
      • 如果您不添加包含在 GDI Plus 程序集中的类 RenderingExtensionsGdiPlus ,则会出现错误。如果没有 Assembly 和包含的类,它将无法工作。
      • 如何添加 RenderingExtensionsGdiPlus 类?我找不到它...
      【解决方案7】:

      在 Windows 和 Linux 上寻找强大且免费的 dotnet core 解决方案让我找到了https://github.com/Dtronix/PDFiumCorehttps://github.com/GowenGit/docnet。由于 PDFiumCore 使用更新版本的 Pdfium(这似乎是使用 pdf 库的关键点),我最终使用了它。

      注意:如果你想在 Linux 上使用它,你应该按照https://stackoverflow.com/a/59252639/6339469 的建议安装“libgdiplus”。

      这是一个简单的单线程代码:

      var pageIndex = 0;
      var scale = 2;
      
      fpdfview.FPDF_InitLibrary();
      
      var document = fpdfview.FPDF_LoadDocument("test.pdf", null);
      
      var page = fpdfview.FPDF_LoadPage(document, pageIndex);
      
      var size = new FS_SIZEF_();
      fpdfview.FPDF_GetPageSizeByIndexF(document, 0, size);
      
      var width = (int)Math.Round(size.Width * scale);
      var height = (int)Math.Round(size.Height * scale);
      
      var bitmap = fpdfview.FPDFBitmapCreateEx(
          width,
          height,
          4, // BGRA
          IntPtr.Zero,
          0);
      
      fpdfview.FPDFBitmapFillRect(bitmap, 0, 0, width, height, (uint)Color.White.ToArgb());
      
      // |          | a b 0 |
      // | matrix = | c d 0 |
      // |          | e f 1 |
      using var matrix = new FS_MATRIX_();
      using var clipping = new FS_RECTF_();
      
      matrix.A = scale;
      matrix.B = 0;
      matrix.C = 0;
      matrix.D = scale;
      matrix.E = 0;
      matrix.F = 0;
      
      clipping.Left = 0;
      clipping.Right = width;
      clipping.Bottom = 0;
      clipping.Top = height;
      
      fpdfview.FPDF_RenderPageBitmapWithMatrix(bitmap, page, matrix, clipping, (int)RenderFlags.RenderAnnotations);
      
      var bitmapImage = new Bitmap(
          width,
          height,
          fpdfview.FPDFBitmapGetStride(bitmap),
          PixelFormat.Format32bppArgb,
          fpdfview.FPDFBitmapGetBuffer(bitmap));
      
      bitmapImage.Save("test.jpg", ImageFormat.Jpeg);
      

      有关线程安全的实现,请参见: https://github.com/hmdhasani/DtronixPdf/blob/master/src/DtronixPdfBenchmark/Program.cs

      【讨论】:

        【解决方案8】:

        Apache PDFBox 也很适合我。

        使用命令行工具:

        javar -jar pdfbox-app-2.0.19.jar PDFToImage -quality 1.0  -dpi 150 -prefix out_dir/page -format png
        

        【讨论】:

        • 谢谢,我不知道pdfbox有DPI参数。
        【解决方案9】:

        使用 AppCompat 等 Android 默认库,您可以将所有 PDF 页面转换为图像。这种方式非常快速且经过优化。 以下代码用于获取 PDF 页面的单独图像。速度非常快。

        ParcelFileDescriptor fileDescriptor = ParcelFileDescriptor.open(new File("pdfFilePath.pdf"), MODE_READ_ONLY);
            PdfRenderer renderer = new PdfRenderer(fileDescriptor);
            final int pageCount = renderer.getPageCount();
            for (int i = 0; i < pageCount; i++) {
                PdfRenderer.Page page = renderer.openPage(i);
                Bitmap bitmap = Bitmap.createBitmap(page.getWidth(), page.getHeight(),Bitmap.Config.ARGB_8888);
                Canvas canvas = new Canvas(bitmap);
                canvas.drawColor(Color.WHITE);
                canvas.drawBitmap(bitmap, 0, 0, null);
                page.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
                page.close();
        
                if (bitmap == null)
                    return null;
        
                if (bitmapIsBlankOrWhite(bitmap))
                    return null;
        
                String root = Environment.getExternalStorageDirectory().toString();
                File file = new File(root + filename + ".png");
        
                if (file.exists()) file.delete();
                try {
                    FileOutputStream out = new FileOutputStream(file);
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
                    Log.v("Saved Image - ", file.getAbsolutePath());
                    out.flush();
                    out.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        

        ================================================ ========

        private static boolean bitmapIsBlankOrWhite(Bitmap bitmap) {
            if (bitmap == null)
                return true;
        
            int w = bitmap.getWidth();
            int h = bitmap.getHeight();
            for (int i =  0; i < w; i++) {
                for (int j = 0; j < h; j++) {
                    int pixel =  bitmap.getPixel(i, j);
                    if (pixel != Color.WHITE) {
                        return false;
                    }
                }
            }
            return true;
        }
        

        【讨论】:

          【解决方案10】:

          NuGet 包Pdf2Png 是免费提供的,仅受MIT License 保护,非常开放。

          我已经测试了一下,这是让它将 PDF 文件转换为图像的代码(tt 确实将图像保存在调试文件夹中)。

          using cs_pdf_to_image;
          using PdfToImage;
          
          private void BtnConvert_Click(object sender, EventArgs e)
          {
              if(openFileDialog1.ShowDialog() == DialogResult.OK)
              {
                  try
                  {
                      string PdfFile = openFileDialog1.FileName;
                      string PngFile = "Convert.png";
                      List<string> Conversion = cs_pdf_to_image.Pdf2Image.Convert(PdfFile, PngFile);
                      Bitmap Output = new Bitmap(PngFile);
                      PbConversion.Image = Output;
                  }
                  catch(Exception E)
                  {
                      MessageBox.Show(E.Message);
                  }
              }
          }
          

          【讨论】:

          • @MaxVollmer 我认为您的大部分反馈都已得到解决。
          • 当您单击 Nuget 包到项目页面 (github.com/chen0040/cs-pdf-to-image) 时,它会提到它使用 GhostScript。因此,它没有最初出现的许可优势。
          • 我快速测试发现1),只转换多页PDF的第一页。 2),我测试的PDF字体的图像分辨率很差,输出图像只有612 × 792px,所以这可能是分辨率差的原因。从项目的 cmets 看来,其他人似乎也面临同样的问题。
          • pdf2png 包的输出质量很差。
          【解决方案11】:

          有一个免费的 nuget 包 (Pdf2Image),它允许在一行中将 pdf 页面提取为 jpg 文件或图像集合 (List)

                  string file = "c:\\tmp\\test.pdf";
          
                  List<System.Drawing.Image> images = PdfSplitter.GetImages(file, PdfSplitter.Scale.High);
          
                  PdfSplitter.WriteImages(file, "c:\\tmp", PdfSplitter.Scale.High, PdfSplitter.CompressionLevel.Medium);
          

          所有源码也可以在 github 上找到Pdf2Image

          【讨论】:

            【解决方案12】:

            您可以查看 Freeware.Pdf2Png MIT 许可证。 只需在您的 nuget 中找到这些名称即可。

            var dd = System.IO.File.ReadAllBytes("pdffile.pdf");
            byte[] pngByte = Freeware.Pdf2Png.Convert(dd, 1);
            System.IO.File.WriteAllBytes(Path.Combine(@"C:\temp", "dd.png"), pngByte );
            

            【讨论】:

              【解决方案13】:

              我在 SourceForge 遇到了这个项目。在我看来它仍然处于活动状态。

              1. PDF convert to JPEG at SourceForge
              2. Developer's site

              我的两分钱。

              【讨论】:

                【解决方案14】:

                https://www.codeproject.com/articles/317700/convert-a-pdf-into-a-series-of-images-using-csharp

                我发现这个 GhostScript 包装器在将 PDF 逐页转换为 PNG 时非常有效。

                用法:

                string pdf_filename = @"C:\TEMP\test.pdf";            
                var pdf2Image = new Cyotek.GhostScript.PdfConversion.Pdf2Image(pdf_filename);
                for (var page = 1; page < pdf2Image.PageCount; page++)
                {
                    string png_filename = @"C:\TEMP\test" + page + ".png";
                    pdf2Image.ConvertPdfPageToImage(png_filename, page);
                }
                

                基于 GhostScript 构建,显然对于商业应用,许可问题仍然存在。

                【讨论】:

                  【解决方案15】:

                  (免责声明我曾在 Software Siglo XXI 开发过这个组件)

                  您可以使用 Super Pdf2Image Converter 生成一个 TIFF 多页文件,其中包含 PDF 中所有呈现的高分辨率页面。它适用于 32 位和 64 位,并且非常便宜且有效。我建议你试试看。

                  只需一行代码...

                  GetImage(outputFileName, firstPage, lastPage, resolution, imageFormat)
                  
                  Converts specifies pages to image and save them to outputFileName (tiff allows multi-page or creates several files)
                  

                  你可以看这里:http://softwaresigloxxi.com/SuperPdf2ImageConverter.html

                  【讨论】:

                  • 404 - 死链接
                  猜你喜欢
                  • 2013-08-13
                  • 1970-01-01
                  • 2012-07-28
                  • 2016-08-16
                  • 2012-09-01
                  • 1970-01-01
                  • 2020-04-19
                  • 2016-07-18
                  • 1970-01-01
                  相关资源
                  最近更新 更多