2009-04-29 43 views
19

Tôi đã sử dụng mã này với thành công lớn để rút ra hình ảnh đầu tiên được tìm thấy trong mỗi trang của PDF. Tuy nhiên, hiện tại, nó không hoạt động với một số tệp PDF mới vì lý do uknown. Tôi đã sử dụng các công cụ khác (Datalogics, v.v.) để làm nổi bật các hình ảnh tốt với các tệp PDF mới này. Tuy nhiên, tôi không muốn mua Datalogics hoặc bất kỳ công cụ nào nếu tôi có thể sử dụng iTextSharp. Ai có thể cho tôi biết tại sao mã này không tìm thấy hình ảnh trong PDF?Trích xuất hình ảnh bằng iTextSharp

Được biết: tệp PDF của tôi chỉ có 1 hình ảnh trên mỗi trang và không có gì khác.

using iTextSharp.text; 
using iTextSharp.text.pdf; 
... 
public static void ExtractImagesFromPDF(string sourcePdf, string outputPath) 
{ 
    // NOTE: This will only get the first image it finds per page. 
    PdfReader pdf = new PdfReader(sourcePdf); 
    RandomAccessFileOrArray raf = new iTextSharp.text.pdf.RandomAccessFileOrArray(sourcePdf); 

    try 
    { 
     for (int pageNumber = 1; pageNumber <= pdf.NumberOfPages; pageNumber++) 
     { 
      PdfDictionary pg = pdf.GetPageN(pageNumber); 
      PdfDictionary res = (PdfDictionary)PdfReader.GetPdfObject(pg.Get(PdfName.RESOURCES)); 

      PdfDictionary xobj = (PdfDictionary)PdfReader.GetPdfObject(res.Get(PdfName.XOBJECT)); 
      if (xobj != null) 
      { 
       foreach (PdfName name in xobj.Keys) 
       { 
        PdfObject obj = xobj.Get(name); 
        if (obj.IsIndirect()) 
        { 
         PdfDictionary tg = (PdfDictionary)PdfReader.GetPdfObject(obj); 
         PdfName type = (PdfName)PdfReader.GetPdfObject(tg.Get(PdfName.SUBTYPE)); 
         if (PdfName.IMAGE.Equals(type)) 
         { 
          int XrefIndex = Convert.ToInt32(((PRIndirectReference)obj).Number.ToString(System.Globalization.CultureInfo.InvariantCulture)); 
          PdfObject pdfObj = pdf.GetPdfObject(XrefIndex); 
          PdfStream pdfStrem = (PdfStream)pdfObj; 
          byte[] bytes = PdfReader.GetStreamBytesRaw((PRStream)pdfStrem); 
          if ((bytes != null)) 
          { 
           using (System.IO.MemoryStream memStream = new System.IO.MemoryStream(bytes)) 
           { 
            memStream.Position = 0; 
            System.Drawing.Image img = System.Drawing.Image.FromStream(memStream); 
            // must save the file while stream is open. 
            if (!Directory.Exists(outputPath)) 
             Directory.CreateDirectory(outputPath); 

            string path = Path.Combine(outputPath, String.Format(@"{0}.jpg", pageNumber)); 
            System.Drawing.Imaging.EncoderParameters parms = new System.Drawing.Imaging.EncoderParameters(1); 
            parms.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Compression, 0); 
            System.Drawing.Imaging.ImageCodecInfo jpegEncoder = Utilities.GetImageEncoder("JPEG"); 
            img.Save(path, jpegEncoder, parms); 
            break; 
           } 
          } 
         } 
        } 
       } 
      } 
     } 
    } 

    catch 
    { 
     throw; 
    } 
    finally 
    { 
     pdf.Close(); 
     raf.Close(); 
    } 
} 
+0

Bạn có thể lấy đúng tên hình ảnh từ pdf ví dụ: image1.png – techno

Trả lời

19

Tôi thấy rằng vấn đề của tôi là tôi không đệ quy tìm kiếm bên trong biểu mẫu và nhóm cho hình ảnh. Về cơ bản, mã ban đầu sẽ chỉ tìm thấy hình ảnh được nhúng vào thư mục gốc của tài liệu pdf. Đây là phương pháp sửa đổi cộng với một phương pháp mới (FindImageInPDFDictionary) mà đệ quy tìm kiếm hình ảnh trong trang. LƯU Ý: các lỗi chỉ hỗ trợ ảnh JPEG và không nén vẫn được áp dụng. Xem mã của R Ubben để biết các tùy chọn để sửa các lỗi đó. HTH ai đó.

