Compare commits
No commits in common. "42c154903a3264fc677e170a91826883af746965" and "04d6693c37c416224b33d75222333fbfda7fb08d" have entirely different histories.
42c154903a
...
04d6693c37
228
banner.go
228
banner.go
@ -5,7 +5,6 @@ import (
|
|||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
"image/png"
|
"image/png"
|
||||||
"math"
|
|
||||||
"math/rand/v2"
|
"math/rand/v2"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -40,6 +39,7 @@ func NewTextData(text string, size float64, multiline bool) *TextData {
|
|||||||
return &TextData{splits, size, false, -1, -1, -1, -1}
|
return &TextData{splits, size, false, -1, -1, -1, -1}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Consistent outline thickness based on font size
|
||||||
func getOutlineThickness(size float64) int {
|
func getOutlineThickness(size float64) int {
|
||||||
thickness := int(size / 8)
|
thickness := int(size / 8)
|
||||||
if thickness < 1 {
|
if thickness < 1 {
|
||||||
@ -50,6 +50,7 @@ func getOutlineThickness(size float64) int {
|
|||||||
return thickness
|
return thickness
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Actual bounding box for text including outline
|
||||||
func getTextBounds(text []string, size float64) (width, height int) {
|
func getTextBounds(text []string, size float64) (width, height int) {
|
||||||
face, err := createFontFace(size)
|
face, err := createFontFace(size)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -144,7 +145,8 @@ func drawTextWithOutline(canvas *image.RGBA, text []string, x, y int, textColor,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func findTextPositions(textData []*TextData, filename string) {
|
// Place all elements to canvas without overlaps
|
||||||
|
func findTextPositions(textData []*TextData) {
|
||||||
padding := 10
|
padding := 10
|
||||||
|
|
||||||
for i, data := range textData {
|
for i, data := range textData {
|
||||||
@ -179,7 +181,7 @@ func findTextPositions(textData []*TextData, filename string) {
|
|||||||
y := rand.IntN(maxY-minY+1) + minY
|
y := rand.IntN(maxY-minY+1) + minY
|
||||||
|
|
||||||
// bounding box for cur. text
|
// bounding box for cur. text
|
||||||
curRect := struct{ x, y, w, h int }{
|
currentRect := struct{ x, y, w, h int }{
|
||||||
x: x,
|
x: x,
|
||||||
y: y,
|
y: y,
|
||||||
w: w,
|
w: w,
|
||||||
@ -201,7 +203,7 @@ func findTextPositions(textData []*TextData, filename string) {
|
|||||||
h: other.H + padding,
|
h: other.H + padding,
|
||||||
}
|
}
|
||||||
|
|
||||||
if rectsOverlap(curRect, otherRect) {
|
if rectsOverlap(currentRect, otherRect) {
|
||||||
overlaps = true
|
overlaps = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -216,196 +218,93 @@ func findTextPositions(textData []*TextData, filename string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fallback: place to a free corner
|
// fallback: use grid positioning
|
||||||
if !placed {
|
if !placed {
|
||||||
log.Debugf("Using fallback position for text '%s' in '%s'", data.Text, filename)
|
log.Warnf("Using fallback position for text '%v'", data.Text)
|
||||||
|
|
||||||
corners := []struct {
|
gridCols := 2
|
||||||
name string
|
col := i % gridCols
|
||||||
x, y int
|
row := i / gridCols
|
||||||
}{
|
|
||||||
{"top-left", padding, padding},
|
cellWidth := config.BannerWidth / gridCols
|
||||||
{"top-right", config.BannerWidth - w - padding, padding},
|
cellHeight := config.BannerHeight / 3 // NOTE: assuming max 3 rows
|
||||||
{"bottom-left", padding, config.BannerHeight - h - padding},
|
|
||||||
{"bottom-right", config.BannerWidth - w - padding, config.BannerHeight - h - padding},
|
data.X = col*cellWidth + (cellWidth-w)/2
|
||||||
|
data.Y = row*cellHeight + (cellHeight-h)/2
|
||||||
|
|
||||||
|
// ensure within bounds
|
||||||
|
if data.X < padding {
|
||||||
|
data.X = padding
|
||||||
|
}
|
||||||
|
if data.Y < padding {
|
||||||
|
data.Y = padding
|
||||||
|
}
|
||||||
|
if data.X+w > config.BannerWidth-padding {
|
||||||
|
data.X = config.BannerWidth - w - padding
|
||||||
|
}
|
||||||
|
if data.Y+h > config.BannerHeight-padding {
|
||||||
|
data.Y = config.BannerHeight - h - padding
|
||||||
}
|
}
|
||||||
|
|
||||||
bestCorner := 0
|
|
||||||
minOverlapArea := int(^uint(0) >> 1) // max. int
|
|
||||||
|
|
||||||
// try each corner and find the one with least overlap
|
|
||||||
for cornerIdx, corner := range corners {
|
|
||||||
curRect := struct{ x, y, w, h int }{
|
|
||||||
x: corner.x,
|
|
||||||
y: corner.y,
|
|
||||||
w: w,
|
|
||||||
h: h,
|
|
||||||
}
|
|
||||||
|
|
||||||
totalOverlapArea := 0
|
|
||||||
|
|
||||||
// calculate total overlap area with existing texts
|
|
||||||
for j := 0; j < i; j++ {
|
|
||||||
other := textData[j]
|
|
||||||
if !other.Positioned {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
otherRect := struct{ x, y, w, h int }{
|
|
||||||
x: other.X,
|
|
||||||
y: other.Y,
|
|
||||||
w: other.W,
|
|
||||||
h: other.H,
|
|
||||||
}
|
|
||||||
|
|
||||||
if rectsOverlap(curRect, otherRect) {
|
|
||||||
// intersection rectangle
|
|
||||||
overlapLeft := max(curRect.x, otherRect.x)
|
|
||||||
overlapTop := max(curRect.y, otherRect.y)
|
|
||||||
overlapRight := min(curRect.x+curRect.w, otherRect.x+otherRect.w)
|
|
||||||
overlapBottom := min(curRect.y+curRect.h, otherRect.y+otherRect.h)
|
|
||||||
|
|
||||||
overlapWidth := overlapRight - overlapLeft
|
|
||||||
overlapHeight := overlapBottom - overlapTop
|
|
||||||
overlapArea := overlapWidth * overlapHeight
|
|
||||||
|
|
||||||
totalOverlapArea += overlapArea
|
|
||||||
}
|
|
||||||
|
|
||||||
if totalOverlapArea < minOverlapArea {
|
|
||||||
minOverlapArea = totalOverlapArea
|
|
||||||
bestCorner = cornerIdx
|
|
||||||
}
|
|
||||||
|
|
||||||
// if no overlap, use the pos. immediately
|
|
||||||
if totalOverlapArea == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// place at the best corner
|
|
||||||
data.X = corners[bestCorner].x
|
|
||||||
data.Y = corners[bestCorner].y
|
|
||||||
data.Positioned = true
|
data.Positioned = true
|
||||||
|
|
||||||
if minOverlapArea > 0 {
|
|
||||||
log.Debugf("Placed text '%v' at %s corner with some overlap (area: %d)", data.Text, corners[bestCorner].name, minOverlapArea)
|
|
||||||
} else {
|
|
||||||
log.Debugf("Placed text '%v' at %s corner with no overlap", data.Text, corners[bestCorner].name)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func genPerlinBG() (*image.RGBA, string) {
|
func genPerlinBG() *image.RGBA {
|
||||||
palette, theme := getRandomThemePalette()
|
palette, theme := getRandomThemePalette()
|
||||||
img := image.NewRGBA(image.Rect(0, 0, config.BannerWidth, config.BannerHeight))
|
img := image.NewRGBA(image.Rect(0, 0, config.BannerWidth, config.BannerHeight))
|
||||||
|
|
||||||
// noise params for interesting patterns
|
// noise params for interesting patterns
|
||||||
scale1 := 0.008 + rand.Float64()*0.015 // 0.008-0.023 (large patterns)
|
scale1 := 0.01 + rand.Float64()*0.02 // primary pattern scale (adjusted by lib)
|
||||||
scale2 := 0.025 + rand.Float64()*0.035 // 0.025-0.06 (medium detail)
|
scale2 := 0.03 + rand.Float64()*0.03 // secondary detail
|
||||||
scale3 := 0.060 + rand.Float64()*0.040 // 0.060-0.100 (fine detail, reduced grain)
|
scale3 := 0.08 + rand.Float64()*0.05 // fine detail
|
||||||
|
|
||||||
// variation offsets
|
// variation offsets
|
||||||
offsetX := rand.Float64() * 5000
|
offsetX := rand.Float64() * 1000
|
||||||
offsetY := rand.Float64() * 5000
|
offsetY := rand.Float64() * 1000
|
||||||
|
|
||||||
// noise layer weights for different effects
|
log.Infof("Generating background with theme: %s, scales: %.4f, %.4f, %.4f", theme, scale1, scale2, scale3)
|
||||||
weight1 := 0.4 + rand.Float64()*0.4 // 0.4-0.8 (large patterns)
|
|
||||||
weight2 := 0.15 + rand.Float64()*0.25 // 0.15-0.4 (medium detail)
|
|
||||||
weight3 := 0.05 + rand.Float64()*0.15 // 0.15-0.4 (fine detail, reduced grain)
|
|
||||||
|
|
||||||
// normalize weights to sum to 1.0
|
|
||||||
totalWeight := weight1 + weight2 + weight3
|
|
||||||
weight1 /= totalWeight
|
|
||||||
weight2 /= totalWeight
|
|
||||||
weight3 /= totalWeight
|
|
||||||
|
|
||||||
// FIX: limit gradient strength to prevent overwhelming the noise
|
|
||||||
gradientStrengthX := rand.Float64() * 0.25 // old: 0.4
|
|
||||||
gradientStrengthY := rand.Float64() * 0.2 // old: 0.3
|
|
||||||
gradientDirectionX := 1.0
|
|
||||||
gradientDirectionY := 1.0
|
|
||||||
|
|
||||||
// sometimes reverse gradient direction for variety
|
|
||||||
if rand.Float64() < 0.3 {
|
|
||||||
gradientDirectionX = -1.0
|
|
||||||
}
|
|
||||||
if rand.Float64() < 0.3 {
|
|
||||||
gradientDirectionY = -1.0
|
|
||||||
}
|
|
||||||
|
|
||||||
// randomize noise combination method
|
|
||||||
combineMethod := rand.IntN(4)
|
|
||||||
|
|
||||||
// fix: increase distortion chance and make it more visible
|
|
||||||
useDistortion := rand.Float64() < 0.4 // old: 30%
|
|
||||||
distortionStrength := 0.05 + rand.Float64()*0.15 // 0.05-0.2 (old: 0.0-0.1)
|
|
||||||
|
|
||||||
log.Debugf("BG theme: %s / Scales: %.4f, %.4f, %.4f / Weights: %.3f, %.3f, %.3f",
|
|
||||||
theme, scale1, scale2, scale3, weight1, weight2, weight3)
|
|
||||||
log.Debugf("Gradient: X=%.3f*%.0f, Y=%.3f*%.0f / Combine method: %d / Distortion %t (%.3f)",
|
|
||||||
gradientStrengthX, gradientDirectionX, gradientStrengthY, gradientDirectionY,
|
|
||||||
combineMethod, useDistortion, distortionStrength)
|
|
||||||
|
|
||||||
for y := range config.BannerHeight {
|
for y := range config.BannerHeight {
|
||||||
for x := range config.BannerWidth {
|
for x := range config.BannerWidth {
|
||||||
baseX := float64(x) + offsetX
|
// multi-octave noise
|
||||||
baseY := float64(y) + offsetY
|
fx := (float64(x) + offsetX) * scale1
|
||||||
|
fy := (float64(y) + offsetY) * scale1
|
||||||
// optional distortion for more organic patterns
|
|
||||||
if useDistortion {
|
|
||||||
baseX += math.Sin(float64(y)*0.015) * distortionStrength * 200
|
|
||||||
baseY += math.Cos(float64(x)*0.015) * distortionStrength * 200
|
|
||||||
}
|
|
||||||
|
|
||||||
// multi-octave noise with randomized scales
|
|
||||||
fx1 := baseX * scale1
|
|
||||||
fy1 := baseY * scale1
|
|
||||||
fx2 := baseX * scale2
|
|
||||||
fy2 := baseY * scale2
|
|
||||||
fx3 := baseX * scale3
|
|
||||||
fy3 := baseY * scale3
|
|
||||||
|
|
||||||
// noise values at different scales
|
// noise values at different scales
|
||||||
noise1 := perlinNoise.Noise2D(fx1, fy1)
|
noise1 := perlinNoise.Noise2D(fx, fy)
|
||||||
noise2 := perlinNoise.Noise2D(fx2, fy2)
|
noise2 := perlinNoise.Noise2D(fx/scale1*scale2, fy/scale1*scale2)
|
||||||
noise3 := perlinNoise.Noise2D(fx3, fy3)
|
noise3 := perlinNoise.Noise2D(fx/scale1*scale3, fy/scale1*scale3)
|
||||||
|
|
||||||
// different combination methods for variety
|
// combined noise layers with different weights
|
||||||
var combined float64
|
combined := noise1*0.6 + noise2*0.3 + noise3*0.1
|
||||||
switch combineMethod {
|
|
||||||
case 0: // standard linear combination
|
|
||||||
combined = noise1*weight1 + noise2*weight2 + noise3*weight3
|
|
||||||
case 1: // multiplicative blend
|
|
||||||
combined = (noise1*weight1)*(1+noise2*weight2)*(1+noise3*weight3) - 1
|
|
||||||
case 2: // maximum blend (creates sharper patterns)
|
|
||||||
values := []float64{noise1 * weight1, noise2 * weight2, noise3 * weight3}
|
|
||||||
combined = math.Max(math.Max(values[0], values[1]), values[2])
|
|
||||||
case 3: // turbulence (abs. values create more chaotic patterns)
|
|
||||||
combined = math.Abs(noise1)*weight1 + math.Abs(noise2)*weight2 + math.Abs(noise3)*weight3
|
|
||||||
}
|
|
||||||
|
|
||||||
// randomized gradient with variable direction and strength
|
// position-based gradient for a more dynamic look
|
||||||
gradientX := (float64(x) / float64(config.BannerWidth)) * gradientStrengthX * gradientDirectionX
|
gradientX := float64(x) / float64(config.BannerWidth) * 0.2
|
||||||
gradientY := (float64(y) / float64(config.BannerHeight)) * gradientStrengthY * gradientDirectionY
|
gradientY := float64(y) / float64(config.BannerHeight) * 0.1
|
||||||
|
|
||||||
// combined and normalized to [0, 1] range
|
// combined and normalized to [0, 1] range
|
||||||
noise := min(max((combined+gradientX+gradientY+1)/2, 0), 1)
|
noise := (combined + gradientX + gradientY + 1) / 2
|
||||||
|
if noise < 0 {
|
||||||
|
noise = 0
|
||||||
|
}
|
||||||
|
if noise > 1 {
|
||||||
|
noise = 1
|
||||||
|
}
|
||||||
|
|
||||||
pixelColor := palette.interpolate(noise)
|
pixelColor := palette.interpolate(noise)
|
||||||
img.Set(x, y, pixelColor)
|
img.Set(x, y, pixelColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return img, theme
|
return img
|
||||||
}
|
}
|
||||||
|
|
||||||
func genBanner(textData []*TextData) error {
|
func genBanner(textData []*TextData) error {
|
||||||
fn := fmt.Sprintf("banner_%d.png", time.Now().UnixMicro())
|
canvas := genPerlinBG()
|
||||||
canvas, theme := genPerlinBG()
|
|
||||||
findTextPositions(textData, fn)
|
findTextPositions(textData)
|
||||||
|
|
||||||
for _, td := range textData {
|
for _, td := range textData {
|
||||||
if td.Positioned {
|
if td.Positioned {
|
||||||
@ -414,6 +313,7 @@ func genBanner(textData []*TextData) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn := fmt.Sprintf("banner_%d.png", time.Now().UnixMicro())
|
||||||
fp := filepath.Join(bannersDir, fn)
|
fp := filepath.Join(bannersDir, fn)
|
||||||
file, err := os.Create(fp)
|
file, err := os.Create(fp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -421,13 +321,7 @@ func genBanner(textData []*TextData) error {
|
|||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
if err := png.Encode(file, canvas); err != nil {
|
return png.Encode(file, canvas)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Infof("Output '%s' with theme '%s'", fn, theme)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: functions for banner rotation implementation
|
// TODO: functions for banner rotation implementation
|
||||||
|
148
palette.go
148
palette.go
@ -157,6 +157,14 @@ var themePalettes = map[string]Palette{
|
|||||||
{100, 255, 0, 255}, // lime
|
{100, 255, 0, 255}, // lime
|
||||||
{150, 0, 255, 255}, // purple
|
{150, 0, 255, 255}, // purple
|
||||||
},
|
},
|
||||||
|
"forest": {
|
||||||
|
{34, 139, 34, 255}, // forest green
|
||||||
|
{107, 142, 35, 255}, // olive
|
||||||
|
{154, 205, 50, 255}, // yellow green
|
||||||
|
{50, 205, 50, 255}, // lime green
|
||||||
|
{0, 128, 0, 255}, // green
|
||||||
|
{85, 107, 47, 255}, // dark olive
|
||||||
|
},
|
||||||
"cosmic": {
|
"cosmic": {
|
||||||
{138, 43, 226, 255}, // blue violet
|
{138, 43, 226, 255}, // blue violet
|
||||||
{75, 0, 130, 255}, // indigo
|
{75, 0, 130, 255}, // indigo
|
||||||
@ -165,146 +173,6 @@ var themePalettes = map[string]Palette{
|
|||||||
{255, 0, 255, 255}, // magenta
|
{255, 0, 255, 255}, // magenta
|
||||||
{72, 61, 139, 255}, // dark slate blue
|
{72, 61, 139, 255}, // dark slate blue
|
||||||
},
|
},
|
||||||
"midnight": {
|
|
||||||
{25, 25, 112, 255}, // midnight blue
|
|
||||||
{72, 61, 139, 255}, // dark slate blue
|
|
||||||
{123, 104, 238, 255}, // medium slate blue
|
|
||||||
{147, 112, 219, 255}, // medium purple
|
|
||||||
{138, 43, 226, 255}, // blue violet
|
|
||||||
{75, 0, 130, 255}, // indigo
|
|
||||||
{0, 0, 139, 255}, // dark blue
|
|
||||||
{30, 144, 255, 255}, // dodger blue
|
|
||||||
},
|
|
||||||
"fire": {
|
|
||||||
{139, 0, 0, 255}, // dark red
|
|
||||||
{178, 34, 34, 255}, // firebrick
|
|
||||||
{220, 20, 60, 255}, // crimson
|
|
||||||
{255, 69, 0, 255}, // red orange
|
|
||||||
{255, 140, 0, 255}, // dark orange
|
|
||||||
{255, 165, 0, 255}, // orange
|
|
||||||
{255, 215, 0, 255}, // gold
|
|
||||||
{255, 255, 224, 255}, // light yellow
|
|
||||||
},
|
|
||||||
"pastel": {
|
|
||||||
{255, 182, 193, 255}, // light pink
|
|
||||||
{255, 218, 185, 255}, // peach puff
|
|
||||||
{255, 255, 224, 255}, // light yellow
|
|
||||||
{240, 255, 240, 255}, // honeydew
|
|
||||||
{224, 255, 255, 255}, // light cyan
|
|
||||||
{230, 230, 250, 255}, // lavender
|
|
||||||
{255, 228, 225, 255}, // misty rose
|
|
||||||
{245, 255, 250, 255}, // mint cream
|
|
||||||
},
|
|
||||||
"earth": {
|
|
||||||
{139, 69, 19, 255}, // saddle brown
|
|
||||||
{160, 82, 45, 255}, // saddle brown
|
|
||||||
{205, 133, 63, 255}, // peru
|
|
||||||
{222, 184, 135, 255}, // burlywood
|
|
||||||
{210, 180, 140, 255}, // tan
|
|
||||||
{188, 143, 143, 255}, // rosy brown
|
|
||||||
{218, 165, 32, 255}, // goldenrod
|
|
||||||
{128, 128, 0, 255}, // olive
|
|
||||||
},
|
|
||||||
"ice": {
|
|
||||||
{240, 248, 255, 255}, // alice blue
|
|
||||||
{230, 230, 250, 255}, // lavender
|
|
||||||
{176, 196, 222, 255}, // light steel blue
|
|
||||||
{173, 216, 230, 255}, // light blue
|
|
||||||
{135, 206, 250, 255}, // light sky blue
|
|
||||||
{135, 206, 235, 255}, // sky blue
|
|
||||||
{70, 130, 180, 255}, // steel blue
|
|
||||||
{100, 149, 237, 255}, // cornflower blue
|
|
||||||
},
|
|
||||||
"autumn": {
|
|
||||||
{139, 69, 19, 255}, // saddle brown
|
|
||||||
{165, 42, 42, 255}, // brown
|
|
||||||
{178, 34, 34, 255}, // firebrick
|
|
||||||
{205, 92, 92, 255}, // indian red
|
|
||||||
{233, 150, 122, 255}, // dark salmon
|
|
||||||
{255, 160, 122, 255}, // light salmon
|
|
||||||
{255, 215, 0, 255}, // gold
|
|
||||||
{255, 140, 0, 255}, // dark orange
|
|
||||||
},
|
|
||||||
"cyberpunk": {
|
|
||||||
{255, 0, 150, 255}, // hot pink
|
|
||||||
{0, 255, 255, 255}, // cyan
|
|
||||||
{255, 0, 255, 255}, // magenta
|
|
||||||
{148, 0, 211, 255}, // dark violet
|
|
||||||
{75, 0, 130, 255}, // indigo
|
|
||||||
{0, 0, 139, 255}, // dark blue
|
|
||||||
{255, 20, 147, 255}, // deep pink
|
|
||||||
{138, 43, 226, 255}, // blue violet
|
|
||||||
},
|
|
||||||
"retro": {
|
|
||||||
{255, 105, 180, 255}, // hot pink
|
|
||||||
{255, 20, 147, 255}, // deep pink
|
|
||||||
{255, 69, 0, 255}, // red orange
|
|
||||||
{255, 215, 0, 255}, // gold
|
|
||||||
{50, 205, 50, 255}, // lime green
|
|
||||||
{0, 191, 255, 255}, // deep sky blue
|
|
||||||
{138, 43, 226, 255}, // blue violet
|
|
||||||
{255, 140, 0, 255}, // dark orange
|
|
||||||
},
|
|
||||||
"monochrome": {
|
|
||||||
{0, 0, 0, 255}, // black
|
|
||||||
{105, 105, 105, 255}, // dim gray
|
|
||||||
{128, 128, 128, 255}, // gray
|
|
||||||
{169, 169, 169, 255}, // dark gray
|
|
||||||
{192, 192, 192, 255}, // silver
|
|
||||||
{211, 211, 211, 255}, // light gray
|
|
||||||
{220, 220, 220, 255}, // gainsboro
|
|
||||||
{255, 255, 255, 255}, // white
|
|
||||||
},
|
|
||||||
"tropical": {
|
|
||||||
{255, 99, 71, 255}, // tomato
|
|
||||||
{255, 165, 0, 255}, // orange
|
|
||||||
{255, 215, 0, 255}, // gold
|
|
||||||
{154, 205, 50, 255}, // yellow green
|
|
||||||
{0, 255, 127, 255}, // spring green
|
|
||||||
{64, 224, 208, 255}, // turquoise
|
|
||||||
{0, 206, 209, 255}, // dark turquoise
|
|
||||||
{72, 209, 204, 255}, // medium turquoise
|
|
||||||
},
|
|
||||||
"volcanic": {
|
|
||||||
{128, 0, 0, 255}, // maroon
|
|
||||||
{139, 0, 0, 255}, // dark red
|
|
||||||
{165, 42, 42, 255}, // brown
|
|
||||||
{178, 34, 34, 255}, // firebrick
|
|
||||||
{205, 92, 92, 255}, // indian red
|
|
||||||
{220, 20, 60, 255}, // crimson
|
|
||||||
{255, 69, 0, 255}, // red orange
|
|
||||||
{255, 99, 71, 255}, // tomato
|
|
||||||
},
|
|
||||||
"aurora": {
|
|
||||||
{0, 255, 127, 255}, // spring green
|
|
||||||
{50, 205, 50, 255}, // lime green
|
|
||||||
{0, 255, 255, 255}, // cyan
|
|
||||||
{135, 206, 250, 255}, // light sky blue
|
|
||||||
{138, 43, 226, 255}, // blue violet
|
|
||||||
{148, 0, 211, 255}, // dark violet
|
|
||||||
{255, 20, 147, 255}, // deep pink
|
|
||||||
{255, 105, 180, 255}, // hot pink
|
|
||||||
},
|
|
||||||
"desert": {
|
|
||||||
{244, 164, 96, 255}, // sandy brown
|
|
||||||
{210, 180, 140, 255}, // tan
|
|
||||||
{222, 184, 135, 255}, // burlywood
|
|
||||||
{238, 203, 173, 255}, // navajo white
|
|
||||||
{255, 228, 181, 255}, // moccasin
|
|
||||||
{255, 218, 185, 255}, // peach puff
|
|
||||||
{255, 160, 122, 255}, // light salmon
|
|
||||||
{205, 133, 63, 255}, // peru
|
|
||||||
},
|
|
||||||
"matrix": {
|
|
||||||
{0, 100, 0, 255}, // dark green
|
|
||||||
{0, 128, 0, 255}, // green
|
|
||||||
{34, 139, 34, 255}, // forest green
|
|
||||||
{50, 205, 50, 255}, // lime green
|
|
||||||
{124, 252, 0, 255}, // lawn green
|
|
||||||
{127, 255, 0, 255}, // chartreuse
|
|
||||||
{0, 255, 0, 255}, // lime
|
|
||||||
{173, 255, 47, 255}, // green yellow
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRandomTextColors() (color.RGBA, color.RGBA) {
|
func getRandomTextColors() (color.RGBA, color.RGBA) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user