var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __reExport = (target, module2, copyDefault, desc) => {
  if (module2 && typeof module2 === "object" || typeof module2 === "function") {
    for (let key of __getOwnPropNames(module2))
      if (!__hasOwnProp.call(target, key) && (copyDefault || key !== "default"))
        __defProp(target, key, { get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable });
  }
  return target;
};
var __toCommonJS = /* @__PURE__ */ ((cache) => {
  return (module2, temp) => {
    return cache && cache.get(module2) || (temp = __reExport(__markAsModule({}), module2, 1), cache && cache.set(module2, temp), temp);
  };
})(typeof WeakMap !== "undefined" ? /* @__PURE__ */ new WeakMap() : 0);
var __publicField = (obj, key, value) => {
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
  return value;
};

// src/index.ts
var src_exports = {};
__export(src_exports, {
  applyPalette: () => applyPalette,
  applyPaletteSync: () => applyPaletteSync,
  buildPalette: () => buildPalette,
  buildPaletteSync: () => buildPaletteSync,
  constants: () => constants_exports,
  conversion: () => conversion_exports,
  distance: () => distance_exports,
  image: () => image_exports,
  palette: () => palette_exports,
  quality: () => quality_exports,
  utils: () => utils_exports
});

// src/constants/index.ts
var constants_exports = {};
__export(constants_exports, {
  bt709: () => bt709_exports
});

// src/constants/bt709.ts
var bt709_exports = {};
__export(bt709_exports, {
  Y: () => Y,
  x: () => x,
  y: () => y
});
var Y = /* @__PURE__ */ ((Y2) => {
  Y2[Y2["RED"] = 0.2126] = "RED";
  Y2[Y2["GREEN"] = 0.7152] = "GREEN";
  Y2[Y2["BLUE"] = 0.0722] = "BLUE";
  Y2[Y2["WHITE"] = 1] = "WHITE";
  return Y2;
})(Y || {});
var x = /* @__PURE__ */ ((x2) => {
  x2[x2["RED"] = 0.64] = "RED";
  x2[x2["GREEN"] = 0.3] = "GREEN";
  x2[x2["BLUE"] = 0.15] = "BLUE";
  x2[x2["WHITE"] = 0.3127] = "WHITE";
  return x2;
})(x || {});
var y = /* @__PURE__ */ ((y2) => {
  y2[y2["RED"] = 0.33] = "RED";
  y2[y2["GREEN"] = 0.6] = "GREEN";
  y2[y2["BLUE"] = 0.06] = "BLUE";
  y2[y2["WHITE"] = 0.329] = "WHITE";
  return y2;
})(y || {});

// src/conversion/index.ts
var conversion_exports = {};
__export(conversion_exports, {
  lab2rgb: () => lab2rgb,
  lab2xyz: () => lab2xyz,
  rgb2hsl: () => rgb2hsl,
  rgb2lab: () => rgb2lab,
  rgb2xyz: () => rgb2xyz,
  xyz2lab: () => xyz2lab,
  xyz2rgb: () => xyz2rgb
});

// src/conversion/rgb2xyz.ts
function correctGamma(n) {
  return n > 0.04045 ? ((n + 0.055) / 1.055) ** 2.4 : n / 12.92;
}
function rgb2xyz(r, g, b) {
  r = correctGamma(r / 255);
  g = correctGamma(g / 255);
  b = correctGamma(b / 255);
  return {
    x: r * 0.4124 + g * 0.3576 + b * 0.1805,
    y: r * 0.2126 + g * 0.7152 + b * 0.0722,
    z: r * 0.0193 + g * 0.1192 + b * 0.9505
  };
}

// src/utils/arithmetic.ts
var arithmetic_exports = {};
__export(arithmetic_exports, {
  degrees2radians: () => degrees2radians,
  inRange0to255: () => inRange0to255,
  inRange0to255Rounded: () => inRange0to255Rounded,
  intInRange: () => intInRange,
  max3: () => max3,
  min3: () => min3,
  stableSort: () => stableSort
});
function degrees2radians(n) {
  return n * (Math.PI / 180);
}
function max3(a, b, c) {
  let m = a;
  if (m < b)
    m = b;
  if (m < c)
    m = c;
  return m;
}
function min3(a, b, c) {
  let m = a;
  if (m > b)
    m = b;
  if (m > c)
    m = c;
  return m;
}
function intInRange(value, low, high) {
  if (value > high)
    value = high;
  if (value < low)
    value = low;
  return value | 0;
}
function inRange0to255Rounded(n) {
  n = Math.round(n);
  if (n > 255)
    n = 255;
  else if (n < 0)
    n = 0;
  return n;
}
function inRange0to255(n) {
  if (n > 255)
    n = 255;
  else if (n < 0)
    n = 0;
  return n;
}
function stableSort(arrayToSort, callback) {
  const type = typeof arrayToSort[0];
  let sorted;
  if (type === "number" || type === "string") {
    const ord = /* @__PURE__ */ Object.create(null);
    for (let i = 0, l = arrayToSort.length; i < l; i++) {
      const val = arrayToSort[i];
      if (ord[val] || ord[val] === 0)
        continue;
      ord[val] = i;
    }
    sorted = arrayToSort.sort((a, b) => callback(a, b) || ord[a] - ord[b]);
  } else {
    const ord2 = arrayToSort.slice(0);
    sorted = arrayToSort.sort((a, b) => callback(a, b) || ord2.indexOf(a) - ord2.indexOf(b));
  }
  return sorted;
}

// src/conversion/rgb2hsl.ts
function rgb2hsl(r, g, b) {
  const min = min3(r, g, b);
  const max = max3(r, g, b);
  const delta = max - min;
  const l = (min + max) / 510;
  let s = 0;
  if (l > 0 && l < 1)
    s = delta / (l < 0.5 ? max + min : 510 - max - min);
  let h = 0;
  if (delta > 0) {
    if (max === r) {
      h = (g - b) / delta;
    } else if (max === g) {
      h = 2 + (b - r) / delta;
    } else {
      h = 4 + (r - g) / delta;
    }
    h *= 60;
    if (h < 0)
      h += 360;
  }
  return { h, s, l };
}

// src/conversion/xyz2lab.ts
var refX = 0.95047;
var refY = 1;
var refZ = 1.08883;
function pivot(n) {
  return n > 8856e-6 ? n ** (1 / 3) : 7.787 * n + 16 / 116;
}
function xyz2lab(x2, y2, z) {
  x2 = pivot(x2 / refX);
  y2 = pivot(y2 / refY);
  z = pivot(z / refZ);
  if (116 * y2 - 16 < 0)
    throw new Error("xxx");
  return {
    L: Math.max(0, 116 * y2 - 16),
    a: 500 * (x2 - y2),
    b: 200 * (y2 - z)
  };
}

// src/conversion/rgb2lab.ts
function rgb2lab(r, g, b) {
  const xyz = rgb2xyz(r, g, b);
  return xyz2lab(xyz.x, xyz.y, xyz.z);
}

// src/conversion/lab2xyz.ts
var refX2 = 0.95047;
var refY2 = 1;
var refZ2 = 1.08883;
function pivot2(n) {
  return n > 0.206893034 ? n ** 3 : (n - 16 / 116) / 7.787;
}
function lab2xyz(L, a, b) {
  const y2 = (L + 16) / 116;
  const x2 = a / 500 + y2;
  const z = y2 - b / 200;
  return {
    x: refX2 * pivot2(x2),
    y: refY2 * pivot2(y2),
    z: refZ2 * pivot2(z)
  };
}

// src/conversion/xyz2rgb.ts
function correctGamma2(n) {
  return n > 31308e-7 ? 1.055 * n ** (1 / 2.4) - 0.055 : 12.92 * n;
}
function xyz2rgb(x2, y2, z) {
  const r = correctGamma2(x2 * 3.2406 + y2 * -1.5372 + z * -0.4986);
  const g = correctGamma2(x2 * -0.9689 + y2 * 1.8758 + z * 0.0415);
  const b = correctGamma2(x2 * 0.0557 + y2 * -0.204 + z * 1.057);
  return {
    r: inRange0to255Rounded(r * 255),
    g: inRange0to255Rounded(g * 255),
    b: inRange0to255Rounded(b * 255)
  };
}

// src/conversion/lab2rgb.ts
function lab2rgb(L, a, b) {
  const xyz = lab2xyz(L, a, b);
  return xyz2rgb(xyz.x, xyz.y, xyz.z);
}

// src/distance/index.ts
var distance_exports = {};
__export(distance_exports, {
  AbstractDistanceCalculator: () => AbstractDistanceCalculator,
  AbstractEuclidean: () => AbstractEuclidean,
  AbstractManhattan: () => AbstractManhattan,
  CIE94GraphicArts: () => CIE94GraphicArts,
  CIE94Textiles: () => CIE94Textiles,
  CIEDE2000: () => CIEDE2000,
  CMetric: () => CMetric,
  Euclidean: () => Euclidean,
  EuclideanBT709: () => EuclideanBT709,
  EuclideanBT709NoAlpha: () => EuclideanBT709NoAlpha,
  Manhattan: () => Manhattan,
  ManhattanBT709: () => ManhattanBT709,
  ManhattanNommyde: () => ManhattanNommyde,
  PNGQuant: () => PNGQuant
});

// src/distance/distanceCalculator.ts
var AbstractDistanceCalculator = class {
  constructor() {
    __publicField(this, "_maxDistance");
    __publicField(this, "_whitePoint");
    this._setDefaults();
    this.setWhitePoint(255, 255, 255, 255);
  }
  setWhitePoint(r, g, b, a) {
    this._whitePoint = {
      r: r > 0 ? 255 / r : 0,
      g: g > 0 ? 255 / g : 0,
      b: b > 0 ? 255 / b : 0,
      a: a > 0 ? 255 / a : 0
    };
    this._maxDistance = this.calculateRaw(r, g, b, a, 0, 0, 0, 0);
  }
  calculateNormalized(colorA, colorB) {
    return this.calculateRaw(colorA.r, colorA.g, colorA.b, colorA.a, colorB.r, colorB.g, colorB.b, colorB.a) / this._maxDistance;
  }
};

// src/distance/cie94.ts
var AbstractCIE94 = class extends AbstractDistanceCalculator {
  calculateRaw(r1, g1, b1, a1, r2, g2, b2, a2) {
    const lab1 = rgb2lab(inRange0to255(r1 * this._whitePoint.r), inRange0to255(g1 * this._whitePoint.g), inRange0to255(b1 * this._whitePoint.b));
    const lab2 = rgb2lab(inRange0to255(r2 * this._whitePoint.r), inRange0to255(g2 * this._whitePoint.g), inRange0to255(b2 * this._whitePoint.b));
    const dL = lab1.L - lab2.L;
    const dA = lab1.a - lab2.a;
    const dB = lab1.b - lab2.b;
    const c1 = Math.sqrt(lab1.a * lab1.a + lab1.b * lab1.b);
    const c2 = Math.sqrt(lab2.a * lab2.a + lab2.b * lab2.b);
    const dC = c1 - c2;
    let deltaH = dA * dA + dB * dB - dC * dC;
    deltaH = deltaH < 0 ? 0 : Math.sqrt(deltaH);
    const dAlpha = (a2 - a1) * this._whitePoint.a * this._kA;
    return Math.sqrt((dL / this._Kl) ** 2 + (dC / (1 + this._K1 * c1)) ** 2 + (deltaH / (1 + this._K2 * c1)) ** 2 + dAlpha ** 2);
  }
};
var CIE94Textiles = class extends AbstractCIE94 {
  _setDefaults() {
    this._Kl = 2;
    this._K1 = 0.048;
    this._K2 = 0.014;
    this._kA = 0.25 * 50 / 255;
  }
};
var CIE94GraphicArts = class extends AbstractCIE94 {
  _setDefaults() {
    this._Kl = 1;
    this._K1 = 0.045;
    this._K2 = 0.015;
    this._kA = 0.25 * 100 / 255;
  }
};

