@@ -280,6 +280,13 @@ def convert(
280280 text_content = page .extract_text () or ""
281281 if text_content .strip ():
282282 markdown_content .append (text_content .strip ())
283+ else :
284+ # Scanned page with no image objects or text layer:
285+ # render the whole page and OCR it, so it doesn't
286+ # silently vanish from the output.
287+ page_ocr = self ._ocr_page (page , ocr_service )
288+ if page_ocr :
289+ markdown_content .append (page_ocr )
283290 else :
284291 # No OCR, just extract text
285292 text_content = page .extract_text () or ""
@@ -337,6 +344,27 @@ def _extract_page_images(self, pdf_bytes: io.BytesIO, page_num: int) -> list[dic
337344
338345 return images
339346
347+ def _ocr_page (self , page : Any , ocr_service : LLMVisionOCRService ) -> str :
348+ """
349+ Render a single pdfplumber page to PNG and run OCR on it.
350+
351+ Returns a formatted OCR block, a 'no text' marker if OCR is empty,
352+ or an error marker if rendering/OCR raises.
353+ """
354+ try :
355+ page_img = page .to_image (resolution = 300 )
356+ img_stream = io .BytesIO ()
357+ page_img .original .save (img_stream , format = "PNG" )
358+ img_stream .seek (0 )
359+
360+ ocr_result = ocr_service .extract_text (img_stream )
361+ text = (ocr_result .text or "" ).strip ()
362+ if text :
363+ return f"*[Image OCR]\n { text } \n [End OCR]*"
364+ return "*[No text could be extracted from this page]*"
365+ except Exception as e :
366+ return f"*[Error processing page { page .page_number } : { str (e )} ]*"
367+
340368 def _ocr_full_pages (
341369 self , pdf_bytes : io .BytesIO , ocr_service : LLMVisionOCRService
342370 ) -> str :
0 commit comments