npm package: @irithell-js/image2braille
Description: Convert images to Braille Unicode art with customizable themes, colors, and multiple output formats (console, TXT, HTML, PNG).
Author: Irithell
Latest version: 1.0.0

# image2braille

High-performance image to Braille Unicode art converter with Floyd-Steinberg dithering, 20+ built-in themes, and multiple output formats (console, TXT, HTML, PNG).

## Features

- **Multiple Output Formats** - Console, TXT, HTML (interactive), PNG
- **20+ Built-in Themes** - Dracula, Nord, Monokai, Solarized, Terminal styles
- **Floyd-Steinberg Dithering** - Smooth gradients with error diffusion algorithm
- **Flexible Color System** - Use hex codes, RGB values, or color names
- **Quality Presets** - Fast, balanced, or best quality processing
- **Smart Resizing** - Lanczos3, Mitchell, Cubic kernels with aspect ratio preservation
- **TypeScript** - Full type definitions included
- **Dual Format** - ESM and CommonJS support
- **Zero Dependencies** - Only Sharp for image processing

## Installation

```bash
npm i @irithell-js/image2braille
```

## Quick Start

### Basic Usage (ESM)

```typescript
import { Image2Braille } from "image2braille";

const converter = new Image2Braille();

// Convert and display in console
await converter.convertAndShow("photo.jpg", { width: 80 });

// Convert and save as PNG
await converter.convertAndSave(
  "photo.jpg",
  "output.png",
  { width: 100 },
  { format: "image", theme: "dracula" },
);

// Get art as string
const art = await converter.convertToString("photo.jpg", { width: 60 });
console.log(art);
```

### Basic Usage (CommonJS)

```javascript
const { Image2Braille } = require("image2braille");

async function convert() {
  const converter = new Image2Braille();
  await converter.convertAndShow("image.png", { width: 80 });
}

convert();
```

### Using Themes

```typescript
// Use built-in theme
const converter = new Image2Braille({
  theme: "nord",
  dithering: true,
  quality: "best",
});

// List all available themes
Image2Braille.listThemes();
// Output:
// Available themes:
//   dark                 - Classic black and white
//     bg: #000000  fg: #ffffff
//   terminal             - Matrix-style green phosphor
//     bg: #000000  fg: #00ff00
//   ...

// Get theme names programmatically
const themes = Image2Braille.getThemeNames();
// ['dark', 'light', 'terminal', 'dracula', 'nord', ...]
```

## Configuration

### Constructor Options

```typescript
const converter = new Image2Braille({
  // Conversion settings
  defaultWidth: 80, // Default output width in characters
  defaultHeight: undefined, // Default height (auto if undefined)
  preserveAspectRatio: true, // Maintain image proportions
  threshold: 128, // Black/white threshold (0-255)
  dithering: true, // Enable Floyd-Steinberg dithering
  invert: false, // Invert colors (negative)

  // Output settings
  outputFormat: "console", // Default format: console|txt|html|image
  outputDir: "./output", // Output directory

  // Style settings
  theme: "dark", // Theme name (overrides colors)
  fontSize: 10, // Font size for HTML/PNG output
  fontFamily: "Cascadia Code, Courier New, monospace",
  backgroundColor: "#000000", // Background color (hex, rgb, or name)
  textColor: "#ffffff", // Text color (hex, rgb, or name)
  lineHeight: 1.0, // Line spacing
  padding: 20, // Padding for HTML/PNG

  // Quality settings
  resizeKernel: "lanczos3", // Resize algorithm
  quality: "balanced", // Processing speed: fast|balanced|best

  // Logging
  logger: console, // Optional logger instance
});
```

### Quality Presets

```typescript
// Ultra-fast (nearest neighbor, no dithering)
const fast = new Image2Braille({
  quality: "fast",
  resizeKernel: "nearest",
  dithering: false,
});

// Balanced (recommended)
const balanced = new Image2Braille({
  quality: "balanced",
  resizeKernel: "lanczos3",
  dithering: true,
});

// Best quality (slowest, highest detail)
const best = new Image2Braille({
  quality: "best",
  resizeKernel: "lanczos3",
  dithering: true,
});
```

### Color Configuration

