74 lines
2.2 KiB
Python
74 lines
2.2 KiB
Python
"""
|
|
PDF-family extractor.
|
|
|
|
Text per page via pypdf, plus the document info dict (title/author/dates). When
|
|
options['render'] is set and pdf2image (+ system poppler) is available, page 1 is
|
|
rendered to thumb.jpg.
|
|
"""
|
|
import io
|
|
from pathlib import Path
|
|
|
|
from .base import ExtractionResult
|
|
|
|
EXTRACTOR_ID = "pdf/pypdf@1"
|
|
|
|
|
|
def _info_metadata(reader) -> dict:
|
|
out = {}
|
|
info = getattr(reader, "metadata", None)
|
|
if not info:
|
|
return out
|
|
for src, dst in (("title", "title"), ("author", "author"),
|
|
("creation_date", "created"), ("modification_date", "modified_doc")):
|
|
try:
|
|
val = getattr(info, src, None)
|
|
except Exception:
|
|
val = None
|
|
if val:
|
|
out[dst] = str(val)
|
|
return out
|
|
|
|
|
|
def _render_first_page(source: Path) -> bytes:
|
|
from pdf2image import convert_from_path # needs system poppler
|
|
images = convert_from_path(str(source), first_page=1, last_page=1, dpi=100)
|
|
if not images:
|
|
return b""
|
|
im = images[0]
|
|
im.thumbnail((640, 640))
|
|
buf = io.BytesIO()
|
|
im.convert("RGB").save(buf, format="JPEG", quality=80)
|
|
return buf.getvalue()
|
|
|
|
|
|
def extract(source: Path, options: dict) -> ExtractionResult:
|
|
from pypdf import PdfReader # lazy
|
|
|
|
warnings = []
|
|
reader = PdfReader(str(source))
|
|
pages = reader.pages
|
|
blocks = []
|
|
for i, page in enumerate(pages, 1):
|
|
try:
|
|
text = page.extract_text() or ""
|
|
except Exception as e:
|
|
text = ""
|
|
warnings.append(f"page {i} text extraction failed: {e}")
|
|
blocks.append(f"## Page {i}\n\n{text.strip()}")
|
|
content = "\n\n".join(blocks) + "\n"
|
|
|
|
metadata = _info_metadata(reader)
|
|
metadata["pages"] = len(pages)
|
|
|
|
thumb = None
|
|
if options.get("render"):
|
|
try:
|
|
thumb = _render_first_page(source) or None
|
|
except ImportError:
|
|
warnings.append("--render requested but pdf2image/poppler not available")
|
|
except Exception as e:
|
|
warnings.append(f"page render failed: {e}")
|
|
|
|
return ExtractionResult(content=content, metadata=metadata, thumb=thumb,
|
|
warnings=warnings, extractor=EXTRACTOR_ID)
|