caligrama 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,9 @@
1
+ target/
2
+ .venv/
3
+ __pycache__/
4
+ *.so
5
+ .pytest_cache/
6
+ live-test/
7
+ .playwright-mcp/
8
+ .code-review-graph/
9
+ dist/
@@ -0,0 +1,22 @@
1
+ # Changelog
2
+
3
+ El formato sigue [Keep a Changelog](https://keepachangelog.com/es-ES/1.1.0/) y el proyecto usa [versionado semántico](https://semver.org/lang/es/).
4
+
5
+ ## [Sin publicar]
6
+
7
+ ## [0.1.0] - 2026-09-24
8
+
9
+ Primera versión.
10
+
11
+ ### Añadido
12
+
13
+ - `caligrama.dibujar(imagen, texto, ...)`: escribe el texto dentro de la silueta y devuelve un `str`. Acepta ruta, `PathLike` o bytes; lee PNG, JPEG, GIF, BMP y WebP.
14
+ - `caligrama.analizar(imagen, texto=None, ...)`: capacidad en letras y palabras, letras por fila, tramos, plantilla y, si se pasa texto, el ancho donde cabe completo.
15
+ - Comando `caligrama` con los subcomandos de dibujo y `analizar`.
16
+ - Detección de figura por distancia al color del borde, con umbral automático ajustado al ruido, y uso del canal alfa si existe.
17
+ - Relleno de huecos interiores (`huecos=True` para conservarlos).
18
+ - `ancho="auto"`, `espacios="normal"|"sin"|"todos"`, `suavizar`, `invertir`, `umbral`, `aspecto`, `repetir`.
19
+ - Wheel `abi3` para Python 3.9+ sin dependencias de Python.
20
+
21
+ [Sin publicar]: https://github.com/maosuarez/caligrama/compare/v0.1.0...HEAD
22
+ [0.1.0]: https://github.com/maosuarez/caligrama/releases/tag/v0.1.0
@@ -0,0 +1,83 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Estado
6
+
7
+ MVP funcional. Paquete/crate/módulo: **`caligrama`** (un caligrama es un poema cuyo texto dibuja una figura). API Python y CLI en español.
8
+
9
+ ```python
10
+ import caligrama
11
+ print(caligrama.dibujar("flor.png", "Podrá nublarse el sol...", ancho=60))
12
+ # imagen: str | os.PathLike | bytes. ancho: int | "auto". Opcionales: aspecto=2.0, repetir=True, espacios="normal"|"sin"|"todos", umbral=None (auto), invertir=False, huecos=False, suavizar=0
13
+ caligrama.analizar("flor.png", texto=None, ancho=60) # dict: letras, palabras_aprox, letras_por_fila, tramos, plantilla, letras_por_ancho, [ancho_recomendado, sobran]
14
+ ```
15
+ ```bash
16
+ caligrama flor.png -w 60 -t "mensaje" # o -f poema.txt, o por stdin; -w auto
17
+ caligrama analizar flor.png [-f poema.txt] # informe para diseñar el texto (no lee stdin)
18
+ ```
19
+
20
+ ## Objetivo
21
+
22
+ Librería de Python escrita **100% en Rust** (PyO3 + maturin) que, de forma local y offline:
23
+
24
+ 1. Recibe una imagen (ruta o bytes).
25
+ 2. Detecta la silueta/contorno del objeto.
26
+ 3. Rellena el interior de la silueta con un mensaje o poema, carácter a carácter, dejando espacios fuera.
27
+ 4. Devuelve **solo un `str`** con saltos de línea cuya forma reproduce la imagen.
28
+
29
+ Debe poder usarse desde cualquier script Python (`import ...`) y desde la terminal.
30
+
31
+ Referencias de la idea en `../flor-amarilla/`:
32
+ - `archivo.txt`: arte ASCII por densidad generado con `pywhatkit.image_to_ascii_art` (80 columnas). Es la inspiración de formato, **no** el resultado buscado: aquí los caracteres son el texto del poema, no una rampa de densidad (`.:!*%$@&`).
33
+ - `test.jpeg`: imagen de prueba (logo de Python, 189x148, JPEG sin alpha, fondo blanco, dos colores azul/amarillo).
34
+ - `art.py`, `poema.py`: prototipos en Python (pywhatkit, Pillow). No se deben usar como dependencias.
35
+
36
+ ## Restricciones
37
+
38
+ - Toda la lógica (decodificar imagen, segmentar, redimensionar, componer texto) vive en Rust. Nada de Pillow/numpy/pywhatkit en runtime; el paquete Python no debe tener dependencias.
39
+ - Decodificación de imágenes con crates de Rust (p. ej. `image`).
40
+ - El CLI también debe ser Rust: expuesto como `[project.scripts]` en `pyproject.toml` apuntando a un `#[pyfunction]` que lee `sys.argv`, o como binario Rust aparte. No escribir el CLI en Python.
41
+ - Usar `abi3` en PyO3 (feature `abi3-py39`: pyo3 0.29) para que una sola wheel funcione en cualquier versión de Python ≥ mínima.
42
+
43
+ ## Arquitectura
44
+
45
+ - `src/core.rs`: núcleo puro Rust, sin PyO3. Pipeline `dibujar` = `mascara` → `rejilla` → `rellenar`. Tests unitarios aquí con imágenes sintéticas.
46
+ - `mascara`: si la imagen tiene transparencia usa el alfa; si no, estima el fondo como la mediana de los píxeles del borde y umbraliza la distancia RGB con Otsu. La luminancia sola no sirve (en `tests/data/python.jpeg` el amarillo es casi tan claro como el fondo blanco).
47
+ - Umbral automático = `min(Otsu, p99 del ruido en el borde + 10)`. Otsu solo corta entre tonos de la figura y deja bordes suaves como fondo.
48
+ - `suavizar=N`: cierre morfológico (dilatar + erosionar, cuadrado de radio N px, separable con sumas prefijas) para unir trazos punteados o hechos de letras. Va **antes** del relleno de huecos: un contorno cerrado hace que su interior pase a ser figura; combinar con `huecos=True` para conservar el hueco.
49
+ - Después rellena huecos: fondo = lo parecido al color del borde **y conectado al borde** (flood fill). Así una barriga blanca sobre fondo blanco sigue siendo figura. `huecos=True` / `--con-huecos` lo desactiva (p. ej. para conservar el ojo del logo de Python).
50
+ - `rejilla`: celda = figura si ≥50 % de sus píxeles lo son; `aspecto` corrige que los caracteres de terminal son ~2x más altos que anchos.
51
+ - `rellenar`: espacios según `Espacios` (`Normal` colapsa y separa repeticiones con un espacio; `Sin` los quita y pega repeticiones; `Todos` conserva cada uno, `\n`/tab = 1 espacio, sin separador, ignorando saltos finales). `contar_letras` usa el mismo modo, así que `ancho="auto"` y `analizar` cuentan igual que el dibujo. Además recorre por grafemas (`unicode-segmentation`), recorta filas vacías y el margen izquierdo común.
52
+ - `Silueta`: máscara calculada una vez y muestreada a varios anchos. `ancho_para` = búsqueda binaria del menor ancho cuya capacidad (celdas de figura) ≥ letras del texto, hasta `ANCHO_AUTO_MAX`. `analizar` y `dibujar` usan la misma rejilla y recorte, así que `plantilla` coincide celda a celda con el dibujo (hay test de eso).
53
+ - `src/lib.rs`: binding fino. Convierte `core::Error` a `OSError` (E/S) o `ValueError`. `informe` alimenta tanto `analizar` (dict) como `caligrama analizar` (texto). Contiene también el CLI (`cli` lee `sys.argv`, devuelve el código de salida); `pyproject.toml` lo expone como `[project.scripts] caligrama = "caligrama:cli"`. El parseo de argumentos es manual para no añadir dependencias.
54
+ - En el enum `Imagen`, `Bytes` debe ir antes que `Ruta`: `PathBuf` también acepta `bytes` al extraer.
55
+ - `tests/test_caligrama.py`: tests de la API Python y del CLI (vía subprocess). `tests/data/referencia_ascii.txt` es la salida de pywhatkit de referencia (80×34).
56
+
57
+ ## Comandos
58
+
59
+ El entorno tiene conda activo (`CONDA_PREFIX`); maturin se niega a correr si también está `VIRTUAL_ENV`, y sin venv activo instala en el env de conda. Para trabajar en `.venv`:
60
+
61
+ ```bash
62
+ uv venv .venv && uv pip install --python .venv/bin/python maturin pytest # una vez
63
+ unset CONDA_PREFIX; export VIRTUAL_ENV=$PWD/.venv PATH=$PWD/.venv/bin:$PATH
64
+
65
+ maturin develop --uv # compila e instala en .venv (--release para medir rendimiento)
66
+ maturin build --release # wheel abi3 (cp39-abi3) en target/wheels/ (o en $CARGO_TARGET_DIR)
67
+
68
+ cargo test # tests del núcleo Rust
69
+ cargo test rellenar # filtra tests Rust por nombre
70
+ pytest -q tests # API Python + CLI (requiere maturin develop antes)
71
+ pytest tests/test_caligrama.py::test_errores
72
+
73
+ cargo fmt && cargo clippy --all-targets -- -D warnings
74
+ ```
75
+
76
+ ## Publicación
77
+
78
+ - Repo: https://github.com/maosuarez/caligrama · PyPI: https://pypi.org/p/caligrama
79
+ - `.github/workflows/ci.yml`: fmt, clippy, `cargo test` y pytest + `examples/demo.py` en Linux/macOS/Windows × Python 3.9/3.13.
80
+ - `.github/workflows/release.yml`: al empujar un tag `vX.Y.Z` compila wheels abi3 (manylinux/musllinux x86_64+aarch64, Windows x64, macOS x86_64+arm64) y sdist, publica en PyPI con Trusted Publishing (environment `pypi`, sin tokens) y crea el GitHub Release. La versión sale de `Cargo.toml`.
81
+ - `caligrama.pyi` son las firmas públicas: actualizarlas junto con `src/lib.rs`.
82
+ - `assets/latido.svg` (animación del README) se regenera con `python examples/latido.py --svg assets/latido.svg`. El README usa URLs absolutas de GitHub porque también se muestra en PyPI.
83
+ - `live-test/` está en `.gitignore`: carpeta local para probar imágenes (`./live-test/probar.sh [ancho] [opciones]`).
@@ -0,0 +1,7 @@
1
+ # Código de conducta
2
+
3
+ Este proyecto adopta el [Contributor Covenant 2.1](https://www.contributor-covenant.org/es/version/2/1/code_of_conduct/).
4
+
5
+ En corto: trata a los demás con respeto, critica ideas y no a personas, y recuerda que aquí se viene a escribir poemas con forma de gato.
6
+
7
+ Para reportar un comportamiento inaceptable, escribe a maosuarezbarrer@gmail.com. Los reportes se tratan con confidencialidad.
@@ -0,0 +1,46 @@
1
+ # Contribuir a caligrama
2
+
3
+ Gracias por pasar por aquí. Cualquier aporte sirve: un bug con una imagen que se dibuja mal, una idea de opción nueva, un ejemplo bonito para la galería o un PR.
4
+
5
+ ## Entorno
6
+
7
+ Necesitas Rust estable y Python 3.9 o más reciente.
8
+
9
+ ```bash
10
+ python -m venv .venv && source .venv/bin/activate
11
+ pip install maturin pytest
12
+ maturin develop # compila e instala la extensión en el venv
13
+ ```
14
+
15
+ Si usas conda y maturin se queja de que `VIRTUAL_ENV` y `CONDA_PREFIX` están definidos a la vez, haz `unset CONDA_PREFIX` en esa terminal.
16
+
17
+ ## Antes de abrir un PR
18
+
19
+ ```bash
20
+ cargo fmt --check
21
+ cargo clippy --all-targets -- -D warnings
22
+ cargo test # núcleo en Rust
23
+ pytest -q tests # API de Python y CLI
24
+ ```
25
+
26
+ La CI corre lo mismo en Linux, macOS y Windows.
27
+
28
+ ## Dónde va cada cosa
29
+
30
+ - `src/core.rs`: todo el algoritmo, sin nada de Python. Los tests del núcleo van aquí, con imágenes sintéticas.
31
+ - `src/lib.rs`: la capa de PyO3 y el CLI. Debe seguir siendo delgada.
32
+ - `caligrama.pyi`: las firmas para autocompletado. Si cambias la API, actualízala.
33
+ - `tests/`: tests de Python y del comando.
34
+
35
+ ## Reglas de la casa
36
+
37
+ - La librería no puede depender de paquetes de Python. Si algo hace falta, se hace en Rust.
38
+ - La API y las opciones del CLI están en español. Mantén ese idioma en los nombres nuevos.
39
+ - Un cambio de comportamiento viene con su test.
40
+ - Anota el cambio en `CHANGELOG.md` bajo "Sin publicar".
41
+
42
+ ## Publicar una versión (mantenedores)
43
+
44
+ 1. Sube la versión en `Cargo.toml` y mueve las notas del CHANGELOG.
45
+ 2. `git tag vX.Y.Z && git push origin vX.Y.Z`.
46
+ 3. El workflow `Release` compila las wheels, publica en PyPI con Trusted Publishing y crea el release en GitHub.
@@ -0,0 +1,346 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 4
4
+
5
+ [[package]]
6
+ name = "adler2"
7
+ version = "2.0.1"
8
+ source = "registry+https://github.com/rust-lang/crates.io-index"
9
+ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
10
+
11
+ [[package]]
12
+ name = "autocfg"
13
+ version = "1.5.1"
14
+ source = "registry+https://github.com/rust-lang/crates.io-index"
15
+ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
16
+
17
+ [[package]]
18
+ name = "bitflags"
19
+ version = "2.13.2"
20
+ source = "registry+https://github.com/rust-lang/crates.io-index"
21
+ checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06"
22
+
23
+ [[package]]
24
+ name = "bytemuck"
25
+ version = "1.25.2"
26
+ source = "registry+https://github.com/rust-lang/crates.io-index"
27
+ checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797"
28
+
29
+ [[package]]
30
+ name = "byteorder-lite"
31
+ version = "0.1.0"
32
+ source = "registry+https://github.com/rust-lang/crates.io-index"
33
+ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
34
+
35
+ [[package]]
36
+ name = "caligrama"
37
+ version = "0.1.0"
38
+ dependencies = [
39
+ "image",
40
+ "pyo3",
41
+ "unicode-segmentation",
42
+ ]
43
+
44
+ [[package]]
45
+ name = "cfg-if"
46
+ version = "1.0.5"
47
+ source = "registry+https://github.com/rust-lang/crates.io-index"
48
+ checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
49
+
50
+ [[package]]
51
+ name = "color_quant"
52
+ version = "1.1.0"
53
+ source = "registry+https://github.com/rust-lang/crates.io-index"
54
+ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
55
+
56
+ [[package]]
57
+ name = "crc32fast"
58
+ version = "1.5.2"
59
+ source = "registry+https://github.com/rust-lang/crates.io-index"
60
+ checksum = "01a7799fd6b852db0e61728dde9a204c423b44d689dbd432522543614b490e78"
61
+ dependencies = [
62
+ "cfg-if",
63
+ ]
64
+
65
+ [[package]]
66
+ name = "fdeflate"
67
+ version = "0.3.7"
68
+ source = "registry+https://github.com/rust-lang/crates.io-index"
69
+ checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
70
+ dependencies = [
71
+ "simd-adler32",
72
+ ]
73
+
74
+ [[package]]
75
+ name = "flate2"
76
+ version = "1.1.10"
77
+ source = "registry+https://github.com/rust-lang/crates.io-index"
78
+ checksum = "6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb"
79
+ dependencies = [
80
+ "crc32fast",
81
+ "miniz_oxide 0.9.1",
82
+ "zlib-rs",
83
+ ]
84
+
85
+ [[package]]
86
+ name = "gif"
87
+ version = "0.14.2"
88
+ source = "registry+https://github.com/rust-lang/crates.io-index"
89
+ checksum = "ee8cfcc411d9adbbaba82fb72661cc1bcca13e8bba98b364e62b2dba8f960159"
90
+ dependencies = [
91
+ "color_quant",
92
+ "weezl",
93
+ ]
94
+
95
+ [[package]]
96
+ name = "heck"
97
+ version = "0.5.0"
98
+ source = "registry+https://github.com/rust-lang/crates.io-index"
99
+ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
100
+
101
+ [[package]]
102
+ name = "image"
103
+ version = "0.25.10"
104
+ source = "registry+https://github.com/rust-lang/crates.io-index"
105
+ checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104"
106
+ dependencies = [
107
+ "bytemuck",
108
+ "byteorder-lite",
109
+ "color_quant",
110
+ "gif",
111
+ "image-webp",
112
+ "moxcms",
113
+ "num-traits",
114
+ "png",
115
+ "zune-core",
116
+ "zune-jpeg",
117
+ ]
118
+
119
+ [[package]]
120
+ name = "image-webp"
121
+ version = "0.2.4"
122
+ source = "registry+https://github.com/rust-lang/crates.io-index"
123
+ checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3"
124
+ dependencies = [
125
+ "byteorder-lite",
126
+ "quick-error",
127
+ ]
128
+
129
+ [[package]]
130
+ name = "libc"
131
+ version = "0.2.189"
132
+ source = "registry+https://github.com/rust-lang/crates.io-index"
133
+ checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
134
+
135
+ [[package]]
136
+ name = "miniz_oxide"
137
+ version = "0.8.9"
138
+ source = "registry+https://github.com/rust-lang/crates.io-index"
139
+ checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
140
+ dependencies = [
141
+ "adler2",
142
+ "simd-adler32",
143
+ ]
144
+
145
+ [[package]]
146
+ name = "miniz_oxide"
147
+ version = "0.9.1"
148
+ source = "registry+https://github.com/rust-lang/crates.io-index"
149
+ checksum = "b63fbc4a50860e98e7b2aa7804ded1db5cbc3aff9193adaff57a6931bf7c4b4c"
150
+ dependencies = [
151
+ "adler2",
152
+ "simd-adler32",
153
+ ]
154
+
155
+ [[package]]
156
+ name = "moxcms"
157
+ version = "0.8.1"
158
+ source = "registry+https://github.com/rust-lang/crates.io-index"
159
+ checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b"
160
+ dependencies = [
161
+ "num-traits",
162
+ "pxfm",
163
+ ]
164
+
165
+ [[package]]
166
+ name = "num-traits"
167
+ version = "0.2.19"
168
+ source = "registry+https://github.com/rust-lang/crates.io-index"
169
+ checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
170
+ dependencies = [
171
+ "autocfg",
172
+ ]
173
+
174
+ [[package]]
175
+ name = "once_cell"
176
+ version = "1.21.4"
177
+ source = "registry+https://github.com/rust-lang/crates.io-index"
178
+ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
179
+
180
+ [[package]]
181
+ name = "png"
182
+ version = "0.18.1"
183
+ source = "registry+https://github.com/rust-lang/crates.io-index"
184
+ checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61"
185
+ dependencies = [
186
+ "bitflags",
187
+ "crc32fast",
188
+ "fdeflate",
189
+ "flate2",
190
+ "miniz_oxide 0.8.9",
191
+ ]
192
+
193
+ [[package]]
194
+ name = "portable-atomic"
195
+ version = "1.15.0"
196
+ source = "registry+https://github.com/rust-lang/crates.io-index"
197
+ checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
198
+
199
+ [[package]]
200
+ name = "proc-macro2"
201
+ version = "1.0.107"
202
+ source = "registry+https://github.com/rust-lang/crates.io-index"
203
+ checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
204
+ dependencies = [
205
+ "unicode-ident",
206
+ ]
207
+
208
+ [[package]]
209
+ name = "pxfm"
210
+ version = "0.1.30"
211
+ source = "registry+https://github.com/rust-lang/crates.io-index"
212
+ checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea"
213
+
214
+ [[package]]
215
+ name = "pyo3"
216
+ version = "0.29.2"
217
+ source = "registry+https://github.com/rust-lang/crates.io-index"
218
+ checksum = "4688ddedf473e32662b9b067670129a8afb8c18e351482c70d62ba4a88171e8b"
219
+ dependencies = [
220
+ "libc",
221
+ "once_cell",
222
+ "portable-atomic",
223
+ "pyo3-build-config",
224
+ "pyo3-ffi",
225
+ "pyo3-macros",
226
+ ]
227
+
228
+ [[package]]
229
+ name = "pyo3-build-config"
230
+ version = "0.29.2"
231
+ source = "registry+https://github.com/rust-lang/crates.io-index"
232
+ checksum = "f41027e41b4bd03f6e60f9f417fe24a6341a6bb744edd62b6f709f2a52ea30e9"
233
+ dependencies = [
234
+ "target-lexicon",
235
+ ]
236
+
237
+ [[package]]
238
+ name = "pyo3-ffi"
239
+ version = "0.29.2"
240
+ source = "registry+https://github.com/rust-lang/crates.io-index"
241
+ checksum = "e591a95526fead067432c3b3a33fc74770b87b1e04e73671090d9c2055a2b327"
242
+ dependencies = [
243
+ "libc",
244
+ "pyo3-build-config",
245
+ ]
246
+
247
+ [[package]]
248
+ name = "pyo3-macros"
249
+ version = "0.29.2"
250
+ source = "registry+https://github.com/rust-lang/crates.io-index"
251
+ checksum = "73225868fc1cd84eef2c3c230ddb91273bf1de46aeb8a4248da76d32a0924a1c"
252
+ dependencies = [
253
+ "proc-macro2",
254
+ "pyo3-macros-backend",
255
+ "quote",
256
+ "syn",
257
+ ]
258
+
259
+ [[package]]
260
+ name = "pyo3-macros-backend"
261
+ version = "0.29.2"
262
+ source = "registry+https://github.com/rust-lang/crates.io-index"
263
+ checksum = "571575aa3749fa6216757dd47d2a3e7ef360f329a40f0666a9fbd14889024952"
264
+ dependencies = [
265
+ "heck",
266
+ "proc-macro2",
267
+ "quote",
268
+ "syn",
269
+ ]
270
+
271
+ [[package]]
272
+ name = "quick-error"
273
+ version = "2.0.1"
274
+ source = "registry+https://github.com/rust-lang/crates.io-index"
275
+ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
276
+
277
+ [[package]]
278
+ name = "quote"
279
+ version = "1.0.47"
280
+ source = "registry+https://github.com/rust-lang/crates.io-index"
281
+ checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
282
+ dependencies = [
283
+ "proc-macro2",
284
+ ]
285
+
286
+ [[package]]
287
+ name = "simd-adler32"
288
+ version = "0.3.10"
289
+ source = "registry+https://github.com/rust-lang/crates.io-index"
290
+ checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea"
291
+
292
+ [[package]]
293
+ name = "syn"
294
+ version = "2.0.119"
295
+ source = "registry+https://github.com/rust-lang/crates.io-index"
296
+ checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
297
+ dependencies = [
298
+ "proc-macro2",
299
+ "quote",
300
+ "unicode-ident",
301
+ ]
302
+
303
+ [[package]]
304
+ name = "target-lexicon"
305
+ version = "0.13.5"
306
+ source = "registry+https://github.com/rust-lang/crates.io-index"
307
+ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
308
+
309
+ [[package]]
310
+ name = "unicode-ident"
311
+ version = "1.0.26"
312
+ source = "registry+https://github.com/rust-lang/crates.io-index"
313
+ checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954"
314
+
315
+ [[package]]
316
+ name = "unicode-segmentation"
317
+ version = "1.13.3"
318
+ source = "registry+https://github.com/rust-lang/crates.io-index"
319
+ checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
320
+
321
+ [[package]]
322
+ name = "weezl"
323
+ version = "0.1.12"
324
+ source = "registry+https://github.com/rust-lang/crates.io-index"
325
+ checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
326
+
327
+ [[package]]
328
+ name = "zlib-rs"
329
+ version = "0.6.8"
330
+ source = "registry+https://github.com/rust-lang/crates.io-index"
331
+ checksum = "b268e58e7c693d7c271f93ffc4ba3b380412554231c85bf61ca7af91042a4112"
332
+
333
+ [[package]]
334
+ name = "zune-core"
335
+ version = "0.5.3"
336
+ source = "registry+https://github.com/rust-lang/crates.io-index"
337
+ checksum = "d56377fd46368984a170bc5aac5567e52ca5da874caa60bea39fcbca78fb658b"
338
+
339
+ [[package]]
340
+ name = "zune-jpeg"
341
+ version = "0.5.15"
342
+ source = "registry+https://github.com/rust-lang/crates.io-index"
343
+ checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296"
344
+ dependencies = [
345
+ "zune-core",
346
+ ]
@@ -0,0 +1,26 @@
1
+ [package]
2
+ name = "caligrama"
3
+ version = "0.1.0"
4
+ edition = "2021"
5
+ description = "Escribe un poema dentro de la silueta de una imagen y lo devuelve como texto. Núcleo en Rust de la librería de Python caligrama."
6
+ license = "MIT"
7
+ authors = ["Mao Suarez <maosuarezbarrer@gmail.com>"]
8
+ repository = "https://github.com/maosuarez/caligrama"
9
+ readme = "README.md"
10
+ keywords = ["calligram", "ascii-art", "poetry", "text-art", "pyo3"]
11
+ categories = ["text-processing", "multimedia::images", "command-line-utilities"]
12
+ exclude = ["live-test/", "assets/", ".github/"]
13
+
14
+ [lib]
15
+ name = "caligrama"
16
+ crate-type = ["cdylib", "rlib"]
17
+
18
+ [dependencies]
19
+ pyo3 = { version = "0.29", features = ["abi3-py39"] }
20
+ image = { version = "0.25", default-features = false, features = ["jpeg", "png", "gif", "bmp", "webp"] }
21
+ unicode-segmentation = "1.13"
22
+
23
+ [profile.release]
24
+ lto = true
25
+ codegen-units = 1
26
+ strip = true
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mao Suarez
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.