```typescript
// Using hex colors
const hex = new Image2Braille({
  backgroundColor: "#282a36",
  textColor: "#f8f8f2",
});

// Using RGB
const rgb = new Image2Braille({
  backgroundColor: "rgb(40, 42, 54)",
  textColor: "rgb(248, 248, 242)",
});

// Using color names
const named = new Image2Braille({
  backgroundColor: "black",
  textColor: "green",
});

// Supported color names:
// black, white, red, green, blue, yellow, cyan, magenta, orange,
// purple, pink, lime, teal, navy, maroon, olive, gray, darkgray,
// lightgray, silver, darkred, darkgreen, darkblue, lightred,
// lightgreen, lightblue, transparent
```

## API Reference

### Image2Braille Methods

#### `convert(input: string | Buffer, options?: ConversionOptions): Promise<ConversionResult>`

Convert an image to Braille art.

```typescript
const result = await converter.convert("photo.jpg", {
  width: 100, // Width in characters
  height: 50, // Height in characters (optional)
  threshold: 128, // Black/white threshold (0-255)
  dithering: true, // Enable dithering
  invert: false, // Invert colors
  aspectRatio: true, // Preserve aspect ratio
});

console.log(result.art); // Braille art string
console.log(result.width); // 100 characters
console.log(result.height); // 50 characters
console.log(result.originalWidth); // 1920 pixels
console.log(result.originalHeight); // 1080 pixels
console.log(result.processingTime); // 234 ms
```

#### `convertAndSave(input, outputPath?, conversionOptions?, saveOptions?): Promise<ConversionResult>`

Convert and save to file.

```typescript
// Save as PNG with theme
await converter.convertAndSave(
  "input.jpg",
  "output.png",
  { width: 80 },
  {
    format: "image",
    theme: "dracula",
    fontSize: 12,
  },
);

// Save as HTML with custom colors
await converter.convertAndSave(
  "input.jpg",
  "output.html",
  { width: 100, dithering: true },
  {
    format: "html",
    backgroundColor: "navy",
    textColor: "cyan",
  },
);

// Save as TXT
await converter.convertAndSave(
  "input.jpg",
  "output.txt",
  { width: 60 },
  { format: "txt" },
);

// Display in console
await converter.convertAndSave(
  "input.jpg",
  undefined,
  { width: 80 },
  { format: "console", showInfo: true },
);
```

#### `convertToString(input, options?): Promise<string>`

Convert and return art as string.

```typescript
const art = await converter.convertToString("photo.jpg", { width: 60 });
console.log(art);
```

#### `convertAndShow(input, options?): Promise<ConversionResult>`

Convert and display in console with metadata.

```typescript
await converter.convertAndShow("photo.jpg", { width: 80 });
// Output:
// Original: 1920x1080px
// Braille: 80x33 characters
// Represented pixels: 160x132px
//
// ⣿⣿⣿⣿⣿⣿...
```

#### `updateConfig(newConfig: Partial<Image2BrailleConfig>): void`

Update configuration at runtime.

```typescript
converter.updateConfig({
  theme: "terminal",
  dithering: false,
  threshold: 150,
});
```

#### `getConfig(): Image2BrailleConfig`

Get current configuration.

```typescript
const config = converter.getConfig();
console.log(config.theme);
console.log(config.threshold);
```

#### `static listThemes(): void`

List all available themes.

```typescript
Image2Braille.listThemes();
```

#### `static getThemeNames(): string[]`

Get array of theme names.

```typescript
const themes = Image2Braille.getThemeNames();
// ['dark', 'light', 'terminal', ...]
```

## Available Themes

| Theme             | Description                  | Background | Foreground |
| ----------------- | ---------------------------- | ---------- | ---------- |
| `dark`            | Classic black and white      | #000000    | #ffffff    |
| `light`           | White background, black text | #ffffff    | #000000    |
| `terminal`        | Matrix-style green phosphor  | #000000    | #00ff00    |
| `amber`           | Retro DOS amber              | #1a0f00    | #ffb000    |
| `green`           | Classic green terminal       | #0a1a0a    | #00ff41    |
| `dracula`         | Dracula theme                | #282a36    | #f8f8f2    |
| `monokai`         | Monokai theme                | #272822    | #f8f8f2    |
| `solarized-dark`  | Solarized dark               | #002b36    | #839496    |
| `solarized-light` | Solarized light              | #fdf6e3    | #657b83    |
| `nord`            | Nord theme                   | #2e3440    | #d8dee9    |
| `one-dark`        | Atom One Dark                | #282c34    | #abb2bf    |
| `gruvbox-dark`    | Gruvbox dark                 | #282828    | #ebdbb2    |
| `gruvbox-light`   | Gruvbox light                | #fbf1c7    | #3c3836    |
| `blue`            | Cyberpunk blue               | #001122    | #00aaff    |
| `purple`          | Neon purple                  | #0d001a    | #bf40ff    |
| `red`             | Alert red                    | #1a0000    | #ff4444    |
| `cyan`            | Bright cyan                  | #001a1a    | #00ffff    |
| `paper`           | Aged paper                   | #f5f5dc    | #2c2c2c    |
| `hacker`          | Hacker terminal              | #0c0c0c    | #0f0       |

