Skip to main content

caligrama

Dale una imagen y un poema. Te devuelve el poema con la forma de la imagen.

PyPI Python 3.9+ CI Licencia MIT Hecho en Rust Documentación

Un corazón que late, escrito con un poema que corre por dentro. Generado con caligrama.

El título y este corazón los genera la propia librería con caligrama animar. Código en examples/latido.py.

Un caligrama es un poema cuyas letras dibujan aquello de lo que habla. Apollinaire los hacía a mano. Esta librería los hace con cualquier imagen que le pases: detecta la silueta, la reduce a una rejilla de caracteres y escribe tu texto dentro, letra por letra y en orden. Lo que sale es texto plano, así que puedes pegarlo en un chat, en un README, en un commit o en una tarjeta.

$ caligrama logo.jpeg -w auto --sin-repetir -f becquer.txt

         Podrá nubla
        rse el sol et
       ernamente; podr
        á secarse en u
  n instante el mar; podrá r
 omperse el eje de la  tierr
a como un débil crist al. ¡To
do sucede rá! Podrá la muerte
 cubrir me con su fúnebre cre
 spón;  pero jamás en mí pod
  rá ap agarse la llama de
        tu amor.

Y si se lo pides, cada letra toma el color que tiene la imagen en ese punto:

Ilustración de un árbol con copa verde y tronco café
la imagen
El mismo árbol escrito con un poema; la copa sale verde y el tronco café
el caligrama

caligrama arbol.png -w 70 --espacios sin --colores imagen -f poema.txt · código en examples/arbol.py

Instalación

pip install caligrama

Eso es todo. No arrastra dependencias de Python (ni Pillow, ni numpy): la lectura de la imagen y el dibujo se hacen en Rust, dentro de una sola wheel que sirve para Python 3.9 en adelante en Linux, macOS y Windows. Funciona sin conexión y no manda nada a ningún lado.

En diez segundos

Desde Python:

import caligrama

print(caligrama.dibujar("gato.png", "Te quiero más que a mi café de la mañana", ancho=50))

Desde la terminal:

caligrama gato.png -w 50 -t "Te quiero más que a mi café de la mañana"
caligrama gato.png -f poema.txt          # el texto desde un archivo
cat poema.txt | caligrama gato.png       # o desde stdin

La imagen puede ser una ruta, un pathlib.Path o los bytes crudos (lo que te devuelve requests, una base de datos o un upload). Lee PNG, JPEG, GIF, BMP y WebP.

Diseña el texto antes de escribirlo

Lo más frustrante de hacer caligramas a mano es escribir el poema y descubrir que no cabe, o que sobra media figura. caligrama analizar te dice de antemano cuánto espacio tienes:

$ caligrama analizar logo.jpeg -w 40 -t "Podrá nublarse el sol eternamente"

Silueta a 40 columnas × 16 filas
Caben 452 letras (los espacios cuentan) ≈ 75 palabras
Tramos: 26 (de 5 a 28 letras); cada hueco entre tramos puede partir una palabra

Plantilla (letras por fila a la derecha):
               #############               │  13
             #################             │  17
            ###################            │  19
     ########################## ######     │  32
    ########################### #######    │  34
  ...

Otros anchos:
  ancho  filas  letras  ≈palabras
     30     12     252        42
     40     16     452        75
     60     23     955       159
  ...

Tu texto: 33 letras. Cabe completo desde 11 columnas (-w auto). A 40 columnas sobran 419 letras.

La plantilla coincide celda por celda con el dibujo final (hay un test que lo garantiza), así que puedes contar letras por fila y ajustar tus versos a mano. Desde Python, caligrama.analizar() devuelve lo mismo en un diccionario.

Y si no quieres contar nada, ancho="auto" busca el ancho exacto en el que tu texto llena la figura una sola vez.

Animaciones, en la terminal o en SVG

El título de este README sale de un solo comando:

caligrama animar assets/titulo.png -t caligrama -w 160 --espacios sin --con-huecos \
    --colores "#ff2d55,#ff8a3d,#b44dff" --svg titulo.svg

