Bilder aus PDF ohne Resampling in Python extrahieren?


79

Wie kann man alle Bilder aus einem PDF-Dokument mit nativer Auflösung und Format extrahieren? (Bedeutung tiff als tiff extrahieren, jpeg als jpeg usw. und ohne Resampling). Das Layout ist unwichtig, es ist mir egal, wo sich das Quellbild auf der Seite befindet.

Ich verwende Python 2.7, kann aber bei Bedarf 3.x verwenden.


Vielen Dank. Diese URL "Wie Bilder in PDF gespeichert werden" hat nicht funktioniert, aber dies scheint: jpedal.org/PDFblog/2010/04/…
nealmcb

Es gibt eine JPedal- Java-Bibliothek, die dies als PDF Clipped Image Extraction bezeichnet . Der Autor, Mark Stephens, hat einen kurzen Überblick darüber, wie Bilder in PDF gespeichert werden, was jemandem beim Erstellen eines Python-Extraktors helfen kann.
Matt Wilkie

Antworten:


44

Sie können das Modul PyMuPDF verwenden. Dies gibt alle Bilder als PNG-Dateien aus, hat aber sofort funktioniert und ist schnell.

import fitz
doc = fitz.open("file.pdf")
for i in range(len(doc)):
    for img in doc.getPageImageList(i):
        xref = img[0]
        pix = fitz.Pixmap(doc, xref)
        if pix.n < 5:       # this is GRAY or RGB
            pix.writePNG("p%s-%s.png" % (i, xref))
        else:               # CMYK: convert to RGB first
            pix1 = fitz.Pixmap(fitz.csRGB, pix)
            pix1.writePNG("p%s-%s.png" % (i, xref))
            pix1 = None
        pix = None

Weitere Ressourcen finden Sie hier


2
Das funktioniert super! (wird pip install pymudfzuerst offensichtlich benötigt)
Basj

9
* pip install pymupdffür die anderen Googler, die sich fragen, warum die obige Installation fehlschlägt
VSZM

9
Anstatt mehr Informationen zupip install pymupdf versuchenpip install PyMuPDF
Damotorie

1
RuntimeError: pixmap must be grayscale or rgb to write as pngKann mir jemand helfen, den ich mit diesem Code bekomme ?
Gewölbe

4
@vault Dieser Kommentar ist veraltet. Sie sollten "if pix.n <5" in "if pix.n - pix.alpha <4" ändern, da der ursprüngliche Zustand CMYK-Bilder nicht korrekt findet.
Oringa

39

In Python mit PyPDF2- und Pillow-Bibliotheken ist es einfach:

import PyPDF2

from PIL import Image

if __name__ == '__main__':
    input1 = PyPDF2.PdfFileReader(open("input.pdf", "rb"))
    page0 = input1.getPage(0)
    xObject = page0['/Resources']['/XObject'].getObject()

    for obj in xObject:
        if xObject[obj]['/Subtype'] == '/Image':
            size = (xObject[obj]['/Width'], xObject[obj]['/Height'])
            data = xObject[obj].getData()
            if xObject[obj]['/ColorSpace'] == '/DeviceRGB':
                mode = "RGB"
            else:
                mode = "P"

            if xObject[obj]['/Filter'] == '/FlateDecode':
                img = Image.frombytes(mode, size, data)
                img.save(obj[1:] + ".png")
            elif xObject[obj]['/Filter'] == '/DCTDecode':
                img = open(obj[1:] + ".jpg", "wb")
                img.write(data)
                img.close()
            elif xObject[obj]['/Filter'] == '/JPXDecode':
                img = open(obj[1:] + ".jp2", "wb")
                img.write(data)
                img.close()

14
Anfangs davon aufgeregt, aber es hat sich übergeben NotImplementedError: unsupported filter /DCTDecodeoder ... /JPXDecodevon xObject[obj].getData()den ersten paar PDFs, die ich getestet habe. Details unter gist.github.com/maphew/fe6ba4bf9ed2bc98ecf5
matt wilkie

4
Ich habe kürzlich die Änderung '/ DCTDecode' in die PyPDF2-Bibliothek verschoben. Sie können mein Repository verwenden: github.com/sylvainpelissier/PyPDF2, während es in den Hauptzweig integriert ist.
Sylvain

1
Danke für das Update, aber sorry, immer noch nicht los. Inhalt aktualisiert. Ich bekomme ValueError: not enough image datafür dctdecode eingebettete Bilder und unsupported filter /JPXDecodeauf ein anderes pdf.
Matt Wilkie

1
Fortschritte machen! Die dctdecode-PDFs werden jetzt fehlerfrei verarbeitet (obwohl die Ausgabebilder manchmal auf dem Kopf stehen). Die JPXDecode-Datei wird jetzt jedoch ausgelöst KeyError:/Filter. Ich habe das Wesentliche entsprechend aktualisiert. Die PDF-Dateien sind nur zufällige aus dem Netz. Das Wesentliche hat Quelllinks.
Matt Wilkie

28
"Es ist einfach ... "
mlissner

34

Oft wird das Bild in einer PDF-Datei einfach so gespeichert, wie sie ist. Beispielsweise hat eine PDF-Datei mit einem eingefügten JPG einen Bytebereich in der Mitte, der beim Extrahieren eine gültige JPG-Datei ist. Sie können dies verwenden, um ganz einfach Bytebereiche aus dem PDF zu extrahieren. Ich habe vor einiger Zeit darüber geschrieben, mit Beispielcode: JPGs aus PDFs extrahieren .


1
danke Ned. Es sieht so aus, als ob die speziellen PDFs, für die ich dies benötige, kein JPEG in situ verwenden, aber ich werde Ihr Beispiel behalten, falls es mit anderen Dingen übereinstimmt, die auftauchen.
Matt Wilkie

3
Können Sie bitte ein paar Dinge im Code erklären? Warum sollten Sie beispielsweise zuerst nach "Stream" und dann nach "Stream" suchen startmark? Sie könnten einfach anfangen zu suchen, startmarkda dies der Beginn von JPG ist. Nein? und was ist der Sinn der startfixVariablen, Sie ändern es überhaupt nicht ..
user3599803

Dies funktionierte perfekt für das PDF, aus dem ich Bilder extrahieren wollte. (Falls es jemand anderem hilft, habe ich seinen Code als .py-Datei gespeichert, dann Python 2.7.18 installiert / verwendet, um ihn auszuführen, und den Pfad zu meiner PDF-Datei als einzelnes Befehlszeilenargument übergeben.)
Matt

25

In Python mit PyPDF2 für CCITTFaxDecode-Filter:

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

Das hat bei mir sofort funktioniert und ist extrem schnell !! Alle meine Bilder wurden invertiert ausgegeben, aber ich konnte das mit OpenCV beheben. Ich habe ImageMagicks convertverwendet subprocess, um es aufzurufen, aber es ist schmerzhaft langsam. Vielen Dank für das Teilen dieser Lösung
crld

2
Wie an anderer Stelle darauf hingewiesen , Sie tiff_header_structlesen sollen '<' + '2s' + 'H' + 'L' + 'H' + 'HHLL' * 8 + 'L'. Beachten Sie insbesondere die 'L'am Ende.
Spender


17

Libpoppler wird mit einem Tool namens "pdfimages" geliefert, das genau dies tut.

(Auf Ubuntu-Systemen ist es im Poppler-Utils-Paket enthalten)

http://poppler.freedesktop.org/

http://en.wikipedia.org/wiki/Pdfimages

Windows-Binärdateien: http://blog.alivate.com.au/poppler-windows/


Ich würde mich freuen, wenn jemand ein Python-Modul finden würde, das nicht auf pdfimagesder Installation auf dem Subsystem beruht .
user1717828

es gibt keine Bilder pagewise aus
Alok Nayak

9

Ich bevorzuge Minecart, da es extrem einfach zu bedienen ist. Das folgende Snippet zeigt, wie Sie Bilder aus einem PDF extrahieren:

#pip install minecart
import minecart

pdffile = open('Invoices.pdf', 'rb')
doc = minecart.Document(pdffile)