public static void ExtractImagesFromPDF(string sourcePdf, string outputPath) 
    { 
     // NOTE: This will only get the first image it finds per page. 
     PdfReader pdf = new PdfReader(sourcePdf); 
     RandomAccessFileOrArray raf = new iTextSharp.text.pdf.RandomAccessFileOrArray(sourcePdf); 

     try 
     { 
      for (int pageNumber = 1; pageNumber <= pdf.NumberOfPages; pageNumber++) 
      { 
       PdfDictionary pg = pdf.GetPageN(pageNumber); 

       // recursively search pages, forms and groups for images. 
       PdfObject obj = FindImageInPDFDictionary(pg); 
       if (obj != null) 
       { 

        int XrefIndex = Convert.ToInt32(((PRIndirectReference)obj).Number.ToString(System.Globalization.CultureInfo.InvariantCulture)); 
        PdfObject pdfObj = pdf.GetPdfObject(XrefIndex); 
        PdfStream pdfStrem = (PdfStream)pdfObj; 
        byte[] bytes = PdfReader.GetStreamBytesRaw((PRStream)pdfStrem); 
        if ((bytes != null)) 
        { 
         using (System.IO.MemoryStream memStream = new System.IO.MemoryStream(bytes)) 
         { 
          memStream.Position = 0; 
          System.Drawing.Image img = System.Drawing.Image.FromStream(memStream); 
          // must save the file while stream is open. 
          if (!Directory.Exists(outputPath)) 
           Directory.CreateDirectory(outputPath); 

          string path = Path.Combine(outputPath, String.Format(@"{0}.jpg", pageNumber)); 
          System.Drawing.Imaging.EncoderParameters parms = new System.Drawing.Imaging.EncoderParameters(1); 
          parms.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Compression, 0); 
          System.Drawing.Imaging.ImageCodecInfo jpegEncoder = Utilities.GetImageEncoder("JPEG"); 
          img.Save(path, jpegEncoder, parms); 
         } 
        } 
       } 
      } 
     } 
     catch 
     { 
      throw; 
     } 
     finally 
     { 
      pdf.Close(); 
      raf.Close(); 
     } 


    } 

    private static PdfObject FindImageInPDFDictionary(PdfDictionary pg) 
    { 
     PdfDictionary res = 
      (PdfDictionary)PdfReader.GetPdfObject(pg.Get(PdfName.RESOURCES)); 


     PdfDictionary xobj = 
      (PdfDictionary)PdfReader.GetPdfObject(res.Get(PdfName.XOBJECT)); 
     if (xobj != null) 
     { 
      foreach (PdfName name in xobj.Keys) 
      { 

       PdfObject obj = xobj.Get(name); 
       if (obj.IsIndirect()) 
       { 
        PdfDictionary tg = (PdfDictionary)PdfReader.GetPdfObject(obj); 

        PdfName type = 
         (PdfName)PdfReader.GetPdfObject(tg.Get(PdfName.SUBTYPE)); 

        //image at the root of the pdf 
        if (PdfName.IMAGE.Equals(type)) 
        { 
         return obj; 
        }// image inside a form 
        else if (PdfName.FORM.Equals(type)) 
        { 
         return FindImageInPDFDictionary(tg); 
        } //image inside a group 
        else if (PdfName.GROUP.Equals(type)) 
        { 
         return FindImageInPDFDictionary(tg); 
        } 

       } 
      } 
     } 

     return null; 

    } 
+6

Tiện ích.GetImageEncoder ở đâu ?? –

+0

Bạn có thể lấy bộ mã hóa jpg từ /System.Drawing.Imaging.ImageCodecInfo.GetEncoders()/ –

+1

Hình ảnh PDF KHÔNG ở định dạng chuẩn - chúng là "mảng giá trị màu" trong một không gian màu cụ thể với một số bit nhất định trên mỗi thành phần và có khả năng được xử lý với một hoặc nhiều "bộ lọc". Chi tiết được mô tả trong ISO 32000-1. như được đề cập ở đây: http://itext-general.2136553.n4.nabble.com/Extract-PDF-embedded-images-using-iText-td2172216.html –

3

