浅析如何通过C#提取PDF单页与全文档的图片

在C#中提取PDF文档中的图片(包括单页图片和全文档图片)是一个常见的需求,尤其在文档处理、内容分析和数据迁移等场景中。本文将介绍几种主流方法,重点讲解使用 ​iTextSharp(iText7 for .NET)​​ 和 ​PdfPig​ 这两个常用库的操作步骤与代码示例。

图片[1]_浅析如何通过C#提取PDF单页与全文档的图片_知途无界

一、常用工具库简介

1. ​iTextSharp / iText7(推荐用于复杂PDF)​

  • 简介​:iText是业界知名的PDF处理库,支持PDF生成、编辑和内容提取。iTextSharp是其.NET版本(旧版),而iText7是新一代跨平台版本(推荐使用)。
  • 特点​:功能强大,支持加密PDF、复杂布局解析,能精准提取嵌入的图片对象。
  • NuGet包​:
    • iText7核心库:itext7
    • 可选附加组件(如PDF/A支持):itext7.pdfhtml

2. ​PdfPig(轻量级开源方案)​

  • 简介​:基于.NET的开源PDF解析库,专注于文本和图片提取,适合简单场景。
  • 特点​:API简洁,无需处理复杂依赖,但对某些特殊PDF(如图片嵌入方式特殊的文档)支持可能有限。
  • NuGet包​:PdfPig

二、使用iText7提取PDF图片(推荐)

iText7通过解析PDF的XObject对象(包含图片的底层元素)提取图片,支持单页和全文档操作。

1. 安装依赖

在NuGet包管理器中安装:

Install-Package itext7

2. 提取全文档图片

以下代码遍历PDF所有页面,提取每一页中的所有图片并保存到本地:

using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Canvas.Parser;
using iText.Kernel.Pdf.Canvas.Parser.Listener;
using System.IO;

public class PdfImageExtractor
{
    public static void ExtractAllImages(string pdfPath, string outputFolder)
    {
        // 确保输出目录存在
        Directory.CreateDirectory(outputFolder);

        using (PdfReader reader = new PdfReader(pdfPath))
        using (PdfDocument pdfDoc = new PdfDocument(reader))
        {
            int pageCount = pdfDoc.GetNumberOfPages();
            for (int pageNum = 1; pageNum <= pageCount; pageNum++)
            {
                PdfPage page = pdfDoc.GetPage(pageNum);
                // 使用自定义监听器提取当前页图片
                ImageExtractionListener listener = new ImageExtractionListener(outputFolder, pageNum);
                PdfCanvasProcessor processor = new PdfCanvasProcessor(listener);
                processor.ProcessPageContent(page);
            }
        }
    }
}

// 自定义监听器:继承自FilteredImageRenderListener,捕获图片数据
public class ImageExtractionListener : FilteredImageRenderListener
{
    private readonly string _outputFolder;
    private readonly int _pageNum;

    public ImageExtractionListener(string outputFolder, int pageNum) 
        : base(new PdfCanvasProcessor(null), new LocationTextExtractionStrategy())
    {
        _outputFolder = outputFolder;
        _pageNum = pageNum;
    }

    // 重写图片渲染方法(iText7新版需通过PdfResources解析)
    // 注:iText7的图片提取需通过PdfResources和XObject直接获取(下方为更准确的实现)
}

// 更准确的全文档图片提取实现(基于PdfResources)
public static void ExtractAllImagesAccurate(string pdfPath, string outputFolder)
{
    Directory.CreateDirectory(outputFolder);
    using (PdfReader reader = new PdfReader(pdfPath))
    using (PdfDocument pdfDoc = new PdfDocument(reader))
    {
        int imageCounter = 1;
        for (int pageNum = 1; pageNum <= pdfDoc.GetNumberOfPages(); pageNum++)
        {
            PdfPage page = pdfDoc.GetPage(pageNum);
            PdfResources resources = page.GetResources();
            if (resources == null) continue;

            // 获取页面中的XObject(包含图片)
            foreach (var entry in resources.GetResourceNames())
            {
                if (entry.Equals(PdfName.XObject))
                {
                    PdfDictionary xObjects = resources.GetResourceObject(PdfName.XObject) as PdfDictionary;
                    if (xObjects == null) continue;

                    foreach (var xObjEntry in xObjects.GetResourceNames())
                    {
                        PdfName xObjName = xObjEntry;
                        PdfObject xObj = xObjects.Get(xObjName);
                        if (xObj is PdfStream stream && PdfName.Image.Equals(((PdfDictionary)stream).GetAsName(PdfName.Subtype)))
                        {
                            // 提取图片数据
                            byte[] imageBytes = stream.GetBytes();
                            string extension = GetImageExtension(stream);
                            string fileName = $"{outputFolder}/page_{pageNum}_img_{imageCounter++}{extension}";
                            File.WriteAllBytes(fileName, imageBytes);
                        }
                    }
                }
            }
        }
    }
}

