diff --git a/docling_parse/pdf_parser.py b/docling_parse/pdf_parser.py index e42d71737..1e31cb898 100644 --- a/docling_parse/pdf_parser.py +++ b/docling_parse/pdf_parser.py @@ -1139,6 +1139,11 @@ def __init__( self._pages: Dict[tuple[int, int, int, int, int, bool], SegmentedPdfPage] = {} self._page_decoder: PdfPageDecoder | None = None self._default_image: PILImage.Image | None = None + # Last image rendered at a non-default scale for a cropped request: OCR + # crops several regions of a page at the same scale, and each crop would + # re-render the page. Full-page requests are not kept: callers such as + # Docling cache those already, and one per live page adds up quickly. + self._scaled_image: tuple[float, PILImage.Image] | None = None self.doc_key: str = raw_result.doc_key self.page_number: int = raw_result.page_number + 1 @@ -1369,7 +1374,9 @@ def _get_default_image(self) -> PILImage.Image: ) return self._default_image - def _render_image_at_scale(self, scale: float) -> PILImage.Image: + def _render_image_at_scale(self, scale: float, cache: bool) -> PILImage.Image: + if self._scaled_image is not None and self._scaled_image[0] == scale: + return self._scaled_image[1] page_decoder = self._require_page_decoder() render_config = self._rendering_config() render_config.scale = scale @@ -1380,7 +1387,10 @@ def _render_image_at_scale(self, scale: float) -> PILImage.Image: raise RuntimeError( f"Rendered image is empty for page {self.page_number} of {self.doc_key}" ) - return self._image_from_bytes(raw_bytes, image_shape) + image = self._image_from_bytes(raw_bytes, image_shape) + if cache: + self._scaled_image = (scale, image) + return image def _render_image_at_canvas_size( self, canvas_size: tuple[int, int] @@ -1440,7 +1450,7 @@ def get_image( ): image = self._get_default_image() else: - image = self._render_image_at_scale(scale) + image = self._render_image_at_scale(scale, cache=cropbox is not None) else: assert canvas_size is not None if canvas_size[0] <= 0 or canvas_size[1] <= 0: