ansimax 1.2.4 → 1.2.5

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.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,131 @@
3
3
  All notable changes to **ansimax** are documented in this file.
4
4
  This project follows [Semantic Versioning](https://semver.org/).
5
5
 
6
+ ## [1.2.5] — Phase 3 closure: image-to-ASCII engine
7
+
8
+ Minor release closing the **ASCII engine roadmap (Phase 3)** with five
9
+ new capabilities. All additions are fully backwards-compatible — existing
10
+ code runs identically.
11
+
12
+ ### Added — `ascii.fromImage(pixels, opts)` — image-to-ASCII converter
13
+
14
+ Convert a `PixelGrid` (from `ansimax.images`) into ASCII art. Five
15
+ features in one call:
16
+
17
+ ```ts
18
+ import { ascii } from 'ansimax';
19
+
20
+ console.log(ascii.fromImage(pixels, {
21
+ width: 80,
22
+ ramp: 'detailed', // 'standard' | 'detailed' | 'blocks' | 'simple' | custom string
23
+ invert: false,
24
+ dither: 'floyd-steinberg', // 'none' | 'floyd-steinberg'
25
+ edgeDetect: 'sobel', // 'none' | 'sobel'
26
+ edgeThreshold: 40,
27
+ color: true, // preserve source colors
28
+ faceMode: false, // histogram stretch for portraits
29
+ }));
30
+ ```
31
+
32
+ **Aspect-ratio aware**: terminal cells are ~2× as tall as wide, so the
33
+ output height is auto-halved to maintain visual proportion (override
34
+ with `height`).
35
+
36
+ **Zero-dependency**: input is a `PixelGrid` (one Pixel per cell). Users
37
+ of `sharp`, `jimp`, or any decoder convert their output to `PixelGrid`
38
+ once, then call `ascii.fromImage()`.
39
+
40
+ ### Added — `ASCII_RAMPS` — pre-built character ramps
41
+
42
+ Four curated character ramps, ordered dark → light, exported as a
43
+ read-only object:
44
+
45
+ ```ts
46
+ ASCII_RAMPS.standard // ' .:-=+*#%@' — balanced 10-char (default)
47
+ ASCII_RAMPS.detailed // 70-char Paul Bourke — max detail
48
+ ASCII_RAMPS.blocks // ' ░▒▓█' — looks like a real photo
49
+ ASCII_RAMPS.simple // ' .+#' — minimal 4-char
50
+ ```
51
+
52
+ Or pass any custom string as the `ramp` option for full control.
53
+
54
+ ### Added — Sobel edge detection
55
+
56
+ Set `edgeDetect: 'sobel'` to render edges instead of luminance. Useful
57
+ for line-art effects or technical diagrams:
58
+
59
+ ```ts
60
+ console.log(ascii.fromImage(pixels, {
61
+ width: 100,
62
+ edgeDetect: 'sobel',
63
+ edgeThreshold: 50, // tune for noise/detail balance
64
+ ramp: 'blocks',
65
+ }));
66
+ ```
67
+
68
+ ### Added — Floyd-Steinberg dithering
69
+
70
+ Set `dither: 'floyd-steinberg'` for error-diffusion dithering. Produces
71
+ smoother tonal gradients in photos. Most useful with shorter ramps:
72
+
73
+ ```ts
74
+ ascii.fromImage(pixels, {
75
+ width: 80,
76
+ ramp: 'simple',
77
+ dither: 'floyd-steinberg',
78
+ });
79
+ ```
80
+
81
+ ### Added — Face mode
82
+
83
+ Set `faceMode: true` to apply histogram stretching ([10%, 90%] percentile
84
+ remap to [0, 255]). Boosts midtone contrast where facial features live,
85
+ producing better results on portraits:
86
+
87
+ ```ts
88
+ ascii.fromImage(portraitPixels, {
89
+ width: 60,
90
+ ramp: 'detailed',
91
+ faceMode: true,
92
+ });
93
+ ```
94
+
95
+ ### Added — Figlet (.flf) font support
96
+
97
+ Parse and render with community FIGfonts (250+ available at
98
+ [figlet.org](http://www.figlet.org/fontdb.cgi)):
99
+
100
+ ```ts
101
+ import { readFileSync } from 'node:fs';
102
+ import { parseFiglet, ascii } from 'ansimax';
103
+
104
+ const fontStr = readFileSync('./standard.flf', 'utf8');
105
+ const font = parseFiglet(fontStr);
106
+
107
+ console.log(ascii.figletText('Hello!', font, {
108
+ trim: true,
109
+ colorFn: (t) => t, // optional colorize
110
+ }));
111
+ ```
112
+
113
+ Returns a `FigletFont` object containing the parsed glyphs. Renders
114
+ ASCII 32-126; unknown chars fall back to space.
115
+
116
+ ### Added — Type exports
117
+
118
+ `AsciiRamp`, `FromImageOptions`, `FigletFont`, `FigletOptions` — all
119
+ exported from the main barrel.
120
+
121
+ ### Notes
122
+
123
+ - Phase 3 of the [roadmap](README.md#%EF%B8%8F-roadmap) is now **fully complete**.
124
+ - Image decoding (PNG/JPEG → PixelGrid) is intentionally **not** included;
125
+ users pair ansimax with `sharp`/`jimp`/`pngjs` to keep zero deps.
126
+ - 1914 + 30 new tests pass.
127
+ - No new runtime dependencies — still zero.
128
+
129
+ ---
130
+
6
131
  ## [1.2.4] — Gradient utilities + inspectability
7
132
 
8
133
  Patch release adding gradient inspection and manipulation utilities.
package/README.es.md CHANGED
@@ -7,7 +7,7 @@
7
7
  _Colores • Gradientes • Animaciones • ASCII Art • Pixel Art • Árboles • Componentes • Temas_
8
8
 
9
9
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg?style=flat-square)](LICENSE)
10
- [![npm](https://img.shields.io/badge/npm-v1.2.4-cb3837.svg?style=flat-square)](https://www.npmjs.com/package/ansimax)
10
+ [![npm](https://img.shields.io/badge/npm-v1.2.5-cb3837.svg?style=flat-square)](https://www.npmjs.com/package/ansimax)
11
11
  [![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178c6.svg?style=flat-square)](tsconfig.json)
12
12
  [![Coverage](https://img.shields.io/badge/coverage-98%25-brightgreen.svg?style=flat-square)](#testing)
13
13
  [![Tests](https://img.shields.io/badge/tests-1700%2B%20passing-brightgreen.svg?style=flat-square)](#testing)
@@ -306,6 +306,60 @@ console.log(ascii.banner('HOLA', {
306
306
  console.log(ascii.box('¡Caja arcoiris!', { padding: 1, borderStyle: 'rounded' }));
307
307
  ```
308
308
 
309
+ ### Imagen → ASCII (v1.2.5)
310
+
311
+ ```ts
312
+ import { ascii } from 'ansimax';
313
+ import type { PixelGrid } from 'ansimax';
314
+
315
+ // Obtén un PixelGrid de cualquier librería de imágenes (sharp, jimp, pngjs, etc.)
316
+ // Cada Pixel es `{ r, g, b }` o null
317
+ const pixels: PixelGrid = await loadImagePixels('./foto.png');
318
+
319
+ // Monocromo
320
+ console.log(ascii.fromImage(pixels, { width: 80 }));
321
+
322
+ // Color + dithering Floyd-Steinberg + ramp detallado
323
+ console.log(ascii.fromImage(pixels, {
324
+ width: 100,
325
+ color: true,
326
+ dither: 'floyd-steinberg',
327
+ ramp: 'detailed',
328
+ }));
329
+
330
+ // Modo detección de bordes (line art)
331
+ console.log(ascii.fromImage(pixels, {
332
+ width: 80,
333
+ edgeDetect: 'sobel',
334
+ edgeThreshold: 50,
335
+ ramp: 'blocks',
336
+ }));
337
+
338
+ // Modo rostro para retratos (mejora contraste de tonos medios)
339
+ console.log(ascii.fromImage(retratoPixels, {
340
+ width: 60,
341
+ ramp: 'detailed',
342
+ faceMode: true,
343
+ }));
344
+ ```
345
+
346
+ ### Fuentes Figlet (v1.2.5)
347
+
348
+ ```ts
349
+ import { readFileSync } from 'node:fs';
350
+ import { parseFiglet, ascii } from 'ansimax';
351
+
352
+ // Descarga fuentes desde http://www.figlet.org/fontdb.cgi
353
+ const font = parseFiglet(readFileSync('./standard.flf', 'utf8'));
354
+
355
+ console.log(ascii.figletText('¡Hola!', font));
356
+
357
+ // Con color
358
+ console.log(ascii.figletText('STYLE', font, {
359
+ colorFn: (t) => gradient(t, ['#ff79c6', '#bd93f9', '#8be9fd']),
360
+ }));
361
+ ```
362
+
309
363
  ### Árboles
310
364
 
311
365
  <img src="media/trees.png" alt="Árboles" />
@@ -365,7 +419,7 @@ console.log(components.table([
365
419
  ['loaders', color.green('● listo'), '100%'],
366
420
  ], { borderStyle: 'rounded' }));
367
421
 
368
- console.log(components.badge('VERSION', 'v1.2.4'));
422
+ console.log(components.badge('VERSION', 'v1.2.5'));
369
423
  console.log(components.badge('BUILD', 'passing'));
370
424
  ```
371
425
 
@@ -579,7 +633,7 @@ El roadmap apunta intencionalmente — y busca superar — gaps que ni siquiera
579
633
  - [x] **Curvas de interpolación** — `linear` / `ease-in` / `ease-out` / `ease-in-out` / `cubic-bezier` / personalizado (v1.2.0)
580
634
  - [x] **Gradientes cónicos** — barrido radial con `style: 'conic'` (v1.2.0)
581
635
 
582
- ### 🟡 Fase 3 — Motor ASCII
636
+ ### Fase 3 — Motor ASCII
583
637
  - [x] Fuentes de bloque (`big`, `small`)
584
638
  - [x] Banner con gradiente + alineación + coloreado por carácter
585
639
  - [x] Dibujo de cajas (6 estilos de borde)
@@ -587,11 +641,12 @@ El roadmap apunta intencionalmente — y busca superar — gaps que ni siquiera
587
641
  - [x] Compositor de logos (gradiente + box wrapping)
588
642
  - [x] Registro de fuentes personalizadas (`registerFont`, `hasFont`, `listFonts`)
589
643
  - [x] API de stream (`ascii.stream()` con AbortSignal)
590
- - [ ] **Conversor Imagen → ASCII** (con detección de bordes, Sobel/Canny)
591
- - [ ] **Renderizado ASCII en color** (preservar colores de imagen)
592
- - [ ] **Dithering de imágenes** para mejor rango tonal (Floyd-Steinberg)
593
- - [ ] **ASCII optimizado para rostros** (modo de alto detalle para retratos)
594
- - [ ] **Soporte de fuentes figlet** (loader de archivos `.flf` 250+ fuentes de comunidad)
644
+ - [x] **Conversor Imagen → ASCII** — `ascii.fromImage()` con mapeo de luminancia (v1.2.5)
645
+ - [x] **Renderizado ASCII en color** preserva colores de imagen con `color: true` (v1.2.5)
646
+ - [x] **Dithering de imágenes** error diffusion Floyd-Steinberg (v1.2.5)
647
+ - [x] **ASCII optimizado para rostros** histogram stretching para retratos (v1.2.5)
648
+ - [x] **Soporte de fuentes figlet** parser + renderer `.flf` (`parseFiglet` + `ascii.figletText`) (v1.2.5)
649
+ - [x] **Detección de bordes** — operador Sobel integrado en `fromImage` (v1.2.5, bonus)
595
650
 
596
651
  ### ✅ Fase 4 — Primitivas TUI
597
652
  - [x] Tablas (filas irregulares, celdas multi-línea, conscientes de ANSI)
@@ -767,6 +822,35 @@ ansimax/
767
822
 
768
823
  ## 📝 Changelog
769
824
 
825
+ ### v1.2.5 — Fase 3 completa: motor de imagen-a-ASCII
826
+
827
+ Release minor que cierra el roadmap del motor ASCII con 5 features nuevas:
828
+
829
+ - 🖼️ **`ascii.fromImage(pixels, opts)`** — Conversor Imagen → ASCII (input: `PixelGrid`)
830
+ - 🎨 **Renderizado ASCII en color** — `color: true` preserva los colores fuente
831
+ - 📐 **Dithering Floyd-Steinberg** — `dither: 'floyd-steinberg'` para gradientes tonales más suaves
832
+ - 👤 **Modo optimizado para rostros** — `faceMode: true` mejora contraste de tonos medios en retratos
833
+ - 🔠 **Soporte Figlet (.flf)** — `parseFiglet()` + `ascii.figletText()` para 250+ fuentes de comunidad
834
+ - ⚡ **Bonus: detección de bordes Sobel** — `edgeDetect: 'sobel'` para efectos line-art
835
+
836
+ ```ts
837
+ import { ascii } from 'ansimax';
838
+
839
+ // Imagen a ASCII (input desde sharp/jimp/etc, sin dependencia de decoder)
840
+ console.log(ascii.fromImage(pixels, {
841
+ width: 80,
842
+ color: true,
843
+ dither: 'floyd-steinberg',
844
+ ramp: 'detailed',
845
+ }));
846
+
847
+ // Renderizado Figlet
848
+ const font = parseFiglet(readFileSync('./standard.flf', 'utf8'));
849
+ console.log(ascii.figletText('¡Hola!', font));
850
+ ```
851
+
852
+ Drop-in replacement para `1.2.4`.
853
+
770
854
  ### v1.2.4 — Utilidades de gradiente + inspectabilidad
771
855
 
772
856
  Release patch añadiendo metadata de inspección y un helper `reverseGradient()`:
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  _Colors • Gradients • Animations • ASCII Art • Pixel Art • Trees • Components • Themes_
8
8
 
9
9
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg?style=flat-square)](LICENSE)
10
- [![npm](https://img.shields.io/badge/npm-v1.2.4-cb3837.svg?style=flat-square)](https://www.npmjs.com/package/ansimax)
10
+ [![npm](https://img.shields.io/badge/npm-v1.2.5-cb3837.svg?style=flat-square)](https://www.npmjs.com/package/ansimax)
11
11
  [![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178c6.svg?style=flat-square)](tsconfig.json)
12
12
  [![Coverage](https://img.shields.io/badge/coverage-98%25-brightgreen.svg?style=flat-square)](#testing)
13
13
  [![Tests](https://img.shields.io/badge/tests-1700%2B%20passing-brightgreen.svg?style=flat-square)](#testing)
@@ -306,6 +306,60 @@ console.log(ascii.banner('HELLO', {
306
306
  console.log(ascii.box('Rainbow box!', { padding: 1, borderStyle: 'rounded' }));
307
307
  ```
308
308
 
309
+ ### Image → ASCII (v1.2.5)
310
+
311
+ ```ts
312
+ import { ascii } from 'ansimax';
313
+ import type { PixelGrid } from 'ansimax';
314
+
315
+ // Get a PixelGrid from any image library (sharp, jimp, pngjs, etc.)
316
+ // Each Pixel is `{ r, g, b }` or null
317
+ const pixels: PixelGrid = await loadImagePixels('./photo.png');
318
+
319
+ // Monochrome
320
+ console.log(ascii.fromImage(pixels, { width: 80 }));
321
+
322
+ // Color + Floyd-Steinberg dithering + detailed ramp
323
+ console.log(ascii.fromImage(pixels, {
324
+ width: 100,
325
+ color: true,
326
+ dither: 'floyd-steinberg',
327
+ ramp: 'detailed',
328
+ }));
329
+
330
+ // Edge-detection mode (line art)
331
+ console.log(ascii.fromImage(pixels, {
332
+ width: 80,
333
+ edgeDetect: 'sobel',
334
+ edgeThreshold: 50,
335
+ ramp: 'blocks',
336
+ }));
337
+
338
+ // Face mode for portraits (boosts midtone contrast)
339
+ console.log(ascii.fromImage(portraitPixels, {
340
+ width: 60,
341
+ ramp: 'detailed',
342
+ faceMode: true,
343
+ }));
344
+ ```
345
+
346
+ ### Figlet Fonts (v1.2.5)
347
+
348
+ ```ts
349
+ import { readFileSync } from 'node:fs';
350
+ import { parseFiglet, ascii } from 'ansimax';
351
+
352
+ // Download fonts from http://www.figlet.org/fontdb.cgi
353
+ const font = parseFiglet(readFileSync('./standard.flf', 'utf8'));
354
+
355
+ console.log(ascii.figletText('Hello!', font));
356
+
357
+ // With color
358
+ console.log(ascii.figletText('STYLE', font, {
359
+ colorFn: (t) => gradient(t, ['#ff79c6', '#bd93f9', '#8be9fd']),
360
+ }));
361
+ ```
362
+
309
363
  ### Trees
310
364
 
311
365
  <img src="media/trees.png" alt="Trees" />
@@ -365,7 +419,7 @@ console.log(components.table([
365
419
  ['loaders', color.green('● ready'), '100%'],
366
420
  ], { borderStyle: 'rounded' }));
367
421
 
368
- console.log(components.badge('VERSION', 'v1.2.4'));
422
+ console.log(components.badge('VERSION', 'v1.2.5'));
369
423
  console.log(components.badge('BUILD', 'passing'));
370
424
  ```
371
425
 
@@ -579,7 +633,7 @@ The roadmap intentionally targets — and aims to surpass — gaps that even mat
579
633
  - [x] **Gradient interpolation curves** — `linear` / `ease-in` / `ease-out` / `ease-in-out` / `cubic-bezier` / custom (v1.2.0)
580
634
  - [x] **Conic gradients** — radial sweep with `style: 'conic'` (v1.2.0)
581
635
 
582
- ### 🟡 Phase 3 — ASCII engine
636
+ ### Phase 3 — ASCII engine
583
637
  - [x] Block fonts (`big`, `small`)
584
638
  - [x] Banner with gradient + alignment + per-char coloring
585
639
  - [x] Box drawing (6 border styles)
@@ -587,11 +641,12 @@ The roadmap intentionally targets — and aims to surpass — gaps that even mat
587
641
  - [x] Logo composer (gradient + box wrapping)
588
642
  - [x] Custom font registry (`registerFont`, `hasFont`, `listFonts`)
589
643
  - [x] Stream API (`ascii.stream()` with AbortSignal)
590
- - [ ] **Image → ASCII** converter (with edge detection, Sobel/Canny)
591
- - [ ] **Color ASCII** rendering (preserve image colors)
592
- - [ ] **Image dithering** for better tonal range (Floyd-Steinberg)
593
- - [ ] **Face-optimized ASCII** (high-detail mode for portraits)
594
- - [ ] **Figlet font support** (.flf file loader 250+ community fonts)
644
+ - [x] **Image → ASCII** converter — `ascii.fromImage()` with luminance mapping (v1.2.5)
645
+ - [x] **Color ASCII** rendering preserve image colors via `color: true` (v1.2.5)
646
+ - [x] **Image dithering** Floyd-Steinberg error diffusion (v1.2.5)
647
+ - [x] **Face-optimized ASCII** histogram stretching for portraits (v1.2.5)
648
+ - [x] **Figlet font support** — `.flf` parser + renderer (`parseFiglet` + `ascii.figletText`) (v1.2.5)
649
+ - [x] **Edge detection** — Sobel operator integrated in `fromImage` (v1.2.5, bonus)
595
650
 
596
651
  ### ✅ Phase 4 — Terminal UI primitives
597
652
  - [x] Tables (irregular rows, multi-line cells, ANSI-aware)
@@ -767,6 +822,35 @@ ansimax/
767
822
 
768
823
  ## 📝 Changelog
769
824
 
825
+ ### v1.2.5 — Phase 3 complete: image-to-ASCII engine
826
+
827
+ Minor release closing the ASCII engine roadmap with 5 new features:
828
+
829
+ - 🖼️ **`ascii.fromImage(pixels, opts)`** — Image → ASCII converter (input: `PixelGrid`)
830
+ - 🎨 **Color ASCII rendering** — `color: true` preserves source colors
831
+ - 📐 **Floyd-Steinberg dithering** — `dither: 'floyd-steinberg'` for smoother tonal gradients
832
+ - 👤 **Face-optimized mode** — `faceMode: true` boosts midtone contrast for portraits
833
+ - 🔠 **Figlet (.flf) support** — `parseFiglet()` + `ascii.figletText()` for 250+ community fonts
834
+ - ⚡ **Bonus: Sobel edge detection** — `edgeDetect: 'sobel'` for line-art effects
835
+
836
+ ```ts
837
+ import { ascii } from 'ansimax';
838
+
839
+ // Image to ASCII (input from sharp/jimp/etc, no decoder dependency)
840
+ console.log(ascii.fromImage(pixels, {
841
+ width: 80,
842
+ color: true,
843
+ dither: 'floyd-steinberg',
844
+ ramp: 'detailed',
845
+ }));
846
+
847
+ // Figlet rendering
848
+ const font = parseFiglet(readFileSync('./standard.flf', 'utf8'));
849
+ console.log(ascii.figletText('Hello!', font));
850
+ ```
851
+
852
+ Drop-in replacement for `1.2.4`.
853
+
770
854
  ### v1.2.4 — Gradient utilities + inspectability
771
855
 
772
856
  Patch release adding inspection metadata and a `reverseGradient()` helper: