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/README.md +10 -2
- package/dist/index.d.mts +44 -26
- package/dist/index.d.ts +44 -26
- package/dist/index.js +202 -244
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +202 -248
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
// index.ts
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
ENABLE_DECK_JSON,
|
|
5
|
-
PPTX_JSON_PAYLOAD_PATH,
|
|
6
|
-
PPTX_JSON_PAYLOAD_VERSION
|
|
7
|
-
} from "json2pptx";
|
|
2
|
+
import { parseDocument } from "json2pptx-schema";
|
|
8
3
|
|
|
9
4
|
// parser/parse.ts
|
|
10
5
|
import JSZip from "jszip";
|
|
@@ -3129,176 +3124,8 @@ function shapeArc(cX, cY, rX, rY, stAng, endAng, isClose) {
|
|
|
3129
3124
|
}
|
|
3130
3125
|
function getCustomShapePath(custShapType, w, h) {
|
|
3131
3126
|
const pathLstNode = getTextByPathList(custShapType, ["a:pathLst"]);
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
const maxX = parseInt(pathNodes["attrs"]["w"]);
|
|
3135
|
-
const maxY = parseInt(pathNodes["attrs"]["h"]);
|
|
3136
|
-
const cX = maxX === 0 ? 0 : 1 / maxX * w;
|
|
3137
|
-
const cY = maxY === 0 ? 0 : 1 / maxY * h;
|
|
3138
|
-
let d = "";
|
|
3139
|
-
let moveToNode = getTextByPathList(pathNodes, ["a:moveTo"]);
|
|
3140
|
-
let lnToNodes = pathNodes["a:lnTo"];
|
|
3141
|
-
let cubicBezToNodes = pathNodes["a:cubicBezTo"];
|
|
3142
|
-
let quadBezToNodes = pathNodes["a:quadBezTo"];
|
|
3143
|
-
const arcToNodes = pathNodes["a:arcTo"];
|
|
3144
|
-
let closeNode = getTextByPathList(pathNodes, ["a:close"]);
|
|
3145
|
-
if (!Array.isArray(moveToNode)) moveToNode = [moveToNode];
|
|
3146
|
-
const multiSapeAry = [];
|
|
3147
|
-
if (moveToNode.length > 0) {
|
|
3148
|
-
Object.keys(moveToNode).forEach((key) => {
|
|
3149
|
-
const moveToPtNode = moveToNode[key]["a:pt"];
|
|
3150
|
-
if (moveToPtNode) {
|
|
3151
|
-
Object.keys(moveToPtNode).forEach((key2) => {
|
|
3152
|
-
const moveToNoPt = moveToPtNode[key2];
|
|
3153
|
-
const spX = moveToNoPt["attrs"]?.["x"];
|
|
3154
|
-
const spY = moveToNoPt["attrs"]?.["y"];
|
|
3155
|
-
const order = moveToNoPt["attrs"]?.["order"];
|
|
3156
|
-
multiSapeAry.push({
|
|
3157
|
-
type: "movto",
|
|
3158
|
-
x: spX,
|
|
3159
|
-
y: spY,
|
|
3160
|
-
order
|
|
3161
|
-
});
|
|
3162
|
-
});
|
|
3163
|
-
}
|
|
3164
|
-
});
|
|
3165
|
-
if (lnToNodes) {
|
|
3166
|
-
if (!Array.isArray(lnToNodes)) lnToNodes = [lnToNodes];
|
|
3167
|
-
Object.keys(lnToNodes).forEach((key) => {
|
|
3168
|
-
const lnToPtNode = lnToNodes[key]["a:pt"];
|
|
3169
|
-
if (lnToPtNode) {
|
|
3170
|
-
Object.keys(lnToPtNode).forEach((key2) => {
|
|
3171
|
-
const lnToNoPt = lnToPtNode[key2];
|
|
3172
|
-
const ptX = lnToNoPt["attrs"]?.["x"];
|
|
3173
|
-
const ptY = lnToNoPt["attrs"]?.["y"];
|
|
3174
|
-
const order = lnToNoPt["attrs"]?.["order"];
|
|
3175
|
-
multiSapeAry.push({
|
|
3176
|
-
type: "lnto",
|
|
3177
|
-
x: ptX,
|
|
3178
|
-
y: ptY,
|
|
3179
|
-
order
|
|
3180
|
-
});
|
|
3181
|
-
});
|
|
3182
|
-
}
|
|
3183
|
-
});
|
|
3184
|
-
}
|
|
3185
|
-
if (cubicBezToNodes) {
|
|
3186
|
-
const cubicBezToPtNodesAry = [];
|
|
3187
|
-
if (!Array.isArray(cubicBezToNodes)) cubicBezToNodes = [cubicBezToNodes];
|
|
3188
|
-
Object.keys(cubicBezToNodes).forEach((key) => {
|
|
3189
|
-
cubicBezToPtNodesAry.push(cubicBezToNodes[key]["a:pt"]);
|
|
3190
|
-
});
|
|
3191
|
-
cubicBezToPtNodesAry.forEach((key) => {
|
|
3192
|
-
const pts_ary = [];
|
|
3193
|
-
key.forEach((pt) => {
|
|
3194
|
-
const pt_obj = {
|
|
3195
|
-
x: pt["attrs"]["x"],
|
|
3196
|
-
y: pt["attrs"]["y"]
|
|
3197
|
-
};
|
|
3198
|
-
pts_ary.push(pt_obj);
|
|
3199
|
-
});
|
|
3200
|
-
const order = key[0]["attrs"]["order"];
|
|
3201
|
-
multiSapeAry.push({
|
|
3202
|
-
type: "cubicBezTo",
|
|
3203
|
-
cubBzPt: pts_ary,
|
|
3204
|
-
order
|
|
3205
|
-
});
|
|
3206
|
-
});
|
|
3207
|
-
}
|
|
3208
|
-
if (quadBezToNodes) {
|
|
3209
|
-
const quadBezToPtNodesAry = [];
|
|
3210
|
-
if (!Array.isArray(quadBezToNodes)) quadBezToNodes = [quadBezToNodes];
|
|
3211
|
-
Object.keys(quadBezToNodes).forEach((key) => {
|
|
3212
|
-
quadBezToPtNodesAry.push(quadBezToNodes[key]["a:pt"]);
|
|
3213
|
-
});
|
|
3214
|
-
quadBezToPtNodesAry.forEach((key) => {
|
|
3215
|
-
const pts_ary = [];
|
|
3216
|
-
key.forEach((pt) => {
|
|
3217
|
-
const pt_obj = {
|
|
3218
|
-
x: pt["attrs"]["x"],
|
|
3219
|
-
y: pt["attrs"]["y"]
|
|
3220
|
-
};
|
|
3221
|
-
pts_ary.push(pt_obj);
|
|
3222
|
-
});
|
|
3223
|
-
const order = key[0]["attrs"]["order"];
|
|
3224
|
-
multiSapeAry.push({
|
|
3225
|
-
type: "quadBezTo",
|
|
3226
|
-
quadBzPt: pts_ary,
|
|
3227
|
-
order
|
|
3228
|
-
});
|
|
3229
|
-
});
|
|
3230
|
-
}
|
|
3231
|
-
if (arcToNodes) {
|
|
3232
|
-
const arcToNodesAttrs = arcToNodes["attrs"];
|
|
3233
|
-
const order = arcToNodesAttrs["order"];
|
|
3234
|
-
const hR = arcToNodesAttrs["hR"];
|
|
3235
|
-
const wR = arcToNodesAttrs["wR"];
|
|
3236
|
-
const stAng = arcToNodesAttrs["stAng"];
|
|
3237
|
-
const swAng = arcToNodesAttrs["swAng"];
|
|
3238
|
-
let shftX = 0;
|
|
3239
|
-
let shftY = 0;
|
|
3240
|
-
const arcToPtNode = getTextByPathList(arcToNodes, ["a:pt", "attrs"]);
|
|
3241
|
-
if (arcToPtNode) {
|
|
3242
|
-
shftX = arcToPtNode["x"];
|
|
3243
|
-
shftY = arcToPtNode["y"];
|
|
3244
|
-
}
|
|
3245
|
-
multiSapeAry.push({
|
|
3246
|
-
type: "arcTo",
|
|
3247
|
-
hR,
|
|
3248
|
-
wR,
|
|
3249
|
-
stAng,
|
|
3250
|
-
swAng,
|
|
3251
|
-
shftX,
|
|
3252
|
-
shftY,
|
|
3253
|
-
order
|
|
3254
|
-
});
|
|
3255
|
-
}
|
|
3256
|
-
if (closeNode) {
|
|
3257
|
-
if (!Array.isArray(closeNode)) closeNode = [closeNode];
|
|
3258
|
-
Object.keys(closeNode).forEach(() => {
|
|
3259
|
-
multiSapeAry.push({
|
|
3260
|
-
type: "close",
|
|
3261
|
-
order: Infinity
|
|
3262
|
-
});
|
|
3263
|
-
});
|
|
3264
|
-
}
|
|
3265
|
-
multiSapeAry.sort((a, b) => a.order - b.order);
|
|
3266
|
-
let k = 0;
|
|
3267
|
-
while (k < multiSapeAry.length) {
|
|
3268
|
-
if (multiSapeAry[k].type === "movto") {
|
|
3269
|
-
const spX = parseInt(multiSapeAry[k].x) * cX;
|
|
3270
|
-
const spY = parseInt(multiSapeAry[k].y) * cY;
|
|
3271
|
-
d += " M" + spX + "," + spY;
|
|
3272
|
-
} else if (multiSapeAry[k].type === "lnto") {
|
|
3273
|
-
const Lx = parseInt(multiSapeAry[k].x) * cX;
|
|
3274
|
-
const Ly = parseInt(multiSapeAry[k].y) * cY;
|
|
3275
|
-
d += " L" + Lx + "," + Ly;
|
|
3276
|
-
} else if (multiSapeAry[k].type === "cubicBezTo") {
|
|
3277
|
-
const Cx1 = parseInt(multiSapeAry[k].cubBzPt[0].x) * cX;
|
|
3278
|
-
const Cy1 = parseInt(multiSapeAry[k].cubBzPt[0].y) * cY;
|
|
3279
|
-
const Cx2 = parseInt(multiSapeAry[k].cubBzPt[1].x) * cX;
|
|
3280
|
-
const Cy2 = parseInt(multiSapeAry[k].cubBzPt[1].y) * cY;
|
|
3281
|
-
const Cx3 = parseInt(multiSapeAry[k].cubBzPt[2].x) * cX;
|
|
3282
|
-
const Cy3 = parseInt(multiSapeAry[k].cubBzPt[2].y) * cY;
|
|
3283
|
-
d += " C" + Cx1 + "," + Cy1 + " " + Cx2 + "," + Cy2 + " " + Cx3 + "," + Cy3;
|
|
3284
|
-
} else if (multiSapeAry[k].type === "quadBezTo") {
|
|
3285
|
-
const Qx1 = parseInt(multiSapeAry[k].quadBzPt[0].x) * cX;
|
|
3286
|
-
const Qy1 = parseInt(multiSapeAry[k].quadBzPt[0].y) * cY;
|
|
3287
|
-
const Qx2 = parseInt(multiSapeAry[k].quadBzPt[1].x) * cX;
|
|
3288
|
-
const Qy2 = parseInt(multiSapeAry[k].quadBzPt[1].y) * cY;
|
|
3289
|
-
d += " Q" + Qx1 + "," + Qy1 + " " + Qx2 + "," + Qy2;
|
|
3290
|
-
} else if (multiSapeAry[k].type === "arcTo") {
|
|
3291
|
-
const hR = parseInt(multiSapeAry[k].hR) * cX;
|
|
3292
|
-
const wR = parseInt(multiSapeAry[k].wR) * cY;
|
|
3293
|
-
const stAng = parseInt(multiSapeAry[k].stAng) / 6e4;
|
|
3294
|
-
const swAng = parseInt(multiSapeAry[k].swAng) / 6e4;
|
|
3295
|
-
const endAng = stAng + swAng;
|
|
3296
|
-
d += shapeArc(wR, hR, wR, hR, stAng, endAng, false);
|
|
3297
|
-
} else if (multiSapeAry[k].type === "close") d += "z";
|
|
3298
|
-
k++;
|
|
3299
|
-
}
|
|
3300
|
-
}
|
|
3301
|
-
return d;
|
|
3127
|
+
const pathNodes = normalizeToArray(getTextByPathList(pathLstNode, ["a:path"]));
|
|
3128
|
+
return pathNodes.map((pathNode) => buildCustomShapeSegment(pathNode, w, h)).filter(Boolean).join(" ");
|
|
3302
3129
|
}
|
|
3303
3130
|
function identifyShape(shapeData) {
|
|
3304
3131
|
const pathLst = shapeData["a:pathLst"];
|
|
@@ -3313,16 +3140,16 @@ function identifyShape(shapeData) {
|
|
|
3313
3140
|
}
|
|
3314
3141
|
function extractPathCommands(path) {
|
|
3315
3142
|
const commands = [];
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
const pt = moveTo["a:pt"];
|
|
3143
|
+
const moveToList = normalizeToArray(path["a:moveTo"]);
|
|
3144
|
+
moveToList.forEach((moveTo) => {
|
|
3145
|
+
const pt = Array.isArray(moveTo?.["a:pt"]) ? moveTo["a:pt"][0] : moveTo?.["a:pt"];
|
|
3319
3146
|
if (pt) {
|
|
3320
3147
|
commands.push({
|
|
3321
3148
|
type: "moveTo",
|
|
3322
3149
|
points: [{ x: parseInt(pt.attrs?.x) || 0, y: parseInt(pt.attrs?.y) || 0 }]
|
|
3323
3150
|
});
|
|
3324
3151
|
}
|
|
3325
|
-
}
|
|
3152
|
+
});
|
|
3326
3153
|
const lineToList = normalizeToArray(path["a:lnTo"]);
|
|
3327
3154
|
lineToList.forEach((lnTo) => {
|
|
3328
3155
|
const pt = lnTo["a:pt"];
|
|
@@ -3372,6 +3199,55 @@ function normalizeToArray(value) {
|
|
|
3372
3199
|
if (!value) return [];
|
|
3373
3200
|
return Array.isArray(value) ? value : [value];
|
|
3374
3201
|
}
|
|
3202
|
+
function buildCustomShapeSegment(pathNode, w, h) {
|
|
3203
|
+
if (!pathNode || typeof pathNode !== "object") return "";
|
|
3204
|
+
const maxX = parseInt(pathNode.attrs?.w) || 0;
|
|
3205
|
+
const maxY = parseInt(pathNode.attrs?.h) || 0;
|
|
3206
|
+
const scaleX = maxX === 0 ? 0 : w / maxX;
|
|
3207
|
+
const scaleY = maxY === 0 ? 0 : h / maxY;
|
|
3208
|
+
const commands = extractPathCommands(pathNode);
|
|
3209
|
+
if (!commands.length) return "";
|
|
3210
|
+
return commands.map((command) => mapCommandToPath(command, scaleX, scaleY)).filter(Boolean).join(" ");
|
|
3211
|
+
}
|
|
3212
|
+
function mapCommandToPath(command, scaleX, scaleY) {
|
|
3213
|
+
switch (command.type) {
|
|
3214
|
+
case "moveTo": {
|
|
3215
|
+
const point = command.points?.[0];
|
|
3216
|
+
return `M${scaleValue(point?.x, scaleX)},${scaleValue(point?.y, scaleY)}`;
|
|
3217
|
+
}
|
|
3218
|
+
case "lineTo": {
|
|
3219
|
+
const point = command.points?.[0];
|
|
3220
|
+
return `L${scaleValue(point?.x, scaleX)},${scaleValue(point?.y, scaleY)}`;
|
|
3221
|
+
}
|
|
3222
|
+
case "cubicBezTo": {
|
|
3223
|
+
if (!Array.isArray(command.points) || command.points.length < 3) return "";
|
|
3224
|
+
const [p1, p2, p3] = command.points;
|
|
3225
|
+
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)}`;
|
|
3226
|
+
}
|
|
3227
|
+
case "quadBezTo": {
|
|
3228
|
+
if (!Array.isArray(command.points) || command.points.length < 2) return "";
|
|
3229
|
+
const [p1, p2] = command.points;
|
|
3230
|
+
return `Q${scaleValue(p1?.x, scaleX)},${scaleValue(p1?.y, scaleY)} ${scaleValue(p2?.x, scaleX)},${scaleValue(p2?.y, scaleY)}`;
|
|
3231
|
+
}
|
|
3232
|
+
case "arcTo": {
|
|
3233
|
+
const startAngle = (parseInt(command.stAng) || 0) / 6e4;
|
|
3234
|
+
const sweepAngle = (parseInt(command.swAng) || 0) / 6e4;
|
|
3235
|
+
const endAngle = startAngle + sweepAngle;
|
|
3236
|
+
const radiusX = scaleValue(command.wR, scaleX);
|
|
3237
|
+
const radiusY = scaleValue(command.hR, scaleY);
|
|
3238
|
+
return shapeArc(radiusX, radiusY, radiusX, radiusY, startAngle, endAngle, false).trim();
|
|
3239
|
+
}
|
|
3240
|
+
case "close":
|
|
3241
|
+
return "z";
|
|
3242
|
+
default:
|
|
3243
|
+
return "";
|
|
3244
|
+
}
|
|
3245
|
+
}
|
|
3246
|
+
function scaleValue(value, scale) {
|
|
3247
|
+
const numeric = typeof value === "number" ? value : parseFloat(String(value ?? 0));
|
|
3248
|
+
if (!Number.isFinite(numeric) || !Number.isFinite(scale)) return 0;
|
|
3249
|
+
return numeric * scale;
|
|
3250
|
+
}
|
|
3375
3251
|
function analyzePathCommands(commands, pathWidth, pathHeight) {
|
|
3376
3252
|
const analysis = {
|
|
3377
3253
|
lineCount: 0,
|
|
@@ -9310,6 +9186,7 @@ async function genDiagram(node, warpObj) {
|
|
|
9310
9186
|
|
|
9311
9187
|
// utils.ts
|
|
9312
9188
|
var PT_TO_PX = 96 / 72;
|
|
9189
|
+
var EXPORTED_OBJECT_NAME_RE = /^(shape-text|shape|text)-(\d+)-(.+)$/;
|
|
9313
9190
|
function toPx(value) {
|
|
9314
9191
|
if (value === void 0 || value === null) return void 0;
|
|
9315
9192
|
return value * PT_TO_PX;
|
|
@@ -9327,18 +9204,80 @@ function mapFillColor(value) {
|
|
|
9327
9204
|
if (!value) return void 0;
|
|
9328
9205
|
return value.startsWith("#") ? value : `#${value}`;
|
|
9329
9206
|
}
|
|
9207
|
+
function parseExportedObjectName(name) {
|
|
9208
|
+
if (!name) return void 0;
|
|
9209
|
+
const match = name.match(EXPORTED_OBJECT_NAME_RE);
|
|
9210
|
+
if (!match) return void 0;
|
|
9211
|
+
const slideIndex = Number.parseInt(match[2], 10);
|
|
9212
|
+
if (!Number.isFinite(slideIndex)) return void 0;
|
|
9213
|
+
return {
|
|
9214
|
+
kind: match[1],
|
|
9215
|
+
slideIndex,
|
|
9216
|
+
refId: match[3]
|
|
9217
|
+
};
|
|
9218
|
+
}
|
|
9219
|
+
function parseGradientPosition(value) {
|
|
9220
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
9221
|
+
return value > 100 ? value / 1e3 : value;
|
|
9222
|
+
}
|
|
9223
|
+
if (typeof value !== "string") return 0;
|
|
9224
|
+
const numeric = Number.parseFloat(value);
|
|
9225
|
+
if (!Number.isFinite(numeric)) return 0;
|
|
9226
|
+
if (value.trim().endsWith("%")) return numeric;
|
|
9227
|
+
return numeric > 100 ? numeric / 1e3 : numeric;
|
|
9228
|
+
}
|
|
9229
|
+
function mapGradient(value) {
|
|
9230
|
+
if (!value || typeof value !== "object") return void 0;
|
|
9231
|
+
const colors = Array.isArray(value.colors) ? value.colors.filter((stop) => stop && typeof stop === "object").map((stop) => ({
|
|
9232
|
+
pos: parseGradientPosition(stop.pos),
|
|
9233
|
+
color: mapFillColor(stop.color) ?? "#FFFFFF"
|
|
9234
|
+
})) : [];
|
|
9235
|
+
return {
|
|
9236
|
+
type: typeof value.type === "string" ? value.type === "line" ? "linear" : value.type : typeof value.path === "string" ? value.path === "line" ? "linear" : value.path : "linear",
|
|
9237
|
+
rotate: typeof value.rotate === "number" ? value.rotate : typeof value.rot === "number" ? value.rot : 0,
|
|
9238
|
+
colors
|
|
9239
|
+
};
|
|
9240
|
+
}
|
|
9330
9241
|
function mapFill(fill) {
|
|
9331
|
-
if (!fill) return
|
|
9332
|
-
if (typeof fill === "string")
|
|
9333
|
-
|
|
9334
|
-
|
|
9335
|
-
|
|
9336
|
-
|
|
9337
|
-
|
|
9338
|
-
|
|
9339
|
-
|
|
9242
|
+
if (!fill) return void 0;
|
|
9243
|
+
if (typeof fill === "string") {
|
|
9244
|
+
const color = mapFillColor(fill);
|
|
9245
|
+
return color ? { type: "solid", color } : void 0;
|
|
9246
|
+
}
|
|
9247
|
+
if (typeof fill !== "object") {
|
|
9248
|
+
return void 0;
|
|
9249
|
+
}
|
|
9250
|
+
if (fill.type === "color" && typeof fill.value === "string") {
|
|
9251
|
+
const color = mapFillColor(fill.value);
|
|
9252
|
+
return color ? { type: "solid", color } : void 0;
|
|
9253
|
+
}
|
|
9254
|
+
if (fill.type === "solid" || fill.type === void 0 && typeof fill.color === "string") {
|
|
9255
|
+
const color = mapFillColor(fill.color);
|
|
9256
|
+
return color ? { type: "solid", color } : void 0;
|
|
9340
9257
|
}
|
|
9341
|
-
|
|
9258
|
+
if (fill.type === "gradient") {
|
|
9259
|
+
const gradient = mapGradient(fill.value ?? fill.gradient ?? fill);
|
|
9260
|
+
return gradient ? { type: "gradient", gradient } : void 0;
|
|
9261
|
+
}
|
|
9262
|
+
if ((fill.type === "image" || fill.type === "pattern") && fill.value?.picBase64) {
|
|
9263
|
+
return {
|
|
9264
|
+
type: "image",
|
|
9265
|
+
src: fill.value.picBase64,
|
|
9266
|
+
...typeof fill.value.opacity === "number" ? { opacity: fill.value.opacity } : {}
|
|
9267
|
+
};
|
|
9268
|
+
}
|
|
9269
|
+
if (fill.type === "image" && typeof fill.src === "string") {
|
|
9270
|
+
return {
|
|
9271
|
+
type: "image",
|
|
9272
|
+
src: fill.src,
|
|
9273
|
+
...typeof fill.opacity === "number" ? { opacity: fill.opacity } : {}
|
|
9274
|
+
};
|
|
9275
|
+
}
|
|
9276
|
+
if (fill.gradient || fill.colors) {
|
|
9277
|
+
const gradient = mapGradient(fill.gradient ?? fill);
|
|
9278
|
+
return gradient ? { type: "gradient", gradient } : void 0;
|
|
9279
|
+
}
|
|
9280
|
+
return void 0;
|
|
9342
9281
|
}
|
|
9343
9282
|
function convertFontSizeToPx(content) {
|
|
9344
9283
|
return content.replace(/font-size:\s*([0-9.]+)pt/gi, (_, size) => {
|
|
@@ -9463,14 +9402,16 @@ function mapKeypoints(pathFormula, raw) {
|
|
|
9463
9402
|
// element-mapper.ts
|
|
9464
9403
|
function mapElement(raw) {
|
|
9465
9404
|
if (!raw || !raw.type) return null;
|
|
9466
|
-
const
|
|
9467
|
-
|
|
9405
|
+
const exportedMeta = parseExportedObjectName(raw.name);
|
|
9406
|
+
const base = mapBaseElement(raw, exportedMeta);
|
|
9407
|
+
if (raw.type === "text" || isExportedTextShape(raw, exportedMeta)) {
|
|
9468
9408
|
const content = raw.content !== void 0 ? normalizeTextContent(raw.content) : raw.content;
|
|
9469
9409
|
const fallbackLineHeight = hasMultiLineText(content) ? 1.5 : 1;
|
|
9470
9410
|
const lineHeight = raw.lineHeight ?? fallbackLineHeight;
|
|
9471
9411
|
const normalizedHeight = normalizeTextHeight(base.height, content, lineHeight);
|
|
9472
9412
|
return {
|
|
9473
9413
|
...base,
|
|
9414
|
+
type: "text",
|
|
9474
9415
|
height: normalizedHeight,
|
|
9475
9416
|
rotate: base.rotate ?? 0,
|
|
9476
9417
|
flipH: void 0,
|
|
@@ -9482,7 +9423,7 @@ function mapElement(raw) {
|
|
|
9482
9423
|
lineHeight,
|
|
9483
9424
|
paragraphSpace: raw.paragraphSpace,
|
|
9484
9425
|
vertical: raw.isVertical,
|
|
9485
|
-
fill: mapFill(raw.fill)
|
|
9426
|
+
fill: mapFill(raw.fill)
|
|
9486
9427
|
};
|
|
9487
9428
|
}
|
|
9488
9429
|
if (raw.type === "image") {
|
|
@@ -9507,10 +9448,11 @@ function mapElement(raw) {
|
|
|
9507
9448
|
};
|
|
9508
9449
|
}
|
|
9509
9450
|
if (raw.type === "shape") {
|
|
9510
|
-
const
|
|
9451
|
+
const fill = mapFill(raw.fill) ?? { type: "solid", color: "rgba(255,255,255,0)" };
|
|
9511
9452
|
const pathFormula = mapPathFormula(raw.shapType);
|
|
9512
9453
|
const keypoints = pathFormula ? mapKeypoints(pathFormula, raw.keypoints) : void 0;
|
|
9513
|
-
const
|
|
9454
|
+
const normalizedShapeText = raw.content !== void 0 ? normalizeTextContent(raw.content) : void 0;
|
|
9455
|
+
const hasText = hasRenderableText(normalizedShapeText);
|
|
9514
9456
|
let path = raw.path;
|
|
9515
9457
|
let viewBox = raw.viewBox ?? [raw.width ?? 0, raw.height ?? 0];
|
|
9516
9458
|
let special = false;
|
|
@@ -9549,17 +9491,17 @@ function mapElement(raw) {
|
|
|
9549
9491
|
}
|
|
9550
9492
|
return {
|
|
9551
9493
|
...base,
|
|
9494
|
+
type: "shape",
|
|
9552
9495
|
rotate: base.rotate ?? 0,
|
|
9553
9496
|
fixedRatio: false,
|
|
9554
9497
|
path,
|
|
9555
9498
|
viewBox,
|
|
9556
9499
|
pathFormula: pathFormula ?? void 0,
|
|
9557
9500
|
keypoints: keypoints ?? void 0,
|
|
9558
|
-
|
|
9559
|
-
fill: fill ?? "",
|
|
9501
|
+
fill,
|
|
9560
9502
|
...special ? { special: true } : {},
|
|
9561
9503
|
text: hasText ? {
|
|
9562
|
-
content:
|
|
9504
|
+
content: normalizedShapeText,
|
|
9563
9505
|
align: normalizeVAlign(raw.vAlign) ?? "middle",
|
|
9564
9506
|
defaultColor: normalizeColor(raw.defaultColor) ?? normalizeColor(raw.color) ?? "#333",
|
|
9565
9507
|
defaultFontName: raw.fontName ?? "",
|
|
@@ -9570,6 +9512,7 @@ function mapElement(raw) {
|
|
|
9570
9512
|
if (raw.type === "line") {
|
|
9571
9513
|
return {
|
|
9572
9514
|
...base,
|
|
9515
|
+
type: "line",
|
|
9573
9516
|
start: toPxPair(raw.start),
|
|
9574
9517
|
end: toPxPair(raw.end),
|
|
9575
9518
|
broken: toPxPair(raw.broken),
|
|
@@ -9606,9 +9549,6 @@ function normalizeElement(element) {
|
|
|
9606
9549
|
points: ["", ""]
|
|
9607
9550
|
};
|
|
9608
9551
|
}
|
|
9609
|
-
if (element.type === "shape" && element.fill) {
|
|
9610
|
-
element.fill = mapFillColor(element.fill) ?? element.fill;
|
|
9611
|
-
}
|
|
9612
9552
|
if (element.type === "text" && element.content) {
|
|
9613
9553
|
element.content = normalizeTextContent(element.content);
|
|
9614
9554
|
}
|
|
@@ -9659,20 +9599,21 @@ function mapOutline(raw) {
|
|
|
9659
9599
|
style: raw.borderType
|
|
9660
9600
|
};
|
|
9661
9601
|
}
|
|
9662
|
-
function mapBaseElement(raw) {
|
|
9602
|
+
function mapBaseElement(raw, exportedMeta) {
|
|
9663
9603
|
const outline = mapOutline(raw);
|
|
9664
9604
|
const shadow = mapShadow(raw.shadow);
|
|
9665
|
-
const
|
|
9605
|
+
const fill = mapFill(raw.fill);
|
|
9606
|
+
const exportedId = exportedMeta?.kind === "shape-text" ? `${exportedMeta.refId}__text` : exportedMeta?.refId;
|
|
9666
9607
|
return {
|
|
9667
9608
|
type: raw.type,
|
|
9668
|
-
id: raw.id,
|
|
9609
|
+
id: exportedId ?? raw.id,
|
|
9669
9610
|
groupId: raw.groupId,
|
|
9670
9611
|
left: toPx(raw.left),
|
|
9671
9612
|
top: toPx(raw.top),
|
|
9672
9613
|
width: toPx(raw.width),
|
|
9673
9614
|
height: toPx(raw.height),
|
|
9674
9615
|
rotate: raw.rotate,
|
|
9675
|
-
fill
|
|
9616
|
+
fill,
|
|
9676
9617
|
opacity: raw.opacity,
|
|
9677
9618
|
outline: outline ?? void 0,
|
|
9678
9619
|
shadow: shadow ?? void 0,
|
|
@@ -9680,6 +9621,15 @@ function mapBaseElement(raw) {
|
|
|
9680
9621
|
flipV: raw.isFlipV
|
|
9681
9622
|
};
|
|
9682
9623
|
}
|
|
9624
|
+
function isExportedTextShape(raw, exportedMeta) {
|
|
9625
|
+
if (raw?.type !== "shape" || !raw?.content) return false;
|
|
9626
|
+
return exportedMeta?.kind === "text" || exportedMeta?.kind === "shape-text";
|
|
9627
|
+
}
|
|
9628
|
+
function hasRenderableText(content) {
|
|
9629
|
+
if (!content) return false;
|
|
9630
|
+
const plainText = content.replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim();
|
|
9631
|
+
return plainText.length > 0;
|
|
9632
|
+
}
|
|
9683
9633
|
|
|
9684
9634
|
// slide-normalizer.ts
|
|
9685
9635
|
var ID_ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
|
|
@@ -9694,7 +9644,8 @@ function normalizeSlide(slide, index) {
|
|
|
9694
9644
|
const orderB = typeof b?.order === "number" ? b.order : 0;
|
|
9695
9645
|
return orderA - orderB;
|
|
9696
9646
|
});
|
|
9697
|
-
const
|
|
9647
|
+
const restoredElements = restoreExportedRoundTripElements(orderedElements);
|
|
9648
|
+
const elements = flattenElements(restoredElements).map((element, elementIndex) => {
|
|
9698
9649
|
if (!element.id) {
|
|
9699
9650
|
element.id = makeId(`slide-${index}-element-${elementIndex}-${element.type}`);
|
|
9700
9651
|
}
|
|
@@ -9702,7 +9653,7 @@ function normalizeSlide(slide, index) {
|
|
|
9702
9653
|
});
|
|
9703
9654
|
return {
|
|
9704
9655
|
id: slide?.id ?? slide?.slideId ?? makeId(`slide-${index}`),
|
|
9705
|
-
background: backgroundFill
|
|
9656
|
+
background: backgroundFill,
|
|
9706
9657
|
elements,
|
|
9707
9658
|
remark: slide?.remark ?? ""
|
|
9708
9659
|
};
|
|
@@ -9719,6 +9670,44 @@ function makeId(seed) {
|
|
|
9719
9670
|
}
|
|
9720
9671
|
return id;
|
|
9721
9672
|
}
|
|
9673
|
+
function restoreExportedRoundTripElements(elements) {
|
|
9674
|
+
const restored = elements.map((element) => {
|
|
9675
|
+
if (element?.type === "group" && Array.isArray(element.elements)) {
|
|
9676
|
+
return {
|
|
9677
|
+
...element,
|
|
9678
|
+
elements: restoreExportedRoundTripElements(element.elements)
|
|
9679
|
+
};
|
|
9680
|
+
}
|
|
9681
|
+
return element;
|
|
9682
|
+
});
|
|
9683
|
+
const shapesByRefId = /* @__PURE__ */ new Map();
|
|
9684
|
+
for (const element of restored) {
|
|
9685
|
+
const meta = parseExportedObjectName(element?.name);
|
|
9686
|
+
if (meta?.kind === "shape") {
|
|
9687
|
+
shapesByRefId.set(meta.refId, element);
|
|
9688
|
+
}
|
|
9689
|
+
}
|
|
9690
|
+
return restored.filter((element) => {
|
|
9691
|
+
const meta = parseExportedObjectName(element?.name);
|
|
9692
|
+
if (meta?.kind !== "shape-text") {
|
|
9693
|
+
return true;
|
|
9694
|
+
}
|
|
9695
|
+
const targetShape = shapesByRefId.get(meta.refId);
|
|
9696
|
+
if (!targetShape || targetShape.type !== "shape") {
|
|
9697
|
+
return true;
|
|
9698
|
+
}
|
|
9699
|
+
mergeShapeText(targetShape, element);
|
|
9700
|
+
return false;
|
|
9701
|
+
});
|
|
9702
|
+
}
|
|
9703
|
+
function mergeShapeText(targetShape, textShape) {
|
|
9704
|
+
if (!targetShape.content && textShape?.content) {
|
|
9705
|
+
targetShape.content = textShape.content;
|
|
9706
|
+
}
|
|
9707
|
+
if (textShape?.vAlign) {
|
|
9708
|
+
targetShape.vAlign = textShape.vAlign;
|
|
9709
|
+
}
|
|
9710
|
+
}
|
|
9722
9711
|
function hashSeed(value) {
|
|
9723
9712
|
let hash = 1779033703 ^ value.length;
|
|
9724
9713
|
for (let index = 0; index < value.length; index += 1) {
|
|
@@ -9752,49 +9741,14 @@ var DEFAULT_THEME = {
|
|
|
9752
9741
|
};
|
|
9753
9742
|
async function parsePptxToJson(file) {
|
|
9754
9743
|
const fileBuffer = await file.arrayBuffer();
|
|
9755
|
-
const zip = await JSZip2.loadAsync(fileBuffer);
|
|
9756
|
-
const embedded = ENABLE_DECK_JSON ? await resolveEmbeddedDeck(zip) : null;
|
|
9757
|
-
if (embedded?.deck) {
|
|
9758
|
-
return {
|
|
9759
|
-
deck: embedded.deck,
|
|
9760
|
-
warnings: embedded.warnings
|
|
9761
|
-
};
|
|
9762
|
-
}
|
|
9763
9744
|
return {
|
|
9764
9745
|
deck: await buildDeckFromPptx(fileBuffer),
|
|
9765
|
-
warnings:
|
|
9746
|
+
warnings: []
|
|
9766
9747
|
};
|
|
9767
9748
|
}
|
|
9768
|
-
|
|
9769
|
-
const
|
|
9770
|
-
|
|
9771
|
-
) ?? null;
|
|
9772
|
-
if (!embeddedFile) {
|
|
9773
|
-
return null;
|
|
9774
|
-
}
|
|
9775
|
-
const payloadText = await embeddedFile.async("string");
|
|
9776
|
-
try {
|
|
9777
|
-
const parsed = JSON.parse(payloadText);
|
|
9778
|
-
if (isDeckEnvelope(parsed) && parsed.deck) {
|
|
9779
|
-
return {
|
|
9780
|
-
deck: parsed.deck,
|
|
9781
|
-
warnings: parsed.version && parsed.version !== PPTX_JSON_PAYLOAD_VERSION ? [
|
|
9782
|
-
`Embedded JSON payload version ${parsed.version} differs from ${PPTX_JSON_PAYLOAD_VERSION}.`
|
|
9783
|
-
] : []
|
|
9784
|
-
};
|
|
9785
|
-
}
|
|
9786
|
-
return {
|
|
9787
|
-
deck: parsed,
|
|
9788
|
-
warnings: []
|
|
9789
|
-
};
|
|
9790
|
-
} catch {
|
|
9791
|
-
return {
|
|
9792
|
-
warnings: ["Embedded JSON payload could not be parsed. Falling back to PPTX parsing."]
|
|
9793
|
-
};
|
|
9794
|
-
}
|
|
9795
|
-
}
|
|
9796
|
-
function isDeckEnvelope(payload) {
|
|
9797
|
-
return typeof payload === "object" && payload !== null && "deck" in payload;
|
|
9749
|
+
function normalizeDeck(value) {
|
|
9750
|
+
const document = parseDocument(value);
|
|
9751
|
+
return document;
|
|
9798
9752
|
}
|
|
9799
9753
|
async function buildDeckFromPptx(buffer) {
|
|
9800
9754
|
const pptxJson = await parse2(buffer);
|
|
@@ -9804,7 +9758,7 @@ async function buildDeckFromPptx(buffer) {
|
|
|
9804
9758
|
const slides = (Array.isArray(pptxJson.slides) ? pptxJson.slides : []).map(
|
|
9805
9759
|
(slide, index) => normalizeSlide(slide, index)
|
|
9806
9760
|
);
|
|
9807
|
-
return {
|
|
9761
|
+
return normalizeDeck({
|
|
9808
9762
|
title: DEFAULT_DECK_TITLE,
|
|
9809
9763
|
width,
|
|
9810
9764
|
height,
|
|
@@ -9813,7 +9767,7 @@ async function buildDeckFromPptx(buffer) {
|
|
|
9813
9767
|
themeColors
|
|
9814
9768
|
},
|
|
9815
9769
|
slides
|
|
9816
|
-
};
|
|
9770
|
+
});
|
|
9817
9771
|
}
|
|
9818
9772
|
function mapThemeColors(pptxJson) {
|
|
9819
9773
|
if (!Array.isArray(pptxJson.themeColors)) {
|