在Python中从PDF提取图像而无需重新采样?


79

如何以原始分辨率和格式从pdf文档中提取所有图像?(意思是将tiff提取为tiff,将jpeg提取为jpeg等,而无需重新采样)。布局并不重要,我不在乎源图像是否位于页面上。

我使用的是python 2.7,但可以根据需要使用3.x。


谢谢。那“如何图像存储为PDF” URL没有工作,但这似乎:jpedal.org/PDFblog/2010/04/...
nealmcb

有一个JPedal Java库,它称为PDF Clipped Image Extraction。作者Mark Stephens简要概述了如何将图像存储在PDF中,这可能有助于构建Python提取器的人。
马特·威尔基

Answers:


44

您可以使用模块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显然首先需要)
Basj

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,有人可以帮忙吗?
金库

4
@vault此评论已过时。您应将“ if pix.n <5”更改为“ if pix.n-pix.alpha <4”,因为原始条件无法正确找到CMYK图像。
奥林加

39

在带有PyPDF2和Pillow库的Python中,它很简单:

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或者... /JPXDecodexObject[obj].getData()第一对夫妇的PDF文件,我测试。详情见gist.github.com/maphew/fe6ba4bf9ed2bc98ecf5
马特·威尔基

4
我最近将'/ DCTDecode'修改推送到PyPDF2库。您可以使用我的存储库:github.com/sylvainpelissier/PyPDF2,它已集成到主分支中。
sylvain 2015年

1
感谢您的更新,但很抱歉,仍然无法进行。要点已更新。我得到ValueError: not enough image datadctdecode嵌入式图像和unsupported filter /JPXDecode另一个pdf。
马特·威尔基

1
取得进展!现在处理dctdecode pdf时没有错误(尽管有时输出图像颠倒了)。但是,现在会抛出JPXDecode文件KeyError:/Filter。我相应地更新了要点。PDF文件只是来自网络的随机文件。要点包含源链接。
马特·威尔基

28
“很简单...
mlissner '16

34

通常以PDF格式将图像按原样存储。例如,插入jpg的PDF在中间的某个位置将具有一定范围的字节,该字节在提取时是有效的jpg文件。您可以使用它非常简单地从PDF中提取字节范围。不久前,我用示例代码撰写了有关此内容的文章:从PDF中提取JPG


1
谢谢内德。看来我需要的特定pdf并不是就地使用jpeg,但是如果它与其他出现的东西匹配,我会保留您的样本。
马特·威尔基

3
您能否解释一下代码中的一些内容?例如,为什么要先搜索“流”,然后再搜索startmark?您可以开始搜索,startmark因为这是JPG的开始吗?又有什么点startfix变量,你不要所有..改变它
user3599803

这非常适合我要从中提取图像的PDF。(以防它对其他人有帮助,我将他的代码另存为.py文件,然后安装/使用Python 2.7.18来运行它,并将路径作为单个命令行参数传递给我的PDF。)
matt

25

在带有用于CCITTFaxDecode过滤器的PyPDF2的Python中:

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'末尾。
饮水机



9

我更喜欢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)

嗨,我的购物车运作良好,但我遇到了一个小问题:有时图像的布局已更改(水平->垂直)。你有什么主意我可以避免这种情况吗?谢谢!
沙里

7

这是我从2019年开始的版本,该版本递归地从PDF获取所有图像并使用PIL读取它们。与Python 2/3兼容。我还发现zlib有时会压缩PDF中的图像,因此我的代码支持解压缩。

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

1
@ GrantD71我不是专家,以前从未听说过ICCBased。另外,如果您不提供输入,则您的错误将无法重现。
Labo

我得到一个KeyError: '/ColorSpace',所以我将您的行替换为DeviceRGB if '/ColorSpace' not in xObject[obj] or xObject[obj]['/ColorSpace'] == '/DeviceRGB':。无论如何,最后这对我不起作用,因为图像可能是PNG(不确定)。
Basj

@Basj我的代码也应该与PNG一起使用。的值是xObject[obj]['/Filter']多少?
Labo

