Test cases for pageinfo; complain about inline images

This commit is contained in:
James R. Barlow
2015-07-26 18:18:41 -07:00
parent 3684f278ed
commit 2c1b5e100b
3 changed files with 65 additions and 49 deletions
+57 -25
View File
@@ -2,8 +2,10 @@
#
from subprocess import Popen, PIPE
import PyPDF2 as pypdf
from decimal import Decimal, getcontext
import re
import sys
import PyPDF2 as pypdf
FRIENDLY_COLORSPACE = {
@@ -35,32 +37,32 @@ FRIENDLY_COMP = {
}
def _pdf_get_pageinfo(infile, page: int):
pageinfo = {}
pageinfo['pageno'] = page
pageinfo['images'] = []
def _page_has_inline_images(page):
# PDF always uses \r\n for separator regardless of platform
# Really basic heuristic that might trigger the odd false positive
# This is only finds the first image and is not quite spec compliant
contents = page.getContents()
data = contents.getData()
begin_image, image_data, end_image = False, False, False
for data in re.split(b'\s+', data):
print(data)
if data == b'BI':
begin_image = True
elif data == b'ID':
image_data = True
elif data == b'EI':
end_image = True
if all((begin_image, image_data, end_image)):
return True
p_pdftotext = Popen(['pdftotext', '-f', str(page), '-l', str(page),
'-raw', '-nopgbrk', infile, '-'],
close_fds=True, stdout=PIPE, stderr=PIPE,
universal_newlines=True)
text, _ = p_pdftotext.communicate()
if len(text.strip()) > 0:
pageinfo['has_text'] = True
else:
pageinfo['has_text'] = False
pdf = pypdf.PdfFileReader(infile)
page = pdf.pages[page - 1]
width_pt = page['/MediaBox'][2] - page['/MediaBox'][0]
height_pt = page['/MediaBox'][3] - page['/MediaBox'][1]
pageinfo['width_inches'] = width_pt / Decimal(72.0)
pageinfo['height_inches'] = height_pt / Decimal(72.0)
if '/XObject' not in page['/Resources']:
# Missing /XObject means no images or possibly corrupt PDF
return pageinfo
def _find_page_images(page, pageinfo):
try:
page['/Resources']['/XObject']
except KeyError:
return
# Look for XObject (out of line images)
for xobj in page['/Resources']['/XObject']:
# PyPDF2 returns the keys as an iterator
pdfimage = page['/Resources']['/XObject'][xobj]
@@ -92,7 +94,37 @@ def _pdf_get_pageinfo(infile, page: int):
image['dpi_w'] = image['width'] / pageinfo['width_inches']
image['dpi_h'] = image['height'] / pageinfo['height_inches']
image['dpi'] = (image['dpi_w'] * image['dpi_h']) ** Decimal(0.5)
pageinfo['images'].append(image)
yield image
def _pdf_get_pageinfo(infile, page: int):
pageinfo = {}
pageinfo['pageno'] = page
pageinfo['images'] = []
p_pdftotext = Popen(['pdftotext', '-f', str(page), '-l', str(page),
'-raw', '-nopgbrk', infile, '-'],
close_fds=True, stdout=PIPE, stderr=PIPE,
universal_newlines=True)
text, _ = p_pdftotext.communicate()
if len(text.strip()) > 0:
pageinfo['has_text'] = True
else:
pageinfo['has_text'] = False
pdf = pypdf.PdfFileReader(infile)
page = pdf.pages[page - 1]
width_pt = page['/MediaBox'][2] - page['/MediaBox'][0]
height_pt = page['/MediaBox'][3] - page['/MediaBox'][1]
pageinfo['width_inches'] = width_pt / Decimal(72.0)
pageinfo['height_inches'] = height_pt / Decimal(72.0)
pageinfo['images'] = [im for im in _find_page_images(page, pageinfo)]
# Look for inline images
if _page_has_inline_images(page):
raise NotImplementedError(
"Warning: input PDF contains inline images - not supported")
if pageinfo['images']:
xres = max(image['dpi_w'] for image in pageinfo['images'])
+7 -23
View File
@@ -8,6 +8,7 @@ from contextlib import suppress
import os
import sys
import shutil
from nose.tools import *
TEST_OUTPUT = os.path.join(os.path.dirname(__file__), 'output')
@@ -43,7 +44,7 @@ def test_single_page_text():
def test_single_page_image():
filename = os.path.join(TEST_OUTPUT, 'image-mono.pdf')
pdf = Canvas(filename, pagesize=(8*72, 6*72))
pdf = Canvas(filename, pagesize=(72, 72))
with NamedTemporaryFile() as im_tmp:
im = Image.new('1', (8, 8), 0)
for n in range(8):
@@ -64,7 +65,7 @@ def test_single_page_image():
pdfimage = page['images'][0]
assert pdfimage['width'] == 8
assert pdfimage['color'] == 'gray'
# assert pdfimage['color'] == 'gray'
# While unexpected, this is correct
# PDF spec says /FlateDecode image must have /BitsPerComponent 8
@@ -72,10 +73,11 @@ def test_single_page_image():
assert pdfimage['bpc'] == 8
# DPI in a 1"x1" is the image width
assert pdfimage['dpi_w'] == 8
assert pdfimage['dpi_h'] == 8
eq_(pdfimage['dpi_w'], 8)
eq_(pdfimage['dpi_h'], 8)
@raises(NotImplementedError)
def test_single_page_inline_image():
filename = os.path.join(TEST_OUTPUT, 'image-mono-inline.pdf')
pdf = Canvas(filename, pagesize=(8*72, 6*72))
@@ -89,23 +91,5 @@ def test_single_page_inline_image():
pdf.showPage()
pdf.save()
pdfinfo = pageinfo.pdf_get_all_pageinfo(filename)
pageinfo.pdf_get_all_pageinfo(filename)
assert len(pdfinfo) == 1
page = pdfinfo[0]
assert not page['has_text']
assert len(page['images']) == 1
pdfimage = page['images'][0]
assert pdfimage['width'] == 8
assert pdfimage['color'] == 'gray'
# While unexpected, this is correct
# PDF spec says /FlateDecode image must have /BitsPerComponent 8
# So mono images get upgraded to 8-bit
assert pdfimage['bpc'] == 8
# DPI in a 1"x1" is the image width
assert pdfimage['dpi_w'] == 8
assert pdfimage['dpi_h'] == 8
+1 -1
View File
@@ -33,7 +33,7 @@ setup(
'Pillow>=2.7.0',
'lxml>=3.4.2',
'reportlab>=3.1.44',
'PyPDF2>=1.24'
'PyPDF2>=1.25.1'
],
entry_points={
'console_scripts': [