Извлекать изображения из 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()
Сначала установите pdf2image
pip install pdf2image == 1.14.0
Следуйте приведенному ниже коду для извлечения страниц из 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.