Skip to content

fix: extract valid encoded images from PDFs - #10795

Open
AIdafashi wants to merge 1 commit into
AstrBotDevs:masterfrom
AIdafashi:fix/pdf-image-encoding
Open

AIdafashi wants to merge 1 commit into
AstrBotDevs:masterfrom
AIdafashi:fix/pdf-image-encoding

Conversation

@AIdafashi

@AIdafashi AIdafashi commented Oct 26, 2026 •

Copy link
Copy Markdown

PDFParser currently saves XObject.get_data() as image bytes and guesses the file type from a single /Filter value. For Flate-compressed images those bytes are raw pixels, so the resulting ".png" cannot be opened. A JPEG with an ASCII85 + DCT filter chain is saved as ".png" with image/png metadata.

Modifications

  • Use pypdf's public page.images API to obtain encoded image bytes, including soft masks and images inside Form XObjects.
  • Derive the extension and MIME type from the extracted image while retaining generated page/counter filenames.
  • Retrieve each image separately so a malformed image does not discard valid images on the same page; keep page-level error isolation and text extraction.
  • Add tests using real PDFs generated in memory: PNG, JPEG, transparency, nested forms, multiple pages, a malformed image followed by a valid image, and text-only PDFs.

No new dependencies or API/schema changes. Previously stored media are not rewritten; affected documents need to be parsed again.

  • This is NOT a breaking change.

Screenshots or Test Results

Verified locally on Windows with Python 3.12:

  • Before the fix: tests/test_pdf_parser.py — 5 failed, 2 passed. PNG decoding fails with UnidentifiedImageError, JPEG metadata is incorrect, and nested images are omitted.
  • After the fix: uv run pytest tests/test_pdf_parser.py -q — 7 passed with pypdf 6.21.2.
  • Minimum supported pypdf: uv run --with pypdf==6.1.1 python -m pytest tests/test_pdf_parser.py -q — 7 passed.
  • Related regression selection — 48 passed:
    tests/test_pdf_parser.py tests/test_epub_parser.py tests/unit/test_kb_upload_atomicity.py tests/unit/test_kb_document_cleanup.py tests/unit/test_knowledge_base_service_contract.py.
    Run with the same pytest.main(...) / flushed os._exit(...) wrapper used by scripts/run_pytests_ci.sh because existing database test worker threads can keep the process alive after completion.
  • uv run ruff format . — 524 files unchanged.
  • uv run ruff check . — passed.
  • Explicit Ruff lint/format checks on the new test file — passed (the repository-wide Ruff configuration excludes tests).
  • uvx --from pyupgrade==3.21.0 pyupgrade --py310-plus astrbot/core/knowledge_base/parsers/pdf_parser.py tests/test_pdf_parser.py and git diff --check — passed.

The full repository suite was not run locally.

Checklist

  • New features discussed with maintainers: not applicable; this fixes existing PDF image extraction.
  • Changes tested, with verification steps and results above.
  • Documentation impact checked: no WebUI navigation, page structure, or labels change, so no UI documentation update is needed.
  • No new dependencies.
  • No malicious code.

Summary by Sourcery

Fix PDF image extraction so stored media remains decodable and correctly identified across supported image layouts.

Bug Fixes:

  • Extract valid encoded PDF images with accurate file extensions and MIME types, including transparency and images nested in Form XObjects.
  • Isolate malformed images so valid images, page processing, and text extraction continue unaffected.

Tests:

  • Add regression coverage for PNG and JPEG extraction, transparency, nested forms, multi-page naming, malformed images, and text-only PDFs.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="astrbot/core/knowledge_base/parsers/pdf_parser.py" line_range="73" />
<code_context>
                         )
                     except Exception:
-                        # 单个图片提取失败不影响整体
+                        # A broken image must not hide other images on the page.
                         continue
             except Exception:
</code_context>
<issue_to_address>
**Image failures go unnoticed**

When pypdf or Pillow raises while retrieving or encoding an image, the per-image `except Exception` discards the failed image and returns the remaining media without recording the exception, so the upload succeeds with missing media and operators have no indication extraction failed.

Log the image/page context and exception before continuing so extraction remains isolated but failures are observable.
</issue_to_address>

Sourcery assessment

Approval pending. 1 finding to address first.

Blocking findings: astrbot/core/knowledge_base/parsers/pdf_parser.py:73


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

)
except Exception:
# 单个图片提取失败不影响整体
# A broken image must not hide other images on the page.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium · Image failures go unnoticed

When pypdf or Pillow raises while retrieving or encoding an image, the per-image except Exception discards the failed image and returns the remaining media without recording the exception, so the upload succeeds with missing media and operators have no indication extraction failed.

Log the image/page context and exception before continuing so extraction remains isolated but failures are observable.

Prompt for AI agents
In `astrbot/core/knowledge_base/parsers/pdf_parser.py` at line 73:

**Image failures go unnoticed**

When pypdf or Pillow raises while retrieving or encoding an image, the per-image `except Exception` discards the failed image and returns the remaining media without recording the exception, so the upload succeeds with missing media and operators have no indication extraction failed.

Log the image/page context and exception before continuing so extraction remains isolated but failures are observable.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants