@@ -6,6 +6,7 @@ class AssetType(str, Enum):
66 video = "video"
77 image = "image"
88 audio = "audio"
9+ text = "text"
910
1011
1112class Fit (str , Enum ):
@@ -39,6 +40,36 @@ class Filter(str, Enum):
3940 negative = "negative"
4041
4142
43+ class TextAlignment (str , Enum ):
44+ """Place the text in one of nine predefined positions of the background."""
45+
46+ top = "top"
47+ top_right = "top_right"
48+ right = "right"
49+ bottom_right = "bottom_right"
50+ bottom = "bottom"
51+ bottom_left = "bottom_left"
52+ left = "left"
53+ top_left = "top_left"
54+ center = "center"
55+
56+
57+ class HorizontalAlignment (str , Enum ):
58+ """Horizontal text alignment options."""
59+
60+ left = "left"
61+ center = "center"
62+ right = "right"
63+
64+
65+ class VerticalAlignment (str , Enum ):
66+ """Vertical text alignment options."""
67+
68+ top = "top"
69+ center = "center"
70+ bottom = "bottom"
71+
72+
4273class Offset :
4374 def __init__ (self , x : float = 0 , y : float = 0 ):
4475 self .x = x
@@ -157,7 +188,197 @@ def to_json(self):
157188 }
158189
159190
160- AnyAsset = Union [VideoAsset , ImageAsset , AudioAsset ]
191+ class Font :
192+ """Font styling properties for text assets."""
193+
194+ def __init__ (
195+ self ,
196+ family : str = "Clear Sans" ,
197+ size : int = 48 ,
198+ color : str = "#FFFFFF" ,
199+ opacity : float = 1.0 ,
200+ weight : Optional [int ] = None ,
201+ ):
202+ if size < 1 :
203+ raise ValueError ("size must be at least 1" )
204+ if not (0.0 <= opacity <= 1.0 ):
205+ raise ValueError ("opacity must be between 0.0 and 1.0" )
206+ if weight is not None and not (100 <= weight <= 900 ):
207+ raise ValueError ("weight must be between 100 and 900" )
208+
209+ self .family = family
210+ self .size = size
211+ self .color = color
212+ self .opacity = opacity
213+ self .weight = weight
214+
215+ def to_json (self ):
216+ data = {
217+ "family" : self .family ,
218+ "size" : self .size ,
219+ "color" : self .color ,
220+ "opacity" : self .opacity ,
221+ }
222+ if self .weight is not None :
223+ data ["weight" ] = self .weight
224+ return data
225+
226+
227+ class Border :
228+ """Text border properties."""
229+
230+ def __init__ (self , color : str = "#000000" , width : float = 0.0 ):
231+ if width < 0.0 :
232+ raise ValueError ("width must be non-negative" )
233+ self .color = color
234+ self .width = width
235+
236+ def to_json (self ):
237+ return {
238+ "color" : self .color ,
239+ "width" : self .width ,
240+ }
241+
242+
243+ class Shadow :
244+ """Text shadow properties."""
245+
246+ def __init__ (self , color : str = "#000000" , x : float = 0.0 , y : float = 0.0 ):
247+ if x < 0.0 :
248+ raise ValueError ("x must be non-negative" )
249+ if y < 0.0 :
250+ raise ValueError ("y must be non-negative" )
251+ self .color = color
252+ self .x = x
253+ self .y = y
254+
255+ def to_json (self ):
256+ return {
257+ "color" : self .color ,
258+ "x" : self .x ,
259+ "y" : self .y ,
260+ }
261+
262+
263+ class Background :
264+ """Text background styling properties."""
265+
266+ def __init__ (
267+ self ,
268+ width : float = 0.0 ,
269+ height : float = 0.0 ,
270+ color : str = "#000000" ,
271+ border_width : float = 0.0 ,
272+ opacity : float = 1.0 ,
273+ text_alignment : TextAlignment = TextAlignment .center ,
274+ ):
275+ if width < 0.0 :
276+ raise ValueError ("width must be non-negative" )
277+ if height < 0.0 :
278+ raise ValueError ("height must be non-negative" )
279+ if border_width < 0.0 :
280+ raise ValueError ("border_width must be non-negative" )
281+ if not (0.0 <= opacity <= 1.0 ):
282+ raise ValueError ("opacity must be between 0.0 and 1.0" )
283+
284+ self .width = width
285+ self .height = height
286+ self .color = color
287+ self .border_width = border_width
288+ self .opacity = opacity
289+ self .text_alignment = text_alignment
290+
291+ def to_json (self ):
292+ return {
293+ "width" : self .width ,
294+ "height" : self .height ,
295+ "color" : self .color ,
296+ "border_width" : self .border_width ,
297+ "opacity" : self .opacity ,
298+ "text_alignment" : self .text_alignment .value ,
299+ }
300+
301+
302+ class Alignment :
303+ """Text alignment properties."""
304+
305+ def __init__ (
306+ self ,
307+ horizontal : HorizontalAlignment = HorizontalAlignment .center ,
308+ vertical : VerticalAlignment = VerticalAlignment .center ,
309+ ):
310+ self .horizontal = horizontal
311+ self .vertical = vertical
312+
313+ def to_json (self ):
314+ return {
315+ "horizontal" : self .horizontal .value ,
316+ "vertical" : self .vertical .value ,
317+ }
318+
319+
320+ class TextAsset (BaseAsset ):
321+ """The TextAsset is used to create text sequences from text strings with full control over the text styling and positioning."""
322+
323+ type = AssetType .text
324+
325+ def __init__ (
326+ self ,
327+ text : str ,
328+ font : Optional [Font ] = None ,
329+ border : Optional [Border ] = None ,
330+ shadow : Optional [Shadow ] = None ,
331+ background : Optional [Background ] = None ,
332+ alignment : Optional [Alignment ] = None ,
333+ tabsize : int = 4 ,
334+ line_spacing : float = 0 ,
335+ width : Optional [int ] = None ,
336+ height : Optional [int ] = None ,
337+ ):
338+ if tabsize < 1 :
339+ raise ValueError ("tabsize must be at least 1" )
340+ if line_spacing < 0.0 :
341+ raise ValueError ("line_spacing must be non-negative" )
342+ if width is not None and width < 1 :
343+ raise ValueError ("width must be at least 1" )
344+ if height is not None and height < 1 :
345+ raise ValueError ("height must be at least 1" )
346+
347+ self .text = text
348+ self .font = font if font is not None else Font ()
349+ self .border = border
350+ self .shadow = shadow
351+ self .background = background
352+ self .alignment = alignment if alignment is not None else Alignment ()
353+ self .tabsize = tabsize
354+ self .line_spacing = line_spacing
355+ self .width = width
356+ self .height = height
357+
358+ def to_json (self ):
359+ data = {
360+ "type" : self .type ,
361+ "text" : self .text ,
362+ "font" : self .font .to_json (),
363+ "alignment" : self .alignment .to_json (),
364+ "tabsize" : self .tabsize ,
365+ "line_spacing" : self .line_spacing ,
366+ }
367+ if self .border :
368+ data ["border" ] = self .border .to_json ()
369+ if self .shadow :
370+ data ["shadow" ] = self .shadow .to_json ()
371+ if self .background :
372+ data ["background" ] = self .background .to_json ()
373+ if self .width is not None :
374+ data ["width" ] = self .width
375+ if self .height is not None :
376+ data ["height" ] = self .height
377+
378+ return data
379+
380+
381+ AnyAsset = Union [VideoAsset , ImageAsset , AudioAsset , TextAsset ]
161382
162383
163384class Clip :
0 commit comments