Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docling_core/transforms/serializer/doctags.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ def serialize(
"""Serializes the passed item."""
params = DocTagsParams(**kwargs)
res_parts: list[SerializationResult] = []
is_chart = False
is_chart = item.label == DocItemLabel.CHART

if item.self_ref not in doc_serializer.get_excluded_refs(**kwargs):
body = ""
Expand Down
17 changes: 15 additions & 2 deletions docling_core/transforms/serializer/html.py
Original file line number Diff line number Diff line change
Expand Up @@ -943,7 +943,13 @@ def serialize(
if (
(params.allowed_meta_names is None or key in params.allowed_meta_names)
and (key not in params.blocked_meta_names)
and (tmp := self._serialize_meta_field(item.meta, key))
and (
tmp := self._serialize_meta_field(
item.meta,
key,
params.enable_chart_tables,
)
)
)
]
if item.meta is not None and item.meta.has_content()
Expand All @@ -960,7 +966,12 @@ def serialize(
# NOTE for now using an empty span source for GroupItems
)

def _serialize_meta_field(self, meta: BaseMeta, name: str) -> Optional[str]:
def _serialize_meta_field(
self,
meta: BaseMeta,
name: str,
enable_chart_tables: bool,
) -> Optional[str]:
if (field_val := getattr(meta, name)) is not None:
is_html_markup = False

Expand Down Expand Up @@ -988,6 +999,8 @@ def _serialize_meta_field(self, meta: BaseMeta, name: str) -> Optional[str]:
elif isinstance(field_val, MoleculeMetaField):
txt = field_val.smi
elif isinstance(field_val, TabularChartMetaField):
if not enable_chart_tables:
return None
temp_doc = DoclingDocument(name="temp")
temp_table = temp_doc.add_table(data=field_val.chart_data)
table_content = temp_table.export_to_html(temp_doc).strip()
Expand Down
19 changes: 17 additions & 2 deletions docling_core/transforms/serializer/markdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,14 @@ def serialize(
if (
(params.allowed_meta_names is None or key in params.allowed_meta_names)
and (key not in params.blocked_meta_names)
and (tmp := self._serialize_meta_field(item.meta, key, params.mark_meta))
and (
tmp := self._serialize_meta_field(
item.meta,
key,
params.mark_meta,
params.enable_chart_tables,
)
)
)
]
if item.meta
Expand All @@ -360,7 +367,13 @@ def serialize(
# NOTE for now using an empty span source for GroupItems
)

def _serialize_meta_field(self, meta: BaseMeta, name: str, mark_meta: bool) -> Optional[str]:
def _serialize_meta_field(
self,
meta: BaseMeta,
name: str,
mark_meta: bool,
enable_chart_tables: bool,
) -> Optional[str]:
if (field_val := getattr(meta, name)) is not None:
if isinstance(field_val, SummaryMetaField):
txt = field_val.text
Expand All @@ -371,6 +384,8 @@ def _serialize_meta_field(self, meta: BaseMeta, name: str, mark_meta: bool) -> O
elif isinstance(field_val, MoleculeMetaField):
txt = field_val.smi
elif isinstance(field_val, TabularChartMetaField):
if not enable_chart_tables:
return None
temp_doc = DoclingDocument(name="temp")
temp_table = temp_doc.add_table(data=field_val.chart_data)
table_content = temp_table.export_to_markdown(temp_doc).strip()
Expand Down
9 changes: 7 additions & 2 deletions docling_core/types/doc/document.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
DocItemLabel.PARAGRAPH,
DocItemLabel.TABLE,
DocItemLabel.PICTURE,
DocItemLabel.CHART,
DocItemLabel.FORMULA,
DocItemLabel.CHECKBOX_UNSELECTED,
DocItemLabel.CHECKBOX_SELECTED,
Expand Down Expand Up @@ -4139,6 +4140,7 @@ def add_picture(
prov: Optional[ProvenanceItem] = None,
parent: Optional[NodeItem] = None,
content_layer: Optional[ContentLayer] = None,
label: Literal[DocItemLabel.PICTURE, DocItemLabel.CHART] = DocItemLabel.PICTURE,
):
"""add_picture.

Expand All @@ -4147,6 +4149,7 @@ def add_picture(
:param RefItem]]: (Default value = None)
:param prov: Optional[ProvenanceItem]: (Default value = None)
:param parent: Optional[NodeItem]: (Default value = None)
:param label: Label for the picture item. (Default value = DocItemLabel.PICTURE)
"""
if not parent:
parent = self.body
Expand All @@ -4155,7 +4158,7 @@ def add_picture(
cref = f"#/pictures/{picture_index}"

fig_item = PictureItem(
label=DocItemLabel.PICTURE,
label=label,
annotations=annotations or [],
image=image,
self_ref=cref,
Expand Down Expand Up @@ -5073,6 +5076,7 @@ def insert_picture(
prov: Optional[ProvenanceItem] = None,
content_layer: Optional[ContentLayer] = None,
after: bool = True,
label: Literal[DocItemLabel.PICTURE, DocItemLabel.CHART] = DocItemLabel.PICTURE,
) -> PictureItem:
"""Creates a new PictureItem item and inserts it into the document.

Expand All @@ -5083,6 +5087,7 @@ def insert_picture(
:param prov: Optional[ProvenanceItem]: (Default value = None)
:param content_layer: Optional[ContentLayer]: (Default value = None)
:param after: bool: (Default value = True)
:param label: Label for the picture item. (Default value = DocItemLabel.PICTURE)

:returns: PictureItem: The newly created PictureItem item.
"""
Expand All @@ -5091,7 +5096,7 @@ def insert_picture(

# Create a new PictureItem NodeItem
picture_item = PictureItem(
label=DocItemLabel.PICTURE,
label=label,
annotations=annotations or [],
image=image,
self_ref="#",
Expand Down
108 changes: 105 additions & 3 deletions test/test_docling_doc.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import itertools
import base64
import itertools
import os
import re
import warnings
Expand Down Expand Up @@ -41,6 +41,7 @@
NodeItem,
Orientation,
PictureItem,
PictureMeta,
ProvenanceItem,
RefItem,
RichTableCell,
Expand All @@ -49,6 +50,7 @@
TableCell,
TableData,
TableItem,
TabularChartMetaField,
TextItem,
TitleItem,
)
Expand Down Expand Up @@ -135,6 +137,106 @@ def test_overlaps_vertically():
bbox1.overlaps_vertically(bbox4)


def test_add_picture_supports_chart_label():
doc = DoclingDocument(name="Chart Doc")

chart = doc.add_picture(label=DocItemLabel.CHART)
picture = doc.add_picture()

assert chart.label == DocItemLabel.CHART
assert picture.label == DocItemLabel.PICTURE
assert doc.pictures == [chart, picture]


def test_insert_picture_supports_chart_label():
doc = DoclingDocument(name="Chart Doc")
text = doc.add_text(label=DocItemLabel.TEXT, text="before chart")

chart = doc.insert_picture(sibling=text, label=DocItemLabel.CHART)

assert chart.label == DocItemLabel.CHART
assert doc.pictures == [chart]
assert doc.body.children[1] == chart.get_ref()


def test_chart_picture_tabular_meta_exports_to_markdown_by_default():
doc = DoclingDocument(name="Chart Doc")
chart = doc.add_picture(label=DocItemLabel.CHART)
chart.meta = PictureMeta(
tabular_chart=TabularChartMetaField(
chart_data=TableData(
num_rows=3,
num_cols=2,
table_cells=[
TableCell(
text="Quarter",
start_row_offset_idx=0,
end_row_offset_idx=1,
start_col_offset_idx=0,
end_col_offset_idx=1,
column_header=True,
),
TableCell(
text="Revenue",
start_row_offset_idx=0,
end_row_offset_idx=1,
start_col_offset_idx=1,
end_col_offset_idx=2,
column_header=True,
),
TableCell(
text="Q1",
start_row_offset_idx=1,
end_row_offset_idx=2,
start_col_offset_idx=0,
end_col_offset_idx=1,
),
TableCell(
text="12.3",
start_row_offset_idx=1,
end_row_offset_idx=2,
start_col_offset_idx=1,
end_col_offset_idx=2,
),
TableCell(
text="Q2",
start_row_offset_idx=2,
end_row_offset_idx=3,
start_col_offset_idx=0,
end_col_offset_idx=1,
),
TableCell(
text="14.2",
start_row_offset_idx=2,
end_row_offset_idx=3,
start_col_offset_idx=1,
end_col_offset_idx=2,
),
],
)
)
)

markdown = doc.export_to_markdown()

assert "<!-- image -->" in markdown
assert "| Quarter | Revenue |" in markdown
assert "| Q1 | 12.3 |" in markdown
assert "| Q2 | 14.2 |" in markdown

markdown_without_chart_table = doc.export_to_markdown(enable_chart_tables=False)
assert "| Quarter | Revenue |" not in markdown_without_chart_table
assert "| Q1 | 12.3 |" not in markdown_without_chart_table

html = doc.export_to_html()
assert "<th>Quarter</th><th>Revenue</th>" in html
assert "<td>12.3</td>" in html

html_without_chart_table = doc.export_to_html(enable_chart_tables=False)
assert "<th>Quarter</th><th>Revenue</th>" not in html_without_chart_table
assert "<td>12.3</td>" not in html_without_chart_table


def test_intersection_area_with():
page_height = 300

Expand Down Expand Up @@ -824,7 +926,7 @@ def test_image_ref_blocks_oversized_base64():
import base64

large_bytes = b"X" * (28 * 1024 * 1024)
large_data = base64.b64encode(large_bytes).decode('ascii')
large_data = base64.b64encode(large_bytes).decode("ascii")
data_uri = f"data:image/png;base64,{large_data}"

image_ref = ImageRef(
Expand All @@ -850,7 +952,7 @@ def test_image_ref_accepts_valid_base64():
buffer = BytesIO()
fig_image.save(buffer, format="PNG")
img_bytes = buffer.getvalue()
img_base64 = base64.b64encode(img_bytes).decode('ascii')
img_base64 = base64.b64encode(img_bytes).decode("ascii")
data_uri = f"data:image/png;base64,{img_base64}"

# Create ImageRef with data URI
Expand Down
28 changes: 27 additions & 1 deletion test/test_serialization_doctag.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@
DocTagsDocSerializer,
DocTagsParams,
)
from docling_core.types.doc import DocItemLabel, DoclingDocument, TableData
from docling_core.types.doc import (
DocItemLabel,
DoclingDocument,
PictureMeta,
TableData,
TabularChartMetaField,
)

from .test_serialization import verify

Expand Down Expand Up @@ -55,6 +61,26 @@ def test_no_content_suppresses_figure_caption_text():
assert "Figure Caption Text" not in txt


def test_chart_labeled_picture_serializes_as_chart_without_classification():
doc = DoclingDocument(name="t")
chart = doc.add_picture(label=DocItemLabel.CHART)

table_data = TableData(num_rows=0, num_cols=2)
table_data.add_row(["Quarter", "Revenue"])
table_data.add_row(["Q1", "12.3"])
chart.meta = PictureMeta(
tabular_chart=TabularChartMetaField(chart_data=table_data)
)

txt = serialize_doctags(doc)

assert "<chart>" in txt
assert "</chart>" in txt
assert "<picture>" not in txt
assert "Quarter" in txt
assert "12.3" in txt


def test_list_items_not_double_wrapped_when_no_content():
doc = DoclingDocument(name="t")
lst = doc.add_list_group()
Expand Down
Loading