about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/openpyxl/drawing/spreadsheet_drawing.py
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/openpyxl/drawing/spreadsheet_drawing.py')
-rw-r--r--.venv/lib/python3.12/site-packages/openpyxl/drawing/spreadsheet_drawing.py382
1 files changed, 382 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/openpyxl/drawing/spreadsheet_drawing.py b/.venv/lib/python3.12/site-packages/openpyxl/drawing/spreadsheet_drawing.py
new file mode 100644
index 00000000..4f378ca2
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/openpyxl/drawing/spreadsheet_drawing.py
@@ -0,0 +1,382 @@
+# Copyright (c) 2010-2024 openpyxl
+
+from openpyxl.descriptors.serialisable import Serialisable
+from openpyxl.descriptors import (
+    Typed,
+    Bool,
+    NoneSet,
+    Integer,
+    Sequence,
+    Alias,
+)
+from openpyxl.descriptors.nested import (
+    NestedText,
+    NestedNoneSet,
+)
+from openpyxl.descriptors.excel import Relation
+
+from openpyxl.packaging.relationship import (
+    Relationship,
+    RelationshipList,
+)
+from openpyxl.utils import coordinate_to_tuple
+from openpyxl.utils.units import (
+    cm_to_EMU,
+    pixels_to_EMU,
+)
+from openpyxl.drawing.image import Image
+
+from openpyxl.xml.constants import SHEET_DRAWING_NS
+
+from openpyxl.chart._chart import ChartBase
+from .xdr import (
+    XDRPoint2D,
+    XDRPositiveSize2D,
+)
+from .fill import Blip
+from .connector import Shape
+from .graphic import (
+    GroupShape,
+    GraphicFrame,
+    )
+from .geometry import PresetGeometry2D
+from .picture import PictureFrame
+from .relation import ChartRelation
+
+
+class AnchorClientData(Serialisable):
+
+    fLocksWithSheet = Bool(allow_none=True)
+    fPrintsWithSheet = Bool(allow_none=True)
+
+    def __init__(self,
+                 fLocksWithSheet=None,
+                 fPrintsWithSheet=None,
+                 ):
+        self.fLocksWithSheet = fLocksWithSheet
+        self.fPrintsWithSheet = fPrintsWithSheet
+
+
+class AnchorMarker(Serialisable):
+
+    tagname = "marker"
+
+    col = NestedText(expected_type=int)
+    colOff = NestedText(expected_type=int)
+    row = NestedText(expected_type=int)
+    rowOff = NestedText(expected_type=int)
+
+    def __init__(self,
+                 col=0,
+                 colOff=0,
+                 row=0,
+                 rowOff=0,
+                 ):
+        self.col = col
+        self.colOff = colOff
+        self.row = row
+        self.rowOff = rowOff
+
+
+class _AnchorBase(Serialisable):
+
+    #one of
+    sp = Typed(expected_type=Shape, allow_none=True)
+    shape = Alias("sp")
+    grpSp = Typed(expected_type=GroupShape, allow_none=True)
+    groupShape = Alias("grpSp")
+    graphicFrame = Typed(expected_type=GraphicFrame, allow_none=True)
+    cxnSp = Typed(expected_type=Shape, allow_none=True)
+    connectionShape = Alias("cxnSp")
+    pic = Typed(expected_type=PictureFrame, allow_none=True)
+    contentPart = Relation()
+
+    clientData = Typed(expected_type=AnchorClientData)
+
+    __elements__ = ('sp', 'grpSp', 'graphicFrame',
+                    'cxnSp', 'pic', 'contentPart', 'clientData')
+
+    def __init__(self,
+                 clientData=None,
+                 sp=None,
+                 grpSp=None,
+                 graphicFrame=None,
+                 cxnSp=None,
+                 pic=None,
+                 contentPart=None
+                 ):
+        if clientData is None:
+            clientData = AnchorClientData()
+        self.clientData = clientData
+        self.sp = sp
+        self.grpSp = grpSp
+        self.graphicFrame = graphicFrame
+        self.cxnSp = cxnSp
+        self.pic = pic
+        self.contentPart = contentPart
+
+
+class AbsoluteAnchor(_AnchorBase):
+
+    tagname = "absoluteAnchor"
+
+    pos = Typed(expected_type=XDRPoint2D)
+    ext = Typed(expected_type=XDRPositiveSize2D)
+
+    sp = _AnchorBase.sp
+    grpSp = _AnchorBase.grpSp
+    graphicFrame = _AnchorBase.graphicFrame
+    cxnSp = _AnchorBase.cxnSp
+    pic = _AnchorBase.pic
+    contentPart = _AnchorBase.contentPart
+    clientData = _AnchorBase.clientData
+
+    __elements__ = ('pos', 'ext') + _AnchorBase.__elements__
+
+    def __init__(self,
+                 pos=None,
+                 ext=None,
+                 **kw
+                ):
+        if pos is None:
+            pos = XDRPoint2D(0, 0)
+        self.pos = pos
+        if ext is None:
+            ext = XDRPositiveSize2D(0, 0)
+        self.ext = ext
+        super().__init__(**kw)
+
+
+class OneCellAnchor(_AnchorBase):
+
+    tagname = "oneCellAnchor"
+
+    _from = Typed(expected_type=AnchorMarker)
+    ext = Typed(expected_type=XDRPositiveSize2D)
+
+    sp = _AnchorBase.sp
+    grpSp = _AnchorBase.grpSp
+    graphicFrame = _AnchorBase.graphicFrame
+    cxnSp = _AnchorBase.cxnSp
+    pic = _AnchorBase.pic
+    contentPart = _AnchorBase.contentPart
+    clientData = _AnchorBase.clientData
+
+    __elements__ = ('_from', 'ext') + _AnchorBase.__elements__
+
+
+    def __init__(self,
+                 _from=None,
+                 ext=None,
+                 **kw
+                ):
+        if _from is None:
+            _from = AnchorMarker()
+        self._from = _from
+        if ext is None:
+            ext = XDRPositiveSize2D(0, 0)
+        self.ext = ext
+        super().__init__(**kw)
+
+
+class TwoCellAnchor(_AnchorBase):
+
+    tagname = "twoCellAnchor"
+
+    editAs = NoneSet(values=(['twoCell', 'oneCell', 'absolute']))
+    _from = Typed(expected_type=AnchorMarker)
+    to = Typed(expected_type=AnchorMarker)
+
+    sp = _AnchorBase.sp
+    grpSp = _AnchorBase.grpSp
+    graphicFrame = _AnchorBase.graphicFrame
+    cxnSp = _AnchorBase.cxnSp
+    pic = _AnchorBase.pic
+    contentPart = _AnchorBase.contentPart
+    clientData = _AnchorBase.clientData
+
+    __elements__ = ('_from', 'to') + _AnchorBase.__elements__
+
+    def __init__(self,
+                 editAs=None,
+                 _from=None,
+                 to=None,
+                 **kw
+                 ):
+        self.editAs = editAs
+        if _from is None:
+            _from = AnchorMarker()
+        self._from = _from
+        if to is None:
+            to = AnchorMarker()
+        self.to = to
+        super().__init__(**kw)
+
+
+def _check_anchor(obj):
+    """
+    Check whether an object has an existing Anchor object
+    If not create a OneCellAnchor using the provided coordinate
+    """
+    anchor = obj.anchor
+    if not isinstance(anchor, _AnchorBase):
+        row, col = coordinate_to_tuple(anchor.upper())
+        anchor = OneCellAnchor()
+        anchor._from.row = row -1
+        anchor._from.col = col -1
+        if isinstance(obj, ChartBase):
+            anchor.ext.width = cm_to_EMU(obj.width)
+            anchor.ext.height = cm_to_EMU(obj.height)
+        elif isinstance(obj, Image):
+            anchor.ext.width = pixels_to_EMU(obj.width)
+            anchor.ext.height = pixels_to_EMU(obj.height)
+    return anchor
+
+
+class SpreadsheetDrawing(Serialisable):
+
+    tagname = "wsDr"
+    mime_type = "application/vnd.openxmlformats-officedocument.drawing+xml"
+    _rel_type = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing"
+    _path = PartName="/xl/drawings/drawing{0}.xml"
+    _id = None
+
+    twoCellAnchor = Sequence(expected_type=TwoCellAnchor, allow_none=True)
+    oneCellAnchor = Sequence(expected_type=OneCellAnchor, allow_none=True)
+    absoluteAnchor = Sequence(expected_type=AbsoluteAnchor, allow_none=True)
+
+    __elements__ = ("twoCellAnchor", "oneCellAnchor", "absoluteAnchor")
+
+    def __init__(self,
+                 twoCellAnchor=(),
+                 oneCellAnchor=(),
+                 absoluteAnchor=(),
+                 ):
+        self.twoCellAnchor = twoCellAnchor
+        self.oneCellAnchor = oneCellAnchor
+        self.absoluteAnchor = absoluteAnchor
+        self.charts = []
+        self.images = []
+        self._rels = []
+
+
+    def __hash__(self):
+        """
+        Just need to check for identity
+        """
+        return id(self)
+
+
+    def __bool__(self):
+        return bool(self.charts) or bool(self.images)
+
+
+
+    def _write(self):
+        """
+        create required structure and the serialise
+        """
+        anchors = []
+        for idx, obj in enumerate(self.charts + self.images, 1):
+            anchor = _check_anchor(obj)
+            if isinstance(obj, ChartBase):
+                rel = Relationship(type="chart", Target=obj.path)
+                anchor.graphicFrame = self._chart_frame(idx)
+            elif isinstance(obj, Image):
+                rel = Relationship(type="image", Target=obj.path)
+                child = anchor.pic or anchor.groupShape and anchor.groupShape.pic
+                if not child:
+                    anchor.pic = self._picture_frame(idx)
+                else:
+                    child.blipFill.blip.embed = "rId{0}".format(idx)
+
+            anchors.append(anchor)
+            self._rels.append(rel)
+
+        for a in anchors:
+            if isinstance(a, OneCellAnchor):
+                self.oneCellAnchor.append(a)
+            elif isinstance(a, TwoCellAnchor):
+                self.twoCellAnchor.append(a)
+            else:
+                self.absoluteAnchor.append(a)
+
+        tree = self.to_tree()
+        tree.set('xmlns', SHEET_DRAWING_NS)
+        return tree
+
+
+    def _chart_frame(self, idx):
+        chart_rel = ChartRelation(f"rId{idx}")
+        frame = GraphicFrame()
+        nv = frame.nvGraphicFramePr.cNvPr
+        nv.id = idx
+        nv.name = "Chart {0}".format(idx)
+        frame.graphic.graphicData.chart = chart_rel
+        return frame
+
+
+    def _picture_frame(self, idx):
+        pic = PictureFrame()
+        pic.nvPicPr.cNvPr.descr = "Picture"
+        pic.nvPicPr.cNvPr.id = idx
+        pic.nvPicPr.cNvPr.name = "Image {0}".format(idx)
+
+        pic.blipFill.blip = Blip()
+        pic.blipFill.blip.embed = "rId{0}".format(idx)
+        pic.blipFill.blip.cstate = "print"
+
+        pic.spPr.prstGeom = PresetGeometry2D(prst="rect")
+        pic.spPr.ln = None
+        return pic
+
+
+    def _write_rels(self):
+        rels = RelationshipList()
+        for r in self._rels:
+            rels.append(r)
+        return rels.to_tree()
+
+
+    @property
+    def path(self):
+        return self._path.format(self._id)
+
+
+    @property
+    def _chart_rels(self):
+        """
+        Get relationship information for each chart and bind anchor to it
+        """
+        rels = []
+        anchors = self.absoluteAnchor + self.oneCellAnchor + self.twoCellAnchor
+        for anchor in anchors:
+            if anchor.graphicFrame is not None:
+                graphic = anchor.graphicFrame.graphic
+                rel = graphic.graphicData.chart
+                if rel is not None:
+                    rel.anchor = anchor
+                    rel.anchor.graphicFrame = None
+                    rels.append(rel)
+        return rels
+
+
+    @property
+    def _blip_rels(self):
+        """
+        Get relationship information for each blip and bind anchor to it
+
+        Images that are not part of the XLSX package will be ignored.
+        """
+        rels = []
+        anchors = self.absoluteAnchor + self.oneCellAnchor + self.twoCellAnchor
+
+        for anchor in anchors:
+            child = anchor.pic or anchor.groupShape and anchor.groupShape.pic
+            if child and child.blipFill:
+                rel = child.blipFill.blip
+                if rel is not None and rel.embed:
+                    rel.anchor = anchor
+                    rels.append(rel)
+
+        return rels