cairo (biblioteca)

En informática, Cairo es una biblioteca gráfica de la API GTK+ usada para proporcionar imágenes basadas en gráficos vectoriales. Aunque Cairo es una API independiente de dispositivos, está diseñado para usar aceleración por hardware cuando esté disponible. Cairo ofrece numerosas primitivas para imágenes de dos dimensiones.

cairo
The cairo graphics library logo
Información general
Tipo de programa API gráfica
Desarrollador Carl Worth, Behdad Esfahbod
Licencia
Información técnica
Programado en C
Versiones
Última versión estable 1.18.2 (info) ( 01 de septiembre de 2024 (2 meses y 13 días))
Última versión en pruebas 1.12.16 (info) ( 26 de agosto de 2013 (11 años, 2 meses y 19 días))
Enlaces

A pesar de que está escrito en C, existen implementaciones en otros lenguajes de programación, incluyendo C++, C#, Common Lisp, Haskell, Java, Python, Perl, Ruby, Scheme (Guile, Chicken), Smalltalk y muchos otros. Dada la doble licencia incluyendo la Licencia Pública General Reducida de GNU y la Licencia Pública de Mozilla, cairo es software libre.

Modelo gráfico de Cairo

editar

Para poder explicar el modelo gráfico que usa Cairo se tienen que definir los conceptos que se utilizan. Se tienen los sustantivos y los verbos. Los sustantivos son objetos abstractos o entidades en los cuales operan los verbos. Hay varios tipos de sustantivos y varios tipos de verbos.

Sustantivos

editar
Destino. El destino es la superficie sobre la cual se dibuja. Puede ser una matriz de píxeles, o un archivo SVG o PDF, o cualquier tipo de gráfico. Esta superficie colecciona los elementos de los gráficos mientras se van aplicando, permitiendo así construir un trabajo completo, de forma análoga a pintar sobre un lienzo.  
Fuente. Es la "pintura" sobre la cual se trabaja. Se muestra como una capa superior (capa negra en la imagen). Puede ser totalmente de un color, un patrón de colores, o incluso una superficie destino previamente creada. De forma contraria a una pintura real, la fuente puede contener un canal de transparencia.  
Máscara. La máscara es la pieza más importante pues controla la aplicación de la fuente al destino. En la imagen se muestra como una pala amarilla que deja pasar la fuente. Cuando se aplica un verbo, es como si se adhiriera la fuente al destino. Siempre que la máscara lo permita, la fuente es copiada, en caso contrario, no sucede nada.  
Ruta. Es cualquier cosa entre una parte de la máscara y una parte del contexto. Se manipula por medio de los verbos de ruta.
Contexto. El contexto mantiene un registro de todo lo que un verbo afecta. Mantiene una fuente, un destino y una máscara. También mantiene muchas variables de ayuda como el grosor de la línea y el estido, el tipo de fuente de letra y el tamaño, etc. También mantiene la ruta, la cual se transforma a una máscara cuando se usan los verbos de dibujo.

Antes de que se dibuje algo con Cairo, se necesita crear un contexto. El contexto se almacena en el tipo de dato cairo_t. Cuando se crea un contexto, debe de ser ligado a una superficie, por ejemplo, una superficie de imagen si se desea crear un archivo PNG.

Verbos

editar
Trazar. La operación cairo_stroke() toma un lápiz virtual a través de toda la ruta. Permite transferir parte de la fuente (la línea de la ruta) a través de la máscara, de acuerdo al ancho de la línea, estilo, etc. que define el contexto. Transfiere la mitad del ancho de línea en cada lado de la ruta.
cairo_set_line_width (cr, 0.1);
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_rectangle (cr, 0.25, 0.25, 0.5, 0.5);
cairo_stroke (cr);
 
Rellenar. La operación cairo_fill() permite pasar un hoyo de la fuente (los límites de la ruta) a través de la máscara. Al usar rutas complejas (rutas con múltiples subrutas , como una dona, o rutas que se intersecan), estas se ven influenciadas por las reglas de rellenado.
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_rectangle (cr, 0.25, 0.25, 0.5, 0.5);
cairo_fill (cr);
 