Sin --svg, la animación se reproduce en la terminal hasta que pulses Ctrl+C. Hay dos movimientos, y se pueden combinar:

  • --paso N: el texto avanza N letras por fotograma y parece correr por dentro de la figura. Por defecto, animar calcula cuántos fotogramas hacen falta para que el texto dé la vuelta completa, así que el bucle no tiene salto.
  • --latido F: la figura late con un pulso doble y se encoge hasta el F·100 % de su tamaño entre latidos.

Desde Python son tres funciones que encajan entre sí:

fotos = caligrama.animar("corazon.png", poema, paso=3, latido=0.22, ancho=56)   # list[str]
caligrama.reproducir(fotos, intervalo=0.07, colores=["#ff5f8f", "#ff2d55"])        # en la terminal
svg = caligrama.a_svg(fotos, intervalo=0.07, fondo="#14111a")                       # para tu README o tu web

Los fotogramas son texto normal, todos del mismo tamaño y alineados, así que también puedes llevarlos a un GIF, a una web o a donde quieras. Los colores de la terminal usan ANSI de 24 bits: funcionan en Windows Terminal, iTerm2, GNOME Terminal y en casi cualquier terminal moderna.

Los colores de la imagen

Con color=True (o --colores imagen) cada letra se pinta con el color que tiene la imagen en ese punto. Así sale el árbol del principio: nadie le dijo dónde estaba la copa ni dónde el tronco. El color de cada celda es el promedio de sus píxeles de figura, así que el blanco del fondo no aclara los bordes.

print(caligrama.dibujar("arbol.png", poema, ancho=70, espacios="sin", color=True))
svg = caligrama.a_svg(caligrama.animar("arbol.png", poema, fotogramas=24, color=True), fondo="#111")
caligrama arbol.png -f poema.txt -w 70 --colores imagen
caligrama animar arbol.png -f poema.txt --colores imagen --svg arbol.svg

El resultado sigue siendo un str, con los colores en ANSI; a_svg y reproducir los respetan tal cual. Si además pasas un degradado con colores=, el degradado manda.

Dos cosas a tener en cuenta. En el SVG cada letra de color lleva su propia etiqueta, así que una animación larga pesa: limita los fotogramas si va a un README. Y una figura muy oscura (un gato negro) casi no se ve sobre una terminal oscura; es el color real de la imagen.

Frente a otras herramientas

Puse el árbol de arriba y el mismo poema en todo lo que encontré para dibujar imágenes con texto en la terminal, a 70 columnas:

Qué dibuja Tiempo Import Paquetes Palabras que se leen Colores
caligrama color=True tu texto, con la forma y los colores de la imagen 2,1 ms 1 ms 1 80 % 1161
Pillow + rich, a mano tu texto sin espacios, con 2 colores fijos 13,7 ms 40 ms 5 17 % 2
ascii_magic símbolos según el brillo, 16 colores 22,1 ms 42 ms 2 0 % 5
pywhatkit símbolos según el brillo, siempre a 80 columnas 1,6 ms 904 ms 27 0 % 0
viu la foto, dos píxeles por celda con ▄ 3,2 ms¹ — binario 0 % 3007
catimg la foto, dos píxeles por celda con ▀ 3,3 ms¹ — binario 0 % 3184

Mediana de 5 ejecuciones en un portátil con WSL2 y Python 3.11; el import se mide aparte, en un proceso nuevo. ¹ Incluye arrancar el programa, que es como se usan. "Palabras que se leen" es el porcentaje de palabras del dibujo que son palabras enteras del poema. "Paquetes" cuenta todo lo que se instala, dependencias y el propio paquete incluidos.

Si lo que quieres es ver una foto en la terminal, viu y catimg ganan sin discusión: pintan dos píxeles de color por celda y ningún dibujo hecho con letras se les acerca. Pero no llevan mensaje, y si copias su salida como texto plano te queda un rectángulo de bloques. ascii_magic y pywhatkit cambian el brillo por símbolos: la imagen se reconoce y el texto no existe.