// src/distance/ciede2000.ts
var _CIEDE2000 = class extends AbstractDistanceCalculator {
  _setDefaults() {
  }
  static _calculatehp(b, ap) {
    const hp = Math.atan2(b, ap);
    if (hp >= 0)
      return hp;
    return hp + _CIEDE2000._deg360InRad;
  }
  static _calculateRT(ahp, aCp) {
    const aCp_to_7 = aCp ** 7;
    const R_C = 2 * Math.sqrt(aCp_to_7 / (aCp_to_7 + _CIEDE2000._pow25to7));
    const delta_theta = _CIEDE2000._deg30InRad * Math.exp(-(((ahp - _CIEDE2000._deg275InRad) / _CIEDE2000._deg25InRad) ** 2));
    return -Math.sin(2 * delta_theta) * R_C;
  }
  static _calculateT(ahp) {
    return 1 - 0.17 * Math.cos(ahp - _CIEDE2000._deg30InRad) + 0.24 * Math.cos(ahp * 2) + 0.32 * Math.cos(ahp * 3 + _CIEDE2000._deg6InRad) - 0.2 * Math.cos(ahp * 4 - _CIEDE2000._deg63InRad);
  }
  static _calculate_ahp(C1pC2p, h_bar, h1p, h2p) {
    const hpSum = h1p + h2p;
    if (C1pC2p === 0)
      return hpSum;
    if (h_bar <= _CIEDE2000._deg180InRad)
      return hpSum / 2;
    if (hpSum < _CIEDE2000._deg360InRad) {
      return (hpSum + _CIEDE2000._deg360InRad) / 2;
    }
    return (hpSum - _CIEDE2000._deg360InRad) / 2;
  }
  static _calculate_dHp(C1pC2p, h_bar, h2p, h1p) {
    let dhp;
    if (C1pC2p === 0) {
      dhp = 0;
    } else if (h_bar <= _CIEDE2000._deg180InRad) {
      dhp = h2p - h1p;
    } else if (h2p <= h1p) {
      dhp = h2p - h1p + _CIEDE2000._deg360InRad;
    } else {
      dhp = h2p - h1p - _CIEDE2000._deg360InRad;
    }
    return 2 * Math.sqrt(C1pC2p) * Math.sin(dhp / 2);
  }
  calculateRaw(r1, g1, b1, a1, r2, g2, b2, a2) {
    const lab1 = rgb2lab(inRange0to255(r1 * this._whitePoint.r), inRange0to255(g1 * this._whitePoint.g), inRange0to255(b1 * this._whitePoint.b));
    const lab2 = rgb2lab(inRange0to255(r2 * this._whitePoint.r), inRange0to255(g2 * this._whitePoint.g), inRange0to255(b2 * this._whitePoint.b));
    const dA = (a2 - a1) * this._whitePoint.a * _CIEDE2000._kA;
    const dE2 = this.calculateRawInLab(lab1, lab2);
    return Math.sqrt(dE2 + dA * dA);
  }
  calculateRawInLab(Lab1, Lab2) {
    const L1 = Lab1.L;
    const a1 = Lab1.a;
    const b1 = Lab1.b;
    const L2 = Lab2.L;
    const a2 = Lab2.a;
    const b2 = Lab2.b;
    const C1 = Math.sqrt(a1 * a1 + b1 * b1);
    const C2 = Math.sqrt(a2 * a2 + b2 * b2);
    const pow_a_C1_C2_to_7 = ((C1 + C2) / 2) ** 7;
    const G = 0.5 * (1 - Math.sqrt(pow_a_C1_C2_to_7 / (pow_a_C1_C2_to_7 + _CIEDE2000._pow25to7)));
    const a1p = (1 + G) * a1;
    const a2p = (1 + G) * a2;
    const C1p = Math.sqrt(a1p * a1p + b1 * b1);
    const C2p = Math.sqrt(a2p * a2p + b2 * b2);
    const C1pC2p = C1p * C2p;
    const h1p = _CIEDE2000._calculatehp(b1, a1p);
    const h2p = _CIEDE2000._calculatehp(b2, a2p);
    const h_bar = Math.abs(h1p - h2p);
    const dLp = L2 - L1;
    const dCp = C2p - C1p;
    const dHp = _CIEDE2000._calculate_dHp(C1pC2p, h_bar, h2p, h1p);
    const ahp = _CIEDE2000._calculate_ahp(C1pC2p, h_bar, h1p, h2p);
    const T = _CIEDE2000._calculateT(ahp);
    const aCp = (C1p + C2p) / 2;
    const aLp_minus_50_square = ((L1 + L2) / 2 - 50) ** 2;
    const S_L = 1 + 0.015 * aLp_minus_50_square / Math.sqrt(20 + aLp_minus_50_square);
    const S_C = 1 + 0.045 * aCp;
    const S_H = 1 + 0.015 * T * aCp;
    const R_T = _CIEDE2000._calculateRT(ahp, aCp);
    const dLpSL = dLp / S_L;
    const dCpSC = dCp / S_C;
    const dHpSH = dHp / S_H;
    return dLpSL ** 2 + dCpSC ** 2 + dHpSH ** 2 + R_T * dCpSC * dHpSH;
  }
};
var CIEDE2000 = _CIEDE2000;
__publicField(CIEDE2000, "_kA", 0.25 * 100 / 255);
__publicField(CIEDE2000, "_pow25to7", 25 ** 7);
__publicField(CIEDE2000, "_deg360InRad", degrees2radians(360));
__publicField(CIEDE2000, "_deg180InRad", degrees2radians(180));
__publicField(CIEDE2000, "_deg30InRad", degrees2radians(30));
__publicField(CIEDE2000, "_deg6InRad", degrees2radians(6));
__publicField(CIEDE2000, "_deg63InRad", degrees2radians(63));
__publicField(CIEDE2000, "_deg275InRad", degrees2radians(275));
__publicField(CIEDE2000, "_deg25InRad", degrees2radians(25));

// src/distance/cmetric.ts
var CMetric = class extends AbstractDistanceCalculator {
  calculateRaw(r1, g1, b1, a1, r2, g2, b2, a2) {
    const rmean = (r1 + r2) / 2 * this._whitePoint.r;
    const r = (r1 - r2) * this._whitePoint.r;
    const g = (g1 - g2) * this._whitePoint.g;
    const b = (b1 - b2) * this._whitePoint.b;
    const dE = ((512 + rmean) * r * r >> 8) + 4 * g * g + ((767 - rmean) * b * b >> 8);
    const dA = (a2 - a1) * this._whitePoint.a;
    return Math.sqrt(dE + dA * dA);
  }
  _setDefaults() {
  }
};

// src/distance/euclidean.ts
var AbstractEuclidean = class extends AbstractDistanceCalculator {
  calculateRaw(r1, g1, b1, a1, r2, g2, b2, a2) {
    const dR = r2 - r1;
    const dG = g2 - g1;
    const dB = b2 - b1;
    const dA = a2 - a1;
    return Math.sqrt(this._kR * dR * dR + this._kG * dG * dG + this._kB * dB * dB + this._kA * dA * dA);
  }
};
var Euclidean = class extends AbstractEuclidean {
  _setDefaults() {
    this._kR = 1;
    this._kG = 1;
    this._kB = 1;
    this._kA = 1;
  }
};
var EuclideanBT709 = class extends AbstractEuclidean {
  _setDefaults() {
    this._kR = 0.2126 /* RED */;
    this._kG = 0.7152 /* GREEN */;
    this._kB = 0.0722 /* BLUE */;
    this._kA = 1;
  }
};
var EuclideanBT709NoAlpha = class extends AbstractEuclidean {
  _setDefaults() {
    this._kR = 0.2126 /* RED */;
    this._kG = 0.7152 /* GREEN */;
    this._kB = 0.0722 /* BLUE */;
    this._kA = 0;
  }
};

// src/distance/manhattan.ts
var AbstractManhattan = class extends AbstractDistanceCalculator {
  calculateRaw(r1, g1, b1, a1, r2, g2, b2, a2) {
    let dR = r2 - r1;
    let dG = g2 - g1;
    let dB = b2 - b1;
    let dA = a2 - a1;
    if (dR < 0)
      dR = 0 - dR;
    if (dG < 0)
      dG = 0 - dG;
    if (dB < 0)
      dB = 0 - dB;
    if (dA < 0)
      dA = 0 - dA;
    return this._kR * dR + this._kG * dG + this._kB * dB + this._kA * dA;
  }
};
var Manhattan = class extends AbstractManhattan {
  _setDefaults() {
    this._kR = 1;
    this._kG = 1;
    this._kB = 1;
    this._kA = 1;
  }
};
var ManhattanNommyde = class extends AbstractManhattan {
  _setDefaults() {
    this._kR = 0.4984;
    this._kG = 0.8625;
    this._kB = 0.2979;
    this._kA = 1;
  }
};
var ManhattanBT709 = class extends AbstractManhattan {
  _setDefaults() {
    this._kR = 0.2126 /* RED */;
    this._kG = 0.7152 /* GREEN */;
    this._kB = 0.0722 /* BLUE */;
    this._kA = 1;
  }
};

// src/distance/pngQuant.ts
var PNGQuant = class extends AbstractDistanceCalculator {
  calculateRaw(r1, g1, b1, a1, r2, g2, b2, a2) {
    const alphas = (a2 - a1) * this._whitePoint.a;
    return this._colordifferenceCh(r1 * this._whitePoint.r, r2 * this._whitePoint.r, alphas) + this._colordifferenceCh(g1 * this._whitePoint.g, g2 * this._whitePoint.g, alphas) + this._colordifferenceCh(b1 * this._whitePoint.b, b2 * this._whitePoint.b, alphas);
  }
  _colordifferenceCh(x2, y2, alphas) {
    const black = x2 - y2;
    const white = black + alphas;
    return black * black + white * white;
  }
  _setDefaults() {
  }
};

// src/palette/index.ts
var palette_exports = {};
__export(palette_exports, {
  AbstractPaletteQuantizer: () => AbstractPaletteQuantizer,
  ColorHistogram: () => ColorHistogram,
  NeuQuant: () => NeuQuant,
  NeuQuantFloat: () => NeuQuantFloat,
  RGBQuant: () => RGBQuant,
  WuColorCube: () => WuColorCube,
  WuQuant: () => WuQuant
});

// src/palette/paletteQuantizer.ts
var AbstractPaletteQuantizer = class {
  quantizeSync() {
    for (const value of this.quantize()) {
      if (value.palette) {
        return value.palette;
      }
    }
    throw new Error("unreachable");
  }
};

// src/utils/point.ts
var Point = class {
  constructor() {
    __publicField(this, "r");
    __publicField(this, "g");
    __publicField(this, "b");
    __publicField(this, "a");
    __publicField(this, "uint32");
    __publicField(this, "rgba");
    this.uint32 = -1 >>> 0;
    this.r = this.g = this.b = this.a = 0;
    this.rgba = new Array(4);
    this.rgba[0] = 0;
    this.rgba[1] = 0;
    this.rgba[2] = 0;
    this.rgba[3] = 0;
  }
  static createByQuadruplet(quadruplet) {
    const point = new Point();
    point.r = quadruplet[0] | 0;
    point.g = quadruplet[1] | 0;
    point.b = quadruplet[2] | 0;
    point.a = quadruplet[3] | 0;
    point._loadUINT32();
    point._loadQuadruplet();
    return point;
  }
  static createByRGBA(red, green, blue, alpha) {
    const point = new Point();
    point.r = red | 0;
    point.g = green | 0;
    point.b = blue | 0;
    point.a = alpha | 0;
    point._loadUINT32();
    point._loadQuadruplet();
    return point;
  }
  static createByUint32(uint32) {
    const point = new Point();
    point.uint32 = uint32 >>> 0;
    point._loadRGBA();
    point._loadQuadruplet();
    return point;
  }
  from(point) {
    this.r = point.r;
    this.g = point.g;
    this.b = point.b;
    this.a = point.a;
    this.uint32 = point.uint32;
    this.rgba[0] = point.r;
    this.rgba[1] = point.g;
    this.rgba[2] = point.b;
    this.rgba[3] = point.a;
  }
  getLuminosity(useAlphaChannel) {
    let r = this.r;
    let g = this.g;
    let b = this.b;
    if (useAlphaChannel) {
      r = Math.min(255, 255 - this.a + this.a * r / 255);
      g = Math.min(255, 255 - this.a + this.a * g / 255);
      b = Math.min(255, 255 - this.a + this.a * b / 255);
    }
    return r * 0.2126 /* RED */ + g * 0.7152 /* GREEN */ + b * 0.0722 /* BLUE */;
  }
  _loadUINT32() {
    this.uint32 = (this.a << 24 | this.b << 16 | this.g << 8 | this.r) >>> 0;
  }
  _loadRGBA() {
    this.r = this.uint32 & 255;
    this.g = this.uint32 >>> 8 & 255;
    this.b = this.uint32 >>> 16 & 255;
    this.a = this.uint32 >>> 24 & 255;
  }
  _loadQuadruplet() {
    this.rgba[0] = this.r;
    this.rgba[1] = this.g;
    this.rgba[2] = this.b;
    this.rgba[3] = this.a;
  }
};

// src/utils/pointContainer.ts
var PointContainer = class {
  constructor() {
    __publicField(this, "_pointArray");
    __publicField(this, "_width");
    __publicField(this, "_height");
    this._width = 0;
    this._height = 0;
    this._pointArray = [];
  }
  getWidth() {
    return this._width;
  }
  getHeight() {
    return this._height;
  }
  setWidth(width) {
    this._width = width;
  }
  setHeight(height) {
    this._height = height;
  }
  getPointArray() {
    return this._pointArray;
  }
  clone() {
    const clone = new PointContainer();
    clone._width = this._width;
    clone._height = this._height;
    for (let i = 0, l = this._pointArray.length; i < l; i++) {
      clone._pointArray[i] = Point.createByUint32(this._pointArray[i].uint32 | 0);
    }
    return clone;
  }
  toUint32Array() {
    const l = this._pointArray.length;
    const uint32Array = new Uint32Array(l);
    for (let i = 0; i < l; i++) {
      uint32Array[i] = this._pointArray[i].uint32;
    }
    return uint32Array;
  }
  toUint8Array() {
    return new Uint8Array(this.toUint32Array().buffer);
  }
  static fromHTMLImageElement(img) {
    const width = img.naturalWidth;
    const height = img.naturalHeight;
    const canvas = document.createElement("canvas");
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext("2d");
    ctx.drawImage(img, 0, 0, width, height, 0, 0, width, height);
    return PointContainer.fromHTMLCanvasElement(canvas);
  }
  static fromHTMLCanvasElement(canvas) {
    const width = canvas.width;
    const height = canvas.height;
    const ctx = canvas.getContext("2d");
    const imgData = ctx.getImageData(0, 0, width, height);
    return PointContainer.fromImageData(imgData);
  }
  static fromImageData(imageData) {
    const width = imageData.width;
    const height = imageData.height;
    return PointContainer.fromUint8Array(imageData.data, width, height);
  }
  static fromUint8Array(uint8Array, width, height) {
    switch (Object.prototype.toString.call(uint8Array)) {
      case "[object Uint8ClampedArray]":
      case "[object Uint8Array]":
        break;
      default:
        uint8Array = new Uint8Array(uint8Array);
    }
    const uint32Array = new Uint32Array(uint8Array.buffer);
    return PointContainer.fromUint32Array(uint32Array, width, height);
  }
  static fromUint32Array(uint32Array, width, height) {
    const container = new PointContainer();
    container._width = width;
    container._height = height;
    for (let i = 0, l = uint32Array.length; i < l; i++) {
      container._pointArray[i] = Point.createByUint32(uint32Array[i] | 0);
    }
    return container;
  }
  static fromBuffer(buffer, width, height) {
    const uint32Array = new Uint32Array(buffer.buffer, buffer.byteOffset, buffer.byteLength / Uint32Array.BYTES_PER_ELEMENT);
    return PointContainer.fromUint32Array(uint32Array, width, height);
  }
};

// src/utils/palette.ts
var hueGroups = 10;
function hueGroup(hue, segmentsNumber) {
  const maxHue = 360;
  const seg = maxHue / segmentsNumber;
  const half = seg / 2;
  for (let i = 1, mid = seg - half; i < segmentsNumber; i++, mid += seg) {
    if (hue >= mid && hue < mid + seg)
      return i;
  }
  return 0;
}
var Palette = class {
  constructor() {
    __publicField(this, "_pointContainer");
    __publicField(this, "_pointArray", []);
    __publicField(this, "_i32idx", {});
    this._pointContainer = new PointContainer();
    this._pointContainer.setHeight(1);
    this._pointArray = this._pointContainer.getPointArray();
  }
  add(color) {
    this._pointArray.push(color);
    this._pointContainer.setWidth(this._pointArray.length);
  }
  has(color) {
    for (let i = this._pointArray.length - 1; i >= 0; i--) {
      if (color.uint32 === this._pointArray[i].uint32)
        return true;
    }
    return false;
  }
  getNearestColor(colorDistanceCalculator, color) {
    return this._pointArray[this._getNearestIndex(colorDistanceCalculator, color) | 0];
  }
  getPointContainer() {
    return this._pointContainer;
  }
  _nearestPointFromCache(key) {
    return typeof this._i32idx[key] === "number" ? this._i32idx[key] : -1;
  }
  _getNearestIndex(colorDistanceCalculator, point) {
    let idx = this._nearestPointFromCache("" + point.uint32);
    if (idx >= 0)
      return idx;
    let minimalDistance = Number.MAX_VALUE;
    idx = 0;
    for (let i = 0, l = this._pointArray.length; i < l; i++) {
      const p = this._pointArray[i];
      const distance = colorDistanceCalculator.calculateRaw(point.r, point.g, point.b, point.a, p.r, p.g, p.b, p.a);
      if (distance < minimalDistance) {
        minimalDistance = distance;
        idx = i;
      }
    }
    this._i32idx[point.uint32] = idx;
    return idx;
  }
  sort() {
    this._i32idx = {};
    this._pointArray.sort((a, b) => {
      const hslA = rgb2hsl(a.r, a.g, a.b);
      const hslB = rgb2hsl(b.r, b.g, b.b);
      const hueA = a.r === a.g && a.g === a.b ? 0 : 1 + hueGroup(hslA.h, hueGroups);
      const hueB = b.r === b.g && b.g === b.b ? 0 : 1 + hueGroup(hslB.h, hueGroups);
      const hueDiff = hueB - hueA;
      if (hueDiff)
        return -hueDiff;
      const lA = a.getLuminosity(true);
      const lB = b.getLuminosity(true);
      if (lB - lA !== 0)
        return lB - lA;
      const satDiff = (hslB.s * 100 | 0) - (hslA.s * 100 | 0);
      if (satDiff)
        return -satDiff;
      return 0;
    });
  }
};

