emf-converter 4.8.8 → 4.8.9

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
@@ -35709,21 +35709,243 @@ function handleEmfObjectRecord(rCtx, recType, dataOff, recSize) {
35709
35709
  }
35710
35710
  }
35711
35711
 
35712
+ // src/wmf-mapping.ts
35713
+ var MM_TEXT = 1;
35714
+ var MM_LOMETRIC = 2;
35715
+ var MM_HIMETRIC = 3;
35716
+ var MM_LOENGLISH = 4;
35717
+ var MM_HIENGLISH = 5;
35718
+ var MM_TWIPS = 6;
35719
+ var MM_ISOTROPIC = 7;
35720
+ var MM_ANISOTROPIC = 8;
35721
+ var DEVICE_DPI = 96;
35722
+ function cloneMapping(m) {
35723
+ return {
35724
+ ...m.dpi ? { dpi: { ...m.dpi } } : {},
35725
+ mode: m.mode,
35726
+ winOrg: { ...m.winOrg },
35727
+ winExt: { ...m.winExt },
35728
+ vpOrg: { ...m.vpOrg },
35729
+ vpExt: { ...m.vpExt }
35730
+ };
35731
+ }
35732
+ var METRIC_UNITS_PER_INCH = {
35733
+ [MM_LOMETRIC]: 254,
35734
+ [MM_HIMETRIC]: 2540,
35735
+ [MM_LOENGLISH]: 100,
35736
+ [MM_HIENGLISH]: 1e3,
35737
+ [MM_TWIPS]: 1440
35738
+ };
35739
+ function fixIsotropic(m) {
35740
+ if (m.mode !== MM_ISOTROPIC || !m.winExt.cx || !m.winExt.cy) {
35741
+ return;
35742
+ }
35743
+ const xdim = Math.abs(m.vpExt.cx / m.winExt.cx) / (m.dpi?.x ?? DEVICE_DPI);
35744
+ const ydim = Math.abs(m.vpExt.cy / m.winExt.cy) / (m.dpi?.y ?? DEVICE_DPI);
35745
+ if (xdim > ydim) {
35746
+ const min = m.vpExt.cx >= 0 ? 1 : -1;
35747
+ m.vpExt.cx = Math.floor(m.vpExt.cx * ydim / xdim + 0.5) || min;
35748
+ } else if (ydim > xdim) {
35749
+ const min = m.vpExt.cy >= 0 ? 1 : -1;
35750
+ m.vpExt.cy = Math.floor(m.vpExt.cy * xdim / ydim + 0.5) || min;
35751
+ }
35752
+ }
35753
+ function setMapMode(m, mode) {
35754
+ if (mode < MM_TEXT || mode > MM_ANISOTROPIC) {
35755
+ return;
35756
+ }
35757
+ const units = METRIC_UNITS_PER_INCH[mode === MM_ISOTROPIC ? MM_LOMETRIC : mode];
35758
+ if (mode === MM_TEXT) {
35759
+ m.winExt = { cx: 1, cy: 1 };
35760
+ m.vpExt = { cx: 1, cy: 1 };
35761
+ } else if (units !== void 0 && (mode !== MM_ISOTROPIC || m.mode !== MM_ISOTROPIC)) {
35762
+ m.winExt = { cx: units, cy: units };
35763
+ m.vpExt = { cx: m.dpi?.x ?? DEVICE_DPI, cy: -(m.dpi?.y ?? DEVICE_DPI) };
35764
+ }
35765
+ m.mode = mode;
35766
+ }
35767
+ function extentsSettable(m) {
35768
+ return m.mode === MM_ISOTROPIC || m.mode === MM_ANISOTROPIC;
35769
+ }
35770
+ function setWindowExt(m, cx, cy) {
35771
+ if (!extentsSettable(m) || cx === 0 || cy === 0) {
35772
+ return;
35773
+ }
35774
+ m.winExt = { cx, cy };
35775
+ fixIsotropic(m);
35776
+ }
35777
+ function setViewportExt(m, cx, cy) {
35778
+ if (!extentsSettable(m) || cx === 0 || cy === 0) {
35779
+ return;
35780
+ }
35781
+ m.vpExt = { cx, cy };
35782
+ fixIsotropic(m);
35783
+ }
35784
+ function scaled(v, num, den) {
35785
+ return Math.trunc(v * num / den);
35786
+ }
35787
+ function scaleWindowExt(m, xNum, xDen, yNum, yDen) {
35788
+ if (!extentsSettable(m) || !xDen || !yDen) {
35789
+ return;
35790
+ }
35791
+ const cx = scaled(m.winExt.cx, xNum, xDen);
35792
+ const cy = scaled(m.winExt.cy, yNum, yDen);
35793
+ if (cx === 0 || cy === 0) {
35794
+ return;
35795
+ }
35796
+ m.winExt = { cx, cy };
35797
+ fixIsotropic(m);
35798
+ }
35799
+ function scaleViewportExt(m, xNum, xDen, yNum, yDen) {
35800
+ if (!extentsSettable(m) || !xDen || !yDen) {
35801
+ return;
35802
+ }
35803
+ const cx = scaled(m.vpExt.cx, xNum, xDen);
35804
+ const cy = scaled(m.vpExt.cy, yNum, yDen);
35805
+ if (cx === 0 || cy === 0) {
35806
+ return;
35807
+ }
35808
+ m.vpExt = { cx, cy };
35809
+ fixIsotropic(m);
35810
+ }
35811
+ function applyWmfMapping(rCtx, m, kx, ky, mirrorWidth = 0) {
35812
+ rCtx.wmfLayoutRtl = mirrorWidth > 0;
35813
+ rCtx.useMappingMode = true;
35814
+ rCtx.windowOrg = { x: m.winOrg.x, y: m.winOrg.y };
35815
+ rCtx.windowExt = { cx: m.winExt.cx || 1, cy: m.winExt.cy || 1 };
35816
+ rCtx.viewportOrg = { x: m.vpOrg.x * kx, y: m.vpOrg.y * ky };
35817
+ rCtx.viewportExt = { cx: (m.vpExt.cx || 1) * kx, cy: (m.vpExt.cy || 1) * ky };
35818
+ if (mirrorWidth > 0) {
35819
+ rCtx.viewportOrg.x = mirrorWidth * kx - rCtx.viewportOrg.x;
35820
+ rCtx.viewportExt.cx = -rCtx.viewportExt.cx;
35821
+ }
35822
+ }
35823
+ function scanMappingRecords(view, start) {
35824
+ const out = {
35825
+ mode: null,
35826
+ winExt: null,
35827
+ vpExt: null
35828
+ };
35829
+ let off = start;
35830
+ let guard = 0;
35831
+ while (off + 6 <= view.byteLength && guard++ < 1e6) {
35832
+ const size = view.getUint32(off, true) * 2;
35833
+ const type = view.getUint16(off + 4, true);
35834
+ if (size < 6 || off + size > view.byteLength || type === 0) {
35835
+ break;
35836
+ }
35837
+ const d = off + 6;
35838
+ if (type === 259 && size >= 8 && out.mode === null) {
35839
+ out.mode = view.getUint16(d, true);
35840
+ } else if (type === 524 && size >= 10 && !out.winExt) {
35841
+ out.winExt = { cy: view.getInt16(d, true), cx: view.getInt16(d + 2, true) };
35842
+ } else if (type === 526 && size >= 10 && !out.vpExt) {
35843
+ out.vpExt = { cy: view.getInt16(d, true), cx: view.getInt16(d + 2, true) };
35844
+ }
35845
+ off += size;
35846
+ }
35847
+ return out;
35848
+ }
35849
+ function wmfPlayback(view, header, referenceDpi) {
35850
+ const valid = (v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : DEVICE_DPI;
35851
+ const dpi = { x: valid(typeof referenceDpi === "number" ? referenceDpi : referenceDpi?.x), y: valid(typeof referenceDpi === "number" ? referenceDpi : referenceDpi?.y) };
35852
+ const density = referenceDpi === void 0 ? {} : { dpi };
35853
+ const bw = header.boundsRight - header.boundsLeft;
35854
+ const bh = header.boundsBottom - header.boundsTop;
35855
+ if (header.placeable !== false) {
35856
+ const inch = header.unitsPerInch > 0 ? header.unitsPerInch : DEVICE_DPI;
35857
+ const width2 = Math.max(1, Math.round(Math.abs(bw) * dpi.x / inch));
35858
+ const height2 = Math.max(1, Math.round(Math.abs(bh) * dpi.y / inch));
35859
+ return {
35860
+ width: width2,
35861
+ height: height2,
35862
+ mapping: {
35863
+ ...density,
35864
+ mode: MM_ANISOTROPIC,
35865
+ winOrg: { x: header.boundsLeft, y: header.boundsTop },
35866
+ winExt: { cx: bw || 1, cy: bh || 1 },
35867
+ vpOrg: { x: 0, y: 0 },
35868
+ vpExt: { cx: width2, cy: height2 }
35869
+ }
35870
+ };
35871
+ }
35872
+ const scan = scanMappingRecords(view, header.headerSize);
35873
+ const scalable = scan.mode === MM_ISOTROPIC || scan.mode === MM_ANISOTROPIC;
35874
+ const ext = scalable && scan.vpExt ? scan.vpExt : scan.winExt;
35875
+ const width = ext ? Math.abs(ext.cx) : Math.abs(bw);
35876
+ const height = ext ? Math.abs(ext.cy) : Math.abs(bh);
35877
+ const w = Math.max(1, width || 1);
35878
+ const h = Math.max(1, height || 1);
35879
+ return {
35880
+ width: w,
35881
+ height: h,
35882
+ mapping: {
35883
+ ...density,
35884
+ mode: MM_ANISOTROPIC,
35885
+ winOrg: { x: 0, y: 0 },
35886
+ winExt: { cx: w, cy: h },
35887
+ vpOrg: { x: 0, y: 0 },
35888
+ vpExt: { cx: w, cy: h }
35889
+ }
35890
+ };
35891
+ }
35892
+
35712
35893
  // src/emf-gdi-transform-handlers.ts
35713
- function extentsSettable(rCtx) {
35714
- return rCtx.mapMode === 7 || rCtx.mapMode === 8;
35894
+ function emfDeviceDpi(view) {
35895
+ if (view.byteLength < 88 || view.getUint32(0, true) !== 1) {
35896
+ return void 0;
35897
+ }
35898
+ const devW = view.getInt32(72, true);
35899
+ const devH = view.getInt32(76, true);
35900
+ const mmW = view.getInt32(80, true);
35901
+ const mmH = view.getInt32(84, true);
35902
+ if (devW <= 0 || devH <= 0 || mmW <= 0 || mmH <= 0) {
35903
+ return void 0;
35904
+ }
35905
+ return { x: devW * 25.4 / mmW, y: devH * 25.4 / mmH };
35906
+ }
35907
+ function emfMapping(r) {
35908
+ const dpi = emfDeviceDpi(r.view);
35909
+ return {
35910
+ ...dpi ? { dpi } : {},
35911
+ mode: r.mapMode ?? MM_TEXT,
35912
+ winOrg: r.windowOrg,
35913
+ winExt: { ...r.windowExt },
35914
+ vpOrg: r.viewportOrg,
35915
+ vpExt: { ...r.viewportExt }
35916
+ };
35917
+ }
35918
+ function storeMapping(r, m) {
35919
+ r.mapMode = m.mode;
35920
+ r.windowExt = m.winExt;
35921
+ r.viewportExt = m.vpExt;
35922
+ }
35923
+ function setExtent(r, viewport, cx, cy) {
35924
+ const m = emfMapping(r);
35925
+ if (!extentsSettable(m) || cx === 0 || cy === 0) {
35926
+ return;
35927
+ }
35928
+ if (viewport) {
35929
+ m.vpExt = { cx, cy };
35930
+ } else {
35931
+ m.winExt = { cx, cy };
35932
+ }
35933
+ fixIsotropic(m);
35934
+ storeMapping(r, m);
35935
+ activateGdiMappingMode(r);
35936
+ }
35937
+ function scaleExtent(r, viewport, xNum, xDenom, yNum, yDenom) {
35938
+ const ext = viewport ? r.viewportExt : r.windowExt;
35939
+ const cx = xDenom !== 0 ? Math.round(ext.cx * xNum / xDenom) : ext.cx;
35940
+ const cy = yDenom !== 0 ? Math.round(ext.cy * yNum / yDenom) : ext.cy;
35941
+ setExtent(r, viewport, cx, cy);
35715
35942
  }
35716
35943
  function handleCoordinateRecord(rCtx, recType, dataOff, recSize) {
35717
35944
  const { view } = rCtx;
35718
35945
  switch (recType) {
35719
35946
  case EMR_SETWINDOWEXTEX: {
35720
- if (recSize >= 16 && extentsSettable(rCtx)) {
35721
- const cx = view.getInt32(dataOff, true);
35722
- const cy = view.getInt32(dataOff + 4, true);
35723
- if (cx !== 0 && cy !== 0) {
35724
- rCtx.windowExt = { cx, cy };
35725
- activateGdiMappingMode(rCtx);
35726
- }
35947
+ if (recSize >= 16) {
35948
+ setExtent(rCtx, false, view.getInt32(dataOff, true), view.getInt32(dataOff + 4, true));
35727
35949
  }
35728
35950
  return true;
35729
35951
  }
@@ -35736,13 +35958,8 @@ function handleCoordinateRecord(rCtx, recType, dataOff, recSize) {
35736
35958
  return true;
35737
35959
  }
35738
35960
  case EMR_SETVIEWPORTEXTEX: {
35739
- if (recSize >= 16 && extentsSettable(rCtx)) {
35740
- const cx = view.getInt32(dataOff, true);
35741
- const cy = view.getInt32(dataOff + 4, true);
35742
- if (cx !== 0 && cy !== 0) {
35743
- rCtx.viewportExt = { cx, cy };
35744
- activateGdiMappingMode(rCtx);
35745
- }
35961
+ if (recSize >= 16) {
35962
+ setExtent(rCtx, true, view.getInt32(dataOff, true), view.getInt32(dataOff + 4, true));
35746
35963
  }
35747
35964
  return true;
35748
35965
  }
@@ -35757,48 +35974,26 @@ function handleCoordinateRecord(rCtx, recType, dataOff, recSize) {
35757
35974
  case EMR_SETMAPMODE: {
35758
35975
  if (recSize >= 12) {
35759
35976
  const mode = view.getUint32(dataOff, true);
35760
- if (mode >= 1 && mode <= 8) {
35761
- rCtx.mapMode = mode;
35762
- if (mode === 1) {
35763
- rCtx.windowExt = { cx: 1, cy: 1 };
35764
- rCtx.viewportExt = { cx: 1, cy: 1 };
35765
- }
35766
- if (mode === 1 || mode === 8 || mode === 7) {
35767
- activateGdiMappingMode(rCtx);
35768
- }
35769
- }
35770
- }
35771
- return true;
35772
- }
35773
- case EMR_SCALEVIEWPORTEXTEX: {
35774
- if (recSize >= 24 && extentsSettable(rCtx)) {
35775
- const xNum = view.getInt32(dataOff, true);
35776
- const xDenom = view.getInt32(dataOff + 4, true);
35777
- const yNum = view.getInt32(dataOff + 8, true);
35778
- const yDenom = view.getInt32(dataOff + 12, true);
35779
- if (xDenom !== 0) {
35780
- rCtx.viewportExt.cx = Math.round(rCtx.viewportExt.cx * xNum / xDenom);
35781
- }
35782
- if (yDenom !== 0) {
35783
- rCtx.viewportExt.cy = Math.round(rCtx.viewportExt.cy * yNum / yDenom);
35977
+ if (mode >= MM_TEXT && mode <= MM_ANISOTROPIC) {
35978
+ const m = emfMapping(rCtx);
35979
+ setMapMode(m, mode);
35980
+ storeMapping(rCtx, m);
35981
+ activateGdiMappingMode(rCtx);
35784
35982
  }
35785
- activateGdiMappingMode(rCtx);
35786
35983
  }
35787
35984
  return true;
35788
35985
  }
35986
+ case EMR_SCALEVIEWPORTEXTEX:
35789
35987
  case EMR_SCALEWINDOWEXTEX: {
35790
- if (recSize >= 24 && extentsSettable(rCtx)) {
35791
- const xNum = view.getInt32(dataOff, true);
35792
- const xDenom = view.getInt32(dataOff + 4, true);
35793
- const yNum = view.getInt32(dataOff + 8, true);
35794
- const yDenom = view.getInt32(dataOff + 12, true);
35795
- if (xDenom !== 0) {
35796
- rCtx.windowExt.cx = Math.round(rCtx.windowExt.cx * xNum / xDenom);
35797
- }
35798
- if (yDenom !== 0) {
35799
- rCtx.windowExt.cy = Math.round(rCtx.windowExt.cy * yNum / yDenom);
35800
- }
35801
- activateGdiMappingMode(rCtx);
35988
+ if (recSize >= 24) {
35989
+ scaleExtent(
35990
+ rCtx,
35991
+ recType === EMR_SCALEVIEWPORTEXTEX,
35992
+ view.getInt32(dataOff, true),
35993
+ view.getInt32(dataOff + 4, true),
35994
+ view.getInt32(dataOff + 8, true),
35995
+ view.getInt32(dataOff + 12, true)
35996
+ );
35802
35997
  }
35803
35998
  return true;
35804
35999
  }
@@ -36790,24 +36985,22 @@ function rgbaToHex(c) {
36790
36985
  }
36791
36986
  return /^#[0-9a-f]{6}$/i.test(c) ? c : null;
36792
36987
  }
36793
- function drawPlusStringWithEngine(rCtx, font, text, layoutX, layoutY, paint, alignment, format, brushSampler2 = null) {
36988
+ function realizePlusEngineFont(rCtx, font, paint, brushSampler2) {
36794
36989
  const fonts = rCtx.fonts;
36795
36990
  const color = typeof paint === "string" ? rgbaToHex(paint) : null;
36796
- const hintNow = rCtx.textRenderingHint ?? 0;
36797
- const graySmooth = hintNow === 3 || hintNow === 4 || hintNow === 5;
36991
+ const hint = rCtx.textRenderingHint ?? 0;
36992
+ const graySmooth = hint === 3 || hint === 4 || hint === 5;
36798
36993
  const solidViaCoverage = !!color && graySmooth && !isSvgContext(rCtx.ctx);
36799
36994
  const sampler = isSvgContext(rCtx.ctx) ? null : solidViaCoverage ? solidSampler(cssColorToArgb(paint) ?? 4278190080) : color ? null : brushSampler2;
36800
36995
  const unit = font.unit ?? 0;
36801
- if (!fonts || !color && !sampler || alignment !== 0 || unit !== 0 && unit !== 2) {
36802
- return false;
36996
+ if (!fonts || !color && !sampler || unit !== 0 && unit !== 2) {
36997
+ return null;
36803
36998
  }
36804
36999
  const m = plusWorldMatrix(rCtx);
36805
37000
  if (m[1] !== 0 || m[2] !== 0 || m[0] <= 0 || m[3] <= 0) {
36806
- return false;
37001
+ return null;
36807
37002
  }
36808
37003
  const emPx = font.emSize * m[3];
36809
- const hint = rCtx.textRenderingHint ?? 0;
36810
- const quality = HINT_QUALITY[hint] ?? NONANTIALIASED_QUALITY;
36811
37004
  const spec = {
36812
37005
  face: font.family,
36813
37006
  height: -Math.round(emPx),
@@ -36816,7 +37009,7 @@ function drawPlusStringWithEngine(rCtx, font, text, layoutX, layoutY, paint, ali
36816
37009
  italic: (font.flags & 2) !== 0,
36817
37010
  charSet: 1,
36818
37011
  pitchAndFamily: 0,
36819
- quality,
37012
+ quality: HINT_QUALITY[hint] ?? NONANTIALIASED_QUALITY,
36820
37013
  unhinted: hint === 2 || hint === 4,
36821
37014
  // AntiAlias ignores the font's gasp table (measured: Arial 16 px is
36822
37015
  // grayscale there, but single-bit under AntiAliasGridFit, as in GDI).
@@ -36824,31 +37017,32 @@ function drawPlusStringWithEngine(rCtx, font, text, layoutX, layoutY, paint, ali
36824
37017
  };
36825
37018
  const realized = fonts.realize(spec, rCtx.fontFamilyMap);
36826
37019
  if (!realized) {
36827
- return false;
36828
- }
36829
- const ttf = realized.ttf;
36830
- const unhinted = spec.unhinted === true;
36831
- const exactAscent = emPx * ttf.winAscent / ttf.unitsPerEm;
36832
- const ascent = unhinted ? exactAscent : Math.ceil(exactAscent);
36833
- const x = m[0] * layoutX + m[4] + emPx * (format?.leadingMargin ?? PLUS_LEADING_EM);
36834
- const y = m[3] * layoutY + m[5] + ascent;
36835
- const codes = [];
36836
- for (let i = 0; i < text.length; i++) {
36837
- codes.push(text.charCodeAt(i));
37020
+ return null;
36838
37021
  }
36839
- const tracking = format?.tracking ?? PLUS_DEFAULT_TRACKING;
36840
- const dx = unhinted ? codes.map((c) => realized.advance(realized.glyphIndex(c)) * tracking) : null;
36841
- if ((!color || solidViaCoverage) && sampler) {
36842
- const cov = gdiTextCoverage(realized, {
36843
- codes,
36844
- glyphIndices: false,
36845
- x,
36846
- y,
36847
- dx,
36848
- dy: null,
36849
- textAlign: 24,
36850
- options: 0,
36851
- matrix: null});
37022
+ return {
37023
+ realized,
37024
+ emPx,
37025
+ m,
37026
+ unhinted: spec.unhinted === true,
37027
+ color,
37028
+ sampler,
37029
+ solidViaCoverage,
37030
+ underline: (font.flags & 4) !== 0,
37031
+ strikeOut: (font.flags & 8) !== 0
37032
+ };
37033
+ }
37034
+ function paintPlusEngineRun(rCtx, ef, run) {
37035
+ const base = {
37036
+ ...run,
37037
+ textAlign: 24,
37038
+ bkColor: "#ffffff",
37039
+ bkMode: 1,
37040
+ options: 0,
37041
+ rect: null,
37042
+ matrix: null
37043
+ };
37044
+ if ((!ef.color || ef.solidViaCoverage) && ef.sampler) {
37045
+ const cov = gdiTextCoverage(ef.realized, { ...base});
36852
37046
  if (!cov) {
36853
37047
  return true;
36854
37048
  }
@@ -36858,7 +37052,7 @@ function drawPlusStringWithEngine(rCtx, font, text, layoutX, layoutY, paint, ali
36858
37052
  }
36859
37053
  return compositeBrushCoverage(
36860
37054
  rCtx,
36861
- sampler,
37055
+ ef.sampler,
36862
37056
  { x: cov.x, y: cov.y, w: cov.width, h: cov.height },
36863
37057
  cov.data,
36864
37058
  cov.channels,
@@ -36866,25 +37060,82 @@ function drawPlusStringWithEngine(rCtx, font, text, layoutX, layoutY, paint, ali
36866
37060
  cov.channels === 3 ? gamma : 1
36867
37061
  );
36868
37062
  }
36869
- paintGdiTextRun(rCtx.ctx, realized, {
36870
- codes,
36871
- glyphIndices: false,
36872
- x,
36873
- y,
36874
- dx,
36875
- dy: null,
36876
- textAlign: 24,
36877
- textColor: color,
36878
- bkColor: "#ffffff",
36879
- bkMode: 1,
36880
- options: 0,
36881
- rect: null,
36882
- matrix: null,
36883
- underline: (font.flags & 4) !== 0,
36884
- strikeOut: (font.flags & 8) !== 0
36885
- }, rCtx.fontFamilyMap);
37063
+ paintGdiTextRun(
37064
+ rCtx.ctx,
37065
+ ef.realized,
37066
+ { ...base, textColor: ef.color, underline: ef.underline, strikeOut: ef.strikeOut },
37067
+ rCtx.fontFamilyMap
37068
+ );
36886
37069
  return true;
36887
37070
  }
37071
+ function drawPlusStringWithEngine(rCtx, font, text, layoutX, layoutY, paint, alignment, format, brushSampler2 = null) {
37072
+ if (alignment !== 0) {
37073
+ return false;
37074
+ }
37075
+ const ef = realizePlusEngineFont(rCtx, font, paint, brushSampler2);
37076
+ if (!ef) {
37077
+ return false;
37078
+ }
37079
+ const { realized, emPx, m, unhinted } = ef;
37080
+ const ttf = realized.ttf;
37081
+ const exactAscent = emPx * ttf.winAscent / ttf.unitsPerEm;
37082
+ const ascent = unhinted ? exactAscent : Math.ceil(exactAscent);
37083
+ const x = m[0] * layoutX + m[4] + emPx * (format?.leadingMargin ?? PLUS_LEADING_EM);
37084
+ const y = m[3] * layoutY + m[5] + ascent;
37085
+ const codes = [];
37086
+ for (let i = 0; i < text.length; i++) {
37087
+ codes.push(text.charCodeAt(i));
37088
+ }
37089
+ const tracking = format?.tracking ?? PLUS_DEFAULT_TRACKING;
37090
+ const dx = unhinted ? codes.map((c) => realized.advance(realized.glyphIndex(c)) * tracking) : null;
37091
+ return paintPlusEngineRun(rCtx, ef, { codes, glyphIndices: false, x, y, dx, dy: null });
37092
+ }
37093
+ var DRIVER_STRING_CMAP_LOOKUP = 1;
37094
+ var DRIVER_STRING_VERTICAL = 2;
37095
+ var DRIVER_STRING_REALIZED_ADVANCE = 4;
37096
+ function drawPlusDriverString(rCtx, recFlags, brushVal, font, codes, positions, options2) {
37097
+ const cmap = (options2 & DRIVER_STRING_CMAP_LOOKUP) !== 0;
37098
+ const realizedAdvance = (options2 & DRIVER_STRING_REALIZED_ADVANCE) !== 0;
37099
+ if (!(options2 & DRIVER_STRING_VERTICAL)) {
37100
+ const paint = resolveBrushPaint(rCtx, recFlags, brushVal);
37101
+ const ef = realizePlusEngineFont(rCtx, font, paint, rCtx.fonts ? deviceBrushSampler(rCtx, recFlags, brushVal) : null);
37102
+ if (ef) {
37103
+ const { m } = ef;
37104
+ const dev = positions.map((p) => ({ x: m[0] * p.x + m[4], y: m[3] * p.y + m[5] }));
37105
+ const step = (axis) => dev.map((p, i) => i + 1 < dev.length ? dev[i + 1][axis] - p[axis] : 0);
37106
+ paintPlusEngineRun(rCtx, ef, {
37107
+ codes,
37108
+ glyphIndices: !cmap,
37109
+ x: dev[0].x,
37110
+ y: dev[0].y,
37111
+ dx: realizedAdvance ? null : step("x"),
37112
+ dy: realizedAdvance ? null : step("y")
37113
+ });
37114
+ return;
37115
+ }
37116
+ }
37117
+ if (!cmap) {
37118
+ return;
37119
+ }
37120
+ const { ctx } = rCtx;
37121
+ const bold = font.flags & 1 ? "bold " : "";
37122
+ const italic = font.flags & 2 ? "italic " : "";
37123
+ const family = mapFontFamily(font.family, rCtx.fontFamilyMap);
37124
+ const setFont = () => {
37125
+ ctx.font = `${italic}${bold}${font.emSize}px ${family}`;
37126
+ ctx.textBaseline = "alphabetic";
37127
+ ctx.textAlign = "left";
37128
+ };
37129
+ if (realizedAdvance) {
37130
+ setFont();
37131
+ fillPlusText(rCtx, recFlags, brushVal, String.fromCharCode(...codes), positions[0].x, positions[0].y, font.emSize);
37132
+ return;
37133
+ }
37134
+ for (let i = 0; i < codes.length; i++) {
37135
+ setFont();
37136
+ fillPlusText(rCtx, recFlags, brushVal, String.fromCharCode(codes[i]), positions[i].x, positions[i].y, font.emSize);
37137
+ }
37138
+ }
36888
37139
  function handleEmfPlusTextImageRecord(rCtx, recType, recFlags, dataOff, recDataSize) {
36889
37140
  const { ctx, view, objectTable } = rCtx;
36890
37141
  switch (recType) {
@@ -36968,24 +37219,31 @@ function handleEmfPlusTextImageRecord(rCtx, recType, recFlags, dataOff, recDataS
36968
37219
  case EMFPLUS_DRAWDRIVERSTRING: {
36969
37220
  if (recDataSize >= 16) {
36970
37221
  const brushVal = view.getUint32(dataOff, true);
37222
+ const options2 = view.getUint32(dataOff + 4, true);
37223
+ const matrixPresent = view.getUint32(dataOff + 8, true) !== 0;
36971
37224
  const glyphCount = view.getUint32(dataOff + 12, true);
36972
- const fontId = recFlags & 255;
36973
- const font = objectTable.get(fontId);
37225
+ const font = objectTable.get(recFlags & 255);
36974
37226
  const glyphsOff = dataOff + 16;
36975
37227
  const posOff = glyphsOff + glyphCount * 2;
36976
- const alignedPosOff = posOff + 3 & -4;
36977
- if (glyphCount > 0 && glyphCount < 1e5 && alignedPosOff + glyphCount * 8 <= dataOff + recDataSize && font && font.kind === "plus-font") {
36978
- const text = readUtf16LE(view, glyphsOff, glyphCount);
36979
- if (text.length > 0) {
36980
- const bold = font.flags & 1 ? "bold " : "";
36981
- const italic = font.flags & 2 ? "italic " : "";
36982
- const family = mapFontFamily(font.family, rCtx.fontFamilyMap);
36983
- ctx.font = `${italic}${bold}${font.emSize}px ${family}`;
36984
- ctx.textBaseline = "alphabetic";
36985
- ctx.textAlign = "left";
36986
- const gx = view.getFloat32(alignedPosOff, true);
36987
- const gy = view.getFloat32(alignedPosOff + 4, true);
36988
- fillPlusText(rCtx, recFlags, brushVal, text, gx, gy, font.emSize);
37228
+ const matrixOff = posOff + glyphCount * 8;
37229
+ if (glyphCount > 0 && glyphCount < 1e5 && matrixOff + (matrixPresent ? 24 : 0) <= dataOff + recDataSize && font && font.kind === "plus-font") {
37230
+ const codes = [];
37231
+ const positions = [];
37232
+ for (let i = 0; i < glyphCount; i++) {
37233
+ codes.push(view.getUint16(glyphsOff + i * 2, true));
37234
+ positions.push({ x: view.getFloat32(posOff + i * 8, true), y: view.getFloat32(posOff + i * 8 + 4, true) });
37235
+ }
37236
+ const world = rCtx.worldTransform;
37237
+ if (matrixPresent) {
37238
+ const xf = [0, 4, 8, 12, 16, 20].map((k) => view.getFloat32(matrixOff + k, true));
37239
+ if (xf.every(Number.isFinite)) {
37240
+ rCtx.worldTransform = mulMatrix(world, xf);
37241
+ }
37242
+ }
37243
+ try {
37244
+ drawPlusDriverString(rCtx, recFlags, brushVal, font, codes, positions, options2);
37245
+ } finally {
37246
+ rCtx.worldTransform = world;
36989
37247
  }
36990
37248
  }
36991
37249
  }
@@ -37764,7 +38022,7 @@ function parseEmfPlusRegionObject(view, off, maxLen) {
37764
38022
  }
37765
38023
  view.getUint32(off, true);
37766
38024
  const regionNodeCount = view.getUint32(off + 4, true);
37767
- if (regionNodeCount === 0 || regionNodeCount > 1e5) {
38025
+ if (regionNodeCount > 1e5) {
37768
38026
  return null;
37769
38027
  }
37770
38028
  const endOff = off + maxLen;
@@ -38280,187 +38538,6 @@ function extractEmbeddedEmf(view, start) {
38280
38538
  return out.buffer;
38281
38539
  }
38282
38540
 
38283
- // src/wmf-mapping.ts
38284
- var MM_TEXT = 1;
38285
- var MM_LOMETRIC = 2;
38286
- var MM_HIMETRIC = 3;
38287
- var MM_LOENGLISH = 4;
38288
- var MM_HIENGLISH = 5;
38289
- var MM_TWIPS = 6;
38290
- var MM_ISOTROPIC = 7;
38291
- var MM_ANISOTROPIC = 8;
38292
- var DEVICE_DPI = 96;
38293
- function cloneMapping(m) {
38294
- return {
38295
- ...m.dpi ? { dpi: { ...m.dpi } } : {},
38296
- mode: m.mode,
38297
- winOrg: { ...m.winOrg },
38298
- winExt: { ...m.winExt },
38299
- vpOrg: { ...m.vpOrg },
38300
- vpExt: { ...m.vpExt }
38301
- };
38302
- }
38303
- var METRIC_UNITS_PER_INCH = {
38304
- [MM_LOMETRIC]: 254,
38305
- [MM_HIMETRIC]: 2540,
38306
- [MM_LOENGLISH]: 100,
38307
- [MM_HIENGLISH]: 1e3,
38308
- [MM_TWIPS]: 1440
38309
- };
38310
- function fixIsotropic(m) {
38311
- if (m.mode !== MM_ISOTROPIC || !m.winExt.cx || !m.winExt.cy) {
38312
- return;
38313
- }
38314
- const xdim = Math.abs(m.vpExt.cx / m.winExt.cx) / (m.dpi?.x ?? DEVICE_DPI);
38315
- const ydim = Math.abs(m.vpExt.cy / m.winExt.cy) / (m.dpi?.y ?? DEVICE_DPI);
38316
- if (xdim > ydim) {
38317
- const min = m.vpExt.cx >= 0 ? 1 : -1;
38318
- m.vpExt.cx = Math.floor(m.vpExt.cx * ydim / xdim + 0.5) || min;
38319
- } else if (ydim > xdim) {
38320
- const min = m.vpExt.cy >= 0 ? 1 : -1;
38321
- m.vpExt.cy = Math.floor(m.vpExt.cy * xdim / ydim + 0.5) || min;
38322
- }
38323
- }
38324
- function setMapMode(m, mode) {
38325
- if (mode < MM_TEXT || mode > MM_ANISOTROPIC) {
38326
- return;
38327
- }
38328
- const units = METRIC_UNITS_PER_INCH[mode === MM_ISOTROPIC ? MM_LOMETRIC : mode];
38329
- if (mode === MM_TEXT) {
38330
- m.winExt = { cx: 1, cy: 1 };
38331
- m.vpExt = { cx: 1, cy: 1 };
38332
- } else if (units !== void 0 && (mode !== MM_ISOTROPIC || m.mode !== MM_ISOTROPIC)) {
38333
- m.winExt = { cx: units, cy: units };
38334
- m.vpExt = { cx: m.dpi?.x ?? DEVICE_DPI, cy: -(m.dpi?.y ?? DEVICE_DPI) };
38335
- }
38336
- m.mode = mode;
38337
- }
38338
- function extentsSettable2(m) {
38339
- return m.mode === MM_ISOTROPIC || m.mode === MM_ANISOTROPIC;
38340
- }
38341
- function setWindowExt(m, cx, cy) {
38342
- if (!extentsSettable2(m) || cx === 0 || cy === 0) {
38343
- return;
38344
- }
38345
- m.winExt = { cx, cy };
38346
- fixIsotropic(m);
38347
- }
38348
- function setViewportExt(m, cx, cy) {
38349
- if (!extentsSettable2(m) || cx === 0 || cy === 0) {
38350
- return;
38351
- }
38352
- m.vpExt = { cx, cy };
38353
- fixIsotropic(m);
38354
- }
38355
- function scaled(v, num, den) {
38356
- return Math.trunc(v * num / den);
38357
- }
38358
- function scaleWindowExt(m, xNum, xDen, yNum, yDen) {
38359
- if (!extentsSettable2(m) || !xDen || !yDen) {
38360
- return;
38361
- }
38362
- const cx = scaled(m.winExt.cx, xNum, xDen);
38363
- const cy = scaled(m.winExt.cy, yNum, yDen);
38364
- if (cx === 0 || cy === 0) {
38365
- return;
38366
- }
38367
- m.winExt = { cx, cy };
38368
- fixIsotropic(m);
38369
- }
38370
- function scaleViewportExt(m, xNum, xDen, yNum, yDen) {
38371
- if (!extentsSettable2(m) || !xDen || !yDen) {
38372
- return;
38373
- }
38374
- const cx = scaled(m.vpExt.cx, xNum, xDen);
38375
- const cy = scaled(m.vpExt.cy, yNum, yDen);
38376
- if (cx === 0 || cy === 0) {
38377
- return;
38378
- }
38379
- m.vpExt = { cx, cy };
38380
- fixIsotropic(m);
38381
- }
38382
- function applyWmfMapping(rCtx, m, kx, ky, mirrorWidth = 0) {
38383
- rCtx.wmfLayoutRtl = mirrorWidth > 0;
38384
- rCtx.useMappingMode = true;
38385
- rCtx.windowOrg = { x: m.winOrg.x, y: m.winOrg.y };
38386
- rCtx.windowExt = { cx: m.winExt.cx || 1, cy: m.winExt.cy || 1 };
38387
- rCtx.viewportOrg = { x: m.vpOrg.x * kx, y: m.vpOrg.y * ky };
38388
- rCtx.viewportExt = { cx: (m.vpExt.cx || 1) * kx, cy: (m.vpExt.cy || 1) * ky };
38389
- if (mirrorWidth > 0) {
38390
- rCtx.viewportOrg.x = mirrorWidth * kx - rCtx.viewportOrg.x;
38391
- rCtx.viewportExt.cx = -rCtx.viewportExt.cx;
38392
- }
38393
- }
38394
- function scanMappingRecords(view, start) {
38395
- const out = {
38396
- mode: null,
38397
- winExt: null,
38398
- vpExt: null
38399
- };
38400
- let off = start;
38401
- let guard = 0;
38402
- while (off + 6 <= view.byteLength && guard++ < 1e6) {
38403
- const size = view.getUint32(off, true) * 2;
38404
- const type = view.getUint16(off + 4, true);
38405
- if (size < 6 || off + size > view.byteLength || type === 0) {
38406
- break;
38407
- }
38408
- const d = off + 6;
38409
- if (type === 259 && size >= 8 && out.mode === null) {
38410
- out.mode = view.getUint16(d, true);
38411
- } else if (type === 524 && size >= 10 && !out.winExt) {
38412
- out.winExt = { cy: view.getInt16(d, true), cx: view.getInt16(d + 2, true) };
38413
- } else if (type === 526 && size >= 10 && !out.vpExt) {
38414
- out.vpExt = { cy: view.getInt16(d, true), cx: view.getInt16(d + 2, true) };
38415
- }
38416
- off += size;
38417
- }
38418
- return out;
38419
- }
38420
- function wmfPlayback(view, header, referenceDpi) {
38421
- const valid = (v) => typeof v === "number" && Number.isFinite(v) && v > 0 ? v : DEVICE_DPI;
38422
- const dpi = { x: valid(typeof referenceDpi === "number" ? referenceDpi : referenceDpi?.x), y: valid(typeof referenceDpi === "number" ? referenceDpi : referenceDpi?.y) };
38423
- const density = referenceDpi === void 0 ? {} : { dpi };
38424
- const bw = header.boundsRight - header.boundsLeft;
38425
- const bh = header.boundsBottom - header.boundsTop;
38426
- if (header.placeable !== false) {
38427
- const inch = header.unitsPerInch > 0 ? header.unitsPerInch : DEVICE_DPI;
38428
- const width2 = Math.max(1, Math.round(Math.abs(bw) * dpi.x / inch));
38429
- const height2 = Math.max(1, Math.round(Math.abs(bh) * dpi.y / inch));
38430
- return {
38431
- width: width2,
38432
- height: height2,
38433
- mapping: {
38434
- ...density,
38435
- mode: MM_ANISOTROPIC,
38436
- winOrg: { x: header.boundsLeft, y: header.boundsTop },
38437
- winExt: { cx: bw || 1, cy: bh || 1 },
38438
- vpOrg: { x: 0, y: 0 },
38439
- vpExt: { cx: width2, cy: height2 }
38440
- }
38441
- };
38442
- }
38443
- const scan = scanMappingRecords(view, header.headerSize);
38444
- const scalable = scan.mode === MM_ISOTROPIC || scan.mode === MM_ANISOTROPIC;
38445
- const ext = scalable && scan.vpExt ? scan.vpExt : scan.winExt;
38446
- const width = ext ? Math.abs(ext.cx) : Math.abs(bw);
38447
- const height = ext ? Math.abs(ext.cy) : Math.abs(bh);
38448
- const w = Math.max(1, width || 1);
38449
- const h = Math.max(1, height || 1);
38450
- return {
38451
- width: w,
38452
- height: h,
38453
- mapping: {
38454
- ...density,
38455
- mode: MM_ANISOTROPIC,
38456
- winOrg: { x: 0, y: 0 },
38457
- winExt: { cx: w, cy: h },
38458
- vpOrg: { x: 0, y: 0 },
38459
- vpExt: { cx: w, cy: h }
38460
- }
38461
- };
38462
- }
38463
-
38464
38541
  // src/wmf-emf-bridge.ts
38465
38542
  var EmfRecordWriter = class {
38466
38543
  constructor(type, capacity = 64) {