【问题标题】:Extract image from PDF using itextsharp使用 itextsharp 从 PDF 中提取图像
【发布时间】:2011-08-22 03:52:32
【问题描述】:

我正在尝试使用 itextsharp 从 pdf 中提取所有图像,但似乎无法克服这一障碍。

错误发生在System.Drawing.Image ImgPDF = System.Drawing.Image.FromStream(MS); 行,给出“参数无效”的错误。

我认为当图像是位图但不是任何其他格式时它可以工作。

我有以下代码 - 抱歉,篇幅较长;

    private void Form1_Load(object sender, EventArgs e)
    {
        FileStream fs = File.OpenRead(@"reader.pdf");
        byte[] data = new byte[fs.Length];
        fs.Read(data, 0, (int)fs.Length);

        List<System.Drawing.Image> ImgList = new List<System.Drawing.Image>();

        iTextSharp.text.pdf.RandomAccessFileOrArray RAFObj = null;
        iTextSharp.text.pdf.PdfReader PDFReaderObj = null;
        iTextSharp.text.pdf.PdfObject PDFObj = null;
        iTextSharp.text.pdf.PdfStream PDFStremObj = null;

        try
        {
            RAFObj = new iTextSharp.text.pdf.RandomAccessFileOrArray(data);
            PDFReaderObj = new iTextSharp.text.pdf.PdfReader(RAFObj, null);

            for (int i = 0; i <= PDFReaderObj.XrefSize - 1; i++)
            {
                PDFObj = PDFReaderObj.GetPdfObject(i);

                if ((PDFObj != null) && PDFObj.IsStream())
                {
                    PDFStremObj = (iTextSharp.text.pdf.PdfStream)PDFObj;
                    iTextSharp.text.pdf.PdfObject subtype = PDFStremObj.Get(iTextSharp.text.pdf.PdfName.SUBTYPE);

                    if ((subtype != null) && subtype.ToString() == iTextSharp.text.pdf.PdfName.IMAGE.ToString())
                    {
                        byte[] bytes = iTextSharp.text.pdf.PdfReader.GetStreamBytesRaw((iTextSharp.text.pdf.PRStream)PDFStremObj);

                        if ((bytes != null))
                        {
                            try
                            {
                                System.IO.MemoryStream MS = new System.IO.MemoryStream(bytes);

                                MS.Position = 0;
                                System.Drawing.Image ImgPDF = System.Drawing.Image.FromStream(MS);

                                ImgList.Add(ImgPDF);

                            }
                            catch (Exception)
                            {
                            }
                        }
                    }
                }
            }
            PDFReaderObj.Close();
        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message);
        }



    } //Form1_Load

【问题讨论】:

标签: c# image pdf itextsharp


【解决方案1】:

您需要检查流的 /Filter 以查看给定图像使用的图像格式。可能是标准图片格式:

  • DCT解码 (jpeg)
  • JPX 解码 (jpeg 2000)
  • JBIG2Decode(jbig 是一种纯黑白格式)
  • CCITTFaxDecode(传真格式,PDF 支持组 3 和 4)

除此之外,您需要获取原始字节(原样),并使用图像流的宽度、高度、每个组件的位数、颜色组件的数量(可以是 CMYK、索引、RGB ,或奇怪的东西),以及其他一些,如ISO PDF SPECIFICATION 的第 8.9 节中所定义(免费提供)。

所以在某些情况下你的代码会工作,但在其他情况下,它会因为你提到的异常而失败。

PS:当您遇到异常时,请每次都包含堆栈跟踪。很高兴在上面加糖?

【讨论】:

  • +1 @Mark Storer,对 StackTrace 感到抱歉。下次会做。当一个简单的 500 美元的图书馆就可以完成这项工作时,这听起来像是很多 faffen 来获取图像吧?我不是一个图形人,所以我想我会让公司买点东西。也谢谢你的回答。
【解决方案2】:

我过去使用过这个库没有任何问题。

http://www.winnovative-software.com/PdfImgExtractor.aspx

private void btnExtractImages_Click(object sender, EventArgs e)
{
    if (pdfFileTextBox.Text.Trim().Equals(String.Empty))
    {
        MessageBox.Show("Please choose a source PDF file", "Choose PDF file", MessageBoxButtons.OK);
        return;
    }

    // the source pdf file
    string pdfFileName = pdfFileTextBox.Text.Trim();

    // start page number
    int startPageNumber = int.Parse(textBoxStartPage.Text.Trim());
    // end page number
    // when it is 0 the extraction will continue up to the end of document
    int endPageNumber = 0;
    if (textBoxEndPage.Text.Trim() != String.Empty)
        endPageNumber = int.Parse(textBoxEndPage.Text.Trim());

    // create the PDF images extractor object
    PdfImagesExtractor pdfImagesExtractor = new PdfImagesExtractor();

    pdfImagesExtractor.LicenseKey = "31FAUEJHUEBQRl5AUENBXkFCXklJSUlQQA==";

    // the demo output directory
    string outputDirectory = Path.Combine(Application.StartupPath, @"DemoFiles\Output");

    Cursor = Cursors.WaitCursor;

    // set the handler to be called when an image was extracted
    pdfImagesExtractor.ImageExtractedEvent += pdfImagesExtractor_ImageExtractedEvent;

    try
    {
        // start images counting
        imageIndex = 0;

        // call the images extractor to raise the ImageExtractedEvent event when an images is extracted from a PDF page
        // the pdfImagesExtractor_ImageExtractedEvent handler below will be executed for each extracted image
        pdfImagesExtractor.ExtractImagesInEvent(pdfFileName, startPageNumber, endPageNumber);

        // Alternatively you can use the ExtractImages() and ExtractImagesToFile() methods
        // to extracted the images from a PDF document in memory or to image files in a directory

        // uncomment the line below to extract the images to an array of ExtractedImage objects
        //ExtractedImage[] pdfPageImages = pdfImagesExtractor.ExtractImages(pdfFileName, startPageNumber, endPageNumber);

        // uncomment the lines below to extract the images to image files in a directory
        //string outputDirectory = System.IO.Path.Combine(Application.StartupPath, @"DemoFiles\Output");
        //pdfImagesExtractor.ExtractImagesToFile(pdfFileName, startPageNumber, endPageNumber, outputDirectory, "pdfimage");
    }
    catch (Exception ex)
    {
        // The extraction failed
        MessageBox.Show(String.Format("An error occurred. {0}", ex.Message), "Error");
        return;
    }
    finally
    {
        // uninstall the event handler
        pdfImagesExtractor.ImageExtractedEvent -= pdfImagesExtractor_ImageExtractedEvent;

        Cursor = Cursors.Arrow;
    }

    try
    {
        System.Diagnostics.Process.Start(outputDirectory);
    }
    catch (Exception ex)
    {
        MessageBox.Show(string.Format("Cannot open output folder. {0}", ex.Message));
        return;
    }
}

/// <summary>
/// The ImageExtractedEvent event handler called after an image was extracted from a PDF page.
/// The event is raised when the ExtractImagesInEvent() method is used
/// </summary>
/// <param name="args">The handler argument containing the extracted image and the PDF page number</param>
void pdfImagesExtractor_ImageExtractedEvent(ImageExtractedEventArgs args)
{
    // get the image object and page number from even handler argument
    Image pdfPageImageObj = args.ExtractedImage.ImageObject;
    int pageNumber = args.ExtractedImage.PageNumber;

    // save the extracted image to a PNG file
    string outputPageImage = Path.Combine(Application.StartupPath, @"DemoFiles\Output", 
        "pdfimage_" + pageNumber.ToString() + "_" + imageIndex++ + ".png");
    pdfPageImageObj.Save(outputPageImage, ImageFormat.Png);

    args.ExtractedImage.Dispose();
}

【讨论】:

  • 实际上,我们正在使用它。对大多数事情都非常有效。
  • @MohamedSakherSawan 好的,很好。
【解决方案3】:

要提取所有页面上的所有图像,无需实施不同的过滤器。 iTextSharp 有一个图像渲染器,它将所有图像保存为其原始图像类型。

只需执行此处找到的以下操作:http://kuujinbo.info/iTextSharp/CCITTFaxDecodeExtract.aspx 你不需要实现 HttpHandler...

