Text API

Advanced text rendering, typography, and Unicode support.

Font Management

Loading Fonts

// Load font from file
dc.LoadFontFace("fonts/arial.ttf", 24)

// Load font from bytes
fontData, err := ioutil.ReadFile("fonts/custom.ttf")
if err == nil {
    dc.LoadFontFaceFromBytes(fontData, 24)
}

// Load system fonts (platform-specific)
dc.LoadSystemFont("Arial", 24)
dc.LoadSystemFont("Times New Roman", 18)

// Set font size for existing font
dc.SetFontSize(32)

Font Properties

// Get font metrics
metrics := dc.GetFontMetrics()
fmt.Printf("Ascent: %f\n", metrics.Ascent)
fmt.Printf("Descent: %f\n", metrics.Descent)
fmt.Printf("Height: %f\n", metrics.Height)

// Check if font supports character
supported := dc.FontSupportsChar('€')
fmt.Printf("Euro symbol supported: %v\n", supported)

// Get available font families
families := advancegg.GetSystemFontFamilies()
for _, family := range families {
    fmt.Println("Available font:", family)
}

Basic Text Rendering

Simple Text Drawing

// Draw text at position
dc.DrawString("Hello World", 100, 100)

// Draw text with anchor positioning
dc.DrawStringAnchored("Centered Text", 400, 300, 0.5, 0.5)
// ax, ay: 0=left/top, 0.5=center, 1=right/bottom

// Draw text with rotation
dc.Push()
dc.Translate(200, 200)
dc.Rotate(math.Pi / 4) // 45 degrees
dc.DrawString("Rotated Text", 0, 0)
dc.Pop()

Text Measurement

// Measure text dimensions
width, height := dc.MeasureString("Sample Text")
fmt.Printf("Text size: %fx%f\n", width, height)

// Get text bounds (more detailed)
bounds := dc.GetStringBounds("Sample Text")
fmt.Printf("Bounds: %v\n", bounds)

// Measure multiline text
lines := []string{"Line 1", "Line 2", "Line 3"}
totalHeight := dc.MeasureMultilineString(lines, 1.2) // 1.2 = line spacing

Advanced Text Layout

Word Wrapping

// Wrap text to fit width
text := "This is a long text that needs to be wrapped to fit within a specific width."
lines := dc.WordWrap(text, 300) // 300 pixels wide

// Draw wrapped text
lineHeight := 1.2
for i, line := range lines {
    y := 100 + float64(i)*dc.FontHeight()*lineHeight
    dc.DrawString(line, 50, y)
}

// Advanced word wrapping with alignment
dc.DrawStringWrapped(text, 50, 100, 0, 0, 300, lineHeight, advancegg.AlignLeft)
dc.DrawStringWrapped(text, 50, 200, 0, 0, 300, lineHeight, advancegg.AlignCenter)
dc.DrawStringWrapped(text, 50, 300, 0, 0, 300, lineHeight, advancegg.AlignRight)
dc.DrawStringWrapped(text, 50, 400, 0, 0, 300, lineHeight, advancegg.AlignJustify)

Text Alignment

// Text alignment constants
const (
    AlignLeft    = advancegg.AlignLeft
    AlignCenter  = advancegg.AlignCenter
    AlignRight   = advancegg.AlignRight
    AlignJustify = advancegg.AlignJustify
)

// Draw aligned text in a box
boxX, boxY := 100.0, 100.0
boxWidth, boxHeight := 300.0, 200.0

// Draw box outline
dc.SetRGB(0.8, 0.8, 0.8)
dc.DrawRectangle(boxX, boxY, boxWidth, boxHeight)
dc.Stroke()

// Draw text with different alignments
dc.SetRGB(0, 0, 0)
dc.DrawStringInBox("Left aligned text", boxX, boxY, boxWidth, boxHeight, AlignLeft)
dc.DrawStringInBox("Center aligned text", boxX, boxY+50, boxWidth, boxHeight, AlignCenter)
dc.DrawStringInBox("Right aligned text", boxX, boxY+100, boxWidth, boxHeight, AlignRight)