page = doc.get_page(0) # getting a single page

#iterating through all pages
for page in doc.iter_pages():
    im = page.images[0].as_pil()  # requires pillow
    display(im)

Hallo zusammen, Minecart funktioniert perfekt, aber ich habe ein kleines Problem: Manchmal wird das Layout der Bilder geändert (horizontal -> vertikal). Haben Sie eine Idee, wie ich das vermeiden könnte? Vielen Dank!
Sha Li

7

Hier ist meine Version von 2019, die rekursiv alle Bilder aus PDF abruft und sie mit PIL liest. Kompatibel mit Python 2/3. Ich habe auch festgestellt, dass Bilder in PDF manchmal von zlib komprimiert werden, sodass mein Code die Dekomprimierung unterstützt.

#!/usr/bin/env python3
try:
    from StringIO import StringIO
except ImportError:
    from io import BytesIO as StringIO
from PIL import Image
from PyPDF2 import PdfFileReader, generic
import zlib


def get_color_mode(obj):

    try:
        cspace = obj['/ColorSpace']
    except KeyError:
        return None

    if cspace == '/DeviceRGB':
        return "RGB"
    elif cspace == '/DeviceCMYK':
        return "CMYK"
    elif cspace == '/DeviceGray':
        return "P"

    if isinstance(cspace, generic.ArrayObject) and cspace[0] == '/ICCBased':
        color_map = obj['/ColorSpace'][1].getObject()['/N']
        if color_map == 1:
            return "P"
        elif color_map == 3:
            return "RGB"
        elif color_map == 4:
            return "CMYK"


def get_object_images(x_obj):
    images = []
    for obj_name in x_obj:
        sub_obj = x_obj[obj_name]

        if '/Resources' in sub_obj and '/XObject' in sub_obj['/Resources']:
            images += get_object_images(sub_obj['/Resources']['/XObject'].getObject())

        elif sub_obj['/Subtype'] == '/Image':
            zlib_compressed = '/FlateDecode' in sub_obj.get('/Filter', '')
            if zlib_compressed:
               sub_obj._data = zlib.decompress(sub_obj._data)

            images.append((
                get_color_mode(sub_obj),
                (sub_obj['/Width'], sub_obj['/Height']),
                sub_obj._data
            ))

    return images


def get_pdf_images(pdf_fp):
    images = []
    try:
        pdf_in = PdfFileReader(open(pdf_fp, "rb"))
    except:
        return images

    for p_n in range(pdf_in.numPages):

        page = pdf_in.getPage(p_n)

        try:
            page_x_obj = page['/Resources']['/XObject'].getObject()
        except KeyError:
            continue

        images += get_object_images(page_x_obj)

    return images


if __name__ == "__main__":

    pdf_fp = "test.pdf"

    for image in get_pdf_images(pdf_fp):
        (mode, size, data) = image
        try:
            img = Image.open(StringIO(data))
        except Exception as e:
            print ("Failed to read image with PIL: {}".format(e))
            continue
        # Do whatever you want with the image

Dieser Code funktionierte für mich fast ohne Änderungen. Vielen Dank.
xax

6

Ich habe mit dem Code von @sylvain begonnen. Es gab einige Fehler, wie die Ausnahme NotImplementedError: unsupported filter /DCTDecodevon getData oder die Tatsache, dass der Code auf einigen Seiten keine Bilder fand, weil sie sich auf einer tieferen Ebene als die Seite befanden.

Da ist mein Code:

import PyPDF2

from PIL import Image

import sys
from os import path
import warnings
warnings.filterwarnings("ignore")

number = 0

