Spaces:
Running
Running
File size: 4,386 Bytes
d3325ee 9617a9b d3325ee 9617a9b d3325ee 9617a9b d3325ee 9617a9b d3325ee 9617a9b d3325ee |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
from fastapi import APIRouter, Query, HTTPException
from fastapi.responses import StreamingResponse
from PIL import Image, ImageDraw
from io import BytesIO
import requests
router = APIRouter()
def download_image_from_url(url: str) -> Image.Image:
headers = {
"User-Agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/115.0.0.0 Safari/537.36"
)
}
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
return Image.open(BytesIO(response.content)).convert("RGBA")
except Exception as e:
raise HTTPException(status_code=400, detail=f"Erro ao baixar imagem: {url} ({str(e)})")
def resize_and_crop_to_fill(img: Image.Image, target_width: int, target_height: int) -> Image.Image:
"""
Redimensiona e corta a imagem para preencher exatamente o espaço alvo (sempre centralizado).
Args:
img: Imagem PIL
target_width: Largura alvo
target_height: Altura alvo
"""
img_ratio = img.width / img.height
target_ratio = target_width / target_height
if img_ratio > target_ratio:
# Imagem é mais larga proporcionalmente - redimensionar baseado na altura
scale_height = target_height
scale_width = int(scale_height * img_ratio)
else:
# Imagem é mais alta proporcionalmente - redimensionar baseado na largura
scale_width = target_width
scale_height = int(scale_width / img_ratio)
img_resized = img.resize((scale_width, scale_height), Image.LANCZOS)
# Centralizar o crop
left = (scale_width - target_width) // 2
top = (scale_height - target_height) // 2
right = left + target_width
bottom = top + target_height
return img_resized.crop((left, top, right, bottom))
def add_rounded_corners(img: Image.Image, radius: int) -> Image.Image:
"""
Adiciona cantos arredondados à imagem.
Args:
img: Imagem PIL
radius: Raio do arredondamento em pixels
Returns:
Imagem com cantos arredondados
"""
# Criar máscara para os cantos arredondados
mask = Image.new("L", img.size, 0)
draw = ImageDraw.Draw(mask)
# Desenhar retângulo com cantos arredondados
draw.rounded_rectangle(
[(0, 0), (img.width, img.height)],
radius=radius,
fill=255
)
# Aplicar máscara à imagem
output = Image.new("RGBA", img.size, (0, 0, 0, 0))
output.paste(img, (0, 0))
output.putalpha(mask)
return output
def create_cover_image(image_url: str) -> BytesIO:
"""
Cria uma capa para reels do Instagram.
- Fundo preto
- Largura: 1080, Altura: 1920
- Imagem renderizada em Largura: 1080, Altura: 1440, X: 0, Y: 240
- Cantos arredondados com raio de 145px
"""
# Dimensões do canvas
canvas_width = 1080
canvas_height = 1920
# Criar canvas com fundo preto
canvas = Image.new("RGBA", (canvas_width, canvas_height), color=(0, 0, 0, 255))
# Baixar e processar imagem
img = download_image_from_url(image_url)
# Redimensionar e cortar imagem para as dimensões especificadas
# Largura: 1080, Altura: 1440
img_width = 1080
img_height = 1440
filled_img = resize_and_crop_to_fill(img, img_width, img_height)
# Aplicar arredondamento de 145px nos cantos
rounded_img = add_rounded_corners(filled_img, 145)
# Colar imagem na posição X: 0, Y: 240
canvas.paste(rounded_img, (0, 240), rounded_img)
# Converter para bytes
buffer = BytesIO()
canvas.convert("RGB").save(buffer, format="PNG")
buffer.seek(0)
return buffer
@router.get("/cover/reel")
def get_reel_cover(
image_url: str = Query(..., description="URL da imagem a ser renderizada")
):
"""
Endpoint para gerar capa para reels do Instagram.
Args:
image_url: URL da imagem a ser renderizada (obrigatório)
Returns:
Imagem PNG com fundo preto e imagem renderizada nas posições especificadas
"""
try:
buffer = create_cover_image(image_url)
return StreamingResponse(buffer, media_type="image/png")
except Exception as e:
raise HTTPException(status_code=500, detail=f"Erro ao gerar imagem: {str(e)}") |