Unicode and International Text

Unicode Support

// Unicode text rendering
dc.DrawString("Hello 世界", 100, 100)           // Chinese
dc.DrawString("مرحبا بالعالم", 100, 130)        // Arabic
dc.DrawString("Здравствуй мир", 100, 160)      // Russian
dc.DrawString("नमस्ते दुनिया", 100, 190)         // Hindi
dc.DrawString("こんにちは世界", 100, 220)          // Japanese

// Complex script shaping (automatic)
dc.EnableTextShaping(true) // Enable for complex scripts
dc.DrawString("مرحبا بالعالم", 100, 250) // Properly shaped Arabic

Emoji Rendering

// Color emoji support
dc.DrawString("Hello 👋 World 🌍", 100, 100)
dc.DrawString("🎨 Graphics 📊 Charts 🎮 Games", 100, 130)

// Emoji with fallback
dc.SetEmojiFont("fonts/NotoColorEmoji.ttf")
dc.DrawString("Emoji: 😀 🎉 🚀 ⭐ 💖", 100, 160)

// Check emoji support
if dc.SupportsEmoji() {
    dc.DrawString("Emoji supported! 🎉", 100, 190)
} else {
    dc.DrawString("Emoji not supported", 100, 190)
}

Text Direction

// Set text direction
dc.SetTextDirection(advancegg.TextDirectionLTR) // Left-to-right (default)
dc.SetTextDirection(advancegg.TextDirectionRTL) // Right-to-left
dc.SetTextDirection(advancegg.TextDirectionTTB) // Top-to-bottom

// Bidirectional text (automatic detection)
dc.EnableBidirectionalText(true)
dc.DrawString("English النص العربي English", 100, 100)

Text Effects

Text Shadows

// Simple shadow
dc.SetTextShadow(2, 2, 0, color.RGBA{0, 0, 0, 128})
dc.SetRGB(1, 1, 1)
dc.DrawString("Text with Shadow", 100, 100)

// Blur shadow
dc.SetTextShadow(3, 3, 5, color.RGBA{0, 0, 0, 100})
dc.DrawString("Blurred Shadow", 100, 150)

// Multiple shadows
shadows := []advancegg.TextShadow{
    {OffsetX: 1, OffsetY: 1, Blur: 0, Color: color.RGBA{255, 0, 0, 128}},
    {OffsetX: -1, OffsetY: -1, Blur: 0, Color: color.RGBA{0, 0, 255, 128}},
}
dc.SetTextShadows(shadows)
dc.DrawString("Multiple Shadows", 100, 200)

// Clear shadows
dc.ClearTextShadow()

Text Outlines

// Text with outline
dc.SetTextOutline(2, color.RGBA{0, 0, 0, 255})
dc.SetRGB(1, 1, 1)
dc.DrawString("Outlined Text", 100, 100)

// Gradient outline
outlineGradient := advancegg.NewLinearGradient(0, 0, 100, 0)
outlineGradient.AddColorStop(0, color.RGBA{255, 0, 0, 255})
outlineGradient.AddColorStop(1, color.RGBA{0, 0, 255, 255})
dc.SetTextOutlineGradient(3, outlineGradient)
dc.DrawString("Gradient Outline", 100, 150)

Text Gradients

// Gradient text fill
gradient := advancegg.NewLinearGradient(0, 0, 200, 0)
gradient.AddColorStop(0, color.RGBA{255, 0, 0, 255})
gradient.AddColorStop(0.5, color.RGBA{255, 255, 0, 255})
gradient.AddColorStop(1, color.RGBA{0, 255, 0, 255})

dc.SetTextFillGradient(gradient)
dc.DrawString("Gradient Text", 100, 100)

