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