1# Copyright (c) 2010-2024 openpyxl
2
3from openpyxl.descriptors.serialisable import Serialisable
4from openpyxl.descriptors import (
5 Alias,
6 Bool,
7 Integer,
8 Set,
9 NoneSet,
10 Typed,
11 MinMax,
12)
13from openpyxl.descriptors.excel import (
14 Relation,
15 Percentage,
16)
17from openpyxl.descriptors.nested import NestedNoneSet, NestedValue
18from openpyxl.descriptors.sequence import NestedSequence
19from openpyxl.descriptors.excel import ExtensionList as OfficeArtExtensionList
20from openpyxl.xml.constants import DRAWING_NS
21
22from .colors import (
23 ColorChoice,
24 HSLColor,
25 SystemColor,
26 SchemeColor,
27 PRESET_COLORS,
28 RGBPercent,
29)
30
31from .effect import (
32 AlphaBiLevelEffect,
33 AlphaCeilingEffect,
34 AlphaFloorEffect,
35 AlphaInverseEffect,
36 AlphaModulateEffect,
37 AlphaModulateFixedEffect,
38 AlphaReplaceEffect,
39 BiLevelEffect,
40 BlurEffect,
41 ColorChangeEffect,
42 ColorReplaceEffect,
43 DuotoneEffect,
44 FillOverlayEffect,
45 GrayscaleEffect,
46 HSLEffect,
47 LuminanceEffect,
48 TintEffect,
49)
50
51"""
52Fill elements from drawing main schema
53"""
54
55class PatternFillProperties(Serialisable):
56
57 tagname = "pattFill"
58 namespace = DRAWING_NS
59
60 prst = NoneSet(values=(['pct5', 'pct10', 'pct20', 'pct25', 'pct30',
61 'pct40', 'pct50', 'pct60', 'pct70', 'pct75', 'pct80', 'pct90', 'horz',
62 'vert', 'ltHorz', 'ltVert', 'dkHorz', 'dkVert', 'narHorz', 'narVert',
63 'dashHorz', 'dashVert', 'cross', 'dnDiag', 'upDiag', 'ltDnDiag',
64 'ltUpDiag', 'dkDnDiag', 'dkUpDiag', 'wdDnDiag', 'wdUpDiag', 'dashDnDiag',
65 'dashUpDiag', 'diagCross', 'smCheck', 'lgCheck', 'smGrid', 'lgGrid',
66 'dotGrid', 'smConfetti', 'lgConfetti', 'horzBrick', 'diagBrick',
67 'solidDmnd', 'openDmnd', 'dotDmnd', 'plaid', 'sphere', 'weave', 'divot',
68 'shingle', 'wave', 'trellis', 'zigZag']))
69 preset = Alias("prst")
70 fgClr = Typed(expected_type=ColorChoice, allow_none=True)
71 foreground = Alias("fgClr")
72 bgClr = Typed(expected_type=ColorChoice, allow_none=True)
73 background = Alias("bgClr")
74
75 __elements__ = ("fgClr", "bgClr")
76
77 def __init__(self,
78 prst=None,
79 fgClr=None,
80 bgClr=None,
81 ):
82 self.prst = prst
83 self.fgClr = fgClr
84 self.bgClr = bgClr
85
86
87class RelativeRect(Serialisable):
88
89 tagname = "rect"
90 namespace = DRAWING_NS
91
92 l = Percentage(allow_none=True)
93 left = Alias('l')
94 t = Percentage(allow_none=True)
95 top = Alias('t')
96 r = Percentage(allow_none=True)
97 right = Alias('r')
98 b = Percentage(allow_none=True)
99 bottom = Alias('b')
100
101 def __init__(self,
102 l=None,
103 t=None,
104 r=None,
105 b=None,
106 ):
107 self.l = l
108 self.t = t
109 self.r = r
110 self.b = b
111
112
113class StretchInfoProperties(Serialisable):
114
115 tagname = "stretch"
116 namespace = DRAWING_NS
117
118 fillRect = Typed(expected_type=RelativeRect, allow_none=True)
119
120 def __init__(self,
121 fillRect=RelativeRect(),
122 ):
123 self.fillRect = fillRect
124
125
126class GradientStop(Serialisable):
127
128 tagname = "gs"
129 namespace = DRAWING_NS
130
131 pos = MinMax(min=0, max=100000, allow_none=True)
132 # Color Choice Group
133 scrgbClr = Typed(expected_type=RGBPercent, allow_none=True)
134 RGBPercent = Alias('scrgbClr')
135 srgbClr = NestedValue(expected_type=str, allow_none=True) # needs pattern and can have transform
136 RGB = Alias('srgbClr')
137 hslClr = Typed(expected_type=HSLColor, allow_none=True)
138 sysClr = Typed(expected_type=SystemColor, allow_none=True)
139 schemeClr = Typed(expected_type=SchemeColor, allow_none=True)
140 prstClr = NestedNoneSet(values=PRESET_COLORS)
141
142 __elements__ = ('scrgbClr', 'srgbClr', 'hslClr', 'sysClr', 'schemeClr', 'prstClr')
143
144 def __init__(self,
145 pos=None,
146 scrgbClr=None,
147 srgbClr=None,
148 hslClr=None,
149 sysClr=None,
150 schemeClr=None,
151 prstClr=None,
152 ):
153 if pos is None:
154 pos = 0
155 self.pos = pos
156
157 self.scrgbClr = scrgbClr
158 self.srgbClr = srgbClr
159 self.hslClr = hslClr
160 self.sysClr = sysClr
161 self.schemeClr = schemeClr
162 self.prstClr = prstClr
163
164
165class LinearShadeProperties(Serialisable):
166
167 tagname = "lin"
168 namespace = DRAWING_NS
169
170 ang = Integer()
171 scaled = Bool(allow_none=True)
172
173 def __init__(self,
174 ang=None,
175 scaled=None,
176 ):
177 self.ang = ang
178 self.scaled = scaled
179
180
181class PathShadeProperties(Serialisable):
182
183 tagname = "path"
184 namespace = DRAWING_NS
185
186 path = Set(values=(['shape', 'circle', 'rect']))
187 fillToRect = Typed(expected_type=RelativeRect, allow_none=True)
188
189 def __init__(self,
190 path=None,
191 fillToRect=None,
192 ):
193 self.path = path
194 self.fillToRect = fillToRect
195
196
197class GradientFillProperties(Serialisable):
198
199 tagname = "gradFill"
200 namespace = DRAWING_NS
201
202 flip = NoneSet(values=(['x', 'y', 'xy']))
203 rotWithShape = Bool(allow_none=True)
204
205 gsLst = NestedSequence(expected_type=GradientStop, count=False)
206 stop_list = Alias("gsLst")
207
208 lin = Typed(expected_type=LinearShadeProperties, allow_none=True)
209 linear = Alias("lin")
210 path = Typed(expected_type=PathShadeProperties, allow_none=True)
211
212 tileRect = Typed(expected_type=RelativeRect, allow_none=True)
213
214 __elements__ = ('gsLst', 'lin', 'path', 'tileRect')
215
216 def __init__(self,
217 flip=None,
218 rotWithShape=None,
219 gsLst=(),
220 lin=None,
221 path=None,
222 tileRect=None,
223 ):
224 self.flip = flip
225 self.rotWithShape = rotWithShape
226 self.gsLst = gsLst
227 self.lin = lin
228 self.path = path
229 self.tileRect = tileRect
230
231
232class SolidColorFillProperties(Serialisable):
233
234 tagname = "solidFill"
235
236 # uses element group EG_ColorChoice
237 scrgbClr = Typed(expected_type=RGBPercent, allow_none=True)
238 RGBPercent = Alias('scrgbClr')
239 srgbClr = NestedValue(expected_type=str, allow_none=True) # needs pattern and can have transform
240 RGB = Alias('srgbClr')
241 hslClr = Typed(expected_type=HSLColor, allow_none=True)
242 sysClr = Typed(expected_type=SystemColor, allow_none=True)
243 schemeClr = Typed(expected_type=SchemeColor, allow_none=True)
244 prstClr = NestedNoneSet(values=PRESET_COLORS)
245
246 __elements__ = ('scrgbClr', 'srgbClr', 'hslClr', 'sysClr', 'schemeClr', 'prstClr')
247
248 def __init__(self,
249 scrgbClr=None,
250 srgbClr=None,
251 hslClr=None,
252 sysClr=None,
253 schemeClr=None,
254 prstClr=None,
255 ):
256 self.scrgbClr = scrgbClr
257 self.srgbClr = srgbClr
258 self.hslClr = hslClr
259 self.sysClr = sysClr
260 self.schemeClr = schemeClr
261 self.prstClr = prstClr
262
263
264class Blip(Serialisable):
265
266 tagname = "blip"
267 namespace = DRAWING_NS
268
269 # Using attribute groupAG_Blob
270 cstate = NoneSet(values=(['email', 'screen', 'print', 'hqprint']))
271 embed = Relation() # rId
272 link = Relation() # hyperlink
273 noGrp = Bool(allow_none=True)
274 noSelect = Bool(allow_none=True)
275 noRot = Bool(allow_none=True)
276 noChangeAspect = Bool(allow_none=True)
277 noMove = Bool(allow_none=True)
278 noResize = Bool(allow_none=True)
279 noEditPoints = Bool(allow_none=True)
280 noAdjustHandles = Bool(allow_none=True)
281 noChangeArrowheads = Bool(allow_none=True)
282 noChangeShapeType = Bool(allow_none=True)
283 # some elements are choice
284 extLst = Typed(expected_type=OfficeArtExtensionList, allow_none=True)
285 alphaBiLevel = Typed(expected_type=AlphaBiLevelEffect, allow_none=True)
286 alphaCeiling = Typed(expected_type=AlphaCeilingEffect, allow_none=True)
287 alphaFloor = Typed(expected_type=AlphaFloorEffect, allow_none=True)
288 alphaInv = Typed(expected_type=AlphaInverseEffect, allow_none=True)
289 alphaMod = Typed(expected_type=AlphaModulateEffect, allow_none=True)
290 alphaModFix = Typed(expected_type=AlphaModulateFixedEffect, allow_none=True)
291 alphaRepl = Typed(expected_type=AlphaReplaceEffect, allow_none=True)
292 biLevel = Typed(expected_type=BiLevelEffect, allow_none=True)
293 blur = Typed(expected_type=BlurEffect, allow_none=True)
294 clrChange = Typed(expected_type=ColorChangeEffect, allow_none=True)
295 clrRepl = Typed(expected_type=ColorReplaceEffect, allow_none=True)
296 duotone = Typed(expected_type=DuotoneEffect, allow_none=True)
297 fillOverlay = Typed(expected_type=FillOverlayEffect, allow_none=True)
298 grayscl = Typed(expected_type=GrayscaleEffect, allow_none=True)
299 hsl = Typed(expected_type=HSLEffect, allow_none=True)
300 lum = Typed(expected_type=LuminanceEffect, allow_none=True)
301 tint = Typed(expected_type=TintEffect, allow_none=True)
302
303 __elements__ = ('alphaBiLevel', 'alphaCeiling', 'alphaFloor', 'alphaInv',
304 'alphaMod', 'alphaModFix', 'alphaRepl', 'biLevel', 'blur', 'clrChange',
305 'clrRepl', 'duotone', 'fillOverlay', 'grayscl', 'hsl', 'lum', 'tint')
306
307 def __init__(self,
308 cstate=None,
309 embed=None,
310 link=None,
311 noGrp=None,
312 noSelect=None,
313 noRot=None,
314 noChangeAspect=None,
315 noMove=None,
316 noResize=None,
317 noEditPoints=None,
318 noAdjustHandles=None,
319 noChangeArrowheads=None,
320 noChangeShapeType=None,
321 extLst=None,
322 alphaBiLevel=None,
323 alphaCeiling=None,
324 alphaFloor=None,
325 alphaInv=None,
326 alphaMod=None,
327 alphaModFix=None,
328 alphaRepl=None,
329 biLevel=None,
330 blur=None,
331 clrChange=None,
332 clrRepl=None,
333 duotone=None,
334 fillOverlay=None,
335 grayscl=None,
336 hsl=None,
337 lum=None,
338 tint=None,
339 ):
340 self.cstate = cstate
341 self.embed = embed
342 self.link = link
343 self.noGrp = noGrp
344 self.noSelect = noSelect
345 self.noRot = noRot
346 self.noChangeAspect = noChangeAspect
347 self.noMove = noMove
348 self.noResize = noResize
349 self.noEditPoints = noEditPoints
350 self.noAdjustHandles = noAdjustHandles
351 self.noChangeArrowheads = noChangeArrowheads
352 self.noChangeShapeType = noChangeShapeType
353 self.extLst = extLst
354 self.alphaBiLevel = alphaBiLevel
355 self.alphaCeiling = alphaCeiling
356 self.alphaFloor = alphaFloor
357 self.alphaInv = alphaInv
358 self.alphaMod = alphaMod
359 self.alphaModFix = alphaModFix
360 self.alphaRepl = alphaRepl
361 self.biLevel = biLevel
362 self.blur = blur
363 self.clrChange = clrChange
364 self.clrRepl = clrRepl
365 self.duotone = duotone
366 self.fillOverlay = fillOverlay
367 self.grayscl = grayscl
368 self.hsl = hsl
369 self.lum = lum
370 self.tint = tint
371
372
373class TileInfoProperties(Serialisable):
374
375 tx = Integer(allow_none=True)
376 ty = Integer(allow_none=True)
377 sx = Integer(allow_none=True)
378 sy = Integer(allow_none=True)
379 flip = NoneSet(values=(['x', 'y', 'xy']))
380 algn = Set(values=(['tl', 't', 'tr', 'l', 'ctr', 'r', 'bl', 'b', 'br']))
381
382 def __init__(self,
383 tx=None,
384 ty=None,
385 sx=None,
386 sy=None,
387 flip=None,
388 algn=None,
389 ):
390 self.tx = tx
391 self.ty = ty
392 self.sx = sx
393 self.sy = sy
394 self.flip = flip
395 self.algn = algn
396
397
398class BlipFillProperties(Serialisable):
399
400 tagname = "blipFill"
401
402 dpi = Integer(allow_none=True)
403 rotWithShape = Bool(allow_none=True)
404
405 blip = Typed(expected_type=Blip, allow_none=True)
406 srcRect = Typed(expected_type=RelativeRect, allow_none=True)
407 tile = Typed(expected_type=TileInfoProperties, allow_none=True)
408 stretch = Typed(expected_type=StretchInfoProperties, allow_none=True)
409
410 __elements__ = ("blip", "srcRect", "tile", "stretch")
411
412 def __init__(self,
413 dpi=None,
414 rotWithShape=None,
415 blip=None,
416 tile=None,
417 stretch=StretchInfoProperties(),
418 srcRect=None,
419 ):
420 self.dpi = dpi
421 self.rotWithShape = rotWithShape
422 self.blip = blip
423 self.tile = tile
424 self.stretch = stretch
425 self.srcRect = srcRect