@aitjcize/epaper-image-convert

中文文档
0.1.21发布于 2026/10/05MITES Module近 30 天下载 7845

Convert images for e-paper displays with advanced tone mapping, dithering, and color palette optimization

原始使用文档
文档目录21 节
  1. Features
  2. Installation
  3. CLI Usage
  4. Basic Usage
  5. Processing Presets
  6. Custom Processing Parameters
  7. Palette Options
  8. ESP32 PhotoFrame Device Config
  9. Generate Thumbnails
  10. Output Format
  11. All Options
  12. Library Usage
  13. Basic Conversion
  14. Advanced Usage
  15. Custom Palette
  16. Palette Format
  17. Why Two Palettes?
  18. Processing Presets
  19. Support
  20. License
  21. Credits

epaper-image-convert

Convert images for e-paper displays with advanced tone mapping, dithering, and color palette optimization.

Features

  • Advanced Tone Mapping - S-curve and contrast-based tone mapping for optimal e-paper display
  • Error Diffusion Dithering - Floyd-Steinberg, Stucki, Burkes, and Sierra algorithms
  • Dynamic Range Compression - Automatically compress images to match display's actual luminance range
  • Color Palette Support - Built-in presets and custom palette support with theoretical/perceived pairs
  • EXIF Orientation - Automatic EXIF orientation handling
  • CLI and Library - Use from command line or as a Node.js library

Installation

npm install epaper-image-convert

Or install globally for CLI use:

npm install -g epaper-image-convert

CLI Usage

Basic Usage

# Convert a single image
epaper-image-convert input.jpg output.png

# Convert with specific display dimensions
epaper-image-convert input.jpg -d 640x384

# Convert all images in a directory
epaper-image-convert ./photos ./converted

Processing Presets

# List all available presets
epaper-image-convert -l

# Use Balanced preset - default, produces the most balanced result
epaper-image-convert input.jpg -p balanced

# Use Dynamic preset - enhanced contrast, vibrant colors
epaper-image-convert input.jpg -p dynamic

# Use Vivid preset - boosted colors for illustrations
epaper-image-convert input.jpg -p vivid

# Available presets: balanced, dynamic, vivid, soft, grayscale

Custom Processing Parameters

# Adjust exposure and saturation
epaper-image-convert input.jpg --exposure 1.2 --saturation 1.4

# Use S-curve tone mapping with custom parameters
epaper-image-convert input.jpg --tone-mode scurve \
  --scurve-strength 0.8 \
  --scurve-shadow 0.1 \
  --scurve-highlight 1.5

# Use LAB color space for better grayscale matching
epaper-image-convert input.jpg --color-method lab

# Change dithering algorithm
epaper-image-convert input.jpg --dither-algorithm stucki

Palette Options

# Use built-in palette preset
epaper-image-convert input.jpg --palette-preset spectra6

# Use custom palette (JSON format)
epaper-image-convert input.jpg --palette '{
  "theoretical": {
    "black": {"r": 0, "g": 0, "b": 0},
    "white": {"r": 255, "g": 255, "b": 255},
    "yellow": {"r": 255, "g": 255, "b": 0},
    "red": {"r": 255, "g": 0, "b": 0},
    "blue": {"r": 0, "g": 0, "b": 255},
    "green": {"r": 0, "g": 255, "b": 0}
  },
  "perceived": {
    "black": {"r": 5, "g": 5, "b": 5},
    "white": {"r": 200, "g": 200, "b": 195},
    "yellow": {"r": 210, "g": 200, "b": 10},
    "red": {"r": 180, "g": 35, "b": 25},
    "blue": {"r": 20, "g": 70, "b": 160},
    "green": {"r": 45, "g": 120, "b": 70}
  }
}'

ESP32 PhotoFrame Device Config

An ESP32 PhotoFrame exports its settings from the web UI (Settings → Maintenance → Config Backup → Export Config). Point the CLI at that file to convert for that frame without re-typing its calibration:

epaper-image-convert input.jpg output.epdgz --device-config living-room-config.json

The file supplies the defaults:

  • palette → the panel's calibrated perceived colours (paired with the Spectra 6 theoretical palette), or on a GC16 panel the measured luminance endpoints the grayscale ramp is derived from
  • processing → the processing parameters (in place of -p), plus the --scale-mode / --background-color layout
  • config.display_orientation → --orientation
  • system_info → the panel size (-d); exports from older firmware lack it, so pass -d WxH for those