def recurse(page, xObject):
    global number

    xObject = xObject['/Resources']['/XObject'].getObject()

    for obj in xObject:

        if xObject[obj]['/Subtype'] == '/Image':
            size = (xObject[obj]['/Width'], xObject[obj]['/Height'])
            data = xObject[obj]._data
            if xObject[obj]['/ColorSpace'] == '/DeviceRGB':
                mode = "RGB"
            else:
                mode = "P"

            imagename = "%s - p. %s - %s"%(abspath[:-4], p, obj[1:])

            if xObject[obj]['/Filter'] == '/FlateDecode':
                img = Image.frombytes(mode, size, data)
                img.save(imagename + ".png")
                number += 1
            elif xObject[obj]['/Filter'] == '/DCTDecode':
                img = open(imagename + ".jpg", "wb")
                img.write(data)
                img.close()
                number += 1
            elif xObject[obj]['/Filter'] == '/JPXDecode':
                img = open(imagename + ".jp2", "wb")
                img.write(data)
                img.close()
                number += 1
        else:
            recurse(page, xObject[obj])



try:
    _, filename, *pages = sys.argv
    *pages, = map(int, pages)
    abspath = path.abspath(filename)
except BaseException:
    print('Usage :\nPDF_extract_images file.pdf page1 page2 page3 …')
    sys.exit()


file = PyPDF2.PdfFileReader(open(filename, "rb"))

for p in pages:    
    page0 = file.getPage(p-1)
    recurse(p, page0)

print('%s extracted images'% number)

Dieser Code schlägt für mich bei '/ ICCBased' '/ FlateDecode' gefilterten Bildern mitimg = Image.frombytes(mode, size, data) ValueError: not enough image data
GrantD71

1
@ GrantD71 Ich bin kein Experte und habe noch nie von ICCBased gehört. Außerdem ist Ihr Fehler nicht reproduzierbar, wenn Sie keine Eingaben machen.
Labo

Ich bekomme eine KeyError: '/ColorSpace', also würde ich Ihre Leitung durch DeviceRGB durch ersetzen if '/ColorSpace' not in xObject[obj] or xObject[obj]['/ColorSpace'] == '/DeviceRGB':. Jedenfalls hat das am Ende bei mir nicht funktioniert, da die Bilder wahrscheinlich PNG waren (nicht sicher).
Basj

@Basj mein Code soll auch mit PNG funktionieren. Was ist der Wert von xObject[obj]['/Filter']?
Labo

2
Ich habe Ihren Code so angepasst, dass er sowohl mit Python 2 als auch mit Python 3 funktioniert. Ich habe auch die / Indexed-Änderung von Ronan Paixão implementiert. Ich habe auch den Filter if / elif so geändert, dass er "in" und nicht gleich ist. Ich hatte eine PDF-Datei mit dem Typ / Filter ['/ ASCII85Decode', '/ FlateDecode']. Ich habe auch die Funktion geändert, um Bild-Blobs zurückzugeben, anstatt in eine Datei zu schreiben. Den aktualisierten Code finden Sie hier: gist.github.com/gstorer/f6a9f1dfe41e8e64dcf58d07afa9ab2a
Gerald

4

Ich habe ImageMagick auf meinem Server installiert und dann Befehlszeilenaufrufe ausgeführt über Popen:

 #!/usr/bin/python

 import sys
 import os
 import subprocess
 import settings

 IMAGE_PATH = os.path.join(settings.MEDIA_ROOT , 'pdf_input' )

 def extract_images(pdf):
     output = 'temp.png'
     cmd = 'convert ' + os.path.join(IMAGE_PATH, pdf) + ' ' + os.path.join(IMAGE_PATH, output)
     subprocess.Popen(cmd.split(), stderr=subprocess.STDOUT, stdout=subprocess.PIPE)

Dadurch wird für jede Seite ein Bild erstellt und als temp-0.png, temp-1.png .... gespeichert. Dies ist nur dann "Extraktion", wenn Sie ein PDF mit nur Bildern und ohne Text erhalten haben.


1
Image Magick verwendet dazu Ghostscript. Sie können diesen Beitrag auf den Ghostscript-Befehl überprüfen , den Image Magick unter der Decke verwendet.
Filipe Correia

Ich muss sagen, dass das Rendering manchmal wirklich schlecht ist. Mit Poppler funktioniert es ohne Probleme.
Raffi

4

Nach einiger Suche habe ich das folgende Skript gefunden, das sehr gut mit meinen PDFs funktioniert. Es behandelt nur JPG, aber es hat perfekt mit meinen ungeschützten Dateien funktioniert. Außerdem sind keine externen Bibliotheken erforderlich.

