ppt2json 0.2.0 → 0.3.0

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.js CHANGED
@@ -33,8 +33,7 @@ __export(index_exports, {
33
33
  parsePptxToJson: () => parsePptxToJson
34
34
  });
35
35
  module.exports = __toCommonJS(index_exports);
36
- var import_jszip2 = __toESM(require("jszip"));
37
- var import_json2pptx = require("json2pptx");
36
+ var import_json2pptx_schema = require("json2pptx-schema");
38
37
 
39
38
  // parser/parse.ts
40
39
  var import_jszip = __toESM(require("jszip"));
@@ -3159,176 +3158,8 @@ function shapeArc(cX, cY, rX, rY, stAng, endAng, isClose) {
3159
3158
  }
3160
3159
  function getCustomShapePath(custShapType, w, h) {
3161
3160
  const pathLstNode = getTextByPathList(custShapType, ["a:pathLst"]);
3162
- let pathNodes = getTextByPathList(pathLstNode, ["a:path"]);
3163
- if (Array.isArray(pathNodes)) pathNodes = pathNodes.shift();
3164
- const maxX = parseInt(pathNodes["attrs"]["w"]);
3165
- const maxY = parseInt(pathNodes["attrs"]["h"]);
3166
- const cX = maxX === 0 ? 0 : 1 / maxX * w;
3167
- const cY = maxY === 0 ? 0 : 1 / maxY * h;
3168
- let d = "";
3169
- let moveToNode = getTextByPathList(pathNodes, ["a:moveTo"]);
3170
- let lnToNodes = pathNodes["a:lnTo"];
3171
- let cubicBezToNodes = pathNodes["a:cubicBezTo"];
3172
- let quadBezToNodes = pathNodes["a:quadBezTo"];
3173
- const arcToNodes = pathNodes["a:arcTo"];
3174
- let closeNode = getTextByPathList(pathNodes, ["a:close"]);
3175
- if (!Array.isArray(moveToNode)) moveToNode = [moveToNode];
3176
- const multiSapeAry = [];
3177
- if (moveToNode.length > 0) {
3178
- Object.keys(moveToNode).forEach((key) => {
3179
- const moveToPtNode = moveToNode[key]["a:pt"];
3180
- if (moveToPtNode) {
3181
- Object.keys(moveToPtNode).forEach((key2) => {
3182
- const moveToNoPt = moveToPtNode[key2];
3183
- const spX = moveToNoPt["attrs"]?.["x"];
3184
- const spY = moveToNoPt["attrs"]?.["y"];
3185
- const order = moveToNoPt["attrs"]?.["order"];
3186
- multiSapeAry.push({
3187
- type: "movto",
3188
- x: spX,
3189
- y: spY,
3190
- order
3191
- });
3192
- });
3193
- }
3194
- });
3195
- if (lnToNodes) {
3196
- if (!Array.isArray(lnToNodes)) lnToNodes = [lnToNodes];
3197
- Object.keys(lnToNodes).forEach((key) => {
3198
- const lnToPtNode = lnToNodes[key]["a:pt"];
3199
- if (lnToPtNode) {
3200
- Object.keys(lnToPtNode).forEach((key2) => {
3201
- const lnToNoPt = lnToPtNode[key2];
3202
- const ptX = lnToNoPt["attrs"]?.["x"];
3203
- const ptY = lnToNoPt["attrs"]?.["y"];
3204
- const order = lnToNoPt["attrs"]?.["order"];
3205
- multiSapeAry.push({
3206
- type: "lnto",
3207
- x: ptX,
3208
- y: ptY,
3209
- order
3210
- });
3211
- });
3212
- }
3213
- });
3214
- }
3215
- if (cubicBezToNodes) {
3216
- const cubicBezToPtNodesAry = [];
3217
- if (!Array.isArray(cubicBezToNodes)) cubicBezToNodes = [cubicBezToNodes];
3218
- Object.keys(cubicBezToNodes).forEach((key) => {
3219
- cubicBezToPtNodesAry.push(cubicBezToNodes[key]["a:pt"]);
3220
- });
3221
- cubicBezToPtNodesAry.forEach((key) => {
3222
- const pts_ary = [];
3223
- key.forEach((pt) => {
3224
- const pt_obj = {
3225
- x: pt["attrs"]["x"],
3226
- y: pt["attrs"]["y"]
3227
- };
3228
- pts_ary.push(pt_obj);
3229
- });
3230
- const order = key[0]["attrs"]["order"];
3231
- multiSapeAry.push({
3232
- type: "cubicBezTo",
3233
- cubBzPt: pts_ary,
3234
- order
3235
- });
3236
- });
3237
- }
3238
- if (quadBezToNodes) {
3239
- const quadBezToPtNodesAry = [];
3240
- if (!Array.isArray(quadBezToNodes)) quadBezToNodes = [quadBezToNodes];
3241
- Object.keys(quadBezToNodes).forEach((key) => {
3242
- quadBezToPtNodesAry.push(quadBezToNodes[key]["a:pt"]);
3243
- });
3244
- quadBezToPtNodesAry.forEach((key) => {
3245
- const pts_ary = [];
3246
- key.forEach((pt) => {
3247
- const pt_obj = {
3248
- x: pt["attrs"]["x"],
3249
- y: pt["attrs"]["y"]
3250
- };
3251
- pts_ary.push(pt_obj);
3252
- });
3253
- const order = key[0]["attrs"]["order"];
3254
- multiSapeAry.push({
3255
- type: "quadBezTo",
3256
- quadBzPt: pts_ary,
3257
- order
3258
- });
3259
- });
3260
- }
3261
- if (arcToNodes) {
3262
- const arcToNodesAttrs = arcToNodes["attrs"];
3263
- const order = arcToNodesAttrs["order"];
3264
- const hR = arcToNodesAttrs["hR"];
3265
- const wR = arcToNodesAttrs["wR"];
3266
- const stAng = arcToNodesAttrs["stAng"];
3267
- const swAng = arcToNodesAttrs["swAng"];
3268
- let shftX = 0;
3269
- let shftY = 0;
3270
- const arcToPtNode = getTextByPathList(arcToNodes, ["a:pt", "attrs"]);
3271
- if (arcToPtNode) {
3272
- shftX = arcToPtNode["x"];
3273
- shftY = arcToPtNode["y"];
3274
- }
3275
- multiSapeAry.push({
3276
- type: "arcTo",
3277
- hR,
3278
- wR,
3279
- stAng,
3280
- swAng,
3281
- shftX,
3282
- shftY,
3283
- order
3284
- });
3285
- }
3286
- if (closeNode) {
3287
- if (!Array.isArray(closeNode)) closeNode = [closeNode];
3288
- Object.keys(closeNode).forEach(() => {
3289
- multiSapeAry.push({
3290
- type: "close",
3291
- order: Infinity
3292
- });
3293
- });
3294
- }
3295
- multiSapeAry.sort((a, b) => a.order - b.order);
3296
- let k = 0;
3297
- while (k < multiSapeAry.length) {
3298
- if (multiSapeAry[k].type === "movto") {
3299
- const spX = parseInt(multiSapeAry[k].x) * cX;
3300
- const spY = parseInt(multiSapeAry[k].y) * cY;
3301
- d += " M" + spX + "," + spY;
3302
- } else if (multiSapeAry[k].type === "lnto") {
3303
- const Lx = parseInt(multiSapeAry[k].x) * cX;
3304
- const Ly = parseInt(multiSapeAry[k].y) * cY;
3305
- d += " L" + Lx + "," + Ly;
3306
- } else if (multiSapeAry[k].type === "cubicBezTo") {
3307
- const Cx1 = parseInt(multiSapeAry[k].cubBzPt[0].x) * cX;
3308
- const Cy1 = parseInt(multiSapeAry[k].cubBzPt[0].y) * cY;
3309
- const Cx2 = parseInt(multiSapeAry[k].cubBzPt[1].x) * cX;
3310
- const Cy2 = parseInt(multiSapeAry[k].cubBzPt[1].y) * cY;
3311
- const Cx3 = parseInt(multiSapeAry[k].cubBzPt[2].x) * cX;
3312
- const Cy3 = parseInt(multiSapeAry[k].cubBzPt[2].y) * cY;
3313
- d += " C" + Cx1 + "," + Cy1 + " " + Cx2 + "," + Cy2 + " " + Cx3 + "," + Cy3;
3314
- } else if (multiSapeAry[k].type === "quadBezTo") {
3315
- const Qx1 = parseInt(multiSapeAry[k].quadBzPt[0].x) * cX;
3316
- const Qy1 = parseInt(multiSapeAry[k].quadBzPt[0].y) * cY;
3317
- const Qx2 = parseInt(multiSapeAry[k].quadBzPt[1].x) * cX;
3318
- const Qy2 = parseInt(multiSapeAry[k].quadBzPt[1].y) * cY;
3319
- d += " Q" + Qx1 + "," + Qy1 + " " + Qx2 + "," + Qy2;
3320
- } else if (multiSapeAry[k].type === "arcTo") {
3321
- const hR = parseInt(multiSapeAry[k].hR) * cX;
3322
- const wR = parseInt(multiSapeAry[k].wR) * cY;
3323
- const stAng = parseInt(multiSapeAry[k].stAng) / 6e4;
3324
- const swAng = parseInt(multiSapeAry[k].swAng) / 6e4;
3325
- const endAng = stAng + swAng;
3326
- d += shapeArc(wR, hR, wR, hR, stAng, endAng, false);
3327
- } else if (multiSapeAry[k].type === "close") d += "z";
3328
- k++;
3329
- }
3330
- }
3331
- return d;
3161
+ const pathNodes = normalizeToArray(getTextByPathList(pathLstNode, ["a:path"]));
3162
+ return pathNodes.map((pathNode) => buildCustomShapeSegment(pathNode, w, h)).filter(Boolean).join(" ");
3332
3163
  }
