1# Copyright (c) 2010-2024 openpyxl
2
3from openpyxl.descriptors.serialisable import Serialisable
4from openpyxl.descriptors import (
5 Typed,
6 Float,
7 Integer,
8 Bool,
9 MinMax,
10 Set,
11 NoneSet,
12 String,
13 Alias,
14)
15from openpyxl.descriptors.excel import Coordinate, Percentage
16from openpyxl.descriptors.excel import ExtensionList as OfficeArtExtensionList
17from .line import LineProperties
18
19from openpyxl.styles.colors import Color
20from openpyxl.xml.constants import DRAWING_NS
21
22
23class Point2D(Serialisable):
24
25 tagname = "off"
26 namespace = DRAWING_NS
27
28 x = Coordinate()
29 y = Coordinate()
30
31 def __init__(self,
32 x=None,
33 y=None,
34 ):
35 self.x = x
36 self.y = y
37
38
39class PositiveSize2D(Serialisable):
40
41 tagname = "ext"
42 namespace = DRAWING_NS
43
44 """
45 Dimensions in EMUs
46 """
47
48 cx = Integer()
49 width = Alias('cx')
50 cy = Integer()
51 height = Alias('cy')
52
53 def __init__(self,
54 cx=None,
55 cy=None,
56 ):
57 self.cx = cx
58 self.cy = cy
59
60
61class Transform2D(Serialisable):
62
63 tagname = "xfrm"
64 namespace = DRAWING_NS
65
66 rot = Integer(allow_none=True)
67 flipH = Bool(allow_none=True)
68 flipV = Bool(allow_none=True)
69 off = Typed(expected_type=Point2D, allow_none=True)
70 ext = Typed(expected_type=PositiveSize2D, allow_none=True)
71 chOff = Typed(expected_type=Point2D, allow_none=True)
72 chExt = Typed(expected_type=PositiveSize2D, allow_none=True)
73
74 __elements__ = ('off', 'ext', 'chOff', 'chExt')
75
76 def __init__(self,
77 rot=None,
78 flipH=None,
79 flipV=None,
80 off=None,
81 ext=None,
82 chOff=None,
83 chExt=None,
84 ):
85 self.rot = rot
86 self.flipH = flipH
87 self.flipV = flipV
88 self.off = off
89 self.ext = ext
90 self.chOff = chOff
91 self.chExt = chExt
92
93
94class GroupTransform2D(Serialisable):
95
96 tagname = "xfrm"
97 namespace = DRAWING_NS
98
99 rot = Integer(allow_none=True)
100 flipH = Bool(allow_none=True)
101 flipV = Bool(allow_none=True)
102 off = Typed(expected_type=Point2D, allow_none=True)
103 ext = Typed(expected_type=PositiveSize2D, allow_none=True)
104 chOff = Typed(expected_type=Point2D, allow_none=True)
105 chExt = Typed(expected_type=PositiveSize2D, allow_none=True)
106
107 __elements__ = ("off", "ext", "chOff", "chExt")
108
109 def __init__(self,
110 rot=0,
111 flipH=None,
112 flipV=None,
113 off=None,
114 ext=None,
115 chOff=None,
116 chExt=None,
117 ):
118 self.rot = rot
119 self.flipH = flipH
120 self.flipV = flipV
121 self.off = off
122 self.ext = ext
123 self.chOff = chOff
124 self.chExt = chExt
125
126
127class SphereCoords(Serialisable):
128
129 tagname = "sphereCoords" # usually
130
131 lat = Integer()
132 lon = Integer()
133 rev = Integer()
134
135 def __init__(self,
136 lat=None,
137 lon=None,
138 rev=None,
139 ):
140 self.lat = lat
141 self.lon = lon
142 self.rev = rev
143
144
145class Camera(Serialisable):
146
147 tagname = "camera"
148
149 prst = Set(values=[
150 'legacyObliqueTopLeft', 'legacyObliqueTop', 'legacyObliqueTopRight', 'legacyObliqueLeft',
151 'legacyObliqueFront', 'legacyObliqueRight', 'legacyObliqueBottomLeft',
152 'legacyObliqueBottom', 'legacyObliqueBottomRight', 'legacyPerspectiveTopLeft',
153 'legacyPerspectiveTop', 'legacyPerspectiveTopRight', 'legacyPerspectiveLeft',
154 'legacyPerspectiveFront', 'legacyPerspectiveRight', 'legacyPerspectiveBottomLeft',
155 'legacyPerspectiveBottom', 'legacyPerspectiveBottomRight', 'orthographicFront',
156 'isometricTopUp', 'isometricTopDown', 'isometricBottomUp', 'isometricBottomDown',
157 'isometricLeftUp', 'isometricLeftDown', 'isometricRightUp', 'isometricRightDown',
158 'isometricOffAxis1Left', 'isometricOffAxis1Right', 'isometricOffAxis1Top',
159 'isometricOffAxis2Left', 'isometricOffAxis2Right', 'isometricOffAxis2Top',
160 'isometricOffAxis3Left', 'isometricOffAxis3Right', 'isometricOffAxis3Bottom',
161 'isometricOffAxis4Left', 'isometricOffAxis4Right', 'isometricOffAxis4Bottom',
162 'obliqueTopLeft', 'obliqueTop', 'obliqueTopRight', 'obliqueLeft', 'obliqueRight',
163 'obliqueBottomLeft', 'obliqueBottom', 'obliqueBottomRight', 'perspectiveFront',
164 'perspectiveLeft', 'perspectiveRight', 'perspectiveAbove', 'perspectiveBelow',
165 'perspectiveAboveLeftFacing', 'perspectiveAboveRightFacing',
166 'perspectiveContrastingLeftFacing', 'perspectiveContrastingRightFacing',
167 'perspectiveHeroicLeftFacing', 'perspectiveHeroicRightFacing',
168 'perspectiveHeroicExtremeLeftFacing', 'perspectiveHeroicExtremeRightFacing',
169 'perspectiveRelaxed', 'perspectiveRelaxedModerately'])
170 fov = Integer(allow_none=True)
171 zoom = Typed(expected_type=Percentage, allow_none=True)
172 rot = Typed(expected_type=SphereCoords, allow_none=True)
173
174
175 def __init__(self,
176 prst=None,
177 fov=None,
178 zoom=None,
179 rot=None,
180 ):
181 self.prst = prst
182 self.fov = fov
183 self.zoom = zoom
184 self.rot = rot
185
186
187class LightRig(Serialisable):
188
189 tagname = "lightRig"
190
191 rig = Set(values=['legacyFlat1', 'legacyFlat2', 'legacyFlat3', 'legacyFlat4', 'legacyNormal1',
192 'legacyNormal2', 'legacyNormal3', 'legacyNormal4', 'legacyHarsh1',
193 'legacyHarsh2', 'legacyHarsh3', 'legacyHarsh4', 'threePt', 'balanced',
194 'soft', 'harsh', 'flood', 'contrasting', 'morning', 'sunrise', 'sunset',
195 'chilly', 'freezing', 'flat', 'twoPt', 'glow', 'brightRoom']
196 )
197 dir = Set(values=(['tl', 't', 'tr', 'l', 'r', 'bl', 'b', 'br']))
198 rot = Typed(expected_type=SphereCoords, allow_none=True)
199
200 def __init__(self,
201 rig=None,
202 dir=None,
203 rot=None,
204 ):
205 self.rig = rig
206 self.dir = dir
207 self.rot = rot
208
209
210class Vector3D(Serialisable):
211
212 tagname = "vector"
213
214 dx = Integer() # can be in or universl measure :-/
215 dy = Integer()
216 dz = Integer()
217
218 def __init__(self,
219 dx=None,
220 dy=None,
221 dz=None,
222 ):
223 self.dx = dx
224 self.dy = dy
225 self.dz = dz
226
227
228class Point3D(Serialisable):
229
230 tagname = "anchor"
231
232 x = Integer()
233 y = Integer()
234 z = Integer()
235
236 def __init__(self,
237 x=None,
238 y=None,
239 z=None,
240 ):
241 self.x = x
242 self.y = y
243 self.z = z
244
245
246class Backdrop(Serialisable):
247
248 anchor = Typed(expected_type=Point3D, )
249 norm = Typed(expected_type=Vector3D, )
250 up = Typed(expected_type=Vector3D, )
251 extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
252
253 def __init__(self,
254 anchor=None,
255 norm=None,
256 up=None,
257 extLst=None,
258 ):
259 self.anchor = anchor
260 self.norm = norm
261 self.up = up
262 self.extLst = extLst
263
264
265class Scene3D(Serialisable):
266
267 camera = Typed(expected_type=Camera, )
268 lightRig = Typed(expected_type=LightRig, )
269 backdrop = Typed(expected_type=Backdrop, allow_none=True)
270 extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
271
272 def __init__(self,
273 camera=None,
274 lightRig=None,
275 backdrop=None,
276 extLst=None,
277 ):
278 self.camera = camera
279 self.lightRig = lightRig
280 self.backdrop = backdrop
281 self.extLst = extLst
282
283
284class Bevel(Serialisable):
285
286 tagname = "bevel"
287
288 w = Integer()
289 h = Integer()
290 prst = NoneSet(values=
291 ['relaxedInset', 'circle', 'slope', 'cross', 'angle',
292 'softRound', 'convex', 'coolSlant', 'divot', 'riblet',
293 'hardEdge', 'artDeco']
294 )
295
296 def __init__(self,
297 w=None,
298 h=None,
299 prst=None,
300 ):
301 self.w = w
302 self.h = h
303 self.prst = prst
304
305
306class Shape3D(Serialisable):
307
308 namespace = DRAWING_NS
309
310 z = Typed(expected_type=Coordinate, allow_none=True)
311 extrusionH = Integer(allow_none=True)
312 contourW = Integer(allow_none=True)
313 prstMaterial = NoneSet(values=[
314 'legacyMatte','legacyPlastic', 'legacyMetal', 'legacyWireframe', 'matte', 'plastic',
315 'metal', 'warmMatte', 'translucentPowder', 'powder', 'dkEdge',
316 'softEdge', 'clear', 'flat', 'softmetal']
317 )
318 bevelT = Typed(expected_type=Bevel, allow_none=True)
319 bevelB = Typed(expected_type=Bevel, allow_none=True)
320 extrusionClr = Typed(expected_type=Color, allow_none=True)
321 contourClr = Typed(expected_type=Color, allow_none=True)
322 extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
323
324 def __init__(self,
325 z=None,
326 extrusionH=None,
327 contourW=None,
328 prstMaterial=None,
329 bevelT=None,
330 bevelB=None,
331 extrusionClr=None,
332 contourClr=None,
333 extLst=None,
334 ):
335 self.z = z
336 self.extrusionH = extrusionH
337 self.contourW = contourW
338 self.prstMaterial = prstMaterial
339 self.bevelT = bevelT
340 self.bevelB = bevelB
341 self.extrusionClr = extrusionClr
342 self.contourClr = contourClr
343 self.extLst = extLst
344
345
346class Path2D(Serialisable):
347
348 w = Float()
349 h = Float()
350 fill = NoneSet(values=(['norm', 'lighten', 'lightenLess', 'darken', 'darkenLess']))
351 stroke = Bool(allow_none=True)
352 extrusionOk = Bool(allow_none=True)
353
354 def __init__(self,
355 w=None,
356 h=None,
357 fill=None,
358 stroke=None,
359 extrusionOk=None,
360 ):
361 self.w = w
362 self.h = h
363 self.fill = fill
364 self.stroke = stroke
365 self.extrusionOk = extrusionOk
366
367
368class Path2DList(Serialisable):
369
370 path = Typed(expected_type=Path2D, allow_none=True)
371
372 def __init__(self,
373 path=None,
374 ):
375 self.path = path
376
377
378class GeomRect(Serialisable):
379
380 l = Coordinate()
381 t = Coordinate()
382 r = Coordinate()
383 b = Coordinate()
384
385 def __init__(self,
386 l=None,
387 t=None,
388 r=None,
389 b=None,
390 ):
391 self.l = l
392 self.t = t
393 self.r = r
394 self.b = b
395
396
397class AdjPoint2D(Serialisable):
398
399 x = Coordinate()
400 y = Coordinate()
401
402 def __init__(self,
403 x=None,
404 y=None,
405 ):
406 self.x = x
407 self.y = y
408
409
410class ConnectionSite(Serialisable):
411
412 ang = MinMax(min=0, max=360) # guess work, can also be a name
413 pos = Typed(expected_type=AdjPoint2D, )
414
415 def __init__(self,
416 ang=None,
417 pos=None,
418 ):
419 self.ang = ang
420 self.pos = pos
421
422
423class ConnectionSiteList(Serialisable):
424
425 cxn = Typed(expected_type=ConnectionSite, allow_none=True)
426
427 def __init__(self,
428 cxn=None,
429 ):
430 self.cxn = cxn
431
432
433class AdjustHandleList(Serialisable):
434
435 pass
436
437class GeomGuide(Serialisable):
438
439 name = String()
440 fmla = String()
441
442 def __init__(self,
443 name=None,
444 fmla=None,
445 ):
446 self.name = name
447 self.fmla = fmla
448
449
450class GeomGuideList(Serialisable):
451
452 gd = Typed(expected_type=GeomGuide, allow_none=True)
453
454 def __init__(self,
455 gd=None,
456 ):
457 self.gd = gd
458
459
460class CustomGeometry2D(Serialisable):
461
462 avLst = Typed(expected_type=GeomGuideList, allow_none=True)
463 gdLst = Typed(expected_type=GeomGuideList, allow_none=True)
464 ahLst = Typed(expected_type=AdjustHandleList, allow_none=True)
465 cxnLst = Typed(expected_type=ConnectionSiteList, allow_none=True)
466 #rect = Typed(expected_type=GeomRect, allow_none=True)
467 pathLst = Typed(expected_type=Path2DList, )
468
469 def __init__(self,
470 avLst=None,
471 gdLst=None,
472 ahLst=None,
473 cxnLst=None,
474 rect=None,
475 pathLst=None,
476 ):
477 self.avLst = avLst
478 self.gdLst = gdLst
479 self.ahLst = ahLst
480 self.cxnLst = cxnLst
481 self.rect = None
482 self.pathLst = pathLst
483
484
485class PresetGeometry2D(Serialisable):
486
487 namespace = DRAWING_NS
488
489 prst = Set(values=(
490 ['line', 'lineInv', 'triangle', 'rtTriangle', 'rect',
491 'diamond', 'parallelogram', 'trapezoid', 'nonIsoscelesTrapezoid',
492 'pentagon', 'hexagon', 'heptagon', 'octagon', 'decagon', 'dodecagon',
493 'star4', 'star5', 'star6', 'star7', 'star8', 'star10', 'star12',
494 'star16', 'star24', 'star32', 'roundRect', 'round1Rect',
495 'round2SameRect', 'round2DiagRect', 'snipRoundRect', 'snip1Rect',
496 'snip2SameRect', 'snip2DiagRect', 'plaque', 'ellipse', 'teardrop',
497 'homePlate', 'chevron', 'pieWedge', 'pie', 'blockArc', 'donut',
498 'noSmoking', 'rightArrow', 'leftArrow', 'upArrow', 'downArrow',
499 'stripedRightArrow', 'notchedRightArrow', 'bentUpArrow',
500 'leftRightArrow', 'upDownArrow', 'leftUpArrow', 'leftRightUpArrow',
501 'quadArrow', 'leftArrowCallout', 'rightArrowCallout', 'upArrowCallout',
502 'downArrowCallout', 'leftRightArrowCallout', 'upDownArrowCallout',
503 'quadArrowCallout', 'bentArrow', 'uturnArrow', 'circularArrow',
504 'leftCircularArrow', 'leftRightCircularArrow', 'curvedRightArrow',
505 'curvedLeftArrow', 'curvedUpArrow', 'curvedDownArrow', 'swooshArrow',
506 'cube', 'can', 'lightningBolt', 'heart', 'sun', 'moon', 'smileyFace',
507 'irregularSeal1', 'irregularSeal2', 'foldedCorner', 'bevel', 'frame',
508 'halfFrame', 'corner', 'diagStripe', 'chord', 'arc', 'leftBracket',
509 'rightBracket', 'leftBrace', 'rightBrace', 'bracketPair', 'bracePair',
510 'straightConnector1', 'bentConnector2', 'bentConnector3',
511 'bentConnector4', 'bentConnector5', 'curvedConnector2',
512 'curvedConnector3', 'curvedConnector4', 'curvedConnector5', 'callout1',
513 'callout2', 'callout3', 'accentCallout1', 'accentCallout2',
514 'accentCallout3', 'borderCallout1', 'borderCallout2', 'borderCallout3',
515 'accentBorderCallout1', 'accentBorderCallout2', 'accentBorderCallout3',
516 'wedgeRectCallout', 'wedgeRoundRectCallout', 'wedgeEllipseCallout',
517 'cloudCallout', 'cloud', 'ribbon', 'ribbon2', 'ellipseRibbon',
518 'ellipseRibbon2', 'leftRightRibbon', 'verticalScroll',
519 'horizontalScroll', 'wave', 'doubleWave', 'plus', 'flowChartProcess',
520 'flowChartDecision', 'flowChartInputOutput',
521 'flowChartPredefinedProcess', 'flowChartInternalStorage',
522 'flowChartDocument', 'flowChartMultidocument', 'flowChartTerminator',
523 'flowChartPreparation', 'flowChartManualInput',
524 'flowChartManualOperation', 'flowChartConnector', 'flowChartPunchedCard',
525 'flowChartPunchedTape', 'flowChartSummingJunction', 'flowChartOr',
526 'flowChartCollate', 'flowChartSort', 'flowChartExtract',
527 'flowChartMerge', 'flowChartOfflineStorage', 'flowChartOnlineStorage',
528 'flowChartMagneticTape', 'flowChartMagneticDisk',
529 'flowChartMagneticDrum', 'flowChartDisplay', 'flowChartDelay',
530 'flowChartAlternateProcess', 'flowChartOffpageConnector',
531 'actionButtonBlank', 'actionButtonHome', 'actionButtonHelp',
532 'actionButtonInformation', 'actionButtonForwardNext',
533 'actionButtonBackPrevious', 'actionButtonEnd', 'actionButtonBeginning',
534 'actionButtonReturn', 'actionButtonDocument', 'actionButtonSound',
535 'actionButtonMovie', 'gear6', 'gear9', 'funnel', 'mathPlus', 'mathMinus',
536 'mathMultiply', 'mathDivide', 'mathEqual', 'mathNotEqual', 'cornerTabs',
537 'squareTabs', 'plaqueTabs', 'chartX', 'chartStar', 'chartPlus']))
538 avLst = Typed(expected_type=GeomGuideList, allow_none=True)
539
540 def __init__(self,
541 prst=None,
542 avLst=None,
543 ):
544 self.prst = prst
545 self.avLst = avLst
546
547
548class FontReference(Serialisable):
549
550 idx = NoneSet(values=(['major', 'minor']))
551
552 def __init__(self,
553 idx=None,
554 ):
555 self.idx = idx
556
557
558class StyleMatrixReference(Serialisable):
559
560 idx = Integer()
561
562 def __init__(self,
563 idx=None,
564 ):
565 self.idx = idx
566
567
568class ShapeStyle(Serialisable):
569
570 lnRef = Typed(expected_type=StyleMatrixReference, )
571 fillRef = Typed(expected_type=StyleMatrixReference, )
572 effectRef = Typed(expected_type=StyleMatrixReference, )
573 fontRef = Typed(expected_type=FontReference, )
574
575 def __init__(self,
576 lnRef=None,
577 fillRef=None,
578 effectRef=None,
579 fontRef=None,
580 ):
581 self.lnRef = lnRef
582 self.fillRef = fillRef
583 self.effectRef = effectRef
584 self.fontRef = fontRef