pdfinfo: learn to detect vector graphic objects

This commit is contained in:
James R. Barlow
2018-10-18 01:21:51 -07:00
parent 7a5504dfa5
commit b18e66e2ca
2 changed files with 34 additions and 10 deletions
+28 -10
View File
@@ -104,7 +104,7 @@ InlineSettings = namedtuple('InlineSettings',
['iimage', 'shorthand', 'stack_depth'])
ContentsInfo = namedtuple('ContentsInfo',
['xobject_settings', 'inline_images', 'found_text'])
['xobject_settings', 'inline_images', 'found_text', 'found_vector'])
def _normalize_stack(graphobjs):
@@ -119,7 +119,7 @@ def _normalize_stack(graphobjs):
def _interpret_contents(contentstream, initial_shorthand=UNIT_SQUARE):
"""Interpret the PDF content stream
"""Interpret the PDF content stream.
The stack represents the state of the PDF graphics stack. We are only
interested in the current transformation matrix (CTM) so we only track
@@ -136,16 +136,16 @@ def _interpret_contents(contentstream, initial_shorthand=UNIT_SQUARE):
page.
PDF units suit our needs so we initialize ctm to the identity matrix.
"""
stack = []
ctm = PdfMatrix(initial_shorthand)
xobject_settings = []
inline_images = []
found_text = False
text_operators = set(['Tj', 'TJ', '"', "'"])
operator_whitelist = """q Q Do cm TJ Tj " ' BI ID EI"""
found_text, found_vector = False, False
text_operators = set("""Tj " ' TJ""".split())
vector_operators = set('S s f F f* B B* b b*'.split())
operator_whitelist = """q Q Do cm TJ Tj " ' BI ID EI S s f F f* B B* b b*"""
for n, graphobj in enumerate(_normalize_stack(
pikepdf.parse_content_stream(contentstream, operator_whitelist))):
@@ -178,12 +178,14 @@ def _interpret_contents(contentstream, initial_shorthand=UNIT_SQUARE):
inline_images.append(inline)
elif operator in text_operators:
found_text = True
elif operator in vector_operators:
found_vector = True
return ContentsInfo(
xobject_settings=xobject_settings,
inline_images=inline_images,
found_text=found_text)
found_text=found_text,
found_vector=found_vector)
def _get_dpi(ctm_shorthand, image_size):
@@ -250,6 +252,11 @@ def _get_dpi(ctm_shorthand, image_size):
return dpi_w, dpi_h
class VectorInfo:
def __init__(self):
pass
class ImageInfo:
DPI_PREC = Decimal('1.000')
@@ -482,6 +489,8 @@ def _find_images(*, pdf, container, shorthand=None):
contentsinfo = _interpret_contents(container, initial_shorthand)
if contentsinfo.found_vector:
yield VectorInfo()
yield from _find_inline_images(contentsinfo)
yield from _find_regular_images(container, contentsinfo)
yield from _find_form_xobject_images(pdf, container, contentsinfo)
@@ -585,6 +594,12 @@ def _pdf_get_pageinfo(pdf, pageno: int, infile, xmltext):
pageinfo['images'] = [im for im in
_find_images(pdf=pdf, container=page,
shorthand=userunit_shorthand)]
if any(isinstance(im, VectorInfo) for im in pageinfo['images']):
pageinfo['has_vector'] = True
pageinfo['images'] = [im for im in pageinfo['images']
if not isinstance(im, VectorInfo)]
if pageinfo['images']:
xres = Decimal(max(image.xres for image in pageinfo['images']))
yres = Decimal(max(image.yres for image in pageinfo['images']))
@@ -647,6 +662,10 @@ class PageInfo:
def has_text(self):
return self._pageinfo['has_text']
@property
def has_vector(self):
return self._pageinfo['has_vector']
@property
def width_inches(self):
return self._pageinfo['width_inches']
@@ -711,9 +730,8 @@ class PageInfo:
class PdfInfo:
"""Get summary information about a PDF
"""Get summary information about a PDF"""
"""
def __init__(self, infile, log=None):
self._infile = infile
self._pages, pdf = _pdf_get_all_pageinfo(infile, log=log)
+6
View File
@@ -169,3 +169,9 @@ def test_regex():
assert rx.match(s)
for s in must_not_match:
assert not rx.match(s)
def test_vector(resources):
filename = resources / 'vector.pdf'
pdf = pdfinfo.PdfInfo(filename)
assert pdf[0].has_vector