使用C#在.NET中实现高效提取PDF文档中的图片
作者:大尚来也
在文档处理、内容分析、数据迁移或自动化测试等场景中,开发者常常需要从 PDF 文件中提取嵌入的图像资源——无论是产品手册中的示意图、发票上的二维码,还是报告中的图表。.NET 生态提供了多种库来实现这一目标。本文将详细介绍如何使用 C# 从 PDF 中提取所有图片,并对比主流方案(如 iText 7 和 PdfiumViewer / PdfPig),提供可直接运行的代码示例。
一、为什么提取 PDF 中的图片并不简单
PDF 并非简单的“图片容器”,而是一种复杂的文档格式,其中的图像可能以不同方式存储:
- 嵌入为 JPEG、PNG、CCITT(传真格式)、JBIG2、JPX 等编码;
- 被压缩或加密;
- 作为 XObject(Form XObject 或 Image XObject)存在;
- 甚至被分割成多个片段。
因此,通用、健壮的图片提取依赖于成熟的 PDF 解析库,而非正则表达式或字节扫描。
二、技术选型:主流 .NET 库对比
| 库名 | 类型 | 图片提取支持 | 开源 | 推荐度 |
|---|---|---|---|---|
| iText 7 | 商业/AGPL | ✅ 完整支持 | 部分开源 | ⭐⭐⭐⭐☆ |
| UglyToad.PdfPig | MIT 开源 | ✅ 支持主流格式 | ✅ | ⭐⭐⭐⭐ |
| PdfiumViewer | BSD 开源(基于 Chromium 的 PDFium) | ✅ 可渲染页面截图,但非原始图 | ✅ | ⭐⭐☆ |
| Aspose.PDF | 商业 | ✅ 强大 | ❌ | ⭐⭐⭐⭐(需授权) |
本文重点介绍 PdfPig(纯托管、开源) 和 iText 7(功能全面) 两种方案。
三、方案一:使用 PdfPig(推荐用于开源项目)
PdfPig 是一个纯 C# 编写的 PDF 解析库,无需本地依赖,支持提取原始图像数据。
1. 安装 NuGet 包
Install-Package UglyToad.PdfPig
2. 提取图片代码示例
using UglyToad.PdfPig;
using UglyToad.PdfPig.Content;
using System.Drawing.Imaging;
using System.IO;
class PdfImageExtractor
{
public static void ExtractImagesFromPdf(string pdfPath, string outputFolder)
{
if (!Directory.Exists(outputFolder))
Directory.CreateDirectory(outputFolder);
using (var document = PdfDocument.Open(pdfPath))
{
int imageIndex = 0;
foreach (var page in document.GetPages())
{
foreach (var image in page.GetImages())
{
// 获取原始字节和格式
var bytes = image.Data;
var format = GetImageFormat(image);
if (format != null)
{
string fileName = Path.Combine(outputFolder, $"image_{imageIndex++}.{format}");
File.WriteAllBytes(fileName, bytes);
Console.WriteLine($"Saved: {fileName}");
}
}
}
}
}
private static string? GetImageFormat(XObjectImage image)
{
return image.Type switch
{
"Jpeg" => "jpg",
"Png" => "png",
"Jpx" => "jp2", // JPEG2000
"CCITTFax" => "tiff", // 常见于扫描文档
_ => null // 未知格式暂不处理
};
}
}
3. 调用示例
PdfImageExtractor.ExtractImagesFromPdf("report.pdf", @"./extracted_images");
优点:无外部依赖、跨平台(.NET Core/.NET 5+)、MIT 许可证。
局限:对某些特殊编码(如内联图像、掩码图像)支持有限。
四、方案二:使用 iText 7(适合复杂 PDF)
iText 7 提供更底层的访问能力,可处理几乎所有 PDF 图像类型。
1. 安装 NuGet 包
Install-Package itext7
2. 自定义图像提取策略
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Canvas.Parser;
using iText.Kernel.Pdf.Canvas.Parser.Data;
using iText.Kernel.Pdf.Canvas.Parser.Listener;
using System.IO;
public class ImageExtractor : IRenderListener
{
private readonly string _outputDir;
private int _imageCount = 0;
public ImageExtractor(string outputDir)
{
_outputDir = outputDir;
Directory.CreateDirectory(outputDir);
}
public void BeginTextBlock() { }
public void EndTextBlock() { }
public void RenderText(TextRenderInfo renderInfo) { }
public void RenderImage(ImageRenderInfo renderInfo)
{
try
{
var image = renderInfo.GetImage();
if (image != null)
{
byte[] bytes = image.GetImageAsBytes();
string extension = GetExtension(renderInfo);
string path = Path.Combine(_outputDir, $"itext_img_{_imageCount++}.{extension}");
File.WriteAllBytes(path, bytes);
Console.WriteLine($"Extracted: {path}");
}
}
catch (System.Exception ex)
{
Console.WriteLine($"Failed to extract image: {ex.Message}");
}
}
private string GetExtension(ImageRenderInfo info)
{
var filter = info.GetImage().GetPdfObject().GetAsStream().GetAsName(iText.Kernel.Pdf.PdfName.Filter);
if (filter == null) return "png";
if (filter.Equals(iText.Kernel.Pdf.PdfName.DCTDecode)) return "jpg";
if (filter.Equals(iText.Kernel.Pdf.PdfName.FlateDecode)) return "png";
if (filter.Equals(iText.Kernel.Pdf.PdfName.JPXDecode)) return "jp2";
if (filter.Equals(iText.Kernel.Pdf.PdfName.CCITTFaxDecode)) return "tiff";
return "bin";
}
}
// 使用方法
public static void ExtractWithItext(string pdfPath, string outputDir)
{
using var reader = new PdfReader(pdfPath);
using var pdfDoc = new PdfDocument(reader);
var extractor = new ImageExtractor(outputDir);
for (int i = 1; i <= pdfDoc.GetNumberOfPages(); i++)
{
PdfCanvasProcessor processor = new PdfCanvasProcessor(extractor);
processor.ProcessPageContent(pdfDoc.GetPage(i));
}
}
注意:iText 7 在闭源商业项目中需购买许可证。
五、常见问题与优化建议
Q1:提取的图片模糊?
- 原因:PDF 中图像本身分辨率低,或为矢量图转栅格。
- 建议:优先提取原始嵌入图像,而非页面截图。
Q2:无法提取扫描版 PDF 中的图片?
扫描 PDF 通常整页为一张图像。此时可使用 PdfiumViewer 渲染整页为 PNG:
var bitmap = PdfiumViewer.PdfDocument.Load("scan.pdf").Render(0, 300, 300, true);
bitmap.Save("page.png", ImageFormat.Png);
Q3:如何只提取特定区域的图片?
PdfPig 支持获取图像的边界框(image.Rectangle),可结合坐标过滤。
六、总结
| 方案 | 适用场景 | 优势 | 劣势 |
|---|---|---|---|
| PdfPig | 开源项目、简单到中等复杂 PDF | 纯 C#、无依赖、免费 | 对高级图像格式支持有限 |
| iText 7 | 企业级应用、复杂 PDF | 功能全面、标准兼容 | 商业授权成本 |
| PdfiumViewer | 扫描文档、整页图像 | 渲染质量高 | 无法提取原始嵌入图 |
对于大多数 .NET 开发者,PdfPig 是首选的开源解决方案;若需处理高度复杂的 PDF 或已有 iText 授权,则选择 iText 7。
通过本文提供的代码,你可以快速集成 PDF 图片提取功能,赋能文档智能处理、内容审核或数据归档等应用场景。
到此这篇关于使用C#在.NET中实现高效提取PDF文档中的图片的文章就介绍到这了,更多相关C#提取PDF图片内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
