Kevin McIntyre f1544ef49c
Some checks failed
CI / Test (Go 1.24.x, ubuntu-latest) (push) Successful in 1m53s
CI / Code Quality (push) Failing after 26s
CI / Security Scan (push) Failing after 11s
CI / Test Coverage (push) Successful in 1m13s
CI / Benchmarks (push) Failing after 10m22s
CI / Build CLI (push) Failing after 8s
Benchmarks / Run Benchmarks (push) Failing after 10m13s
Release / Test (push) Successful in 55s
Release / Build (amd64, darwin, ) (push) Failing after 12s
Release / Build (amd64, linux, ) (push) Failing after 6s
Release / Build (amd64, windows, .exe) (push) Failing after 12s
Release / Build (arm64, darwin, ) (push) Failing after 12s
Release / Build (arm64, linux, ) (push) Failing after 12s
Release / Release (push) Has been skipped
CI / Test (Go 1.24.x, macos-latest) (push) Has been cancelled
CI / Test (Go 1.24.x, windows-latest) (push) Has been cancelled
chore: update module path to gitea.dockr.co/kev/go-jdenticon
Move hosting from GitHub to private Gitea instance.
2026-02-10 10:07:57 -05:00

Go Jdenticon

CI Benchmarks GoDoc Go Report Card codecov License: Elastic-2.0

A high-performance, idiomatic Go library for generating Jdenticon identicons. This library provides a simple API for creating PNG and SVG avatars, is fully configurable, and includes a command-line tool for easy generation.

It produces identical SVG output to the original Jdenticon JavaScript library.

Sample identicons

Features

  • Simple API: Generate icons with just a few lines of code
  • PNG & SVG Support: Output to standard raster and vector formats
  • Highly Configurable: Adjust colors, saturation, padding, and more
  • Performance Optimized: Built-in LRU caching and efficient rendering
  • Concurrent Batch Processing: High-performance worker pool for bulk generation
  • CLI Included: Generate icons directly from your terminal
  • Comprehensive Error Handling: Structured error types with actionable messages
  • Identical SVG Output: Produces the same SVGs as the original JavaScript library
  • High-Quality PNG Output: Visually very close PNGs (different rendering engine; differences only noticeable in side-by-side comparison)

Quick Start

This will get you generating your first icon in under a minute.

1. Installation

Library:

go get -u github.com/ungluedlabs/go-jdenticon

Command-Line Tool (Optional):

go install github.com/ungluedlabs/go-jdenticon/cmd/jdenticon@latest

2. Basic Usage (Library)

Create a file main.go and add the following code:

package main

import (
	"context"
	"log"
	"os"

	"github.com/ungluedlabs/go-jdenticon/jdenticon"
)

func main() {
	// Generate an icon from a string value
	icon, err := jdenticon.Generate(context.Background(), "user@example.com", 200)
	if err != nil {
		log.Fatalf("Failed to create icon: %v", err)
	}

	// Save the icon as SVG
	svg, err := icon.ToSVG()
	if err != nil {
		log.Fatalf("Failed to generate SVG: %v", err)
	}

	if err := os.WriteFile("my-icon.svg", []byte(svg), 0644); err != nil {
		log.Fatalf("Failed to save SVG: %v", err)
	}

	// Save the icon as PNG
	png, err := icon.ToPNG()
	if err != nil {
		log.Fatalf("Failed to generate PNG: %v", err)
	}

	if err := os.WriteFile("my-icon.png", png, 0644); err != nil {
		log.Fatalf("Failed to save PNG: %v", err)
	}

	log.Println("Generated my-icon.svg and my-icon.png successfully!")
	// Note: SVG output is identical to JavaScript library
	// PNG output is visually very close but uses a different rendering engine
}

Run the code:

go run main.go

You will find my-icon.svg and my-icon.png files in the same directory.

Advanced Usage & Configuration

The library offers fine-grained control over the icon's appearance via the Config struct and functional options.

Customizing an Icon

Here's how to generate an icon with custom colors and settings:

package main

import (
	"context"
	"log"
	"os"

	"github.com/ungluedlabs/go-jdenticon/jdenticon"
)

