diff --git a/docling_core/types/doc/document.py b/docling_core/types/doc/document.py index ce795f974..4a622001e 100644 --- a/docling_core/types/doc/document.py +++ b/docling_core/types/doc/document.py @@ -3750,6 +3750,8 @@ def export_to_markdown( allowed_meta_names: Optional[set[str]] = None, blocked_meta_names: Optional[set[str]] = None, mark_meta: bool = False, + image_dir: Optional[Path] = None, + image_path_prefix: str = "", ) -> str: r"""Serialize to Markdown. @@ -3812,6 +3814,15 @@ def export_to_markdown( :type allowed_meta_names: Optional[set[str]] = None :param blocked_meta_names: Optional[set[str]]: Meta names to block; takes precedence over allowed_meta_names. :type blocked_meta_names: Optional[set[str]] = None + :param image_dir: When set together with `image_mode=ImageRefMode.REFERENCED`, pictures are + saved as PNG files under this directory and referenced from the Markdown output instead + of requiring the caller to save images and rewrite URIs manually. The directory is + created if it does not already exist. (Default value = None). + :type image_dir: Optional[Path] = None + :param image_path_prefix: Prefix prepended to each saved image's filename when building the + Markdown image reference, e.g. "images/" or a URL prefix. Only used when `image_dir` is + set. (Default value = ""). + :type image_path_prefix: str = "" """ from docling_core.transforms.serializer.markdown import ( MarkdownDocSerializer, @@ -3827,8 +3838,16 @@ def export_to_markdown( DeprecationWarning, ) + export_doc: DoclingDocument = self + if image_dir is not None: + export_doc = self._with_pictures_refs(image_dir=image_dir, page_no=page_no) + for item, _ in export_doc.iterate_items(page_no=page_no, with_groups=False): + if isinstance(item, PictureItem) and item.image is not None and item.image.uri is not None: + filename = Path(str(item.image.uri)).name + item.image.uri = Path(f"{image_path_prefix}{filename}") + serializer = MarkdownDocSerializer( - doc=self, + doc=export_doc, params=MarkdownParams( labels=my_labels, layers=my_layers, diff --git a/test/test_docling_doc.py b/test/test_docling_doc.py index c073f9011..cef4c6801 100644 --- a/test/test_docling_doc.py +++ b/test/test_docling_doc.py @@ -1335,6 +1335,32 @@ def test_save_to_disk(sample_doc): assert True +def test_export_to_markdown_image_dir(sample_doc: DoclingDocument, tmp_path: Path) -> None: + image_dir = tmp_path / "assets" + + md = sample_doc.export_to_markdown( + image_mode=ImageRefMode.REFERENCED, + image_dir=image_dir, + image_path_prefix="assets/", + ) + + saved_images = list(image_dir.glob("*.png")) + assert len(saved_images) == 1, "expected exactly one image to be saved to image_dir" + + image_lines = [line for line in md.splitlines() if "![" in line] + assert len(image_lines) == 1, "expected exactly one image reference in the markdown output" + assert saved_images[0].name in image_lines[0], "markdown should reference the saved image's filename" + assert "assets" in image_lines[0], "markdown reference should include image_path_prefix" + + +def test_export_to_markdown_without_image_dir_is_unaffected(sample_doc: DoclingDocument) -> None: + # image_dir defaults to None, so no images should be written to disk and + # behavior should match calling export_to_markdown without the new params. + baseline = sample_doc.export_to_markdown(image_mode=ImageRefMode.PLACEHOLDER) + unchanged = sample_doc.export_to_markdown(image_mode=ImageRefMode.PLACEHOLDER, image_path_prefix="assets/") + assert baseline == unchanged + + def test_document_stack_operations(sample_doc): # _print(document=doc)