asciify-engine 1.0.61 → 1.0.64

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/dist/index.cjs CHANGED
@@ -284,9 +284,7 @@ function getCellColorStr(cell, colorMode, acR, acG, acB, _isInverted = false) {
284
284
  case "matrix":
285
285
  return GREEN_LUT[0.299 * cell.r + 0.587 * cell.g + 0.114 * cell.b | 0];
286
286
  case "accent": {
287
- const rawAb = (0.299 * cell.r + 0.587 * cell.g + 0.114 * cell.b) / 255;
288
- const ab = _isInverted ? 1 - rawAb : rawAb;
289
- return `rgb(${acR * ab | 0},${acG * ab | 0},${acB * ab | 0})`;
287
+ return `rgb(${acR},${acG},${acB})`;
290
288
  }
291
289
  default: {
292
290
  const gray = 0.299 * cell.r + 0.587 * cell.g + 0.114 * cell.b | 0;
@@ -310,11 +308,9 @@ function getCellColorRGB(cell, colorMode, acR, acG, acB, _isInverted = false) {
310
308
  break;
311
309
  }
312
310
  case "accent": {
313
- const rawAb = (0.299 * cell.r + 0.587 * cell.g + 0.114 * cell.b) / 255;
314
- const ab = _isInverted ? 1 - rawAb : rawAb;
315
- _colorRGB[0] = acR * ab | 0;
316
- _colorRGB[1] = acG * ab | 0;
317
- _colorRGB[2] = acB * ab | 0;
311
+ _colorRGB[0] = acR;
312
+ _colorRGB[1] = acG;
313
+ _colorRGB[2] = acB;
318
314
  break;
319
315
  }
320
316
  default: {
@@ -730,9 +726,14 @@ function imageToAsciiFrame(source, options, targetWidth, targetHeight) {
730
726
  if (cols <= 0 || rows <= 0) {
731
727
  return { frame: [], cols: 0, rows: 0 };
732
728
  }
733
- const { ctx } = createOffscreenCanvas(cols, rows);
734
- ctx.drawImage(source, 0, 0, cols, rows);
735
- const imageData = ctx.getImageData(0, 0, cols, rows);
729
+ const maxDim = 2048;
730
+ const ssX = Math.max(1, Math.min(Math.floor(maxDim / cols), Math.floor(srcWidth / cols)));
731
+ const ssY = Math.max(1, Math.min(Math.floor(maxDim / rows), Math.floor(srcHeight / rows)));
732
+ const sampleW = cols * ssX;
733
+ const sampleH = rows * ssY;
734
+ const { ctx } = createOffscreenCanvas(sampleW, sampleH);
735
+ ctx.drawImage(source, 0, 0, sampleW, sampleH);
736
+ const imageData = ctx.getImageData(0, 0, sampleW, sampleH);
736
737
  const pixels = imageData.data;
737
738
  const ck = options.chromaKey;
738
739
  const ckEnabled = ck != null && ck !== false;
@@ -771,36 +772,53 @@ function imageToAsciiFrame(source, options, targetWidth, targetHeight) {
771
772
  }
772
773
  const frame = [];
773
774
  const invertVal = resolveInvert(options.invert);
775
+ const effectiveCharset = ckEnabled ? options.charset.replace(/ /g, "") || options.charset : options.charset;
776
+ const ssCount = ssX * ssY;
774
777
  for (let y = 0; y < rows; y++) {
775
778
  const row = [];
776
779
  for (let x = 0; x < cols; x++) {
777
- const i = (y * cols + x) * 4;
778
- const r = pixels[i];
779
- const g = pixels[i + 1];
780
- const b = pixels[i + 2];
781
- const a = pixels[i + 3];
782
- if (ckEnabled) {
783
- let keyed = false;
784
- if (ckHeuristicGreen) {
785
- keyed = g > r * 1.4 && g > b * 1.4 && g > 80;
786
- } else if (ckHeuristicBlue) {
787
- keyed = b > r * 1.4 && b > g * 1.4 && b > 80;
788
- } else if (ckRGB !== null) {
789
- const dr = r - ckRGB.r;
790
- const dg = g - ckRGB.g;
791
- const db = b - ckRGB.b;
792
- keyed = dr * dr + dg * dg + db * db <= ckTolSq;
793
- }
794
- if (keyed) {
795
- row.push({ char: " ", r: 0, g: 0, b: 0, a: 0 });
796
- continue;
780
+ let sumR = 0, sumG = 0, sumB = 0, sumA = 0;
781
+ let keyedCount = 0;
782
+ for (let sy = 0; sy < ssY; sy++) {
783
+ const rowOff = (y * ssY + sy) * sampleW;
784
+ for (let sx = 0; sx < ssX; sx++) {
785
+ const i = (rowOff + x * ssX + sx) * 4;
786
+ const pr = pixels[i], pg = pixels[i + 1], pb = pixels[i + 2], pa = pixels[i + 3];
787
+ if (ckEnabled) {
788
+ let keyed = false;
789
+ if (ckHeuristicGreen) {
790
+ keyed = pg > pr * 1.4 && pg > pb * 1.4 && pg > 80;
791
+ } else if (ckHeuristicBlue) {
792
+ keyed = pb > pr * 1.4 && pb > pg * 1.4 && pb > 80;
793
+ } else if (ckRGB !== null) {
794
+ const dr = pr - ckRGB.r, dg = pg - ckRGB.g, db = pb - ckRGB.b;
795
+ keyed = dr * dr + dg * dg + db * db <= ckTolSq;
796
+ }
797
+ if (keyed) {
798
+ keyedCount++;
799
+ continue;
800
+ }
801
+ }
802
+ sumR += pr;
803
+ sumG += pg;
804
+ sumB += pb;
805
+ sumA += pa;
797
806
  }
798
807
  }
808
+ if (ckEnabled && keyedCount > ssCount / 2) {
809
+ row.push({ char: " ", r: 0, g: 0, b: 0, a: 0 });
810
+ continue;
811
+ }
812
+ const nonKeyed = ssCount - keyedCount;
813
+ const r = nonKeyed > 0 ? sumR / nonKeyed : 0;
814
+ const g = nonKeyed > 0 ? sumG / nonKeyed : 0;
815
+ const b = nonKeyed > 0 ? sumB / nonKeyed : 0;
816
+ const a = nonKeyed > 0 ? sumA / nonKeyed : 0;
799
817
  const rawLum = 0.299 * r + 0.587 * g + 0.114 * b;
800
818
  const lum = options.normalize ? (rawLum - normMin) / normRange * 255 : rawLum;
801
819
  const adjustedLum = adjustLuminance(lum, options.brightness, options.contrast);
802
820
  const ditheredLum = applyDither(adjustedLum, x, y, options.ditherStrength);
803
- const char = options.customText ? customTextToChar(ditheredLum, options.customText, x, y, cols, invertVal) : luminanceToChar(ditheredLum, options.charset, invertVal);
821
+ const char = options.customText ? customTextToChar(ditheredLum, options.customText, x, y, cols, invertVal) : luminanceToChar(ditheredLum, effectiveCharset, invertVal);
804
822
  row.push({ char, r, g, b, a, lum: ditheredLum });
805
823
  }
806
824
  frame.push(row);