func main() {
	// Create a custom configuration using functional options
	config, err := jdenticon.Configure(
		jdenticon.WithHueRestrictions([]float64{120, 180, 240}), // Greens, teals, blues only
		jdenticon.WithColorSaturation(0.7),                     // More vivid colors
		jdenticon.WithPadding(0.1),                             // 10% padding
		jdenticon.WithBackgroundColor("#f0f0f0"),               // Light gray background
	)
	if err != nil {
		log.Fatalf("Failed to create config: %v", err)
	}

	// Create a generator with the custom config and caching
	generator, err := jdenticon.NewGeneratorWithConfig(config, 1000)
	if err != nil {
		log.Fatalf("Failed to create generator: %v", err)
	}

	// Generate the icon
	icon, err := generator.Generate(context.Background(), "custom-identifier", 200)
	if err != nil {
		log.Fatalf("Failed to generate icon: %v", err)
	}

	// Save as SVG
	svg, err := icon.ToSVG()
	if err != nil {
		log.Fatalf("Failed to generate SVG: %v", err)
	}

	if err := os.WriteFile("custom-icon.svg", []byte(svg), 0644); err != nil {
		log.Fatalf("Failed to save SVG: %v", err)
	}

	log.Println("Generated custom-icon.svg successfully!")
}

Package-Level Functions

For simple use cases, you can use the package-level functions:

// Generate SVG directly
svg, err := jdenticon.ToSVG(context.Background(), "user@example.com", 200)
if err != nil {
	log.Fatal(err)
}

// Generate PNG directly
png, err := jdenticon.ToPNG(context.Background(), "user@example.com", 200)
if err != nil {
	log.Fatal(err)
}

// With custom configuration
config := jdenticon.Config{
	ColorSaturation: 0.8,
	Padding:         0.15,
}
generator, _ := jdenticon.NewGeneratorWithConfig(config, 100)
icon, _ := generator.Generate(context.Background(), "user@example.com", 200)

For a full list of configuration options, please see the GoDoc for the Config struct.

Concurrency & Performance

Thread Safety

All public functions and types are safe for concurrent use by multiple goroutines. The library achieves thread safety through several mechanisms:

  • Immutable Icons: Once created, Icon instances are read-only and can be safely shared across goroutines
  • Thread-Safe Caching: Internal LRU cache uses RWMutex for optimal concurrent read performance
  • Atomic Operations: Performance metrics use lock-free atomic counters
  • Protected State: All shared mutable state is properly synchronized

Concurrent Usage Patterns

// Create one generator and share it across goroutines
generator, err := jdenticon.NewGeneratorWithConfig(config, 1000)
if err != nil {
    log.Fatal(err)
}

// Safe: Multiple goroutines can use the same generator
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
    wg.Add(1)
    go func(id int) {
        defer wg.Done()
        
        userID := fmt.Sprintf("user-%d@example.com", id)
        icon, err := generator.Generate(context.Background(), userID, 64)
        if err != nil {
            log.Printf("Failed to generate icon: %v", err)
            return
        }
        
        // Icons are immutable and safe to share
        svg, _ := icon.ToSVG()
        // Use svg...
    }(i)
}
wg.Wait()

Also Safe: Package-Level Functions

// Safe: Uses internal singleton with caching
var wg sync.WaitGroup
for _, email := range emails {
    wg.Add(1)
    go func(e string) {
        defer wg.Done()
        icon, _ := jdenticon.Generate(context.Background(), e, 64)
        // Process icon...
    }(email)
}
wg.Wait()

Performance Recommendations

  1. Larger Cache Sizes: Use 1000+ entries for high-concurrency scenarios
  2. Generator Reuse: Create one generator per configuration, share across goroutines
  3. Icon Sharing: Generated icons are immutable and efficient to share
  4. Monitor Metrics: Use GetCacheMetrics() to track cache performance
// Example: Monitor cache performance
hits, misses := generator.GetCacheMetrics()
ratio := float64(hits) / float64(hits + misses) * 100
log.Printf("Cache hit ratio: %.1f%%", ratio)

Benchmarks

The library is optimized for concurrent workloads:

  • Single-threaded: ~15,000 icons/second (64x64 PNG)
  • Concurrent (8 cores): ~85,000 icons/second with 99%+ cache hits
  • Memory efficient: ~2.1 KB per operation with LRU caching

Run benchmarks locally:

go test -bench=. -benchmem ./...

Command-Line Interface (CLI)

The jdenticon tool supports both single icon generation and high-performance batch processing.

Single Icon Generation

Generate a default 200x200 SVG icon:

jdenticon generate "my-cli-icon" > my-cli-icon.svg

Generate a 256x256 PNG icon:

jdenticon generate "my-cli-icon" -s 256 -f png -o my-cli-icon.png

Batch Processing

Generate multiple icons from a text file (one value per line):

jdenticon batch users.txt --output-dir ./avatars

High-performance concurrent batch processing:

jdenticon batch large-list.txt --output-dir ./avatars --concurrency 8 --format png --size 128

Key batch features:

  • Concurrent Processing: Uses worker pool pattern for optimal performance
  • Configurable Workers: --concurrency flag (defaults to CPU count)
  • Progress Tracking: Real-time progress bar with completion statistics
  • Graceful Shutdown: Responds to Ctrl+C for clean termination
  • Performance: Up to 3-4x speedup vs sequential processing

All available options:

