Skip to content

Commit 2931cb3

Browse files
awalker4cragwolfe
andauthored
fix: handle KeyError: 'N' for certain pdfs (#2072)
Closes #2059. We've found some pdfs that throw an error in pdfminer. These files use a ICCBased color profile but do not include an expected value `N`. As a workaround, we can wrap pdfminer and drop any colorspace info, since we don't need to render the document. To verify, try to partition the document in the linked issue. ``` elements = partition(filename="google-2023-environmental-report_condensed.pdf", strategy="fast") ``` --------- Co-authored-by: cragwolfe <crag@unstructured.io>
1 parent f8528a0 commit 2931cb3

6 files changed

Lines changed: 25 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## 0.10.31-dev3
1+
## 0.10.31-dev4
22

33
### Enhancements
44
* **Temporary Support for paddle language parameter** User can specify default langage code for paddle with ENV `DEFAULT_PADDLE_LANG` before we have the language mapping for paddle.
@@ -11,6 +11,7 @@
1111
* **Remove default user ./ssh folder** The default notebook user during image build would create the known_hosts file with incorrect ownership, this is legacy and no longer needed so it was removed.
1212
* **Include `languages` in metadata when partitioning strategy='hi_res' or 'fast'** User defined `languages` was previously used for text detection, but not included in the resulting element metadata for some strategies. `languages` will now be included in the metadata regardless of partition strategy for pdfs and images.
1313
* **Handle a case where Paddle returns a list item in ocr_data as None** In partition, while parsing PaddleOCR data, it was assumed that PaddleOCR does not return None for any list item in ocr_data. Removed the assumption by skipping the text region whenever this happens.
14+
* **Fix some pdfs returning `KeyError: 'N'`** Certain pdfs were throwing this error when being opened by pdfminer. Added a wrapper function for pdfminer that allows these documents to be partitioned.
1415

1516
## 0.10.30
1617

185 KB
Binary file not shown.

requirements/base.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ numpy
1515
rapidfuzz
1616
backoff
1717
typing-extensions
18+
wrapt

test_unstructured/partition/pdf_image/test_pdf.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -973,3 +973,10 @@ def test_partition_pdf_with_all_number_table_and_ocr_only_strategy():
973973
# numerical values with `strategy="ocr_only"`
974974
filename = example_doc_path("all-number-table.pdf")
975975
assert pdf.partition_pdf(filename, strategy="ocr_only")
976+
977+
978+
# As of pdfminer 221105, this pdf throws an error and requires a workaround
979+
# See #2059
980+
def test_partition_pdf_with_bad_color_profile():
981+
filename = example_doc_path("pdf-bad-color-space.pdf")
982+
assert pdf.partition_pdf(filename, strategy="fast")

unstructured/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.10.31-dev3" # pragma: no cover
1+
__version__ = "0.10.31-dev4" # pragma: no cover

unstructured/partition/pdf.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import numpy as np
2222
import pdf2image
23+
import wrapt
2324
from pdfminer.converter import PDFPageAggregator
2425
from pdfminer.layout import (
2526
LAParams,
@@ -521,6 +522,19 @@ def _extract_text(item: LTItem) -> str:
521522
return "\n"
522523

523524

525+
# Some pages with a ICC color space do not follow the pdf spec
526+
# They throw an error when we call interpreter.process_page
527+
# Since we don't need color info, we can just drop it in the pdfminer code
528+
# See #2059
529+
@wrapt.patch_function_wrapper("pdfminer.pdfinterp", "PDFPageInterpreter.init_resources")
530+
def pdfminer_interpreter_init_resources(wrapped, instance, args, kwargs):
531+
resources = args[0]
532+
if "ColorSpace" in resources:
533+
del resources["ColorSpace"]
534+
535+
return wrapped(resources)
536+
537+
524538
def _process_pdfminer_pages(
525539
fp: BinaryIO,
526540
filename: str,

0 commit comments

Comments
 (0)