Извлекать изображения из PDF без передискретизации в python?

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

Я использую Python 2.7, но могу использовать 3.x, если требуется.

24 ответа

Вы можете использовать модуль 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

смотрите здесь для получения дополнительной информации

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

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

В 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://stackru.com/questions/2693820/extract-images-from-pdf-without-resampling-in-python
Extract images coded with CCITTFaxDecode in .net: http://stackru.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()

Libpoppler поставляется с инструментом под названием "pdfimages", который делает именно это.

(В системах с Ubuntu он находится в пакете poppler-utils)

http://poppler.freedesktop.org/

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

Двоичные файлы Windows: http://blog.alivate.com.au/poppler-windows/

Я предпочитаю 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)

PikePDF can do this with very little code:

      from pikepdf import Pdf, PdfImage

filename = "sample-in.pdf"
example = Pdf.open(filename)

for i, page in enumerate(example.pages):
    for j, (name, raw_image) in enumerate(page.images.items()):
        image = PdfImage(raw_image)
        out = image.extract_to(fileprefix=f"{filename}-page{i:03}-img{j:03}")

extract_to will automatically pick the file extension based on how the imageis encoded in the PDF.

If you want, you could also print some detail about the images as they get extracted:

              # Optional: print info about image
        w = raw_image.stream_dict.Width
        h = raw_image.stream_dict.Height
        filter = raw_image.stream_dict.Filter
        size = raw_image.stream_dict.Length

        print(f"Wrote {name} {w}x{h} {filter} {size:,}B {image.colorspace} to {out}")

which can print something like

      Wrote /Im1 150x150 /DCTDecode 5,952B /ICCBased to sample2.pdf-page000-img000.jpg
Wrote /Im10 32x32 /FlateDecode 36B /ICCBased to sample2.pdf-page000-img001.png
...

See the docs for more that you can do with images, including replacing them in the PDF file.

Вот моя версия от 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

Ну, я боролся с этим в течение многих недель, многие из этих ответов помогли мне пройти, но всегда чего-то не хватало, по-видимому, ни у кого здесь никогда не было проблем с изображениями, закодированными 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

Вы, наконец, сможете преобразовать все извлеченные изображения во что-нибудь полезное.

удачи!

Я начал с кода @sylvain Были некоторые недостатки, как исключение NotImplementedError: unsupported filter /DCTDecode getData или тот факт, что код не смог найти изображения на некоторых страницах, потому что они были на более глубоком уровне, чем страница.

Вот мой код:

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)

Я сделал это для своей собственной программы и обнаружил, что лучшая библиотека для использования - PyMuPDF. Он позволяет вам узнать номера внешних ссылок каждого изображения на каждой странице и использовать их для извлечения необработанных данных изображения из 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()

Тем не менее, обязательно ознакомьтесь с документацией.

Намного более простое решение:

Используйте пакет poppler-utils. Для его установки используйте homebrew (homebrew зависит от MacOS, но вы можете найти пакет poppler-utils для Widows или Linux здесь: https://poppler.freedesktop.org/). Первая строка кода ниже устанавливает утилиты poppler с помощью homebrew. После установки вторая строка (запускается из командной строки) затем извлекает изображения из файла PDF и называет их "изображение *". Для запуска этой программы из Python используйте модуль os или subprocess. Третья строка - это код с использованием модуля 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)

Я установил 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-файл только с изображениями и без текста.

После прочтения сообщений с помощью pyPDF2.

Ошибка при использовании кода @sylvain NotImplementedError: unsupported filter /DCTDecode должно исходить из метода .getData(): Решается при использовании ._data вместо этого @Alex Paramonov.

Пока я встречал только случаи "DCTDecode", но я делюсь адаптированным кодом, который включает примечания из разных сообщений: From 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))

После некоторых поисков я нашел следующий скрипт, который очень хорошо работает с моими 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

Я добавил все это вместе в 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 с помощью Foxit Reader PDF Printer.

По состоянию на февраль 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()

Я переписываю решения как один класс Python. С ним должно быть легко работать. Если вы заметили новый "/Filter" или "/ColorSpace", просто добавьте его во внутренние словари.

https://github.com/survtur/extract_images_from_pdf

Требования:

  • Python3.6+
  • PyPDF2
  • ПИЛ

Вы могли бы использовать 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

Оно работает! Теперь вы можете использовать subprocess.run запустить это из питона.

Попробуйте код ниже. он извлечет все изображения из 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")

С pypdfium2 (v4):

      import pypdfium2.__main__ as pdfium_cli

pdfium_cli.api_main(["extract-images", "input.pdf", "-o", "output_dir"])

Есть несколько вариантов выбора между различными стратегиями извлечения (см.pypdfium2 extract-images --help).

Также доступны актуальные API-интерфейсы Python без CLI. Реализация CLI демонстрирует их (подробности см. в документации):

      # assuming `args` is a given options set (e. g. argparse namepsace)

import pypdfium2 as pdfium
import pypdfium2.raw as pdfium_c

pdf = pdfium.PdfDocument(args.input)

images = []
for i in args.pages:
    page = pdf.get_page(i)
    obj_searcher = page.get_objects(
        filter = (pdfium_c.FPDF_PAGEOBJ_IMAGE, ),
        max_depth = args.max_depth,
    )
    images += list(obj_searcher)

n_digits = len(str(len(images)))

for i, image in enumerate(images):
    prefix = args.output_dir / ("%s_%0*d" % (args.input.stem, n_digits, i+1))
    
    try:
        if args.use_bitmap:
            pil_image = image.get_bitmap(render=args.render).to_pil()
            pil_image.save("%s.%s" % (prefix, args.format))
        else:
            image.extract(prefix, fb_format=args.format, fb_render=args.render)
    except pdfium.PdfiumError:
        traceback.print_exc()

Примечание. К сожалению, общедоступные API-интерфейсы PDFium для извлечения изображений весьма ограничены , поэтомуPdfImage.extract()далеко не так умен, как pikepdf. Если вам нужно только растровое изображение и вы не собираетесь его сохранять,PdfImage.get_bitmap()хотя должно быть вполне нормально.

(Отказ от ответственности: я автор pypdfium2)

Следующий код является обновленной версией PyMUPDF:

      doc = fitz.open("/Users/vignesh/Downloads/ViewJournal2244.pdf")
Images_per_page={}
for i in page:
    images=[]
    for image_box in doc[page].get_images():
        rect=doc[page].get_image_rects(image_box)
        page=doc[page].get_pixmap(matrix=fitz.Identity,clip=rect[0],dpi=None,colorspace=fitz.csRGB,alpha=True, annots=True) 
        string=page.tobytes()
        images.append(string)
    Images_per_page[i]=images

Это сработало для меня:

       import PyPDF2
from PyPDF2 import PdfFileReader

# Open the PDF file
pdf_file = open(r"C:\\Users\\file.pdf", 'rb')
pdf_reader = PdfFileReader(pdf_file)

# Iterate through each page
for page_num in range(pdf_reader.numPages):
    page = pdf_reader.getPage(page_num)
    xObject = page['/Resources']['/XObject'].getObject()

    # Iterate through each image on the page
    for obj in xObject:
        if xObject[obj]['/Subtype'] == '/Image':
            size = (xObject[obj]['/Width'], xObject[obj]['/Height'])
            data = xObject[obj].getData()
            # You can now save the image data to a file
            with open(f'C:\\Users\\filepath\{obj}.jpg', 'wb') as img_file:
                img_file.write(data)

# Close the PDF file
pdf_file.close()
  1. Сначала установите pdf2image

    pip install 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.

Другие вопросы по тегам