// src/utils/index.ts
var utils_exports = {};
__export(utils_exports, {
  HueStatistics: () => HueStatistics,
  Palette: () => Palette,
  Point: () => Point,
  PointContainer: () => PointContainer,
  ProgressTracker: () => ProgressTracker,
  arithmetic: () => arithmetic_exports
});

// src/utils/hueStatistics.ts
var HueGroup = class {
  constructor() {
    __publicField(this, "num", 0);
    __publicField(this, "cols", []);
  }
};
var HueStatistics = class {
  constructor(numGroups, minCols) {
    __publicField(this, "_numGroups");
    __publicField(this, "_minCols");
    __publicField(this, "_stats");
    __publicField(this, "_groupsFull");
    this._numGroups = numGroups;
    this._minCols = minCols;
    this._stats = [];
    for (let i = 0; i <= numGroups; i++) {
      this._stats[i] = new HueGroup();
    }
    this._groupsFull = 0;
  }
  check(i32) {
    if (this._groupsFull === this._numGroups + 1) {
      this.check = () => {
      };
    }
    const r = i32 & 255;
    const g = i32 >>> 8 & 255;
    const b = i32 >>> 16 & 255;
    const hg = r === g && g === b ? 0 : 1 + hueGroup(rgb2hsl(r, g, b).h, this._numGroups);
    const gr = this._stats[hg];
    const min = this._minCols;
    gr.num++;
    if (gr.num > min) {
      return;
    }
    if (gr.num === min) {
      this._groupsFull++;
    }
    if (gr.num <= min) {
      this._stats[hg].cols.push(i32);
    }
  }
  injectIntoDictionary(histG) {
    for (let i = 0; i <= this._numGroups; i++) {
      if (this._stats[i].num <= this._minCols) {
        this._stats[i].cols.forEach((col) => {
          if (!histG[col]) {
            histG[col] = 1;
          } else {
            histG[col]++;
          }
        });
      }
    }
  }
  injectIntoArray(histG) {
    for (let i = 0; i <= this._numGroups; i++) {
      if (this._stats[i].num <= this._minCols) {
        this._stats[i].cols.forEach((col) => {
          if (histG.indexOf(col) === -1) {
            histG.push(col);
          }
        });
      }
    }
  }
};

// src/utils/progressTracker.ts
var _ProgressTracker = class {
  constructor(valueRange, progressRange) {
    __publicField(this, "progress");
    __publicField(this, "_step");
    __publicField(this, "_range");
    __publicField(this, "_last");
    __publicField(this, "_progressRange");
    this._range = valueRange;
    this._progressRange = progressRange;
    this._step = Math.max(1, this._range / (_ProgressTracker.steps + 1) | 0);
    this._last = -this._step;
    this.progress = 0;
  }
  shouldNotify(current) {
    if (current - this._last >= this._step) {
      this._last = current;
      this.progress = Math.min(this._progressRange * this._last / this._range, this._progressRange);
      return true;
    }
    return false;
  }
};
var ProgressTracker = _ProgressTracker;
__publicField(ProgressTracker, "steps", 100);

// src/palette/neuquant/neuquant.ts
var networkBiasShift = 3;
var Neuron = class {
  constructor(defaultValue) {
    __publicField(this, "r");
    __publicField(this, "g");
    __publicField(this, "b");
    __publicField(this, "a");
    this.r = this.g = this.b = this.a = defaultValue;
  }
  toPoint() {
    return Point.createByRGBA(this.r >> networkBiasShift, this.g >> networkBiasShift, this.b >> networkBiasShift, this.a >> networkBiasShift);
  }
  subtract(r, g, b, a) {
    this.r -= r | 0;
    this.g -= g | 0;
    this.b -= b | 0;
    this.a -= a | 0;
  }
};
var _NeuQuant = class extends AbstractPaletteQuantizer {
  constructor(colorDistanceCalculator, colors = 256) {
    super();
    __publicField(this, "_pointArray");
    __publicField(this, "_networkSize");
    __publicField(this, "_network");
    __publicField(this, "_sampleFactor");
    __publicField(this, "_radPower");
    __publicField(this, "_freq");
    __publicField(this, "_bias");
    __publicField(this, "_distance");
    this._distance = colorDistanceCalculator;
    this._pointArray = [];
    this._sampleFactor = 1;
    this._networkSize = colors;
    this._distance.setWhitePoint(255 << networkBiasShift, 255 << networkBiasShift, 255 << networkBiasShift, 255 << networkBiasShift);
  }
  sample(pointContainer) {
    this._pointArray = this._pointArray.concat(pointContainer.getPointArray());
  }
  *quantize() {
    this._init();
    yield* this._learn();
    yield {
      palette: this._buildPalette(),
      progress: 100
    };
  }
  _init() {
    this._freq = [];
    this._bias = [];
    this._radPower = [];
    this._network = [];
    for (let i = 0; i < this._networkSize; i++) {
      this._network[i] = new Neuron((i << networkBiasShift + 8) / this._networkSize | 0);
      this._freq[i] = _NeuQuant._initialBias / this._networkSize | 0;
      this._bias[i] = 0;
    }
  }
  *_learn() {
    let sampleFactor = this._sampleFactor;
    const pointsNumber = this._pointArray.length;
    if (pointsNumber < _NeuQuant._minpicturebytes)
      sampleFactor = 1;
    const alphadec = 30 + (sampleFactor - 1) / 3 | 0;
    const pointsToSample = pointsNumber / sampleFactor | 0;
    let delta = pointsToSample / _NeuQuant._nCycles | 0;
    let alpha = _NeuQuant._initAlpha;
    let radius = (this._networkSize >> 3) * _NeuQuant._radiusBias;
    let rad = radius >> _NeuQuant._radiusBiasShift;
    if (rad <= 1)
      rad = 0;
    for (let i = 0; i < rad; i++) {
      this._radPower[i] = alpha * ((rad * rad - i * i) * _NeuQuant._radBias / (rad * rad)) >>> 0;
    }
    let step;
    if (pointsNumber < _NeuQuant._minpicturebytes) {
      step = 1;
    } else if (pointsNumber % _NeuQuant._prime1 !== 0) {
      step = _NeuQuant._prime1;
    } else if (pointsNumber % _NeuQuant._prime2 !== 0) {
      step = _NeuQuant._prime2;
    } else if (pointsNumber % _NeuQuant._prime3 !== 0) {
      step = _NeuQuant._prime3;
    } else {
      step = _NeuQuant._prime4;
    }
    const tracker = new ProgressTracker(pointsToSample, 99);
    for (let i = 0, pointIndex = 0; i < pointsToSample; ) {
      if (tracker.shouldNotify(i)) {
        yield {
          progress: tracker.progress
        };
      }
      const point = this._pointArray[pointIndex];
      const b = point.b << networkBiasShift;
      const g = point.g << networkBiasShift;
      const r = point.r << networkBiasShift;
      const a = point.a << networkBiasShift;
      const neuronIndex = this._contest(b, g, r, a);
      this._alterSingle(alpha, neuronIndex, b, g, r, a);
      if (rad !== 0)
        this._alterNeighbour(rad, neuronIndex, b, g, r, a);
      pointIndex += step;
      if (pointIndex >= pointsNumber)
        pointIndex -= pointsNumber;
      i++;
      if (delta === 0)
        delta = 1;
      if (i % delta === 0) {
        alpha -= alpha / alphadec | 0;
        radius -= radius / _NeuQuant._radiusDecrease | 0;
        rad = radius >> _NeuQuant._radiusBiasShift;
        if (rad <= 1)
          rad = 0;
        for (let j = 0; j < rad; j++) {
          this._radPower[j] = alpha * ((rad * rad - j * j) * _NeuQuant._radBias / (rad * rad)) >>> 0;
        }
      }
    }
  }
  _buildPalette() {
    const palette = new Palette();
    this._network.forEach((neuron) => {
      palette.add(neuron.toPoint());
    });
    palette.sort();
    return palette;
  }
  _alterNeighbour(rad, i, b, g, r, al) {
    let lo = i - rad;
    if (lo < -1)
      lo = -1;
    let hi = i + rad;
    if (hi > this._networkSize)
      hi = this._networkSize;
    let j = i + 1;
    let k = i - 1;
    let m = 1;
    while (j < hi || k > lo) {
      const a = this._radPower[m++] / _NeuQuant._alphaRadBias;
      if (j < hi) {
        const p = this._network[j++];
        p.subtract(a * (p.r - r), a * (p.g - g), a * (p.b - b), a * (p.a - al));
      }
      if (k > lo) {
        const p = this._network[k--];
        p.subtract(a * (p.r - r), a * (p.g - g), a * (p.b - b), a * (p.a - al));
      }
    }
  }
  _alterSingle(alpha, i, b, g, r, a) {
    alpha /= _NeuQuant._initAlpha;
    const n = this._network[i];
    n.subtract(alpha * (n.r - r), alpha * (n.g - g), alpha * (n.b - b), alpha * (n.a - a));
  }
  _contest(b, g, r, a) {
    const multiplier = 255 * 4 << networkBiasShift;
    let bestd = ~(1 << 31);
    let bestbiasd = bestd;
    let bestpos = -1;
    let bestbiaspos = bestpos;
    for (let i = 0; i < this._networkSize; i++) {
      const n = this._network[i];
      const dist = this._distance.calculateNormalized(n, { r, g, b, a }) * multiplier | 0;
      if (dist < bestd) {
        bestd = dist;
        bestpos = i;
      }
      const biasdist = dist - (this._bias[i] >> _NeuQuant._initialBiasShift - networkBiasShift);
      if (biasdist < bestbiasd) {
        bestbiasd = biasdist;
        bestbiaspos = i;
      }
      const betafreq = this._freq[i] >> _NeuQuant._betaShift;
      this._freq[i] -= betafreq;
      this._bias[i] += betafreq << _NeuQuant._gammaShift;
    }
    this._freq[bestpos] += _NeuQuant._beta;
    this._bias[bestpos] -= _NeuQuant._betaGamma;
    return bestbiaspos;
  }
};
var NeuQuant = _NeuQuant;
__publicField(NeuQuant, "_prime1", 499);
__publicField(NeuQuant, "_prime2", 491);
__publicField(NeuQuant, "_prime3", 487);
__publicField(NeuQuant, "_prime4", 503);
__publicField(NeuQuant, "_minpicturebytes", _NeuQuant._prime4);
__publicField(NeuQuant, "_nCycles", 100);
__publicField(NeuQuant, "_initialBiasShift", 16);
__publicField(NeuQuant, "_initialBias", 1 << _NeuQuant._initialBiasShift);
__publicField(NeuQuant, "_gammaShift", 10);
__publicField(NeuQuant, "_betaShift", 10);
__publicField(NeuQuant, "_beta", _NeuQuant._initialBias >> _NeuQuant._betaShift);
__publicField(NeuQuant, "_betaGamma", _NeuQuant._initialBias << _NeuQuant._gammaShift - _NeuQuant._betaShift);
__publicField(NeuQuant, "_radiusBiasShift", 6);
__publicField(NeuQuant, "_radiusBias", 1 << _NeuQuant._radiusBiasShift);
__publicField(NeuQuant, "_radiusDecrease", 30);
__publicField(NeuQuant, "_alphaBiasShift", 10);
__publicField(NeuQuant, "_initAlpha", 1 << _NeuQuant._alphaBiasShift);
__publicField(NeuQuant, "_radBiasShift", 8);
__publicField(NeuQuant, "_radBias", 1 << _NeuQuant._radBiasShift);
__publicField(NeuQuant, "_alphaRadBiasShift", _NeuQuant._alphaBiasShift + _NeuQuant._radBiasShift);
__publicField(NeuQuant, "_alphaRadBias", 1 << _NeuQuant._alphaRadBiasShift);

// src/palette/neuquant/neuquantFloat.ts
var networkBiasShift2 = 3;
var NeuronFloat = class {
  constructor(defaultValue) {
    __publicField(this, "r");
    __publicField(this, "g");
    __publicField(this, "b");
    __publicField(this, "a");
    this.r = this.g = this.b = this.a = defaultValue;
  }
  toPoint() {
    return Point.createByRGBA(this.r >> networkBiasShift2, this.g >> networkBiasShift2, this.b >> networkBiasShift2, this.a >> networkBiasShift2);
  }
  subtract(r, g, b, a) {
    this.r -= r;
    this.g -= g;
    this.b -= b;
    this.a -= a;
  }
};
var _NeuQuantFloat = class extends AbstractPaletteQuantizer {
  constructor(colorDistanceCalculator, colors = 256) {
    super();
    __publicField(this, "_pointArray");
    __publicField(this, "_networkSize");
    __publicField(this, "_network");
    __publicField(this, "_sampleFactor");
    __publicField(this, "_radPower");
    __publicField(this, "_freq");
    __publicField(this, "_bias");
    __publicField(this, "_distance");
    this._distance = colorDistanceCalculator;
    this._pointArray = [];
    this._sampleFactor = 1;
    this._networkSize = colors;
    this._distance.setWhitePoint(255 << networkBiasShift2, 255 << networkBiasShift2, 255 << networkBiasShift2, 255 << networkBiasShift2);
  }
  sample(pointContainer) {
    this._pointArray = this._pointArray.concat(pointContainer.getPointArray());
  }
  *quantize() {
    this._init();
    yield* this._learn();
    yield {
      palette: this._buildPalette(),
      progress: 100
    };
  }
  _init() {
    this._freq = [];
    this._bias = [];
    this._radPower = [];
    this._network = [];
    for (let i = 0; i < this._networkSize; i++) {
      this._network[i] = new NeuronFloat((i << networkBiasShift2 + 8) / this._networkSize);
      this._freq[i] = _NeuQuantFloat._initialBias / this._networkSize;
      this._bias[i] = 0;
    }
  }
  *_learn() {
    let sampleFactor = this._sampleFactor;
    const pointsNumber = this._pointArray.length;
    if (pointsNumber < _NeuQuantFloat._minpicturebytes)
      sampleFactor = 1;
    const alphadec = 30 + (sampleFactor - 1) / 3;
    const pointsToSample = pointsNumber / sampleFactor;
    let delta = pointsToSample / _NeuQuantFloat._nCycles | 0;
    let alpha = _NeuQuantFloat._initAlpha;
    let radius = (this._networkSize >> 3) * _NeuQuantFloat._radiusBias;
    let rad = radius >> _NeuQuantFloat._radiusBiasShift;
    if (rad <= 1)
      rad = 0;
    for (let i = 0; i < rad; i++) {
      this._radPower[i] = alpha * ((rad * rad - i * i) * _NeuQuantFloat._radBias / (rad * rad));
    }
    let step;
    if (pointsNumber < _NeuQuantFloat._minpicturebytes) {
      step = 1;
    } else if (pointsNumber % _NeuQuantFloat._prime1 !== 0) {
      step = _NeuQuantFloat._prime1;
    } else if (pointsNumber % _NeuQuantFloat._prime2 !== 0) {
      step = _NeuQuantFloat._prime2;
    } else if (pointsNumber % _NeuQuantFloat._prime3 !== 0) {
      step = _NeuQuantFloat._prime3;
    } else {
      step = _NeuQuantFloat._prime4;
    }
    const tracker = new ProgressTracker(pointsToSample, 99);
    for (let i = 0, pointIndex = 0; i < pointsToSample; ) {
      if (tracker.shouldNotify(i)) {
        yield {
          progress: tracker.progress
        };
      }
      const point = this._pointArray[pointIndex];
      const b = point.b << networkBiasShift2;
      const g = point.g << networkBiasShift2;
      const r = point.r << networkBiasShift2;
      const a = point.a << networkBiasShift2;
      const neuronIndex = this._contest(b, g, r, a);
      this._alterSingle(alpha, neuronIndex, b, g, r, a);
      if (rad !== 0)
        this._alterNeighbour(rad, neuronIndex, b, g, r, a);
      pointIndex += step;
      if (pointIndex >= pointsNumber)
        pointIndex -= pointsNumber;
      i++;
      if (delta === 0)
        delta = 1;
      if (i % delta === 0) {
        alpha -= alpha / alphadec;
        radius -= radius / _NeuQuantFloat._radiusDecrease;
        rad = radius >> _NeuQuantFloat._radiusBiasShift;
        if (rad <= 1)
          rad = 0;
        for (let j = 0; j < rad; j++) {
          this._radPower[j] = alpha * ((rad * rad - j * j) * _NeuQuantFloat._radBias / (rad * rad));
        }
      }
    }
  }
  _buildPalette() {
    const palette = new Palette();
    this._network.forEach((neuron) => {
      palette.add(neuron.toPoint());
    });
    palette.sort();
    return palette;
  }
  _alterNeighbour(rad, i, b, g, r, al) {
    let lo = i - rad;
    if (lo < -1)
      lo = -1;
    let hi = i + rad;
    if (hi > this._networkSize)
      hi = this._networkSize;
    let j = i + 1;
    let k = i - 1;
    let m = 1;
    while (j < hi || k > lo) {
      const a = this._radPower[m++] / _NeuQuantFloat._alphaRadBias;
      if (j < hi) {
        const p = this._network[j++];
        p.subtract(a * (p.r - r), a * (p.g - g), a * (p.b - b), a * (p.a - al));
      }
      if (k > lo) {
        const p = this._network[k--];
        p.subtract(a * (p.r - r), a * (p.g - g), a * (p.b - b), a * (p.a - al));
      }
    }
  }
  _alterSingle(alpha, i, b, g, r, a) {
    alpha /= _NeuQuantFloat._initAlpha;
    const n = this._network[i];
    n.subtract(alpha * (n.r - r), alpha * (n.g - g), alpha * (n.b - b), alpha * (n.a - a));
  }
  _contest(b, g, r, al) {
    const multiplier = 255 * 4 << networkBiasShift2;
    let bestd = ~(1 << 31);
    let bestbiasd = bestd;
    let bestpos = -1;
    let bestbiaspos = bestpos;
    for (let i = 0; i < this._networkSize; i++) {
      const n = this._network[i];
      const dist = this._distance.calculateNormalized(n, { r, g, b, a: al }) * multiplier;
      if (dist < bestd) {
        bestd = dist;
        bestpos = i;
      }
      const biasdist = dist - (this._bias[i] >> _NeuQuantFloat._initialBiasShift - networkBiasShift2);
      if (biasdist < bestbiasd) {
        bestbiasd = biasdist;
        bestbiaspos = i;
      }
      const betafreq = this._freq[i] >> _NeuQuantFloat._betaShift;
      this._freq[i] -= betafreq;
      this._bias[i] += betafreq << _NeuQuantFloat._gammaShift;
    }
    this._freq[bestpos] += _NeuQuantFloat._beta;
    this._bias[bestpos] -= _NeuQuantFloat._betaGamma;
    return bestbiaspos;
  }
};
var NeuQuantFloat = _NeuQuantFloat;
__publicField(NeuQuantFloat, "_prime1", 499);
__publicField(NeuQuantFloat, "_prime2", 491);
__publicField(NeuQuantFloat, "_prime3", 487);
__publicField(NeuQuantFloat, "_prime4", 503);
__publicField(NeuQuantFloat, "_minpicturebytes", _NeuQuantFloat._prime4);
__publicField(NeuQuantFloat, "_nCycles", 100);
__publicField(NeuQuantFloat, "_initialBiasShift", 16);
__publicField(NeuQuantFloat, "_initialBias", 1 << _NeuQuantFloat._initialBiasShift);
__publicField(NeuQuantFloat, "_gammaShift", 10);
__publicField(NeuQuantFloat, "_betaShift", 10);
__publicField(NeuQuantFloat, "_beta", _NeuQuantFloat._initialBias >> _NeuQuantFloat._betaShift);
__publicField(NeuQuantFloat, "_betaGamma", _NeuQuantFloat._initialBias << _NeuQuantFloat._gammaShift - _NeuQuantFloat._betaShift);
__publicField(NeuQuantFloat, "_radiusBiasShift", 6);
__publicField(NeuQuantFloat, "_radiusBias", 1 << _NeuQuantFloat._radiusBiasShift);
__publicField(NeuQuantFloat, "_radiusDecrease", 30);
__publicField(NeuQuantFloat, "_alphaBiasShift", 10);
__publicField(NeuQuantFloat, "_initAlpha", 1 << _NeuQuantFloat._alphaBiasShift);
__publicField(NeuQuantFloat, "_radBiasShift", 8);
__publicField(NeuQuantFloat, "_radBias", 1 << _NeuQuantFloat._radBiasShift);
__publicField(NeuQuantFloat, "_alphaRadBiasShift", _NeuQuantFloat._alphaBiasShift + _NeuQuantFloat._radBiasShift);
__publicField(NeuQuantFloat, "_alphaRadBias", 1 << _NeuQuantFloat._alphaRadBiasShift);

// src/palette/rgbquant/colorHistogram.ts
var _ColorHistogram = class {
  constructor(method, colors) {
    __publicField(this, "_method");
    __publicField(this, "_hueStats");
    __publicField(this, "_histogram");
    __publicField(this, "_initColors");
    __publicField(this, "_minHueCols");
    this._method = method;
    this._minHueCols = colors << 2;
    this._initColors = colors << 2;
    this._hueStats = new HueStatistics(_ColorHistogram._hueGroups, this._minHueCols);
    this._histogram = /* @__PURE__ */ Object.create(null);
  }
  sample(pointContainer) {
    switch (this._method) {
      case 1:
        this._colorStats1D(pointContainer);
        break;
      case 2:
        this._colorStats2D(pointContainer);
        break;
    }
  }
  getImportanceSortedColorsIDXI32() {
    const sorted = stableSort(Object.keys(this._histogram), (a, b) => this._histogram[b] - this._histogram[a]);
    if (sorted.length === 0) {
      return [];
    }
    let idxi32;
    switch (this._method) {
      case 1:
        const initialColorsLimit = Math.min(sorted.length, this._initColors);
        const last = sorted[initialColorsLimit - 1];
        const freq = this._histogram[last];
        idxi32 = sorted.slice(0, initialColorsLimit);
        let pos = initialColorsLimit;
        const len = sorted.length;
        while (pos < len && this._histogram[sorted[pos]] === freq) {
          idxi32.push(sorted[pos++]);
        }
        this._hueStats.injectIntoArray(idxi32);
        break;
      case 2:
        idxi32 = sorted;
        break;
      default:
        throw new Error("Incorrect method");
    }
    return idxi32.map((v) => +v);
  }
  _colorStats1D(pointContainer) {
    const histG = this._histogram;
    const pointArray = pointContainer.getPointArray();
    const len = pointArray.length;
    for (let i = 0; i < len; i++) {
      const col = pointArray[i].uint32;
      this._hueStats.check(col);
      if (col in histG) {
        histG[col]++;
      } else {
        histG[col] = 1;
      }
    }
  }
  _colorStats2D(pointContainer) {
    const width = pointContainer.getWidth();
    const height = pointContainer.getHeight();
    const pointArray = pointContainer.getPointArray();
    const boxW = _ColorHistogram._boxSize[0];
    const boxH = _ColorHistogram._boxSize[1];
    const area = boxW * boxH;
    const boxes = this._makeBoxes(width, height, boxW, boxH);
    const histG = this._histogram;
    boxes.forEach((box) => {
      let effc = Math.round(box.w * box.h / area) * _ColorHistogram._boxPixels;
      if (effc < 2)
        effc = 2;
      const histL = {};
      this._iterateBox(box, width, (i) => {
        const col = pointArray[i].uint32;
        this._hueStats.check(col);
        if (col in histG) {
          histG[col]++;
        } else if (col in histL) {
          if (++histL[col] >= effc) {
            histG[col] = histL[col];
          }
        } else {
          histL[col] = 1;
        }
      });
    });
    this._hueStats.injectIntoDictionary(histG);
  }
  _iterateBox(bbox, wid, fn) {
    const b = bbox;
    const i0 = b.y * wid + b.x;
    const i1 = (b.y + b.h - 1) * wid + (b.x + b.w - 1);
    const incr = wid - b.w + 1;
    let cnt = 0;
    let i = i0;
    do {
      fn.call(this, i);
      i += ++cnt % b.w === 0 ? incr : 1;
    } while (i <= i1);
  }
  _makeBoxes(width, height, stepX, stepY) {
    const wrem = width % stepX;
    const hrem = height % stepY;
    const xend = width - wrem;
    const yend = height - hrem;
    const boxesArray = [];
    for (let y2 = 0; y2 < height; y2 += stepY) {
      for (let x2 = 0; x2 < width; x2 += stepX) {
        boxesArray.push({
          x: x2,
          y: y2,
          w: x2 === xend ? wrem : stepX,
          h: y2 === yend ? hrem : stepY
        });
      }
    }
    return boxesArray;
  }
};
var ColorHistogram = _ColorHistogram;
__publicField(ColorHistogram, "_boxSize", [64, 64]);
__publicField(ColorHistogram, "_boxPixels", 2);
__publicField(ColorHistogram, "_hueGroups", 10);

// src/palette/rgbquant/rgbquant.ts
var RemovedColor = class {
  constructor(index, color, distance) {
    __publicField(this, "index");
    __publicField(this, "color");
    __publicField(this, "distance");
    this.index = index;
    this.color = color;
    this.distance = distance;
  }
};
var RGBQuant = class extends AbstractPaletteQuantizer {
  constructor(colorDistanceCalculator, colors = 256, method = 2) {
    super();
    __publicField(this, "_colors");
    __publicField(this, "_initialDistance");
    __publicField(this, "_distanceIncrement");
    __publicField(this, "_histogram");
    __publicField(this, "_distance");
    this._distance = colorDistanceCalculator;
    this._colors = colors;
    this._histogram = new ColorHistogram(method, colors);
    this._initialDistance = 0.01;
    this._distanceIncrement = 5e-3;
  }
  sample(image) {
    this._histogram.sample(image);
  }
  *quantize() {
    const idxi32 = this._histogram.getImportanceSortedColorsIDXI32();
    if (idxi32.length === 0) {
      throw new Error("No colors in image");
    }
    yield* this._buildPalette(idxi32);
  }
  *_buildPalette(idxi32) {
    const palette = new Palette();
    const colorArray = palette.getPointContainer().getPointArray();
    const usageArray = new Array(idxi32.length);
    for (let i = 0; i < idxi32.length; i++) {
      colorArray.push(Point.createByUint32(idxi32[i]));
      usageArray[i] = 1;
    }
    const len = colorArray.length;
    const memDist = [];
    let palLen = len;
    let thold = this._initialDistance;
    const tracker = new ProgressTracker(palLen - this._colors, 99);
    while (palLen > this._colors) {
      memDist.length = 0;
      for (let i = 0; i < len; i++) {
        if (tracker.shouldNotify(len - palLen)) {
          yield {
            progress: tracker.progress
          };
        }
        if (usageArray[i] === 0)
          continue;
        const pxi = colorArray[i];
        for (let j = i + 1; j < len; j++) {
          if (usageArray[j] === 0)
            continue;
          const pxj = colorArray[j];
          const dist = this._distance.calculateNormalized(pxi, pxj);
          if (dist < thold) {
            memDist.push(new RemovedColor(j, pxj, dist));
            usageArray[j] = 0;
            palLen--;
          }
        }
      }
      thold += palLen > this._colors * 3 ? this._initialDistance : this._distanceIncrement;
    }
    if (palLen < this._colors) {
      stableSort(memDist, (a, b) => b.distance - a.distance);
      let k = 0;
      while (palLen < this._colors && k < memDist.length) {
        const removedColor = memDist[k];
        usageArray[removedColor.index] = 1;
        palLen++;
        k++;
      }
    }
    let colors = colorArray.length;
    for (let colorIndex = colors - 1; colorIndex >= 0; colorIndex--) {
      if (usageArray[colorIndex] === 0) {
        if (colorIndex !== colors - 1) {
          colorArray[colorIndex] = colorArray[colors - 1];
        }
        --colors;
      }
    }
    colorArray.length = colors;
    palette.sort();
    yield {
      palette,
      progress: 100
    };
  }
};

// src/palette/wu/wuQuant.ts
function createArray1D(dimension1) {
  const a = [];
  for (let k = 0; k < dimension1; k++) {
    a[k] = 0;
  }
  return a;
}
function createArray4D(dimension1, dimension2, dimension3, dimension4) {
  const a = new Array(dimension1);
  for (let i = 0; i < dimension1; i++) {
    a[i] = new Array(dimension2);
    for (let j = 0; j < dimension2; j++) {
      a[i][j] = new Array(dimension3);
      for (let k = 0; k < dimension3; k++) {
        a[i][j][k] = new Array(dimension4);
        for (let l = 0; l < dimension4; l++) {
          a[i][j][k][l] = 0;
        }
      }
    }
  }
  return a;
}
function createArray3D(dimension1, dimension2, dimension3) {
  const a = new Array(dimension1);
  for (let i = 0; i < dimension1; i++) {
    a[i] = new Array(dimension2);
    for (let j = 0; j < dimension2; j++) {
      a[i][j] = new Array(dimension3);
      for (let k = 0; k < dimension3; k++) {
        a[i][j][k] = 0;
      }
    }
  }
  return a;
}
function fillArray3D(a, dimension1, dimension2, dimension3, value) {
  for (let i = 0; i < dimension1; i++) {
    a[i] = [];
    for (let j = 0; j < dimension2; j++) {
      a[i][j] = [];
      for (let k = 0; k < dimension3; k++) {
        a[i][j][k] = value;
      }
    }
  }
}
function fillArray1D(a, dimension1, value) {
  for (let i = 0; i < dimension1; i++) {
    a[i] = value;
  }
}
var WuColorCube = class {
  constructor() {
    __publicField(this, "redMinimum");
    __publicField(this, "redMaximum");
    __publicField(this, "greenMinimum");
    __publicField(this, "greenMaximum");
    __publicField(this, "blueMinimum");
    __publicField(this, "blueMaximum");
    __publicField(this, "volume");
    __publicField(this, "alphaMinimum");
    __publicField(this, "alphaMaximum");
  }
};
var _WuQuant = class extends AbstractPaletteQuantizer {
  constructor(colorDistanceCalculator, colors = 256, significantBitsPerChannel = 5) {
    super();
    __publicField(this, "_reds");
    __publicField(this, "_greens");
    __publicField(this, "_blues");
    __publicField(this, "_alphas");
    __publicField(this, "_sums");
    __publicField(this, "_weights");
    __publicField(this, "_momentsRed");
    __publicField(this, "_momentsGreen");
    __publicField(this, "_momentsBlue");
    __publicField(this, "_momentsAlpha");
    __publicField(this, "_moments");
    __publicField(this, "_table");
    __publicField(this, "_pixels");
    __publicField(this, "_cubes");
    __publicField(this, "_colors");
    __publicField(this, "_significantBitsPerChannel");
    __publicField(this, "_maxSideIndex");
    __publicField(this, "_alphaMaxSideIndex");
    __publicField(this, "_sideSize");
    __publicField(this, "_alphaSideSize");
    __publicField(this, "_distance");
    this._distance = colorDistanceCalculator;
    this._setQuality(significantBitsPerChannel);
    this._initialize(colors);
  }
  sample(image) {
    const pointArray = image.getPointArray();
    for (let i = 0, l = pointArray.length; i < l; i++) {
      this._addColor(pointArray[i]);
    }
    this._pixels = this._pixels.concat(pointArray);
  }
  *quantize() {
    yield* this._preparePalette();
    const palette = new Palette();
    for (let paletteIndex = 0; paletteIndex < this._colors; paletteIndex++) {
      if (this._sums[paletteIndex] > 0) {
        const sum = this._sums[paletteIndex];
        const r = this._reds[paletteIndex] / sum;
        const g = this._greens[paletteIndex] / sum;
        const b = this._blues[paletteIndex] / sum;
        const a = this._alphas[paletteIndex] / sum;
        const color = Point.createByRGBA(r | 0, g | 0, b | 0, a | 0);
        palette.add(color);
      }
    }
    palette.sort();
    yield {
      palette,
      progress: 100
    };
  }
  *_preparePalette() {
    yield* this._calculateMoments();
    let next = 0;
    const volumeVariance = createArray1D(this._colors);
    for (let cubeIndex = 1; cubeIndex < this._colors; ++cubeIndex) {
      if (this._cut(this._cubes[next], this._cubes[cubeIndex])) {
        volumeVariance[next] = this._cubes[next].volume > 1 ? this._calculateVariance(this._cubes[next]) : 0;
        volumeVariance[cubeIndex] = this._cubes[cubeIndex].volume > 1 ? this._calculateVariance(this._cubes[cubeIndex]) : 0;
      } else {
        volumeVariance[next] = 0;
        cubeIndex--;
      }
      next = 0;
      let temp = volumeVariance[0];
      for (let index = 1; index <= cubeIndex; ++index) {
        if (volumeVariance[index] > temp) {
          temp = volumeVariance[index];
          next = index;
        }
      }
      if (temp <= 0) {
        this._colors = cubeIndex + 1;
        break;
      }
    }
    const lookupRed = [];
    const lookupGreen = [];
    const lookupBlue = [];
    const lookupAlpha = [];
    for (let k = 0; k < this._colors; ++k) {
      const weight = _WuQuant._volume(this._cubes[k], this._weights);
      if (weight > 0) {
        lookupRed[k] = _WuQuant._volume(this._cubes[k], this._momentsRed) / weight | 0;
        lookupGreen[k] = _WuQuant._volume(this._cubes[k], this._momentsGreen) / weight | 0;
        lookupBlue[k] = _WuQuant._volume(this._cubes[k], this._momentsBlue) / weight | 0;
        lookupAlpha[k] = _WuQuant._volume(this._cubes[k], this._momentsAlpha) / weight | 0;
      } else {
        lookupRed[k] = 0;
        lookupGreen[k] = 0;
        lookupBlue[k] = 0;
        lookupAlpha[k] = 0;
      }
    }
    this._reds = createArray1D(this._colors + 1);
    this._greens = createArray1D(this._colors + 1);
    this._blues = createArray1D(this._colors + 1);
    this._alphas = createArray1D(this._colors + 1);
    this._sums = createArray1D(this._colors + 1);
    for (let index = 0, l = this._pixels.length; index < l; index++) {
      const color = this._pixels[index];
      const match = -1;
      let bestMatch = match;
      let bestDistance = Number.MAX_VALUE;
      for (let lookup = 0; lookup < this._colors; lookup++) {
        const foundRed = lookupRed[lookup];
        const foundGreen = lookupGreen[lookup];
        const foundBlue = lookupBlue[lookup];
        const foundAlpha = lookupAlpha[lookup];
        const distance = this._distance.calculateRaw(foundRed, foundGreen, foundBlue, foundAlpha, color.r, color.g, color.b, color.a);
        if (distance < bestDistance) {
          bestDistance = distance;
          bestMatch = lookup;
        }
      }
      this._reds[bestMatch] += color.r;
      this._greens[bestMatch] += color.g;
      this._blues[bestMatch] += color.b;
      this._alphas[bestMatch] += color.a;
      this._sums[bestMatch]++;
    }
  }
  _addColor(color) {
    const bitsToRemove = 8 - this._significantBitsPerChannel;
    const indexRed = (color.r >> bitsToRemove) + 1;
    const indexGreen = (color.g >> bitsToRemove) + 1;
    const indexBlue = (color.b >> bitsToRemove) + 1;
    const indexAlpha = (color.a >> bitsToRemove) + 1;
    this._weights[indexAlpha][indexRed][indexGreen][indexBlue]++;
    this._momentsRed[indexAlpha][indexRed][indexGreen][indexBlue] += color.r;
    this._momentsGreen[indexAlpha][indexRed][indexGreen][indexBlue] += color.g;
    this._momentsBlue[indexAlpha][indexRed][indexGreen][indexBlue] += color.b;
    this._momentsAlpha[indexAlpha][indexRed][indexGreen][indexBlue] += color.a;
    this._moments[indexAlpha][indexRed][indexGreen][indexBlue] += this._table[color.r] + this._table[color.g] + this._table[color.b] + this._table[color.a];
  }
  *_calculateMoments() {
    const area = [];
    const areaRed = [];
    const areaGreen = [];
    const areaBlue = [];
    const areaAlpha = [];
    const area2 = [];
    const xarea = createArray3D(this._sideSize, this._sideSize, this._sideSize);
    const xareaRed = createArray3D(this._sideSize, this._sideSize, this._sideSize);
    const xareaGreen = createArray3D(this._sideSize, this._sideSize, this._sideSize);
    const xareaBlue = createArray3D(this._sideSize, this._sideSize, this._sideSize);
    const xareaAlpha = createArray3D(this._sideSize, this._sideSize, this._sideSize);
    const xarea2 = createArray3D(this._sideSize, this._sideSize, this._sideSize);
    let trackerProgress = 0;
    const tracker = new ProgressTracker(this._alphaMaxSideIndex * this._maxSideIndex, 99);
    for (let alphaIndex = 1; alphaIndex <= this._alphaMaxSideIndex; ++alphaIndex) {
      fillArray3D(xarea, this._sideSize, this._sideSize, this._sideSize, 0);
      fillArray3D(xareaRed, this._sideSize, this._sideSize, this._sideSize, 0);
      fillArray3D(xareaGreen, this._sideSize, this._sideSize, this._sideSize, 0);
      fillArray3D(xareaBlue, this._sideSize, this._sideSize, this._sideSize, 0);
      fillArray3D(xareaAlpha, this._sideSize, this._sideSize, this._sideSize, 0);
      fillArray3D(xarea2, this._sideSize, this._sideSize, this._sideSize, 0);
      for (let redIndex = 1; redIndex <= this._maxSideIndex; ++redIndex, ++trackerProgress) {
        if (tracker.shouldNotify(trackerProgress)) {
          yield {
            progress: tracker.progress
          };
        }
        fillArray1D(area, this._sideSize, 0);
        fillArray1D(areaRed, this._sideSize, 0);
        fillArray1D(areaGreen, this._sideSize, 0);
        fillArray1D(areaBlue, this._sideSize, 0);
        fillArray1D(areaAlpha, this._sideSize, 0);
        fillArray1D(area2, this._sideSize, 0);
        for (let greenIndex = 1; greenIndex <= this._maxSideIndex; ++greenIndex) {
          let line = 0;
          let lineRed = 0;
          let lineGreen = 0;
          let lineBlue = 0;
          let lineAlpha = 0;
          let line2 = 0;
          for (let blueIndex = 1; blueIndex <= this._maxSideIndex; ++blueIndex) {
            line += this._weights[alphaIndex][redIndex][greenIndex][blueIndex];
            lineRed += this._momentsRed[alphaIndex][redIndex][greenIndex][blueIndex];
            lineGreen += this._momentsGreen[alphaIndex][redIndex][greenIndex][blueIndex];
            lineBlue += this._momentsBlue[alphaIndex][redIndex][greenIndex][blueIndex];
            lineAlpha += this._momentsAlpha[alphaIndex][redIndex][greenIndex][blueIndex];
            line2 += this._moments[alphaIndex][redIndex][greenIndex][blueIndex];
            area[blueIndex] += line;
            areaRed[blueIndex] += lineRed;
            areaGreen[blueIndex] += lineGreen;
            areaBlue[blueIndex] += lineBlue;
            areaAlpha[blueIndex] += lineAlpha;
            area2[blueIndex] += line2;
            xarea[redIndex][greenIndex][blueIndex] = xarea[redIndex - 1][greenIndex][blueIndex] + area[blueIndex];
            xareaRed[redIndex][greenIndex][blueIndex] = xareaRed[redIndex - 1][greenIndex][blueIndex] + areaRed[blueIndex];
            xareaGreen[redIndex][greenIndex][blueIndex] = xareaGreen[redIndex - 1][greenIndex][blueIndex] + areaGreen[blueIndex];
            xareaBlue[redIndex][greenIndex][blueIndex] = xareaBlue[redIndex - 1][greenIndex][blueIndex] + areaBlue[blueIndex];
            xareaAlpha[redIndex][greenIndex][blueIndex] = xareaAlpha[redIndex - 1][greenIndex][blueIndex] + areaAlpha[blueIndex];
            xarea2[redIndex][greenIndex][blueIndex] = xarea2[redIndex - 1][greenIndex][blueIndex] + area2[blueIndex];
            this._weights[alphaIndex][redIndex][greenIndex][blueIndex] = this._weights[alphaIndex - 1][redIndex][greenIndex][blueIndex] + xarea[redIndex][greenIndex][blueIndex];
            this._momentsRed[alphaIndex][redIndex][greenIndex][blueIndex] = this._momentsRed[alphaIndex - 1][redIndex][greenIndex][blueIndex] + xareaRed[redIndex][greenIndex][blueIndex];
            this._momentsGreen[alphaIndex][redIndex][greenIndex][blueIndex] = this._momentsGreen[alphaIndex - 1][redIndex][greenIndex][blueIndex] + xareaGreen[redIndex][greenIndex][blueIndex];
            this._momentsBlue[alphaIndex][redIndex][greenIndex][blueIndex] = this._momentsBlue[alphaIndex - 1][redIndex][greenIndex][blueIndex] + xareaBlue[redIndex][greenIndex][blueIndex];
            this._momentsAlpha[alphaIndex][redIndex][greenIndex][blueIndex] = this._momentsAlpha[alphaIndex - 1][redIndex][greenIndex][blueIndex] + xareaAlpha[redIndex][greenIndex][blueIndex];
            this._moments[alphaIndex][redIndex][greenIndex][blueIndex] = this._moments[alphaIndex - 1][redIndex][greenIndex][blueIndex] + xarea2[redIndex][greenIndex][blueIndex];
          }
        }
      }
    }
  }
  static _volumeFloat(cube, moment) {
    return moment[cube.alphaMaximum][cube.redMaximum][cube.greenMaximum][cube.blueMaximum] - moment[cube.alphaMaximum][cube.redMaximum][cube.greenMinimum][cube.blueMaximum] - moment[cube.alphaMaximum][cube.redMinimum][cube.greenMaximum][cube.blueMaximum] + moment[cube.alphaMaximum][cube.redMinimum][cube.greenMinimum][cube.blueMaximum] - moment[cube.alphaMinimum][cube.redMaximum][cube.greenMaximum][cube.blueMaximum] + moment[cube.alphaMinimum][cube.redMaximum][cube.greenMinimum][cube.blueMaximum] + moment[cube.alphaMinimum][cube.redMinimum][cube.greenMaximum][cube.blueMaximum] - moment[cube.alphaMinimum][cube.redMinimum][cube.greenMinimum][cube.blueMaximum] - (moment[cube.alphaMaximum][cube.redMaximum][cube.greenMaximum][cube.blueMinimum] - moment[cube.alphaMinimum][cube.redMaximum][cube.greenMaximum][cube.blueMinimum] - moment[cube.alphaMaximum][cube.redMaximum][cube.greenMinimum][cube.blueMinimum] + moment[cube.alphaMinimum][cube.redMaximum][cube.greenMinimum][cube.blueMinimum] - moment[cube.alphaMaximum][cube.redMinimum][cube.greenMaximum][cube.blueMinimum] + moment[cube.alphaMinimum][cube.redMinimum][cube.greenMaximum][cube.blueMinimum] + moment[cube.alphaMaximum][cube.redMinimum][cube.greenMinimum][cube.blueMinimum] - moment[cube.alphaMinimum][cube.redMinimum][cube.greenMinimum][cube.blueMinimum]);
  }
  static _volume(cube, moment) {
    return _WuQuant._volumeFloat(cube, moment) | 0;
  }
  static _top(cube, direction, position, moment) {
    let result;
    switch (direction) {
      case _WuQuant._alpha:
        result = moment[position][cube.redMaximum][cube.greenMaximum][cube.blueMaximum] - moment[position][cube.redMaximum][cube.greenMinimum][cube.blueMaximum] - moment[position][cube.redMinimum][cube.greenMaximum][cube.blueMaximum] + moment[position][cube.redMinimum][cube.greenMinimum][cube.blueMaximum] - (moment[position][cube.redMaximum][cube.greenMaximum][cube.blueMinimum] - moment[position][cube.redMaximum][cube.greenMinimum][cube.blueMinimum] - moment[position][cube.redMinimum][cube.greenMaximum][cube.blueMinimum] + moment[position][cube.redMinimum][cube.greenMinimum][cube.blueMinimum]);
        break;
      case _WuQuant._red:
        result = moment[cube.alphaMaximum][position][cube.greenMaximum][cube.blueMaximum] - moment[cube.alphaMaximum][position][cube.greenMinimum][cube.blueMaximum] - moment[cube.alphaMinimum][position][cube.greenMaximum][cube.blueMaximum] + moment[cube.alphaMinimum][position][cube.greenMinimum][cube.blueMaximum] - (moment[cube.alphaMaximum][position][cube.greenMaximum][cube.blueMinimum] - moment[cube.alphaMaximum][position][cube.greenMinimum][cube.blueMinimum] - moment[cube.alphaMinimum][position][cube.greenMaximum][cube.blueMinimum] + moment[cube.alphaMinimum][position][cube.greenMinimum][cube.blueMinimum]);
        break;
      case _WuQuant._green:
        result = moment[cube.alphaMaximum][cube.redMaximum][position][cube.blueMaximum] - moment[cube.alphaMaximum][cube.redMinimum][position][cube.blueMaximum] - moment[cube.alphaMinimum][cube.redMaximum][position][cube.blueMaximum] + moment[cube.alphaMinimum][cube.redMinimum][position][cube.blueMaximum] - (moment[cube.alphaMaximum][cube.redMaximum][position][cube.blueMinimum] - moment[cube.alphaMaximum][cube.redMinimum][position][cube.blueMinimum] - moment[cube.alphaMinimum][cube.redMaximum][position][cube.blueMinimum] + moment[cube.alphaMinimum][cube.redMinimum][position][cube.blueMinimum]);
        break;
      case _WuQuant._blue:
        result = moment[cube.alphaMaximum][cube.redMaximum][cube.greenMaximum][position] - moment[cube.alphaMaximum][cube.redMaximum][cube.greenMinimum][position] - moment[cube.alphaMaximum][cube.redMinimum][cube.greenMaximum][position] + moment[cube.alphaMaximum][cube.redMinimum][cube.greenMinimum][position] - (moment[cube.alphaMinimum][cube.redMaximum][cube.greenMaximum][position] - moment[cube.alphaMinimum][cube.redMaximum][cube.greenMinimum][position] - moment[cube.alphaMinimum][cube.redMinimum][cube.greenMaximum][position] + moment[cube.alphaMinimum][cube.redMinimum][cube.greenMinimum][position]);
        break;
      default:
        throw new Error("impossible");
    }
    return result | 0;
  }
  static _bottom(cube, direction, moment) {
    switch (direction) {
      case _WuQuant._alpha:
        return -moment[cube.alphaMinimum][cube.redMaximum][cube.greenMaximum][cube.blueMaximum] + moment[cube.alphaMinimum][cube.redMaximum][cube.greenMinimum][cube.blueMaximum] + moment[cube.alphaMinimum][cube.redMinimum][cube.greenMaximum][cube.blueMaximum] - moment[cube.alphaMinimum][cube.redMinimum][cube.greenMinimum][cube.blueMaximum] - (-moment[cube.alphaMinimum][cube.redMaximum][cube.greenMaximum][cube.blueMinimum] + moment[cube.alphaMinimum][cube.redMaximum][cube.greenMinimum][cube.blueMinimum] + moment[cube.alphaMinimum][cube.redMinimum][cube.greenMaximum][cube.blueMinimum] - moment[cube.alphaMinimum][cube.redMinimum][cube.greenMinimum][cube.blueMinimum]);
      case _WuQuant._red:
        return -moment[cube.alphaMaximum][cube.redMinimum][cube.greenMaximum][cube.blueMaximum] + moment[cube.alphaMaximum][cube.redMinimum][cube.greenMinimum][cube.blueMaximum] + moment[cube.alphaMinimum][cube.redMinimum][cube.greenMaximum][cube.blueMaximum] - moment[cube.alphaMinimum][cube.redMinimum][cube.greenMinimum][cube.blueMaximum] - (-moment[cube.alphaMaximum][cube.redMinimum][cube.greenMaximum][cube.blueMinimum] + moment[cube.alphaMaximum][cube.redMinimum][cube.greenMinimum][cube.blueMinimum] + moment[cube.alphaMinimum][cube.redMinimum][cube.greenMaximum][cube.blueMinimum] - moment[cube.alphaMinimum][cube.redMinimum][cube.greenMinimum][cube.blueMinimum]);
      case _WuQuant._green:
        return -moment[cube.alphaMaximum][cube.redMaximum][cube.greenMinimum][cube.blueMaximum] + moment[cube.alphaMaximum][cube.redMinimum][cube.greenMinimum][cube.blueMaximum] + moment[cube.alphaMinimum][cube.redMaximum][cube.greenMinimum][cube.blueMaximum] - moment[cube.alphaMinimum][cube.redMinimum][cube.greenMinimum][cube.blueMaximum] - (-moment[cube.alphaMaximum][cube.redMaximum][cube.greenMinimum][cube.blueMinimum] + moment[cube.alphaMaximum][cube.redMinimum][cube.greenMinimum][cube.blueMinimum] + moment[cube.alphaMinimum][cube.redMaximum][cube.greenMinimum][cube.blueMinimum] - moment[cube.alphaMinimum][cube.redMinimum][cube.greenMinimum][cube.blueMinimum]);
      case _WuQuant._blue:
        return -moment[cube.alphaMaximum][cube.redMaximum][cube.greenMaximum][cube.blueMinimum] + moment[cube.alphaMaximum][cube.redMaximum][cube.greenMinimum][cube.blueMinimum] + moment[cube.alphaMaximum][cube.redMinimum][cube.greenMaximum][cube.blueMinimum] - moment[cube.alphaMaximum][cube.redMinimum][cube.greenMinimum][cube.blueMinimum] - (-moment[cube.alphaMinimum][cube.redMaximum][cube.greenMaximum][cube.blueMinimum] + moment[cube.alphaMinimum][cube.redMaximum][cube.greenMinimum][cube.blueMinimum] + moment[cube.alphaMinimum][cube.redMinimum][cube.greenMaximum][cube.blueMinimum] - moment[cube.alphaMinimum][cube.redMinimum][cube.greenMinimum][cube.blueMinimum]);
      default:
        return 0;
    }
  }
  _calculateVariance(cube) {
    const volumeRed = _WuQuant._volume(cube, this._momentsRed);
    const volumeGreen = _WuQuant._volume(cube, this._momentsGreen);
    const volumeBlue = _WuQuant._volume(cube, this._momentsBlue);
    const volumeAlpha = _WuQuant._volume(cube, this._momentsAlpha);
    const volumeMoment = _WuQuant._volumeFloat(cube, this._moments);
    const volumeWeight = _WuQuant._volume(cube, this._weights);
    const distance = volumeRed * volumeRed + volumeGreen * volumeGreen + volumeBlue * volumeBlue + volumeAlpha * volumeAlpha;
    return volumeMoment - distance / volumeWeight;
  }
  _maximize(cube, direction, first, last, wholeRed, wholeGreen, wholeBlue, wholeAlpha, wholeWeight) {
    const bottomRed = _WuQuant._bottom(cube, direction, this._momentsRed) | 0;
    const bottomGreen = _WuQuant._bottom(cube, direction, this._momentsGreen) | 0;
    const bottomBlue = _WuQuant._bottom(cube, direction, this._momentsBlue) | 0;
    const bottomAlpha = _WuQuant._bottom(cube, direction, this._momentsAlpha) | 0;
    const bottomWeight = _WuQuant._bottom(cube, direction, this._weights) | 0;
    let result = 0;
    let cutPosition = -1;
    for (let position = first; position < last; ++position) {
      let halfRed = bottomRed + _WuQuant._top(cube, direction, position, this._momentsRed);
      let halfGreen = bottomGreen + _WuQuant._top(cube, direction, position, this._momentsGreen);
      let halfBlue = bottomBlue + _WuQuant._top(cube, direction, position, this._momentsBlue);
      let halfAlpha = bottomAlpha + _WuQuant._top(cube, direction, position, this._momentsAlpha);
      let halfWeight = bottomWeight + _WuQuant._top(cube, direction, position, this._weights);
      if (halfWeight !== 0) {
        let halfDistance = halfRed * halfRed + halfGreen * halfGreen + halfBlue * halfBlue + halfAlpha * halfAlpha;
        let temp = halfDistance / halfWeight;
        halfRed = wholeRed - halfRed;
        halfGreen = wholeGreen - halfGreen;
        halfBlue = wholeBlue - halfBlue;
        halfAlpha = wholeAlpha - halfAlpha;
        halfWeight = wholeWeight - halfWeight;
        if (halfWeight !== 0) {
          halfDistance = halfRed * halfRed + halfGreen * halfGreen + halfBlue * halfBlue + halfAlpha * halfAlpha;
          temp += halfDistance / halfWeight;
          if (temp > result) {
            result = temp;
            cutPosition = position;
          }
        }
      }
    }
    return { max: result, position: cutPosition };
  }
  _cut(first, second) {
    let direction;
    const wholeRed = _WuQuant._volume(first, this._momentsRed);
    const wholeGreen = _WuQuant._volume(first, this._momentsGreen);
    const wholeBlue = _WuQuant._volume(first, this._momentsBlue);
    const wholeAlpha = _WuQuant._volume(first, this._momentsAlpha);
    const wholeWeight = _WuQuant._volume(first, this._weights);
    const red = this._maximize(first, _WuQuant._red, first.redMinimum + 1, first.redMaximum, wholeRed, wholeGreen, wholeBlue, wholeAlpha, wholeWeight);
    const green = this._maximize(first, _WuQuant._green, first.greenMinimum + 1, first.greenMaximum, wholeRed, wholeGreen, wholeBlue, wholeAlpha, wholeWeight);
    const blue = this._maximize(first, _WuQuant._blue, first.blueMinimum + 1, first.blueMaximum, wholeRed, wholeGreen, wholeBlue, wholeAlpha, wholeWeight);
    const alpha = this._maximize(first, _WuQuant._alpha, first.alphaMinimum + 1, first.alphaMaximum, wholeRed, wholeGreen, wholeBlue, wholeAlpha, wholeWeight);
    if (alpha.max >= red.max && alpha.max >= green.max && alpha.max >= blue.max) {
      direction = _WuQuant._alpha;
      if (alpha.position < 0)
        return false;
    } else if (red.max >= alpha.max && red.max >= green.max && red.max >= blue.max) {
      direction = _WuQuant._red;
    } else if (green.max >= alpha.max && green.max >= red.max && green.max >= blue.max) {
      direction = _WuQuant._green;
    } else {
      direction = _WuQuant._blue;
    }
    second.redMaximum = first.redMaximum;
    second.greenMaximum = first.greenMaximum;
    second.blueMaximum = first.blueMaximum;
    second.alphaMaximum = first.alphaMaximum;
    switch (direction) {
      case _WuQuant._red:
        second.redMinimum = first.redMaximum = red.position;
        second.greenMinimum = first.greenMinimum;
        second.blueMinimum = first.blueMinimum;
        second.alphaMinimum = first.alphaMinimum;
        break;
      case _WuQuant._green:
        second.greenMinimum = first.greenMaximum = green.position;
        second.redMinimum = first.redMinimum;
        second.blueMinimum = first.blueMinimum;
        second.alphaMinimum = first.alphaMinimum;
        break;
      case _WuQuant._blue:
        second.blueMinimum = first.blueMaximum = blue.position;
        second.redMinimum = first.redMinimum;
        second.greenMinimum = first.greenMinimum;
        second.alphaMinimum = first.alphaMinimum;
        break;
      case _WuQuant._alpha:
        second.alphaMinimum = first.alphaMaximum = alpha.position;
        second.blueMinimum = first.blueMinimum;
        second.redMinimum = first.redMinimum;
        second.greenMinimum = first.greenMinimum;
        break;
    }
    first.volume = (first.redMaximum - first.redMinimum) * (first.greenMaximum - first.greenMinimum) * (first.blueMaximum - first.blueMinimum) * (first.alphaMaximum - first.alphaMinimum);
    second.volume = (second.redMaximum - second.redMinimum) * (second.greenMaximum - second.greenMinimum) * (second.blueMaximum - second.blueMinimum) * (second.alphaMaximum - second.alphaMinimum);
    return true;
  }
  _initialize(colors) {
    this._colors = colors;
    this._cubes = [];
    for (let cubeIndex = 0; cubeIndex < colors; cubeIndex++) {
      this._cubes[cubeIndex] = new WuColorCube();
    }
    this._cubes[0].redMinimum = 0;
    this._cubes[0].greenMinimum = 0;
    this._cubes[0].blueMinimum = 0;
    this._cubes[0].alphaMinimum = 0;
    this._cubes[0].redMaximum = this._maxSideIndex;
    this._cubes[0].greenMaximum = this._maxSideIndex;
    this._cubes[0].blueMaximum = this._maxSideIndex;
    this._cubes[0].alphaMaximum = this._alphaMaxSideIndex;
    this._weights = createArray4D(this._alphaSideSize, this._sideSize, this._sideSize, this._sideSize);
    this._momentsRed = createArray4D(this._alphaSideSize, this._sideSize, this._sideSize, this._sideSize);
    this._momentsGreen = createArray4D(this._alphaSideSize, this._sideSize, this._sideSize, this._sideSize);
    this._momentsBlue = createArray4D(this._alphaSideSize, this._sideSize, this._sideSize, this._sideSize);
    this._momentsAlpha = createArray4D(this._alphaSideSize, this._sideSize, this._sideSize, this._sideSize);
    this._moments = createArray4D(this._alphaSideSize, this._sideSize, this._sideSize, this._sideSize);
    this._table = [];
    for (let tableIndex = 0; tableIndex < 256; ++tableIndex) {
      this._table[tableIndex] = tableIndex * tableIndex;
    }
    this._pixels = [];
  }
  _setQuality(significantBitsPerChannel = 5) {
    this._significantBitsPerChannel = significantBitsPerChannel;
    this._maxSideIndex = 1 << this._significantBitsPerChannel;
    this._alphaMaxSideIndex = this._maxSideIndex;
    this._sideSize = this._maxSideIndex + 1;
    this._alphaSideSize = this._alphaMaxSideIndex + 1;
  }
};
var WuQuant = _WuQuant;
__publicField(WuQuant, "_alpha", 3);
__publicField(WuQuant, "_red", 2);
__publicField(WuQuant, "_green", 1);
__publicField(WuQuant, "_blue", 0);

// src/image/index.ts
var image_exports = {};
__export(image_exports, {
  AbstractImageQuantizer: () => AbstractImageQuantizer,
  ErrorDiffusionArray: () => ErrorDiffusionArray,
  ErrorDiffusionArrayKernel: () => ErrorDiffusionArrayKernel,
  ErrorDiffusionRiemersma: () => ErrorDiffusionRiemersma,
  NearestColor: () => NearestColor
});

// src/image/imageQuantizer.ts
var AbstractImageQuantizer = class {
  quantizeSync(pointContainer, palette) {
    for (const value of this.quantize(pointContainer, palette)) {
      if (value.pointContainer) {
        return value.pointContainer;
      }
    }
    throw new Error("unreachable");
  }
};

// src/image/nearestColor.ts
var NearestColor = class extends AbstractImageQuantizer {
  constructor(colorDistanceCalculator) {
    super();
    __publicField(this, "_distance");
    this._distance = colorDistanceCalculator;
  }
  *quantize(pointContainer, palette) {
    const pointArray = pointContainer.getPointArray();
    const width = pointContainer.getWidth();
    const height = pointContainer.getHeight();
    const tracker = new ProgressTracker(height, 99);
    for (let y2 = 0; y2 < height; y2++) {
      if (tracker.shouldNotify(y2)) {
        yield {
          progress: tracker.progress
        };
      }
      for (let x2 = 0, idx = y2 * width; x2 < width; x2++, idx++) {
        const point = pointArray[idx];
        point.from(palette.getNearestColor(this._distance, point));
      }
    }
    yield {
      pointContainer,
      progress: 100
    };
  }
};

