pptx-glimpse 0.5.0 → 0.6.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.
Files changed (3) hide show
  1. package/dist/index.cjs +137 -49
  2. package/dist/index.js +137 -39
  3. package/package.json +4 -3
package/dist/index.cjs CHANGED
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,14 +15,6 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
19
 
30
20
  // src/index.ts
@@ -1580,17 +1570,20 @@ function parseXmlOrdered(xml) {
1580
1570
  }
1581
1571
 
1582
1572
  // src/png/png-converter.ts
1583
- var import_sharp = __toESM(require("sharp"), 1);
1573
+ var import_resvg_js = require("@resvg/resvg-js");
1584
1574
  async function svgToPng(svgString, options) {
1585
- const svgBuffer = Buffer.from(svgString);
1586
- let pipeline = (0, import_sharp.default)(svgBuffer);
1575
+ const resvgOptions = {};
1587
1576
  if (options?.width) {
1588
- pipeline = pipeline.resize(options.width);
1577
+ resvgOptions.fitTo = { mode: "width", value: options.width };
1589
1578
  } else if (options?.height) {
1590
- pipeline = pipeline.resize(null, options.height);
1579
+ resvgOptions.fitTo = { mode: "height", value: options.height };
1591
1580
  }
1592
- const result = await pipeline.png().toBuffer({ resolveWithObject: true });
1593
- return { png: result.data, width: result.info.width, height: result.info.height };
1581
+ const rendered = await (0, import_resvg_js.renderAsync)(svgString, resvgOptions);
1582
+ return {
1583
+ png: Buffer.from(rendered.asPng()),
1584
+ width: rendered.width,
1585
+ height: rendered.height
1586
+ };
1594
1587
  }
1595
1588
 
1596
1589
  // src/warning-logger.ts
@@ -3024,7 +3017,7 @@ function navigateOrdered(ordered, path) {
3024
3017
  }
3025
3018
  return current;
3026
3019
  }