Ở trên sẽ chỉ hoạt động với JPEG. Loại trừ hình ảnh nội tuyến và tệp được nhúng, bạn cần phải đi qua các đối tượng của IMAGE loại phụ, sau đó xem bộ lọc và thực hiện hành động thích hợp. Dưới đây là một ví dụ, giả sử chúng ta có một PdfObject của kiểu phụ IMAGE:

  PdfReader pdf = new PdfReader("c:\\temp\\exp0.pdf"); 
     int xo=pdf.XrefSize; 
     for (int i=0;i<xo;i++) 
     { 
      PdfObject obj=pdf.GetPdfObject(i); 
      if (obj!=null && obj.IsStream()) 
      { 
       PdfDictionary pd=(PdfDictionary)obj; 
       if (pd.Contains(PdfName.SUBTYPE) && pd.Get(PdfName.SUBTYPE).ToString()=="/Image") 
       { 
        string filter=pd.Get(PdfName.FILTER).ToString(); 
        string width=pd.Get(PdfName.WIDTH).ToString(); 
        string height=pd.Get(PdfName.HEIGHT).ToString(); 
        string bpp=pd.Get(PdfName.BITSPERCOMPONENT).ToString(); 
        string extent="."; 
        byte [] img=null; 
        switch (filter) 
        { 
         case "/FlateDecode": 
          byte[] arr=PdfReader.FlateDecode(PdfReader.GetStreamBytesRaw((PRStream)obj),true); 
          Bitmap bmp=new Bitmap(Int32.Parse(width),Int32.Parse(height),PixelFormat.Format24bppRgb); 
          BitmapData bmd=bmp.LockBits(new Rectangle(0,0,Int32.Parse(width),Int32.Parse(height)),ImageLockMode.WriteOnly, 
           PixelFormat.Format24bppRgb); 
          Marshal.Copy(arr,0,bmd.Scan0,arr.Length); 
          bmp.UnlockBits(bmd); 
          bmp.Save("c:\\temp\\bmp1.png",ImageFormat.Png); 
          break; 
         default: 
          break; 
        } 
       } 
      } 
     } 

này sẽ mess màu lên vì Microsoft BGR, tất nhiên, nhưng tôi muốn giữ nó ngắn. Làm điều gì đó tương tự cho "/ CCITTFaxDecode", v.v.

+0

Tôi đánh giá cao mã. Nhưng tôi không tìm thấy bất kỳ loại phụ IMAGE nào trong tệp PDF của mình. Mọi thứ đều gián tiếp thuộc loại XObject. Bất kỳ ý tưởng về cách tôi có thể tìm thấy những hình ảnh? – Dave

+0

Vâng, chúng là các xobject gián tiếp; mọi luồng phải gián tiếp, theo tiêu chuẩn. Những gì tôi đã làm là đi qua các đồ vật và tìm kiếm các dòng suối. Tôi nên đã bao gồm trong mã. Tôi sẽ chỉnh sửa nó để thêm phần đó. –

+0

Vì vậy, bạn xem qua các đối tượng cho các luồng, sau đó tìm nạp từ điển của nó. Loại sẽ là luồng và đối với hình ảnh, loại phụ sẽ là "/ Hình ảnh". –

6

Các mã sau đây kết hợp tất cả các ý tưởng Dave và R Ubben của trên, cộng với nó trả về một danh sách đầy đủ của tất cả các hình ảnh và cũng giao dịch với nhiều độ sâu bit. Tôi đã phải chuyển nó sang VB cho dự án tôi đang làm việc trên dù, xin lỗi về điều đó ...