2
我将您的代码修改为可在Python 2和3上使用。我还实现了RonanPaixão的/ Indexed更改。我还将过滤器if / elif更改为“ in”而不是等于。我有一个/ Filter类型为['/ ASCII85Decode','/ FlateDecode']的PDF。我还更改了返回图像斑点而不是写入文件的功能。更新的代码可以在这里找到:gist.github.com/gstorer/f6a9f1dfe41e8e64dcf58d07afa9ab2a
Gerald,

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来做到这一点。您可以在这篇文章中查看image magick在幕后使用的ghostscript命令。
Filipe Correia,2012年

我不得不说有时候渲染真的很糟糕。使用poppler可以正常工作。
拉菲2015年

4

经过一番搜索,我发现以下脚本非常适合我的PDF。它只能处理JPG,但可以与我不受保护的文件完美配合。也是不需要任何外部库的。

不客气,该脚本源自Ned Batchelder,而不是我。Python3代码:从pdf中提取jpg。快速又脏

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


4

更简单的解决方案:

使用poppler-utils软件包。要安装它,请使用homebrew(homebrew是MacOS专用的,但是您可以在此处找到适用于Widows或Linux的poppler-utils软件包:https : //poppler.freedesktop.org/)。下面的第一行代码使用自制软件安装poppler-utils。安装后,第二行(从命令行运行)然后从PDF文件中提取图像并将其命名为“ image *”。要在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)

1
谢谢科尔顿。自制软件仅适用于MacOS。在特定于平台的说明中注明操作系统是一个好习惯。
马特·威尔基(Matt wilkie)

@mattwilkie-感谢您的注意。在我的回答中会注意到这一点。
科尔顿·希克斯

3

我对自己的程序进行了此操作,发现最好使用的库是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()

绝对要检查一下文档。


最好的选择IMO:安装完成后fitz在Win 10,我得到了错误:ModuleNotFoundError:无模块命名为“前端”,这很容易通过安装解决pip install PyMuPDF这里讨论:stackoverflow.com/questions/56467667/...
彼得

3

好吧,我已经为此苦苦挣扎了好几个星期,其中许多答案都帮助了我,但是始终缺少某些东西,显然这里没有人遇到过jbig2编码图像的问题。

在我要扫描的一堆PDF中,以jbig2编码的图像非常流行。

据我了解,有很多复印/扫描机可以扫描纸张并将其转换为包含jbig2编码图像的PDF文件。

因此,经过几天的测试,很久以前就决定寻求dkagedal在此处提出的答案。

这是我在linux上的分步指南:(如果您有其他操作系统,我建议使用linux docker,它将变得更加容易。)

第一步:

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。不过我建议张贴作为自己的新问题,然后自我的答案,因为它没有地址蟒蛇这样做,这是本Q.点(随意交叉链接的帖子,因为这有关。)
马特·威尔基

嗨@mattwilkie,感谢您的意见,这里是问题:stackoverflow.com/questions/60851124/...
马可波罗

2

截至2019年2月,@ 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过滤器仍未实现。
Abhimanyu

您好@调制解调器Rakesh专家,您能否提供触发此错误的PDF文件?谢谢!
mxl

不幸的是,我无法分享该pdf。
调制解调器Rakesh钉

或者,你最终会在拥有类似的Acrobat(不是阅读器,但专业版),或者其他PDF编辑程序一个程序,它可以提取PDF的一部分,并只提供部分或者,只是给我traceback.print_exc()的给定的错误行,以便我可以看到是什么触发了它;或选择本网站上的其他解决方案,因为据我所知,此处提供的解决方案着重于从PDF中以1:1的无损提取数据,可能不是您想要的,谢谢!
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较小并且外观相同。

使用Foxit Reader PDF Printer打印到PDF时,我发现了这些类型的图像。


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

有用 !现在,您可以使用subprocess.run来从python运行它。


1

在使用pyPDF2阅读帖子之后

使用@sylvain的代码时的错误NotImplementedError: unsupported filter /DCTDecode必须来自方法.getData():使用._data@Alex Paramonov可以解决此问题。

到目前为止,我只遇到过“ DCTDecode”案例,但是我正在共享经过改编的代码,其中包括来自不同帖子的评论:来自@Alex zilbParamonov,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")
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.