Das Drehbuch stammt von Ned Batchelder und nicht von mir. Python3-Code: JPGs aus PDFs extrahieren. Schnell und dreckig

import sys

with open(sys.argv[1],"rb") as file:
    file.seek(0)
    pdf = file.read()

startmark = b"\xff\xd8"
startfix = 0
endmark = b"\xff\xd9"
endfix = 2
i = 0

njpg = 0
while True:
    istream = pdf.find(b"stream", i)
    if istream < 0:
        break
    istart = pdf.find(startmark, istream, istream + 20)
    if istart < 0:
        i = istream + 20
        continue
    iend = pdf.find(b"endstream", istart)
    if iend < 0:
        raise Exception("Didn't find end of stream!")
    iend = pdf.find(endmark, iend - 20)
    if iend < 0:
        raise Exception("Didn't find end of JPG!")

    istart += startfix
    iend += endfix
    print("JPG %d from %d to %d" % (njpg, istart, iend))
    jpg = pdf[istart:iend]
    with open("jpg%d.jpg" % njpg, "wb") as jpgfile:
        jpgfile.write(jpg)

    njpg += 1
    i = iend

1
Das sieht interessant aus. Wo hast du es gefunden? (Und die Formatierung in Ihrem Beitrag ist ein bisschen durcheinander. Unausgeglichene Zitate, denke ich.)
Matt Wilkie


4

Viel einfachere Lösung:

Verwenden Sie das Paket poppler-utils. Verwenden Sie zur Installation Homebrew (Homebrew ist MacOS-spezifisch, aber das Poppler-Utils-Paket für Widows oder Linux finden Sie hier: https://poppler.freedesktop.org/ ). In der ersten Codezeile unten werden Poppler-Utils mit Homebrew installiert. Nach der Installation extrahiert die zweite Zeile (über die Befehlszeile ausführen) Bilder aus einer PDF-Datei und nennt sie "image *". Um dieses Programm in Python auszuführen, verwenden Sie das Betriebssystem os oder subprocess. Die dritte Zeile enthält Code mit dem OS-Modul. Darunter befindet sich ein Beispiel mit einem Unterprozess (Python 3.5 oder höher für die Funktion run ()). Weitere Informationen hier: https://www.cyberciti.biz/faq/easily-extract-images-from-pdf-file/

brew install poppler

pdfimages file.pdf image

import os
os.system('pdfimages file.pdf image')

oder

import subprocess
subprocess.run('pdfimages file.pdf image', shell=True)

1
Danke Colton. Homebrew ist nur MacOS. Es wird empfohlen, das Betriebssystem zu beachten, wenn die Anweisungen plattformspezifisch sind.
Matt Wilkie

@ Mattwilkie - Danke für die Hinweise. Ich werde dies in meiner Antwort vermerken.
Colton Hicks

3

Ich habe dies für mein eigenes Programm getan und festgestellt, dass PyMuPDF die beste Bibliothek ist. Auf diese Weise können Sie die "xref" -Nummern jedes Bilds auf jeder Seite ermitteln und damit die Rohbilddaten aus der PDF-Datei extrahieren.

import fitz
from PIL import Image
import io

filePath = "path/to/file.pdf"
#opens doc using PyMuPDF
doc = fitz.Document(filePath)

#loads the first page
page = doc.loadPage(0)

#[First image on page described thru a list][First attribute on image list: xref n], check PyMuPDF docs under getImageList()
xref = page.getImageList()[0][0]

#gets the image as a dict, check docs under extractImage 
baseImage = doc.extractImage(xref)

#gets the raw string image data from the dictionary and wraps it in a BytesIO object before using PIL to open it
image = Image.open(io.BytesIO(baseImage['image']))

#Displays image for good measure
image.show()

Schauen Sie sich auf jeden Fall die Dokumente an.


Beste Option IMO: Nach der Installation fitzunter Win 10 wurde folgende Fehlermeldung angezeigt: ModuleNotFoundError: Kein Modul mit dem Namen 'Frontend', das durch pip install PyMuPDFdie hier beschriebene Installation leicht gelöst werden konnte: stackoverflow.com/questions/56467667/…
Peter

3

Nun, ich habe seit vielen Wochen damit zu kämpfen, viele dieser Antworten haben mir geholfen, aber es fehlte immer etwas, anscheinend hatte hier niemand jemals Probleme mit jbig2-codierten Bildern .

In der Reihe von PDF-Dateien, die ich scannen soll, sind in jbig2 codierte Bilder sehr beliebt.

Soweit ich weiß, gibt es viele Kopier- / Scan-Geräte, die Papiere scannen und in PDF-Dateien mit jbig2-codierten Bildern umwandeln.

Nach vielen Testtagen entschied man sich also vor langer Zeit für die hier von dkagedal vorgeschlagene Antwort.

Hier ist meine Schritt für Schritt unter Linux: (Wenn Sie ein anderes Betriebssystem haben, schlage ich vor, ein Linux-Docker zu verwenden, wird es viel einfacher.)

Erster Schritt:

apt-get install poppler-utils

Dann konnte ich das Befehlszeilentool pdfimages wie folgt ausführen:

pdfimages -all myfile.pdf ./images_found/

Mit dem obigen Befehl können Sie alle in myfile.pdf enthaltenen Bilder extrahieren und sie in images_found speichern lassen (Sie müssen images_found vorher erstellen).

In der Liste finden Sie verschiedene Arten von Bildern, png, jpg, tiff; All dies ist mit jedem Grafikwerkzeug leicht lesbar.

Dann haben Sie einige Dateien mit den Namen: -145.jb2e und -145.jb2g.

Diese 2 Dateien enthalten EIN in jbig2 codiertes BILD, das in 2 verschiedenen Dateien gespeichert ist, eine für den Header und eine für die Daten

Wieder habe ich viele Tage verloren, um herauszufinden, wie man diese Dateien in etwas Lesbares konvertiert, und schließlich bin ich auf dieses Tool namens jbig2dec gestoßen

Also müssen Sie zuerst dieses magische Werkzeug installieren:

apt-get install jbig2dec

dann kannst du laufen:

jbig2dec -t png -145.jb2g -145.jb2e

Sie werden endlich in der Lage sein, alle extrahierten Bilder in etwas Nützliches umzuwandeln.

Viel Glück!


Dies sind nützliche Informationen , die dokumentiert und weitergegeben werden sollten , wie Sie es gerade getan haben. +1. Allerdings empfiehlt Entsendung ich als eigene neue Frage und dann selbst Antwort , weil es keine Adresse dies in Python zu tun, der Punkt dieser Frage ist (Sie können ferner die Pfosten , da dies zu vernetzen ist verwandt.)
matt wilkie

Hallo @mattwilkie, danke für den Rat, hier ist die Frage: stackoverflow.com/questions/60851124/…
Marco

2

Ab Februar 2019 funktioniert die von @sylvain (zumindest in meinem Setup) angegebene Lösung nicht ohne eine kleine Änderung: Es xObject[obj]['/Filter']handelt sich nicht um einen Wert, sondern um eine Liste. Damit das Skript funktioniert, musste ich das Format ändern Überprüfung wie folgt:

import PyPDF2, traceback

from PIL import Image

input1 = PyPDF2.PdfFileReader(open(src, "rb"))
nPages = input1.getNumPages()
print nPages

for i in range(nPages) :
    print i
    page0 = input1.getPage(i)
    try :
        xObject = page0['/Resources']['/XObject'].getObject()
    except : xObject = []

    for obj in xObject:
        if xObject[obj]['/Subtype'] == '/Image':
            size = (xObject[obj]['/Width'], xObject[obj]['/Height'])
            data = xObject[obj].getData()
            try :
                if xObject[obj]['/ColorSpace'] == '/DeviceRGB':
                    mode = "RGB"
                elif xObject[obj]['/ColorSpace'] == '/DeviceCMYK':
                    mode = "CMYK"
                    # will cause errors when saving
                else:
                    mode = "P"

                fn = 'p%03d-%s' % (i + 1, obj[1:])
                print '\t', fn
                if '/FlateDecode' in xObject[obj]['/Filter'] :
                    img = Image.frombytes(mode, size, data)
                    img.save(fn + ".png")
                elif '/DCTDecode' in xObject[obj]['/Filter']:
                    img = open(fn + ".jpg", "wb")
                    img.write(data)
                    img.close()
                elif '/JPXDecode' in xObject[obj]['/Filter'] :
                    img = open(fn + ".jp2", "wb")
                    img.write(data)
                    img.close()
                elif '/LZWDecode' in xObject[obj]['/Filter'] :
                    img = open(fn + ".tif", "wb")
                    img.write(data)
                    img.close()
                else :
                    print 'Unknown format:', xObject[obj]['/Filter']
            except :
                traceback.print_exc()

1
DCTDecode CCITTFaxDecode-Filter sind noch nicht implementiert.
Abhimanyu

Hallo @Modem Rakesh goud, können Sie bitte die PDF-Datei bereitstellen, die diesen Fehler ausgelöst hat? Vielen Dank!
mxl

Leider kann ich das pdf nicht teilen.
Modem Rakesh goud

Oder wären Sie irgendwann im Besitz eines Programms wie Acrobat (nicht Reader, sondern der PRO-Version) oder alternativ eines anderen PDF-Bearbeitungsprogramms, das einen Teil des PDF extrahieren und nur diesen Teil bereitstellen kann, oder geben Sie mir einfach das traceback.print_exc()von die angegebene Fehlerzeile, damit ich sehen kann, was sie ausgelöst hat; Oder entscheiden Sie sich für eine andere Lösung hier auf dieser Website, da die hier angegebene (meines Wissens nach) darauf ausgerichtet ist, eine verlustfreie 1: 1-Extraktion von Daten aus einem PDF-Dokument bereitzustellen und möglicherweise nicht das ist, wonach Sie suchen, danke!
mxl

1

Ich habe all diese hier in PyPDFTK zusammengefügt .

Mein eigener Beitrag ist der Umgang mit /IndexedDateien als solche:

for obj in xObject:
    if xObject[obj]['/Subtype'] == '/Image':
        size = (xObject[obj]['/Width'], xObject[obj]['/Height'])
        color_space = xObject[obj]['/ColorSpace']
        if isinstance(color_space, pdf.generic.ArrayObject) and color_space[0] == '/Indexed':
            color_space, base, hival, lookup = [v.getObject() for v in color_space] # pg 262
        mode = img_modes[color_space]

        if xObject[obj]['/Filter'] == '/FlateDecode':
            data = xObject[obj].getData()
            img = Image.frombytes(mode, size, data)
            if color_space == '/Indexed':
                img.putpalette(lookup.getData())
                img = img.convert('RGB')
            img.save("{}{:04}.png".format(filename_prefix, i))

Beachten Sie, dass Sie beim /IndexedAuffinden von Dateien nicht einfach /ColorSpacemit einer Zeichenfolge vergleichen können , da diese als Zeichenfolge geliefert wird ArrayObject. Wir müssen also das Array überprüfen und die indizierte Palette ( lookupim Code) abrufen und im PIL-Image-Objekt festlegen, andernfalls bleibt es nicht initialisiert (Null) und das gesamte Bild wird schwarz angezeigt.

Mein erster Instinkt war, sie als GIFs (ein indiziertes Format) zu speichern, aber meine Tests ergaben, dass PNGs kleiner waren und genauso aussahen.

Ich habe diese Art von Bildern beim Drucken in PDF mit Foxit Reader PDF Printer gefunden.


1

Sie können den pdfimagesBefehl auch in Ubuntu verwenden.

Installieren Sie poppler lib mit den folgenden Befehlen.

sudo apt install poppler-utils

sudo apt-get install python-poppler

pdfimages file.pdf image

Liste der erstellten Dateien sind (z. B. gibt es zwei Bilder im PDF)

image-000.png
image-001.png

Es klappt ! Jetzt können Sie a verwenden subprocess.run, um dies von Python aus auszuführen.


1

Nach dem Lesen der Beiträge mit pyPDF2 .

Der Fehler bei der Verwendung des Codes NotImplementedError: unsupported filter /DCTDecodevon @ sylvain muss von der folgenden Methode herrühren .getData(): Er wird bei Verwendung ._datastattdessen von @Alex Paramonov behoben.

Bisher habe ich nur "DCTDecode" -Fälle getroffen, aber ich teile den angepassten Code, der Anmerkungen aus den verschiedenen Beiträgen enthält: Von zilbvon @Alex Paramonov, sub_obj['/Filter']als Liste, von @mxl.

Hoffe, es kann den pyPDF2-Benutzern helfen. Folgen Sie dem Code:

    import sys
    import PyPDF2, traceback
    import zlib
    try:
        from PIL import Image
    except ImportError:
        import Image

    pdf_path = 'path_to_your_pdf_file.pdf'
    input1 = PyPDF2.PdfFileReader(open(pdf_path, "rb"))
    nPages = input1.getNumPages()

    for i in range(nPages) :
        page0 = input1.getPage(i)

        if '/XObject' in page0['/Resources']:
            try:
                xObject = page0['/Resources']['/XObject'].getObject()
            except :
                xObject = []

            for obj_name in xObject:
                sub_obj = xObject[obj_name]
                if sub_obj['/Subtype'] == '/Image':
                    zlib_compressed = '/FlateDecode' in sub_obj.get('/Filter', '')
                    if zlib_compressed:
                       sub_obj._data = zlib.decompress(sub_obj._data)

                    size = (sub_obj['/Width'], sub_obj['/Height'])
                    data = sub_obj._data#sub_obj.getData()
                    try :
                        if sub_obj['/ColorSpace'] == '/DeviceRGB':
                            mode = "RGB"
                        elif sub_obj['/ColorSpace'] == '/DeviceCMYK':
                            mode = "CMYK"
                            # will cause errors when saving (might need convert to RGB first)
                        else:
                            mode = "P"

                        fn = 'p%03d-%s' % (i + 1, obj_name[1:])
                        if '/Filter' in sub_obj:
                            if '/FlateDecode' in sub_obj['/Filter']:
                                img = Image.frombytes(mode, size, data)
                                img.save(fn + ".png")
                            elif '/DCTDecode' in sub_obj['/Filter']:
                                img = open(fn + ".jpg", "wb")
                                img.write(data)
                                img.close()
                            elif '/JPXDecode' in sub_obj['/Filter']:
                                img = open(fn + ".jp2", "wb")
                                img.write(data)
                                img.close()
                            elif '/CCITTFaxDecode' in sub_obj['/Filter']:
                                img = open(fn + ".tiff", "wb")
                                img.write(data)
                                img.close()
                            elif '/LZWDecode' in sub_obj['/Filter'] :
                                img = open(fn + ".tif", "wb")
                                img.write(data)
                                img.close()
                            else :
                                print('Unknown format:', sub_obj['/Filter'])
                        else:
                            img = Image.frombytes(mode, size, data)
                            img.save(fn + ".png")
                    except:
                        traceback.print_exc()
        else:
            print("No image found for page %d" % (i + 1))

0

Versuchen Sie es mit dem folgenden Code. Es wird das gesamte Bild aus dem PDF extrahieren.

    import sys
    import PyPDF2
    from PIL import Image
    pdf=sys.argv[1]
    print(pdf)
    input1 = PyPDF2.PdfFileReader(open(pdf, "rb"))
    for x in range(0,input1.numPages):
        xObject=input1.getPage(x)
        xObject = xObject['/Resources']['/XObject'].getObject()
        for obj in xObject:
            if xObject[obj]['/Subtype'] == '/Image':
                size = (xObject[obj]['/Width'], xObject[obj]['/Height'])
                print(size)
                data = xObject[obj]._data
                #print(data)
                print(xObject[obj]['/Filter'])
                if xObject[obj]['/Filter'][0] == '/DCTDecode':
                    img_name=str(x)+".jpg"
                    print(img_name)
                    img = open(img_name, "wb")
                    img.write(data)
                    img.close()
        print(str(x)+" is done")
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.