Private Sub getAllImages(ByVal dict As pdf.PdfDictionary, ByVal images As List(Of Byte()), ByVal doc As pdf.PdfReader) 
    Dim res As pdf.PdfDictionary = CType(pdf.PdfReader.GetPdfObject(dict.Get(pdf.PdfName.RESOURCES)), pdf.PdfDictionary) 
    Dim xobj As pdf.PdfDictionary = CType(pdf.PdfReader.GetPdfObject(res.Get(pdf.PdfName.XOBJECT)), pdf.PdfDictionary) 

    If xobj IsNot Nothing Then 
     For Each name As pdf.PdfName In xobj.Keys 
      Dim obj As pdf.PdfObject = xobj.Get(name) 
      If (obj.IsIndirect) Then 
       Dim tg As pdf.PdfDictionary = CType(pdf.PdfReader.GetPdfObject(obj), pdf.PdfDictionary) 
       Dim subtype As pdf.PdfName = CType(pdf.PdfReader.GetPdfObject(tg.Get(pdf.PdfName.SUBTYPE)), pdf.PdfName) 
       If pdf.PdfName.IMAGE.Equals(subtype) Then 
        Dim xrefIdx As Integer = CType(obj, pdf.PRIndirectReference).Number 
        Dim pdfObj As pdf.PdfObject = doc.GetPdfObject(xrefIdx) 
        Dim str As pdf.PdfStream = CType(pdfObj, pdf.PdfStream) 
        Dim bytes As Byte() = pdf.PdfReader.GetStreamBytesRaw(CType(str, pdf.PRStream)) 

        Dim filter As String = tg.Get(pdf.PdfName.FILTER).ToString 
        Dim width As String = tg.Get(pdf.PdfName.WIDTH).ToString 
        Dim height As String = tg.Get(pdf.PdfName.HEIGHT).ToString 
        Dim bpp As String = tg.Get(pdf.PdfName.BITSPERCOMPONENT).ToString 

        If filter = "/FlateDecode" Then 
         bytes = pdf.PdfReader.FlateDecode(bytes, True) 
         Dim pixelFormat As System.Drawing.Imaging.PixelFormat 
         Select Case Integer.Parse(bpp) 
          Case 1 
           pixelFormat = Drawing.Imaging.PixelFormat.Format1bppIndexed 
          Case 24 
           pixelFormat = Drawing.Imaging.PixelFormat.Format24bppRgb 
          Case Else 
           Throw New Exception("Unknown pixel format " + bpp) 
         End Select 
         Dim bmp As New System.Drawing.Bitmap(Int32.Parse(width), Int32.Parse(height), pixelFormat) 
         Dim bmd As System.Drawing.Imaging.BitmapData = bmp.LockBits(New System.Drawing.Rectangle(0, 0, Int32.Parse(width), Int32.Parse(height)), System.Drawing.Imaging.ImageLockMode.WriteOnly, pixelFormat) 
         Marshal.Copy(bytes, 0, bmd.Scan0, bytes.Length) 
         bmp.UnlockBits(bmd) 
         Using ms As New MemoryStream 
          bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png) 
          bytes = ms.GetBuffer 
         End Using 
        End If 
        images.Add(bytes) 
       ElseIf pdf.PdfName.FORM.Equals(subtype) Or pdf.PdfName.GROUP.Equals(subtype) Then 
        getAllImages(tg, images, doc) 
       End If 
      End If 
     Next 
    End If 
End Sub 
4

De C# phiên bản:

private IList<System.Drawing.Image> GetImagesFromPdfDict(PdfDictionary dict, PdfReader doc){ 
     List<System.Drawing.Image> images = new List<System.Drawing.Image>(); 
     PdfDictionary res = (PdfDictionary)(PdfReader.GetPdfObject(dict.Get(PdfName.RESOURCES))); 
     PdfDictionary xobj = (PdfDictionary)(PdfReader.GetPdfObject(res.Get(PdfName.XOBJECT))); 

     if (xobj != null) 
     { 
      foreach (PdfName name in xobj.Keys) 
      { 
       PdfObject obj = xobj.Get(name); 
       if (obj.IsIndirect()) 
       { 
        PdfDictionary tg = (PdfDictionary)(PdfReader.GetPdfObject(obj)); 
        pdf.PdfName subtype = (pdf.PdfName)(pdf.PdfReader.GetPdfObject(tg.Get(pdf.PdfName.SUBTYPE))); 
        if (pdf.PdfName.IMAGE.Equals(subtype)) 
        { 
         int xrefIdx = ((pdf.PRIndirectReference)obj).Number; 
         pdf.PdfObject pdfObj = doc.GetPdfObject(xrefIdx); 
         pdf.PdfStream str = (pdf.PdfStream)(pdfObj); 
         byte[] bytes = pdf.PdfReader.GetStreamBytesRaw((pdf.PRStream)str); 

         string filter = tg.Get(pdf.PdfName.FILTER).ToString(); 
         string width = tg.Get(pdf.PdfName.WIDTH).ToString(); 
         string height = tg.Get(pdf.PdfName.HEIGHT).ToString(); 
         string bpp = tg.Get(pdf.PdfName.BITSPERCOMPONENT).ToString(); 

         if (filter == "/FlateDecode") 
         { 
          bytes = pdf.PdfReader.FlateDecode(bytes, true); 
          System.Drawing.Imaging.PixelFormat pixelFormat; 
          switch (int.Parse(bpp)) 
          { 
           case 1: 
            pixelFormat = System.Drawing.Imaging.PixelFormat.Format1bppIndexed; 
            break; 
           case 24: 
            pixelFormat = System.Drawing.Imaging.PixelFormat.Format24bppRgb; 
            break; 
           default: 
            throw new Exception("Unknown pixel format " + bpp); 
          } 
          var bmp = new System.Drawing.Bitmap(Int32.Parse(width), Int32.Parse(height), pixelFormat); 
          System.Drawing.Imaging.BitmapData bmd = bmp.LockBits(new System.Drawing.Rectangle(0, 0, Int32.Parse(width), 
           Int32.Parse(height)), System.Drawing.Imaging.ImageLockMode.WriteOnly, pixelFormat); 
          Marshal.Copy(bytes, 0, bmd.Scan0, bytes.Length); 
          bmp.UnlockBits(bmd); 
          using (var ms = new MemoryStream()) 
          { 
           bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png); 
           bytes = ms.GetBuffer(); 
          } 
         } 
         images.Add(System.Drawing.Image.FromStream(new MemoryStream(bytes))); 
        } 
        else if (pdf.PdfName.FORM.Equals(subtype) || pdf.PdfName.GROUP.Equals(subtype)) 
        { 
         images.AddRange(GetImagesFromPdfDict(tg, doc)); 
        } 
       } 
      } 
     } 
     return images; 
    } 
