Витягувати зображення з PDF без передискретизації у python?


80

Як можна витягти всі зображення з PDF-документа в рідній роздільній здатності та форматі? (Мається на увазі вилучення tiff як tiff, jpeg як jpeg тощо тощо без передискретизації). Макет неважливий, мені байдуже, якщо вихідне зображення розташоване на сторінці.

Я використовую python 2.7, але можу використовувати 3.x, якщо потрібно.


Дякую. Те, що "як зображення зберігаються у форматі PDF", не спрацювало, але, схоже, це: jpedal.org/PDFblog/2010/04/…
nealmcb

Існує бібліотека JPedal Java, яка робить це під назвою PDF Clippped Image Extraction . Автор, Марк Стівенс, має короткий огляд високого рівня того, як зображення зберігаються в PDF, що може допомогти комусь побудувати екстрактор пітона.
matt wilkie

Відповіді:


46

Ви можете використовувати модуль PyMuPDF. Це виводить усі зображення у форматі .png-файлів, але працює швидко і швидко.

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

дивіться тут, щоб дізнатися більше


2
Це чудово працює! ( pip install pymudfспочатку потрібно очевидно)
Бас

9
* pip install pymupdfдля колег Google, які цікавляться, чому вищевказана установка не вдається
VSZM

9
Замість того, щоб pip install pymupdfпробувати pip install PyMuPDF більше інформації
Damotorie

1
З цим кодом, який я отримую RuntimeError: pixmap must be grayscale or rgb to write as png, може хтось допомогти?
сховище

5
@vault Цей коментар застарів. Вам слід змінити "if pix.n <5" на "if pix.n - pix.alpha <4", оскільки початковий стан неправильно знаходить зображення CMYK.
Орінга

41

У Python з бібліотеками PyPDF2 та Pillow це просто:

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
Спочатку схвильований цим, але він викинув NotImplementedError: unsupported filter /DCTDecodeабо ... /JPXDecodeз xObject[obj].getData()першої пари PDF-файлів, які я протестував. Подробиці на gist.github.com/maphew/fe6ba4bf9ed2bc98ecf5
Метт Вілкі

4
Нещодавно я переніс модифікацію '/ DCTDecode' до бібліотеки PyPDF2. Ви можете використовувати мій репозиторій: github.com/sylvainpelissier/PyPDF2, поки він інтегрований в основну гілку.
sylvain

1
Дякуємо за оновлення, але вибачте, все одно не піде. Суть оновлена. Я отримую ValueError: not enough image dataвбудовані зображення dctdecode та unsupported filter /JPXDecodeв іншому pdf.
matt wilkie

1
робить прогрес! PDF-файли dctdecode обробляються зараз без помилок (хоча іноді вихідні зображення перевертаються). Однак файл JPXDecode тепер KeyError:/Filterзамість цього видає . Я оновив суть відповідно. Файли PDF - це лише випадкові файли з мережі. Суть посилань на джерела.
matt wilkie

29
"Це просто ... "
mlissner

34

Часто у форматі PDF зображення просто зберігається як є. Наприклад, PDF-файл із вставленим jpg матиме діапазон байтів десь посередині, що при розпакуванні є дійсним файлом jpg. Ви можете використовувати це, щоб дуже просто витягти діапазони байтів з PDF. Я писав про це деякий час тому, із зразком коду: Витяг JPG з PDF-файлів .


1
спасибі Неде. Схоже, конкретні PDF-файли, які мені потрібні, не використовують jpeg in-situ, але я зберігатиму ваш зразок навколо, якщо він збігатиметься з іншими речами.
matt wilkie

3
Ви можете пояснити кілька речей у коді? Наприклад, чому б вам спочатку шукати "потік", а потім - startmark? ви можете просто розпочати пошук, startmarkоскільки це початок JPG ні? а який сенс startfixзмінної, ти взагалі її не
змінюєш

Це чудово працювало для PDF-файлу, з якого я хотів витягти зображення. (На випадок, якщо це допоможе комусь іншому, я зберег його код як файл .py, а потім встановив / використав Python 2.7.18 для його запуску, передавши шлях до мого PDF як єдиний аргумент командного рядка.)
matt

25

У Python з PyPDF2 для фільтра CCITTFaxDecode:

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

