habulaj commited on
Commit
4f52d2a
·
verified ·
1 Parent(s): c4ab957

Update routers/video.py

Browse files
Files changed (1) hide show
  1. routers/video.py +23 -159
routers/video.py CHANGED
@@ -1,179 +1,43 @@
1
- from fastapi import APIRouter, HTTPException, Query
2
  from fastapi.responses import StreamingResponse
3
- from PIL import Image, ImageDraw, ImageFont
4
  from io import BytesIO
5
- from typing import Optional
6
 
7
  router = APIRouter()
8
 
9
-
10
- def render_headline_text(draw: ImageDraw.Draw, text: str, x: int, y: int, max_width: int, max_lines: int = 4) -> None:
11
- """
12
- Renderiza headline no estilo The New York Times com fundo branco.
13
-
14
- Args:
15
- draw: Objeto ImageDraw para desenhar
16
- text: Texto do headline
17
- x: Posição X (esquerda)
18
- y: Posição Y (base - texto alinhado de baixo para cima)
19
- max_width: Largura máxima do texto
20
- max_lines: Número máximo de linhas (padrão: 2)
21
- """
22
- if not text.strip():
23
- return
24
-
25
- # Carregar fonte Cheltenham Normal 700
26
- try:
27
- font_path = "fonts/cheltenham-normal-700.ttf"
28
- except (OSError, IOError):
29
- font_path = None
30
-
31
- # Dividir texto em palavras
32
- words = text.split()
33
- if not words:
34
- return
35
-
36
- # Função para quebrar texto em linhas
37
- def wrap_text(text, font_size, max_width):
38
- if font_path:
39
- try:
40
- test_font = ImageFont.truetype(font_path, font_size)
41
- except (OSError, IOError):
42
- test_font = ImageFont.load_default()
43
- else:
44
- test_font = ImageFont.load_default()
45
-
46
- lines = []
47
- current_line = []
48
-
49
- for word in words:
50
- test_line = " ".join(current_line + [word])
51
- bbox = draw.textbbox((0, 0), test_line, font=test_font)
52
- line_width = bbox[2] - bbox[0]
53
-
54
- if line_width <= max_width:
55
- current_line.append(word)
56
- else:
57
- if current_line:
58
- lines.append(" ".join(current_line))
59
- current_line = [word]
60
- else:
61
- # Palavra muito longa, adiciona mesmo assim
62
- lines.append(word)
63
-
64
- if current_line:
65
- lines.append(" ".join(current_line))
66
-
67
- return lines
68
-
69
- # Encontrar o tamanho de fonte ideal
70
- font_size = 60 # Tamanho inicial para headline
71
- min_font_size = 20 # Tamanho mínimo adequado
72
-
73
- # Tentar diferentes tamanhos de fonte até encontrar um que caiba em max_lines
74
- while font_size >= min_font_size:
75
- lines = wrap_text(text, font_size, max_width)
76
-
77
- # Se o texto cabe em max_lines ou menos, usar este tamanho
78
- if len(lines) <= max_lines:
79
- break
80
-
81
- # Reduzir o tamanho da fonte
82
- font_size -= 2 # Redução menor para melhor precisão
83
-
84
- # Garantir que não seja menor que o tamanho mínimo
85
- font_size = max(font_size, min_font_size)
86
-
87
- # Carregar fonte final
88
- if font_path:
89
- try:
90
- final_font = ImageFont.truetype(font_path, font_size)
91
- except (OSError, IOError):
92
- final_font = ImageFont.load_default()
93
- else:
94
- final_font = ImageFont.load_default()
95
-
96
- # Quebrar texto final
97
- lines = wrap_text(text, font_size, max_width)
98
-
99
- # Se ainda não couber em max_lines, forçar quebra nas primeiras max_lines
100
- if len(lines) > max_lines:
101
- # Combinar as linhas restantes na última linha permitida
102
- combined_text = " ".join(lines[:max_lines-1] + [" ".join(lines[max_lines-1:])])
103
- lines = wrap_text(combined_text, font_size, max_width)
104
- lines = lines[:max_lines] # Garantir que não exceda max_lines
105
-
106
- # Calcular altura total do texto para criar fundo branco
107
- line_heights = []
108
- line_widths = []
109
- for line in lines:
110
- bbox = draw.textbbox((0, 0), line, font=final_font)
111
- line_height = bbox[3] - bbox[1]
112
- line_width = bbox[2] - bbox[0]
113
- line_heights.append(line_height)
114
- line_widths.append(line_width)
115
-
116
- # Calcular dimensões do fundo branco
117
- total_text_height = sum(int(h * 1.20) for h in line_heights) # Com line height de 120%
118
- padding = 20 # Padding interno para headline destacado
119
-
120
- # Desenhar fundo branco em tiras (uma para cada linha)
121
- current_y = y
122
- for i, line in enumerate(reversed(lines)):
123
- line_height = line_heights[len(lines) - 1 - i]
124
- line_width = line_widths[len(lines) - 1 - i]
125
-
126
- # Calcular posição da tira para esta linha
127
- strip_y = current_y - int(line_height * 1.20) - padding
128
- strip_height = int(line_height * 1.20) + (padding * 2)
129
- strip_width = line_width + (padding * 2)
130
-
131
- # Desenhar tira branca para esta linha
132
- strip_x = x - padding
133
- draw.rectangle([strip_x, strip_y, strip_x + strip_width, strip_y + strip_height], fill=(255, 255, 255, 255))
134
-
135
- # Atualizar posição para próxima linha
136
- current_y -= int(line_height * 1.20)
137
-
138
- # Desenhar texto preto
139
- current_y = y
140
- for i, line in enumerate(reversed(lines)):
141
- line_height = line_heights[len(lines) - 1 - i]
142
- # Aplicar line height de 120%
143
- current_y -= int(line_height * 1.20)
144
- draw.text((x, current_y), line, fill=(0, 0, 0, 255), font=final_font)
145
-
146
  @router.get("/cover/video")
147
- def get_video_cover(
148
- headline: Optional[str] = Query(None, description="Headline a ser exibido no canto inferior esquerdo")
149
- ):
150
  """
151
- Endpoint que retorna uma imagem transparente com headline no estilo The New York Times.
152
- Dimensões: 1080x1920 (para sobreposição em vídeo).
153
  """
154
  try:
 
 
 
155
  # Dimensões especificadas: largura 1080, altura 1920
156
  width, height = 1080, 1920
157
 
158
- # Criar imagem transparente
159
- canvas = Image.new("RGBA", (width, height), color=(0, 0, 0, 0))
 
 
 
 
 
 
 
160
 
161
- # Adicionar headline se fornecido
162
- if headline and headline.strip():
163
- draw = ImageDraw.Draw(canvas)
164
- # Posição no canto inferior esquerdo com margem maior
165
- headline_x = 80 # Margem esquerda maior
166
- headline_y = height - 200 # Margem inferior maior (não tão embaixo)
167
- max_width = 780 # Largura máxima do background
168
-
169
- render_headline_text(draw, headline, x=headline_x, y=headline_y, max_width=max_width, max_lines=4)
170
 
171
- # Converter para BytesIO (mantendo transparência)
172
  buffer = BytesIO()
173
- canvas.save(buffer, format="PNG")
174
  buffer.seek(0)
175
 
176
- return StreamingResponse(buffer, media_type="image/png")
177
 
178
  except Exception as e:
179
  raise HTTPException(status_code=500, detail=f"Erro ao gerar imagem: {str(e)}")
 
1
+ from fastapi import APIRouter, HTTPException
2
  from fastapi.responses import StreamingResponse
3
+ from PIL import Image
4
  from io import BytesIO
5
+ import requests
6
 
7
  router = APIRouter()
8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  @router.get("/cover/video")
10
+ def get_video_cover():
 
 
11
  """
12
+ Endpoint que retorna uma imagem de fundo com dimensões 1080x1920.
 
13
  """
14
  try:
15
+ # URL da imagem fornecida
16
+ image_url = "https://3120b81107781652e8544d604cd0343d.cdn.bubble.io/f1759250885668x201722051951041000/caption.jpg"
17
+
18
  # Dimensões especificadas: largura 1080, altura 1920
19
  width, height = 1080, 1920
20
 
21
+ # Baixar a imagem da URL
22
+ response = requests.get(image_url)
23
+ response.raise_for_status()
24
+
25
+ # Abrir a imagem
26
+ background_image = Image.open(BytesIO(response.content))
27
+
28
+ # Redimensionar para as dimensões especificadas
29
+ background_image = background_image.resize((width, height), Image.Resampling.LANCZOS)
30
 
31
+ # Converter para RGB se necessário
32
+ if background_image.mode != 'RGB':
33
+ background_image = background_image.convert('RGB')
 
 
 
 
 
 
34
 
35
+ # Converter para BytesIO
36
  buffer = BytesIO()
37
+ background_image.save(buffer, format="JPEG", quality=95)
38
  buffer.seek(0)
39
 
40
+ return StreamingResponse(buffer, media_type="image/jpeg")
41
 
42
  except Exception as e:
43
  raise HTTPException(status_code=500, detail=f"Erro ao gerar imagem: {str(e)}")