+0

Mỏ không thành công tại 'images.Add (System.Drawing.Image.FromStream (new MemoryStream (bytes)));' vì tham số ** không hợp lệ. ** ps. pdf là không cần thiết khi bạn có 'bằng cách sử dụng iTextSharp.text.pdf;' –

+0

Tôi đã có vấn đề với điều này: quá trình bị khóa trên Marshal.Copy. –

7

Dưới đây là một giải pháp đơn giản hơn:

iTextSharp.text.pdf.parser.PdfImageObject pdfImage = 
          new iTextSharp.text.pdf.parser.PdfImageObject(imgPRStream); 
         System.Drawing.Image img = pdfImage.GetDrawingImage(); 
+0

điều này làm việc cho tôi. cảm ơn bạn – Migs

+1

Tôi nên làm rõ rằng tôi đã gặp sự cố khi nhận "Thông số không hợp lệ" khi hình ảnh được tìm thấy và đó là do định dạng TIFF và tôi đang cố gắng tạo một bản đồ bitmap. Phương pháp được nêu ở trên đã chuyển đổi thành công hình ảnh sang định dạng đúng. – Migs

3

Đây chỉ là một bản tóm tắt khác về ý tưởng của người khác, nhưng ý tưởng đó đã làm việc cho tôi. Ở đây tôi sử dụng đoạn trích hình ảnh của @ Malco với vòng lặp của R Ubben:

private IList<System.Drawing.Image> GetImagesFromPdfDict(PdfDictionary dict, PdfReader doc) 
{ 
    List<System.Drawing.Image> images = new List<System.Drawing.Image>(); 
    PdfDictionary res = (PdfDictionary)(PdfReader.GetPdfObject(dict.Get(PdfName.RESOURCES))); 
    PdfDictionary xobj = (PdfDictionary)(PdfReader.GetPdfObject(res.Get(PdfName.XOBJECT))); 

    if (xobj != null) 
    { 
     foreach (PdfName name in xobj.Keys) 
     { 
      PdfObject obj = xobj.Get(name); 
      if (obj.IsIndirect()) 
      { 
       PdfDictionary tg = (PdfDictionary)(PdfReader.GetPdfObject(obj)); 
       PdfName subtype = (PdfName)(PdfReader.GetPdfObject(tg.Get(PdfName.SUBTYPE))); 
       if (PdfName.IMAGE.Equals(subtype)) 
       { 
        int xrefIdx = ((PRIndirectReference)obj).Number; 
        PdfObject pdfObj = doc.GetPdfObject(xrefIdx); 
        PdfStream str = (PdfStream)(pdfObj); 

        iTextSharp.text.pdf.parser.PdfImageObject pdfImage = 
         new iTextSharp.text.pdf.parser.PdfImageObject((PRStream)str); 
        System.Drawing.Image img = pdfImage.GetDrawingImage(); 

        images.Add(img); 
       } 
       else if (PdfName.FORM.Equals(subtype) || PdfName.GROUP.Equals(subtype)) 
       { 
        images.AddRange(GetImagesFromPdfDict(tg, doc)); 
       } 
      } 
     } 
    } 

    return images; 
} 
Các vấn đề liên quan