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

第 11 課:AI 排版 — 生成文字、字體樣式和位置

AI 為 T 卹產生引言、迷因文字、風格化排版。字體推薦引擎。文字渲染管道:字體樣式傳輸、列印區域自動放置。

🧠 人工智慧與機器學習 — 第 10 課 第 11 課:AI 排版 — 生成文本, 字體樣式和位置

人工智慧在行動:建構時尚和按需印刷的人工智慧平台

第 3 部分:AI 設計優化與編輯

亞洲開發網

簡介

版式是 T 卹設計的重要組成部分——引言、迷因文字、品牌名稱、風格化字體。人工智慧不僅可以創建圖像,還必須產生具有正確字體樣式的漂亮文本,並將其放置在襯衫上的正確位置。


1. 人工智慧中的版面挑戰

為什麼文字產生很困難?

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. 文字產生管道

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文字內容產生器

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.字體推薦引擎

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. 文字渲染引擎

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. 自動放置

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"]

總結

人工智慧排版系統:

  1. 文字產生 — LLM 建立引言、迷因文字、口號
  2. 字體推薦-根據設計風格的字體建議
  3. 文本渲染 — Pillow/Cairo 渲染高品質文本
  4. 效果 — 霓虹燈發光、陰影、輪廓、漸變
  5. 自動放置 — 在設計上找到合適的空白區域

下一篇文章開始第 4 部分:AI 個人化——AI 系統學習每個使用者的美感趣味。