Anything given explicitly on the command line still wins: -d, -p, --exposure and friends, --scale-mode, --orientation, and --gray-* (which override the file's endpoints one at a time). --palette or an explicit --palette-preset replaces the file's palette entirely.

The same file works with the frame's own photoframe-process --device-config.

Generate Thumbnails

# Generate thumbnail alongside output
epaper-image-convert input.jpg output.png -t output_thumb.jpg

# Custom thumbnail dimensions
epaper-image-convert input.jpg output.png -t thumb.jpg --thumbnail-dimension 200x120

Output Format

# Output as PNG (default)
epaper-image-convert input.jpg output.png

# Output as BMP
epaper-image-convert input.jpg output.bmp -f bmp

# Format is auto-detected when output is a directory
epaper-image-convert input.jpg /tmp -f bmp  # Creates /tmp/input.bmp

All Options

Options:
  -V, --version                       output the version number
  -l, --list-presets                  List available presets and exit
  -d, --dimension <WxH>               Display dimension (e.g., 800x480)
                                      (default: "800x480")
  -f, --format <format>               Output format: epdgz, png, or bmp
                                      (default: "epdgz")
  --palette-preset <name>             Palette preset: spectra6, grayscale16,
                                      default (default: "spectra6")
  --palette <json>                    Custom palette JSON (overrides
                                      --palette-preset)
  --device-config <file>              Config exported from an ESP32 PhotoFrame's
                                      web UI (Maintenance > Config Backup >
                                      Export Config): its palette, processing
                                      settings, orientation and panel size
                                      become the defaults; explicit flags (-d,
                                      -p, --exposure, --gray-*, ...) still win,
                                      and --palette or --palette-preset replaces
                                      its palette
  --gray-black-y <Y>                  GC16 grayscale: measured relative
                                      luminance (0..1) of full black
  --gray-white-y <Y>                  GC16 grayscale: measured relative
                                      luminance (0..1) of full white
  --gray-gamma <g>                    GC16 grayscale: mid-level gamma (1 =
                                      linear in L*, >1 darkens mids)
  -p, --processing-preset <name>      Processing preset: balanced, dynamic,
                                      vivid, soft, grayscale (default:
                                      "balanced")
  --exposure <value>                  Exposure multiplier (0.5-2.0)
  --saturation <value>                Saturation multiplier (0.5-2.0)
  --contrast <value>                  Contrast multiplier (0.5-2.0)
  --tone-mode <mode>                  Tone mapping mode: scurve or contrast
  --scurve-strength <value>           S-curve overall strength (0.0-1.0)
  --scurve-shadow <value>             S-curve shadow boost (0.0-1.0)
  --scurve-highlight <value>          S-curve highlight compress (0.5-5.0)
  --scurve-midpoint <value>           S-curve midpoint (0.3-0.7)
  --color-method <method>             Color matching: rgb or lab
  --dither-algorithm <algorithm>      Dithering algorithm: floyd-steinberg,
                                      stucki, burkes, or sierra
  --compress-dynamic-range            Compress dynamic range to display range
  --no-compress-dynamic-range         Disable dynamic range compression
  --orientation <mode>                Display orientation: landscape or portrait
                                      (default: native)
  --scale-mode <mode>                 Scale mode: cover (crop to fill) or fit
                                      (letterbox) (default: "cover")
  --background-color <name>           Background palette color for fit mode
                                      (black, white, etc.) (default: "white")
  --skip-dithering                    Skip dithering step
  --use-perceived-output              Use perceived palette for output (for
                                      preview)
  -t, --thumbnail <path>              Generate thumbnail and save to path
  --thumbnail-max-dimension <pixels>  Maximum thumbnail dimension (longest side)
                                      (default: "400")
  -v, --verbose                       Enable verbose output
  -h, --help                          display help for command

Library Usage

Basic Conversion

import { convertImage } from 'epaper-image-convert';

const { canvas, buffer } = await convertImage('input.jpg', {
  width: 800,
  height: 480,
  processingPreset: 'balanced',
  verbose: true,
});

// buffer is a PNG Buffer ready to write or send to device
fs.writeFileSync('output.png', buffer);

Advanced Usage

import {
  processImage,
  applyExifOrientation,
  createPNG,
  getPreset,
  getPalette,
  SPECTRA6,
} from 'epaper-image-convert';
import { createCanvas, loadImage } from 'canvas';

// Load image
const image = await loadImage('input.jpg');
const sourceCanvas = createCanvas(image.width, image.height);
sourceCanvas.getContext('2d').drawImage(image, 0, 0);

// Process with custom options
const { canvas, originalCanvas } = processImage(sourceCanvas, {
  displayWidth: 800,
  displayHeight: 480,
  palette: SPECTRA6,
  params: {
    ...getPreset('dynamic'),
    exposure: 1.1,
    saturation: 1.4,
  },
  skipRotation: false,
  verbose: true,
  createCanvas,
});

// Convert to PNG
const pngBuffer = await createPNG(canvas);

Custom Palette

import { processImage, validatePalette } from 'epaper-image-convert';

const customPalette = {
  theoretical: {
    black: { r: 0, g: 0, b: 0 },
    white: { r: 255, g: 255, b: 255 },
    yellow: { r: 255, g: 255, b: 0 },
    red: { r: 255, g: 0, b: 0 },
    blue: { r: 0, g: 0, b: 255 },
    green: { r: 0, g: 255, b: 0 },
  },
  perceived: {
    black: { r: 10, g: 10, b: 10 },
    white: { r: 220, g: 215, b: 210 },
    yellow: { r: 200, g: 190, b: 20 },
    red: { r: 170, g: 40, b: 30 },
    blue: { r: 30, g: 80, b: 150 },
    green: { r: 50, g: 110, b: 65 },
  },
};

// Validate palette format
validatePalette(customPalette);

// Use in processing
const { canvas } = processImage(sourceCanvas, {
  displayWidth: 800,
  displayHeight: 480,
  palette: customPalette,
});

Palette Format

Palettes come in pairs - theoretical and perceived:

  • theoretical: The ideal RGB values that the e-paper display driver expects. These are the values written to the output image that the device firmware will interpret.
  • perceived: The actual RGB colors as they appear on the physical display when measured or observed. E-paper displays have limited color gamut - "white" is often grayish, "red" appears more muted, etc.

Why Two Palettes?

E-paper displays don't reproduce colors accurately. For example, when you send "pure red" (255, 0, 0) to a Spectra 6 display, the actual color that appears might be closer to (135, 19, 0) - a darker, less saturated red.

The dithering algorithm uses the perceived palette to make accurate color-matching decisions. When deciding which palette color best represents a pixel, we compare against what colors actually look like on the display, not what we tell the display to show.

The output image uses the theoretical palette because that's what the device firmware understands. The display driver maps these theoretical values to the appropriate ink colors.

This separation allows the dithering algorithm to produce visually accurate results while maintaining compatibility with the device's expected input format.

For a visual comparison showing the impact of using perceived palettes vs theoretical palettes, see the Image Quality Comparison in the ESP32 PhotoFrame project.

{
  "theoretical": {
    "black": { "r": 0, "g": 0, "b": 0 },
    "white": { "r": 255, "g": 255, "b": 255 },
    "yellow": { "r": 255, "g": 255, "b": 0 },
    "red": { "r": 255, "g": 0, "b": 0 },
    "blue": { "r": 0, "g": 0, "b": 255 },
    "green": { "r": 0, "g": 255, "b": 0 }
  },
  "perceived": {
    "black": { "r": 2, "g": 2, "b": 2 },
    "white": { "r": 190, "g": 190, "b": 190 },
    "yellow": { "r": 205, "g": 202, "b": 0 },
    "red": { "r": 135, "g": 19, "b": 0 },
    "blue": { "r": 5, "g": 64, "b": 158 },
    "green": { "r": 39, "g": 102, "b": 60 }
  }
}

Processing Presets

PresetDescriptionBest For
balancedCompressed dynamic range (default)General use, prevents overexposure
dynamicS-Curve tone mappingPhotos with good dynamic range
vividHigh saturationColorful images, illustrations
softLow contrastSubtle gradients
grayscaleLAB color spaceB&W photos, documents

Support

If you find this project useful, consider buying me a coffee! ☕

Buy Me A Coffee

License

MIT

Credits

Developed for the ESP32 PhotoFrame project.

版本与发布记录

@aitjcize/epaper-image-convert 共发布 21 个版本,首次发布于 2026/01/27;过去 12 个月发布了 21 个版本。

版本发布日期距今
0.1.21latest2026/10/051 个月前
0.1.202026/08/182 个月前
0.1.192026/08/172 个月前
0.1.182026/06/304 个月前
0.1.172026/06/294 个月前
0.1.152026/04/246 个月前

关于 @aitjcize/epaper-image-convert 的常见问题

@aitjcize/epaper-image-convert 是什么?

Convert images for e-paper displays with advanced tone mapping, dithering, and color palette optimization

如何安装 @aitjcize/epaper-image-convert?

在项目目录运行 npm install @aitjcize/epaper-image-convert,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 epaper-image-convert,可以用 npx epaper-image-convert 直接运行。

@aitjcize/epaper-image-convert 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/aitjcize__epaper-image-convert 是否存在。

@aitjcize/epaper-image-convert 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@aitjcize/epaper-image-convert 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=18.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@aitjcize/epaper-image-convert 可以商用吗?

@aitjcize/epaper-image-convert 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@aitjcize/epaper-image-convert 的下载量有多少?

根据 npm 官方下载统计,@aitjcize/epaper-image-convert 在 2026/10/05 – 2026/11/03 这 30 天内被下载 7,845 次,日均约 262 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@aitjcize/epaper-image-convert 还在维护吗?

最新版本 0.1.21 发布于 2026/10/05(1 个月前);至今共发布 21 个版本,其中过去 12 个月发布了 21 个;首次发布于 2026/01/27。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。