3333
3164
  function identifyShape(shapeData) {
3334
3165
  const pathLst = shapeData["a:pathLst"];
@@ -3343,16 +3174,16 @@ function identifyShape(shapeData) {
3343
3174
  }
3344
3175
  function extractPathCommands(path) {
3345
3176
  const commands = [];
3346
- if (path["a:moveTo"]) {
3347
- const moveTo = path["a:moveTo"];
3348
- const pt = moveTo["a:pt"];
3177
+ const moveToList = normalizeToArray(path["a:moveTo"]);
3178
+ moveToList.forEach((moveTo) => {
3179
+ const pt = Array.isArray(moveTo?.["a:pt"]) ? moveTo["a:pt"][0] : moveTo?.["a:pt"];
3349
3180
  if (pt) {
3350
3181
  commands.push({
3351
3182
  type: "moveTo",
3352
3183
  points: [{ x: parseInt(pt.attrs?.x) || 0, y: parseInt(pt.attrs?.y) || 0 }]
3353
3184
  });
3354
3185
  }
3355
- }
3186
+ });
3356
3187
  const lineToList = normalizeToArray(path["a:lnTo"]);
3357
3188
  lineToList.forEach((lnTo) => {
3358
3189
  const pt = lnTo["a:pt"];
@@ -3402,6 +3233,55 @@ function normalizeToArray(value) {
3402
3233
  if (!value) return [];
3403
3234
  return Array.isArray(value) ? value : [value];
3404
3235
  }
3236
+ function buildCustomShapeSegment(pathNode, w, h) {
3237
+ if (!pathNode || typeof pathNode !== "object") return "";
3238
+ const maxX = parseInt(pathNode.attrs?.w) || 0;
3239
+ const maxY = parseInt(pathNode.attrs?.h) || 0;
3240
+ const scaleX = maxX === 0 ? 0 : w / maxX;
3241
+ const scaleY = maxY === 0 ? 0 : h / maxY;
3242
+ const commands = extractPathCommands(pathNode);
3243
+ if (!commands.length) return "";
3244
+ return commands.map((command) => mapCommandToPath(command, scaleX, scaleY)).filter(Boolean).join(" ");
3245
+ }
3246
+ function mapCommandToPath(command, scaleX, scaleY) {
3247
+ switch (command.type) {
3248
+ case "moveTo": {
3249
+ const point = command.points?.[0];
3250
+ return `M${scaleValue(point?.x, scaleX)},${scaleValue(point?.y, scaleY)}`;
3251
+ }
3252
+ case "lineTo": {
3253
+ const point = command.points?.[0];
3254
+ return `L${scaleValue(point?.x, scaleX)},${scaleValue(point?.y, scaleY)}`;
3255
+ }
3256
+ case "cubicBezTo": {
3257
+ if (!Array.isArray(command.points) || command.points.length < 3) return "";
3258
+ const [p1, p2, p3] = command.points;
3259
+ return `C${scaleValue(p1?.x, scaleX)},${scaleValue(p1?.y, scaleY)} ${scaleValue(p2?.x, scaleX)},${scaleValue(p2?.y, scaleY)} ${scaleValue(p3?.x, scaleX)},${scaleValue(p3?.y, scaleY)}`;
3260
+ }
3261
+ case "quadBezTo": {
3262
+ if (!Array.isArray(command.points) || command.points.length < 2) return "";
3263
+ const [p1, p2] = command.points;
3264
+ return `Q${scaleValue(p1?.x, scaleX)},${scaleValue(p1?.y, scaleY)} ${scaleValue(p2?.x, scaleX)},${scaleValue(p2?.y, scaleY)}`;
3265
+ }
3266
+ case "arcTo": {
3267
+ const startAngle = (parseInt(command.stAng) || 0) / 6e4;
3268
+ const sweepAngle = (parseInt(command.swAng) || 0) / 6e4;
3269
+ const endAngle = startAngle + sweepAngle;
3270
+ const radiusX = scaleValue(command.wR, scaleX);
3271
+ const radiusY = scaleValue(command.hR, scaleY);
3272
+ return shapeArc(radiusX, radiusY, radiusX, radiusY, startAngle, endAngle, false).trim();
3273
+ }
3274
+ case "close":
3275
+ return "z";
3276
+ default:
3277
+ return "";
3278
+ }
3279
+ }
3280
+ function scaleValue(value, scale) {
3281
+ const numeric = typeof value === "number" ? value : parseFloat(String(value ?? 0));
3282
+ if (!Number.isFinite(numeric) || !Number.isFinite(scale)) return 0;
3283
+ return numeric * scale;
3284
+ }
3405
3285
  function analyzePathCommands(commands, pathWidth, pathHeight) {
3406
3286
  const analysis = {
3407
3287
  lineCount: 0,
@@ -9340,6 +9220,7 @@ async function genDiagram(node, warpObj) {
9340
9220
 
9341
9221
  // utils.ts
9342
9222
  var PT_TO_PX = 96 / 72;
9223
+ var EXPORTED_OBJECT_NAME_RE = /^(shape-text|shape|text)-(\d+)-(.+)$/;
9343
9224
  function toPx(value) {
9344
9225
  if (value === void 0 || value === null) return void 0;
9345
9226
  return value * PT_TO_PX;
@@ -9357,18 +9238,80 @@ function mapFillColor(value) {
9357
9238
  if (!value) return void 0;
9358
9239
  return value.startsWith("#") ? value : `#${value}`;
9359
9240
  }
9241
+ function parseExportedObjectName(name) {
9242
+ if (!name) return void 0;
9243
+ const match = name.match(EXPORTED_OBJECT_NAME_RE);
9244
+ if (!match) return void 0;
9245
+ const slideIndex = Number.parseInt(match[2], 10);
9246
+ if (!Number.isFinite(slideIndex)) return void 0;
9247
+ return {
9248
+ kind: match[1],
9249
+ slideIndex,
9250
+ refId: match[3]
9251
+ };
9252
+ }
9253
+ function parseGradientPosition(value) {
9254
+ if (typeof value === "number" && Number.isFinite(value)) {
9255
+ return value > 100 ? value / 1e3 : value;
9256
+ }
9257
+ if (typeof value !== "string") return 0;
9258
+ const numeric = Number.parseFloat(value);
9259
+ if (!Number.isFinite(numeric)) return 0;
9260
+ if (value.trim().endsWith("%")) return numeric;
9261
+ return numeric > 100 ? numeric / 1e3 : numeric;
9262
+ }
9263
+ function mapGradient(value) {
9264
+ if (!value || typeof value !== "object") return void 0;
9265
+ const colors = Array.isArray(value.colors) ? value.colors.filter((stop) => stop && typeof stop === "object").map((stop) => ({
9266
+ pos: parseGradientPosition(stop.pos),
9267
+ color: mapFillColor(stop.color) ?? "#FFFFFF"
9268
+ })) : [];
9269
+ return {
9270
+ type: typeof value.type === "string" ? value.type === "line" ? "linear" : value.type : typeof value.path === "string" ? value.path === "line" ? "linear" : value.path : "linear",
9271
+ rotate: typeof value.rotate === "number" ? value.rotate : typeof value.rot === "number" ? value.rot : 0,
9272
+ colors
9273
+ };
9274
+ }
9360
9275
  function mapFill(fill) {
9361
- if (!fill) return {};
9362
- if (typeof fill === "string") return { fill: mapFillColor(fill) ?? void 0 };
9363
- if (typeof fill === "object") {
9364
- if (fill.type === "color" && typeof fill.value === "string") {
9365
- return { fill: mapFillColor(fill.value) ?? void 0 };
9366
- }
9367
- if (fill.type === "image" && fill.value?.picBase64) {
9368
- return { fill: "", pattern: fill.value.picBase64 };
9369
- }
9276
+ if (!fill) return void 0;
9277
+ if (typeof fill === "string") {
9278
+ const color = mapFillColor(fill);
9279
+ return color ? { type: "solid", color } : void 0;
9280
+ }
9281
+ if (typeof fill !== "object") {
9282
+ return void 0;
9283
+ }
9284
+ if (fill.type === "color" && typeof fill.value === "string") {
9285
+ const color = mapFillColor(fill.value);
9286
+ return color ? { type: "solid", color } : void 0;
9287
+ }
9288
+ if (fill.type === "solid" || fill.type === void 0 && typeof fill.color === "string") {
9289
+ const color = mapFillColor(fill.color);
9290
+ return color ? { type: "solid", color } : void 0;
9370
9291
  }
9371
- return {};
9292
+ if (fill.type === "gradient") {
9293
+ const gradient = mapGradient(fill.value ?? fill.gradient ?? fill);
9294
+ return gradient ? { type: "gradient", gradient } : void 0;
9295
+ }
9296
+ if ((fill.type === "image" || fill.type === "pattern") && fill.value?.picBase64) {
9297
+ return {
9298
+ type: "image",
9299
+ src: fill.value.picBase64,
9300
+ ...typeof fill.value.opacity === "number" ? { opacity: fill.value.opacity } : {}
9301
+ };
9302
+ }
9303
+ if (fill.type === "image" && typeof fill.src === "string") {
9304
+ return {
9305
+ type: "image",
9306
+ src: fill.src,
9307
+ ...typeof fill.opacity === "number" ? { opacity: fill.opacity } : {}
9308
+ };
9309
+ }
9310
+ if (fill.gradient || fill.colors) {
9311
+ const gradient = mapGradient(fill.gradient ?? fill);
9312
+ return gradient ? { type: "gradient", gradient } : void 0;
9313
+ }
9314
+ return void 0;
9372
9315
  }
9373
9316
  function convertFontSizeToPx(content) {
9374
9317
  return content.replace(/font-size:\s*([0-9.]+)pt/gi, (_, size) => {
@@ -9493,14 +9436,16 @@ function mapKeypoints(pathFormula, raw) {
9493
9436
  // element-mapper.ts
9494
9437
  function mapElement(raw) {
9495
9438
  if (!raw || !raw.type) return null;
9496
- const base = mapBaseElement(raw);
9497
- if (raw.type === "text") {
9439
+ const exportedMeta = parseExportedObjectName(raw.name);
9440
+ const base = mapBaseElement(raw, exportedMeta);
9441
+ if (raw.type === "text" || isExportedTextShape(raw, exportedMeta)) {
9498
9442
  const content = raw.content !== void 0 ? normalizeTextContent(raw.content) : raw.content;
9499
9443
  const fallbackLineHeight = hasMultiLineText(content) ? 1.5 : 1;
9500
9444
  const lineHeight = raw.lineHeight ?? fallbackLineHeight;
9501
9445
  const normalizedHeight = normalizeTextHeight(base.height, content, lineHeight);
9502
9446
  return {
9503
9447
  ...base,
9448
+ type: "text",
9504
9449
  height: normalizedHeight,
9505
9450
  rotate: base.rotate ?? 0,
9506
9451
  flipH: void 0,
@@ -9512,7 +9457,7 @@ function mapElement(raw) {
9512
9457
  lineHeight,
9513
9458
  paragraphSpace: raw.paragraphSpace,
9514
9459
  vertical: raw.isVertical,
9515
- fill: mapFill(raw.fill).fill ?? ""
9460
+ fill: mapFill(raw.fill)
9516
9461
  };
9517
9462
  }
9518
9463
  if (raw.type === "image") {
@@ -9537,10 +9482,11 @@ function mapElement(raw) {
9537
9482
  };
9538
9483
  }
9539
9484
  if (raw.type === "shape") {
9540
- const { fill, pattern } = mapFill(raw.fill);
9485
+ const fill = mapFill(raw.fill) ?? { type: "solid", color: "rgba(255,255,255,0)" };
9541
9486
  const pathFormula = mapPathFormula(raw.shapType);
9542
9487
  const keypoints = pathFormula ? mapKeypoints(pathFormula, raw.keypoints) : void 0;
9543
- const hasText = raw.content !== void 0;
9488
+ const normalizedShapeText = raw.content !== void 0 ? normalizeTextContent(raw.content) : void 0;
9489
+ const hasText = hasRenderableText(normalizedShapeText);
9544
9490
  let path = raw.path;
9545
9491
  let viewBox = raw.viewBox ?? [raw.width ?? 0, raw.height ?? 0];
9546
9492
  let special = false;
@@ -9579,17 +9525,17 @@ function mapElement(raw) {
9579
9525
  }
9580
9526
  return {
9581
9527
  ...base,
9528
+ type: "shape",
9582
9529
  rotate: base.rotate ?? 0,
9583
9530
  fixedRatio: false,
9584
9531
  path,
9585
9532
  viewBox,
9586
9533
  pathFormula: pathFormula ?? void 0,
9587
9534
  keypoints: keypoints ?? void 0,
9588
- pattern,
9589
- fill: fill ?? "",
9535
+ fill,
9590
9536
  ...special ? { special: true } : {},
9591
9537
  text: hasText ? {
9592
- content: normalizeTextContent(raw.content),
9538
+ content: normalizedShapeText,
9593
9539
  align: normalizeVAlign(raw.vAlign) ?? "middle",
9594
9540
  defaultColor: normalizeColor(raw.defaultColor) ?? normalizeColor(raw.color) ?? "#333",
9595
9541
  defaultFontName: raw.fontName ?? "",
@@ -9600,6 +9546,7 @@ function mapElement(raw) {
9600
9546
  if (raw.type === "line") {
9601
9547
  return {
9602
9548
  ...base,
9549
+ type: "line",
9603
9550
  start: toPxPair(raw.start),
9604
9551
  end: toPxPair(raw.end),
9605
9552
  broken: toPxPair(raw.broken),
@@ -9636,9 +9583,6 @@ function normalizeElement(element) {
9636
9583
  points: ["", ""]
9637
9584
  };
9638
9585
  }
9639
- if (element.type === "shape" && element.fill) {
9640
- element.fill = mapFillColor(element.fill) ?? element.fill;
9641
- }
9642
9586
  if (element.type === "text" && element.content) {
9643
9587
  element.content = normalizeTextContent(element.content);
9644
9588
  }
@@ -9689,20 +9633,21 @@ function mapOutline(raw) {
9689
9633
  style: raw.borderType
9690
9634
  };
9691
9635
  }
9692
- function mapBaseElement(raw) {
9636
+ function mapBaseElement(raw, exportedMeta) {
9693
9637
  const outline = mapOutline(raw);
9694
9638
  const shadow = mapShadow(raw.shadow);
9695
- const { fill } = mapFill(raw.fill);
9639
+ const fill = mapFill(raw.fill);
9640
+ const exportedId = exportedMeta?.kind === "shape-text" ? `${exportedMeta.refId}__text` : exportedMeta?.refId;
9696
9641
  return {
9697
9642
  type: raw.type,
9698
- id: raw.id,
9643
+ id: exportedId ?? raw.id,
9699
9644
  groupId: raw.groupId,
9700
9645
  left: toPx(raw.left),
9701
9646
  top: toPx(raw.top),
9702
9647
  width: toPx(raw.width),
9703
9648
  height: toPx(raw.height),
9704
9649
  rotate: raw.rotate,
9705
- fill: fill ?? void 0,
9650
+ fill,
9706
9651
  opacity: raw.opacity,
9707
9652
  outline: outline ?? void 0,
9708
9653
  shadow: shadow ?? void 0,
@@ -9710,6 +9655,15 @@ function mapBaseElement(raw) {
9710
9655
  flipV: raw.isFlipV
9711
9656
  };
9712
9657
  }
9658
+ function isExportedTextShape(raw, exportedMeta) {
9659
+ if (raw?.type !== "shape" || !raw?.content) return false;
9660
+ return exportedMeta?.kind === "text" || exportedMeta?.kind === "shape-text";
9661
+ }
9662
+ function hasRenderableText(content) {
9663
+ if (!content) return false;
9664
+ const plainText = content.replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim();
9665
+ return plainText.length > 0;
9666
+ }
9713
9667
 
9714
9668
  // slide-normalizer.ts
9715
9669
  var ID_ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
@@ -9724,7 +9678,8 @@ function normalizeSlide(slide, index) {
9724
9678
  const orderB = typeof b?.order === "number" ? b.order : 0;
9725
9679
  return orderA - orderB;
9726
9680
  });
9727
- const elements = flattenElements(orderedElements).map((element, elementIndex) => {
9681
+ const restoredElements = restoreExportedRoundTripElements(orderedElements);
9682
+ const elements = flattenElements(restoredElements).map((element, elementIndex) => {
9728
9683
  if (!element.id) {
9729
9684
  element.id = makeId(`slide-${index}-element-${elementIndex}-${element.type}`);
9730
9685
  }
@@ -9732,7 +9687,7 @@ function normalizeSlide(slide, index) {
9732
9687
  });
9733
9688
  return {
9734
9689
  id: slide?.id ?? slide?.slideId ?? makeId(`slide-${index}`),
9735
- background: backgroundFill.fill ? { type: "solid", color: backgroundFill.fill } : backgroundFill.pattern ? { type: "image", src: backgroundFill.pattern } : void 0,
9690
+ background: backgroundFill,
9736
9691
  elements,
9737
9692
  remark: slide?.remark ?? ""
9738
9693
  };
@@ -9749,6 +9704,44 @@ function makeId(seed) {
9749
9704
  }
9750
9705
  return id;
9751
9706
  }
9707
+ function restoreExportedRoundTripElements(elements) {
9708
+ const restored = elements.map((element) => {
9709
+ if (element?.type === "group" && Array.isArray(element.elements)) {
9710
+ return {
9711
+ ...element,
9712
+ elements: restoreExportedRoundTripElements(element.elements)
9713
+ };
9714
+ }
9715
+ return element;
9716
+ });
9717
+ const shapesByRefId = /* @__PURE__ */ new Map();
9718
+ for (const element of restored) {
9719
+ const meta = parseExportedObjectName(element?.name);
9720
+ if (meta?.kind === "shape") {
9721
+ shapesByRefId.set(meta.refId, element);
9722
+ }
9723
+ }
9724
+ return restored.filter((element) => {
9725
+ const meta = parseExportedObjectName(element?.name);
9726
+ if (meta?.kind !== "shape-text") {
9727
+ return true;
9728
+ }
9729
+ const targetShape = shapesByRefId.get(meta.refId);
9730
+ if (!targetShape || targetShape.type !== "shape") {
9731
+ return true;
9732
+ }
9733
+ mergeShapeText(targetShape, element);
9734
+ return false;
9735
+ });
9736
+ }
9737
+ function mergeShapeText(targetShape, textShape) {
9738
+ if (!targetShape.content && textShape?.content) {
9739
+ targetShape.content = textShape.content;
9740
+ }
9741
+ if (textShape?.vAlign) {
9742
+ targetShape.vAlign = textShape.vAlign;
9743
+ }
9744
+ }
9752
9745
  function hashSeed(value) {
9753
9746
  let hash = 1779033703 ^ value.length;
9754
9747
  for (let index = 0; index < value.length; index += 1) {
@@ -9782,49 +9775,14 @@ var DEFAULT_THEME = {
9782
9775
  };
9783
9776
  async function parsePptxToJson(file) {
9784
9777
  const fileBuffer = await file.arrayBuffer();
9785
- const zip = await import_jszip2.default.loadAsync(fileBuffer);
9786
- const embedded = import_json2pptx.ENABLE_DECK_JSON ? await resolveEmbeddedDeck(zip) : null;
9787
- if (embedded?.deck) {
9788
- return {
9789
- deck: embedded.deck,
9790
- warnings: embedded.warnings
9791
- };
9792
- }
9793
9778
  return {
9794
9779
  deck: await buildDeckFromPptx(fileBuffer),
9795
- warnings: embedded?.warnings ?? []
9780
+ warnings: []
9796
9781
  };
9797
9782
  }
9798
- async function resolveEmbeddedDeck(zip) {
9799
- const embeddedFile = zip.file(import_json2pptx.PPTX_JSON_PAYLOAD_PATH) ?? Object.values(zip.files).find(
9800
- (entry) => entry.name.endsWith(`/${import_json2pptx.PPTX_JSON_PAYLOAD_PATH}`)
9801
- ) ?? null;
9802
- if (!embeddedFile) {
9803
- return null;
9804
- }
9805
- const payloadText = await embeddedFile.async("string");
9806
- try {
9807
- const parsed = JSON.parse(payloadText);
9808
- if (isDeckEnvelope(parsed) && parsed.deck) {
9809
- return {
9810
- deck: parsed.deck,
9811
- warnings: parsed.version && parsed.version !== import_json2pptx.PPTX_JSON_PAYLOAD_VERSION ? [
9812
- `Embedded JSON payload version ${parsed.version} differs from ${import_json2pptx.PPTX_JSON_PAYLOAD_VERSION}.`
9813
- ] : []
9814
- };
9815
- }
9816
- return {
9817
- deck: parsed,
9818
- warnings: []
9819
- };
9820
- } catch {
9821
- return {
9822
- warnings: ["Embedded JSON payload could not be parsed. Falling back to PPTX parsing."]
9823
- };
9824
- }
9825
- }
9826
- function isDeckEnvelope(payload) {
9827
- return typeof payload === "object" && payload !== null && "deck" in payload;
9783
+ function normalizeDeck(value) {
9784
+ const document = (0, import_json2pptx_schema.parseDocument)(value);
9785
+ return document;
9828
9786
  }
9829
9787
  async function buildDeckFromPptx(buffer) {
9830
9788
  const pptxJson = await parse2(buffer);
@@ -9834,7 +9792,7 @@ async function buildDeckFromPptx(buffer) {
9834
9792
  const slides = (Array.isArray(pptxJson.slides) ? pptxJson.slides : []).map(
9835
9793
  (slide, index) => normalizeSlide(slide, index)
9836
9794
  );
9837
- return {
9795
+ return normalizeDeck({
9838
9796
  title: DEFAULT_DECK_TITLE,
9839
9797
  width,
9840
9798
  height,
@@ -9843,7 +9801,7 @@ async function buildDeckFromPptx(buffer) {
9843
9801
  themeColors
9844
9802
  },
9845
9803
  slides
9846
- };
9804
+ });
9847
9805
  }
9848
9806
  function mapThemeColors(pptxJson) {
9849
9807
  if (!Array.isArray(pptxJson.themeColors)) {