emf-converter 4.8.2 → 4.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/browser.mjs CHANGED
@@ -16808,14 +16808,21 @@ function blurKernel(radius) {
16808
16808
  k[0] = 1;
16809
16809
  return k;
16810
16810
  }
16811
- let sum = 0;
16812
- for (let i = -taps; i <= taps; i++) {
16813
- const w = Math.exp(-1.96 * i * i / (radius * radius));
16814
- k[i + taps] = w;
16815
- sum += w;
16816
- }
16817
- for (let i = 0; i < k.length; i++) {
16818
- k[i] /= sum;
16811
+ const step = truncF32(truncF32(1.4) / Math.fround(radius));
16812
+ const w = new Float64Array(taps + 1);
16813
+ w[0] = 1;
16814
+ let offset = 0;
16815
+ let sum = 1;
16816
+ for (let i = 1; i <= taps; i++) {
16817
+ offset = truncF32(offset + step);
16818
+ w[i] = truncF32(Math.exp(-truncF32(offset * offset)));
16819
+ sum = truncF32(sum + truncF32(2 * w[i]));
16820
+ }
16821
+ const scale = truncF32(256 / sum);
16822
+ for (let i = 0; i <= taps; i++) {
16823
+ const weight = truncF32(w[i] * scale) / 256;
16824
+ k[taps + i] = weight;
16825
+ k[taps - i] = weight;
16819
16826
  }
16820
16827
  return k;
16821
16828
  }
@@ -17037,13 +17044,17 @@ function expandedBlur(rgba, width, height, radius, x0, y0, x1, y1, cropped) {
17037
17044
  const blurred = blurReduction(radius) > 1 ? effectBlur(buf, bw, bh, radius, cropped ? { x: r, y: r, w: x1 - x0, h: y1 - y0 } : void 0, true) : gdipBlur(buf, bw, bh, radius, cropped ? r : 0, cropped, Math.ceil((y1 - y0) / (x1 - x0)));
17038
17045
  const w = x1 - x0;
17039
17046
  const out = new Uint8ClampedArray(w * (y1 - y0) * 4);
17047
+ const halo = new Uint8ClampedArray((y1 - y0) * 4);
17040
17048
  for (let y = 0; y < y1 - y0; y++) {
17041
17049
  const from = ((y + r) * bw + r) * 4;
17042
17050
  for (let i = 0; i < w * 4; i++) {
17043
17051
  out[y * w * 4 + i] = Math.round(blurred[from + i]);
17044
17052
  }
17053
+ for (let i = 0; i < 4; i++) {
17054
+ halo[y * 4 + i] = Math.round(blurred[from + w * 4 + i]);
17055
+ }
17045
17056
  }
17046
- return out;
17057
+ return { out, halo };
17047
17058
  }
17048
17059
  function applyImageEffectToRect(rgba, width, height, effect, src) {
17049
17060
  if (width <= 0 || height <= 0 || rgba.length !== width * height * 4) {
@@ -17076,7 +17087,12 @@ function applyImageEffectToRect(rgba, width, height, effect, src) {
17076
17087
  };
17077
17088
  if (src && effect.kind === "blur" && effect.expandEdge) {
17078
17089
  const cropped = Math.ceil(src.x + src.w) < width && Math.ceil(src.y + src.h) < height;
17079
- return result(expandedBlur(rgba, width, height, effect.radius, x0, y0, x1, y1, cropped));
17090
+ const { out: out2, halo } = expandedBlur(rgba, width, height, effect.radius, x0, y0, x1, y1, cropped);
17091
+ const region2 = result(out2);
17092
+ if (shownWidth === w && shownHeight === h) {
17093
+ region2.haloRight = halo;
17094
+ }
17095
+ return region2;
17080
17096
  }
17081
17097
  let region = rgba;
17082
17098
  if (w !== width || h !== height) {
@@ -20448,6 +20464,22 @@ function cubicIntegral(t, a) {
20448
20464
  }
20449
20465
  return Math.sign(t) * v;
20450
20466
  }
20467
+ var FAR_FADE = [1, 1, 0.985, 0.95, 0.91, 0.85, 0.8, 0.745, 0.69, 0.63, 0.56, 0.5, 0.43, 0.35, 0.28, 0.22, 0.16, 0.11, 0.065, 0.03, 0];
20468
+ function fadeAt(d, bilinear) {
20469
+ if (d >= 1) {
20470
+ return 0;
20471
+ }
20472
+ if (bilinear) {
20473
+ return 1 - Math.max(0, d);
20474
+ }
20475
+ const x = Math.max(0, d) * 20;
20476
+ const i = Math.floor(x);
20477
+ return FAR_FADE[i] + (FAR_FADE[i + 1] - FAR_FADE[i]) * (x - i);
20478
+ }
20479
+ function nearSourceExtent(deviceLen, srcLen) {
20480
+ const d = Math.ceil(deviceLen - 1e-6) - srcLen;
20481
+ return d >= -1 && d <= 1;
20482
+ }
20451
20483
  var BICUBIC_A = -0.5;
20452
20484
  var HQ_BICUBIC_A = -1;
20453
20485
  function axisFilter(kernel, scale, copy) {
@@ -20552,13 +20584,39 @@ function mirroredOrigin(o) {
20552
20584
  return f === 0 ? o : Math.floor(o) + 1 - f;
20553
20585
  }
20554
20586
  function resampleImage(rgba, width, height, spec, surface) {
20587
+ if (spec.rightHalo && spec.rightHalo.length === height * 4) {
20588
+ const grown = new Uint8ClampedArray((width + 1) * height * 4);
20589
+ for (let y = 0; y < height; y++) {
20590
+ grown.set(rgba.subarray(y * width * 4, (y + 1) * width * 4), y * (width + 1) * 4);
20591
+ grown.set(spec.rightHalo.subarray(y * 4, y * 4 + 4), (y * (width + 1) + width) * 4);
20592
+ }
20593
+ return resampleImage(grown, width + 1, height, { ...spec, rightHalo: void 0 }, surface);
20594
+ }
20555
20595
  if (spec.kernel === "nearest" && !spec.wrap) {
20556
20596
  return resampleNearest(rgba, width, height, spec, surface);
20557
20597
  }
20558
20598
  let m = snapToDeviceGrid(spec);
20559
- const kernel = spec.kernel;
20599
+ let kernel = spec.kernel;
20560
20600
  const hq = kernel === "hq-bilinear" || kernel === "hq-bicubic";
20561
20601
  const axisAligned = m[1] === 0 && m[2] === 0;
20602
+ let farFade = false;
20603
+ let shiftX = 0;
20604
+ let shiftY = 0;
20605
+ if (hq && !axisAligned) {
20606
+ const extentU = Math.hypot(m[0], m[1]) * spec.srcW;
20607
+ const extentV = Math.hypot(m[2], m[3]) * spec.srcH;
20608
+ if (nearSourceExtent(extentU, spec.srcW) || nearSourceExtent(extentV, spec.srcH)) {
20609
+ kernel = kernel === "hq-bicubic" ? "bicubic" : "bilinear";
20610
+ } else {
20611
+ farFade = true;
20612
+ if (spec.halfPixelOffset) {
20613
+ const lu = Math.hypot(m[0], m[1]);
20614
+ const lv = Math.hypot(m[2], m[3]);
20615
+ shiftX = 0.5 * m[0] / lu + 0.5 * m[2] / lv;
20616
+ shiftY = 0.5 * m[1] / lu + 0.5 * m[3] / lv;
20617
+ }
20618
+ }
20619
+ }
20562
20620
  if (hq && axisAligned) {
20563
20621
  const ox = m[0] * spec.srcX + m[4];
20564
20622
  m = [m[0], 0, 0, m[3], m[4] + mirroredOrigin(ox) - ox, m[5]];
@@ -20613,6 +20671,8 @@ function resampleImage(rgba, width, height, spec, surface) {
20613
20671
  const vMax = spec.srcY + spec.srcH;
20614
20672
  const wu = [];
20615
20673
  const wv = [];
20674
+ const gradU = Math.hypot(inv2[0], inv2[2]);
20675
+ const gradV = Math.hypot(inv2[1], inv2[3]);
20616
20676
  const c = spec.clampArgb ?? 0;
20617
20677
  const edge = {
20618
20678
  wrap: spec.wrap,
@@ -20624,8 +20684,8 @@ function resampleImage(rgba, width, height, spec, surface) {
20624
20684
  const py = by0 + j + o;
20625
20685
  for (let i = 0; i < w; i++) {
20626
20686
  const px = bx0 + i + o;
20627
- const u = inv2[0] * px + inv2[2] * py + inv2[4];
20628
- const v = inv2[1] * px + inv2[3] * py + inv2[5];
20687
+ const u = inv2[0] * (px - shiftX) + inv2[2] * (py - shiftY) + inv2[4];
20688
+ const v = inv2[1] * (px - shiftX) + inv2[3] * (py - shiftY) + inv2[5];
20629
20689
  const cx = px + COVERAGE_NUDGE_X;
20630
20690
  const cy = py + COVERAGE_NUDGE_Y;
20631
20691
  const eu = inv2[0] * cx + inv2[2] * cy + inv2[4];
@@ -20633,31 +20693,35 @@ function resampleImage(rgba, width, height, spec, surface) {
20633
20693
  if (eu < spec.srcX || ev < spec.srcY || eu >= uMax || ev >= vMax) {
20634
20694
  continue;
20635
20695
  }
20636
- const cu = u;
20637
- const cv = v;
20638
- const iu0 = Math.ceil(cu - fu.radius);
20639
- const iu1 = Math.floor(cu + fu.radius);
20640
- const iv0 = Math.ceil(cv - fv.radius);
20641
- const iv1 = Math.floor(cv + fv.radius);
20642
- wu.length = 0;
20643
- wv.length = 0;
20644
- for (let t = iu0; t <= iu1; t++) {
20645
- wu.push(fu.weight(t, cu));
20646
- }
20647
- for (let t = iv0; t <= iv1; t++) {
20648
- wv.push(fv.weight(t, cv));
20649
- }
20650
- const [r, g, b, a] = blendSeparable(
20651
- rgba,
20652
- width,
20653
- spec.wrap ? { x0: 0, y0: 0, x1: width, y1: height } : { x0: sx0, y0: sy0, x1: sx1, y1: sy1 },
20654
- iu0,
20655
- wu,
20656
- iv0,
20657
- wv,
20658
- kernel === "bicubic",
20659
- edge
20660
- );
20696
+ const box = { x0: 0, y0: 0, x1: width, y1: height };
20697
+ const sampleAt = (cu, cv) => {
20698
+ const iu0 = Math.ceil(cu - fu.radius);
20699
+ const iu1 = Math.floor(cu + fu.radius);
20700
+ const iv0 = Math.ceil(cv - fv.radius);
20701
+ const iv1 = Math.floor(cv + fv.radius);
20702
+ wu.length = 0;
20703
+ wv.length = 0;
20704
+ for (let t = iu0; t <= iu1; t++) {
20705
+ wu.push(fu.weight(t, cu));
20706
+ }
20707
+ for (let t = iv0; t <= iv1; t++) {
20708
+ wv.push(fv.weight(t, cv));
20709
+ }
20710
+ return blendSeparable(rgba, width, box, iu0, wu, iv0, wv, kernel === "bicubic", edge);
20711
+ };
20712
+ let [r, g, b, a] = sampleAt(u, v);
20713
+ if (farFade && !spec.wrap && a > 0) {
20714
+ const du = (uMax - u) / gradU;
20715
+ const dv = (vMax - v) / gradV;
20716
+ const k = 1 - (du < 1 ? fadeAt(du, kernel === "hq-bilinear") * (sampleAt(uMax, v)[3] / a) : 0) - (dv < 1 ? fadeAt(dv, kernel === "hq-bilinear") * (sampleAt(u, vMax)[3] / a) : 0);
20717
+ if (k < 1) {
20718
+ const f = Math.max(0, k);
20719
+ r *= f;
20720
+ g *= f;
20721
+ b *= f;
20722
+ a *= f;
20723
+ }
20724
+ }
20661
20725
  if (a <= 0) {
20662
20726
  continue;
20663
20727
  }
@@ -23484,7 +23548,8 @@ function effectedDraw(img, bitmap, effect, draw, source) {
23484
23548
  srcY,
23485
23549
  srcW,
23486
23550
  srcH,
23487
- toDevice: mulMatrix(draw.resample.toDevice, shift)
23551
+ toDevice: mulMatrix(draw.resample.toDevice, shift),
23552
+ rightHalo: region.haloRight
23488
23553
  }
23489
23554
  }
23490
23555
  };
@@ -31423,6 +31488,15 @@ function illuminantCube(index) {
31423
31488
  }
31424
31489
  return cube;
31425
31490
  }
31491
+ var ILLUMINANT_MATRICES = {
31492
+ 1: [[1.64737, -0.59174, -0.05494], [0.02963, 0.96126, 881e-5], [0.2911, 0.40189, 0.30769]],
31493
+ 2: [[1.22319, -0.17765, -0.04515], [275e-5, 0.99054, 645e-5], [0.05514, 0.12795, 0.81816]],
31494
+ 3: [[1.02833, -0.01775, -0.01086], [861e-5, 0.98431, 728e-5], [-0.01616, -0.0448, 1.05995]],
31495
+ 4: [[1.17271, -0.14059, -0.03174], [-474e-5, 1.00266, 183e-5], [0.05783, 0.14663, 0.79683]],
31496
+ 5: [[1.10431, -0.08327, -0.02067], [-336e-5, 1.0025, 67e-5], [0.03344, 0.09072, 0.87702]],
31497
+ 7: [[0.92515, 0.05628, 0.01822], [318e-5, 0.9967, 34e-5], [-0.02086, -0.06817, 1.08783]],
31498
+ 8: [[1.31275, -0.26259, -0.04977], [-244e-5, 0.99695, 524e-5], [0.10854, 0.23443, 0.65827]]
31499
+ };
31426
31500
  function hasIlluminant(ca) {
31427
31501
  return illuminantCube(ca.illuminant) !== null;
31428
31502
  }
@@ -31493,9 +31567,9 @@ var BRIGHTNESS_STEP = 0.95625;
31493
31567
  var COLORFULNESS_SCALE = 1 / 100;
31494
31568
  var TINT_RADIANS = -Math.PI / 3;
31495
31569
  var RGB_TO_XYZ = [
31496
- [0.4124, 0.3576, 0.1805],
31497
- [0.2126, 0.7152, 0.0722],
31498
- [0.0193, 0.1192, 0.9505]
31570
+ [0.4123908, 0.3575843, 0.1804808],
31571
+ [0.212639, 0.7151687, 0.0721923],
31572
+ [0.0193308, 0.1191948, 0.9505322]
31499
31573
  ];
31500
31574
  var XYZ_TO_RGB = invert3(RGB_TO_XYZ);
31501
31575
  var WHITE = RGB_TO_XYZ.map((row2) => row2[0] + row2[1] + row2[2]);
@@ -31523,13 +31597,13 @@ function adjustChroma(r, g, b, scale, angle) {
31523
31597
  const z = RGB_TO_XYZ[2][0] * r + RGB_TO_XYZ[2][1] * g + RGB_TO_XYZ[2][2] * b;
31524
31598
  const d = x + 15 * y + 3 * z;
31525
31599
  if (d <= 1e-9 || y <= 1e-9) {
31526
- return [r, g, b];
31600
+ return [clamp255(r), clamp255(g), clamp255(b)];
31527
31601
  }
31528
31602
  const du = 4 * x / d - WHITE_U;
31529
31603
  const dv = 9 * y / d - WHITE_V;
31530
31604
  const cos = Math.cos(angle) * scale;
31531
31605
  const sin = Math.sin(angle) * scale;
31532
- const u = WHITE_U + du * cos - dv * sin;
31606
+ const u = Math.max(0, WHITE_U + du * cos - dv * sin);
31533
31607
  const v = Math.max(1e-6, WHITE_V + du * sin + dv * cos);
31534
31608
  const x2 = y * 9 * u / (4 * v);
31535
31609
  const z2 = y * (12 - 3 * u - 20 * v) / (4 * v);
@@ -31548,6 +31622,7 @@ function adjustChroma(r, g, b, scale, angle) {
31548
31622
  }
31549
31623
  function colorAdjustmentMapper(ca) {
31550
31624
  const illuminant = illuminantCube(ca.illuminant);
31625
+ const matrix = ILLUMINANT_MATRICES[ca.illuminant];
31551
31626
  const gammas = [ca.redGamma / 1e4, ca.greenGamma / 1e4, ca.blueGamma / 1e4];
31552
31627
  const black = ca.referenceBlack / 1e4 * 255;
31553
31628
  const span = Math.max(1e-6, ca.referenceWhite / 1e4 * 255 - black);
@@ -31576,16 +31651,17 @@ function colorAdjustmentMapper(ca) {
31576
31651
  }
31577
31652
  return (rgb2) => {
31578
31653
  let c = [rgb2 >> 16 & 255, rgb2 >> 8 & 255, rgb2 & 255];
31579
- if (illuminant) {
31580
- const mapped = lookupIlluminant(illuminant, c[0] / 255, c[1] / 255, c[2] / 255);
31581
- c = [mapped[0] * 255, mapped[1] * 255, mapped[2] * 255];
31582
- }
31583
31654
  if (chroma) {
31584
- if (!illuminant) {
31585
- c = c.map(exactPaletteLevel);
31655
+ c = c.map(exactPaletteLevel);
31656
+ if (matrix) {
31657
+ const [r, g, b] = c;
31658
+ c = matrix.map((row2) => row2[0] * r + row2[1] * g + row2[2] * b);
31586
31659
  }
31587
- c = adjustChroma(clamp255(c[0]), clamp255(c[1]), clamp255(c[2]), scale, angle);
31660
+ c = adjustChroma(c[0], c[1], c[2], scale, angle);
31588
31661
  c = c.map(roundHalfUp);
31662
+ } else if (illuminant) {
31663
+ const mapped = lookupIlluminant(illuminant, c[0] / 255, c[1] / 255, c[2] / 255);
31664
+ c = [mapped[0] * 255, mapped[1] * 255, mapped[2] * 255];
31589
31665
  }
31590
31666
  return curve(c[0], 0) << 16 | curve(c[1], 1) << 8 | curve(c[2], 2);
31591
31667
  };
@@ -31939,20 +32015,6 @@ function halftoneDespeckle(px, w, h) {
31939
32015
  }
31940
32016
  }
31941
32017
  }
31942
- function halftoneSharpen(px, w, h) {
31943
- const src = px.slice();
31944
- const at = (x, y, c) => src[(Math.max(0, Math.min(h - 1, y)) * w + Math.max(0, Math.min(w - 1, x))) * 3 + c];
31945
- for (let y = 0; y < h; y++) {
31946
- for (let x = 0; x < w; x++) {
31947
- for (let c = 0; c < 3; c++) {
31948
- const v = at(x, y, c);
31949
- const sum = at(x - 1, y, c) + at(x + 1, y, c) + at(x, y - 1, c) + at(x, y + 1, c);
31950
- const out = v + Math.floor((4 * v - sum) / 8);
31951
- px[(y * w + x) * 3 + c] = out < 0 ? 0 : out > 255 ? 255 : out;
31952
- }
31953
- }
31954
- }
31955
- }
31956
32018
  function halftonePairDespeckle(px, w, h, rows) {
31957
32019
  const n = rows ? w : h;
31958
32020
  const at = (k, side) => (rows ? side * w + k : k * w + side) * 3;
@@ -31975,6 +32037,46 @@ function halftoneKeepLast(px, w, h, rows) {
31975
32037
  }
31976
32038
  return out;
31977
32039
  }
32040
+ function halftoneReduceBoth(rect, sw, sh, dw, dh, flipX, flipY) {
32041
+ const cols = halftoneReduceTaps(sw, dw, flipX);
32042
+ const rows = halftoneReduceTaps(sh, dh, flipY);
32043
+ const wide = new Int32Array(dw * sh * 3);
32044
+ for (let y = 0; y < sh; y++) {
32045
+ for (let x = 0; x < dw; x++) {
32046
+ let total = 0;
32047
+ for (const [, w] of cols[x]) total += w;
32048
+ for (let c = 0; c < 3; c++) {
32049
+ let sum = 0;
32050
+ for (const [xx, w] of cols[x]) sum += rect[(y * sw + xx) * 3 + c] * w;
32051
+ wide[(y * dw + x) * 3 + c] = Math.floor((2 * sum + total) / (2 * total));
32052
+ }
32053
+ }
32054
+ }
32055
+ const avg = new Float64Array(dw * dh * 3);
32056
+ for (let y = 0; y < dh; y++) {
32057
+ let total = 0;
32058
+ for (const [, w] of rows[y]) total += w;
32059
+ for (let x = 0; x < dw; x++) {
32060
+ for (let c = 0; c < 3; c++) {
32061
+ let sum = 0;
32062
+ for (const [yy, w] of rows[y]) sum += wide[(yy * dw + x) * 3 + c] * w;
32063
+ avg[(y * dw + x) * 3 + c] = sum / total;
32064
+ }
32065
+ }
32066
+ }
32067
+ const at = (x, y, c) => avg[(Math.max(0, Math.min(dh - 1, y)) * dw + Math.max(0, Math.min(dw - 1, x))) * 3 + c];
32068
+ const out = new Int32Array(dw * dh * 3);
32069
+ for (let y = 0; y < dh; y++) {
32070
+ for (let x = 0; x < dw; x++) {
32071
+ for (let c = 0; c < 3; c++) {
32072
+ const v = at(x, y, c);
32073
+ const sum = at(x - 1, y, c) + at(x + 1, y, c) + at(x, y - 1, c) + at(x, y + 1, c);
32074
+ out[(y * dw + x) * 3 + c] = Math.max(0, Math.min(255, Math.floor(v + (4 * v - sum) / 8)));
32075
+ }
32076
+ }
32077
+ }
32078
+ return out;
32079
+ }
31978
32080
  function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSampling = false, directDib = false, dither, curves) {
31979
32081
  const W = Math.max(0, Math.round(Math.abs(dw)));
31980
32082
  const H = Math.max(0, Math.round(Math.abs(dh)));
@@ -32026,11 +32128,18 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
32026
32128
  }
32027
32129
  const reducedEven = W < SW ? SW % 2 === 0 && H % SH === 0 : SH % 2 === 0 && W % SW === 0;
32028
32130
  const ditherAtSource = dithered && (W >= SW && H >= SH || nativeMixed && reducedEven);
32131
+ const extendRow = ditherAtSource && nativeMixed && W < SW && H > SH && !flipY;
32132
+ if (extendRow) {
32133
+ const bigger = new Int32Array((SH + 1) * SW * 3);
32134
+ bigger.set(rect);
32135
+ bigger.copyWithin(SH * SW * 3, (SH - 1) * SW * 3, SH * SW * 3);
32136
+ rect = bigger;
32137
+ }
32029
32138
  if (ditherAtSource) {
32030
32139
  ditherPixels(
32031
32140
  rect,
32032
32141
  SW,
32033
- SH,
32142
+ extendRow ? SH + 1 : SH,
32034
32143
  dither,
32035
32144
  false,
32036
32145
  false,
@@ -32070,7 +32179,10 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
32070
32179
  linear(rows, SH, H, flipY);
32071
32180
  }
32072
32181
  let out = nativeMixed ? new Float64Array(sampleW * sampleH * 3) : new Int32Array(W * H * 3);
32073
- for (let y = 0; y < sampleH; y++) {
32182
+ if (reducing) {
32183
+ out = halftoneReduceBoth(rect, SW, SH, W, H, flipX, flipY);
32184
+ }
32185
+ for (let y = 0; !reducing && y < sampleH; y++) {
32074
32186
  const ys = rows[y];
32075
32187
  for (let x = 0; x < sampleW; x++) {
32076
32188
  const xs = cols[x];
@@ -32095,15 +32207,38 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSamplin
32095
32207
  out[o + 2] = round(b);
32096
32208
  }
32097
32209
  }
32098
- if (reducing) {
32099
- halftoneSharpen(out, W, H);
32100
- }
32101
32210
  if (nativeMixed) {
32102
32211
  const reduceHorizontal = W < SW;
32212
+ let extension;
32213
+ if (extendRow) {
32214
+ const reduced = new Float64Array(sampleW * 3);
32215
+ for (let x = 0; x < sampleW; x++) {
32216
+ let total = 0;
32217
+ const sums = [0, 0, 0];
32218
+ for (const [xx, wx] of cols[x]) {
32219
+ total += wx;
32220
+ for (let c = 0; c < 3; c++) sums[c] += rect[(SH * SW + xx) * 3 + c] * wx;
32221
+ }
32222
+ for (let c = 0; c < 3; c++) reduced[x * 3 + c] = sums[c] / total;
32223
+ }
32224
+ extension = reduced;
32225
+ }
32103
32226
  for (const horizontal of [reduceHorizontal, !reduceHorizontal]) {
32104
32227
  const source2 = out;
32105
32228
  out = new Int32Array(source2.length);
32106
- const at = (x, y, c) => source2[(Math.max(0, Math.min(sampleH - 1, y)) * sampleW + Math.max(0, Math.min(sampleW - 1, x))) * 3 + c];
32229
+ const ext = extension;
32230
+ const at = (x, y, c) => y >= sampleH && ext ? ext[Math.max(0, Math.min(sampleW - 1, x)) * 3 + c] : source2[(Math.max(0, Math.min(sampleH - 1, y)) * sampleW + Math.max(0, Math.min(sampleW - 1, x))) * 3 + c];
32231
+ if (horizontal && ext) {
32232
+ const next = new Int32Array(sampleW * 3);
32233
+ for (let x = 0; x < sampleW; x++) {
32234
+ for (let c = 0; c < 3; c++) {
32235
+ const v = ext[x * 3 + c];
32236
+ const sum = at(x - 1, sampleH, c) + at(x + 1, sampleH, c);
32237
+ next[x * 3 + c] = Math.max(0, Math.min(255, Math.floor(v + (2 * v - sum) / 4)));
32238
+ }
32239
+ }
32240
+ extension = next;
32241
+ }
32107
32242
  for (let y = 0; y < sampleH; y++) {
32108
32243
  for (let x = 0; x < sampleW; x++) {
32109
32244
  for (let c = 0; c < 3; c++) {