Це одразу у мене спрацювало, і це надзвичайно швидко !! Всі мої зображення вийшли перевернутими, але я зміг це виправити за допомогою OpenCV. Я використовую ImageMagick - й з convertвикористанням subprocessназвати , але це болісно повільно. Дякуємо, що поділилися цим рішенням
crld

2
Як вказували в інших місцях, вам tiff_header_structслід прочитати '<' + '2s' + 'H' + 'L' + 'H' + 'HHLL' * 8 + 'L'. Зверніть увагу, зокрема, 'L'на кінець.
Диспенсер

Будь-яка допомога з цього приводу: stackoverflow.com/questions/55899363/…
Aakash Basu,

17

Libpoppler постачається з інструментом під назвою "pdfimages", який робить саме це.

(У системах ubuntu це в пакеті poppler-utils)

http://poppler.freedesktop.org/

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

Бінарні файли Windows: http://blog.alivate.com.au/poppler-windows/


Я б дуже хотів, щоб хтось знайшов модуль Python, який не покладається на pdfimagesвстановлення в підсистемі.
user1717828

він не виводить зображення по сторінках
Алок Наяк

10

Мені більше подобається minecart, оскільки він надзвичайно простий у використанні. У наведеному нижче фрагменті показано, як витягти зображення з PDF-файлу:

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

Привіт, Minecart працює ідеально, але у мене є невелика проблема: іноді макет зображень змінюється (горизонтальний -> вертикальний). Ти уявляєш, як я міг цього уникнути? Дякую!
Ша Лі

З minecart я отримую: pdfminer.pdftypes.PDFNotImplementedError: Непідтримуваний фільтр: / CCITTFaxDecode
Javi12

7

Ось моя версія від 2019 року, яка рекурсивно отримує всі зображення з PDF і зчитує їх за допомогою PIL. Сумісний з Python 2/3. Я також виявив, що іноді зображення у PDF може стискатися zlib, тому мій код підтримує декомпресію.

#!/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

Цей код працював у мене майже без змін. Дякую.
xax

6

Я почав з коду @sylvain. Були деякі недоліки, наприклад, виняток NotImplementedError: unsupported filter /DCTDecodegetData, або той факт, що в коді не вдалося знайти зображення на деяких сторінках, оскільки вони були на глибшому рівні, ніж сторінка.

Є мій код:

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)

Цей код для мене не вдається на "/ ICCBased" '/ FlateDecode' відфільтрованих зображеннях ізimg = Image.frombytes(mode, size, data) ValueError: not enough image data
GrantD71

1
@ GrantD71 Я не фахівець і раніше ніколи не чув про ICCB. Плюс ваша помилка не відтворюється, якщо ви не надаєте вхідні дані.
Лабо

Я отримую KeyError: '/ColorSpace', тому я б замінив вашу лінію на DeviceRGB на if '/ColorSpace' not in xObject[obj] or xObject[obj]['/ColorSpace'] == '/DeviceRGB':. У кожному разі, це в кінці кінців у мене не спрацювало, оскільки зображення, ймовірно, були у форматі PNG (не впевнений).
Бас

@Basj мій код також повинен працювати з PNG. У чому цінність xObject[obj]['/Filter']?
Лабо

2
Я адаптував ваш код для роботи як на Python 2, так і на 3. Я також реалізував / Індексовані зміни від Ronan Paixão. Я також змінив фільтр if / elif на "in", а не на дорівнює. У мене був PDF із типом / Filter ['/ ASCII85Decode', '/ FlateDecode']. Я також змінив функцію повернення крапок зображення, а не запису у файл. Оновлений код можна знайти тут: gist.github.com/gstorer/f6a9f1dfe41e8e64dcf58d07afa9ab2a
Джеральд

4

Я встановив ImageMagick на своєму сервері, а потім запустив виклики командного рядка через 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)

Це створить зображення для кожної сторінки та збереже їх у форматі temp-0.png, temp-1.png .... Це лише "витяг", якщо у вас є PDF-файл із лише зображеннями та без тексту.


1
Image magick використовує ghostscript для цього. Ви можете перевірити цю публікацію на наявність команди ghostscript, яку використовує Магія зображення під обкладинками.
Філіпе Коррея

Треба сказати, що іноді рендеринг буває дуже поганим. З poppler це працює без будь-яких проблем.
Раффі

4

