emf-converter 4.4.2 → 4.4.3

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.js CHANGED
@@ -10985,7 +10985,7 @@ function flattenBezierPath(pts) {
10985
10985
  }
10986
10986
  return out;
10987
10987
  }
10988
- function roundRectCorners(l, t, r, b, cw, ch) {
10988
+ function roundRectCorners(l, t, r, b, cw, ch, compatible = false) {
10989
10989
  const w = r - l;
10990
10990
  const h = b - t;
10991
10991
  let ew = Math.min(Math.abs(cw), w);
@@ -10997,7 +10997,9 @@ function roundRectCorners(l, t, r, b, cw, ch) {
10997
10997
  const hy = Math.floor(h / 2) - Math.floor((h - eh) / 2);
10998
10998
  const topX = Math.floor(r - ew / 2);
10999
10999
  const hx = r - topX;
11000
- const q = [r, t + hy, r, t + hy - Math.floor(KAPPA * hy), r - hx + Math.ceil(KAPPA * hx), t, topX, t];
11000
+ const verticalControl = compatible ? Math.round(KAPPA * hy) : Math.floor(KAPPA * hy);
11001
+ const horizontalControl = Math.ceil(KAPPA * hx);
11002
+ const q = [r, t + hy, r, t + hy - verticalControl, r - hx + horizontalControl, t, topX, t];
11001
11003
  const mx = (x) => l + r - x;
11002
11004
  const my = (y) => t + b - y;
11003
11005
  return [
@@ -28497,9 +28499,9 @@ function boxFrame(box) {
28497
28499
  const h = Math.round(Math.hypot(box.eyx, box.eyy));
28498
28500
  return { l: 0, t: 0, r: w, b: h };
28499
28501
  }
28500
- function roundRectDeviceBeziers(box, cw, ch, clockwise = false) {
28502
+ function roundRectDeviceBeziers(box, cw, ch, clockwise = false, compatible = false) {
28501
28503
  const f = boxFrame(box);
28502
- const q = roundRectCorners(f.l, f.t, f.r, f.b, cw, ch);
28504
+ const q = roundRectCorners(f.l, f.t, f.r, f.b, cw, ch, compatible);
28503
28505
  const map = frameMapper(box, f.l, f.t, f.r - f.l, f.b - f.t);
28504
28506
  const pts = [];
28505
28507
  for (let i = 0; i < q.length; i += 2) {
@@ -28507,9 +28509,9 @@ function roundRectDeviceBeziers(box, cw, ch, clockwise = false) {
28507
28509
  }
28508
28510
  return pts;
28509
28511
  }
28510
- function roundRectRasterPath(box, cw, ch, clockwise = false, rectangle = false) {
28512
+ function roundRectRasterPath(box, cw, ch, clockwise = false, rectangle = false, compatible = false) {
28511
28513
  if (rectangle) return rectRasterPath(box, clockwise);
28512
- const pts = roundRectDeviceBeziers(box, cw, ch, clockwise);
28514
+ const pts = roundRectDeviceBeziers(box, cw, ch, clockwise, compatible);
28513
28515
  const path = new GdiRasterPath();
28514
28516
  for (let c = 0; c < 4; c++) {
28515
28517
  const o = c * 8;
@@ -30087,6 +30089,9 @@ function handleEmfGdiShapeRecord(rCtx, recType, dataOff, recSize) {
30087
30089
  var CA_NEGATIVE = 1;
30088
30090
  var CA_LOG_FILTER = 2;
30089
30091
  var COLOR_ADJUSTMENT_SIZE = 24;
30092
+ function isChannelOnlyColorAdjustment(ca) {
30093
+ return !!ca && (ca.flags & ~CA_LOG_FILTER) === 0 && (ca.illuminant === 0 || ca.illuminant === 6) && ca.referenceBlack === 0 && ca.referenceWhite === 1e4 && ca.contrast === 0 && ca.brightness === 0 && ca.colorfulness === 0 && ca.redGreenTint === 0;
30094
+ }
30090
30095
  function readColorAdjustment(view, off) {
30091
30096
  const ca = {
30092
30097
  flags: view.getUint16(off + 2, true),
@@ -30142,6 +30147,19 @@ function fromLightness(l) {
30142
30147
  }
30143
30148
  var clamp012 = (v) => v < 0 ? 0 : v > 1 ? 1 : v;
30144
30149
  function colorAdjustmentMapper(ca) {
30150
+ if (ca.referenceBlack === 0 && ca.referenceWhite === 1e4 && ca.contrast === 0 && ca.brightness === 0 && ca.colorfulness === 0 && ca.redGreenTint === 0) {
30151
+ const tables = [ca.redGamma, ca.greenGamma, ca.blueGamma].map((gamma) => {
30152
+ const table = new Uint8Array(256);
30153
+ for (let i = 0; i < 256; i++) {
30154
+ const input = (ca.flags & CA_NEGATIVE) !== 0 ? 255 - i : i;
30155
+ let value = (input / 255) ** (gamma / 1e4);
30156
+ if ((ca.flags & CA_LOG_FILTER) !== 0) value = Math.log2(1 + 7 * value) / 3;
30157
+ table[i] = Math.round(value * 255);
30158
+ }
30159
+ return table;
30160
+ });
30161
+ return (rgb2) => tables[0][rgb2 >> 16 & 255] << 16 | tables[1][rgb2 >> 8 & 255] << 8 | tables[2][rgb2 & 255];
30162
+ }
30145
30163
  const black = ca.referenceBlack / 1e4;
30146
30164
  const span = Math.max(1e-6, ca.referenceWhite / 1e4 - black);
30147
30165
  const gammas = [ca.redGamma / 1e4, ca.greenGamma / 1e4, ca.blueGamma / 1e4];
@@ -30165,7 +30183,7 @@ function colorAdjustmentMapper(ca) {
30165
30183
  const out = (v, c) => {
30166
30184
  v = clamp012(fromLightness(slope * lightness(clamp012(v)) + offset)) ** (1 / gammas[c]);
30167
30185
  if (log) {
30168
- v = Math.log10(1 + 9 * v);
30186
+ v = Math.log2(1 + 7 * v) / 3;
30169
30187
  }
30170
30188
  return Math.round(v * 255);
30171
30189
  };
@@ -30389,7 +30407,7 @@ function halftoneSharpen(px, w, h) {
30389
30407
  }
30390
30408
  }
30391
30409
  }
30392
- function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust) {
30410
+ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSampling = false, directDib = false) {
30393
30411
  const W = Math.max(0, Math.round(Math.abs(dw)));
30394
30412
  const H = Math.max(0, Math.round(Math.abs(dh)));
30395
30413
  const SW = Math.round(Math.abs(sw));
@@ -30420,10 +30438,10 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust) {
30420
30438
  const enlarging = W >= SW && H >= SH && (W > SW || H > SH);
30421
30439
  const reducing = W < SW && H < SH;
30422
30440
  const mixed = W > SW && H < SH || W < SW && H > SH;
30423
- if (enlarging) {
30441
+ if (enlarging && !directDib) {
30424
30442
  halftoneDespeckle(rect, SW, SH);
30425
30443
  }
30426
- if (adjust) {
30444
+ if (adjust && !adjustAfterSampling) {
30427
30445
  adjust(rect);
30428
30446
  }
30429
30447
  const cols = halftoneAxis(0, SW, W, flipX);
@@ -30482,6 +30500,7 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust) {
30482
30500
  }
30483
30501
  }
30484
30502
  }
30503
+ if (adjust && adjustAfterSampling) adjust(out);
30485
30504
  for (let i = 0, o = 0; i < W * H; i++, o += 3) {
30486
30505
  data[i * 4] = out[o];
30487
30506
  data[i * 4 + 1] = out[o + 1];
@@ -30513,7 +30532,18 @@ function patternOperand(rCtx, brush) {
30513
30532
  function drawSourceMapped(target, decoded, req, offsetX, offsetY, mode) {
30514
30533
  const dLeft = Math.min(req.dx, req.dx + req.dw) - offsetX;
30515
30534
  const dTop = Math.min(req.dy, req.dy + req.dh) - offsetY;
30516
- const px = mode === HALFTONE ? stretchHalftone(decoded.pixels, req.sx, req.sy, req.sw, req.sh, req.dw, req.dh, decoded.adjust) : stretchGdi(decoded.pixels, req.sx, req.sy, req.sw, req.sh, req.dw, req.dh, mode);
30535
+ const px = mode === HALFTONE ? stretchHalftone(
30536
+ decoded.pixels,
30537
+ req.sx,
30538
+ req.sy,
30539
+ req.sw,
30540
+ req.sh,
30541
+ req.dw,
30542
+ req.dh,
30543
+ decoded.adjust,
30544
+ decoded.adjustAfterSampling,
30545
+ req.dibOrigin === "bottom-left"
30546
+ ) : stretchGdi(decoded.pixels, req.sx, req.sy, req.sw, req.sh, req.dw, req.dh, mode);
30517
30547
  if (px.width === 0 || px.height === 0) {
30518
30548
  return;
30519
30549
  }
@@ -30548,7 +30578,7 @@ function decodeSource(rCtx, req) {
30548
30578
  sy = image.height - sy - req.sh;
30549
30579
  }
30550
30580
  return {
30551
- decoded: { pixels: image, adjust },
30581
+ decoded: { pixels: image, adjust, adjustAfterSampling: isChannelOnlyColorAdjustment(ca) },
30552
30582
  req: { ...req, sy }
30553
30583
  };
30554
30584
  }
@@ -37572,7 +37602,7 @@ function wmfRoundRect(p, l, t, r, b, w, h) {
37572
37602
  c.ellipse(cr.x + ex, cr.y + ey, ex, ey, 0, 2 * q, 3 * q);
37573
37603
  c.closePath();
37574
37604
  },
37575
- raster: () => roundRectRasterPath(fixBoxOf(box), cw, ch, clockwiseOf(p), w === 0 || h === 0),
37605
+ raster: () => roundRectRasterPath(fixBoxOf(box), cw, ch, clockwiseOf(p), w === 0 || h === 0, true),
37576
37606
  roundPen: true,
37577
37607
  fill: true,
37578
37608
  stroke: true
package/dist/browser.mjs CHANGED
@@ -10983,7 +10983,7 @@ function flattenBezierPath(pts) {
10983
10983
  }
10984
10984
  return out;
10985
10985
  }
10986
- function roundRectCorners(l, t, r, b, cw, ch) {
10986
+ function roundRectCorners(l, t, r, b, cw, ch, compatible = false) {
10987
10987
  const w = r - l;
10988
10988
  const h = b - t;
10989
10989
  let ew = Math.min(Math.abs(cw), w);
@@ -10995,7 +10995,9 @@ function roundRectCorners(l, t, r, b, cw, ch) {
10995
10995
  const hy = Math.floor(h / 2) - Math.floor((h - eh) / 2);
10996
10996
  const topX = Math.floor(r - ew / 2);
10997
10997
  const hx = r - topX;
10998
- const q = [r, t + hy, r, t + hy - Math.floor(KAPPA * hy), r - hx + Math.ceil(KAPPA * hx), t, topX, t];
10998
+ const verticalControl = compatible ? Math.round(KAPPA * hy) : Math.floor(KAPPA * hy);
10999
+ const horizontalControl = Math.ceil(KAPPA * hx);
11000
+ const q = [r, t + hy, r, t + hy - verticalControl, r - hx + horizontalControl, t, topX, t];
10999
11001
  const mx = (x) => l + r - x;
11000
11002
  const my = (y) => t + b - y;
11001
11003
  return [
@@ -28495,9 +28497,9 @@ function boxFrame(box) {
28495
28497
  const h = Math.round(Math.hypot(box.eyx, box.eyy));
28496
28498
  return { l: 0, t: 0, r: w, b: h };
28497
28499
  }
28498
- function roundRectDeviceBeziers(box, cw, ch, clockwise = false) {
28500
+ function roundRectDeviceBeziers(box, cw, ch, clockwise = false, compatible = false) {
28499
28501
  const f = boxFrame(box);
28500
- const q = roundRectCorners(f.l, f.t, f.r, f.b, cw, ch);
28502
+ const q = roundRectCorners(f.l, f.t, f.r, f.b, cw, ch, compatible);
28501
28503
  const map = frameMapper(box, f.l, f.t, f.r - f.l, f.b - f.t);
28502
28504
  const pts = [];
28503
28505
  for (let i = 0; i < q.length; i += 2) {
@@ -28505,9 +28507,9 @@ function roundRectDeviceBeziers(box, cw, ch, clockwise = false) {
28505
28507
  }
28506
28508
  return pts;
28507
28509
  }
28508
- function roundRectRasterPath(box, cw, ch, clockwise = false, rectangle = false) {
28510
+ function roundRectRasterPath(box, cw, ch, clockwise = false, rectangle = false, compatible = false) {
28509
28511
  if (rectangle) return rectRasterPath(box, clockwise);
28510
- const pts = roundRectDeviceBeziers(box, cw, ch, clockwise);
28512
+ const pts = roundRectDeviceBeziers(box, cw, ch, clockwise, compatible);
28511
28513
  const path = new GdiRasterPath();
28512
28514
  for (let c = 0; c < 4; c++) {
28513
28515
  const o = c * 8;
@@ -30085,6 +30087,9 @@ function handleEmfGdiShapeRecord(rCtx, recType, dataOff, recSize) {
30085
30087
  var CA_NEGATIVE = 1;
30086
30088
  var CA_LOG_FILTER = 2;
30087
30089
  var COLOR_ADJUSTMENT_SIZE = 24;
30090
+ function isChannelOnlyColorAdjustment(ca) {
30091
+ return !!ca && (ca.flags & ~CA_LOG_FILTER) === 0 && (ca.illuminant === 0 || ca.illuminant === 6) && ca.referenceBlack === 0 && ca.referenceWhite === 1e4 && ca.contrast === 0 && ca.brightness === 0 && ca.colorfulness === 0 && ca.redGreenTint === 0;
30092
+ }
30088
30093
  function readColorAdjustment(view, off) {
30089
30094
  const ca = {
30090
30095
  flags: view.getUint16(off + 2, true),
@@ -30140,6 +30145,19 @@ function fromLightness(l) {
30140
30145
  }
30141
30146
  var clamp012 = (v) => v < 0 ? 0 : v > 1 ? 1 : v;
30142
30147
  function colorAdjustmentMapper(ca) {
30148
+ if (ca.referenceBlack === 0 && ca.referenceWhite === 1e4 && ca.contrast === 0 && ca.brightness === 0 && ca.colorfulness === 0 && ca.redGreenTint === 0) {
30149
+ const tables = [ca.redGamma, ca.greenGamma, ca.blueGamma].map((gamma) => {
30150
+ const table = new Uint8Array(256);
30151
+ for (let i = 0; i < 256; i++) {
30152
+ const input = (ca.flags & CA_NEGATIVE) !== 0 ? 255 - i : i;
30153
+ let value = (input / 255) ** (gamma / 1e4);
30154
+ if ((ca.flags & CA_LOG_FILTER) !== 0) value = Math.log2(1 + 7 * value) / 3;
30155
+ table[i] = Math.round(value * 255);
30156
+ }
30157
+ return table;
30158
+ });
30159
+ return (rgb2) => tables[0][rgb2 >> 16 & 255] << 16 | tables[1][rgb2 >> 8 & 255] << 8 | tables[2][rgb2 & 255];
30160
+ }
30143
30161
  const black = ca.referenceBlack / 1e4;
30144
30162
  const span = Math.max(1e-6, ca.referenceWhite / 1e4 - black);
30145
30163
  const gammas = [ca.redGamma / 1e4, ca.greenGamma / 1e4, ca.blueGamma / 1e4];
@@ -30163,7 +30181,7 @@ function colorAdjustmentMapper(ca) {
30163
30181
  const out = (v, c) => {
30164
30182
  v = clamp012(fromLightness(slope * lightness(clamp012(v)) + offset)) ** (1 / gammas[c]);
30165
30183
  if (log) {
30166
- v = Math.log10(1 + 9 * v);
30184
+ v = Math.log2(1 + 7 * v) / 3;
30167
30185
  }
30168
30186
  return Math.round(v * 255);
30169
30187
  };
@@ -30387,7 +30405,7 @@ function halftoneSharpen(px, w, h) {
30387
30405
  }
30388
30406
  }
30389
30407
  }
30390
- function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust) {
30408
+ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSampling = false, directDib = false) {
30391
30409
  const W = Math.max(0, Math.round(Math.abs(dw)));
30392
30410
  const H = Math.max(0, Math.round(Math.abs(dh)));
30393
30411
  const SW = Math.round(Math.abs(sw));
@@ -30418,10 +30436,10 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust) {
30418
30436
  const enlarging = W >= SW && H >= SH && (W > SW || H > SH);
30419
30437
  const reducing = W < SW && H < SH;
30420
30438
  const mixed = W > SW && H < SH || W < SW && H > SH;
30421
- if (enlarging) {
30439
+ if (enlarging && !directDib) {
30422
30440
  halftoneDespeckle(rect, SW, SH);
30423
30441
  }
30424
- if (adjust) {
30442
+ if (adjust && !adjustAfterSampling) {
30425
30443
  adjust(rect);
30426
30444
  }
30427
30445
  const cols = halftoneAxis(0, SW, W, flipX);
@@ -30480,6 +30498,7 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust) {
30480
30498
  }
30481
30499
  }
30482
30500
  }
30501
+ if (adjust && adjustAfterSampling) adjust(out);
30483
30502
  for (let i = 0, o = 0; i < W * H; i++, o += 3) {
30484
30503
  data[i * 4] = out[o];
30485
30504
  data[i * 4 + 1] = out[o + 1];
@@ -30511,7 +30530,18 @@ function patternOperand(rCtx, brush) {
30511
30530
  function drawSourceMapped(target, decoded, req, offsetX, offsetY, mode) {
30512
30531
  const dLeft = Math.min(req.dx, req.dx + req.dw) - offsetX;
30513
30532
  const dTop = Math.min(req.dy, req.dy + req.dh) - offsetY;
30514
- const px = mode === HALFTONE ? stretchHalftone(decoded.pixels, req.sx, req.sy, req.sw, req.sh, req.dw, req.dh, decoded.adjust) : stretchGdi(decoded.pixels, req.sx, req.sy, req.sw, req.sh, req.dw, req.dh, mode);
30533
+ const px = mode === HALFTONE ? stretchHalftone(
30534
+ decoded.pixels,
30535
+ req.sx,
30536
+ req.sy,
30537
+ req.sw,
30538
+ req.sh,
30539
+ req.dw,
30540
+ req.dh,
30541
+ decoded.adjust,
30542
+ decoded.adjustAfterSampling,
30543
+ req.dibOrigin === "bottom-left"
30544
+ ) : stretchGdi(decoded.pixels, req.sx, req.sy, req.sw, req.sh, req.dw, req.dh, mode);
30515
30545
  if (px.width === 0 || px.height === 0) {
30516
30546
  return;
30517
30547
  }
@@ -30546,7 +30576,7 @@ function decodeSource(rCtx, req) {
30546
30576
  sy = image.height - sy - req.sh;
30547
30577
  }
30548
30578
  return {
30549
- decoded: { pixels: image, adjust },
30579
+ decoded: { pixels: image, adjust, adjustAfterSampling: isChannelOnlyColorAdjustment(ca) },
30550
30580
  req: { ...req, sy }
30551
30581
  };
30552
30582
  }
@@ -37570,7 +37600,7 @@ function wmfRoundRect(p, l, t, r, b, w, h) {
37570
37600
  c.ellipse(cr.x + ex, cr.y + ey, ex, ey, 0, 2 * q, 3 * q);
37571
37601
  c.closePath();
37572
37602
  },
37573
- raster: () => roundRectRasterPath(fixBoxOf(box), cw, ch, clockwiseOf(p), w === 0 || h === 0),
37603
+ raster: () => roundRectRasterPath(fixBoxOf(box), cw, ch, clockwiseOf(p), w === 0 || h === 0, true),
37574
37604
  roundPen: true,
37575
37605
  fill: true,
37576
37606
  stroke: true
package/dist/index.js CHANGED
@@ -10986,7 +10986,7 @@ function flattenBezierPath(pts) {
10986
10986
  }
10987
10987
  return out;
10988
10988
  }
10989
- function roundRectCorners(l, t, r, b, cw, ch) {
10989
+ function roundRectCorners(l, t, r, b, cw, ch, compatible = false) {
10990
10990
  const w = r - l;
10991
10991
  const h = b - t;
10992
10992
  let ew = Math.min(Math.abs(cw), w);
@@ -10998,7 +10998,9 @@ function roundRectCorners(l, t, r, b, cw, ch) {
10998
10998
  const hy = Math.floor(h / 2) - Math.floor((h - eh) / 2);
10999
10999
  const topX = Math.floor(r - ew / 2);
11000
11000
  const hx = r - topX;
11001
- const q = [r, t + hy, r, t + hy - Math.floor(KAPPA * hy), r - hx + Math.ceil(KAPPA * hx), t, topX, t];
11001
+ const verticalControl = compatible ? Math.round(KAPPA * hy) : Math.floor(KAPPA * hy);
11002
+ const horizontalControl = Math.ceil(KAPPA * hx);
11003
+ const q = [r, t + hy, r, t + hy - verticalControl, r - hx + horizontalControl, t, topX, t];
11002
11004
  const mx = (x) => l + r - x;
11003
11005
  const my = (y) => t + b - y;
11004
11006
  return [
@@ -28498,9 +28500,9 @@ function boxFrame(box) {
28498
28500
  const h = Math.round(Math.hypot(box.eyx, box.eyy));
28499
28501
  return { l: 0, t: 0, r: w, b: h };
28500
28502
  }
28501
- function roundRectDeviceBeziers(box, cw, ch, clockwise = false) {
28503
+ function roundRectDeviceBeziers(box, cw, ch, clockwise = false, compatible = false) {
28502
28504
  const f = boxFrame(box);
28503
- const q = roundRectCorners(f.l, f.t, f.r, f.b, cw, ch);
28505
+ const q = roundRectCorners(f.l, f.t, f.r, f.b, cw, ch, compatible);
28504
28506
  const map = frameMapper(box, f.l, f.t, f.r - f.l, f.b - f.t);
28505
28507
  const pts = [];
28506
28508
  for (let i = 0; i < q.length; i += 2) {
@@ -28508,9 +28510,9 @@ function roundRectDeviceBeziers(box, cw, ch, clockwise = false) {
28508
28510
  }
28509
28511
  return pts;
28510
28512
  }
28511
- function roundRectRasterPath(box, cw, ch, clockwise = false, rectangle = false) {
28513
+ function roundRectRasterPath(box, cw, ch, clockwise = false, rectangle = false, compatible = false) {
28512
28514
  if (rectangle) return rectRasterPath(box, clockwise);
28513
- const pts = roundRectDeviceBeziers(box, cw, ch, clockwise);
28515
+ const pts = roundRectDeviceBeziers(box, cw, ch, clockwise, compatible);
28514
28516
  const path = new GdiRasterPath();
28515
28517
  for (let c = 0; c < 4; c++) {
28516
28518
  const o = c * 8;
@@ -30088,6 +30090,9 @@ function handleEmfGdiShapeRecord(rCtx, recType, dataOff, recSize) {
30088
30090
  var CA_NEGATIVE = 1;
30089
30091
  var CA_LOG_FILTER = 2;
30090
30092
  var COLOR_ADJUSTMENT_SIZE = 24;
30093
+ function isChannelOnlyColorAdjustment(ca) {
30094
+ return !!ca && (ca.flags & ~CA_LOG_FILTER) === 0 && (ca.illuminant === 0 || ca.illuminant === 6) && ca.referenceBlack === 0 && ca.referenceWhite === 1e4 && ca.contrast === 0 && ca.brightness === 0 && ca.colorfulness === 0 && ca.redGreenTint === 0;
30095
+ }
30091
30096
  function readColorAdjustment(view, off) {
30092
30097
  const ca = {
30093
30098
  flags: view.getUint16(off + 2, true),
@@ -30143,6 +30148,19 @@ function fromLightness(l) {
30143
30148
  }
30144
30149
  var clamp012 = (v) => v < 0 ? 0 : v > 1 ? 1 : v;
30145
30150
  function colorAdjustmentMapper(ca) {
30151
+ if (ca.referenceBlack === 0 && ca.referenceWhite === 1e4 && ca.contrast === 0 && ca.brightness === 0 && ca.colorfulness === 0 && ca.redGreenTint === 0) {
30152
+ const tables = [ca.redGamma, ca.greenGamma, ca.blueGamma].map((gamma) => {
30153
+ const table = new Uint8Array(256);
30154
+ for (let i = 0; i < 256; i++) {
30155
+ const input = (ca.flags & CA_NEGATIVE) !== 0 ? 255 - i : i;
30156
+ let value = (input / 255) ** (gamma / 1e4);
30157
+ if ((ca.flags & CA_LOG_FILTER) !== 0) value = Math.log2(1 + 7 * value) / 3;
30158
+ table[i] = Math.round(value * 255);
30159
+ }
30160
+ return table;
30161
+ });
30162
+ return (rgb2) => tables[0][rgb2 >> 16 & 255] << 16 | tables[1][rgb2 >> 8 & 255] << 8 | tables[2][rgb2 & 255];
30163
+ }
30146
30164
  const black = ca.referenceBlack / 1e4;
30147
30165
  const span = Math.max(1e-6, ca.referenceWhite / 1e4 - black);
30148
30166
  const gammas = [ca.redGamma / 1e4, ca.greenGamma / 1e4, ca.blueGamma / 1e4];
@@ -30166,7 +30184,7 @@ function colorAdjustmentMapper(ca) {
30166
30184
  const out = (v, c) => {
30167
30185
  v = clamp012(fromLightness(slope * lightness(clamp012(v)) + offset)) ** (1 / gammas[c]);
30168
30186
  if (log) {
30169
- v = Math.log10(1 + 9 * v);
30187
+ v = Math.log2(1 + 7 * v) / 3;
30170
30188
  }
30171
30189
  return Math.round(v * 255);
30172
30190
  };
@@ -30390,7 +30408,7 @@ function halftoneSharpen(px, w, h) {
30390
30408
  }
30391
30409
  }
30392
30410
  }
30393
- function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust) {
30411
+ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSampling = false, directDib = false) {
30394
30412
  const W = Math.max(0, Math.round(Math.abs(dw)));
30395
30413
  const H = Math.max(0, Math.round(Math.abs(dh)));
30396
30414
  const SW = Math.round(Math.abs(sw));
@@ -30421,10 +30439,10 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust) {
30421
30439
  const enlarging = W >= SW && H >= SH && (W > SW || H > SH);
30422
30440
  const reducing = W < SW && H < SH;
30423
30441
  const mixed = W > SW && H < SH || W < SW && H > SH;
30424
- if (enlarging) {
30442
+ if (enlarging && !directDib) {
30425
30443
  halftoneDespeckle(rect, SW, SH);
30426
30444
  }
30427
- if (adjust) {
30445
+ if (adjust && !adjustAfterSampling) {
30428
30446
  adjust(rect);
30429
30447
  }
30430
30448
  const cols = halftoneAxis(0, SW, W, flipX);
@@ -30483,6 +30501,7 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust) {
30483
30501
  }
30484
30502
  }
30485
30503
  }
30504
+ if (adjust && adjustAfterSampling) adjust(out);
30486
30505
  for (let i = 0, o = 0; i < W * H; i++, o += 3) {
30487
30506
  data[i * 4] = out[o];
30488
30507
  data[i * 4 + 1] = out[o + 1];
@@ -30514,7 +30533,18 @@ function patternOperand(rCtx, brush) {
30514
30533
  function drawSourceMapped(target, decoded, req, offsetX, offsetY, mode) {
30515
30534
  const dLeft = Math.min(req.dx, req.dx + req.dw) - offsetX;
30516
30535
  const dTop = Math.min(req.dy, req.dy + req.dh) - offsetY;
30517
- const px = mode === HALFTONE ? stretchHalftone(decoded.pixels, req.sx, req.sy, req.sw, req.sh, req.dw, req.dh, decoded.adjust) : stretchGdi(decoded.pixels, req.sx, req.sy, req.sw, req.sh, req.dw, req.dh, mode);
30536
+ const px = mode === HALFTONE ? stretchHalftone(
30537
+ decoded.pixels,
30538
+ req.sx,
30539
+ req.sy,
30540
+ req.sw,
30541
+ req.sh,
30542
+ req.dw,
30543
+ req.dh,
30544
+ decoded.adjust,
30545
+ decoded.adjustAfterSampling,
30546
+ req.dibOrigin === "bottom-left"
30547
+ ) : stretchGdi(decoded.pixels, req.sx, req.sy, req.sw, req.sh, req.dw, req.dh, mode);
30518
30548
  if (px.width === 0 || px.height === 0) {
30519
30549
  return;
30520
30550
  }
@@ -30549,7 +30579,7 @@ function decodeSource(rCtx, req) {
30549
30579
  sy = image.height - sy - req.sh;
30550
30580
  }
30551
30581
  return {
30552
- decoded: { pixels: image, adjust },
30582
+ decoded: { pixels: image, adjust, adjustAfterSampling: isChannelOnlyColorAdjustment(ca) },
30553
30583
  req: { ...req, sy }
30554
30584
  };
30555
30585
  }
@@ -37573,7 +37603,7 @@ function wmfRoundRect(p, l, t, r, b, w, h) {
37573
37603
  c.ellipse(cr.x + ex, cr.y + ey, ex, ey, 0, 2 * q, 3 * q);
37574
37604
  c.closePath();
37575
37605
  },
37576
- raster: () => roundRectRasterPath(fixBoxOf(box), cw, ch, clockwiseOf(p), w === 0 || h === 0),
37606
+ raster: () => roundRectRasterPath(fixBoxOf(box), cw, ch, clockwiseOf(p), w === 0 || h === 0, true),
37577
37607
  roundPen: true,
37578
37608
  fill: true,
37579
37609
  stroke: true
package/dist/index.mjs CHANGED
@@ -10984,7 +10984,7 @@ function flattenBezierPath(pts) {
10984
10984
  }
10985
10985
  return out;
10986
10986
  }
10987
- function roundRectCorners(l, t, r, b, cw, ch) {
10987
+ function roundRectCorners(l, t, r, b, cw, ch, compatible = false) {
10988
10988
  const w = r - l;
10989
10989
  const h = b - t;
10990
10990
  let ew = Math.min(Math.abs(cw), w);
@@ -10996,7 +10996,9 @@ function roundRectCorners(l, t, r, b, cw, ch) {
10996
10996
  const hy = Math.floor(h / 2) - Math.floor((h - eh) / 2);
10997
10997
  const topX = Math.floor(r - ew / 2);
10998
10998
  const hx = r - topX;
10999
- const q = [r, t + hy, r, t + hy - Math.floor(KAPPA * hy), r - hx + Math.ceil(KAPPA * hx), t, topX, t];
10999
+ const verticalControl = compatible ? Math.round(KAPPA * hy) : Math.floor(KAPPA * hy);
11000
+ const horizontalControl = Math.ceil(KAPPA * hx);
11001
+ const q = [r, t + hy, r, t + hy - verticalControl, r - hx + horizontalControl, t, topX, t];
11000
11002
  const mx = (x) => l + r - x;
11001
11003
  const my = (y) => t + b - y;
11002
11004
  return [
@@ -28496,9 +28498,9 @@ function boxFrame(box) {
28496
28498
  const h = Math.round(Math.hypot(box.eyx, box.eyy));
28497
28499
  return { l: 0, t: 0, r: w, b: h };
28498
28500
  }
28499
- function roundRectDeviceBeziers(box, cw, ch, clockwise = false) {
28501
+ function roundRectDeviceBeziers(box, cw, ch, clockwise = false, compatible = false) {
28500
28502
  const f = boxFrame(box);
28501
- const q = roundRectCorners(f.l, f.t, f.r, f.b, cw, ch);
28503
+ const q = roundRectCorners(f.l, f.t, f.r, f.b, cw, ch, compatible);
28502
28504
  const map = frameMapper(box, f.l, f.t, f.r - f.l, f.b - f.t);
28503
28505
  const pts = [];
28504
28506
  for (let i = 0; i < q.length; i += 2) {
@@ -28506,9 +28508,9 @@ function roundRectDeviceBeziers(box, cw, ch, clockwise = false) {
28506
28508
  }
28507
28509
  return pts;
28508
28510
  }
28509
- function roundRectRasterPath(box, cw, ch, clockwise = false, rectangle = false) {
28511
+ function roundRectRasterPath(box, cw, ch, clockwise = false, rectangle = false, compatible = false) {
28510
28512
  if (rectangle) return rectRasterPath(box, clockwise);
28511
- const pts = roundRectDeviceBeziers(box, cw, ch, clockwise);
28513
+ const pts = roundRectDeviceBeziers(box, cw, ch, clockwise, compatible);
28512
28514
  const path = new GdiRasterPath();
28513
28515
  for (let c = 0; c < 4; c++) {
28514
28516
  const o = c * 8;
@@ -30086,6 +30088,9 @@ function handleEmfGdiShapeRecord(rCtx, recType, dataOff, recSize) {
30086
30088
  var CA_NEGATIVE = 1;
30087
30089
  var CA_LOG_FILTER = 2;
30088
30090
  var COLOR_ADJUSTMENT_SIZE = 24;
30091
+ function isChannelOnlyColorAdjustment(ca) {
30092
+ return !!ca && (ca.flags & ~CA_LOG_FILTER) === 0 && (ca.illuminant === 0 || ca.illuminant === 6) && ca.referenceBlack === 0 && ca.referenceWhite === 1e4 && ca.contrast === 0 && ca.brightness === 0 && ca.colorfulness === 0 && ca.redGreenTint === 0;
30093
+ }
30089
30094
  function readColorAdjustment(view, off) {
30090
30095
  const ca = {
30091
30096
  flags: view.getUint16(off + 2, true),
@@ -30141,6 +30146,19 @@ function fromLightness(l) {
30141
30146
  }
30142
30147
  var clamp012 = (v) => v < 0 ? 0 : v > 1 ? 1 : v;
30143
30148
  function colorAdjustmentMapper(ca) {
30149
+ if (ca.referenceBlack === 0 && ca.referenceWhite === 1e4 && ca.contrast === 0 && ca.brightness === 0 && ca.colorfulness === 0 && ca.redGreenTint === 0) {
30150
+ const tables = [ca.redGamma, ca.greenGamma, ca.blueGamma].map((gamma) => {
30151
+ const table = new Uint8Array(256);
30152
+ for (let i = 0; i < 256; i++) {
30153
+ const input = (ca.flags & CA_NEGATIVE) !== 0 ? 255 - i : i;
30154
+ let value = (input / 255) ** (gamma / 1e4);
30155
+ if ((ca.flags & CA_LOG_FILTER) !== 0) value = Math.log2(1 + 7 * value) / 3;
30156
+ table[i] = Math.round(value * 255);
30157
+ }
30158
+ return table;
30159
+ });
30160
+ return (rgb2) => tables[0][rgb2 >> 16 & 255] << 16 | tables[1][rgb2 >> 8 & 255] << 8 | tables[2][rgb2 & 255];
30161
+ }
30144
30162
  const black = ca.referenceBlack / 1e4;
30145
30163
  const span = Math.max(1e-6, ca.referenceWhite / 1e4 - black);
30146
30164
  const gammas = [ca.redGamma / 1e4, ca.greenGamma / 1e4, ca.blueGamma / 1e4];
@@ -30164,7 +30182,7 @@ function colorAdjustmentMapper(ca) {
30164
30182
  const out = (v, c) => {
30165
30183
  v = clamp012(fromLightness(slope * lightness(clamp012(v)) + offset)) ** (1 / gammas[c]);
30166
30184
  if (log) {
30167
- v = Math.log10(1 + 9 * v);
30185
+ v = Math.log2(1 + 7 * v) / 3;
30168
30186
  }
30169
30187
  return Math.round(v * 255);
30170
30188
  };
@@ -30388,7 +30406,7 @@ function halftoneSharpen(px, w, h) {
30388
30406
  }
30389
30407
  }
30390
30408
  }
30391
- function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust) {
30409
+ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust, adjustAfterSampling = false, directDib = false) {
30392
30410
  const W = Math.max(0, Math.round(Math.abs(dw)));
30393
30411
  const H = Math.max(0, Math.round(Math.abs(dh)));
30394
30412
  const SW = Math.round(Math.abs(sw));
@@ -30419,10 +30437,10 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust) {
30419
30437
  const enlarging = W >= SW && H >= SH && (W > SW || H > SH);
30420
30438
  const reducing = W < SW && H < SH;
30421
30439
  const mixed = W > SW && H < SH || W < SW && H > SH;
30422
- if (enlarging) {
30440
+ if (enlarging && !directDib) {
30423
30441
  halftoneDespeckle(rect, SW, SH);
30424
30442
  }
30425
- if (adjust) {
30443
+ if (adjust && !adjustAfterSampling) {
30426
30444
  adjust(rect);
30427
30445
  }
30428
30446
  const cols = halftoneAxis(0, SW, W, flipX);
@@ -30481,6 +30499,7 @@ function stretchHalftone(src, sx, sy, sw, sh, dw, dh, adjust) {
30481
30499
  }
30482
30500
  }
30483
30501
  }
30502
+ if (adjust && adjustAfterSampling) adjust(out);
30484
30503
  for (let i = 0, o = 0; i < W * H; i++, o += 3) {
30485
30504
  data[i * 4] = out[o];
30486
30505
  data[i * 4 + 1] = out[o + 1];
@@ -30512,7 +30531,18 @@ function patternOperand(rCtx, brush) {
30512
30531
  function drawSourceMapped(target, decoded, req, offsetX, offsetY, mode) {
30513
30532
  const dLeft = Math.min(req.dx, req.dx + req.dw) - offsetX;
30514
30533
  const dTop = Math.min(req.dy, req.dy + req.dh) - offsetY;
30515
- const px = mode === HALFTONE ? stretchHalftone(decoded.pixels, req.sx, req.sy, req.sw, req.sh, req.dw, req.dh, decoded.adjust) : stretchGdi(decoded.pixels, req.sx, req.sy, req.sw, req.sh, req.dw, req.dh, mode);
30534
+ const px = mode === HALFTONE ? stretchHalftone(
30535
+ decoded.pixels,
30536
+ req.sx,
30537
+ req.sy,
30538
+ req.sw,
30539
+ req.sh,
30540
+ req.dw,
30541
+ req.dh,
30542
+ decoded.adjust,
30543
+ decoded.adjustAfterSampling,
30544
+ req.dibOrigin === "bottom-left"
30545
+ ) : stretchGdi(decoded.pixels, req.sx, req.sy, req.sw, req.sh, req.dw, req.dh, mode);
30516
30546
  if (px.width === 0 || px.height === 0) {
30517
30547
  return;
30518
30548
  }
@@ -30547,7 +30577,7 @@ function decodeSource(rCtx, req) {
30547
30577
  sy = image.height - sy - req.sh;
30548
30578
  }
30549
30579
  return {
30550
- decoded: { pixels: image, adjust },
30580
+ decoded: { pixels: image, adjust, adjustAfterSampling: isChannelOnlyColorAdjustment(ca) },
30551
30581
  req: { ...req, sy }
30552
30582
  };
30553
30583
  }
@@ -37571,7 +37601,7 @@ function wmfRoundRect(p, l, t, r, b, w, h) {
37571
37601
  c.ellipse(cr.x + ex, cr.y + ey, ex, ey, 0, 2 * q, 3 * q);
37572
37602
  c.closePath();
37573
37603
  },
37574
- raster: () => roundRectRasterPath(fixBoxOf(box), cw, ch, clockwiseOf(p), w === 0 || h === 0),
37604
+ raster: () => roundRectRasterPath(fixBoxOf(box), cw, ch, clockwiseOf(p), w === 0 || h === 0, true),
37575
37605
  roundPen: true,
37576
37606
  fill: true,
37577
37607
  stroke: true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "emf-converter",
3
- "version": "4.4.2",
3
+ "version": "4.4.3",
4
4
  "description": "Convert EMF/WMF metafile binaries to PNG data URLs or SVG (markup, data URL, React/JSX)",
5
5
  "keywords": [
6
6
  "canvas",