pptx-glimpse 0.11.0 → 0.11.1

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/index.cjs CHANGED
@@ -1962,25 +1962,48 @@ var LazyMediaMap = class {
1962
1962
  return data;
1963
1963
  }
1964
1964
  };
1965
+ var LazyXmlMap = class {
1966
+ rawInput;
1967
+ cache = /* @__PURE__ */ new Map();
1968
+ entryIndex;
1969
+ constructor(rawInput, xmlEntryNames) {
1970
+ this.rawInput = rawInput;
1971
+ this.entryIndex = xmlEntryNames;
1972
+ }
1973
+ has(path) {
1974
+ return this.entryIndex.has(path);
1975
+ }
1976
+ get(path) {
1977
+ if (!this.entryIndex.has(path)) return void 0;
1978
+ const cached = this.cache.get(path);
1979
+ if (cached !== void 0) return cached;
1980
+ const result = (0, import_fflate.unzipSync)(this.rawInput, {
1981
+ filter: (file) => file.name === path
1982
+ });
1983
+ const data = result[path];
1984
+ if (data) {
1985
+ const str = (0, import_fflate.strFromU8)(data);
1986
+ this.cache.set(path, str);
1987
+ return str;
1988
+ }
1989
+ return void 0;
1990
+ }
1991
+ };
1965
1992
  function readPptx(input) {
1966
1993
  const rawInput = new Uint8Array(input);
1994
+ const xmlEntryNames = /* @__PURE__ */ new Set();
1967
1995
  const mediaEntryNames = /* @__PURE__ */ new Set();
1968
- const unzipped = (0, import_fflate.unzipSync)(rawInput, {
1996
+ (0, import_fflate.unzipSync)(rawInput, {
1969
1997
  filter: (file) => {
1970
1998
  if (file.name.startsWith("ppt/media/")) {
1971
1999
  mediaEntryNames.add(file.name);
1972
- return false;
2000
+ } else if (file.name.endsWith(".xml") || file.name.endsWith(".rels") || file.name === "[Content_Types].xml") {
2001
+ xmlEntryNames.add(file.name);
1973
2002
  }
1974
- return true;
2003
+ return false;
1975
2004
  }
1976
2005
  });
1977
- const files = /* @__PURE__ */ new Map();
1978
- for (const [relativePath, data] of Object.entries(unzipped)) {
1979
- if (relativePath.endsWith("/")) continue;
1980
- if (relativePath.endsWith(".xml") || relativePath.endsWith(".rels") || relativePath === "[Content_Types].xml") {
1981
- files.set(relativePath, (0, import_fflate.strFromU8)(data));
1982
- }
1983
- }
2006
+ const files = new LazyXmlMap(rawInput, xmlEntryNames);
1984
2007
  const media = new LazyMediaMap(rawInput, mediaEntryNames);
1985
2008
  return { files, media };
1986
2009
  }
@@ -3176,6 +3199,10 @@ function createDefaultBorders() {
3176
3199
 
3177
3200
  // src/parser/slide-parser.ts
3178
3201
  var SHAPE_TAGS = /* @__PURE__ */ new Set(["sp", "pic", "cxnSp", "grpSp", "graphicFrame"]);
3202
+ var SMARTART_DIAGRAM_URIS = /* @__PURE__ */ new Set([
3203
+ "http://schemas.openxmlformats.org/drawingml/2006/diagram",
3204
+ "http://purl.oclc.org/ooxml/drawingml/diagram"
3205
+ ]);
3179
3206
  function navigateOrdered(ordered, path) {
3180
3207
  let current = ordered;
3181
3208
  for (const key of path) {
@@ -3723,7 +3750,7 @@ function parseGraphicFrame(gf, rels, slidePath, archive, colorResolver, fontSche
3723
3750
  if (!tableData) return null;
3724
3751
  return { type: "table", transform, table: tableData };
3725
3752
  }
3726
- if (graphicData["@_uri"] === "http://schemas.openxmlformats.org/drawingml/2006/diagram") {
3753
+ if (SMARTART_DIAGRAM_URIS.has(graphicData["@_uri"])) {
3727
3754
  return parseSmartArt(
3728
3755
  graphicData,
3729
3756
  transform,
@@ -8475,10 +8502,23 @@ function computePathLineX(alignment, textStartX, effectiveTextWidth, width, marg
8475
8502
  return textStartX;
8476
8503
  }
8477
8504
  }
8478
- function measureLineWidth(segments, defaultFontSize, fontScale) {
8505
+ function measureLineWidth(segments, defaultFontSize, fontScale, fontResolver) {
8479
8506
  let totalWidth = 0;
8507
+ const jpanFallback = fontResolver ? getJpanFallbackFont() : null;
8480
8508
  for (const seg of segments) {
8481
8509
  const fontSize = (seg.properties.fontSize ?? defaultFontSize) * fontScale;
8510
+ if (fontResolver) {
8511
+ const fontSizePx = fontSize * PX_PER_PT3;
8512
+ const font = fontResolver.resolveFont(
8513
+ seg.properties.fontFamily,
8514
+ seg.properties.fontFamilyEa,
8515
+ jpanFallback
8516
+ );
8517
+ if (font) {
8518
+ totalWidth += font.getAdvanceWidth(seg.text, fontSizePx);
8519
+ continue;
8520
+ }
8521
+ }
8482
8522
  totalWidth += getTextMeasurer().measureTextWidth(
8483
8523
  seg.text,
8484
8524
  fontSize,
@@ -8534,7 +8574,7 @@ function renderSegmentAsPath(text, props, x, y, fontScale, defaultFontSize, font
8534
8574
  const processSegment = (segText, fontFamily, fontFamilyEa) => {
8535
8575
  if (segText.length === 0) return;
8536
8576
  const font = fontResolver.resolveFont(fontFamily, fontFamilyEa, jpanFallback);
8537
- const segWidth = getTextMeasurer().measureTextWidth(
8577
+ const segWidth = font ? font.getAdvanceWidth(segText, fontSizePx) : getTextMeasurer().measureTextWidth(
8538
8578
  segText,
8539
8579
  fontSize,
8540
8580
  props.bold,
@@ -8559,7 +8599,7 @@ function renderSegmentAsPath(text, props, x, y, fontScale, defaultFontSize, font
8559
8599
  const font = fontResolver.resolveFont(fontFamily, fontFamilyEa, jpanFallback);
8560
8600
  const fillAttrs = buildPathFillAttrs(props);
8561
8601
  for (const char of segText) {
8562
- const charWidth = getTextMeasurer().measureTextWidth(
8602
+ const charWidth = font ? font.getAdvanceWidth(char, fontSizePx) : getTextMeasurer().measureTextWidth(
8563
8603
  char,
8564
8604
  fontSize,
8565
8605
  props.bold,
@@ -8731,7 +8771,7 @@ function renderTextBodyAsPath(textBody, transform, fontResolver) {
8731
8771
  if (!isFirstLine) {
8732
8772
  currentY += lineNaturalHeightPt * PX_PER_PT3 * getLineSpacing(para, lnSpcReduction) + lineGapPx;
8733
8773
  }
8734
- const lineWidth = measureLineWidth(line.segments, defaultFontSize, fontScale);
8774
+ const lineWidth = measureLineWidth(line.segments, defaultFontSize, fontScale, fontResolver);
8735
8775
  const lineStartX = computePathLineX(
8736
8776
  para.properties.alignment,
8737
8777
  textStartX,
@@ -8780,7 +8820,7 @@ function renderTextBodyAsPath(textBody, transform, fontResolver) {
8780
8820
  currentY += naturalHeightPt * PX_PER_PT3 * getLineSpacing(para, lnSpcReduction) + paragraphGapPx;
8781
8821
  }
8782
8822
  const runsAsSegments = para.runs.filter((r) => r.text.length > 0).map((r) => ({ text: r.text, properties: r.properties }));
8783
- const lineWidth = measureLineWidth(runsAsSegments, defaultFontSize, fontScale);
8823
+ const lineWidth = measureLineWidth(runsAsSegments, defaultFontSize, fontScale, fontResolver);
8784
8824
  const lineStartX = computePathLineX(
8785
8825
  para.properties.alignment,
8786
8826
  textStartX,
package/dist/index.d.cts CHANGED
@@ -151,6 +151,7 @@ interface OpentypeFullFont {
151
151
  ascender: number;
152
152
  descender: number;
153
153
  getPath(text: string, x: number, y: number, fontSize: number): OpentypePath;
154
+ getAdvanceWidth(text: string, fontSize: number): number;
154
155
  }
155
156
  interface TextPathFontResolver {
156
157
  resolveFont(fontFamily: string | null | undefined, fontFamilyEa: string | null | undefined, jpanFallback?: string | null): OpentypeFullFont | null;
package/dist/index.d.ts CHANGED
@@ -151,6 +151,7 @@ interface OpentypeFullFont {
151
151
  ascender: number;
152
152
  descender: number;
153
153
  getPath(text: string, x: number, y: number, fontSize: number): OpentypePath;
154
+ getAdvanceWidth(text: string, fontSize: number): number;
154
155
  }
155
156
  interface TextPathFontResolver {
156
157
  resolveFont(fontFamily: string | null | undefined, fontFamilyEa: string | null | undefined, jpanFallback?: string | null): OpentypeFullFont | null;
package/dist/index.js CHANGED
@@ -1924,25 +1924,48 @@ var LazyMediaMap = class {
1924
1924
  return data;
1925
1925
  }
1926
1926
  };
1927
+ var LazyXmlMap = class {
1928
+ rawInput;
1929
+ cache = /* @__PURE__ */ new Map();
1930
+ entryIndex;
1931
+ constructor(rawInput, xmlEntryNames) {
1932
+ this.rawInput = rawInput;
1933
+ this.entryIndex = xmlEntryNames;
1934
+ }
1935
+ has(path) {
1936
+ return this.entryIndex.has(path);
1937
+ }
1938
+ get(path) {
1939
+ if (!this.entryIndex.has(path)) return void 0;
1940
+ const cached = this.cache.get(path);
1941
+ if (cached !== void 0) return cached;
1942
+ const result = unzipSync(this.rawInput, {
1943
+ filter: (file) => file.name === path
1944
+ });
1945
+ const data = result[path];
1946
+ if (data) {
1947
+ const str = strFromU8(data);
1948
+ this.cache.set(path, str);
1949
+ return str;
1950
+ }
1951
+ return void 0;
1952
+ }
1953
+ };
1927
1954
  function readPptx(input) {
1928
1955
  const rawInput = new Uint8Array(input);
1956
+ const xmlEntryNames = /* @__PURE__ */ new Set();
1929
1957
  const mediaEntryNames = /* @__PURE__ */ new Set();
1930
- const unzipped = unzipSync(rawInput, {
1958
+ unzipSync(rawInput, {
1931
1959
  filter: (file) => {
1932
1960
  if (file.name.startsWith("ppt/media/")) {
1933
1961
  mediaEntryNames.add(file.name);
1934
- return false;
1962
+ } else if (file.name.endsWith(".xml") || file.name.endsWith(".rels") || file.name === "[Content_Types].xml") {
1963
+ xmlEntryNames.add(file.name);
1935
1964
  }
1936
- return true;
1965
+ return false;
1937
1966
  }
1938
1967
  });
1939
- const files = /* @__PURE__ */ new Map();
1940
- for (const [relativePath, data] of Object.entries(unzipped)) {
1941
- if (relativePath.endsWith("/")) continue;
1942
- if (relativePath.endsWith(".xml") || relativePath.endsWith(".rels") || relativePath === "[Content_Types].xml") {
1943
- files.set(relativePath, strFromU8(data));
1944
- }
1945
- }
1968
+ const files = new LazyXmlMap(rawInput, xmlEntryNames);
1946
1969
  const media = new LazyMediaMap(rawInput, mediaEntryNames);
1947
1970
  return { files, media };
1948
1971
  }
@@ -3138,6 +3161,10 @@ function createDefaultBorders() {
3138
3161
 
3139
3162
  // src/parser/slide-parser.ts
3140
3163
  var SHAPE_TAGS = /* @__PURE__ */ new Set(["sp", "pic", "cxnSp", "grpSp", "graphicFrame"]);
3164
+ var SMARTART_DIAGRAM_URIS = /* @__PURE__ */ new Set([
3165
+ "http://schemas.openxmlformats.org/drawingml/2006/diagram",
3166
+ "http://purl.oclc.org/ooxml/drawingml/diagram"
3167
+ ]);
3141
3168
  function navigateOrdered(ordered, path) {
3142
3169
  let current = ordered;
3143
3170
  for (const key of path) {
@@ -3685,7 +3712,7 @@ function parseGraphicFrame(gf, rels, slidePath, archive, colorResolver, fontSche
3685
3712
  if (!tableData) return null;
3686
3713
  return { type: "table", transform, table: tableData };
3687
3714
  }
3688
- if (graphicData["@_uri"] === "http://schemas.openxmlformats.org/drawingml/2006/diagram") {
3715
+ if (SMARTART_DIAGRAM_URIS.has(graphicData["@_uri"])) {
3689
3716
  return parseSmartArt(
3690
3717
  graphicData,
3691
3718
  transform,
@@ -8437,10 +8464,23 @@ function computePathLineX(alignment, textStartX, effectiveTextWidth, width, marg
8437
8464
  return textStartX;
8438
8465
  }
8439
8466
  }
8440
- function measureLineWidth(segments, defaultFontSize, fontScale) {
8467
+ function measureLineWidth(segments, defaultFontSize, fontScale, fontResolver) {
8441
8468
  let totalWidth = 0;
8469
+ const jpanFallback = fontResolver ? getJpanFallbackFont() : null;
8442
8470
  for (const seg of segments) {
8443
8471
  const fontSize = (seg.properties.fontSize ?? defaultFontSize) * fontScale;
8472
+ if (fontResolver) {
8473
+ const fontSizePx = fontSize * PX_PER_PT3;
8474
+ const font = fontResolver.resolveFont(
8475
+ seg.properties.fontFamily,
8476
+ seg.properties.fontFamilyEa,
8477
+ jpanFallback
8478
+ );
8479
+ if (font) {
8480
+ totalWidth += font.getAdvanceWidth(seg.text, fontSizePx);
8481
+ continue;
8482
+ }
8483
+ }
8444
8484
  totalWidth += getTextMeasurer().measureTextWidth(
8445
8485
  seg.text,
8446
8486
  fontSize,
@@ -8496,7 +8536,7 @@ function renderSegmentAsPath(text, props, x, y, fontScale, defaultFontSize, font
8496
8536
  const processSegment = (segText, fontFamily, fontFamilyEa) => {
8497
8537
  if (segText.length === 0) return;
8498
8538
  const font = fontResolver.resolveFont(fontFamily, fontFamilyEa, jpanFallback);
8499
- const segWidth = getTextMeasurer().measureTextWidth(
8539
+ const segWidth = font ? font.getAdvanceWidth(segText, fontSizePx) : getTextMeasurer().measureTextWidth(
8500
8540
  segText,
8501
8541
  fontSize,
8502
8542
  props.bold,
@@ -8521,7 +8561,7 @@ function renderSegmentAsPath(text, props, x, y, fontScale, defaultFontSize, font
8521
8561
  const font = fontResolver.resolveFont(fontFamily, fontFamilyEa, jpanFallback);
8522
8562
  const fillAttrs = buildPathFillAttrs(props);
8523
8563
  for (const char of segText) {
8524
- const charWidth = getTextMeasurer().measureTextWidth(
8564
+ const charWidth = font ? font.getAdvanceWidth(char, fontSizePx) : getTextMeasurer().measureTextWidth(
8525
8565
  char,
8526
8566
  fontSize,
8527
8567
  props.bold,
@@ -8693,7 +8733,7 @@ function renderTextBodyAsPath(textBody, transform, fontResolver) {
8693
8733
  if (!isFirstLine) {
8694
8734
  currentY += lineNaturalHeightPt * PX_PER_PT3 * getLineSpacing(para, lnSpcReduction) + lineGapPx;
8695
8735
  }
8696
- const lineWidth = measureLineWidth(line.segments, defaultFontSize, fontScale);
8736
+ const lineWidth = measureLineWidth(line.segments, defaultFontSize, fontScale, fontResolver);
8697
8737
  const lineStartX = computePathLineX(
8698
8738
  para.properties.alignment,
8699
8739
  textStartX,
@@ -8742,7 +8782,7 @@ function renderTextBodyAsPath(textBody, transform, fontResolver) {
8742
8782
  currentY += naturalHeightPt * PX_PER_PT3 * getLineSpacing(para, lnSpcReduction) + paragraphGapPx;
8743
8783
  }
8744
8784
  const runsAsSegments = para.runs.filter((r) => r.text.length > 0).map((r) => ({ text: r.text, properties: r.properties }));
8745
- const lineWidth = measureLineWidth(runsAsSegments, defaultFontSize, fontScale);
8785
+ const lineWidth = measureLineWidth(runsAsSegments, defaultFontSize, fontScale, fontResolver);
8746
8786
  const lineStartX = computePathLineX(
8747
8787
  para.properties.alignment,
8748
8788
  textStartX,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pptx-glimpse",
3
- "version": "0.11.0",
3
+ "version": "0.11.1",
4
4
  "description": "A lightweight JavaScript library for rendering PowerPoint (.pptx) files as SVG or PNG in Node.js. No LibreOffice required.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",