【问题标题】:exception in system.drawing while extracting images from pdf using itextsharp使用 itextsharp 从 pdf 中提取图像时 system.drawing 出现异常
【发布时间】:2011-11-15 16:00:11
【问题描述】:

我正在尝试使用 itextsharp 从 pdf 文件中提取图像

使用here 的示例 pdf 文件

我使用的代码是:-

static void Main(string[] args)
    {

        try
        {
            WriteImageFile(); // write image file
            System.Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory);
            System.Console.ReadLine();
        }
        catch (Exception ex)
        {
            System.Console.WriteLine(ex.Message);
        }
    }

    private static List<System.Drawing.Image> ExtractImages(String PDFSourcePath)
    {
        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(PDFSourcePath);
            PDFReaderObj = new iTextSharp.text.pdf.PdfReader(RAFObj, null);
            if (PDFReaderObj.IsOpenedWithFullPermissions)
            {
                Debug.Print("this is a test");
            }

            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 e)
                            {
                                Console.WriteLine  ("Exception in extract: " + e);
                            }
                        }
                    }
                }
            }
            PDFReaderObj.Close();
        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message);
        }
        return ImgList;
    }


    private static void WriteImageFile()
    {
        try
        {
            System.Console.WriteLine("Wait for extracting image from PDF file....");

            // Get a List of Image
            List<System.Drawing.Image> ListImage = ExtractImages(@"C:\Users\pradyut.bhattacharya\Documents\CEVA PDF\more\CS_75.pdf");

            for (int i = 0; i < ListImage.Count; i++)
            {
                try
                {
                    // Write Image File
                    ListImage[i].Save(@"C:\Users\pradyut.bhattacharya\Documents\CEVA PDF\more\Image" + i + ".jpeg", System.Drawing.Imaging.ImageFormat.Jpeg);
                    System.Console.WriteLine("Image" + i + ".jpeg write sucessfully");
                }
                catch (Exception)
                { }
            }

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

现在在某些情况下,我可以获取图像,但对于大多数包含扫描文件的 PDF,我得到了错误:-

    A first chance exception of type 'System.ArgumentException' occurred in System.Drawing.dll
    Exception in extract: System.ArgumentException: Parameter is not valid.
       at System.Drawing.Image.FromStream(Stream stream, Boolean useEmbeddedColorManagement, Boolean validateImageData)
       at System.Drawing.Image.FromStream(Stream stream)
       at ConsoleApplication1.Program.ExtractImages(String PDFSourcePath) in C:\Users\pradyut.bhattacharya\Documents\Visual Studio 

    2010\Projects\ConsoleApplication2\ConsoleApplication2\Program.cs:line 67
    A first chance exception of type 'System.ArgumentException' occurred in System.Drawing.dll
    Exception in extract: System.ArgumentException: Parameter is not valid.
       at System.Drawing.Image.FromStream(Stream stream, Boolean useEmbeddedColorManagement, Boolean validateImageData)
       at System.Drawing.Image.FromStream(Stream stream)
       at ConsoleApplication1.Program.ExtractImages(String PDFSourcePath) in C:\Users\pradyut.bhattacharya\Documents\Visual Studio 

    2010\Projects\ConsoleApplication2\ConsoleApplication2\Program.cs:line 67

任何帮助

谢谢

【问题讨论】:

    标签: c# image pdf itextsharp


    【解决方案1】:

    PDF 中的图像可以以多种方式存储。您的代码将适用于 .Net 框架具有解码器的所有类型,但对于没有解码器的类型将失败。具体来说,您的代码失败了,因为该 PDF 的图像编码为 JBIG2Decode。您可以通过查看 PDFStremObj /FILTER 属性来检查这一点。

    PdfObject filterType = PDFStremObj.Get(PdfName.FILTER);
    if(filterType.Equals(PdfName.JBIG2DECODE)){
        //...
    }
    

    对于框架不知道的类型,不幸的是,您要么需要一个库,要么编写自己的解码器。

    See this post for some other libraries that do it.Here's Wikipedia's entry 在 JBIG 上,如果你想尝试自己动手。 here's one more post 显示了一些可能还支持解码的编码器,这正是您所需要的。

    【讨论】:

      【解决方案2】:

      老问题,我知道,但实际上我已经找到了一个不错的解决方案。我也很难从具有 JBig2 编码的 PDF 中提取图像。 iTextSharp 的较新版本(4.1.6 后)实际上支持它,但这些版本现在受 AGPL 许可。

      使用version 1 of this library by JPedal(第2 版不是免费的),您可以将JBig2 编码图像转换为System.Drawing.Bitmap,然后根据需要保存/修改它。 然而,这个库只会解码数据,它不能编码图像成JBig2格式。

      一个很小但非常次要的警告是,该库是用 Java 编写的。不过,这对于 C# 用户来说根本不是问题,这要感谢IKVM。 IKVM,如果您还不知道的话,它有一个在 .NET 中运行的完整的 java VM,并且具有 java 类库的本机 .NET 实现。设置起来非常简单,而且我在大约 2 小时前刚刚自己测试过。

      从上述链接下载 IKVM 和 JBig2 jar 后,您可以执行此命令将 IKVM convert jar 转换为原生 .NET dll。

      ikvmc -target:library [jbig2.jar 的路径]

      这将输出一个名为 jbig2.dll 的 .NET dll 到 jar 或 ikvmc 可执行文件的同一目录中(我不记得是哪个)。然后,在您的项目中引用jbig2.dllIKVM.OpenJDK.CoreIKVM.OpenJDK.MediaIKVM.OpenJDK.SwingAWTIKVM.Runtime。我使用类似于以下的代码来提取图像:

      // code to iterate over PDF objects and get bytes of a valid image elided
      var imageBytes = GetRawImageBytesFromPdf();
      
      if (filterType.Equals(PdfName.JBIG2DECODE))
      {
          var jbg2 = new JBIG2Decoder();
      
          // Some JBig2 will extract without setting the JBig2Globals
          var decodeParams = stream.GetAsDict(PdfName.DECODEPARMS);
          if(decodeParams != null)
          {
              var globalRef = decodeParams.GetAsIndirectObject(
                                              PdfName.JBIG2GLOBALS);
              if(globalRef != null)
              {
                  var globals = PdfReader.GetPdfObject(globalRef);
                  var globalStream = globals as PRStream;
                  var globalBytes = PdfReader.GetStreamBytesRaw(globalStream);
      
                  if (globalBytes != null)
                  {
                      jbg2.setGlobalData(globalBytes);
                  }
              }
          }
      
          jbg2.decodeJBIG2(imageBytes);
      
          var pages = jbg2.getNumberOfPages();
      
          for(int p = 0; p < pages; p++)
          {
              java.awt.image.BufferedImage bufImg = jbg2.getPageAsBufferedImage(p);
      
              var bitmap = bufImg.getBitmap();
              bitmap.Save(@"c:\path\to\file.tif", ImageFormat.Tiff);
              // note: I am unsure about the need to free the memory of the internal
              //       bitmap used in the BufferedImage class.  The docs for IKVM and
              //       that class should probably be consulted to find out if that
              //       should be done.
          }
      }
      // handle other formats like CCITTFAXDECODE
      

      它做得很好,虽然库不是最快的(这与它在 IKVM 中使用的事实无关,开发人员承认这个库的版本 1 效率低下)。我不喜欢编写/编辑 java 代码,所以如果我想自己提高速度,我想我可能会直接将它移植到 C# 代码中。然而,这个 java 代码at this github project 的另一个分支,声称速度提高了 2.5-4.5 倍。您可能可以编译该 jar 并使用 ikvmc。

      希望这对仍在寻找解决此问题的方法的人有所帮助!

      【讨论】:

      • 每当我尝试调用“jbgI.getPageAsBufferedImage”时,都会出现异常“'java.awt.image.DataBuffer' 的类型初始化程序引发异常。---> 'sun 的类型初始化程序.awt.image.SunWritableRaster' 抛出异常。---> 'java.awt.image.WritableRaster' 的类型初始化器抛出异常。---> 'java.awt.image.Raster' 的类型初始化器抛出一个异常。---> 'java.awt.image.ColorModel' 的类型初始值设定项引发了异常。---> java.lang.UnsatisfiedLinkError: no awt in java.library.path",也许这些库不起作用没有了吗?
      • 什么是字节?在这一行 jbg2.decodeJBIG2(bytes); ?
      • @Ray 这些是 PDF 中图像的字节。我认为应该是这样的:byte[] bytes = iTextSharp.text.pdf.PdfReader.GetStreamBytesRaw((iTextSharp.text.pdf.PRStream)PDFStremObj);(复制自用户的问题)。
      【解决方案3】:

      感谢您分享这个想法。

      他的解决方案是我使用免费版iTextsharper 发现的最优雅的解决方案。

      按照你的建议,我包含了这些库:

      jbig2dec.dll (generated from promt >ikmvc jbig2dec.jar)
      ICSharpCode.SharpZipLib
      IKVM.Runtime
      IKVM.OpenJDK.Core
      IKVM.OpenJDK.Media
      IKVM.OpenJDK.SwingAWT
      

      【讨论】:

        猜你喜欢
        • 2011-08-22
        • 1970-01-01
        • 1970-01-01
        • 2019-08-07
        • 1970-01-01
        • 2016-02-14
        • 2020-10-27
        • 2015-07-10
        • 2020-08-17
        相关资源
        最近更新 更多