You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

224 lines
8.3 KiB

/* ——————————————————————————————————————————————————————————————————————————
Proyecto WIAWAIW
—————————————————————————————————————————————————————————————————————————————
Fichero main.go
Package app
Autor Juan V. Navarro juanvnl@activething.com
Creado 15/08/2025
—————————————————————————————————————————————————————————————————————————————
LICENSES AND TERMS OF USE
-------------------------
This software is licensed under the Elastic License v2.0 (the "License").
For full terms and additional information regarding permitted and prohibited
uses, please visit:
https://activething.com/wiawiaw/licenses
You may use, copy, modify, and redistribute this software internally within
your organization for any purpose, including research, development, and
testing, subject to the terms of this License.
You may NOT, however, use, provide, distribute, or make this software
available to any third party as part of a hosted service, SaaS offering, or
commercial product without first obtaining a commercial license from
Active Thing.
You may combine this software with other code, provided that such
combination does not circumvent the restrictions of this License.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. In no event shall
the authors or copyright holders be liable for any claim, damages, or other
liability arising from the use of this software.
—————————————————————————————————————————————————————————————————————————————
Web : activething.com | wiawiaw.com
git : g.activething.com | github.com/activething
Correo : dev@activething.com
—————————————————————————————————————————————————————————————————————————————
No deseo caminar sobre el agua", dijo Siddhartha.
Que los antiguos chamanes se contenten con tales habilidades.
—— Hermann Hesse, Siddhartha
—————————————————————————————————————————————————————————————————————————————
Copyright (c) 2025 Active Thing
————————————————————————————————————————————————————————————————————————————— */
package main
import (
"fmt"
"math"
)
// ReduceColor1 toma un color RGB y lo reduce a la mejor representación disponible
// según el soporte del terminal.
func ReduceColor(r, g, b uint8, hasTrueColor, has256Colors bool) string {
// 1. Soporte TrueFgColor (24 bits)
if hasTrueColor {
return fmt.Sprintf("\x1b[38;2;%d;%d;%dm", r, g, b)
}
// 2. Soporte 256 colores
if has256Colors {
// Convertir a un color del cubo 6x6x6
dr := math.Round(float64(r) / 51.0)
dg := math.Round(float64(g) / 51.0)
db := math.Round(float64(b) / 51.0)
// Calcular el índice
index := 16 + (36 * int(dr)) + (6 * int(dg)) + int(db)
// Considerar la paleta de grises de 24 niveles para mayor precisión
if r == g && g == b {
grayIndex := 232 + int(math.Round(float64(r)/10.5))
return fmt.Sprintf("\x1b[38;5;%d;1m", grayIndex)
}
return fmt.Sprintf("\x1b[38;5;%d;1m", index)
}
// 3. Soporte ANSI de 8 colores
// Usar la distancia euclidiana para encontrar el color más cercano.
colorsAnsi := []struct {
r, g, b uint8
code int
}{
{0, 0, 0, 30}, // Negro
{255, 0, 0, 31}, // Rojo
{0, 255, 0, 32}, // Verde
{255, 255, 0, 33}, // Amarillo
{0, 0, 255, 34}, // Azul
{255, 0, 255, 35}, // Magenta
{0, 255, 255, 36}, // Cian
{255, 255, 255, 37}, // Blanco
}
minDist := float64(math.MaxFloat64)
bestCode := 37 // Blanco por defecto
for _, c := range colorsAnsi {
dist := math.Pow(float64(r-c.r), 2) + math.Pow(float64(g-c.g), 2) + math.Pow(float64(b-c.b), 2)
if dist < minDist {
minDist = dist
bestCode = c.code
}
}
return fmt.Sprintf("\x1b[0;%dm", bestCode)
}
// ReduceColor toma un color RGB y lo reduce a la mejor representación disponible
// según el soporte del terminal.
func ReduceColor2(r, g, b uint8, hasTrueColor, has256Colors bool) string {
// 1. Soporte TrueFgColor (24 bits)
if hasTrueColor {
return fmt.Sprintf("\x1b[38;2;%d;%d;%dm", r, g, b)
}
// 2. Soporte 256 colores
if has256Colors {
// Convertir a cubo 6x6x6 (valores: 0, 51, 102, 153, 204, 255)
r6 := int(math.Round(float64(r) * 5.0 / 255.0)) // Escalar a 0-5
g6 := int(math.Round(float64(g) * 5.0 / 255.0))
b6 := int(math.Round(float64(b) * 5.0 / 255.0))
index := 16 + (36 * r6) + (6 * g6) + b6
// Calcular distancia al color del cubo 6x6x6
rCube := uint8(r6 * 51)
gCube := uint8(g6 * 51)
bCube := uint8(b6 * 51)
distCube := weightedDistance(r, g, b, rCube, gCube, bCube)
// Verificar si un tono de gris es mejor (232-255)
gray := uint8((int(r) + int(g) + int(b)) / 3)
grayIndex := 232 + int(math.Round(float64(gray)/10.5))
grayValue := uint8((grayIndex - 232) * 10)
distGray := weightedDistance(r, g, b, grayValue, grayValue, grayValue)
if distGray < distCube {
return fmt.Sprintf("\x1b[38;5;%dm", grayIndex)
}
return fmt.Sprintf("\x1b[38;5;%dm", index)
}
// 3. Soporte ANSI de 8 colores (incluye brillantes)
colorsAnsi := []struct {
r, g, b uint8
code int
}{
{0, 0, 0, 30}, // Negro
{128, 0, 0, 31}, // Rojo
{0, 128, 0, 32}, // Verde
{128, 128, 0, 33}, // Amarillo
{0, 0, 128, 34}, // Azul
{128, 0, 128, 35}, // Magenta
{0, 128, 128, 36}, // Cian
{192, 192, 192, 37}, // Blanco
{128, 128, 128, 90}, // Negro brillante
{255, 0, 0, 91}, // Rojo brillante
{0, 255, 0, 92}, // Verde brillante
{255, 255, 0, 93}, // Amarillo brillante
{0, 0, 255, 94}, // Azul brillante
{255, 0, 255, 95}, // Magenta brillante
{0, 255, 255, 96}, // Cian brillante
{255, 255, 255, 97}, // Blanco brillante
}
minDist := float64(math.MaxFloat64)
bestCode := 37 // Blanco por defecto
for _, c := range colorsAnsi {
dist := weightedDistance(r, g, b, c.r, c.g, c.b)
if dist < minDist {
minDist = dist
bestCode = c.code
}
}
return fmt.Sprintf("\x1b[0;%dm", bestCode)
}
// weightedDistance calcula la distancia euclidiana ponderada para mejor percepción visual
func weightedDistance(r1, g1, b1, r2, g2, b2 uint8) float64 {
// Ponderaciones basadas en la sensibilidad del ojo humano
dr := float64(r1 - r2) * 0.30
dg := float64(g1 - g2) * 0.59
db := float64(b1 - b2) * 0.11
return math.Sqrt(dr*dr + dg*dg + db*db)
}
func main() {
r, g, b := uint8(25), uint8(128), uint8(200)
// Caso 1: Soporte TrueFgColor
fmt.Printf("1- Soporte TrueFgColor: %sTexto de ejemplo\x1b[0m\n", ReduceColor(r, g, b, true, true))
fmt.Printf("2- Soporte TrueFgColor: %sTexto de ejemplo\x1b[0m\n", ReduceColor2(r, g, b, true, true))
// Caso 2: Soporte 256 colores
fmt.Printf("1- Soporte 256 colores: %sTexto de ejemplo\x1b[0m\n", ReduceColor(r, g, b, false, true))
fmt.Printf("2- Soporte 256 colores: %sTexto de ejemplo\x1b[0m\n", ReduceColor2(r, g, b, false, true))
// Caso 3: Soporte ANSI 8 colores
fmt.Printf("1- Soporte 8 colores: %sTexto de ejemplo\x1b[0m\n", ReduceColor(r, g, b, false, false))
fmt.Printf("2- Soporte 8 colores: %sTexto de ejemplo\x1b[0m\n", ReduceColor2(r, g, b, false, false))
// Caso 4: Sin color (manejarlo fuera de la función, ya que no se necesita código de escape)
fmt.Printf("Sin soporte: Texto de ejemplo\n")
}
/*
func main() {
ansiStylesMain()
}
*/

Powered by TurnKey Linux.