Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
177349cc84 | ||
|
|
070c9772ce | ||
|
|
1bc09045a5 | ||
|
|
e46a18dd2f | ||
|
|
c64871c2ed |
@@ -28,6 +28,12 @@ tagged yet.
|
||||
|
||||
.. |OCRmyPDF PyPI| image:: https://img.shields.io/pypi/v/ocrmypdf.svg
|
||||
|
||||
v14.2.1
|
||||
=======
|
||||
|
||||
- Fixed :issue:`977`, where images inside Form XObjects were always excluded
|
||||
from image optimization.
|
||||
|
||||
v14.2.0
|
||||
=======
|
||||
|
||||
|
||||
+2
-6
@@ -37,16 +37,12 @@ classifiers = [
|
||||
"Intended Audience :: Science/Research",
|
||||
"Intended Audience :: System Administrators",
|
||||
"License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)",
|
||||
"Operating System :: MacOS :: MacOS X",
|
||||
"Operating System :: Microsoft :: Windows :: Windows 10",
|
||||
"Operating System :: MacOS",
|
||||
"Operating System :: Microsoft :: Windows",
|
||||
"Operating System :: POSIX",
|
||||
"Operating System :: POSIX :: BSD",
|
||||
"Operating System :: POSIX :: Linux",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3 :: Only",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Topic :: Scientific/Engineering :: Image Recognition",
|
||||
"Topic :: Text Processing :: Indexing",
|
||||
"Topic :: Text Processing :: Linguistic",
|
||||
|
||||
+60
-23
@@ -230,6 +230,65 @@ def extract_image_generic(
|
||||
return None
|
||||
|
||||
|
||||
def _find_image_xrefs_container(
|
||||
pdf: Pdf,
|
||||
container: Object,
|
||||
pageno: int,
|
||||
include_xrefs: MutableSet[Xref],
|
||||
exclude_xrefs: MutableSet[Xref],
|
||||
pageno_for_xref: dict[Xref, int],
|
||||
depth: int = 0,
|
||||
):
|
||||
"""Find all image XRefs in a page or Form XObject and add to the include/exclude sets."""
|
||||
if depth > 10:
|
||||
log.warning("Recursion depth exceeded in _find_image_xrefs_page")
|
||||
return
|
||||
try:
|
||||
xobjs = container.Resources.XObject
|
||||
except AttributeError:
|
||||
return
|
||||
for _imname, image in dict(xobjs).items():
|
||||
if image.objgen[1] != 0:
|
||||
continue # Ignore images in an incremental PDF
|
||||
if Name.Subtype in image and image.Subtype == Name.Form:
|
||||
# Recurse into Form XObjects
|
||||
log.debug(f"Recursing into Form XObject {_imname} in page {pageno}")
|
||||
_find_image_xrefs_container(
|
||||
pdf,
|
||||
image,
|
||||
pageno,
|
||||
include_xrefs,
|
||||
exclude_xrefs,
|
||||
pageno_for_xref,
|
||||
depth + 1,
|
||||
)
|
||||
continue
|
||||
xref = Xref(image.objgen[0])
|
||||
if Name.SMask in image:
|
||||
# Ignore soft masks
|
||||
smask_xref = Xref(image.SMask.objgen[0])
|
||||
exclude_xrefs.add(smask_xref)
|
||||
log.debug(f"xref {smask_xref}: skipping image because it is an SMask")
|
||||
include_xrefs.add(xref)
|
||||
log.debug(f"xref {xref}: treating as an optimization candidate")
|
||||
if xref not in pageno_for_xref:
|
||||
pageno_for_xref[xref] = pageno
|
||||
|
||||
|
||||
def _find_image_xrefs(pdf: Pdf):
|
||||
include_xrefs: MutableSet[Xref] = set()
|
||||
exclude_xrefs: MutableSet[Xref] = set()
|
||||
pageno_for_xref: dict[Xref, int] = {}
|
||||
|
||||
for pageno, page in enumerate(pdf.pages):
|
||||
_find_image_xrefs_container(
|
||||
pdf, page, pageno, include_xrefs, exclude_xrefs, pageno_for_xref
|
||||
)
|
||||
|
||||
working_xrefs = include_xrefs - exclude_xrefs
|
||||
return working_xrefs, pageno_for_xref
|
||||
|
||||
|
||||
def extract_images(
|
||||
pike: Pdf,
|
||||
root: Path,
|
||||
@@ -250,30 +309,8 @@ def extract_images(
|
||||
it does a tuple should be returned: (xref, ext) where .ext is the file
|
||||
extension. extract_fn must also extract the file it finds interesting.
|
||||
"""
|
||||
include_xrefs: MutableSet[Xref] = set()
|
||||
exclude_xrefs: MutableSet[Xref] = set()
|
||||
pageno_for_xref = {}
|
||||
errors = 0
|
||||
for pageno, page in enumerate(pike.pages):
|
||||
try:
|
||||
xobjs = page.Resources.XObject
|
||||
except AttributeError:
|
||||
continue
|
||||
for _imname, image in dict(xobjs).items():
|
||||
if image.objgen[1] != 0:
|
||||
continue # Ignore images in an incremental PDF
|
||||
xref = Xref(image.objgen[0])
|
||||
if Name.SMask in image:
|
||||
# Ignore soft masks
|
||||
smask_xref = Xref(image.SMask.objgen[0])
|
||||
exclude_xrefs.add(smask_xref)
|
||||
log.debug(f"xref {smask_xref}: skipping image because it is an SMask")
|
||||
include_xrefs.add(xref)
|
||||
log.debug(f"xref {xref}: treating as an optimization candidate")
|
||||
if xref not in pageno_for_xref:
|
||||
pageno_for_xref[xref] = pageno
|
||||
|
||||
working_xrefs = include_xrefs - exclude_xrefs
|
||||
working_xrefs, pageno_for_xref = _find_image_xrefs(pike)
|
||||
for xref in working_xrefs:
|
||||
image = pike.get_object((xref, 0))
|
||||
try:
|
||||
|
||||
@@ -204,3 +204,11 @@ def test_group3(resources, outdir):
|
||||
assert (
|
||||
opt.extract_image_filter(pdf, outdir, im, im.objgen[0]) is None
|
||||
), "Group 3 should be disallowed"
|
||||
|
||||
|
||||
def test_find_formx(resources, outdir):
|
||||
with pikepdf.open(resources / 'formxobject.pdf') as pdf:
|
||||
working, pagenos = opt._find_image_xrefs(pdf)
|
||||
assert len(working) == 1
|
||||
xref = next(iter(working))
|
||||
assert pagenos[xref] == 0
|
||||
|
||||
Reference in New Issue
Block a user