2017-11-03 1 views
2

iTextSharp를 사용하여 PDF 파일에서 이미지를 추출하려고합니다./ASCIIHexDecode로 이미지를 디코딩하는 방법

이 프로세스는 대부분의 PDF 파일에서 작동하지만 일부 파일에서는 실패합니다.

특히, 실패한 PDF는 필터 /ASCIIHexDecode/CCITTFaxDecode의 이미지가 있음을 확인했습니다.

이 필터로 이미지를 디코딩하는 방법은 무엇입니까? 여기에 문제를 일으키는 샘플 PDF입니다 :

private static FindImages(PdfReader reader, PdfDictionary pdfPage) 
{ 
    var imgPdfObject = FindImageInPDFDictionary(pdfPage); 
    foreach (var image in imgPdfObject) 
    { 
     var xrefIndex = ((PRIndirectReference)image).Number; 
     var stream = reader.GetPdfObject(xrefIndex); 
     // Exception occurs here : 
     var pdfImage = new PdfImageObject((PRStream)stream); 
     img = (Bitmap)pdfImage.GetDrawingImage(); 

     // Do something with the image 

    } 
} 
private static IEnumerable<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)) 
       { 
        yield return obj; 
       }// image inside a form 
       else if (PdfName.FORM.Equals(type)) 
       { 
        foreach (var nestedObj in FindImageInPDFDictionary(tg)) 
        { 
         yield return nestedObj; 
        } 
       } //image inside a group 
       else if (PdfName.GROUP.Equals(type)) 
       { 
        foreach (var nestedObj in FindImageInPDFDictionary(tg)) 
        { 
         yield return nestedObj; 
        } 
       } 
      } 
     } 
    } 
} 

정확한 예외는 다음과 같습니다 : 참고로

