2010-04-14 5 views
13

Ho un pdf che è stato generato dal software di scansione. Il pdf ha 1 immagine TIFF per pagina. Voglio estrarre l'immagine TIFF da ciascuna pagina.Estrazione dell'immagine da PDF con/CCITTFaxDecode filter

Sto usando iTextSharp e ho trovato con successo le immagini e posso recuperare i byte grezzi dal metodo PdfReader.GetStreamBytesRaw. Il problema è che, come molti prima di me hanno scoperto, iTextSharp non contiene un metodo PdfReader.CCITTFaxDecode.

Cos'altro so? Anche senza iTextSharp posso aprire il PDF in blocco note e trovare i corsi d'acqua con /Filter /CCITTFaxDecode e so dal /DecodeParams che sta utilizzando gruppo CCITTFaxDecode 4.

Qualcuno là fuori sa come posso ottenere le immagini Filtro CCITTFaxDecode fuori dalla mia PDF?

Cheers, Kahu

+0

nel caso in cui qualcuno è interessato a una soluzione esclusivamente iTextSharp, c'è questo altro link (http://kuujinbo.info/iTextSharp/CCITTFaxDecodeExtract.aspx) che suggerisce l'utilizzo di una nuova funzionalità introdotta in iTextSharp 5xx chiamato Parser - funziona davvero. crediti a @kuunjinbo è solo che nel mio caso ho dovuto usare ImageConverter sul risultato per creare una Bitmap (non so perché) –

risposta

0

Forse si può provare a decomprimere il PDF con pdftk? La sintassi è

pdftk infile.pdf output uncompressed.pdf uncompress 

Non ho un PDF codificato CCITTFax qui, quindi non posso testarlo.

+1

Questo comando uncompress non sembra correlato al campo COMPRESSION della libtiff. Ho provato questo su un pdf con immagini CCITTFaxdecode, e non sembrava fare alcuna differenza. – nealmcb

6

Questa libreria ... http://www.bitmiracle.com/libtiff/ e questo esempio di seguito dovrebbe ottenere il 99% del modo in cui ci

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(); 

switch (filter) 
{ 
    case "/CCITTFaxDecode": 

     byte[] data = PdfReader.GetStreamBytesRaw((PRStream)pdfStream); 
     int tiff = TIFFOpen("example.tif", "w"); 
     TIFFSetField(tiff, (uint)BitMiracle.LibTiff.Classic.TiffTag.IMAGEWIDTH,(uint)Int32.Parse(width)); 
     TIFFSetField(tiff, (uint)BitMiracle.LibTiff.Classic.TiffTag.IMAGEHEIGHT, (uint)Int32.Parse(height)); 
     TIFFSetField(tiff, (uint)BitMiarcle.LibTiff.Classic.TiffTag.COMPRESSION, (uint)BitMiracle.Libtiff.Classic.Compression.CCITTFAX4); 
     TIFFSetField(tiff, (uint)BitMiracle.LibTiff.Classic.TiffTag.BITSPERSAMPLE, (uint)Int32.Parse(bpp)); 
     TIFFSetField(tiff, (uint)BitMiarcle.Libtiff.Classic.TiffTag.SAMPLESPERPIXEL,1); 

     IntPtr pointer = Marshal.AllocHGlobal(data.length); 
     Marshal.copy(data, 0, pointer, data.length); 
     TIFFWriteRawStrip(tiff, 0, pointer, data.length); 
     TIFFClose(tiff); 

     break; 




     break; 

} 
+0