Після деяких пошуків я знайшов наступний сценарій, який дуже добре працює з моїми PDF-файлами. Це стосується лише JPG, але він чудово працював з моїми незахищеними файлами. Також не вимагає жодних зовнішніх бібліотек.

Щоб не брати на себе повагу, сценарій походить від Неда Батчелдера, а не від мене. Код Python3: витягніть JPG-файли з PDF-файлів. Швидкий і брудний

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
Це виглядає цікаво. Де ти його знайшов? (І форматування у вашому дописі трохи заплутане. Думаю, незбалансовані цитати.)
matt wilkie

1
nedbatchelder.com/blog/200712/extracting_jpgs_from_pdfs.html оригінальний допис ви можете знайти тут ...
Макс АХ Хартвігсен,

4

Набагато простіше рішення:

Використовуйте пакет poppler-utils. Щоб встановити його, використовуйте homebrew (homebrew є специфічним для MacOS, але ви можете знайти пакет poppler-utils для вдів або Linux тут: https://poppler.freedesktop.org/ ). Перший рядок коду нижче встановлює poppler-utils за допомогою домашньої мови. Після встановлення другий рядок (запускається з командного рядка) потім витягує зображення з файлу PDF і називає їх "зображення *". Для запуску цієї програми з Python використовуйте os або модуль підпроцесу. Третій рядок - це код, що використовує модуль os, нижче - приклад із підпроцесом (python 3.5 або пізніша версія для функції run ()). Більше інформації тут: 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')

або

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

1
Спасибі Колтоне. Homebrew - це лише MacOS. Хорошою практикою є зазначати ОС, коли інструкції стосуються певної платформи.
matt wilkie

@mattwilkie - Дякую за увагу. Відзначу це у своїй відповіді.
Колтон Хікс,

3

Я зробив це для власної програми і виявив, що найкращою бібліотекою для використання була PyMuPDF. Це дозволяє вам дізнатися "xref" номери кожного зображення на кожній сторінці та використовувати їх для вилучення необроблених даних зображень з PDF.

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

Безумовно, перегляньте документи.


Найкращий варіант IMO: Після встановлення fitz на Win 10, я отримав помилку: ModuleNotFoundError: Немає модуля з назвою 'frontend', що було легко вирішити шляхом встановлення, pip install PyMuPDFяк обговорювалося тут: stackoverflow.com/questions/56467667/…
Петро,

3

Ну, я боровся з цим протягом багатьох тижнів, багато з цих відповідей допомогли мені пройти, але завжди чогось не вистачало, мабуть, ніхто тут ніколи не мав проблем із зображеннями, закодованими jbig2 .

У наборі PDF-файлів, який я маю сканувати, зображення, закодовані у jbig2, дуже популярні.

Наскільки я розумію, існує безліч копіювальних / скануючих машин, які сканують папери та перетворюють їх у файли PDF, повні зображень, кодованих jbig2.

Тож після багатьох днів тестів вирішив піти на відповідь, запропоновану тут давно dkagedal.

Ось мій крок за кроком на Linux: (якщо у вас інша ОС, я пропоную використовувати докер Linux це буде набагато простіше.)

Перший крок:

apt-get install poppler-utils

Тоді я зміг запустити інструмент командного рядка, який називається pdfimages, таким чином:

pdfimages -all myfile.pdf ./images_found/

За допомогою вищезазначеної команди ви зможете витягти всі містяться зображення в myfile.pdf, і збережете їх у images_found (перед цим потрібно створити images_found)

У списку ви знайдете кілька типів зображень, png, jpg, tiff; все це легко читати за допомогою будь-якого графічного інструменту.

Тоді у вас буде кілька файлів з іменами: -145.jb2e та -145.jb2g.

Ці 2 файли містять ОДИН ЗОБРАЖЕННЯ, закодований у jbig2, збережений у 2 різних файлах - одному для заголовка та одному для даних

Я знову втратив багато днів, намагаючись дізнатись, як перетворити ці файли на щось читабельне, і нарешті я натрапив на цей інструмент під назвою jbig2dec

Отже, спочатку потрібно встановити цей чарівний інструмент:

apt-get install jbig2dec

тоді ви можете запустити:

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

Ви нарешті зможете перетворити всі витягнуті зображення на щось корисне.

Щасти!


Це корисна інформація, яку слід документувати та ділитися нею , як ви щойно зробили. +1. Тим НЕ менше , я пропоную розмістити як свій власний новий питання , а потім сам-відповідь , тому що він не робить це адреса в Python, який є точкою цього Q. (Ви можете зшити пости як це є пов'язаним.)
матовим Уїлкі

Привіт @mattwilkie, дякую за пораду, ось питання: stackoverflow.com/questions/60851124/…
Марко

2

Станом на лютий 2019 р. Рішення, надане @sylvain (принаймні на моїй установці), не працює без невеликої модифікації: xObject[obj]['/Filter']це не значення, а список, тому, щоб сценарій працював, мені довелося змінити формат перевірка наступним чином:

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 фільтри все ще не реалізовані.
Абхіманю

Привіт, @Modem Rakesh goud, не могли б ви надати файл PDF, який спричинив цю помилку? Дякую!
mxl,

На жаль, я не можу поділитися цим pdf.
Modem

Або ви в кінцевому підсумку буде в розпорядженні програми , як Acrobat (НЕ Reader, але PRO версії), або в якості альтернативи іншої програми редагування PDF , який можна витягти частину PDF і забезпечити тільки ту частину, або просто дати мені traceback.print_exc()з заданий рядок помилок, щоб я міг побачити, що його спричинило; або, можливо, обрати інше з рішень на цьому веб-сайті, оскільки наведене тут (на моє розуміння) орієнтоване на забезпечення витягу даних без втрат у форматі 1: 1 із PDF-файлу, і, можливо, це не те, що ви шукаєте, дякую!
mxl

1

Я додав усі разом у PyPDFTK сюди .

Мій власний внесок - це обробка /Indexedфайлів як таких:

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

Зверніть увагу, що коли /Indexedфайли знайдені, ви не можете просто порівняти /ColorSpaceїх із рядком, оскільки він поставляється як ArrayObject. Отже, ми повинні перевірити масив і отримати індексовану палітру (lookup у коді) та встановити її в об’єкт PIL Image, інакше вона залишається неініціалізованою (нуль), а все зображення відображається чорним.

Моїм першим інстинктом було зберегти їх у форматі GIF (це індексований формат), але мої тести виявили, що PNG були меншими і виглядали однаково.

Я знайшов такі типи зображень під час друку у PDF за допомогою PDF-принтера Foxit Reader.


1

Ви могли б використовувати pdfimages команду в Ubuntu.

Встановіть poppler lib, використовуючи наведені нижче команди.

sudo apt install poppler-utils

sudo apt-get install python-poppler

pdfimages file.pdf image

Список створених файлів: (наприклад,. У PDF є два зображення)

image-000.png
image-001.png

Це працює ! Тепер ви можете використовувати a subprocess.runдля запуску цього з python.


1

Після прочитання повідомлень за допомогою pyPDF2 .

Помилка під час використання коду @ sylvain NotImplementedError: unsupported filter /DCTDecodeповинна походити від методу .getData(): вона вирішується при використанні._data його вирішує @Alex Paramonov.

Наразі я зустрічав лише випадки "DCTDecode", але я ділюсь адаптованим кодом, який включає зауваження з різних публікацій: zilbАвтор: @Alex Paramonov,sub_obj['/Filter'] будучи списком, @mxl.

Сподіваюся, це може допомогти користувачам pyPDF2. Дотримуйтесь коду:

    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

Спробуйте нижче код. він витягне все зображення з PDF.

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

0
  1. Спочатку встановіть pdf2image

    pip встановити pdf2image == 1.14.0

  2. Дотримуйтесь наведеного нижче коду для вилучення сторінок з PDF.

    file_path="file path of PDF"
    info = pdfinfo_from_path(file_path, userpw=None, poppler_path=None)
    maxPages = info["Pages"]
    image_counter = 0
    if maxPages > 10:
        for page in range(1, maxPages, 10):
            pages = convert_from_path(file_path, dpi=300, first_page=page, 
                    last_page=min(page+10-1, maxPages))
            for page in pages:
                page.save(image_path+'/' + str(image_counter) + '.png', 'PNG')
                image_counter += 1
    else:
        pages = convert_from_path(file_path, 300)
        for i, j in enumerate(pages):
            j.save(image_path+'/' + str(i) + '.png', 'PNG')
    

Сподіваюся, це допоможе кодерам, які шукають легке перетворення файлів PDF у зображення відповідно до сторінок PDF.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.