Coverage for lib/lottie/utils/fancy_text.py: 0%

103 statements  

« prev     ^ index     » next       coverage.py v7.2.2, created at 2023-03-20 16:17 +0100

1import re 

2 

3from .font import FontStyle 

4from ..nvector import NVector 

5from ..parsers.svg.importer import parse_color 

6from ..objects.shapes import Group, Fill 

7 

8 

9class FancyStyle: 

10 def __init__(self, font: FontStyle, color: NVector, font_size: float, offset: NVector, scale: NVector, rotation: float): 

11 self.font = font 

12 self.color = color.clone() 

13 self.font_size = font_size 

14 self.offset = offset.clone() 

15 self.scale = scale.clone() 

16 self.rotation = rotation 

17 

18 def clone(self): 

19 return FancyStyle(self.font, self.color, self.font_size, self.offset, self.scale, self.rotation) 

20 

21 def render(self, text, pos, start_x): 

22 pos += self.offset 

23 g = self.font.renderer.render(text, self.font_size, pos, True, start_x) 

24 g.add_shape(Fill(self.color)) 

25 if self.scale.x != 1 or self.scale.y != 1 or self.rotation != 0: 

26 center = g.bounding_box().center() 

27 g.transform.anchor_point.value = center 

28 g.transform.position.value += center 

29 g.transform.scale.value = self.scale * 100 

30 g.transform.rotation.value = self.rotation 

31 pos -= self.offset 

32 return g 

33 

34 

35class FancyTextRenderer: 

36 _regex = re.compile(r'\\([a-z0-9]+)(?:\{([^}]*)\})?') 

37 

38 def __init__(self, font: FontStyle, default_color: NVector, font_size: float): 

39 self.font = font 

40 self.font_size = font_size 

41 self.default_color = default_color 

42 self.groups = [] 

43 

44 @staticmethod 

45 def _int_arg(value, default=0): 

46 try: 

47 return float(value) 

48 except (ValueError, TypeError): 

49 return default 

50 

51 def render(self, text: str, pos: NVector = None): 

52 if pos is None: 

53 pos = NVector(0, 0) 

54 

55 line_start = pos.x 

56 default_style = FancyStyle(self.font, self.default_color, self.font_size, NVector(0, 0), NVector(1, 1), 0) 

57 style = default_style.clone() 

58 container = Group() 

59 last_pos = 0 

60 

61 for match in self._regex.finditer(text): 

62 prev_text = text[last_pos:match.start()] 

63 last_pos = match.end() 

64 if prev_text: 

65 container.insert_shape(0, style.render(prev_text, pos, line_start)) 

66 

67 style = style.clone() 

68 

69 command = match.group(1) 

70 arg = match.group(2) 

71 

72 if command == "color": 

73 if arg: 

74 style.color = parse_color(arg, self.default_color) 

75 else: 

76 style.color = self.default_color 

77 elif command == "huge": 

78 style.font_size = self.font_size * 2 

79 elif command == "large": 

80 style.font_size = self.font_size * 1.5 

81 elif command == "normal": 

82 style.font_size = self.font_size 

83 elif command == "small": 

84 style.font_size = self.font_size / 1.5 

85 elif command == "tiny": 

86 style.font_size = self.font_size / 2 

87 elif command == "super": 

88 style.offset.y -= self.font_size / 2 

89 elif command == "sub": 

90 style.offset.y += self.font_size / 2 

91 elif command == "center": 

92 style.offset.y = 0 

93 elif command == "clear": 

94 style = default_style.clone() 

95 elif command == "flip": 

96 style.scale.x *= -1 

97 elif command == "vflip": 

98 style.scale.y *= -1 

99 elif command == "r": 

100 pos.x = line_start 

101 elif command == "n": 

102 pos.x = line_start 

103 pos.y += self.font.line_height 

104 elif command == "hspace": 

105 pos.x += self._int_arg(arg) 

106 elif command == "rot": 

107 style.rotation = self._int_arg(arg) 

108 

109 # Eat space after no argument command 

110 if arg is None and len(text) > last_pos and text[last_pos] == ' ': 

111 last_pos += 1 

112 

113 last_text = text[last_pos:] 

114 if last_text: 

115 container.insert_shape(0, style.render(last_text, pos, line_start)) 

116 

117 if len(container.shapes) > 1: 

118 container.next_x = container.shapes[-2].next_x 

119 else: 

120 container.next_x = pos.x 

121 

122 return container 

123 

124 

125def render_fancy_text(text: str, font: FontStyle, default_color: NVector, font_size: float, pos: NVector = None): 

126 renderer = FancyTextRenderer(font, default_color, font_size) 

127 return renderer.render(text, pos)