// Radial gradient text
radialGradient := advancegg.NewRadialGradient(100, 50, 0, 100, 50, 50)
radialGradient.AddColorStop(0, color.RGBA{255, 255, 255, 255})
radialGradient.AddColorStop(1, color.RGBA{0, 0, 0, 255})

dc.SetTextFillGradient(radialGradient)
dc.DrawString("Radial Gradient", 100, 150)

Text on Path

Text on Circle

// Text following a circle
advancegg.DrawTextOnCircle(dc, "Circular Text Example", 400, 300, 150)

// Text on arc
advancegg.DrawTextOnArc(dc, "Arc Text", 400, 300, 150, 0, math.Pi)

// Upside-down circular text
advancegg.DrawTextOnCircle(dc, "Upside Down Text", 400, 300, 120, true)

Text on Custom Path

// Create a custom path
path := advancegg.NewPath2D()
path.MoveTo(100, 200)
path.CubicTo(200, 100, 400, 100, 500, 200)
path.CubicTo(600, 300, 400, 300, 300, 200)

// Draw text along the path
advancegg.DrawTextOnPath(dc, "Text following custom path", path)

// Text with offset along path
advancegg.DrawTextOnPathWithOffset(dc, "Offset text", path, 50) // 50 pixels offset

Text on Wave

// Text following a sine wave
advancegg.DrawTextOnWave(dc, "Wavy Text Example", 100, 200, 400, 30, 3)
// Parameters: text, startX, startY, width, amplitude, frequency

// Text on custom wave function
waveFunc := func(x float64) float64 {
    return 30 * math.Sin(x*0.02) + 20 * math.Cos(x*0.03)
}
advancegg.DrawTextOnCustomWave(dc, "Custom Wave", 100, 300, 400, waveFunc)

Advanced Typography

Kerning and Spacing

// Enable/disable kerning
dc.SetKerning(true)  // Enable kerning (default)
dc.SetKerning(false) // Disable kerning

// Letter spacing
dc.SetLetterSpacing(2.0) // 2 pixels between letters
dc.DrawString("Spaced Text", 100, 100)

// Word spacing
dc.SetWordSpacing(10.0) // 10 pixels between words
dc.DrawString("Word Spaced Text", 100, 150)

// Line height
dc.SetLineHeight(1.5) // 1.5x font size
multilineText := "Line 1\nLine 2\nLine 3"
dc.DrawString(multilineText, 100, 200)

Text Decoration

// Underline
dc.SetTextDecoration(advancegg.TextDecorationUnderline)
dc.DrawString("Underlined Text", 100, 100)

// Strikethrough
dc.SetTextDecoration(advancegg.TextDecorationStrikethrough)
dc.DrawString("Strikethrough Text", 100, 150)

// Overline
dc.SetTextDecoration(advancegg.TextDecorationOverline)
dc.DrawString("Overlined Text", 100, 200)

// Multiple decorations
dc.SetTextDecoration(advancegg.TextDecorationUnderline | advancegg.TextDecorationStrikethrough)
dc.DrawString("Multiple Decorations", 100, 250)

// Custom decoration style
dc.SetUnderlineStyle(advancegg.UnderlineStyleDotted, 2.0, color.RGBA{255, 0, 0, 255})
dc.DrawString("Custom Underline", 100, 300)

Font Variants

// Small caps
dc.SetFontVariant(advancegg.FontVariantSmallCaps)
dc.DrawString("Small Caps Text", 100, 100)

// Subscript and superscript
dc.SetFontVariant(advancegg.FontVariantSubscript)
dc.DrawString("H₂O", 100, 150)

dc.SetFontVariant(advancegg.FontVariantSuperscript)
dc.DrawString("E=mc²", 150, 150)

// Reset to normal
dc.SetFontVariant(advancegg.FontVariantNormal)

Complete Examples

Typography Showcase

package main

import (
    "image/color"
    "math"
    "github.com/GrandpaEJ/advancegg"
)