Hacerlo a mano con Pillow sirve hasta que la imagen tiene ruido de JPEG, un amarillo claro sobre blanco o un hueco en medio; ahí empiezan los ajustes que caligrama ya trae (la sección siguiente cuenta cuáles). En la tabla también se ve lo otro: sin espacios las palabras se pegan y casi nada se lee. caligrama con espacios="sin", como el árbol de arriba, baja al 13 %. Es el precio de una figura más sólida.

Para repetirlo con tus imágenes: python bench/benchmark.py. Deja en bench/resultados/ un informe HTML con todos los dibujos lado a lado.

Por qué se ve bien con imágenes reales

Casi todas las herramientas de arte ASCII deciden qué es figura mirando el brillo: lo oscuro se pinta y lo claro se deja vacío. Eso falla más de lo que parece. En el logo de Python, la serpiente amarilla es casi tan clara como el fondo blanco y desaparece. En un pingüino, la barriga blanca queda como un agujero.

caligrama hace otra cosa:

  1. Estima el color del fondo con los píxeles del borde de la imagen y marca como figura lo que se aleja de ese color, con un umbral automático que se ajusta al ruido del JPEG.
  2. Rellena lo que está encerrado por la figura aunque sea del color del fondo. La barriga del pingüino vuelve a ser pingüino. Si quieres conservar los huecos (el ojo del logo, el centro de una dona), usa huecos=True.
  3. Si la imagen tiene transparencia, usa el canal alfa y listo.
  4. suavizar=N une trazos punteados o hechos de letras antes de muestrear, útil para logos de línea fina o imágenes que ya son arte ASCII.
  5. Corrige la proporción de la terminal (un carácter es el doble de alto que de ancho) para que un círculo salga redondo.
  6. Recorre el texto por grafemas, no por bytes: tildes, ñ, ü y emojis compuestos no se parten.

Todas las opciones

Python Terminal Por defecto Qué hace
ancho -w, --ancho 60 Columnas de salida. "auto" elige el menor ancho donde cabe todo el texto.
repetir --sin-repetir True Repite el texto hasta llenar la figura.
espacios --espacios "normal" normal junta espacios y separa repeticiones con uno; sin los quita todos (figura más sólida); todos los deja tal cual.
huecos --con-huecos False Respeta los huecos interiores del color del fondo.
suavizar --suavizar 0 Radio en píxeles para cerrar trazos punteados.
invertir --invertir False Escribe alrededor de la figura en vez de dentro.
umbral --umbral auto Umbral 0–255 de separación figura/fondo, por si el automático no te convence.
aspecto --aspecto 2.0 Alto/ancho de un carácter en tu terminal o fuente.
desfase --desfase 0 Empieza a escribir el texto N letras más adelante.
color --colores imagen False Pinta cada letra con el color de la imagen en su posición (ANSI de 24 bits).
colores --colores sin color Degradado horizontal en hexadecimal, en la terminal y en el SVG.
(a_svg) --svg Guarda un SVG en vez de imprimir (animado con animar).

Solo para animar: fotogramas/--fotogramas, paso/--paso, latido/--latido, intervalo/--intervalo y, en la terminal, veces/--veces.

caligrama --help muestra lo mismo.

La documentación completa (en español e inglés) explica cada opción con ejemplos, recetas (web, Jupyter, tarjetas, banners), la referencia del CLI y qué hacer cuando la silueta no sale bien. Full documentation in English: maosuarez.github.io/Caligrama/?lang=en.

Ideas para usarlo

  • Una tarjeta de cumpleaños que es su foto escrita con los mensajes de todos.
  • El banner de bienvenida de tu CLI con tu logo y el nombre de la herramienta.
  • Un mensaje para alguien especial, con la forma de algo que solo ustedes entienden.
  • Una pantalla de carga para tu CLI con tu logo latiendo mientras el texto corre por dentro.