Mostrar texto. La operación cairo_show_text() forma la máscara desde cierto texto. Se usa como atajo en vez de crear una ruta con cairo_text_path() y luego usar cairo_fill() para transferirla.
cairo_text_extents_t te;
cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
cairo_select_font_face (cr, "Georgia",
    CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size (cr, 1.2);
cairo_text_extents (cr, "a", &te);
cairo_move_to (cr, 0.5 - te.width / 2 - te.x_bearing,
    0.5 - te.height / 2 - te.y_bearing);
cairo_show_text (cr, "a");
 
Pintar. La operación cairo_paint() usa una máscara que transfiere la fuente completa al destino. Algunas personas la consideran como una máscara infinitamente grande, otros no la consideran máscara, el resultado es el mismo. La operación similar cairo_paint_with_alpha() permite transferir la fuente completa al destino, pero solo transfiere cierto porcentaje de color.
cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
cairo_paint_with_alpha (cr, 0.5);
 
Enmascarar. Las operaciones cairo_mask() y cairo_mask_surface() permiten transferir de acuerdo al nivel de transparencia u opacidad. En las partes transparentes de la superficie, la fuente se transfiere al destino. En las partes opacas, nada se transfiere.
cairo_pattern_t *linpat, *radpat;
linpat = cairo_pattern_create_linear (0, 0, 1, 1);
cairo_pattern_add_color_stop_rgb (linpat, 0, 0, 0.3, 0.8);
cairo_pattern_add_color_stop_rgb (linpat, 1, 0, 0.8, 0.3);

radpat = cairo_pattern_create_radial (0.5, 0.5, 0.25, 0.5, 0.5, 0.75);
cairo_pattern_add_color_stop_rgba (radpat, 0, 0, 0, 0, 1);
cairo_pattern_add_color_stop_rgba (radpat, 0.5, 0, 0, 0, 0);

cairo_set_source (cr, linpat);
cairo_mask (cr, radpat);
 

Proceso de dibujo

editar

Para poder crear una imagen, se tiene que preparar el contexto para cada uno de los verbos. Para usar cairo_stroke() o cairo_fill() se necesita primero una ruta. Para usar cairo_show_text() se tiene que posicionar el texto en su punto de inserción. Para usar cairo_mask() se necesita una segunda superficie fuente. Para las demás operaciones, incluyendo cairo_paint() sólo se necesitan una fuente primaria.

Hay tres tipos de fuentes principales en Cairo: colores, gradientes e imágenes. Los colores son los más simples; usan un color uniforme en toda la fuente. Se pueden seleccionar colores sin previas preparaciones con cairo_set_source_rgb() y cairo_set_source_rgba(). Usar cairo_set_source_rgb(cr, r, g, b) es equivalente a usar cairo_set_source_rgba(cr, r, g, b,1.0), lo cual pone el color fuente a su máximo nivel de opacidad.

Los gradientes describen una progresión de colores en función a su lugar de inicio y de fin, además de usar una serie de "paradas" a lo largo del camino. Los gradientes lineales se construyen a partir de dos puntos que se pasan a través de líneas paralelas, los cuales definen los lugares de inicio y de fin. Los gradientes radiales se construyen también a partir de dos puntos, pero cada uno tiene un radio asociado para el círculo que define los lugares de inicio y de fin. Las paradas se agregan a los gradientes con cairo_add_color_stop_rgb() y cairo_add_color_stop_rgba() que toman un color como cairo_set_source_rgb*() y un offset para indicar donde se aplica a los lugares de referencia. Los colores entre las paradas adyacentes se promedian en el espacio para mezclarlos de forma uniforme. El comportamiente entre los lugares de referencia pueden ser controlados con cairo_set_extend().

Las imágenes pueden ser superficies cargadas desde archivos existentes con cairo_image_surface_create_from_png() o también pueden ser superficies creadas con Cairo en un destino anterior. La forma más fácil de crear y usar un destino anterior como una fuente es con cairo_push_group(), con cairo_pop_group() o con cairo_pop_group_to_source(). Se usa cairo_pop_group_to_source() justo antes de seleccionar una nueva fuente, y cairo_pop_group() cuando se desea guardarlo, así que se puede seleccionar uno y otra vez con cairo_set_source().

Ejemplo de dibujo usando color
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_move_to (cr, 0, 0);
cairo_line_to (cr, 1, 1);
cairo_move_to (cr, 1, 0);
cairo_line_to (cr, 0, 1);
cairo_set_line_width (cr, 0.2);
cairo_stroke (cr);

cairo_rectangle (cr, 0, 0, 0.5, 0.5);
cairo_set_source_rgba (cr, 1, 0, 0, 0.80);
cairo_fill (cr);

cairo_rectangle (cr, 0, 0.5, 0.5, 0.5);
cairo_set_source_rgba (cr, 0, 1, 0, 0.60);
cairo_fill (cr);

cairo_rectangle (cr, 0.5, 0, 0.5, 0.5);
cairo_set_source_rgba (cr, 0, 0, 1, 0.40);
cairo_fill (cr);
 
Ejemplo de dibujo usando gradientes
int i, j;
cairo_pattern_t *radpat, *linpat;

radpat = cairo_pattern_create_radial (0.25, 0.25, 0.1,  0.5, 0.5, 0.5);
cairo_pattern_add_color_stop_rgb (radpat, 0,  1.0, 0.8, 0.8);
cairo_pattern_add_color_stop_rgb (radpat, 1,  0.9, 0.0, 0.0);

for (i=1; i<10; i++)
    for (j=1; j<10; j++)
        cairo_rectangle (cr, i/10.0 - 0.04, j/10.0 - 0.04, 0.08, 0.08);
cairo_set_source (cr, radpat);
cairo_fill (cr);

linpat = cairo_pattern_create_linear (0.25, 0.35, 0.75, 0.65);
cairo_pattern_add_color_stop_rgba (linpat, 0.00,  1, 1, 1, 0);
cairo_pattern_add_color_stop_rgba (linpat, 0.25,  0, 1, 0, 0.5);
cairo_pattern_add_color_stop_rgba (linpat, 0.50,  1, 1, 1, 0);
cairo_pattern_add_color_stop_rgba (linpat, 0.75,  0, 0, 1, 0.5);
cairo_pattern_add_color_stop_rgba (linpat, 1.00,  1, 1, 1, 0);

cairo_rectangle (cr, 0.0, 0.0, 1, 1);
cairo_set_source (cr, linpat);
cairo_fill (cr);
 

Creación de rutas

editar

Cairo siempre tiene una ruta activa. Si se llama la función cairo_stroke() se dibujará la ruta. Si se llama la función cairo_fill() se rellenará el interior de la ruta. Pero como la ruta inicial está vacía, ambas llamadas a tales funciones no representarán cambios al destino. En cada llamada a cairo_stroke() o a cairo_fill() la ruta se vacía para poder una nueva ruta.

Existen versiones alternativas de las funciones anteriores las cuales no vacían la ruta para que se puede volver a utilizar, estas funciones son: cairo_stroke_preserve() y cairo_fill_preserve().

Proceso de creación de rutas
Cuando se crean rutas, Cairo usa un sistema al estilo conecta los puntos. Comienza en 1, traza una línea a 2, luego a 3, y así sucesivamente. Cuando se comienza una ruta o una subruta, se designa un punto el cual todavía no tiene ningún otro conectado, para esto se usa la función cairo_move_to(). Con esto se cambia el punto de referencia actual sin realizar conexiones a otros puntos. También se puede mover el punto de forma relativa con cairo_rel_move_to(). Después de asignar el primer punto de referencia, se usan otras operaciones las cuales actualizan el punto de referencia y lo conectan de determinada forma.
cairo_move_to (cr, 0.25, 0.25);
 
Se pueden usar líneas rectas para unir los puntos de forma absoluta con cairo_line_to() o de forma relativa con cairo_rel_line_to(). El nuevo punto de referencia se actualiza, después de tales operaciones se encuentra al final de la línea.
cairo_line_to (cr, 0.5, 0.375);
cairo_rel_line_to (cr, 0.25, -0.125);
 
También se pueden usar arcos de un círculo para crear segmentos de ruta. En este caso el punto que se especifica no está en la ruta, sino que es el centro del círculo de tal arco. Ambos puntos, el punto inicial y el punto final del círculo deben de especificarse, tales puntos se conectan en sentido de las agujas del reloj con cairo_arc() y en sentido contrario con cairo_arc_negative(). Si el punto de referencia anterior no está en la nueva curva, se agrega una línea recta donde el arco empieza. El punto de referencia se actualiza a donde termina el arco. Sólo existen versiones absolutas (no número negativos).
cairo_arc (cr, 0.5, 0.5, 0.25 * sqrt(2), -0.25 * M_PI, 0.25 * M_PI);
 
También se pueden usar curvas de Bézier en Cairo. Si se usan, empiezan en el punto de referencia actual y uniformemente sigue la dirección hacia otros dos puntos, y finalmente llega a un tercer punto. Al igual que las líneas rectas, existen dos versiones, una absoluta que es cairo_curve_to() y una relativa que es cairo_rel_curve_to(). Cuando se usa la función relativa todos los puntos son relativos al punto de referencia anterior, en vez de ser relativos entre cada uno de ellos.
cairo_rel_curve_to (cr, -0.25, -0.125, -0.25, 0.125, -0.5, 0);
 
Cairo cierra la ruta trazando una línea recta hacia el inicio de la ruta. Esta línea puede ser útil para, por ejemplo, un polígono, pero no es útil para formas curvas. Una ruta abierta es una ruta continua que su punto inicial y su punto final no se encuentran donde mismo.
cairo_close_path (cr);
 

Programa mínimo de ejemplo en C

editar
#include <cairo.h>

int
main (int argc, char *argv[])
{
   cairo_surface_t *surface;
   cairo_t *cr;

   surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 240, 80);
   cr = cairo_create (surface);

   cairo_select_font_face (cr, "serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
   cairo_set_font_size (cr, 32.0);
   cairo_set_source_rgb (cr, 0.0, 0.0, 1.0);
   cairo_move_to (cr, 10.0, 50.0);
   cairo_show_text (cr, "Hello, world");
   cairo_destroy (cr);
   cairo_surface_write_to_png (surface, "hello.png");
   cairo_surface_destroy (surface);

   return 0;
}

Si tal archivo lo nombráramos como hello.c, la instrucción necesaria para compilarlo sería:

cc -o hello $(pkg-config --cflags --libs cairo) hello.c

Tras correr el programa hello el usuario obtendrá una imagen PNG llamada hello.png con el texto "Hello, world" escrito en color azul.

Véase también

editar

Enlaces externos

editar