diff --git a/src/docx/document.py b/src/docx/document.py index 73757b46d..6980fbf58 100644 --- a/src/docx/document.py +++ b/src/docx/document.py @@ -245,6 +245,16 @@ def _body(self) -> _Body: self.__body = _Body(self._element.body, self) return self.__body + def add_chart(self, cx, cy, chart_part): + """ + :param cx: width + :param cy: height + :param chart_part + :return: chart part + """ + run = self.add_paragraph().add_run() + return run.add_chart(cx, cy, chart_part) + class _Body(BlockItemContainer): """Proxy for `` element in this document. diff --git a/src/docx/opc/package.py b/src/docx/opc/package.py index 3c1cdca22..ed26d99d9 100644 --- a/src/docx/opc/package.py +++ b/src/docx/opc/package.py @@ -162,7 +162,10 @@ def save(self, pkg_file: str | IO[bytes]): `pkg_file` can be either a file-path or a file-like object. """ for part in self.parts: - part.before_marshal() + try: + part.before_marshal() # 尝试调用各Part的预处理方法 + except AttributeError: # 如果Part没有此方法则忽略异常 + pass PackageWriter.write(pkg_file, self.rels, self.parts) @property diff --git a/src/docx/oxml/__init__.py b/src/docx/oxml/__init__.py index 37f608cef..1c6c143e2 100644 --- a/src/docx/oxml/__init__.py +++ b/src/docx/oxml/__init__.py @@ -23,6 +23,7 @@ CT_PositiveSize2D, CT_ShapeProperties, CT_Transform2D, + CT_Chart, ) from docx.oxml.shared import CT_DecimalNumber, CT_OnOff, CT_String from docx.oxml.text.hyperlink import CT_Hyperlink @@ -60,6 +61,7 @@ register_element_cls("wp:docPr", CT_NonVisualDrawingProps) register_element_cls("wp:extent", CT_PositiveSize2D) register_element_cls("wp:inline", CT_Inline) +register_element_cls("c:chart", CT_Chart) # --------------------------------------------------------------------------- # hyperlink-related elements diff --git a/src/docx/oxml/shape.py b/src/docx/oxml/shape.py index c6df8e7b8..309c44643 100644 --- a/src/docx/oxml/shape.py +++ b/src/docx/oxml/shape.py @@ -62,6 +62,7 @@ class CT_GraphicalObjectData(BaseOxmlElement): """```` element, container for the XML of a DrawingML object.""" pic: CT_Picture = ZeroOrOne("pic:pic") # pyright: ignore[reportAssignmentType] + cChart = ZeroOrOne("c:chart") uri: str = RequiredAttribute("uri", XsdToken) # pyright: ignore[reportAssignmentType] @@ -117,6 +118,32 @@ def _inline_xml(cls): "" % nsdecls("wp", "a", "pic", "r") ) + @classmethod + def new_chart_inline(cls, shape_id, rId, cx, cy): + """ + 创建一个新的图表内联对象。 + """ + inline = parse_xml(cls._chart_xml()) + inline.extent.cx = cx + inline.extent.cy = cy + chart = CT_Chart.new(rId) + inline.graphic.graphicData._insert_cChart(chart) + return inline + + @classmethod + def _chart_xml(cls): + return ( + "\n" + " \n" + ' \n' + ' \n' + " \n" + " \n" + ' \n' + " \n" + "" % (nsdecls("wp", "a"), nsdecls("a")) + ) + class CT_NonVisualDrawingProps(BaseOxmlElement): """Used for ```` element, and perhaps others. @@ -297,3 +324,15 @@ def cy(self): def cy(self, value): ext = self.get_or_add_ext() ext.cy = value + + +class CT_Chart(BaseOxmlElement): + @classmethod + def new(cls, rId): + chart = parse_xml(cls._chart_xml(rId)) + chart.id = rId + return chart + + @classmethod + def _chart_xml(cls, rId): + return '\n' % (nsdecls("c", "r"), rId) \ No newline at end of file diff --git a/src/docx/parts/document.py b/src/docx/parts/document.py index 4960264b1..4bae2663b 100644 --- a/src/docx/parts/document.py +++ b/src/docx/parts/document.py @@ -14,6 +14,7 @@ from docx.parts.styles import StylesPart from docx.shape import InlineShapes from docx.shared import lazyproperty +from docx.oxml.shape import CT_GraphicalObjectData, CT_Inline if TYPE_CHECKING: from docx.comments import Comments @@ -167,3 +168,12 @@ def _styles_part(self) -> StylesPart: styles_part = StylesPart.default(package) self.relate_to(styles_part, RT.STYLES) return styles_part + + def get_or_add_chart(self, cx, cy, chart_part): + rId = self.relate_to(chart_part, RT.CHART) + return rId, chart_part.chart + + def new_chart_inline(self, cx, cy, chart_part): + rId, chart = self.get_or_add_chart(cx, cy, chart_part) + shape_id = self.next_id + return CT_Inline.new_chart_inline(shape_id, rId, cx, cy), chart diff --git a/src/docx/text/run.py b/src/docx/text/run.py index 57ea31fa4..7fa5cf278 100644 --- a/src/docx/text/run.py +++ b/src/docx/text/run.py @@ -248,6 +248,11 @@ def underline(self) -> bool | WD_UNDERLINE | None: def underline(self, value: bool | WD_UNDERLINE | None): self.font.underline = value + def add_chart(self, cx, cy, chart_part): + inline, chart = self.part.new_chart_inline(cx, cy, chart_part) + self._r.add_drawing(inline) + return chart + class _Text: """Proxy object wrapping `` element."""