3027
- function parseSlide(slideXml, slidePath, slideNumber, archive, colorResolver, fontScheme, fmtScheme) {
3020
+ function parseSlide(slideXml, slidePath, slideNumber, archive, colorResolver, fontScheme, fmtScheme, placeholderStyles) {
3028
3021
  const parsed = parseXml(slideXml);
3029
3022
  const sld = parsed.sld;
3030
3023
  if (!sld) {
@@ -3048,7 +3041,8 @@ function parseSlide(slideXml, slidePath, slideNumber, archive, colorResolver, fo
3048
3041
  fillContext,
3049
3042
  fontScheme,
3050
3043
  orderedSpTree,
3051
- fmtScheme
3044
+ fmtScheme,
3045
+ placeholderStyles
3052
3046
  );
3053
3047
  const showMasterSpAttr = sld?.["@_showMasterSp"];
3054
3048
  const showMasterSp = showMasterSpAttr !== "0" && showMasterSpAttr !== "false";
@@ -3075,7 +3069,7 @@ function mergeChildElements(spTree, source) {
3075
3069
  }
3076
3070
  }
3077
3071
  }
3078
- function parseShapeTree(spTree, rels, slidePath, archive, colorResolver, context, fillContext, fontScheme, orderedChildren, fmtScheme) {
3072
+ function parseShapeTree(spTree, rels, slidePath, archive, colorResolver, context, fillContext, fontScheme, orderedChildren, fmtScheme, placeholderStyles) {
3079
3073
  if (!spTree) return [];
3080
3074
  if (orderedChildren) {
3081
3075
  return parseShapeTreeOrdered(
@@ -3088,7 +3082,8 @@ function parseShapeTree(spTree, rels, slidePath, archive, colorResolver, context
3088
3082
  context,
3089
3083
  fillContext,
3090
3084
  fontScheme,
3091
- fmtScheme
3085
+ fmtScheme,
3086
+ placeholderStyles
3092
3087
  );
3093
3088
  }
3094
3089
  const alternateContents = spTree.AlternateContent ?? [];
@@ -3109,7 +3104,8 @@ function parseShapeTree(spTree, rels, slidePath, archive, colorResolver, context
3109
3104
  fillContext,
3110
3105
  fontScheme,
3111
3106
  void 0,
3112
- fmtScheme
3107
+ fmtScheme,
3108
+ placeholderStyles
3113
3109
  );
3114
3110
  if (shape) {
3115
3111
  elements.push(shape);
@@ -3165,7 +3161,7 @@ function parseShapeTree(spTree, rels, slidePath, archive, colorResolver, context
3165
3161
  }
3166
3162
  return elements;
3167
3163
  }
3168
- function parseShapeTreeOrdered(spTree, orderedChildren, rels, slidePath, archive, colorResolver, context, fillContext, fontScheme, fmtScheme) {
3164
+ function parseShapeTreeOrdered(spTree, orderedChildren, rels, slidePath, archive, colorResolver, context, fillContext, fontScheme, fmtScheme, placeholderStyles) {
3169
3165
  const ctx = context ?? slidePath;
3170
3166
  const elements = [];
3171
3167
  const tagCounters = {};
@@ -3207,7 +3203,8 @@ function parseShapeTreeOrdered(spTree, orderedChildren, rels, slidePath, archive
3207
3203
  ctx,
3208
3204
  fillContext,
3209
3205
  fontScheme,
3210
- fmtScheme
3206
+ fmtScheme,
3207
+ placeholderStyles
3211
3208
  );
3212
3209
  }
3213
3210
  }
@@ -3231,12 +3228,13 @@ function parseShapeTreeOrdered(spTree, orderedChildren, rels, slidePath, archive
3231
3228
  ctx,
3232
3229
  fillContext,
3233
3230
  fontScheme,
3234
- fmtScheme
3231
+ fmtScheme,
3232
+ placeholderStyles
3235
3233
  );
3236
3234
  }
3237
3235
  return elements;
3238
3236
  }
3239
- function parseAndPushElement(tag, element, orderedNode, elements, rels, slidePath, archive, colorResolver, ctx, fillContext, fontScheme, fmtScheme) {
3237
+ function parseAndPushElement(tag, element, orderedNode, elements, rels, slidePath, archive, colorResolver, ctx, fillContext, fontScheme, fmtScheme, placeholderStyles) {
3240
3238
  switch (tag) {
3241
3239
  case "sp": {
3242
3240
  const shape = parseShape(
@@ -3246,7 +3244,8 @@ function parseAndPushElement(tag, element, orderedNode, elements, rels, slidePat
3246
3244
  fillContext,
3247
3245
  fontScheme,
3248
3246
  orderedNode,
3249
- fmtScheme
3247
+ fmtScheme,
3248
+ placeholderStyles
3250
3249
  );
3251
3250
  if (shape) {
3252
3251
  elements.push(shape);
@@ -3311,22 +3310,42 @@ function parseAndPushElement(tag, element, orderedNode, elements, rels, slidePat
3311
3310
  }
3312
3311
  }
3313
3312
  }
3314
- function parseShape(sp, colorResolver, rels, fillContext, fontScheme, orderedNode, fmtScheme) {
3313
+ function parseShape(sp, colorResolver, rels, fillContext, fontScheme, orderedNode, fmtScheme, placeholderStyles) {
3315
3314
  const spPr = sp.spPr;
3316
- if (!spPr) return null;
3317
- const transform = parseTransform(spPr.xfrm);
3315
+ const spPrIsObject = spPr != null && typeof spPr === "object";
3316
+ const nvSpPr = sp.nvSpPr;
3317
+ const nvPr = nvSpPr?.nvPr;
3318
+ const ph = nvPr?.ph;
3319
+ const placeholderType = ph ? ph["@_type"] ?? "body" : void 0;
3320
+ const placeholderIdx = ph?.["@_idx"] !== void 0 ? Number(ph["@_idx"]) : void 0;
3321
+ let transform = null;
3322
+ let geometry;
3323
+ if (spPrIsObject) {
3324
+ transform = parseTransform(spPr.xfrm);
3325
+ geometry = parseGeometry(spPr);
3326
+ } else {
3327
+ geometry = { type: "preset", preset: "rect", adjustValues: {} };
3328
+ }
3329
+ if (!transform && placeholderType && placeholderStyles) {
3330
+ const inherited = findMatchingPlaceholder(placeholderType, placeholderIdx, placeholderStyles);
3331
+ if (inherited?.transform) {
3332
+ transform = inherited.transform;
3333
+ }
3334
+ if (!spPrIsObject && inherited?.geometry) {
3335
+ geometry = inherited.geometry;
3336
+ }
3337
+ }
3318
3338
  if (!transform) return null;
3319
- if (spPr.scene3d) {
3339
+ if (spPrIsObject && spPr.scene3d) {
3320
3340
  warn("spPr.scene3d", "3D scene/camera not implemented");
3321
3341
  }
3322
- if (spPr.sp3d) {
3342
+ if (spPrIsObject && spPr.sp3d) {
3323
3343
  warn("spPr.sp3d", "3D extrusion/bevel not implemented");
3324
3344
  }
3325
- const geometry = parseGeometry(spPr);
3326
3345
  const styleRef = resolveShapeStyle(sp.style, fmtScheme, colorResolver);
3327
- const directFill = parseFillFromNode(spPr, colorResolver, fillContext);
3346
+ const directFill = spPrIsObject ? parseFillFromNode(spPr, colorResolver, fillContext) : null;
3328
3347
  const fill = directFill ?? styleRef?.fill ?? null;
3329
- const directOutline = parseOutline(spPr.ln, colorResolver);
3348
+ const directOutline = spPrIsObject ? parseOutline(spPr.ln, colorResolver) : null;
3330
3349
  const outline = directOutline ?? styleRef?.outline ?? null;
3331
3350
  let orderedTxBody;
3332
3351
  if (orderedNode) {
@@ -3344,16 +3363,11 @@ function parseShape(sp, colorResolver, rels, fillContext, fontScheme, orderedNod
3344
3363
  void 0,
3345
3364
  orderedTxBody
3346
3365
  );
3347
- const directEffects = parseEffectList(spPr.effectLst, colorResolver);
3366
+ const directEffects = spPrIsObject ? parseEffectList(spPr.effectLst, colorResolver) : null;
3348
3367
  const effects = directEffects ?? styleRef?.effects ?? null;
3349
- const nvSpPr = sp.nvSpPr;
3350
3368
  const cNvPr = nvSpPr?.cNvPr;
3351
3369
  const altText = cNvPr?.["@_descr"];
3352
3370
  const hyperlink = parseHyperlink(cNvPr?.hlinkClick, rels);
3353
- const nvPr = nvSpPr?.nvPr;
3354
- const ph = nvPr?.ph;
3355
- const placeholderType = ph ? ph["@_type"] ?? "body" : void 0;
3356
- const placeholderIdx = ph?.["@_idx"] !== void 0 ? Number(ph["@_idx"]) : void 0;
3357
3371
  return {
3358
3372
  type: "shape",
3359
3373
  transform,
@@ -3707,6 +3721,31 @@ function parseGeometry(spPr) {
3707
3721
  }
3708
3722
  return { type: "preset", preset: "rect", adjustValues: {} };
3709
3723
  }
3724
+ function findMatchingPlaceholder(placeholderType, placeholderIdx, styles) {
3725
+ if (placeholderIdx !== void 0) {
3726
+ const byIdx = styles.find((s) => s.placeholderIdx === placeholderIdx && s.transform);
3727
+ if (byIdx) return byIdx;
3728
+ const byIdxAny = styles.find((s) => s.placeholderIdx === placeholderIdx);
3729
+ if (byIdxAny) return byIdxAny;
3730
+ }
3731
+ const byTypeWithTransform = styles.find(
3732
+ (s) => s.placeholderType === placeholderType && s.transform
3733
+ );
3734
+ if (byTypeWithTransform) return byTypeWithTransform;
3735
+ const fallbackType = placeholderType === "ctrTitle" ? "title" : placeholderType === "subTitle" ? "body" : void 0;
3736
+ if (fallbackType) {
3737
+ const byFallbackWithTransform = styles.find(
3738
+ (s) => s.placeholderType === fallbackType && s.transform
3739
+ );
3740
+ if (byFallbackWithTransform) return byFallbackWithTransform;
3741
+ }
3742
+ const byType = styles.find((s) => s.placeholderType === placeholderType);
3743
+ if (byType) return byType;
3744
+ if (fallbackType) {
3745
+ return styles.find((s) => s.placeholderType === fallbackType);
3746
+ }
3747
+ return void 0;
3748
+ }
3710
3749
  function parseTextBody(txBody, colorResolver, rels, fontScheme, lstStyleOverride, orderedTxBody) {
3711
3750
  if (!txBody) return null;
3712
3751
  const bodyPr = txBody.bodyPr;
@@ -4136,10 +4175,15 @@ function parseSlideLayoutPlaceholderStyles(xml, colorResolver) {
4136
4175
  const txBody = sp.txBody;
4137
4176
  const lstStyleNode = txBody?.lstStyle;
4138
4177
  const lstStyle = lstStyleNode ? parseListStyle(lstStyleNode, colorResolver) : void 0;
4178
+ const spPr = sp.spPr;
4179
+ const transform = spPr && typeof spPr === "object" ? parseTransform(spPr.xfrm) : null;
4180
+ const geometry = spPr && typeof spPr === "object" ? parseGeometry(spPr) : void 0;
4139
4181
  results.push({
4140
4182
  placeholderType,
4141
4183
  ...placeholderIdx !== void 0 && { placeholderIdx },
4142
- ...lstStyle && { lstStyle }
4184
+ ...lstStyle && { lstStyle },
4185
+ ...transform && { transform },
4186
+ ...geometry && { geometry }
4143
4187
  });
4144
4188
  }
4145
4189
  return results;
@@ -4256,10 +4300,15 @@ function parseSlideMasterPlaceholderStyles(xml, colorResolver) {
4256
4300
  const txBody = sp.txBody;
4257
4301
  const lstStyleNode = txBody?.lstStyle;
4258
4302
  const lstStyle = lstStyleNode ? parseListStyle(lstStyleNode, colorResolver) : void 0;
4303
+ const spPr = sp.spPr;
4304
+ const transform = spPr && typeof spPr === "object" ? parseTransform(spPr.xfrm) : null;
4305
+ const geometry = spPr && typeof spPr === "object" ? parseGeometry(spPr) : void 0;
4259
4306
  results.push({
4260
4307
  placeholderType,
4261
4308
  ...placeholderIdx !== void 0 && { placeholderIdx },
4262
- ...lstStyle && { lstStyle }
4309
+ ...lstStyle && { lstStyle },
4310
+ ...transform && { transform },
4311
+ ...geometry && { geometry }
4263
4312
  });
4264
4313
  }
4265
4314
  return results;
@@ -4710,6 +4759,17 @@ function parseSlideWithLayout(slideNumber, path, data) {
4710
4759
  slideMasterData,
4711
4760
  data.theme
4712
4761
  );
4762
+ let layoutPlaceholderStyles = [];
4763
+ let layoutShowMasterSp = true;
4764
+ if (layoutXml) {
4765
+ layoutPlaceholderStyles = parseSlideLayoutPlaceholderStyles(layoutXml, slideColorResolver);
4766
+ layoutShowMasterSp = parseSlideLayoutShowMasterSp(layoutXml);
4767
+ }
4768
+ const masterPlaceholderStyles = slideMasterData?.placeholderStyles ?? data.masterPlaceholderStyles;
4769
+ const mergedPlaceholderStyles = mergePlaceholderGeometry(
4770
+ layoutPlaceholderStyles,
4771
+ masterPlaceholderStyles
4772
+ );
4713
4773
  const slide = parseSlide(
4714
4774
  slideXml,
4715
4775
  path,
@@ -4717,11 +4777,10 @@ function parseSlideWithLayout(slideNumber, path, data) {
4717
4777
  data.archive,
4718
4778
  slideColorResolver,
4719
4779
  data.theme.fontScheme,
4720
- data.theme.fmtScheme
4780
+ data.theme.fmtScheme,
4781
+ mergedPlaceholderStyles
4721
4782
  );
4722
4783
  let layoutElements = [];
4723
- let layoutPlaceholderStyles = [];
4724
- let layoutShowMasterSp = true;
4725
4784
  if (layoutXml && layoutPath) {
4726
4785
  if (!slide.background) {
4727
4786
  const layoutFillContext = {
@@ -4743,13 +4802,10 @@ function parseSlideWithLayout(slideNumber, path, data) {
4743
4802
  data.theme.fontScheme,
4744
4803
  data.theme.fmtScheme
4745
4804
  );
4746
- layoutPlaceholderStyles = parseSlideLayoutPlaceholderStyles(layoutXml, slideColorResolver);
4747
- layoutShowMasterSp = parseSlideLayoutShowMasterSp(layoutXml);
4748
4805
  }
4749
4806
  if (!slide.background) {
4750
4807
  slide.background = slideMasterData?.background ?? data.masterBackground;
4751
4808
  }
4752
- const masterPlaceholderStyles = slideMasterData?.placeholderStyles ?? data.masterPlaceholderStyles;
4753
4809
  const masterTxStyles = slideMasterData?.txStyles ?? data.masterTxStyles;
4754
4810
  applyTextStyleInheritance(slide.elements, {
4755
4811
  layoutPlaceholderStyles,
@@ -4761,6 +4817,38 @@ function parseSlideWithLayout(slideNumber, path, data) {
4761
4817
  const masterElements = slideMasterData?.elements ?? data.masterElements;
4762
4818
  return { slide, layoutElements, layoutShowMasterSp, masterElements };
4763
4819
  }
4820
+ function mergePlaceholderGeometry(layoutStyles, masterStyles) {
4821
+ const merged = layoutStyles.map((ls) => {
4822
+ if (ls.transform) return ls;
4823
+ const masterMatch = findPlaceholderByTypeAndIdx(
4824
+ ls.placeholderType,
4825
+ ls.placeholderIdx,
4826
+ masterStyles
4827
+ );
4828
+ if (!masterMatch) return ls;
4829
+ return {
4830
+ ...ls,
4831
+ ...!ls.transform && masterMatch.transform && { transform: masterMatch.transform },
4832
+ ...!ls.geometry && masterMatch.geometry && { geometry: masterMatch.geometry }
4833
+ };
4834
+ });
4835
+ for (const ms of masterStyles) {
4836
+ const exists = merged.some(
4837
+ (m) => m.placeholderType === ms.placeholderType && m.placeholderIdx === ms.placeholderIdx
4838
+ );
4839
+ if (!exists) {
4840
+ merged.push(ms);
4841
+ }
4842
+ }
4843
+ return merged;
4844
+ }
4845
+ function findPlaceholderByTypeAndIdx(type, idx, styles) {
4846
+ if (idx !== void 0) {
4847
+ const byIdx = styles.find((s) => s.placeholderIdx === idx);
4848
+ if (byIdx) return byIdx;
4849
+ }
4850
+ return styles.find((s) => s.placeholderType === type);
4851
+ }
4764
4852
  function defaultColorScheme2() {
4765
4853
  return {
4766
4854
  dk1: "#000000",
package/dist/index.js CHANGED
@@ -1535,17 +1535,20 @@ function parseXmlOrdered(xml) {
1535
1535
  }
1536
1536
 
1537
1537
  // src/png/png-converter.ts
1538
- import sharp from "sharp";
1538
+ import { renderAsync } from "@resvg/resvg-js";
1539
1539
  async function svgToPng(svgString, options) {
1540
- const svgBuffer = Buffer.from(svgString);
1541
- let pipeline = sharp(svgBuffer);
1540
+ const resvgOptions = {};
1542
1541
  if (options?.width) {
1543
- pipeline = pipeline.resize(options.width);
1542
+ resvgOptions.fitTo = { mode: "width", value: options.width };
1544
1543
  } else if (options?.height) {
1545
- pipeline = pipeline.resize(null, options.height);
1544
+ resvgOptions.fitTo = { mode: "height", value: options.height };
1546
1545
  }
1547
- const result = await pipeline.png().toBuffer({ resolveWithObject: true });
1548
- return { png: result.data, width: result.info.width, height: result.info.height };
1546
+ const rendered = await renderAsync(svgString, resvgOptions);
1547
+ return {
1548
+ png: Buffer.from(rendered.asPng()),
1549
+ width: rendered.width,
1550
+ height: rendered.height
1551
+ };
1549
1552
  }
1550
1553
 
1551
1554
  // src/warning-logger.ts
@@ -2979,7 +2982,7 @@ function navigateOrdered(ordered, path) {
2979
2982
  }
2980
2983
  return current;
2981
2984
  }
2982
- function parseSlide(slideXml, slidePath, slideNumber, archive, colorResolver, fontScheme, fmtScheme) {
2985
+ function parseSlide(slideXml, slidePath, slideNumber, archive, colorResolver, fontScheme, fmtScheme, placeholderStyles) {
2983
2986
  const parsed = parseXml(slideXml);
2984
2987
  const sld = parsed.sld;
2985
2988
  if (!sld) {
@@ -3003,7 +3006,8 @@ function parseSlide(slideXml, slidePath, slideNumber, archive, colorResolver, fo
3003
3006
  fillContext,
3004
3007
  fontScheme,
3005
3008
  orderedSpTree,
3006
- fmtScheme
3009
+ fmtScheme,
3010
+ placeholderStyles
3007
3011
  );
3008
3012
  const showMasterSpAttr = sld?.["@_showMasterSp"];
3009
3013
  const showMasterSp = showMasterSpAttr !== "0" && showMasterSpAttr !== "false";
@@ -3030,7 +3034,7 @@ function mergeChildElements(spTree, source) {
3030
3034
  }
3031
3035
  }
3032
3036
  }
3033
- function parseShapeTree(spTree, rels, slidePath, archive, colorResolver, context, fillContext, fontScheme, orderedChildren, fmtScheme) {
3037
+ function parseShapeTree(spTree, rels, slidePath, archive, colorResolver, context, fillContext, fontScheme, orderedChildren, fmtScheme, placeholderStyles) {
3034
3038
  if (!spTree) return [];
3035
3039
  if (orderedChildren) {
3036
3040
  return parseShapeTreeOrdered(
@@ -3043,7 +3047,8 @@ function parseShapeTree(spTree, rels, slidePath, archive, colorResolver, context
3043
3047
  context,
3044
3048
  fillContext,
3045
3049
  fontScheme,
3046
- fmtScheme
3050
+ fmtScheme,
3051
+ placeholderStyles
3047
3052
  );
3048
3053
  }
3049
3054
  const alternateContents = spTree.AlternateContent ?? [];
@@ -3064,7 +3069,8 @@ function parseShapeTree(spTree, rels, slidePath, archive, colorResolver, context
3064
3069
  fillContext,
3065
3070
  fontScheme,
3066
3071
  void 0,
3067
- fmtScheme
3072
+ fmtScheme,
3073
+ placeholderStyles
3068
3074
  );
3069
3075
  if (shape) {
3070
3076
  elements.push(shape);
@@ -3120,7 +3126,7 @@ function parseShapeTree(spTree, rels, slidePath, archive, colorResolver, context
3120
3126
  }
3121
3127
  return elements;
3122
3128
  }
3123
- function parseShapeTreeOrdered(spTree, orderedChildren, rels, slidePath, archive, colorResolver, context, fillContext, fontScheme, fmtScheme) {
3129
+ function parseShapeTreeOrdered(spTree, orderedChildren, rels, slidePath, archive, colorResolver, context, fillContext, fontScheme, fmtScheme, placeholderStyles) {
3124
3130
  const ctx = context ?? slidePath;
3125
3131
  const elements = [];
3126
3132
  const tagCounters = {};
@@ -3162,7 +3168,8 @@ function parseShapeTreeOrdered(spTree, orderedChildren, rels, slidePath, archive
3162
3168
  ctx,
3163
3169
  fillContext,
3164
3170
  fontScheme,
3165
- fmtScheme
3171
+ fmtScheme,
3172
+ placeholderStyles
3166
3173
  );
3167
3174
  }
3168
3175
  }
@@ -3186,12 +3193,13 @@ function parseShapeTreeOrdered(spTree, orderedChildren, rels, slidePath, archive
3186
3193
  ctx,
3187
3194
  fillContext,
3188
3195
  fontScheme,
3189
- fmtScheme
3196
+ fmtScheme,
3197
+ placeholderStyles
3190
3198
  );
3191
3199
  }
3192
3200
  return elements;
3193
3201
  }
3194
- function parseAndPushElement(tag, element, orderedNode, elements, rels, slidePath, archive, colorResolver, ctx, fillContext, fontScheme, fmtScheme) {
3202
+ function parseAndPushElement(tag, element, orderedNode, elements, rels, slidePath, archive, colorResolver, ctx, fillContext, fontScheme, fmtScheme, placeholderStyles) {
3195
3203
  switch (tag) {
3196
3204
  case "sp": {
3197
3205
  const shape = parseShape(
@@ -3201,7 +3209,8 @@ function parseAndPushElement(tag, element, orderedNode, elements, rels, slidePat
3201
3209
  fillContext,
3202
3210
  fontScheme,
3203
3211
  orderedNode,
3204
- fmtScheme
3212
+ fmtScheme,
3213
+ placeholderStyles
3205
3214
  );
3206
3215
  if (shape) {
3207
3216
  elements.push(shape);
@@ -3266,22 +3275,42 @@ function parseAndPushElement(tag, element, orderedNode, elements, rels, slidePat
3266
3275
  }
3267
3276
  }
3268
3277
  }
3269
- function parseShape(sp, colorResolver, rels, fillContext, fontScheme, orderedNode, fmtScheme) {
3278
+ function parseShape(sp, colorResolver, rels, fillContext, fontScheme, orderedNode, fmtScheme, placeholderStyles) {
3270
3279
  const spPr = sp.spPr;
3271
- if (!spPr) return null;
3272
- const transform = parseTransform(spPr.xfrm);
3280
+ const spPrIsObject = spPr != null && typeof spPr === "object";
3281
+ const nvSpPr = sp.nvSpPr;
3282
+ const nvPr = nvSpPr?.nvPr;
3283
+ const ph = nvPr?.ph;
3284
+ const placeholderType = ph ? ph["@_type"] ?? "body" : void 0;
3285
+ const placeholderIdx = ph?.["@_idx"] !== void 0 ? Number(ph["@_idx"]) : void 0;
3286
+ let transform = null;
3287
+ let geometry;
3288
+ if (spPrIsObject) {
3289
+ transform = parseTransform(spPr.xfrm);
3290
+ geometry = parseGeometry(spPr);
3291
+ } else {
3292
+ geometry = { type: "preset", preset: "rect", adjustValues: {} };
3293
+ }
3294
+ if (!transform && placeholderType && placeholderStyles) {
3295
+ const inherited = findMatchingPlaceholder(placeholderType, placeholderIdx, placeholderStyles);
3296
+ if (inherited?.transform) {
3297
+ transform = inherited.transform;
3298
+ }
3299
+ if (!spPrIsObject && inherited?.geometry) {
3300
+ geometry = inherited.geometry;
3301
+ }
3302
+ }
3273
3303
  if (!transform) return null;
3274
- if (spPr.scene3d) {
3304
+ if (spPrIsObject && spPr.scene3d) {
3275
3305
  warn("spPr.scene3d", "3D scene/camera not implemented");
3276
3306
  }
3277
- if (spPr.sp3d) {
3307
+ if (spPrIsObject && spPr.sp3d) {
3278
3308
  warn("spPr.sp3d", "3D extrusion/bevel not implemented");
3279
3309
  }
3280
- const geometry = parseGeometry(spPr);
3281
3310
  const styleRef = resolveShapeStyle(sp.style, fmtScheme, colorResolver);
3282
- const directFill = parseFillFromNode(spPr, colorResolver, fillContext);
3311
+ const directFill = spPrIsObject ? parseFillFromNode(spPr, colorResolver, fillContext) : null;
3283
3312
  const fill = directFill ?? styleRef?.fill ?? null;
3284
- const directOutline = parseOutline(spPr.ln, colorResolver);
3313
+ const directOutline = spPrIsObject ? parseOutline(spPr.ln, colorResolver) : null;
3285
3314
  const outline = directOutline ?? styleRef?.outline ?? null;
3286
3315
  let orderedTxBody;
3287
3316
  if (orderedNode) {
@@ -3299,16 +3328,11 @@ function parseShape(sp, colorResolver, rels, fillContext, fontScheme, orderedNod
3299
3328
  void 0,
3300
3329
  orderedTxBody
3301
3330
  );
3302
- const directEffects = parseEffectList(spPr.effectLst, colorResolver);
3331
+ const directEffects = spPrIsObject ? parseEffectList(spPr.effectLst, colorResolver) : null;
3303
3332
  const effects = directEffects ?? styleRef?.effects ?? null;
3304
- const nvSpPr = sp.nvSpPr;
3305
3333
  const cNvPr = nvSpPr?.cNvPr;
3306
3334
  const altText = cNvPr?.["@_descr"];
3307
3335
  const hyperlink = parseHyperlink(cNvPr?.hlinkClick, rels);
3308
- const nvPr = nvSpPr?.nvPr;
3309
- const ph = nvPr?.ph;
3310
- const placeholderType = ph ? ph["@_type"] ?? "body" : void 0;
3311
- const placeholderIdx = ph?.["@_idx"] !== void 0 ? Number(ph["@_idx"]) : void 0;
3312
3336
  return {
3313
3337
  type: "shape",
3314
3338
  transform,
@@ -3662,6 +3686,31 @@ function parseGeometry(spPr) {
3662
3686
  }
3663
3687
  return { type: "preset", preset: "rect", adjustValues: {} };
3664
3688
  }
3689
+ function findMatchingPlaceholder(placeholderType, placeholderIdx, styles) {
3690
+ if (placeholderIdx !== void 0) {
3691
+ const byIdx = styles.find((s) => s.placeholderIdx === placeholderIdx && s.transform);
3692
+ if (byIdx) return byIdx;
3693
+ const byIdxAny = styles.find((s) => s.placeholderIdx === placeholderIdx);
3694
+ if (byIdxAny) return byIdxAny;
3695
+ }
3696
+ const byTypeWithTransform = styles.find(
3697
+ (s) => s.placeholderType === placeholderType && s.transform
3698
+ );
3699
+ if (byTypeWithTransform) return byTypeWithTransform;
3700
+ const fallbackType = placeholderType === "ctrTitle" ? "title" : placeholderType === "subTitle" ? "body" : void 0;
3701
+ if (fallbackType) {
3702
+ const byFallbackWithTransform = styles.find(
3703
+ (s) => s.placeholderType === fallbackType && s.transform
3704
+ );
3705
+ if (byFallbackWithTransform) return byFallbackWithTransform;
3706
+ }
3707
+ const byType = styles.find((s) => s.placeholderType === placeholderType);
3708
+ if (byType) return byType;
3709
+ if (fallbackType) {
3710
+ return styles.find((s) => s.placeholderType === fallbackType);
3711
+ }
3712
+ return void 0;
3713
+ }
3665
3714
  function parseTextBody(txBody, colorResolver, rels, fontScheme, lstStyleOverride, orderedTxBody) {
3666
3715
  if (!txBody) return null;
3667
3716
  const bodyPr = txBody.bodyPr;
@@ -4091,10 +4140,15 @@ function parseSlideLayoutPlaceholderStyles(xml, colorResolver) {
4091
4140
  const txBody = sp.txBody;
4092
4141
  const lstStyleNode = txBody?.lstStyle;
4093
4142
  const lstStyle = lstStyleNode ? parseListStyle(lstStyleNode, colorResolver) : void 0;
4143
+ const spPr = sp.spPr;
4144
+ const transform = spPr && typeof spPr === "object" ? parseTransform(spPr.xfrm) : null;
4145
+ const geometry = spPr && typeof spPr === "object" ? parseGeometry(spPr) : void 0;
4094
4146
  results.push({
4095
4147
  placeholderType,
4096
4148
  ...placeholderIdx !== void 0 && { placeholderIdx },
4097
- ...lstStyle && { lstStyle }
4149
+ ...lstStyle && { lstStyle },
4150
+ ...transform && { transform },
4151
+ ...geometry && { geometry }
4098
4152
  });
4099
4153
  }
4100
4154
  return results;
@@ -4211,10 +4265,15 @@ function parseSlideMasterPlaceholderStyles(xml, colorResolver) {
4211
4265
  const txBody = sp.txBody;
4212
4266
  const lstStyleNode = txBody?.lstStyle;
4213
4267
  const lstStyle = lstStyleNode ? parseListStyle(lstStyleNode, colorResolver) : void 0;
4268
+ const spPr = sp.spPr;
4269
+ const transform = spPr && typeof spPr === "object" ? parseTransform(spPr.xfrm) : null;
4270
+ const geometry = spPr && typeof spPr === "object" ? parseGeometry(spPr) : void 0;
4214
4271
  results.push({
4215
4272
  placeholderType,
4216
4273
  ...placeholderIdx !== void 0 && { placeholderIdx },
4217
- ...lstStyle && { lstStyle }
4274
+ ...lstStyle && { lstStyle },
4275
+ ...transform && { transform },
4276
+ ...geometry && { geometry }
4218
4277
  });
4219
4278
  }
4220
4279
  return results;
@@ -4665,6 +4724,17 @@ function parseSlideWithLayout(slideNumber, path, data) {
4665
4724
  slideMasterData,
4666
4725
  data.theme
4667
4726
  );
4727
+ let layoutPlaceholderStyles = [];
4728
+ let layoutShowMasterSp = true;
4729
+ if (layoutXml) {
4730
+ layoutPlaceholderStyles = parseSlideLayoutPlaceholderStyles(layoutXml, slideColorResolver);
4731
+ layoutShowMasterSp = parseSlideLayoutShowMasterSp(layoutXml);
4732
+ }
4733
+ const masterPlaceholderStyles = slideMasterData?.placeholderStyles ?? data.masterPlaceholderStyles;
4734
+ const mergedPlaceholderStyles = mergePlaceholderGeometry(
4735
+ layoutPlaceholderStyles,
4736
+ masterPlaceholderStyles
4737
+ );
4668
4738
  const slide = parseSlide(
4669
4739
  slideXml,
4670
4740
  path,
@@ -4672,11 +4742,10 @@ function parseSlideWithLayout(slideNumber, path, data) {
4672
4742
  data.archive,
4673
4743
  slideColorResolver,
4674
4744
  data.theme.fontScheme,
4675
- data.theme.fmtScheme
4745
+ data.theme.fmtScheme,
4746
+ mergedPlaceholderStyles
4676
4747
  );
4677
4748
  let layoutElements = [];
4678
- let layoutPlaceholderStyles = [];
4679
- let layoutShowMasterSp = true;
4680
4749
  if (layoutXml && layoutPath) {
4681
4750
  if (!slide.background) {
4682
4751
  const layoutFillContext = {
@@ -4698,13 +4767,10 @@ function parseSlideWithLayout(slideNumber, path, data) {
4698
4767
  data.theme.fontScheme,
4699
4768
  data.theme.fmtScheme
4700
4769
  );
4701
- layoutPlaceholderStyles = parseSlideLayoutPlaceholderStyles(layoutXml, slideColorResolver);
4702
- layoutShowMasterSp = parseSlideLayoutShowMasterSp(layoutXml);
4703
4770
  }
4704
4771
  if (!slide.background) {
4705
4772
  slide.background = slideMasterData?.background ?? data.masterBackground;
4706
4773
  }
4707
- const masterPlaceholderStyles = slideMasterData?.placeholderStyles ?? data.masterPlaceholderStyles;
4708
4774
  const masterTxStyles = slideMasterData?.txStyles ?? data.masterTxStyles;
4709
4775
  applyTextStyleInheritance(slide.elements, {
4710
4776
  layoutPlaceholderStyles,
@@ -4716,6 +4782,38 @@ function parseSlideWithLayout(slideNumber, path, data) {
4716
4782
  const masterElements = slideMasterData?.elements ?? data.masterElements;
4717
4783
  return { slide, layoutElements, layoutShowMasterSp, masterElements };
4718
4784
  }
4785
+ function mergePlaceholderGeometry(layoutStyles, masterStyles) {
4786
+ const merged = layoutStyles.map((ls) => {
4787
+ if (ls.transform) return ls;
4788
+ const masterMatch = findPlaceholderByTypeAndIdx(
4789
+ ls.placeholderType,
4790
+ ls.placeholderIdx,
4791
+ masterStyles
4792
+ );
4793
+ if (!masterMatch) return ls;
4794
+ return {
4795
+ ...ls,
4796
+ ...!ls.transform && masterMatch.transform && { transform: masterMatch.transform },
4797
+ ...!ls.geometry && masterMatch.geometry && { geometry: masterMatch.geometry }
4798
+ };
4799
+ });
4800
+ for (const ms of masterStyles) {
4801
+ const exists = merged.some(
4802
+ (m) => m.placeholderType === ms.placeholderType && m.placeholderIdx === ms.placeholderIdx
4803
+ );
4804
+ if (!exists) {
4805
+ merged.push(ms);
4806
+ }
4807
+ }
4808
+ return merged;
4809
+ }
4810
+ function findPlaceholderByTypeAndIdx(type, idx, styles) {
4811
+ if (idx !== void 0) {
4812
+ const byIdx = styles.find((s) => s.placeholderIdx === idx);
4813
+ if (byIdx) return byIdx;
4814
+ }
4815
+ return styles.find((s) => s.placeholderType === type);
4816
+ }
4719
4817
  function defaultColorScheme2() {
4720
4818
  return {
4721
4819
  dk1: "#000000",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pptx-glimpse",
3
- "version": "0.5.0",
3
+ "version": "0.6.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",
@@ -64,10 +64,10 @@
64
64
  "author": "hirokisakabe",
65
65
  "license": "MIT",
66
66
  "dependencies": {
67
+ "@resvg/resvg-js": "^2.6.2",
67
68
  "fast-xml-parser": "^5.3.6",
68
69
  "fflate": "^0.8.2",
69
- "opentype.js": "^1.3.4",
70
- "sharp": "^0.34.5"
70
+ "opentype.js": "^1.3.4"
71
71
  },
72
72
  "devDependencies": {
73
73
  "@changesets/cli": "^2.29.8",
@@ -81,6 +81,7 @@
81
81
  "knip": "^5.85.0",
82
82
  "pixelmatch": "^7.1.0",
83
83
  "prettier": "^3.0.0",
84
+ "sharp": "^0.34.5",
84
85
  "tsup": "^8.0.0",
85
86
  "tsx": "^4.21.0",
86
87
  "typescript": "^5.9.3",