// 根据图片流信息获取扩展名(简化版)
private static string GetImageExtension(PdfStream stream)
{
    PdfName subtype = stream.GetAsName(PdfName.Subtype);
    if (subtype == null) return ".png"; // 默认

    // 根据Filter或ColorSpace推断格式(简化逻辑)
    if (stream.ContainsKey(PdfName.Filter) && stream.GetAsName(PdfName.Filter)?.Equals(PdfName.DCTDecode) == true)
        return ".jpg";
    else if (stream.ContainsKey(PdfName.Filter) && stream.GetAsName(PdfName.Filter)?.Equals(PdfName.FlateDecode) == true)
        return ".png";
    else
        return ".png"; // 默认
}

说明:

  • 核心逻辑​:遍历每一页的PdfResources,找到XObject字典中的图片流(Subtype=Image),提取字节数据并保存为文件。
  • 图片格式判断​:通过Filter字段(如DCTDecode对应JPEG,FlateDecode对应PNG)推断扩展名,简化处理中默认使用.png

3. 提取单页图片

若只需提取特定页(如第3页)的图片,只需修改循环范围:

int targetPageNum = 3; // 目标页码
PdfPage page = pdfDoc.GetPage(targetPageNum);
// 后续图片提取逻辑同上(仅处理当前页的resources)

三、使用PdfPig提取PDF图片(轻量级方案)

PdfPig通过解析PDF的页面内容和资源,提取图片数据,适合简单场景。

1. 安装依赖

Install-Package PdfPig

2. 提取全文档图片

using UglyToad.PdfPig;
using UglyToad.PdfPig.Content;
using UglyToad.PdfPig.Graphics.Images;
using System.IO;

public class PdfPigImageExtractor
{
    public static void ExtractAllImages(string pdfPath, string outputFolder)
    {
        Directory.CreateDirectory(outputFolder);
        using (PdfDocument document = PdfDocument.Open(pdfPath))
        {
            int imageCounter = 1;
            foreach (Page page in document.GetPages())
            {
                foreach (var image in page.GetImages())
                {
                    byte[] imageData = image.Data;
                    string extension = GetImageExtension(image);
                    string fileName = $"{outputFolder}/page_{page.Number}_img_{imageCounter++}{extension}";
                    File.WriteAllBytes(fileName, imageData);
                }
            }
        }
    }

    private static string GetImageExtension(PdfImage image)
    {
        // PdfPig的图片格式通常通过Data推断(简化处理)
        // 实际可根据图像头信息判断(如JPEG以FF D8开头)
        return ".png"; // 默认
    }
}

说明:

  • 核心逻辑​:通过page.GetImages()直接获取当前页的所有图片对象,提取字节数据并保存。
  • 优点​:代码简洁,无需深入PDF底层结构。
  • 缺点​:对某些特殊嵌入方式的图片(如内嵌在表单或注释中的图片)可能提取不全。

四、提取单页图片(PdfPig示例)

若只需提取第2页图片:

using (PdfDocument document = PdfDocument.Open(pdfPath))
{
    Page targetPage = document.GetPage(2); // 第2页(页码从1开始)
    foreach (var image in targetPage.GetImages())
    {
        byte[] imageData = image.Data;
        string fileName = $"page_2_img_{1}.png"; // 简化命名
        File.WriteAllBytes(fileName, imageData);
    }
}

五、注意事项与常见问题

  1. 图片格式判断​:
    • iText7和PdfPig提取的图片数据通常是原始字节流,需根据PDF中的Filter字段或图像头信息(如JPEG的FF D8、PNG的89 50 4E 47)判断扩展名(如.jpg.png)。
    • 若不确定格式,可默认保存为.png或通过二进制头分析自动判断。
  2. 加密PDF​:
    • 若PDF受密码保护,需在读取时提供密码(iText7示例): PdfReader reader = new PdfReader(pdfPath, new ReaderProperties().SetPassword("your_password".ToCharArray()));
  3. 性能优化​:
    • 大文档(如数百页)建议逐页处理,避免内存溢出。
    • iText7的性能优于PdfPig,适合复杂或大规模PDF处理。
  4. 特殊嵌入图片​:
    • 某些PDF可能将图片嵌入到表单、注释或图层中,需额外解析(如iText7的PdfFormXObject)。

六、总结

方法适用场景优点缺点
iText7复杂PDF、精准提取功能强大,支持底层XObject解析代码稍复杂,需处理PDF资源结构
PdfPig简单PDF、快速开发API简洁,易上手对特殊嵌入图片支持可能有限

推荐选择​:

  • 若需高可靠性或处理复杂PDF(如加密、多图层),优先使用iText7
  • 若追求快速实现且PDF结构常规,可选择PdfPig

通过上述方法,你可以灵活地在C#中提取PDF的单页或全文档图片,满足文档分析、内容迁移等实际需求。

© 版权声明
THE END
喜欢就点个赞,支持一下吧!
点赞26 分享
评论 抢沙发
头像
欢迎您留下评论!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容