ismdrobiul489 commited on
Commit
699416a
·
1 Parent(s): e93bb43

feat(fact_image): add Bengali text auto-detection and font support

Browse files
.gitattributes CHANGED
@@ -1 +1,2 @@
1
  *.mp3 filter=lfs diff=lfs merge=lfs -text
 
 
1
  *.mp3 filter=lfs diff=lfs merge=lfs -text
2
+ *.ttf filter=lfs diff=lfs merge=lfs -text
modules/fact_image/services/text_overlay.py CHANGED
@@ -5,6 +5,7 @@ Supports heading with background + fact text with shadow
5
  """
6
  import logging
7
  import re
 
8
  from pathlib import Path
9
  from typing import Tuple, Optional, Dict, Any
10
  from PIL import Image, ImageDraw, ImageFont
@@ -38,6 +39,9 @@ class TextOverlay:
38
  TEXT_TOP_PERCENT = 0.45 # Fact text starts at 45% from top
39
  GAP_HEADING_TEXT = 60 # Gap between heading and fact text (fallback)
40
 
 
 
 
41
  def __init__(self, font_path: Optional[str] = None):
42
  """
43
  Initialize text overlay service.
@@ -48,15 +52,33 @@ class TextOverlay:
48
  self.font_path = font_path
49
  self._font_cache = {}
50
 
51
- def _get_font(self, size: int, bold: bool = False) -> ImageFont.FreeTypeFont:
52
- """Get font at specified size (cached)"""
53
- cache_key = (size, bold)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  if cache_key not in self._font_cache:
55
  try:
56
- if self.font_path and Path(self.font_path).exists():
 
 
 
 
57
  self._font_cache[cache_key] = ImageFont.truetype(self.font_path, size)
58
  else:
59
- # Try common system fonts
60
  if bold:
61
  font_names = ['DejaVuSans-Bold.ttf', 'Arial-Bold.ttf', 'Roboto-Bold.ttf', 'FreeSansBold.ttf']
62
  else:
@@ -174,7 +196,12 @@ class TextOverlay:
174
  Returns:
175
  Path to output image
176
  """
177
- logger.info(f"Adding text overlay: heading='{heading}', text='{text[:30]}...'")
 
 
 
 
 
178
 
179
  # Load image
180
  img = Image.open(image_path).convert('RGBA')
@@ -218,9 +245,9 @@ class TextOverlay:
218
  else:
219
  text_font_size = 32 # Minimum for very long text
220
 
221
- # Get fonts with dynamic sizes (both bold)
222
- heading_font = self._get_font(heading_font_size, bold=True)
223
- text_font = self._get_font(text_font_size, bold=True)
224
 
225
  # Word wrap text with dynamic font to fit max_width
226
  words = text.split()
@@ -272,7 +299,8 @@ class TextOverlay:
272
 
273
  # Draw heading with background (UPPERCASE)
274
  if heading:
275
- heading_upper = heading.upper() # Convert to UPPERCASE
 
276
  # Get text bounding box - returns (left, top, right, bottom)
277
  heading_bbox = draw.textbbox((0, 0), heading_upper, font=heading_font)
278
  # The bbox includes font metrics offset
 
5
  """
6
  import logging
7
  import re
8
+ import unicodedata
9
  from pathlib import Path
10
  from typing import Tuple, Optional, Dict, Any
11
  from PIL import Image, ImageDraw, ImageFont
 
39
  TEXT_TOP_PERCENT = 0.45 # Fact text starts at 45% from top
40
  GAP_HEADING_TEXT = 60 # Gap between heading and fact text (fallback)
41
 
42
+ # Path to Bengali font (bundled in static/fonts/)
43
+ BENGALI_FONT = Path(__file__).parent.parent.parent.parent / "static" / "fonts" / "Bangla_Unicode.ttf"
44
+
45
  def __init__(self, font_path: Optional[str] = None):
46
  """
47
  Initialize text overlay service.
 
52
  self.font_path = font_path
53
  self._font_cache = {}
54
 
55
+ @staticmethod
56
+ def _has_bengali(text: str) -> bool:
57
+ """
58
+ Check if text contains any Bengali script characters.
59
+ Bengali Unicode range: U+0980 - U+09FF
60
+ Auto-detects — works for pure Bengali, pure English, or mixed.
61
+ """
62
+ if not text:
63
+ return False
64
+ for ch in text:
65
+ if '\u0980' <= ch <= '\u09FF':
66
+ return True
67
+ return False
68
+
69
+ def _get_font(self, size: int, bold: bool = False, bengali: bool = False) -> ImageFont.FreeTypeFont:
70
+ """Get font at specified size (cached). Uses Bengali font when bengali=True."""
71
+ cache_key = (size, bold, bengali)
72
  if cache_key not in self._font_cache:
73
  try:
74
+ # Bengali font path
75
+ if bengali and self.BENGALI_FONT.exists():
76
+ self._font_cache[cache_key] = ImageFont.truetype(str(self.BENGALI_FONT), size)
77
+ logger.debug(f"Loaded Bengali font at size {size}")
78
+ elif self.font_path and Path(self.font_path).exists():
79
  self._font_cache[cache_key] = ImageFont.truetype(self.font_path, size)
80
  else:
81
+ # Try common system fonts (Latin)
82
  if bold:
83
  font_names = ['DejaVuSans-Bold.ttf', 'Arial-Bold.ttf', 'Roboto-Bold.ttf', 'FreeSansBold.ttf']
84
  else:
 
196
  Returns:
197
  Path to output image
198
  """
199
+ # Detect Bengali INDEPENDENTLY for heading and text
200
+ # So any combination works: BN heading + EN text, EN heading + BN text, etc.
201
+ heading_is_bengali = self._has_bengali(heading or "")
202
+ text_is_bengali = self._has_bengali(text)
203
+
204
+ logger.info(f"Adding text overlay: heading='{heading}' (bn={heading_is_bengali}), text='{text[:30]}...' (bn={text_is_bengali})")
205
 
206
  # Load image
207
  img = Image.open(image_path).convert('RGBA')
 
245
  else:
246
  text_font_size = 32 # Minimum for very long text
247
 
248
+ # Get fonts each uses its OWN Bengali detection
249
+ heading_font = self._get_font(heading_font_size, bold=True, bengali=heading_is_bengali)
250
+ text_font = self._get_font(text_font_size, bold=True, bengali=text_is_bengali)
251
 
252
  # Word wrap text with dynamic font to fit max_width
253
  words = text.split()
 
299
 
300
  # Draw heading with background (UPPERCASE)
301
  if heading:
302
+ # Bengali has no uppercase — skip .upper() for Bengali text
303
+ heading_upper = heading if self._has_bengali(heading) else heading.upper()
304
  # Get text bounding box - returns (left, top, right, bottom)
305
  heading_bbox = draw.textbbox((0, 0), heading_upper, font=heading_font)
306
  # The bbox includes font metrics offset
static/fonts/Bangla_Italic.ttf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:245fa5d1b454f0fd63033f9d9893190edca4b82787fac569151b79326ca25ec7
3
+ size 116468
static/fonts/Bangla_Unicode.ttf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:33a515c00aff1bfd401614cc60df1f383bd6fd3733d0fcbaba1b63f4d69f8f71
3
+ size 112140