Initial release: Go Jdenticon library v0.1.0
- Core library with SVG and PNG generation - CLI tool with generate and batch commands - Cross-platform path handling for Windows compatibility - Comprehensive test suite with integration tests
This commit is contained in:
110
jdenticon/icon.go
Normal file
110
jdenticon/icon.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package jdenticon
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ungluedlabs/go-jdenticon/internal/engine"
|
||||
"github.com/ungluedlabs/go-jdenticon/internal/renderer"
|
||||
)
|
||||
|
||||
// Icon represents a generated identicon that can be rendered as SVG or PNG.
|
||||
// It wraps the internal engine.Icon to provide a clean public API.
|
||||
type Icon struct {
|
||||
engineIcon *engine.Icon
|
||||
}
|
||||
|
||||
// newIcon creates a new public Icon from an internal engine.Icon.
|
||||
func newIcon(engineIcon *engine.Icon) *Icon {
|
||||
return &Icon{
|
||||
engineIcon: engineIcon,
|
||||
}
|
||||
}
|
||||
|
||||
// ToSVG renders the icon as an SVG string.
|
||||
//
|
||||
// Returns the SVG markup as a string, or an error if rendering fails.
|
||||
func (i *Icon) ToSVG() (string, error) {
|
||||
if i.engineIcon == nil {
|
||||
return "", ErrInvalidIcon("icon data is nil")
|
||||
}
|
||||
|
||||
size := int(i.engineIcon.Size)
|
||||
svgRenderer := renderer.NewSVGRenderer(size)
|
||||
|
||||
if err := i.renderToRenderer(svgRenderer); err != nil {
|
||||
return "", NewErrRenderFailed("SVG", err)
|
||||
}
|
||||
|
||||
return svgRenderer.ToSVG(), nil
|
||||
}
|
||||
|
||||
// ToPNG renders the icon as PNG bytes.
|
||||
//
|
||||
// Returns the PNG data as a byte slice, or an error if rendering fails.
|
||||
func (i *Icon) ToPNG() ([]byte, error) {
|
||||
if i.engineIcon == nil {
|
||||
return nil, ErrInvalidIcon("icon data is nil")
|
||||
}
|
||||
|
||||
size := int(i.engineIcon.Size)
|
||||
pngRenderer := renderer.NewPNGRenderer(size)
|
||||
|
||||
if err := i.renderToRenderer(pngRenderer); err != nil {
|
||||
return nil, NewErrRenderFailed("PNG", err)
|
||||
}
|
||||
|
||||
png, err := pngRenderer.ToPNG()
|
||||
if err != nil {
|
||||
return nil, NewErrRenderFailed("PNG", err)
|
||||
}
|
||||
|
||||
return png, nil
|
||||
}
|
||||
|
||||
// renderToRenderer renders the icon to any renderer that implements the Renderer interface.
|
||||
func (i *Icon) renderToRenderer(r renderer.Renderer) error {
|
||||
// Set background if specified
|
||||
if i.engineIcon.Config.BackColor != nil {
|
||||
color := i.engineIcon.Config.BackColor
|
||||
colorStr := color.String()
|
||||
opacity := float64(color.A) / 255.0
|
||||
r.SetBackground(colorStr, opacity)
|
||||
}
|
||||
|
||||
// Render each shape group
|
||||
for _, shapeGroup := range i.engineIcon.Shapes {
|
||||
colorStr := shapeGroup.Color.String()
|
||||
|
||||
r.BeginShape(colorStr)
|
||||
|
||||
for _, shape := range shapeGroup.Shapes {
|
||||
if err := i.renderShape(r, shape); err != nil {
|
||||
return fmt.Errorf("shape rendering failed: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
r.EndShape()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// renderShape renders a single shape to the renderer.
|
||||
func (i *Icon) renderShape(r renderer.Renderer, shape engine.Shape) error {
|
||||
switch shape.Type {
|
||||
case "polygon":
|
||||
if len(shape.Points) < 3 {
|
||||
return fmt.Errorf("polygon must have at least 3 points, got %d", len(shape.Points))
|
||||
}
|
||||
r.AddPolygon(shape.Points)
|
||||
|
||||
case "circle":
|
||||
topLeft := engine.Point{X: shape.CircleX, Y: shape.CircleY}
|
||||
r.AddCircle(topLeft, shape.CircleSize, shape.Invert)
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unsupported shape type: %s", shape.Type)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user