Repository: DS4SD/docling-core

Issue:
export_to_html fails if there is a formula with empty text and no image of the formula
### Bug
When an element of `texts` of a `DoclingDocument` has `"text": ""` for `"label": "formula"`, the html export fails with error
```
Traceback (most recent call last):
  File "workspace/docling-eval/tests/html_export.py", line 87, in <module>
    doclingdoc.export_to_html(
  File "workspace/docling-eval/.venv/lib/python3.11/site-packages/docling_core/types/doc/document.py", line 2815, in export_to_html
    html_text = (delim.join(lines)).strip()
                 ^^^^^^^^^^^^^^^^^
TypeError: sequence item 4: expected str instance, NoneType found
```

The root cause appears to be at https://github.com/DS4SD/docling-core/blob/main/docling_core/types/doc/document.py#L2613 where it returns `None` if `get_image()` fails. If this is a genuine exception, it should throw. Otherwise it should be handled by https://github.com/DS4SD/docling-core/blob/main/docling_core/types/doc/document.py#L2660.

### Steps to reproduce
This is a reduced example to demonstrate the problem from an actual conversion result.
```
from docling_core.types.doc.document import DoclingDocument
from docling_core.types.doc.base import ImageRefMode

doc = {
    "body": {
        "children": [
            {"$ref": "#/texts/0"},
            {"$ref": "#/texts/1"},
        ],
        "content_layer": "body",
        "label": "unspecified",
        "name": "_root_",
        "self_ref": "#/body",
    },
    "form_items": [],
    "furniture": {
        "children": [],
        "content_layer": "furniture",
        "label": "unspecified",
        "name": "_root_",
        "self_ref": "#/furniture",
    },
    "groups": [],
    "key_value_items": [],
    "name": "myfile",
    "origin": {
        "binary_hash": myhash,
        "filename": "myfile",
        "mimetype": "application/pdf",
    },
    "pages": {"1": {"page_no": 1, "size": {"height": 1754.0, "width": 1241.0}}},
    "pictures": [],
    "schema_name": "DoclingDocument",
    "tables": [],
    "texts": [
        {
            "children": [],
            "content_layer": "body",
            "label": "text",
            "orig": "et la composante al continu",
            "parent": {"$ref": "#/body"},
            "prov": [
                {
                    "bbox": {
                        "b": 480.0,
                        "coord_origin": "BOTTOMLEFT",
                        "l": 181.0,
                        "r": 466.6666564941406,
                        "t": 508.0,
                    },
                    "charspan": [0, 27],
                    "page_no": 1,
                }
            ],
            "self_ref": "#/texts/0",
            "text": "et la composante al continu",
        },
        {
            "children": [],
            "content_layer": "body",
            "label": "formula",
            "orig": "Inox (II.27) TT",
            "parent": {"$ref": "#/body"},
            "prov": [
                {
                    "bbox": {
                        "b": 403.3333435058594,
                        "coord_origin": "BOTTOMLEFT",
                        "l": 627.0,
                        "r": 1098.6666259765625,
                        "t": 451.3333435058594,
                    },
                    "charspan": [0, 15],
                    "page_no": 1,
                }
            ],
            "self_ref": "#/texts/1",
            "text": "",
        },
    ],
    "version": "1.1.0",
}

doclingdoc = DoclingDocument.model_validate(doc)
doclingdoc.export_to_html(
    image_mode=ImageRefMode.EMBEDDED,
)
```

### Docling-core version
2.19.1 (SHA: 23fa0b50a7dca1da085d94de6fa09bb1a8687cb8)

### Python version
3.11.11

<!-- ⚠️ ATTENTION: When sharing screenshots, attachments, or other data make sure not to include any sensitive information. -->

Hints from issue comments:
@kmyusk: The bug was observed in this context: https://github.com/DS4SD/docling-eval/blob/kim/dlnv2/docling_eval/benchmarks/doclaynet_v2/create.py#L429-L442
If I try `img = conv_results.pages[0].image` I get error `AttributeError("'NoneType' object has no attribute 'get_width'")` so the image is missing in the page item post-conversion leading to the symptom seen in this bug report. It is possibly an upstream bug causing this but still needs to be properly handled here.

Solution patch:
diff --git a/docling_core/types/doc/document.py b/docling_core/types/doc/document.py
index afa82fb7..8bec0ef1 100644
--- a/docling_core/types/doc/document.py
+++ b/docling_core/types/doc/document.py
@@ -2764,14 +2764,17 @@ def _image_fallback(item: TextItem):
                             "</figure>"
                         )
 
+                img_fallback = _image_fallback(item)
+
                 # If the formula is not processed correcty, use its image
                 if (
                     item.text == ""
                     and item.orig != ""
                     and image_mode == ImageRefMode.EMBEDDED
                     and len(item.prov) > 0
+                    and img_fallback is not None
                 ):
-                    text = _image_fallback(item)
+                    text = img_fallback
 
                 # Building a math equation in MathML format
                 # ref https://www.w3.org/TR/wai-aria-1.1/#math
@@ -2791,9 +2794,13 @@ def _image_fallback(item: TextItem):
                             "Malformed formula cannot be rendered. "
                             f"Error {err.__class__.__name__}, formula={math_formula}"
                         )
-                        if image_mode == ImageRefMode.EMBEDDED and len(item.prov) > 0:
-                            text = _image_fallback(item)
-                        else:
+                        if (
+                            image_mode == ImageRefMode.EMBEDDED
+                            and len(item.prov) > 0
+                            and img_fallback is not None
+                        ):
+                            text = img_fallback
+                        elif len(math_formula) > 0:
                             text = f"<pre>{math_formula}</pre>"
 
                 elif math_formula != "":


Test patch:
diff --git a/test/test_docling_doc.py b/test/test_docling_doc.py
index 09d118c9..4b067e36 100644
--- a/test/test_docling_doc.py
+++ b/test/test_docling_doc.py
@@ -775,6 +775,25 @@ def test_formula_mathml():
     assert doc_html == gt_html
 
 
+def test_formula_with_missing_fallback():
+    doc = DoclingDocument(name="Dummy")
+    bbox = BoundingBox.from_tuple((1, 2, 3, 4), origin=CoordOrigin.BOTTOMLEFT)
+    prov = ProvenanceItem(page_no=1, bbox=bbox, charspan=(0, 2))
+    doc.add_text(label=DocItemLabel.FORMULA, text="", orig="(II.24) 2 Imar", prov=prov)
+
+    actual = doc.export_to_html(
+        formula_to_mathml=True, html_head="", image_mode=ImageRefMode.EMBEDDED
+    )
+
+    expected = """<!DOCTYPE html>
+<html lang="en">
+
+<div class="formula-not-decoded">Formula not decoded</div>
+</html>"""
+
+    assert actual == expected
+
+
 def test_docitem_get_image():
     # Prepare the document
     doc = DoclingDocument(name="Dummy")