// src/image/array.ts
var ErrorDiffusionArrayKernel = /* @__PURE__ */ ((ErrorDiffusionArrayKernel2) => {
  ErrorDiffusionArrayKernel2[ErrorDiffusionArrayKernel2["FloydSteinberg"] = 0] = "FloydSteinberg";
  ErrorDiffusionArrayKernel2[ErrorDiffusionArrayKernel2["FalseFloydSteinberg"] = 1] = "FalseFloydSteinberg";
  ErrorDiffusionArrayKernel2[ErrorDiffusionArrayKernel2["Stucki"] = 2] = "Stucki";
  ErrorDiffusionArrayKernel2[ErrorDiffusionArrayKernel2["Atkinson"] = 3] = "Atkinson";
  ErrorDiffusionArrayKernel2[ErrorDiffusionArrayKernel2["Jarvis"] = 4] = "Jarvis";
  ErrorDiffusionArrayKernel2[ErrorDiffusionArrayKernel2["Burkes"] = 5] = "Burkes";
  ErrorDiffusionArrayKernel2[ErrorDiffusionArrayKernel2["Sierra"] = 6] = "Sierra";
  ErrorDiffusionArrayKernel2[ErrorDiffusionArrayKernel2["TwoSierra"] = 7] = "TwoSierra";
  ErrorDiffusionArrayKernel2[ErrorDiffusionArrayKernel2["SierraLite"] = 8] = "SierraLite";
  return ErrorDiffusionArrayKernel2;
})(ErrorDiffusionArrayKernel || {});
var ErrorDiffusionArray = class extends AbstractImageQuantizer {
  constructor(colorDistanceCalculator, kernel, serpentine = true, minimumColorDistanceToDither = 0, calculateErrorLikeGIMP = false) {
    super();
    __publicField(this, "_minColorDistance");
    __publicField(this, "_serpentine");
    __publicField(this, "_kernel");
    __publicField(this, "_calculateErrorLikeGIMP");
    __publicField(this, "_distance");
    this._setKernel(kernel);
    this._distance = colorDistanceCalculator;
    this._minColorDistance = minimumColorDistanceToDither;
    this._serpentine = serpentine;
    this._calculateErrorLikeGIMP = calculateErrorLikeGIMP;
  }
  *quantize(pointContainer, palette) {
    const pointArray = pointContainer.getPointArray();
    const originalPoint = new Point();
    const width = pointContainer.getWidth();
    const height = pointContainer.getHeight();
    const errorLines = [];
    let dir = 1;
    let maxErrorLines = 1;
    for (const kernel of this._kernel) {
      const kernelErrorLines = kernel[2] + 1;
      if (maxErrorLines < kernelErrorLines)
        maxErrorLines = kernelErrorLines;
    }
    for (let i = 0; i < maxErrorLines; i++) {
      this._fillErrorLine(errorLines[i] = [], width);
    }
    const tracker = new ProgressTracker(height, 99);
    for (let y2 = 0; y2 < height; y2++) {
      if (tracker.shouldNotify(y2)) {
        yield {
          progress: tracker.progress
        };
      }
      if (this._serpentine)
        dir *= -1;
      const lni = y2 * width;
      const xStart = dir === 1 ? 0 : width - 1;
      const xEnd = dir === 1 ? width : -1;
      this._fillErrorLine(errorLines[0], width);
      errorLines.push(errorLines.shift());
      const errorLine = errorLines[0];
      for (let x2 = xStart, idx = lni + xStart; x2 !== xEnd; x2 += dir, idx += dir) {
        const point = pointArray[idx];
        const error = errorLine[x2];
        originalPoint.from(point);
        const correctedPoint = Point.createByRGBA(inRange0to255Rounded(point.r + error[0]), inRange0to255Rounded(point.g + error[1]), inRange0to255Rounded(point.b + error[2]), inRange0to255Rounded(point.a + error[3]));
        const palettePoint = palette.getNearestColor(this._distance, correctedPoint);
        point.from(palettePoint);
        if (this._minColorDistance) {
          const dist = this._distance.calculateNormalized(originalPoint, palettePoint);
          if (dist < this._minColorDistance)
            continue;
        }
        let er;
        let eg;
        let eb;
        let ea;
        if (this._calculateErrorLikeGIMP) {
          er = correctedPoint.r - palettePoint.r;
          eg = correctedPoint.g - palettePoint.g;
          eb = correctedPoint.b - palettePoint.b;
          ea = correctedPoint.a - palettePoint.a;
        } else {
          er = originalPoint.r - palettePoint.r;
          eg = originalPoint.g - palettePoint.g;
          eb = originalPoint.b - palettePoint.b;
          ea = originalPoint.a - palettePoint.a;
        }
        const dStart = dir === 1 ? 0 : this._kernel.length - 1;
        const dEnd = dir === 1 ? this._kernel.length : -1;
        for (let i = dStart; i !== dEnd; i += dir) {
          const x1 = this._kernel[i][1] * dir;
          const y1 = this._kernel[i][2];
          if (x1 + x2 >= 0 && x1 + x2 < width && y1 + y2 >= 0 && y1 + y2 < height) {
            const d = this._kernel[i][0];
            const e = errorLines[y1][x1 + x2];
            e[0] += er * d;
            e[1] += eg * d;
            e[2] += eb * d;
            e[3] += ea * d;
          }
        }
      }
    }
    yield {
      pointContainer,
      progress: 100
    };
  }
  _fillErrorLine(errorLine, width) {
    if (errorLine.length > width) {
      errorLine.length = width;
    }
    const l = errorLine.length;
    for (let i = 0; i < l; i++) {
      const error = errorLine[i];
      error[0] = error[1] = error[2] = error[3] = 0;
    }
    for (let i = l; i < width; i++) {
      errorLine[i] = [0, 0, 0, 0];
    }
  }
  _setKernel(kernel) {
    switch (kernel) {
      case 0 /* FloydSteinberg */:
        this._kernel = [
          [7 / 16, 1, 0],
          [3 / 16, -1, 1],
          [5 / 16, 0, 1],
          [1 / 16, 1, 1]
        ];
        break;
      case 1 /* FalseFloydSteinberg */:
        this._kernel = [
          [3 / 8, 1, 0],
          [3 / 8, 0, 1],
          [2 / 8, 1, 1]
        ];
        break;
      case 2 /* Stucki */:
        this._kernel = [
          [8 / 42, 1, 0],
          [4 / 42, 2, 0],
          [2 / 42, -2, 1],
          [4 / 42, -1, 1],
          [8 / 42, 0, 1],
          [4 / 42, 1, 1],
          [2 / 42, 2, 1],
          [1 / 42, -2, 2],
          [2 / 42, -1, 2],
          [4 / 42, 0, 2],
          [2 / 42, 1, 2],
          [1 / 42, 2, 2]
        ];
        break;
      case 3 /* Atkinson */:
        this._kernel = [
          [1 / 8, 1, 0],
          [1 / 8, 2, 0],
          [1 / 8, -1, 1],
          [1 / 8, 0, 1],
          [1 / 8, 1, 1],
          [1 / 8, 0, 2]
        ];
        break;
      case 4 /* Jarvis */:
        this._kernel = [
          [7 / 48, 1, 0],
          [5 / 48, 2, 0],
          [3 / 48, -2, 1],
          [5 / 48, -1, 1],
          [7 / 48, 0, 1],
          [5 / 48, 1, 1],
          [3 / 48, 2, 1],
          [1 / 48, -2, 2],
          [3 / 48, -1, 2],
          [5 / 48, 0, 2],
          [3 / 48, 1, 2],
          [1 / 48, 2, 2]
        ];
        break;
      case 5 /* Burkes */:
        this._kernel = [
          [8 / 32, 1, 0],
          [4 / 32, 2, 0],
          [2 / 32, -2, 1],
          [4 / 32, -1, 1],
          [8 / 32, 0, 1],
          [4 / 32, 1, 1],
          [2 / 32, 2, 1]
        ];
        break;
      case 6 /* Sierra */:
        this._kernel = [
          [5 / 32, 1, 0],
          [3 / 32, 2, 0],
          [2 / 32, -2, 1],
          [4 / 32, -1, 1],
          [5 / 32, 0, 1],
          [4 / 32, 1, 1],
          [2 / 32, 2, 1],
          [2 / 32, -1, 2],
          [3 / 32, 0, 2],
          [2 / 32, 1, 2]
        ];
        break;
      case 7 /* TwoSierra */:
        this._kernel = [
          [4 / 16, 1, 0],
          [3 / 16, 2, 0],
          [1 / 16, -2, 1],
          [2 / 16, -1, 1],
          [3 / 16, 0, 1],
          [2 / 16, 1, 1],
          [1 / 16, 2, 1]
        ];
        break;
      case 8 /* SierraLite */:
        this._kernel = [
          [2 / 4, 1, 0],
          [1 / 4, -1, 1],
          [1 / 4, 0, 1]
        ];
        break;
      default:
        throw new Error(`ErrorDiffusionArray: unknown kernel = ${kernel}`);
    }
  }
};

// src/image/spaceFillingCurves/hilbertCurve.ts
function* hilbertCurve(width, height, callback) {
  const maxBound = Math.max(width, height);
  const level = Math.floor(Math.log(maxBound) / Math.log(2) + 1);
  const tracker = new ProgressTracker(width * height, 99);
  const data = {
    width,
    height,
    level,
    callback,
    tracker,
    index: 0,
    x: 0,
    y: 0
  };
  yield* walkHilbert(data, 1 /* UP */);
  visit(data, 0 /* NONE */);
}
function* walkHilbert(data, direction) {
  if (data.level < 1)
    return;
  if (data.tracker.shouldNotify(data.index)) {
    yield { progress: data.tracker.progress };
  }
  data.level--;
  switch (direction) {
    case 2 /* LEFT */:
      yield* walkHilbert(data, 1 /* UP */);
      visit(data, 3 /* RIGHT */);
      yield* walkHilbert(data, 2 /* LEFT */);
      visit(data, 4 /* DOWN */);
      yield* walkHilbert(data, 2 /* LEFT */);
      visit(data, 2 /* LEFT */);
      yield* walkHilbert(data, 4 /* DOWN */);
      break;
    case 3 /* RIGHT */:
      yield* walkHilbert(data, 4 /* DOWN */);
      visit(data, 2 /* LEFT */);
      yield* walkHilbert(data, 3 /* RIGHT */);
      visit(data, 1 /* UP */);
      yield* walkHilbert(data, 3 /* RIGHT */);
      visit(data, 3 /* RIGHT */);
      yield* walkHilbert(data, 1 /* UP */);
      break;
    case 1 /* UP */:
      yield* walkHilbert(data, 2 /* LEFT */);
      visit(data, 4 /* DOWN */);
      yield* walkHilbert(data, 1 /* UP */);
      visit(data, 3 /* RIGHT */);
      yield* walkHilbert(data, 1 /* UP */);
      visit(data, 1 /* UP */);
      yield* walkHilbert(data, 3 /* RIGHT */);
      break;
    case 4 /* DOWN */:
      yield* walkHilbert(data, 3 /* RIGHT */);
      visit(data, 1 /* UP */);
      yield* walkHilbert(data, 4 /* DOWN */);
      visit(data, 2 /* LEFT */);
      yield* walkHilbert(data, 4 /* DOWN */);
      visit(data, 4 /* DOWN */);
      yield* walkHilbert(data, 2 /* LEFT */);
      break;
    default:
      break;
  }
  data.level++;
}
function visit(data, direction) {
  if (data.x >= 0 && data.x < data.width && data.y >= 0 && data.y < data.height) {
    data.callback(data.x, data.y);
    data.index++;
  }
  switch (direction) {
    case 2 /* LEFT */:
      data.x--;
      break;
    case 3 /* RIGHT */:
      data.x++;
      break;
    case 1 /* UP */:
      data.y--;
      break;
    case 4 /* DOWN */:
      data.y++;
      break;
  }
}

// src/image/riemersma.ts
var ErrorDiffusionRiemersma = class extends AbstractImageQuantizer {
  constructor(colorDistanceCalculator, errorQueueSize = 16, errorPropagation = 1) {
    super();
    __publicField(this, "_distance");
    __publicField(this, "_weights");
    __publicField(this, "_errorQueueSize");
    this._distance = colorDistanceCalculator;
    this._errorQueueSize = errorQueueSize;
    this._weights = ErrorDiffusionRiemersma._createWeights(errorPropagation, errorQueueSize);
  }
  *quantize(pointContainer, palette) {
    const pointArray = pointContainer.getPointArray();
    const width = pointContainer.getWidth();
    const height = pointContainer.getHeight();
    const errorQueue = [];
    let head = 0;
    for (let i = 0; i < this._errorQueueSize; i++) {
      errorQueue[i] = { r: 0, g: 0, b: 0, a: 0 };
    }
    yield* hilbertCurve(width, height, (x2, y2) => {
      const p = pointArray[x2 + y2 * width];
      let { r, g, b, a } = p;
      for (let i = 0; i < this._errorQueueSize; i++) {
        const weight = this._weights[i];
        const e = errorQueue[(i + head) % this._errorQueueSize];
        r += e.r * weight;
        g += e.g * weight;
        b += e.b * weight;
        a += e.a * weight;
      }
      const correctedPoint = Point.createByRGBA(inRange0to255Rounded(r), inRange0to255Rounded(g), inRange0to255Rounded(b), inRange0to255Rounded(a));
      const quantizedPoint = palette.getNearestColor(this._distance, correctedPoint);
      head = (head + 1) % this._errorQueueSize;
      const tail = (head + this._errorQueueSize - 1) % this._errorQueueSize;
      errorQueue[tail].r = p.r - quantizedPoint.r;
      errorQueue[tail].g = p.g - quantizedPoint.g;
      errorQueue[tail].b = p.b - quantizedPoint.b;
      errorQueue[tail].a = p.a - quantizedPoint.a;
      p.from(quantizedPoint);
    });
    yield {
      pointContainer,
      progress: 100
    };
  }
  static _createWeights(errorPropagation, errorQueueSize) {
    const weights = [];
    const multiplier = Math.exp(Math.log(errorQueueSize) / (errorQueueSize - 1));
    for (let i = 0, next = 1; i < errorQueueSize; i++) {
      weights[i] = (next + 0.5 | 0) / errorQueueSize * errorPropagation;
      next *= multiplier;
    }
    return weights;
  }
};

// src/quality/index.ts
var quality_exports = {};
__export(quality_exports, {
  ssim: () => ssim
});

// src/quality/ssim.ts
var K1 = 0.01;
var K2 = 0.03;
function ssim(image1, image2) {
  if (image1.getHeight() !== image2.getHeight() || image1.getWidth() !== image2.getWidth()) {
    throw new Error("Images have different sizes!");
  }
  const bitsPerComponent = 8;
  const L = (1 << bitsPerComponent) - 1;
  const c1 = (K1 * L) ** 2;
  const c2 = (K2 * L) ** 2;
  let numWindows = 0;
  let mssim = 0;
  iterate(image1, image2, (lumaValues1, lumaValues2, averageLumaValue1, averageLumaValue2) => {
    let sigxy = 0;
    let sigsqx = 0;
    let sigsqy = 0;
    for (let i = 0; i < lumaValues1.length; i++) {
      sigsqx += (lumaValues1[i] - averageLumaValue1) ** 2;
      sigsqy += (lumaValues2[i] - averageLumaValue2) ** 2;
      sigxy += (lumaValues1[i] - averageLumaValue1) * (lumaValues2[i] - averageLumaValue2);
    }
    const numPixelsInWin = lumaValues1.length - 1;
    sigsqx /= numPixelsInWin;
    sigsqy /= numPixelsInWin;
    sigxy /= numPixelsInWin;
    const numerator = (2 * averageLumaValue1 * averageLumaValue2 + c1) * (2 * sigxy + c2);
    const denominator = (averageLumaValue1 ** 2 + averageLumaValue2 ** 2 + c1) * (sigsqx + sigsqy + c2);
    const ssim2 = numerator / denominator;
    mssim += ssim2;
    numWindows++;
  });
  return mssim / numWindows;
}
function iterate(image1, image2, callback) {
  const windowSize = 8;
  const width = image1.getWidth();
  const height = image1.getHeight();
  for (let y2 = 0; y2 < height; y2 += windowSize) {
    for (let x2 = 0; x2 < width; x2 += windowSize) {
      const windowWidth = Math.min(windowSize, width - x2);
      const windowHeight = Math.min(windowSize, height - y2);
      const lumaValues1 = calculateLumaValuesForWindow(image1, x2, y2, windowWidth, windowHeight);
      const lumaValues2 = calculateLumaValuesForWindow(image2, x2, y2, windowWidth, windowHeight);
      const averageLuma1 = calculateAverageLuma(lumaValues1);
      const averageLuma2 = calculateAverageLuma(lumaValues2);
      callback(lumaValues1, lumaValues2, averageLuma1, averageLuma2);
    }
  }
}
function calculateLumaValuesForWindow(image, x2, y2, width, height) {
  const pointArray = image.getPointArray();
  const lumaValues = [];
  let counter = 0;
  for (let j = y2; j < y2 + height; j++) {
    const offset = j * image.getWidth();
    for (let i = x2; i < x2 + width; i++) {
      const point = pointArray[offset + i];
      lumaValues[counter] = point.r * 0.2126 /* RED */ + point.g * 0.7152 /* GREEN */ + point.b * 0.0722 /* BLUE */;
      counter++;
    }
  }
  return lumaValues;
}
function calculateAverageLuma(lumaValues) {
  let sumLuma = 0;
  for (const luma of lumaValues) {
    sumLuma += luma;
  }
  return sumLuma / lumaValues.length;
}

// src/basicAPI.ts
var setImmediateImpl = typeof setImmediate === "function" ? setImmediate : typeof process !== "undefined" && typeof (process == null ? void 0 : process.nextTick) === "function" ? (callback) => process.nextTick(callback) : (callback) => setTimeout(callback, 0);
function buildPaletteSync(images, {
  colorDistanceFormula,
  paletteQuantization,
  colors
} = {}) {
  const distanceCalculator = colorDistanceFormulaToColorDistance(colorDistanceFormula);
  const paletteQuantizer = paletteQuantizationToPaletteQuantizer(distanceCalculator, paletteQuantization, colors);
  images.forEach((image) => paletteQuantizer.sample(image));
  return paletteQuantizer.quantizeSync();
}
async function buildPalette(images, {
  colorDistanceFormula,
  paletteQuantization,
  colors,
  onProgress
} = {}) {
  return new Promise((resolve, reject) => {
    const distanceCalculator = colorDistanceFormulaToColorDistance(colorDistanceFormula);
    const paletteQuantizer = paletteQuantizationToPaletteQuantizer(distanceCalculator, paletteQuantization, colors);
    images.forEach((image) => paletteQuantizer.sample(image));
    let palette;
    const iterator = paletteQuantizer.quantize();
    const next = () => {
      try {
        const result = iterator.next();
        if (result.done) {
          resolve(palette);
        } else {
          if (result.value.palette)
            palette = result.value.palette;
          if (onProgress)
            onProgress(result.value.progress);
          setImmediateImpl(next);
        }
      } catch (error) {
        reject(error);
      }
    };
    setImmediateImpl(next);
  });
}
function applyPaletteSync(image, palette, { colorDistanceFormula, imageQuantization } = {}) {
  const distanceCalculator = colorDistanceFormulaToColorDistance(colorDistanceFormula);
  const imageQuantizer = imageQuantizationToImageQuantizer(distanceCalculator, imageQuantization);
  return imageQuantizer.quantizeSync(image, palette);
}
async function applyPalette(image, palette, {
  colorDistanceFormula,
  imageQuantization,
  onProgress
} = {}) {
  return new Promise((resolve, reject) => {
    const distanceCalculator = colorDistanceFormulaToColorDistance(colorDistanceFormula);
    const imageQuantizer = imageQuantizationToImageQuantizer(distanceCalculator, imageQuantization);
    let outPointContainer;
    const iterator = imageQuantizer.quantize(image, palette);
    const next = () => {
      try {
        const result = iterator.next();
        if (result.done) {
          resolve(outPointContainer);
        } else {
          if (result.value.pointContainer) {
            outPointContainer = result.value.pointContainer;
          }
          if (onProgress)
            onProgress(result.value.progress);
          setImmediateImpl(next);
        }
      } catch (error) {
        reject(error);
      }
    };
    setImmediateImpl(next);
  });
}
function colorDistanceFormulaToColorDistance(colorDistanceFormula = "euclidean-bt709") {
  switch (colorDistanceFormula) {
    case "cie94-graphic-arts":
      return new CIE94GraphicArts();
    case "cie94-textiles":
      return new CIE94Textiles();
    case "ciede2000":
      return new CIEDE2000();
    case "color-metric":
      return new CMetric();
    case "euclidean":
      return new Euclidean();
    case "euclidean-bt709":
      return new EuclideanBT709();
    case "euclidean-bt709-noalpha":
      return new EuclideanBT709NoAlpha();
    case "manhattan":
      return new Manhattan();
    case "manhattan-bt709":
      return new ManhattanBT709();
    case "manhattan-nommyde":
      return new ManhattanNommyde();
    case "pngquant":
      return new PNGQuant();
    default:
      throw new Error(`Unknown colorDistanceFormula ${colorDistanceFormula}`);
  }
}
function imageQuantizationToImageQuantizer(distanceCalculator, imageQuantization = "floyd-steinberg") {
  switch (imageQuantization) {
    case "nearest":
      return new NearestColor(distanceCalculator);
    case "riemersma":
      return new ErrorDiffusionRiemersma(distanceCalculator);
    case "floyd-steinberg":
      return new ErrorDiffusionArray(distanceCalculator, 0 /* FloydSteinberg */);
    case "false-floyd-steinberg":
      return new ErrorDiffusionArray(distanceCalculator, 1 /* FalseFloydSteinberg */);
    case "stucki":
      return new ErrorDiffusionArray(distanceCalculator, 2 /* Stucki */);
    case "atkinson":
      return new ErrorDiffusionArray(distanceCalculator, 3 /* Atkinson */);
    case "jarvis":
      return new ErrorDiffusionArray(distanceCalculator, 4 /* Jarvis */);
    case "burkes":
      return new ErrorDiffusionArray(distanceCalculator, 5 /* Burkes */);
    case "sierra":
      return new ErrorDiffusionArray(distanceCalculator, 6 /* Sierra */);
    case "two-sierra":
      return new ErrorDiffusionArray(distanceCalculator, 7 /* TwoSierra */);
    case "sierra-lite":
      return new ErrorDiffusionArray(distanceCalculator, 8 /* SierraLite */);
    default:
      throw new Error(`Unknown imageQuantization ${imageQuantization}`);
  }
}
function paletteQuantizationToPaletteQuantizer(distanceCalculator, paletteQuantization = "wuquant", colors = 256) {
  switch (paletteQuantization) {
    case "neuquant":
      return new NeuQuant(distanceCalculator, colors);
    case "rgbquant":
      return new RGBQuant(distanceCalculator, colors);
    case "wuquant":
      return new WuQuant(distanceCalculator, colors);
    case "neuquant-float":
      return new NeuQuantFloat(distanceCalculator, colors);
    default:
      throw new Error(`Unknown paletteQuantization ${paletteQuantization}`);
  }
}
module.exports = __toCommonJS(src_exports);
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  applyPalette,
  applyPaletteSync,
  buildPalette,
  buildPaletteSync,
  constants,
  conversion,
  distance,
  image,
  palette,
  quality,
  utils
});
/**
 * @preserve
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * cie94.ts - part of Image Quantization Library
 */
/**
 * @preserve
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * ciede2000.ts - part of Image Quantization Library
 */
/**
 * @preserve
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * cmetric.ts - part of Image Quantization Library
 */
/**
 * @preserve
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * common.ts - part of Image Quantization Library
 */
/**
 * @preserve
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * constants.ts - part of Image Quantization Library
 */
/**
 * @preserve
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * ditherErrorDiffusionArray.ts - part of Image Quantization Library
 */
/**
 * @preserve
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * euclidean.ts - part of Image Quantization Library
 */
/**
 * @preserve
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * helper.ts - part of Image Quantization Library
 */
/**
 * @preserve
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * hueStatistics.ts - part of Image Quantization Library
 */
/**
 * @preserve
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * iq.ts - Image Quantization Library
 */
/**
 * @preserve
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * lab2rgb.ts - part of Image Quantization Library
 */
/**
 * @preserve
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * lab2xyz.ts - part of Image Quantization Library
 */
/**
 * @preserve
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * manhattanNeuQuant.ts - part of Image Quantization Library
 */
/**
 * @preserve
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * nearestColor.ts - part of Image Quantization Library
 */
/**
 * @preserve
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * palette.ts - part of Image Quantization Library
 */
/**
 * @preserve
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * pngQuant.ts - part of Image Quantization Library
 */
/**
 * @preserve
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * point.ts - part of Image Quantization Library
 */
/**
 * @preserve
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * pointContainer.ts - part of Image Quantization Library
 */
/**
 * @preserve
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * rgb2hsl.ts - part of Image Quantization Library
 */
/**
 * @preserve
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * rgb2lab.ts - part of Image Quantization Library
 */
/**
 * @preserve
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * rgb2xyz.ts - part of Image Quantization Library
 */
/**
 * @preserve
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * ssim.ts - part of Image Quantization Library
 */
/**
 * @preserve
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * wuQuant.ts - part of Image Quantization Library
 */
/**
 * @preserve
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * xyz2lab.ts - part of Image Quantization Library
 */
/**
 * @preserve
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * xyz2rgb.ts - part of Image Quantization Library
 */
/**
 * @preserve
 * MIT License
 *
 * Copyright 2015-2018 Igor Bezkrovnyi
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 *
 * riemersma.ts - part of Image Quantization Library
 */
/**
 * @preserve TypeScript port:
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * colorHistogram.ts - part of Image Quantization Library
 */
/**
 * @preserve TypeScript port:
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * neuquant.ts - part of Image Quantization Library
 */
/**
 * @preserve TypeScript port:
 * Copyright 2015-2018 Igor Bezkrovnyi
 * All rights reserved. (MIT Licensed)
 *
 * rgbquant.ts - part of Image Quantization Library
 */
//# sourceMappingURL=image-q.cjs.map