【讨论】:

  • 我真希望你已经包含了代码——那个链接已经失效了。
  • 呃,没有。自 2011 年 11 月 27 日以来,它一直在运行并且未更改。一定是在糟糕的一天访问了共享服务器。
【解决方案4】:

已解决...

即使我遇到了“参数无效”的相同异常,并且经过这么多 在 der_chirurg 提供的链接的帮助下工作 (http://kuujinbo.info/iTextSharp/CCITTFaxDecodeExtract.aspx)我解决了 以下是代码:

using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using iTextSharp.text.pdf.parser;
using Dotnet = System.Drawing.Image;
using iTextSharp.text.pdf;

namespace PDF_Parsing
{
    partial class PDF_ImgExtraction
    {
        string imgPath;
        private void ExtractImage(string pdfFile)
        {
            PdfReader pdfReader = new PdfReader(files[fileIndex]);
            for (int pageNumber = 1; pageNumber <= pdfReader.NumberOfPages; pageNumber++)
            {
                PdfReader pdf = new PdfReader(pdfFile);
                PdfDictionary pg = pdf.GetPageN(pageNumber);
                PdfDictionary res = (PdfDictionary)PdfReader.GetPdfObject(pg.Get(PdfName.RESOURCES));
                PdfDictionary xobj = (PdfDictionary)PdfReader.GetPdfObject(res.Get(PdfName.XOBJECT));
                foreach (PdfName name in xobj.Keys)
                {
                    PdfObject obj = xobj.Get(name);
                    if (obj.IsIndirect())
                    {
                        PdfDictionary tg = (PdfDictionary)PdfReader.GetPdfObject(obj);
                        string width = tg.Get(PdfName.WIDTH).ToString();
                        string height = tg.Get(PdfName.HEIGHT).ToString();
                        ImageRenderInfo imgRI = ImageRenderInfo.CreateForXObject(new Matrix(float.Parse(width), float.Parse(height)), (PRIndirectReference)obj, tg);
                        RenderImage(imgRI);
                    }
                }
            }
        }
        private void RenderImage(ImageRenderInfo renderInfo)
        {
            PdfImageObject image = renderInfo.GetImage();
            using (Dotnet dotnetImg = image.GetDrawingImage())
            {
                if (dotnetImg != null)
                {
                    using (MemoryStream ms = new MemoryStream())
                    {
                        dotnetImg.Save(ms, ImageFormat.Tiff);
                        Bitmap d = new Bitmap(dotnetImg);
                        d.Save(imgPath);
                    }
                }
            }
        }
    }
}

【讨论】:

  • 嗨,谢谢,您的解决方案对我有帮助,但在一个 pdf xobj.Keys 中返回每个页面的所有页面的所有图像。你知道为什么吗?
【解决方案5】:

在较新版本的 iTextSharp 中,ImageRenderInfo.CreateForXObject 的第一个参数不再是 Matrix,而是 GraphicsState。 @der_chirurg 的方法应该有效。我使用以下链接中的信息对自己进行了测试,效果很好:

http://www.thevalvepage.com/swmonkey/2014/11/26/extract-images-from-pdf-files-using-itextsharp/

【讨论】:

  • 您好,欢迎来到 SO 并感谢您的回答。由于链接会随着时间而变化,您能否编辑您的答案以在此处包含相关信息?您仍然可以提供上下文链接。谢谢!
【解决方案6】:

这对我有用,我认为这是一个简单的解决方案:

编写一个自定义的 RenderListener 并实现它的 RenderImage 方法,像这样

    public void RenderImage(ImageRenderInfo info)
    {
        PdfImageObject image = info.GetImage();
        Parser.Matrix matrix = info.GetImageCTM();
        var fileType = image.GetFileType();
        ImageFormat format;
        switch (fileType)
        {//you may add more types here
            case "jpg":
            case "jpeg":
                format = ImageFormat.Jpeg;
                break;
            case "pnt":
                format = ImageFormat.Png;
                break;
            case "bmp":
                format = ImageFormat.Bmp;
                break;
            case "tiff":
                format = ImageFormat.Tiff;
                break;
            case "gif":
                format = ImageFormat.Gif;
                break;
            default:
                format = ImageFormat.Jpeg;
                break;
        }

        var pic = image.GetDrawingImage();
        var x = matrix[Parser.Matrix.I31];
        var y = matrix[Parser.Matrix.I32];
        var width = matrix[Parser.Matrix.I11];
        var height = matrix[Parser.Matrix.I22];
        if (x < <some value> && y < <some value>)
        {
            return;//ignore these images
        }

        pic.Save(<path and name>, format);
}

【讨论】:

    【解决方案7】:

    我在 github 上添加了库,将图像提取为 PDF 并压缩。

    当您要开始使用非常强大的库 ITextSharp 时可能会很有用。

    这里是链接:https://github.com/rock-walker/PdfCompression

    【讨论】:

    • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
    • 我被详细阐述了有关 PDF 压缩(主要是提取图像和压缩它们)的任务 2 个月。并且整个 SO 和其他资源都没有统一的示例,如何处理诸如 itextsharp、提取图像、压缩 PDF 之类的东西。我在 SO 中组装了很多小数据以获得最终的工作库。我真的相信,我的端到端示例可以被视为那些要做同样事情的人的起点。
    • 我不认为你的图书馆有什么问题!只是 Stack Overflow 的政策明确不鼓励仅作为外部站点链接的答案。 SO的目的是人们应该学习;他们不仅会找到解决当前问题的方法。
    • 啊,我不想与 SO 政策争论。根据我的经验,我从外部链接中学到了很多东西,只有少数链接被破坏了。有时深入解决问题是件好事。好吧,这是我的观点。由我决定:)
    【解决方案8】:

    像这样为我工作,使用这两种方法:

        public static List<System.Drawing.Image> ExtractImagesFromPDF(byte[] bytes)
        {
            var imgs = new List<System.Drawing.Image>();
            var pdf = new PdfReader(bytes);
    
            try
            {
                for (int pageNumber = 1; pageNumber <= pdf.NumberOfPages; pageNumber++)
                {
                    PdfDictionary pg = pdf.GetPageN(pageNumber);
                    List<PdfObject> objs = FindImageInPDFDictionary(pg);
    
                    foreach (var obj in objs)
                    {
                        if (obj != null)
                        {
                            int XrefIndex = Convert.ToInt32(((PRIndirectReference)obj).Number.ToString(System.Globalization.CultureInfo.InvariantCulture));
                            PdfObject pdfObj = pdf.GetPdfObject(XrefIndex);
                            PdfStream pdfStrem = (PdfStream)pdfObj;
                            var pdfImage = new PdfImageObject((PRStream)pdfStrem);
                            var img = pdfImage.GetDrawingImage();
    
                            imgs.Add(img);
                        }
                    }
                }
            }
            finally
            {
                pdf.Close();
            }
    
            return imgs;
        }
    
        private static List<PdfObject> FindImageInPDFDictionary(PdfDictionary pg)
        {
            var res = (PdfDictionary)PdfReader.GetPdfObject(pg.Get(PdfName.RESOURCES));
            var xobj = (PdfDictionary)PdfReader.GetPdfObject(res.Get(PdfName.XOBJECT));
            var pdfObgs = new List<PdfObject>();
    
            if (xobj != null)
            {
                foreach (PdfName name in xobj.Keys)
                {
                    PdfObject obj = xobj.Get(name);
                    if (obj.IsIndirect())
                    {
                        var tg = (PdfDictionary)PdfReader.GetPdfObject(obj);
                        var type = (PdfName)PdfReader.GetPdfObject(tg.Get(PdfName.SUBTYPE));
    
                        if (PdfName.IMAGE.Equals(type)) // image at the root of the pdf
                        {
                            pdfObgs.Add(obj);
                        }
                        else if (PdfName.FORM.Equals(type)) // image inside a form
                        {
                            FindImageInPDFDictionary(tg).ForEach(o => pdfObgs.Add(o));
                        }
                        else if (PdfName.GROUP.Equals(type)) // image inside a group
                        {
                            FindImageInPDFDictionary(tg).ForEach(o => pdfObgs.Add(o));
                        }
                    }
                }
            }
    
            return pdfObgs;
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-07
      • 1970-01-01
      • 2016-02-14
      • 1970-01-01
      • 2010-10-22
      • 1970-01-01
      • 2014-06-06
      • 1970-01-01
      相关资源
      最近更新 更多