func main() {
    dc := advancegg.NewContext(1200, 800)
    
    // Background
    dc.SetRGB(0.95, 0.95, 0.98)
    dc.Clear()
    
    // Title with gradient
    dc.LoadFontFace("fonts/arial-bold.ttf", 48)
    gradient := advancegg.NewLinearGradient(0, 0, 400, 0)
    gradient.AddColorStop(0, color.RGBA{255, 0, 100, 255})
    gradient.AddColorStop(1, color.RGBA{100, 0, 255, 255})
    dc.SetTextFillGradient(gradient)
    dc.DrawStringAnchored("Typography Showcase", 600, 80, 0.5, 0.5)
    
    // Subtitle with shadow
    dc.LoadFontFace("fonts/arial.ttf", 24)
    dc.SetTextShadow(2, 2, 3, color.RGBA{0, 0, 0, 100})
    dc.SetRGB(0.2, 0.2, 0.4)
    dc.DrawStringAnchored("Advanced Text Rendering with AdvanceGG", 600, 130, 0.5, 0.5)
    dc.ClearTextShadow()
    
    // International text
    dc.LoadFontFace("fonts/noto-sans.ttf", 20)
    dc.SetRGB(0.1, 0.1, 0.2)
    
    texts := []struct {
        text string
        lang string
    }{
        {"Hello World", "English"},
        {"Bonjour le monde", "French"},
        {"Hola Mundo", "Spanish"},
        {"Hallo Welt", "German"},
        {"Ciao Mondo", "Italian"},
        {"Olá Mundo", "Portuguese"},
        {"Привет мир", "Russian"},
        {"你好世界", "Chinese"},
        {"こんにちは世界", "Japanese"},
        {"안녕하세요 세계", "Korean"},
    }
    
    for i, item := range texts {
        x := 100 + float64(i%5)*220
        y := 200 + float64(i/5)*40
        dc.DrawString(item.text, x, y)
        
        // Language label
        dc.LoadFontFace("fonts/arial.ttf", 12)
        dc.SetRGB(0.5, 0.5, 0.5)
        dc.DrawString(item.lang, x, y+20)
        dc.LoadFontFace("fonts/noto-sans.ttf", 20)
        dc.SetRGB(0.1, 0.1, 0.2)
    }
    
    // Text effects demonstration
    y := 350.0
    
    // Outlined text
    dc.LoadFontFace("fonts/arial-bold.ttf", 32)
    dc.SetTextOutline(3, color.RGBA{0, 0, 0, 255})
    dc.SetRGB(1, 1, 1)
    dc.DrawString("Outlined Text", 100, y)
    
    // Gradient text
    textGradient := advancegg.NewLinearGradient(0, 0, 200, 0)
    textGradient.AddColorStop(0, color.RGBA{255, 100, 0, 255})
    textGradient.AddColorStop(1, color.RGBA{255, 200, 0, 255})
    dc.SetTextFillGradient(textGradient)
    dc.ClearTextOutline()
    dc.DrawString("Gradient Text", 400, y)
    
    // Text on circle
    dc.SetRGB(0.2, 0.4, 0.8)
    dc.LoadFontFace("fonts/arial.ttf", 18)
    advancegg.DrawTextOnCircle(dc, "Text following a circular path around the center", 600, 550, 120)
    
    // Emoji text
    dc.LoadFontFace("fonts/noto-emoji.ttf", 24)
    dc.SetRGB(0.1, 0.1, 0.2)
    dc.DrawString("Emoji support: 🎨 📊 🎮 🚀 ⭐ 💖 🌍", 100, 650)
    
    // Word wrapped text
    dc.LoadFontFace("fonts/arial.ttf", 16)
    longText := "This is a demonstration of word wrapping functionality. The text will automatically wrap to fit within the specified width, maintaining proper spacing and alignment."
    dc.DrawStringWrapped(longText, 100, 700, 0, 0, 400, 1.3, advancegg.AlignJustify)
    
    dc.SavePNG("typography-showcase.png")
}