E il NuGet qui: [BitMiracle.LibTiff.NET] (https://www.nuget.org/packages/BitMiracle.LibTiff.NET/). –

13

In realtà, la risposta di vbcrlfuser mi ha aiutato, ma il codice non è stato del tutto corretto per la versione corrente di BitMiracle.LibTiff.NET, come ho potuto scaricare. Nella versione attuale, il codice equivalente è simile al seguente:

using iTextSharp.text.pdf; 
using BitMiracle.LibTiff.Classic; 

... 
     Tiff tiff = Tiff.Open("C:\\test.tif", "w"); 
     tiff.SetField(TiffTag.IMAGEWIDTH, UInt32.Parse(pd.Get(PdfName.WIDTH).ToString())); 
     tiff.SetField(TiffTag.IMAGELENGTH, UInt32.Parse(pd.Get(PdfName.HEIGHT).ToString())); 
     tiff.SetField(TiffTag.COMPRESSION, Compression.CCITTFAX4); 
     tiff.SetField(TiffTag.BITSPERSAMPLE, UInt32.Parse(pd.Get(PdfName.BITSPERCOMPONENT).ToString())); 
     tiff.SetField(TiffTag.SAMPLESPERPIXEL, 1); 
     tiff.WriteRawStrip(0, raw, raw.Length); 
     tiff.Close(); 

Utilizzando il codice di cui sopra, ho finalmente trovato un file TIFF valida in C: \ Test.tif. Grazie, vbcrlfuser!

+0

Che cos'è 'raw'? Potresti mostrare l'esempio completo. –

+0

B.K. questo potrebbe essere un po 'tardi, ma immagino che sia questo. vedere la risposta di vbcrlfuser ... byte [] data = PdfReader.GetStreamBytesRaw ((PRStream) pdfStream); (utilizzato allo stesso modo del raw) – planty182

4

Qui è la realizzazione di pitone:

import PyPDF2 
import struct 

""" 
Links: 
PDF format: http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/pdf_reference_1-7.pdf 
CCITT Group 4: https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-T.6-198811-I!!PDF-E&type=items 
Extract images from pdf: http://stackoverflow.com/questions/2693820/extract-images-from-pdf-without-resampling-in-python 
Extract images coded with CCITTFaxDecode in .net: http://stackoverflow.com/questions/2641770/extracting-image-from-pdf-with-ccittfaxdecode-filter 
TIFF format and tags: http://www.awaresystems.be/imaging/tiff/faq.html 
""" 


def tiff_header_for_CCITT(width, height, img_size, CCITT_group=4): 
    tiff_header_struct = '<' + '2s' + 'h' + 'l' + 'h' + 'hhll' * 8 + 'h' 
    return struct.pack(tiff_header_struct, 
         b'II', # Byte order indication: Little indian 
         42, # Version number (always 42) 
         8, # Offset to first IFD 
         8, # Number of tags in IFD 
         256, 4, 1, width, # ImageWidth, LONG, 1, width 
         257, 4, 1, height, # ImageLength, LONG, 1, lenght 
         258, 3, 1, 1, # BitsPerSample, SHORT, 1, 1 
         259, 3, 1, CCITT_group, # Compression, SHORT, 1, 4 = CCITT Group 4 fax encoding 
         262, 3, 1, 0, # Threshholding, SHORT, 1, 0 = WhiteIsZero 
         273, 4, 1, struct.calcsize(tiff_header_struct), # StripOffsets, LONG, 1, len of header 
         278, 4, 1, height, # RowsPerStrip, LONG, 1, lenght 
         279, 4, 1, img_size, # StripByteCounts, LONG, 1, size of image 
         0 # last IFD 
         ) 

pdf_filename = 'scan.pdf' 
pdf_file = open(pdf_filename, 'rb') 
cond_scan_reader = PyPDF2.PdfFileReader(pdf_file) 
for i in range(0, cond_scan_reader.getNumPages()): 
    page = cond_scan_reader.getPage(i) 
    xObject = page['/Resources']['/XObject'].getObject() 
    for obj in xObject: 
     if xObject[obj]['/Subtype'] == '/Image': 
      """ 
      The CCITTFaxDecode filter decodes image data that has been encoded using 
      either Group 3 or Group 4 CCITT facsimile (fax) encoding. CCITT encoding is 
      designed to achieve efficient compression of monochrome (1 bit per pixel) image 
      data at relatively low resolutions, and so is useful only for bitmap image data, not 
      for color images, grayscale images, or general data. 

      K < 0 --- Pure two-dimensional encoding (Group 4) 
      K = 0 --- Pure one-dimensional encoding (Group 3, 1-D) 
      K > 0 --- Mixed one- and two-dimensional encoding (Group 3, 2-D) 
      """ 
      if xObject[obj]['/Filter'] == '/CCITTFaxDecode': 
       if xObject[obj]['/DecodeParms']['/K'] == -1: 
        CCITT_group = 4 
       else: 
        CCITT_group = 3 
       width = xObject[obj]['/Width'] 
       height = xObject[obj]['/Height'] 
       data = xObject[obj]._data # sorry, getData() does not work for CCITTFaxDecode 
       img_size = len(data) 
       tiff_header = tiff_header_for_CCITT(width, height, img_size, CCITT_group) 
       img_name = obj[1:] + '.tiff' 
       with open(img_name, 'wb') as img_file: 
        img_file.write(tiff_header + data) 
       # 
       # import io 
       # from PIL import Image 
       # im = Image.open(io.BytesIO(tiff_header + data)) 
pdf_file.close() 
+1

In base al tag e al corpo della domanda, l'op utilizza iTextSharp. La realizzazione di * python *, quindi, non risponde a questa domanda. – mkl

+1

Secondo la specifica TIFF ([link] (http://www.itu.int/itudoc/itu-t/com16/tiff-fx/docs/tiff6.html), penso che la variabile 'tiff_header_struct' dovrebbe leggi ''<' + '2s' + 'H' + 'L' + 'H' + 'HHLL' * 8 + 'L''.Nota in particolare il ''L'' alla fine. – Taar

0

E 'stato scritto extension per questo .E così semplice

PdfDictionary item; 
if (item.IsImage()) { 
    Image image = item.ToImage(); 
}