## Advanced Usage

### Batch Processing with Multiple Themes

```typescript
const converter = new Image2Braille({
  outputDir: "./output",
});

const themes = ["dark", "terminal", "dracula", "nord"];

for (const theme of themes) {
  converter.updateConfig({ theme });
  await converter.convertAndSave(
    "photo.jpg",
    `./output/${theme}.png`,
    { width: 80 },
    { format: "image" },
  );
}
```

### Custom Pipeline

```typescript
import { Image2Braille } from "image2braille";
import { readFileSync } from "fs";

// Load image as buffer
const buffer = readFileSync("photo.jpg");

// Convert with custom settings
const converter = new Image2Braille({
  dithering: false,
  threshold: 150,
});

const result = await converter.convert(buffer, {
  width: 100,
  invert: true,
});

// Process the art string
const lines = result.art.split("\n");
console.log(`Generated ${lines.length} lines`);
```

### Error Handling

```typescript
try {
  const result = await converter.convert("invalid.jpg");
} catch (error) {
  if (error.message.includes("missing dimensions")) {
    console.error("Invalid image file");
  } else {
    console.error("Conversion failed:", error.message);
  }
}
```

### Performance Monitoring

```typescript
const start = Date.now();
const result = await converter.convert("large-photo.jpg", { width: 200 });
console.log(`Processing took ${result.processingTime}ms`);
console.log(`Total time: ${Date.now() - start}ms`);
```

## Output Formats

### Console

Displays art directly in terminal with metadata.

### TXT

Plain text file with Braille characters (UTF-8 encoded).

### HTML

Interactive HTML with:

- All themes as clickable buttons
- Copy to clipboard
- Download as TXT
- Smooth theme transitions
- Responsive design

### PNG

Rendered image with:

- Anti-aliased text
- Custom fonts
- Configurable size and padding
- High-quality SVG-to-PNG conversion

## Performance

Conversion speed depends on image size, quality settings, and dithering:

| Image Size | Width | Quality  | Dithering | Time   |
| ---------- | ----- | -------- | --------- | ------ |
| 1920x1080  | 80    | fast     | off       | ~50ms  |
| 1920x1080  | 80    | balanced | on        | ~90ms  |
| 1920x1080  | 150   | best     | on        | ~175ms |
| 3840x2160  | 80    | balanced | on        | ~140ms |
| 3840x2160  | 200   | best     | on        | ~400ms |

_Times measured on local tests_

## How It Works

1. **Load Image** - Uses Sharp to read image file or buffer
2. **Calculate Dimensions** - Determines target size preserving aspect ratio
3. **Resize** - Resizes to exact pixel dimensions (width×2, height×4)
4. **Convert to Grayscale** - Calculates luminance using ITU-R BT.709 formula
5. **Apply Dithering** - Floyd-Steinberg error diffusion (optional)
6. **Map to Braille** - Converts 2×4 pixel blocks to Braille Unicode (U+2800-U+28FF)
7. **Output** - Renders to selected format

### Braille Unicode

Each Braille character represents a 2×4 pixel block:

```
⠁ = pixel at (0,0)
⠂ = pixel at (0,1)
⠄ = pixel at (0,2)
⡀ = pixel at (0,3)
⠈ = pixel at (1,0)
⠐ = pixel at (1,1)
⠠ = pixel at (1,2)
⢀ = pixel at (1,3)
```

Example: `⣿` = all 8 pixels filled (U+28FF)

## Requirements

- Node.js >= 18.0.0
- Sharp (automatically installed)

## License

MIT

## Changelog

### 1.0.0 (Latest)

- Initial release
- Floyd-Steinberg dithering support
- 20+ built-in themes
- Multiple output formats (console, TXT, HTML, PNG)
- Color name resolution (hex, rgb, names)
- Quality presets (fast, balanced, best)
- Multiple resize kernels (nearest, cubic, mitchell, lanczos2, lanczos3)
- Aspect ratio preservation
- TypeScript support with full type definitions
- ESM and CommonJS support