Chuyển đến nội dung chính

Lesson 11: AI Typography — Generate Text, Font Style & Placement

AI generates quotes, meme text, stylized typography for t-shirts. Font recommendation engine. Text rendering pipeline: style transfer for fonts, auto-placement on print area.

🧠 AI & ML — Lesson 10 Lesson 11: AI Typography — Generate Text, Font Style & Placement

AI in Action: Building an AI Platform for Fashion & Print-on-Demand

Part 3: AI Design Optimization & Editing

xdev.asia

Introduction

Typography is an important component in t-shirt design — quotes, meme text, brand names, stylized lettering. AI not only creates images but also has to generate beautiful text, with the right font style, and place it in the right position on the shirt.


1. Typography Challenges in AI

Why is text generation difficult?

Stable Diffusion (SDXL) + text:
❌ Chữ bị sai spelling ("COFEE" thay vì "COFFEE")
❌ Chữ bị méo, khó đọc
❌ Font không consistent
❌ Chữ bị mirror/reverse

Giải pháp: KHÔNG dùng Diffusion model để render text trực tiếp.
→ Dùng text rendering engine riêng + composite lên design.

2. Text Generation Pipeline

User Input
├── "Tạo áo với quote motivational"
│
├── LLM generate quote text
│   └── "HUSTLE HARDER"
│
├── Font recommendation engine
│   └── Bold sans-serif, uppercase
│
├── Text rendering (Pillow/Cairo)
│   └── High-res text image (transparent)
│
├── Style transfer (optional)
│   └── Neon glow, shadow, gradient
│
└── Composite onto design
    └── Auto-placement + position

3. AI Text Content Generator

class TextContentGenerator:
    """AI generate text content cho áo thun"""

    async def generate_text(
        self,
        category: str,
        style: str = "default",
        language: str = "en",
    ) -> list[str]:
        prompt = f"""
Generate 5 short text/quotes for a {style} style t-shirt.
Category: {category}
Language: {language}

Rules:
- Maximum 5 words per line
- Maximum 2 lines
- ALL CAPS preferred for impact
- Catchy, memorable, trendy
- No offensive content

Return as JSON array of strings.
"""
        response = await self.llm.chat.completions.create(
            model="gpt-4o-mini",
            messages=[{"role": "user", "content": prompt}],
            response_format={"type": "json_object"},
        )

        return json.loads(
            response.choices[0].message.content
        )["texts"]

4. Font Recommendation Engine

class FontRecommender:
    """Gợi ý font phù hợp theo style design"""

    FONT_STYLES = {
        "cyberpunk": [
            {"name": "Orbitron", "weight": "Bold", "case": "upper"},
            {"name": "Rajdhani", "weight": "SemiBold", "case": "upper"},
        ],
        "minimal": [
            {"name": "Montserrat", "weight": "Light", "case": "upper"},
            {"name": "Futura", "weight": "Medium", "case": "mixed"},
        ],
        "streetwear": [
            {"name": "Impact", "weight": "Regular", "case": "upper"},
            {"name": "Bebas Neue", "weight": "Regular", "case": "upper"},
        ],
        "vintage": [
            {"name": "Playfair Display", "weight": "Bold", "case": "mixed"},
            {"name": "Lora", "weight": "Regular", "case": "mixed"},
        ],
        "gaming": [
            {"name": "Press Start 2P", "weight": "Regular", "case": "upper"},
            {"name": "Audiowide", "weight": "Regular", "case": "upper"},
        ],
        "japanese": [
            {"name": "Noto Sans JP", "weight": "Black", "case": "mixed"},
            {"name": "M PLUS 1p", "weight": "Bold", "case": "mixed"},
        ],
    }

    def recommend(self, design_style: str) -> list[dict]:
        return self.FONT_STYLES.get(
            design_style, self.FONT_STYLES["minimal"]
        )

5. Text Rendering Engine

from PIL import Image, ImageDraw, ImageFont

class TextRenderer:
    """Render text thành image cho composite"""

    def render(
        self,
        text: str,
        font_name: str,
        font_size: int,
        color: str = "#FFFFFF",
        effects: list[str] | None = None,
    ) -> Image.Image:
        # Load font
        font = ImageFont.truetype(
            f"fonts/{font_name}.ttf", font_size
        )

        # Calculate text size
        bbox = font.getbbox(text)
        text_width = bbox[2] - bbox[0]
        text_height = bbox[3] - bbox[1]

        # Create canvas with padding
        padding = font_size // 4
        canvas = Image.new(
            "RGBA",
            (text_width + padding * 2, text_height + padding * 2),
            (0, 0, 0, 0)
        )

        draw = ImageDraw.Draw(canvas)
        draw.text(
            (padding, padding),
            text, font=font,
            fill=color,
        )

        # Apply effects
        if effects:
            for effect in effects:
                canvas = self._apply_effect(canvas, effect)

        return canvas

    def _apply_effect(
        self, img: Image.Image, effect: str
    ) -> Image.Image:
        if effect == "neon_glow":
            return self._neon_glow(img)
        elif effect == "drop_shadow":
            return self._drop_shadow(img)
        elif effect == "outline":
            return self._outline(img)
        elif effect == "gradient":
            return self._gradient_fill(img)
        return img

    def _neon_glow(self, img: Image.Image) -> Image.Image:
        """Hiệu ứng neon glow cho text"""
        from PIL import ImageFilter
        import numpy as np

        # Create glow layer
        glow = img.filter(ImageFilter.GaussianBlur(radius=10))
        glow = glow.filter(ImageFilter.GaussianBlur(radius=5))

        # Brighten glow
        glow_array = np.array(glow)
        glow_array[:, :, :3] = np.clip(
            glow_array[:, :, :3] * 1.5, 0, 255
        ).astype(np.uint8)
        glow = Image.fromarray(glow_array)

        # Composite: glow behind text
        result = Image.alpha_composite(glow, img)
        return result

6. Auto-Placement

class TextPlacer:
    """Tự động đặt text vào vị trí phù hợp trên design"""

    def auto_place(
        self,
        design: Image.Image,
        text_image: Image.Image,
        position: str = "auto",
    ) -> Image.Image:
        if position == "auto":
            position = self._find_best_position(
                design, text_image
            )

        positions = {
            "top_center": self._place_top_center,
            "bottom_center": self._place_bottom_center,
            "center": self._place_center,
            "arc_top": self._place_arc_top,
            "arc_bottom": self._place_arc_bottom,
        }

        placer = positions.get(position, self._place_center)
        return placer(design, text_image)

    def _find_best_position(
        self,
        design: Image.Image,
        text_image: Image.Image,
    ) -> str:
        """AI-detect vùng trống tốt nhất cho text"""
        # Phân tích content density theo vùng
        regions = self._analyze_regions(design)

        # Text đặt ở vùng ít content nhất
        least_dense = min(regions, key=lambda r: r["density"])
        return least_dense["position"]

Summary

AI Typography System:

  1. Text generation — LLM creates quotes, meme text, slogans
  2. Font recommendation — font suggestion according to design style
  3. Text rendering — Pillow/Cairo renders high quality text
  4. Effects — neon glow, shadow, outline, gradient
  5. Auto-placement — finds suitable empty areas on the design

The next article begins Part 4: AI Personalization — the AI system learns each user's aesthetic taste.