jdenticon --help
jdenticon batch --help

Development & Testing

This project includes comprehensive testing and validation infrastructure to ensure quality and identical SVG output.

Directory Structure

examples/

Contains practical Go usage examples demonstrating best practices:

  • concurrent-usage.go - Thread-safe patterns, performance optimization, and cache monitoring
  • Run examples: go run examples/concurrent-usage.go
  • Run with race detection: go run -race examples/concurrent-usage.go

benchmark/

Dedicated performance testing infrastructure:

  • Purpose: Performance comparison between Go and JavaScript implementations
  • Coverage: Speed benchmarks, memory analysis, regression testing
  • Usage: Validates performance claims and catches regressions

Building and Testing

To contribute or build from source:

  1. Clone the repository:

    git clone https://github.com/ungluedlabs/go-jdenticon.git
    cd go-jdenticon
    
  2. Run tests:

    go test ./...
    
  3. Run tests with race detection:

    go test -race ./...
    
  4. Run benchmarks:

    go test -bench=. ./...
    
  5. Build the CLI tool:

    go build ./cmd/jdenticon
    

API Reference

Core Functions

  • Generate(ctx context.Context, value string, size int) (*Icon, error) - Generate an icon with default settings
  • ToSVG(ctx context.Context, value string, size int) (string, error) - Generate SVG directly
  • ToPNG(ctx context.Context, value string, size int) ([]byte, error) - Generate PNG directly

Generator Type

For better performance with multiple icons:

  • NewGenerator() (*Generator, error) - Create generator with default cache (1000 entries)
  • NewGeneratorWithCacheSize(size int) (*Generator, error) - Create generator with custom cache size
  • NewGeneratorWithConfig(config Config, cacheSize int) (*Generator, error) - Create generator with custom config
  • Generate(ctx context.Context, value string, size int) (*Icon, error) - Generate icon using this generator

Icon Type

  • ToSVG() (string, error) - Render as SVG string
  • ToPNG() ([]byte, error) - Render as PNG byte data
  • ToPNGWithSize(outputSize int) ([]byte, error) - Render PNG at different size

Configuration

Use functional options for flexible configuration:

config, err := jdenticon.Configure(
    jdenticon.WithColorSaturation(0.7),
    jdenticon.WithPadding(0.1),
    jdenticon.WithBackgroundColor("#ffffff"),
    jdenticon.WithHueRestrictions([]float64{0, 120, 240}),
)

Security & Input Limits

Go Jdenticon includes configurable DoS protection to prevent resource exhaustion attacks:

config := jdenticon.Config{
    MaxIconSize:    4096,  // Maximum icon dimension in pixels (default: 4096)
    MaxInputLength: 1048576, // Maximum input string length in bytes (default: 1MB)
    // ... other config options
}

// Use 0 for default limits, positive values for custom limits, -1 to disable
icon, err := jdenticon.ToSVGWithConfig(context.Background(), "user@example.com", 512, config)

Default Security Limits:

  • Icon Size: 4096×4096 pixels maximum (~64MB memory usage)
  • Input Length: 1MB maximum string length
  • PNG Effective Size: Automatically adjusts supersampling to stay within limits

Features:

  • Smart PNG Handling: ToPNG() automatically reduces supersampling for large icons
  • Configurable Limits: Override defaults or disable limits entirely for special use cases
  • Structured Errors: Clear error messages explain limit violations and how to resolve them
  • Fail-Fast Validation: Invalid inputs are rejected before expensive operations

The Go implementation provides superior DoS protection compared to the JavaScript reference library while producing identical output.

Performance

The library includes several performance optimizations:

  • LRU Caching: Generators cache generated icons for repeated use
  • Efficient Rendering: Optimized SVG and PNG generation
  • Reusable Generators: Create once, use many times
  • Minimal Allocations: Careful memory management

Example with caching:

generator, _ := jdenticon.NewGenerator()

// These will be cached
icon1, _ := generator.Generate(context.Background(), "user1@example.com", 64)
icon2, _ := generator.Generate(context.Background(), "user2@example.com", 64)

// Check cache performance
hits, misses := generator.GetCacheMetrics()
fmt.Printf("Cache: %d hits, %d misses\n", hits, misses)

License

This project is licensed under the Elastic License 2.0 - see the LICENSE file for details.

Key points:

  • Free to use, modify, and distribute
  • Cannot be offered as a hosted/managed service
  • Cannot remove or circumvent license key functionality

Acknowledgments

  • This library is a Go port of the excellent Jdenticon by Daniel Mester
  • Special thanks to the original JavaScript implementation for the visual algorithm
Description
Go Jdenticon library - generates identicon avatars
Readme 12 MiB
Languages
Go 89.4%
Shell 6.5%
JavaScript 2.6%
Makefile 1.5%