Para verlo en acción:

python examples/demo.py          # recorrido por la API
bash examples/demo.sh            # recorrido por la terminal
python examples/latido.py        # el corazón latiendo en tu terminal
python examples/titulo.py        # el título de este README, animado en tu terminal
python examples/arbol.py         # el árbol a color del principio

Cómo está hecho

El núcleo (src/core.rs) es Rust puro: decodifica la imagen con el crate image, construye la máscara, la muestrea a una rejilla de caracteres y rellena. Las animaciones, el SVG y los colores viven en src/animacion.rs, también en Rust. Encima hay una capa fina de PyO3 (src/lib.rs) que expone dibujar, analizar, animar, a_svg, reproducir y el comando caligrama, y maturin lo empaqueta como wheel abi3. El CLI también es Rust, así que se comporta igual que la API.

Contribuir

Los issues y PRs son bienvenidos. Para montar el entorno:

git clone https://github.com/maosuarez/caligrama && cd caligrama
python -m venv .venv && source .venv/bin/activate
pip install maturin pytest
maturin develop
cargo test && pytest

Los detalles están en CONTRIBUTING.md.

Licencia

MIT. Úsalo en lo que quieras, también en proyectos comerciales.


In English

caligrama turns any image into a calligram: it finds the silhouette and writes your text inside it, in reading order, returning plain text you can paste anywhere.

pip install caligrama
caligrama cat.png -w 50 -t "your poem here"
import caligrama
print(caligrama.dibujar("cat.png", "your poem here", ancho="auto"))
info = caligrama.analizar("cat.png", "your poem here")   # capacity, per-row counts, template
frames = caligrama.animar("heart.png", "your poem ", paso=2, latido=0.2)
caligrama.reproducir(frames)                               # animate in the terminal
open("heart.svg", "w").write(caligrama.a_svg(frames))       # or export an animated SVG
print(caligrama.dibujar("tree.png", "your poem", color=True)) # each letter takes the image's color

Compared with image viewers (viu, catimg) and ASCII-art tools (ascii_magic, pywhatkit) on the same image, caligrama is the one that writes your text legibly: 80 % of words intact, against 17 % for a hand-written Pillow + rich script and 0 % for the rest. It has no dependencies and imports in about 1 ms. Viewers are more faithful to the photo; they just can't carry a message. Run python bench/benchmark.py to reproduce.

The core is written in Rust (PyO3 + maturin) and ships as a single abi3 wheel with zero Python dependencies. Instead of a brightness threshold it detects the background from the image border and fills enclosed regions, so light-on-white subjects keep their shape. The API and CLI flags are in Spanish; the table above maps every option.

Metadata

Release files for caligrama 0.3.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for caligrama 0.3.3
File Size Uploaded
caligrama-0.3.3.tar.gz 110.0 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for caligrama 0.3.3
File
caligrama-0.3.3-cp39-abi3-win_amd64.whl CPython 3.9 abi3 Windows x86-64 Details
caligrama-0.3.3-cp39-abi3-musllinux_1_2_x86_64.whl CPython 3.9 abi3 Linux musl 1.2+ x86-64 Details
caligrama-0.3.3-cp39-abi3-musllinux_1_2_aarch64.whl CPython 3.9 abi3 Linux musl 1.2+ ARM64 Details
caligrama-0.3.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.9 abi3 Linux glibc 2.17+ x86-64 Details
caligrama-0.3.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.9 abi3 Linux glibc 2.17+ ARM64 Details
caligrama-0.3.3-cp39-abi3-macosx_11_0_arm64.whl CPython 3.9 abi3 macOS 11.0+ ARM64 Details
caligrama-0.3.3-cp39-abi3-macosx_10_12_x86_64.whl CPython 3.9 abi3 macOS 10.12+ x86-64 Details

Total release size: 5.7 MB

Release files / caligrama-0.3.3.tar.gz

