"La Gaceta de Linux...haciendo de Linux algo un poco mas divertido!"


¡¡¡Te Gusta El Color!!!
(Los misteriosos caracteres ^[[ )

Por Pradeep Padala

Traducción al español por Amanda Kisuy
el día 17 de Mayo 2001, para La Gaceta de Linux

¿Alguna vez has redirigido la salida de un programa con colores y te has preguntado que son esos misteriosos  ^[[ ? ¿Has tratado de producir colores con un printf sin usar curses? Si la respuesta a estas preguntas es si, continua leyendo...

Este artículo se enfoca a explicar esos misteriosos caracteres que uno encuentra en la salida de un programa con curses que produce colores. Después, extendemos el concepto para producir colores con un printf.

Códigos de la Terminal

En los viejos días de terminales teletipo, las terminales estaban aparte de las computadoras y eran conectadas a ellas através de cables seriales. Las terminales podían ser configuradas mandando una serie de bytes a cada uno de ellos. Todas las capacidades de una terminal podían ser accesadas através de estas series de bytes que eran usualmente llamadas secuencias de escape porque comenzaban con un caracter de escape (0x1B). Aún hoy con emulación  vt100,  podemos mandar secuencias de escape a el emulador y eso tendrá  el mismo efecto en la ventana terminal.
De aquí que, para imprimir colores, solamente repetimos un código de control.
Teclea esto en tu consola.
        echo "^[[0;31;40mIn Color"
El primer caracter es un caracter de escape, que se ve como dos caracteres ^ y [. Para  imprimir eso tienes que presionar CTRL+V y después la tecla ESC. Todos los otros son caracteres que se imprimen normalmente. Ves la cadena "In Color"  en rojo. Esto permanecerá así  y regresará a su color original tecleando esto:
        echo "^[[0;37;40m"
Como puedes ver es muy fácil el poner colores y reestablecer el color original. Hay una  gran cantidad de secuencias de escape con las cuales puedes hacer muchas cosas como movimientos del cursor, reinicio de la terminal, etc..

El Código de Color:     <ESC>[{attr};{fg};{bg}m

Explicaré las secuencias de escape para producir colores. La secuencia para imprimir o enviar
a la terminal es
        <ESC>[{attr};{fg};{bg}m
El primer caracter es ESC el cual tiene que ser impreso presionando CTRL+V  y después ESC en la consola Linux o en xterm, konsole, kvt, etc. ("CTRL+V ESC" es tambien una forma para  insertar un caracter de escape en un documento en "vim" ). Después {attr}, {fg}, {bg} deben ser reemplazados con el valor correcto para el efecto correspondiente, attr es el atributo como parpadeo, subrayado, etc.. fg and bg are los colores del frente (foreground ) y  los del fondo (background ) respectivamente. No tienes que poner nada alrededor de los números. El solo escribir el número será suficiente.

{attr} es alguno de los siguientes

        0       Reinicializa Todos Los Atributos(regresa a el modo normal)
        1       Brillo (Generalmente lo vuelve a negritas)
        2       Oscuro
        3       Subrayado
        5       Parpadeo
        7       Reverso
        8       Oculto
{fg} es uno de los siguientes
        30      Negro
        31      Rojo
        32      Verde
        33      Amarillo
        34      Azul
        35      Magenta
        36      Cyan
        37      Blanco
{bg} es uno de los siguientes
        40      Negro
        41      Rojo
        42      Verde
        43      Amarillo
        44      Azul
        45      Magenta
        46      Cyan
        47      Blanco
Así para obtener una línea parpadeante con frente Azul y fondo Verde,la combinación a usar debe ser
        
echo "^[[5;34;42mIn color"
que actualmente es muy feo. :-). Revierte el efecto con

echo "^[0;37;40m"

Con printf()

¿Y si quieres usar estas funciones en un programa en C? Simple! Antes de  que imprimas algo imprime las secuencias de escape para producir el color deseado. He escrito una pequeña rutina textcolor() que lo hace automaticamente. Puedes usarla en tus programas con la constante #define. La versión texto de este programa está aquí

textcolor()

#include <stdio.h>

#define RESET           0
#define BRIGHT          1
#define DIM             2
#define UNDERLINE       3
#define BLINK           4
#define REVERSE         7
#define HIDDEN          8

#define BLACK           0
#define RED             1
#define GREEN           2
#define YELLOW          3
#define BLUE            4
#define MAGENTA         5
#define CYAN            6
#define WHITE           7

void textcolor(int attr, int fg, int bg);
int main()
{       textcolor(BRIGHT, RED, BLACK);  
        printf("In color\n");
        textcolor(RESET, WHITE, BLACK); 
        return 0;
}

void textcolor(int attr, int fg, int bg)
{       char command[13];

        /* Command is the control command to the terminal */
        sprintf(command, "%c[%d;%d;%dm", 0x1B, attr, fg + 30, bg + 40);
        printf("%s", command);
}

El textcolor() esta modelado contra la función Turbo C API. La función llama a el conjunto de colores y después imprime con un sprintf() (una función usada en Turbo C para producir salida a consola a color ).

Un Demo de colores

#include <stdio.h>

#define RESET           0
#define BRIGHT          1
#define DIM             2
#define UNDERLINE       3
#define BLINK           4
#define REVERSE         7
#define HIDDEN          8

#define BLACK           0
#define RED             1
#define GREEN           2
#define YELLOW          3
#define BLUE            4
#define MAGENTA         5
#define CYAN            6
#define WHITE           7

#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))

char *attrs[] = {"NORMAL", "BRIGHT", "DIM", "UNDERLINE", "BLINK",
                 "REVERSE", "HIDDEN", "EXIT"};
char *colors[] = {"BLACK", "RED", "GREEN", "YELLOW", "BLUE", "MAGENTA",
                 "CYAN", "WHITE", "EXIT"};
void textcolor(int attr, int fg, int bg);
int print_menu(char *array[], int n_options, char *title);
int main()
{       int attr, fg, bg;
        int attr_size, colors_size;
        
        attr_size = ARRAY_SIZE(attrs);
        colors_size = ARRAY_SIZE(colors);
        while(1)
        {       printf("\n");
                attr = print_menu(attrs, attr_size, "Choose the attr you want:");
                if(attr == attr_size - 1)
                        break;
                fg = print_menu(colors, colors_size, "Choose the foreground you want:");
                if(attr == colors_size - 1)
                        break;
                bg = print_menu(colors, colors_size, "Choose the background you want:");
                if(attr == colors_size - 1)
                        break;
                printf("\n");
                textcolor(attr, fg, bg);        
                printf("This is what you get if you use the combination %s attribute %s foreground and %s
 background", attrs[attr], colors[fg], colors[bg]);
                textcolor(RESET, WHITE, BLACK);
                system("clear");
        }
        return 0;
}

int print_menu(char *array[], int n_options, char *title)
{       int choice, i;
        for(i = 0;i < n_options; ++i)
                printf("%d.%s\n", i, array[i]);
        printf("%s", title);
        scanf("%d", &choice);
        return choice;
}               
void textcolor(int attr, int fg, int bg)
{       char command[13];

        /* Command is the control command to the terminal */
        sprintf(command, "%c[%d;%d;%dm", 0x1B, attr, fg + 30, bg + 40);
        printf("%s", command);
}

Este programa pide que el usuario juege con los atributos y colores y muestra una cadena en ese color. Generalmente uso esto para encontrar la mejor combinación de colores para mis GUIs. La versión texto del programa anterior esta aquí .

El Catch

Ahora ¿Qué es el catch? Si producir colores es muy fácil, por que la gente gasta su tiempo escribiendo enormes programas , que  se vuelven  complejas peticiones a terminfo?  Como sabemos, hay muchas terminales con pocas capacidades y terminales que no reconocen estos códigos de escape o que necesitan diferentes códigos para producir el mismo efecto. Así si quieres un programa portable que pueda correr en cualquier terminal con la misma ( o reducida) funcionalidad, debes usar curses. Curses usa la terminfo para encontrar los códigos correctos para realizar la tarea con el estilo. Terminfo es una gran base de datos que contiene información sobre varias funciones de diferentes terminales.

Pero si solo quieres escribir un simple programa que produzca colores en una consola Linux o en una ventana xterm, puedes solo usar las secuencias de escape de arriba para hacerlo fácilmente. La mayoría de las consolas Linux  emulan vt100, por lo que reconocen estas secuencias de escape.

Con put

Pero hay una forma para pedir la base de datos terminfo y hacer el trabajo. tput es el comando que pide las bases de datos y ejecuta la función que especifiques. Las opciones setf y setb son usados para poner los colores del frente y del fondo.
Usa esto para poner el fondo rojo y el frente verde.
        tput setf 4     # tput setf {fg color number}
        tput setb 2     # tput setb {bg color number}
Esto se puede usar en scripts del shell cuando quieras. Ve la página del manual de tput para más funciones de tput. La página del manual de terminfo contiene mucha información que considera las capacidades de la terminal - como conseguir y poner sus valores y más. Hay dos páginas del manual de terminfo. "man 5 terminfo"  que describe la base de datos terminfo. "man 3ncurses terminfo" que describe las funciones en C que usan la base de datos.
Estos son los colores que pueden ser pasados como argumentos a "tput setf" y "tput setb".
        0       Negro
        1       Rojo
        2       Verde
        3       Amarillo
        4       Azul
        5       Magenta
        6       Cyan
        7       Blanco
Diviertete!!!

Referencias


Copyright © 2001, Pradeep Padala.
Copying license http://www.linuxgazette.com/copying.html
Publcado en el número 65 de Linux Gazette, Abril 2001