如何将PDF文件转换为图片

64

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

有没有一种开源解决方案,可以像Acrobat产品那样不收费呢?

15个回答

31

关于将PDF文件转换为JPEG图像的问题,"这个讨论串" 适合您的需求。

解决方案之一是使用第三方库。ImageMagick 是一个非常流行且免费可用的图像处理库。您可以在此处获取其 .NET 封装版本,也可以在这里下载原始 ImageMagick 库文件。

您还可以查看"如何在 C# 中使用 pictureBox 打开 PDF 文件的某一页"这个讨论串。

如果您使用此过程将 PDF 转换为 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];
}

2
.NET封装器也有Nuget包。 - Icad
3
“6种将PDF转换为JPG图像的方法”,这是一篇与编程或C#无关的文章链接,介绍了使用在线工具手动转换PDF的方法。 - Alex P.
在使用Magick.NET转换pdf之前,您需要安装最新版本的GhostScript。 - undefined

25

3
到目前为止,我发现将PDF转换为图像格式的最佳解决方案是+1。RasterizerSample1类确实很有帮助。我使用了Sample1()方法,直接就可以用了。您发布的RasterizerSample链接已经失效,这是我使用的类的链接:https://github.com/jhabjan/Ghostscript.NET/blob/master/Ghostscript.NET.Samples/Samples/RasterizerSample1.cs - blueprintchris
19
请注意,Ghostscript本身采用AGPL许可证,不能在商业项目中免费使用。我建议改用带有C#包装器的Poppler工具(GPL许可证)代替。 - Vitaliy Fedorchenko
这个库的.NET版本在执行简单转换操作时会抛出“OutOfMemory”异常。 - Disappointed
2
我打开PDF后,页面计数为“0”。可能的原因是什么? - Sachintha Nayanajith
1
@SachinthaNayanajith - 看起来是一个未解决的问题:https://github.com/jhabjan/Ghostscript.NET/issues/62 - mche
显示剩余3条评论

12
截至2018年,如何在C#中将PDF文档转换为图像仍然没有简单的答案;许多库使用AGPL许可下的Ghostscript,在大多数情况下,生产使用需要昂贵的商业许可证。
一个很好的替代方案可能是使用流行的'pdftoppm'实用程序,它具有GPL许可证;可以将其作为命令行工具从C#中使用,并通过System.Diagnostics.Process执行。流行的工具在Linux世界中很出名,但有一个Windows版本也可用。
如果您不想自己集成pdftoppm,则可以使用我的PdfRenderer流行的包装器(支持经典的.NET Framework和.NET Core)- 它不是免费的,但价格非常实惠。

1
由于poppler本身是GPL,我不明白如何使用商业封装器(无论其技术质量/功能)能够使poppler在商业(非GPL)产品中使用? - StayOnTarget
PdfRenderer使用poppler工具作为独立的命令行程序(通过System.Diagnostics.Process执行),而不是作为库。这种用法是GPL允许的:https://www.gnu.org/licenses/gpl-faq.html#GPLInProprietarySystem - 当您使用PdfRenderer时,应明确声明您的程序执行了GPL poppler的某些功能,并且用户可以在没有您的程序的情况下使用poppler实用程序作为自由软件。对于Web应用程序,您是最终用户,可以在服务器上安装/使用GPL程序(因为您不会重新分发它)。 - Vitaliy Fedorchenko

11

我在一个.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());
}

你知道如何让批注渲染出来吗?我传递了RenderingFlags.Annotations,但似乎被忽略了。 - undefined
对不起,不,我不知道。 - undefined

8
寻找一个在Windows和Linux上都能使用的强大且免费的dotnet core解决方案,我发现了https://github.com/Dtronix/PDFiumCorehttps://github.com/GowenGit/docnet。由于PDFiumCore使用了更新的Pdfium版本(这似乎是使用pdf库的关键点),所以我最终选择了它。
注意:如果您想在Linux上使用它,建议按照https://dev59.com/JVIH5IYBdhLWcg3wkv70#59252639的建议安装'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


2
NuGet安装,复制,粘贴-> 完美!谢谢! - Marc

8

您可以查看免费软件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 );

可以工作,但无法呈现填充值的PDF字段。 - A. Niese
1
不想说得太刻薄,但这是一个写得很糟糕的Ghostscript.NET封装。 - undefined

8
谷歌Chrome浏览器中使用的PDF引擎名为PDFium,在"BSD 3-clause"许可下是开源的。我相信这允许在商业产品中使用时进行再分发。 有一个名为PdfiumViewer(NuGet)的.NET包装器,我已经尝试过它的功能,效果很好。它采用Apache许可,也允许再分发。
(请注意,这不是需要商业许可的https://pdfium.patagames.com/的“包装器”)
(还有另一个PDFium .NET包装器PDFiumSharp,但我没有评估过。)
在我看来,到目前为止,这可能是最好的开源(免费)PDF库,可以完成工作而不会对使用它们的封闭源/商业软件施加限制。据我所知,在这里的答案中没有其他任何东西能够满足这个标准。

1
注意:PdfiumViewer项目已被存档,不再进行积极开发。:-( gethub/nuget仓库/软件包仍可供下载。 - Jeff
PdfiumCore可以替代PdfiumViewer。请参见下面的回答。 - HamedH

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 wrapper:

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

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


3
这行代码出现错误:page.Render(bitmap); 无法将 'System.Drawing.Bitmap' 转换为 'PDFiumSharp.PDFiumBitmap'。 - CountLessQ
2
如果您没有添加包含在GDI Plus程序集中的RenderingExtensionsGdiPlus类,则会出现预期错误。没有程序集和包含类,它将无法工作。 - Dominik Sand
我该如何添加RenderingExtensionsGdiPlus类?我找不到它... - Rafael Ventura

5
NuGet包Pdf2Png可免费使用,仅受MIT许可证保护,该许可证非常开放。
我进行了一些测试,以下是将PDF文件转换为图像的代码(它确实将图像保存在debug文件夹中)。
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);
        }
    }
}

1
@MaxVollmer 我认为你提出的大部分反馈已经得到解决。 - StayOnTarget
6
当您点击Nuget软件包到项目页面(https://github.com/chen0040/cs-pdf-to-image)时,它提到它使用GhostScript。因此它并没有一开始看起来那么具有许可证优势。 - StayOnTarget
3
我快速测试后发现,1)只转换了多页 PDF 的第一页。2)我测试的 PDF 中字体的图像分辨率很低,输出图像仅为 612×792 像素,这可能是分辨率差的原因。从项目的评论中可以看出,其他人也遇到了同样的问题。 - mike
2
pdf2png软件包的输出质量非常差。 - bmi
你可以下载代码库并更改选项(包括分辨率),创建一个新的dll文件并引用该新的dll文件,图像将具有你设定的分辨率和更好的质量。 - undefined

2

有一个免费的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


1
这是使用itextsharp和pdfium。为什么不首先推荐Pdfium呢? - H.A.H.
2
@H.A.H. 因为使用这个库,作为 itextsharp 和 pdfium 的包装器,你只需要三行代码就可以从 PDF 中提取图像。但如果你更喜欢使用 pdfium 来实现相同的结果,那就随你便吧。 - Kabindas
简单而有效(并且没有GhostScript作为核心,这非常重要,因为它们的许可证)。谢谢! - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接