Download URL caligrama-0.3.3.tar.gz
Size 110.0 kB
Tags Source
SHA-256 checksum
How to use checksums
85507fe20b5082fc7c1f63914f909a3155b2a7d2f338b4628c88e4bf471bb283
BLAKE2b-256 checksum
How to use checksums
25e75769f072db3fb67ddbbe813800b06054f2eda82d63b017dfe2745546ef1d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

Release files / caligrama-0.3.3-cp39-abi3-win_amd64.whl

Download URL caligrama-0.3.3-cp39-abi3-win_amd64.whl
Size 703.0 kB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
0ec16899e742a6d9b20d1de25ee235f59adccb69db1d8ee1b5f7cdbb313f3ae6
BLAKE2b-256 checksum
How to use checksums
acee454d522ed7ed30d6a09a91d07c1119078f2b27909db9a3f36539b056290c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

Release files / caligrama-0.3.3-cp39-abi3-musllinux_1_2_x86_64.whl

Download URL caligrama-0.3.3-cp39-abi3-musllinux_1_2_x86_64.whl
Size 981.0 kB
Tags CPython 3.9 Linux musl 1.2+ x86-64 abi3
SHA-256 checksum
How to use checksums
da7c64d47d8417c1d932dba3c412925e4ae2295730f6cad8b7cfba52a4cc6124
BLAKE2b-256 checksum
How to use checksums
1f59ac2a3bac244f363450fe7a3b4877f4e5ad1d159145d3e9914ce94f57579d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

Release files / caligrama-0.3.3-cp39-abi3-musllinux_1_2_aarch64.whl

Download URL caligrama-0.3.3-cp39-abi3-musllinux_1_2_aarch64.whl
Size 910.1 kB
Tags CPython 3.9 Linux musl 1.2+ ARM64 abi3
SHA-256 checksum
How to use checksums
24dd34323ea5816264d435571092c23a48fe68d1ac32a096a11e5a6e1a23450a
BLAKE2b-256 checksum
How to use checksums
8743dc6cf049a231d92b57b1d0b44f524a666d46f7ddf5383afd350372b8f4d9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

Release files / caligrama-0.3.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL caligrama-0.3.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 768.9 kB
Tags CPython 3.9 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
824714ac31aacdf744defd6202c2af700f47686b98386ab057789d30a0522af3
BLAKE2b-256 checksum
How to use checksums
c11c2ed930b58077f5de61ab24182b08ea0e50ce00d923077748d21b5d0b993d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

Release files / caligrama-0.3.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL caligrama-0.3.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 732.0 kB
Tags CPython 3.9 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
21c93f3e4bade7ea9dc08c8058dd005290ccf50a1f34d0e0b199224e64d43d48
BLAKE2b-256 checksum
How to use checksums
dcc7ca79dcc611b1be4492f448c67a8b4811946d6a8a96528a05a4d8f1105eb7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

Release files / caligrama-0.3.3-cp39-abi3-macosx_11_0_arm64.whl

Download URL caligrama-0.3.3-cp39-abi3-macosx_11_0_arm64.whl
Size 710.2 kB
Tags CPython 3.9 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
5302d5523019af673972ebaca84a94114aa53f8fadaa7a5387ed7ac5d9ad663d
BLAKE2b-256 checksum
How to use checksums
33187572113a21e8916794355b5497a0cd2c59202fba3d38690d364fd04c5e94
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

Release files / caligrama-0.3.3-cp39-abi3-macosx_10_12_x86_64.whl

Download URL caligrama-0.3.3-cp39-abi3-macosx_10_12_x86_64.whl
Size 739.7 kB
Tags CPython 3.9 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
142d42acb5ab75daeb6cd40987cd9e88814d99b143e34059db4ddff5e0f898b4
BLAKE2b-256 checksum
How to use checksums
499a0163f44a822332ad2a049d505728cbc202f0f3ad354cff9de2823a9847ef
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.3 This release

8 release files

0.3.2

8 release files

0.3.1

8 release files

0.3.0

8 release files

0.2.0

8 release files

0.1.0

8 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page