Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/openpyxl/drawing/spreadsheet_drawing.py: 41%
228 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1# Copyright (c) 2010-2022 openpyxl
3from openpyxl.descriptors.serialisable import Serialisable
4from openpyxl.descriptors import (
5 Typed,
6 Bool,
7 NoneSet,
8 Integer,
9 Sequence,
10 Alias,
11)
12from openpyxl.descriptors.nested import (
13 NestedText,
14 NestedNoneSet,
15)
16from openpyxl.descriptors.excel import Relation
18from openpyxl.packaging.relationship import (
19 Relationship,
20 RelationshipList,
21)
22from openpyxl.utils import coordinate_to_tuple
23from openpyxl.utils.units import (
24 cm_to_EMU,
25 pixels_to_EMU,
26)
27from openpyxl.drawing.image import Image
29from openpyxl.xml.constants import SHEET_DRAWING_NS
31from openpyxl.chart._chart import ChartBase
32from .xdr import (
33 XDRPoint2D,
34 XDRPositiveSize2D,
35)
36from .fill import Blip
37from .connector import Shape
38from .graphic import (
39 GroupShape,
40 GraphicFrame,
41 )
42from .geometry import PresetGeometry2D
43from .picture import PictureFrame
44from .relation import ChartRelation
47class AnchorClientData(Serialisable):
49 fLocksWithSheet = Bool(allow_none=True)
50 fPrintsWithSheet = Bool(allow_none=True)
52 def __init__(self,
53 fLocksWithSheet=None,
54 fPrintsWithSheet=None,
55 ):
56 self.fLocksWithSheet = fLocksWithSheet
57 self.fPrintsWithSheet = fPrintsWithSheet
60class AnchorMarker(Serialisable):
62 tagname = "marker"
64 col = NestedText(expected_type=int)
65 colOff = NestedText(expected_type=int)
66 row = NestedText(expected_type=int)
67 rowOff = NestedText(expected_type=int)
69 def __init__(self,
70 col=0,
71 colOff=0,
72 row=0,
73 rowOff=0,
74 ):
75 self.col = col
76 self.colOff = colOff
77 self.row = row
78 self.rowOff = rowOff
81class _AnchorBase(Serialisable):
83 #one of
84 sp = Typed(expected_type=Shape, allow_none=True)
85 shape = Alias("sp")
86 grpSp = Typed(expected_type=GroupShape, allow_none=True)
87 groupShape = Alias("grpSp")
88 graphicFrame = Typed(expected_type=GraphicFrame, allow_none=True)
89 cxnSp = Typed(expected_type=Shape, allow_none=True)
90 connectionShape = Alias("cxnSp")
91 pic = Typed(expected_type=PictureFrame, allow_none=True)
92 contentPart = Relation()
94 clientData = Typed(expected_type=AnchorClientData)
96 __elements__ = ('sp', 'grpSp', 'graphicFrame',
97 'cxnSp', 'pic', 'contentPart', 'clientData')
99 def __init__(self,
100 clientData=None,
101 sp=None,
102 grpSp=None,
103 graphicFrame=None,
104 cxnSp=None,
105 pic=None,
106 contentPart=None
107 ):
108 if clientData is None:
109 clientData = AnchorClientData()
110 self.clientData = clientData
111 self.sp = sp
112 self.grpSp = grpSp
113 self.graphicFrame = graphicFrame
114 self.cxnSp = cxnSp
115 self.pic = pic
116 self.contentPart = contentPart
119class AbsoluteAnchor(_AnchorBase):
121 tagname = "absoluteAnchor"
123 pos = Typed(expected_type=XDRPoint2D)
124 ext = Typed(expected_type=XDRPositiveSize2D)
126 sp = _AnchorBase.sp
127 grpSp = _AnchorBase.grpSp
128 graphicFrame = _AnchorBase.graphicFrame
129 cxnSp = _AnchorBase.cxnSp
130 pic = _AnchorBase.pic
131 contentPart = _AnchorBase.contentPart
132 clientData = _AnchorBase.clientData
134 __elements__ = ('pos', 'ext') + _AnchorBase.__elements__
136 def __init__(self,
137 pos=None,
138 ext=None,
139 **kw
140 ):
141 if pos is None:
142 pos = XDRPoint2D(0, 0)
143 self.pos = pos
144 if ext is None:
145 ext = XDRPositiveSize2D(0, 0)
146 self.ext = ext
147 super(AbsoluteAnchor, self).__init__(**kw)
150class OneCellAnchor(_AnchorBase):
152 tagname = "oneCellAnchor"
154 _from = Typed(expected_type=AnchorMarker)
155 ext = Typed(expected_type=XDRPositiveSize2D)
157 sp = _AnchorBase.sp
158 grpSp = _AnchorBase.grpSp
159 graphicFrame = _AnchorBase.graphicFrame
160 cxnSp = _AnchorBase.cxnSp
161 pic = _AnchorBase.pic
162 contentPart = _AnchorBase.contentPart
163 clientData = _AnchorBase.clientData
165 __elements__ = ('_from', 'ext') + _AnchorBase.__elements__
168 def __init__(self,
169 _from=None,
170 ext=None,
171 **kw
172 ):
173 if _from is None:
174 _from = AnchorMarker()
175 self._from = _from
176 if ext is None:
177 ext = XDRPositiveSize2D(0, 0)
178 self.ext = ext
179 super(OneCellAnchor, self).__init__(**kw)
182class TwoCellAnchor(_AnchorBase):
184 tagname = "twoCellAnchor"
186 editAs = NoneSet(values=(['twoCell', 'oneCell', 'absolute']))
187 _from = Typed(expected_type=AnchorMarker)
188 to = Typed(expected_type=AnchorMarker)
190 sp = _AnchorBase.sp
191 grpSp = _AnchorBase.grpSp
192 graphicFrame = _AnchorBase.graphicFrame
193 cxnSp = _AnchorBase.cxnSp
194 pic = _AnchorBase.pic
195 contentPart = _AnchorBase.contentPart
196 clientData = _AnchorBase.clientData
198 __elements__ = ('_from', 'to') + _AnchorBase.__elements__
200 def __init__(self,
201 editAs=None,
202 _from=None,
203 to=None,
204 **kw
205 ):
206 self.editAs = editAs
207 if _from is None:
208 _from = AnchorMarker()
209 self._from = _from
210 if to is None:
211 to = AnchorMarker()
212 self.to = to
213 super(TwoCellAnchor, self).__init__(**kw)
216def _check_anchor(obj):
217 """
218 Check whether an object has an existing Anchor object
219 If not create a OneCellAnchor using the provided coordinate
220 """
221 anchor = obj.anchor
222 if not isinstance(anchor, _AnchorBase):
223 row, col = coordinate_to_tuple(anchor.upper())
224 anchor = OneCellAnchor()
225 anchor._from.row = row -1
226 anchor._from.col = col -1
227 if isinstance(obj, ChartBase):
228 anchor.ext.width = cm_to_EMU(obj.width)
229 anchor.ext.height = cm_to_EMU(obj.height)
230 elif isinstance(obj, Image):
231 anchor.ext.width = pixels_to_EMU(obj.width)
232 anchor.ext.height = pixels_to_EMU(obj.height)
233 return anchor
236class SpreadsheetDrawing(Serialisable):
238 tagname = "wsDr"
239 mime_type = "application/vnd.openxmlformats-officedocument.drawing+xml"
240 _rel_type = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing"
241 _path = PartName="/xl/drawings/drawing{0}.xml"
242 _id = None
244 twoCellAnchor = Sequence(expected_type=TwoCellAnchor, allow_none=True)
245 oneCellAnchor = Sequence(expected_type=OneCellAnchor, allow_none=True)
246 absoluteAnchor = Sequence(expected_type=AbsoluteAnchor, allow_none=True)
248 __elements__ = ("twoCellAnchor", "oneCellAnchor", "absoluteAnchor")
250 def __init__(self,
251 twoCellAnchor=(),
252 oneCellAnchor=(),
253 absoluteAnchor=(),
254 ):
255 self.twoCellAnchor = twoCellAnchor
256 self.oneCellAnchor = oneCellAnchor
257 self.absoluteAnchor = absoluteAnchor
258 self.charts = []
259 self.images = []
260 self._rels = []
263 def __hash__(self):
264 """
265 Just need to check for identity
266 """
267 return id(self)
270 def __bool__(self):
271 return bool(self.charts) or bool(self.images)
275 def _write(self):
276 """
277 create required structure and the serialise
278 """
279 anchors = []
280 for idx, obj in enumerate(self.charts + self.images, 1):
281 anchor = _check_anchor(obj)
282 if isinstance(obj, ChartBase):
283 rel = Relationship(type="chart", Target=obj.path)
284 anchor.graphicFrame = self._chart_frame(idx)
285 elif isinstance(obj, Image):
286 rel = Relationship(type="image", Target=obj.path)
287 child = anchor.pic or anchor.groupShape and anchor.groupShape.pic
288 if not child:
289 anchor.pic = self._picture_frame(idx)
290 else:
291 child.blipFill.blip.embed = "rId{0}".format(idx)
293 anchors.append(anchor)
294 self._rels.append(rel)
296 for a in anchors:
297 if isinstance(a, OneCellAnchor):
298 self.oneCellAnchor.append(a)
299 elif isinstance(a, TwoCellAnchor):
300 self.twoCellAnchor.append(a)
301 else:
302 self.absoluteAnchor.append(a)
304 tree = self.to_tree()
305 tree.set('xmlns', SHEET_DRAWING_NS)
306 return tree
309 def _chart_frame(self, idx):
310 chart_rel = ChartRelation(f"rId{idx}")
311 frame = GraphicFrame()
312 nv = frame.nvGraphicFramePr.cNvPr
313 nv.id = idx
314 nv.name = "Chart {0}".format(idx)
315 frame.graphic.graphicData.chart = chart_rel
316 return frame
319 def _picture_frame(self, idx):
320 pic = PictureFrame()
321 pic.nvPicPr.cNvPr.descr = "Picture"
322 pic.nvPicPr.cNvPr.id = idx
323 pic.nvPicPr.cNvPr.name = "Image {0}".format(idx)
325 pic.blipFill.blip = Blip()
326 pic.blipFill.blip.embed = "rId{0}".format(idx)
327 pic.blipFill.blip.cstate = "print"
329 pic.spPr.prstGeom = PresetGeometry2D(prst="rect")
330 pic.spPr.ln = None
331 return pic
334 def _write_rels(self):
335 rels = RelationshipList()
336 rels.Relationship = self._rels
337 return rels.to_tree()
340 @property
341 def path(self):
342 return self._path.format(self._id)
345 @property
346 def _chart_rels(self):
347 """
348 Get relationship information for each chart and bind anchor to it
349 """
350 rels = []
351 anchors = self.absoluteAnchor + self.oneCellAnchor + self.twoCellAnchor
352 for anchor in anchors:
353 if anchor.graphicFrame is not None:
354 graphic = anchor.graphicFrame.graphic
355 rel = graphic.graphicData.chart
356 if rel is not None:
357 rel.anchor = anchor
358 rel.anchor.graphicFrame = None
359 rels.append(rel)
360 return rels
363 @property
364 def _blip_rels(self):
365 """
366 Get relationship information for each blip and bind anchor to it
368 Images that are not part of the XLSX package will be ignored.
369 """
370 rels = []
371 anchors = self.absoluteAnchor + self.oneCellAnchor + self.twoCellAnchor
373 for anchor in anchors:
374 child = anchor.pic or anchor.groupShape and anchor.groupShape.pic
375 if child and child.blipFill:
376 rel = child.blipFill.blip
377 if rel is not None and rel.embed:
378 rel.anchor = anchor
379 rels.append(rel)
381 return rels