iTextSharp.text.exceptions.InvalidImageException: **Invalid code encountered while decoding 2D group 4 compressed data.** 
    à iTextSharp.text.pdf.codec.TIFFFaxDecoder.DecodeT6(Byte[] buffer, Byte[] compData, Int32 startX, Int32 height, Int64 tiffT6Options) 
    à iTextSharp.text.pdf.FilterHandlers.Filter_CCITTFAXDECODE.Decode(Byte[] b, PdfName filterName, PdfObject decodeParams, PdfDictionary streamDictionary) 
    à iTextSharp.text.pdf.PdfReader.DecodeBytes(Byte[] b, PdfDictionary streamDictionary, IDictionary`2 filterHandlers) 
    à iTextSharp.text.pdf.parser.PdfImageObject..ctor(PdfDictionary dictionary, Byte[] samples, PdfDictionary colorSpaceDic) 
    à iTextSharp.text.pdf.parser.PdfImageObject..ctor(PRStream stream) 
    à MyProject.MyClass.MyMethod(PdfReader reader, PdfDictionary pdfPage) dans c:\\sopmewhere\\PdfProcessor.cs:ligne 161 

참고로, 내 이미지 추출 루틴 (pg 객체가 PdfReader.GetPageN를 사용하여 얻을입니다)입니다 : test.pdf

+0

예외가 발생한 pdf를 공유하십시오. – mkl

+0

실제 오류 코드가 누락 된 재현 코드와 문제를 일으키는 샘플 PDF를 업데이트했습니다. –

+0

샘플 파일에 ** ASCIIHexDecode ** 필터가 포함 된 스트림이 없습니다. Jacek Blaszczynski와 같은 필터에 집중할 수있는 사람들을 오해 할 수 있으므로 질문 제목에서이를 편집 할 수 있습니다. – mkl

답변

0

코드 샘플을 자세히 살펴 보지 않고도 PDF 필터 및 특정 구현 방법이 있습니다. 매우 간단한 것은 다음과 같습니다 PDFSharp - AsciiHexDecode.cs. iTextSharp에 구현 된 인코더 및 디코더를 대체하는 것이 도움이되기를 바랍니다. 데이터가 손상되거나 디코더/인코더 중 하나에 버그가있는 경우 확인이 가능해야합니다. 불행히도 필자는 서면으로 /CCITTFaxDecode에 예제가 없었습니다.

// 
// Copyright (c) 2005-2016 empira Software GmbH, Cologne Area (Germany) 
// 
// http://www.pdfsharp.com 
// http://sourceforge.net/projects/pdfsharp 
// 
// Permission is hereby granted, free of charge, to any person obtaining a 
// copy of this software and associated documentation files (the "Software"), 
// to deal in the Software without restriction, including without limitation 
// the rights to use, copy, modify, merge, publish, distribute, sublicense, 
// and/or sell copies of the Software, and to permit persons to whom the 
// Software is furnished to do so, subject to the following conditions: 
// 
// The above copyright notice and this permission notice shall be included 
// in all copies or substantial portions of the Software. 
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
// DEALINGS IN THE SOFTWARE. 
#endregion 

using System; 

namespace PdfSharp.Pdf.Filters 
{ 
    /// <summary> 
    /// Implements the ASCIIHexDecode filter. 
    /// </summary> 
    public class AsciiHexDecode : Filter 
    { 
     // Reference: 3.3.1 ASCIIHexDecode Filter/Page 69 

     /// <summary> 
     /// Encodes the specified data. 
     /// </summary> 
     public override byte[] Encode(byte[] data) 
     { 
      if (data == null) 
       throw new ArgumentNullException("data"); 

      int count = data.Length; 
      byte[] bytes = new byte[2 * count]; 
      for (int i = 0, j = 0; i < count; i++) 
      { 
       byte b = data[i]; 
       bytes[j++] = (byte)((b >> 4) + ((b >> 4) < 10 ? (byte)'0' : (byte)('A' - 10))); 
       bytes[j++] = (byte)((b & 0xF) + ((b & 0xF) < 10 ? (byte)'0' : (byte)('A' - 10))); 
      } 
      return bytes; 
     } 

     /// <summary> 
     /// Decodes the specified data. 
     /// </summary> 
     public override byte[] Decode(byte[] data, FilterParms parms) 
     { 
      if (data == null) 
       throw new ArgumentNullException("data"); 

      data = RemoveWhiteSpace(data); 
      int count = data.Length; 
      // Ignore EOD (end of data) character. 
      // EOD can be anywhere in the stream, but makes sense only at the end of the stream. 
      if (count > 0 && data[count - 1] == '>') 
       --count; 
      if (count % 2 == 1) 
      { 
       count++; 
       byte[] temp = data; 
       data = new byte[count]; 
       temp.CopyTo(data, 0); 
      } 
      count >>= 1; 
      byte[] bytes = new byte[count]; 
      for (int i = 0, j = 0; i < count; i++) 
      { 
       // Must support 0-9, A-F, a-f - "Any other characters cause an error." 
       byte hi = data[j++]; 
       byte lo = data[j++]; 
       if (hi >= 'a' && hi <= 'f') 
        hi -= 32; 
       if (lo >= 'a' && lo <= 'f') 
        lo -= 32; 
       // TODO Throw on invalid characters. Stop when encountering EOD. Add one more byte if EOD is the lo byte. 
       bytes[i] = (byte)((hi > '9' ? hi - '7'/*'A' + 10*/: hi - '0') * 16 + (lo > '9' ? lo - '7'/*'A' + 10*/: lo - '0')); 
      } 
      return bytes; 
     } 
    } 
} 
+0

iText의 AsciiHexDecoder에서 문제가 발생했을 가능성이 매우 희박합니다. 문제가 iText의 문제 (이미지 데이터가 깨진 것이 아니라)로 인한 것이면,'TIFFFaxDecoder '의 한계 일 가능성이 큽니다. 응답하기 전에 수업을 전부 확인 했니? – mkl

+0

@ Jacek, 고마워.하지만 내 문제는 필터 자체와 관련이 있지만 내 코드의 논리는 아닙니다. 나는'PdfImage.GetDrawingImage' 메소드가 그것을 처리 할 것으로 기대하고있었습니다. 블로그 포스트에서 여러 번 읽었던 것처럼 말입니다. –

관련 문제