asciify-engine 1.0.38 → 1.0.39

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/README.md CHANGED
@@ -387,6 +387,8 @@ Used by `asciify()`, `asciifyGif()`, and `asciifyVideo()`:
387
387
  | `artStyle` | `ArtStyle` | `'classic'` | Art style preset (see `ART_STYLE_PRESETS`) |
388
388
  | `ditherStrength` | `number` | `0` | Floyd-Steinberg dither intensity (0–1) |
389
389
  | `dotSizeRatio` | `number` | `0.8` | Dot size when `renderMode === 'dots'` (fraction of cell) |
390
+ | `charAspect` | `number` | `0.55` | Width ÷ height of a single output character. Set to `0.5` for terminal emulators, `0.52` for browser `line-height: 1.15`, `0.55` for `line-height: 1.09`. Ensuring this matches your rendering environment keeps the output proportional to the source. |
391
+ | `normalize` | `boolean` | `false` | Auto-stretch the luminance range of the frame before charset mapping. Maximises detail and contrast for low-contrast or muted images. |
390
392
 
391
393
  ### Art Styles (`artStyle`)
392
394
 
package/dist/index.cjs CHANGED
@@ -112,6 +112,8 @@ var DEFAULT_OPTIONS = {
112
112
  animationSpeed: 1,
113
113
  dotSizeRatio: 0.8,
114
114
  ditherStrength: 0,
115
+ charAspect: 0.55,
116
+ normalize: false,
115
117
  hoverStrength: 0,
116
118
  hoverRadius: 0.2,
117
119
  hoverEffect: "spotlight",
@@ -606,7 +608,7 @@ function imageToAsciiFrame(source, options, targetWidth, targetHeight) {
606
608
  if (srcWidth === 0 || srcHeight === 0) {
607
609
  return { frame: [], cols: 0, rows: 0 };
608
610
  }
609
- const charAspect = 0.55;
611
+ const charAspect = options.charAspect;
610
612
  const cellW = options.fontSize * options.charSpacing;
611
613
  const cellH = options.fontSize / charAspect * options.charSpacing;
612
614
  const renderW = targetWidth || srcWidth;
@@ -620,6 +622,18 @@ function imageToAsciiFrame(source, options, targetWidth, targetHeight) {
620
622
  ctx.drawImage(source, 0, 0, cols, rows);
621
623
  const imageData = ctx.getImageData(0, 0, cols, rows);
622
624
  const pixels = imageData.data;
625
+ let normMin = 0;
626
+ let normRange = 255;
627
+ if (options.normalize) {
628
+ let lo = 255, hi = 0;
629
+ for (let k = 0; k < pixels.length; k += 4) {
630
+ const l = 0.299 * pixels[k] + 0.587 * pixels[k + 1] + 0.114 * pixels[k + 2];
631
+ if (l < lo) lo = l;
632
+ if (l > hi) hi = l;
633
+ }
634
+ normMin = lo;
635
+ normRange = hi > lo ? hi - lo : 255;
636
+ }
623
637
  const frame = [];
624
638
  for (let y = 0; y < rows; y++) {
625
639
  const row = [];
@@ -629,7 +643,8 @@ function imageToAsciiFrame(source, options, targetWidth, targetHeight) {
629
643
  const g = pixels[i + 1];
630
644
  const b = pixels[i + 2];
631
645
  const a = pixels[i + 3];
632
- const lum = 0.299 * r + 0.587 * g + 0.114 * b;
646
+ const rawLum = 0.299 * r + 0.587 * g + 0.114 * b;
647
+ const lum = options.normalize ? (rawLum - normMin) / normRange * 255 : rawLum;
633
648
  const adjustedLum = adjustLuminance(lum, options.brightness, options.contrast);
634
649
  const ditheredLum = applyDither(adjustedLum, x, y, options.ditherStrength);
635
650
  const char = options.customText ? customTextToChar(ditheredLum, options.customText, x, y, cols, options.invert) : luminanceToChar(ditheredLum, options.charset, options.invert);