pptx-glimpse 3.0.0 → 3.1.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/browser.cjs +3058 -737
- package/dist/browser.d.cts +77 -8
- package/dist/browser.d.ts +77 -8
- package/dist/browser.js +486 -23
- package/dist/{chunk-KMSN55AE.js → chunk-NMAO44T7.js} +2242 -522
- package/dist/{chunk-2AYNMYMC.js → chunk-PGCREQQU.js} +134 -113
- package/dist/{chunk-MWMHSSAD.js → chunk-WAMKNW47.js} +4 -3
- package/dist/chunk-XGCLQP2P.js +83 -0
- package/dist/chunk-ZZKN4U5J.js +141 -0
- package/dist/cli.cjs +11214 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +195 -0
- package/dist/font-collector-BYuaCG-o.d.cts +547 -0
- package/dist/font-collector-BYuaCG-o.d.ts +547 -0
- package/dist/index.cjs +752 -562
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +12 -76
- package/dist/{node-6KTAWUIB.js → node-E6UXPQSQ.js} +2 -2
- package/dist/{node-font-loader-274G445U.js → node-font-loader-OE3OLNDI.js} +2 -2
- package/package.json +9 -6
- package/dist/font-collector-DYooJP6L.d.cts +0 -1345
- package/dist/font-collector-DYooJP6L.d.ts +0 -1345
package/dist/browser.js
CHANGED
|
@@ -1,17 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
collectUsedFonts
|
|
3
|
+
} from "./chunk-ZZKN4U5J.js";
|
|
1
4
|
import {
|
|
2
5
|
DEFAULT_OUTPUT_WIDTH,
|
|
6
|
+
addConnector,
|
|
7
|
+
addEmptySlideFromLayout,
|
|
8
|
+
addTextBox,
|
|
9
|
+
asEmu,
|
|
3
10
|
asPartPath,
|
|
4
11
|
asRelationshipId,
|
|
5
12
|
asSourceNodeId,
|
|
6
|
-
|
|
13
|
+
clearTextRunProperties,
|
|
7
14
|
convertPptxToSvg,
|
|
15
|
+
deleteShape,
|
|
16
|
+
deleteSlide,
|
|
17
|
+
duplicateSlide,
|
|
8
18
|
findShapeNodeBySourceHandle,
|
|
9
19
|
readPptx,
|
|
20
|
+
renderPptxSourceModelToSvg,
|
|
21
|
+
replaceImageBytes,
|
|
10
22
|
replaceParagraphPlainText,
|
|
11
23
|
replaceTextRunPlainText,
|
|
24
|
+
setTextRunProperties,
|
|
25
|
+
unsafeBrandAssertion,
|
|
12
26
|
updateShapeTransform,
|
|
13
27
|
writePptx
|
|
14
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-NMAO44T7.js";
|
|
15
29
|
import {
|
|
16
30
|
DEFAULT_FONT_MAPPING,
|
|
17
31
|
clearFontCache,
|
|
@@ -21,7 +35,7 @@ import {
|
|
|
21
35
|
getMappedFont,
|
|
22
36
|
getWarningEntries,
|
|
23
37
|
getWarningSummary
|
|
24
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-PGCREQQU.js";
|
|
25
39
|
import {
|
|
26
40
|
renderSvgToPng
|
|
27
41
|
} from "./chunk-QPT6BMN5.js";
|
|
@@ -2795,13 +2809,23 @@ var EditorSession = class {
|
|
|
2795
2809
|
const before = this.#document;
|
|
2796
2810
|
if (commands.length === 0) return { ok: true, document: before };
|
|
2797
2811
|
try {
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
)
|
|
2812
|
+
let after = before;
|
|
2813
|
+
const warnings = [];
|
|
2814
|
+
for (const command of commands) {
|
|
2815
|
+
after = applyCommandToDocument(after, command);
|
|
2816
|
+
warnings.push(...collectCommandWarnings(after, [command]));
|
|
2817
|
+
}
|
|
2818
|
+
after = normalizeEditorEdits(after);
|
|
2819
|
+
const dedupedWarnings = dedupeCommandWarnings(warnings);
|
|
2801
2820
|
this.#document = after;
|
|
2821
|
+
this.reconcileSelectionAfterDocumentChange();
|
|
2802
2822
|
this.#undoStack.push({ before, after });
|
|
2803
2823
|
this.#redoStack.length = 0;
|
|
2804
|
-
return {
|
|
2824
|
+
return {
|
|
2825
|
+
ok: true,
|
|
2826
|
+
document: after,
|
|
2827
|
+
...dedupedWarnings.length > 0 ? { warnings: dedupedWarnings } : {}
|
|
2828
|
+
};
|
|
2805
2829
|
} catch (error) {
|
|
2806
2830
|
return {
|
|
2807
2831
|
ok: false,
|
|
@@ -2815,6 +2839,7 @@ var EditorSession = class {
|
|
|
2815
2839
|
const entry = this.#undoStack.pop();
|
|
2816
2840
|
if (entry === void 0) return { ok: false, reason: "empty-undo-stack" };
|
|
2817
2841
|
this.#document = entry.before;
|
|
2842
|
+
this.reconcileSelectionAfterDocumentChange();
|
|
2818
2843
|
this.#redoStack.push(entry);
|
|
2819
2844
|
return { ok: true, document: entry.before };
|
|
2820
2845
|
}
|
|
@@ -2822,9 +2847,16 @@ var EditorSession = class {
|
|
|
2822
2847
|
const entry = this.#redoStack.pop();
|
|
2823
2848
|
if (entry === void 0) return { ok: false, reason: "empty-redo-stack" };
|
|
2824
2849
|
this.#document = entry.after;
|
|
2850
|
+
this.reconcileSelectionAfterDocumentChange();
|
|
2825
2851
|
this.#undoStack.push(entry);
|
|
2826
2852
|
return { ok: true, document: entry.after };
|
|
2827
2853
|
}
|
|
2854
|
+
reconcileSelectionAfterDocumentChange() {
|
|
2855
|
+
if (this.#selection === void 0) return;
|
|
2856
|
+
if (findShapeNodeBySourceHandle(this.#document, this.#selection.shapeHandle) === void 0) {
|
|
2857
|
+
this.#selection = void 0;
|
|
2858
|
+
}
|
|
2859
|
+
}
|
|
2828
2860
|
};
|
|
2829
2861
|
function createEditorSession(document) {
|
|
2830
2862
|
return new EditorSession(document);
|
|
@@ -2835,13 +2867,99 @@ function applyCommandToDocument(document, command) {
|
|
|
2835
2867
|
return replaceTextRunPlainText(document, command.handle, command.text);
|
|
2836
2868
|
case "replaceParagraphPlainText":
|
|
2837
2869
|
return replaceParagraphPlainText(document, command.handle, command.text);
|
|
2870
|
+
case "setTextRunProperties":
|
|
2871
|
+
return setTextRunPropertiesCommand(document, command);
|
|
2872
|
+
case "clearTextRunProperties":
|
|
2873
|
+
return clearTextRunPropertiesCommand(document, command);
|
|
2838
2874
|
case "moveShape":
|
|
2839
2875
|
return moveShape(document, command);
|
|
2840
2876
|
case "resizeShape":
|
|
2841
2877
|
return resizeShape(document, command);
|
|
2842
2878
|
case "setShapeTransform":
|
|
2843
2879
|
return setShapeTransform(document, command);
|
|
2880
|
+
case "addTextBox":
|
|
2881
|
+
return addTextBoxCommand(document, command);
|
|
2882
|
+
case "addConnector":
|
|
2883
|
+
return addConnectorCommand(document, command);
|
|
2884
|
+
case "deleteShape":
|
|
2885
|
+
return deleteShape(document, command.handle);
|
|
2886
|
+
case "replaceImage":
|
|
2887
|
+
return replaceImageBytes(document, command.handle, command.bytes);
|
|
2888
|
+
case "addEmptySlideFromLayout":
|
|
2889
|
+
return addEmptySlideFromLayout(document, command);
|
|
2890
|
+
case "duplicateSlide":
|
|
2891
|
+
return duplicateSlide(document, command.handle);
|
|
2892
|
+
case "deleteSlide":
|
|
2893
|
+
return deleteSlide(document, command.handle);
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
function collectCommandWarnings(document, commands) {
|
|
2897
|
+
if (!commands.some((command) => command.kind === "replaceImage")) return [];
|
|
2898
|
+
const warnings = [];
|
|
2899
|
+
const imageEdits = document.edits?.filter((edit) => edit.kind === "replaceImage") ?? [];
|
|
2900
|
+
for (const command of commands) {
|
|
2901
|
+
if (command.kind !== "replaceImage") continue;
|
|
2902
|
+
let edit;
|
|
2903
|
+
for (let index = imageEdits.length - 1; index >= 0; index -= 1) {
|
|
2904
|
+
const candidate = imageEdits[index];
|
|
2905
|
+
if (candidate.handle.partPath === command.handle.partPath && candidate.handle.nodeId === command.handle.nodeId && candidate.handle.relationshipId === command.handle.relationshipId && candidate.handle.orderingSlot === command.handle.orderingSlot) {
|
|
2906
|
+
edit = candidate;
|
|
2907
|
+
break;
|
|
2908
|
+
}
|
|
2909
|
+
}
|
|
2910
|
+
if (edit === void 0 || edit.sharedReferenceCount <= 1) continue;
|
|
2911
|
+
warnings.push({
|
|
2912
|
+
code: "shared-media-part",
|
|
2913
|
+
mediaPartPath: edit.mediaPartPath,
|
|
2914
|
+
referenceCount: edit.sharedReferenceCount,
|
|
2915
|
+
message: `replaceImage: media part '${edit.mediaPartPath}' is referenced by ${edit.sharedReferenceCount} pic shapes; all references now use the replacement image.`
|
|
2916
|
+
});
|
|
2917
|
+
}
|
|
2918
|
+
return warnings;
|
|
2919
|
+
}
|
|
2920
|
+
function dedupeCommandWarnings(warnings) {
|
|
2921
|
+
const deduped = /* @__PURE__ */ new Map();
|
|
2922
|
+
for (const warning of warnings) {
|
|
2923
|
+
const key = `${warning.code}\0${warning.mediaPartPath}`;
|
|
2924
|
+
if (!deduped.has(key)) deduped.set(key, warning);
|
|
2925
|
+
}
|
|
2926
|
+
return [...deduped.values()];
|
|
2927
|
+
}
|
|
2928
|
+
function addTextBoxCommand(document, command) {
|
|
2929
|
+
requireFiniteEmu(command.offsetX, "addTextBox", "offsetX");
|
|
2930
|
+
requireFiniteEmu(command.offsetY, "addTextBox", "offsetY");
|
|
2931
|
+
requirePositiveFiniteEmu(command.width, "addTextBox", "width");
|
|
2932
|
+
requirePositiveFiniteEmu(command.height, "addTextBox", "height");
|
|
2933
|
+
if (typeof command.text !== "string") {
|
|
2934
|
+
throw new Error("addTextBox: text must be a string");
|
|
2935
|
+
}
|
|
2936
|
+
if (command.name !== void 0 && command.name.trim() === "") {
|
|
2937
|
+
throw new Error("addTextBox: name must be a non-empty string when provided");
|
|
2844
2938
|
}
|
|
2939
|
+
return addTextBox(document, command.slideHandle, command);
|
|
2940
|
+
}
|
|
2941
|
+
function addConnectorCommand(document, command) {
|
|
2942
|
+
requireFiniteEmu(command.offsetX, "addConnector", "offsetX");
|
|
2943
|
+
requireFiniteEmu(command.offsetY, "addConnector", "offsetY");
|
|
2944
|
+
requirePositiveFiniteEmu(command.width, "addConnector", "width");
|
|
2945
|
+
requirePositiveFiniteEmu(command.height, "addConnector", "height");
|
|
2946
|
+
return addConnector(document, command.slideHandle, command);
|
|
2947
|
+
}
|
|
2948
|
+
function setTextRunPropertiesCommand(document, command) {
|
|
2949
|
+
requireNonEmptyPropertySet(command.properties, "setTextRunProperties");
|
|
2950
|
+
validateTextRunPropertySet(command.properties, "setTextRunProperties");
|
|
2951
|
+
return setTextRunProperties(document, command.handle, command.properties);
|
|
2952
|
+
}
|
|
2953
|
+
function clearTextRunPropertiesCommand(document, command) {
|
|
2954
|
+
if (command.properties.length === 0) {
|
|
2955
|
+
throw new Error("clearTextRunProperties: properties must contain at least one property name");
|
|
2956
|
+
}
|
|
2957
|
+
for (const property of command.properties) {
|
|
2958
|
+
if (!EDITABLE_TEXT_RUN_PROPERTY_SET.has(property)) {
|
|
2959
|
+
throw new Error(`clearTextRunProperties: unsupported text run property '${property}'`);
|
|
2960
|
+
}
|
|
2961
|
+
}
|
|
2962
|
+
return clearTextRunProperties(document, command.handle, command.properties);
|
|
2845
2963
|
}
|
|
2846
2964
|
function moveShape(document, command) {
|
|
2847
2965
|
requireFiniteEmu(command.offsetX, "moveShape", "offsetX");
|
|
@@ -2878,6 +2996,49 @@ function setShapeTransform(document, command) {
|
|
|
2878
2996
|
height: command.height
|
|
2879
2997
|
});
|
|
2880
2998
|
}
|
|
2999
|
+
var EDITABLE_TEXT_RUN_PROPERTIES = [
|
|
3000
|
+
"bold",
|
|
3001
|
+
"italic",
|
|
3002
|
+
"underline",
|
|
3003
|
+
"fontSize",
|
|
3004
|
+
"color",
|
|
3005
|
+
"typeface"
|
|
3006
|
+
];
|
|
3007
|
+
var EDITABLE_TEXT_RUN_PROPERTY_SET = new Set(EDITABLE_TEXT_RUN_PROPERTIES);
|
|
3008
|
+
function requireNonEmptyPropertySet(properties, commandName) {
|
|
3009
|
+
if (Object.values(properties).every((value) => value === void 0)) {
|
|
3010
|
+
throw new Error(`${commandName}: properties must contain at least one defined property`);
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
function validateTextRunPropertySet(properties, commandName) {
|
|
3014
|
+
for (const property of Object.keys(properties)) {
|
|
3015
|
+
if (!EDITABLE_TEXT_RUN_PROPERTY_SET.has(property)) {
|
|
3016
|
+
throw new Error(`${commandName}: unsupported text run property '${property}'`);
|
|
3017
|
+
}
|
|
3018
|
+
}
|
|
3019
|
+
requireBooleanOrUndefined(properties.bold, commandName, "bold");
|
|
3020
|
+
requireBooleanOrUndefined(properties.italic, commandName, "italic");
|
|
3021
|
+
requireBooleanOrUndefined(properties.underline, commandName, "underline");
|
|
3022
|
+
if (properties.fontSize !== void 0 && (!Number.isFinite(properties.fontSize) || properties.fontSize <= 0)) {
|
|
3023
|
+
throw new Error(`${commandName}: fontSize must be a finite positive pt value`);
|
|
3024
|
+
}
|
|
3025
|
+
if (properties.typeface !== void 0 && properties.typeface.trim() === "") {
|
|
3026
|
+
throw new Error(`${commandName}: typeface must be a non-empty string`);
|
|
3027
|
+
}
|
|
3028
|
+
if (properties.color !== void 0) {
|
|
3029
|
+
if (properties.color.kind !== "srgb") {
|
|
3030
|
+
throw new Error(`${commandName}: only srgb text run color is supported`);
|
|
3031
|
+
}
|
|
3032
|
+
if (!/^[0-9A-Fa-f]{6}$/.test(properties.color.hex)) {
|
|
3033
|
+
throw new Error(`${commandName}: color.hex must be a 6-digit hex value`);
|
|
3034
|
+
}
|
|
3035
|
+
}
|
|
3036
|
+
}
|
|
3037
|
+
function requireBooleanOrUndefined(value, commandName, fieldName) {
|
|
3038
|
+
if (value !== void 0 && typeof value !== "boolean") {
|
|
3039
|
+
throw new Error(`${commandName}: ${fieldName} must be a boolean value`);
|
|
3040
|
+
}
|
|
3041
|
+
}
|
|
2881
3042
|
function requireEditableShapeTransform(document, handle, commandName) {
|
|
2882
3043
|
const shape = findShapeNodeBySourceHandle(document, handle);
|
|
2883
3044
|
if (shape === void 0) {
|
|
@@ -2905,36 +3066,68 @@ function normalizeEditorEdits(document) {
|
|
|
2905
3066
|
const edits = document.edits;
|
|
2906
3067
|
if (edits === void 0) return document;
|
|
2907
3068
|
const seenTextRuns = /* @__PURE__ */ new Set();
|
|
3069
|
+
const seenTextRunProperties = /* @__PURE__ */ new Map();
|
|
2908
3070
|
const seenParagraphs = /* @__PURE__ */ new Set();
|
|
2909
3071
|
const seenShapeTransforms = /* @__PURE__ */ new Set();
|
|
2910
3072
|
const normalizedReversed = [];
|
|
3073
|
+
let changed = false;
|
|
2911
3074
|
for (let index = edits.length - 1; index >= 0; index -= 1) {
|
|
2912
3075
|
const edit = edits[index];
|
|
2913
3076
|
if (edit.kind === "replaceTextRunPlainText") {
|
|
2914
3077
|
const key = editHandleNodeKey(edit);
|
|
2915
3078
|
const paragraphKey = textRunParagraphEditKey(edit);
|
|
2916
|
-
if (paragraphKey !== void 0 && seenParagraphs.has(paragraphKey))
|
|
2917
|
-
|
|
3079
|
+
if (paragraphKey !== void 0 && seenParagraphs.has(paragraphKey)) {
|
|
3080
|
+
changed = true;
|
|
3081
|
+
continue;
|
|
3082
|
+
}
|
|
3083
|
+
if (seenTextRuns.has(key)) {
|
|
3084
|
+
changed = true;
|
|
3085
|
+
continue;
|
|
3086
|
+
}
|
|
2918
3087
|
seenTextRuns.add(key);
|
|
2919
3088
|
}
|
|
3089
|
+
if (edit.kind === "updateTextRunProperties") {
|
|
3090
|
+
const paragraphKey = textRunParagraphEditKey(edit);
|
|
3091
|
+
if (paragraphKey !== void 0 && seenParagraphs.has(paragraphKey)) {
|
|
3092
|
+
changed = true;
|
|
3093
|
+
continue;
|
|
3094
|
+
}
|
|
3095
|
+
const normalized = normalizeTextRunPropertiesEdit(edit, seenTextRunProperties);
|
|
3096
|
+
if (normalized === void 0) {
|
|
3097
|
+
changed = true;
|
|
3098
|
+
continue;
|
|
3099
|
+
}
|
|
3100
|
+
if (!editorEditsEqual(normalized, edit)) changed = true;
|
|
3101
|
+
normalizedReversed.push(normalized);
|
|
3102
|
+
continue;
|
|
3103
|
+
}
|
|
2920
3104
|
if (edit.kind === "replaceParagraphPlainText") {
|
|
2921
3105
|
const key = editHandleNodeKey(edit);
|
|
2922
|
-
if (seenParagraphs.has(key))
|
|
3106
|
+
if (seenParagraphs.has(key)) {
|
|
3107
|
+
changed = true;
|
|
3108
|
+
continue;
|
|
3109
|
+
}
|
|
2923
3110
|
seenParagraphs.add(key);
|
|
2924
3111
|
}
|
|
2925
3112
|
if (edit.kind === "updateShapeTransform") {
|
|
2926
3113
|
const key = editHandleNodeKey(edit);
|
|
2927
|
-
if (seenShapeTransforms.has(key))
|
|
3114
|
+
if (seenShapeTransforms.has(key)) {
|
|
3115
|
+
changed = true;
|
|
3116
|
+
continue;
|
|
3117
|
+
}
|
|
2928
3118
|
seenShapeTransforms.add(key);
|
|
2929
3119
|
}
|
|
2930
3120
|
normalizedReversed.push(edit);
|
|
2931
3121
|
}
|
|
2932
|
-
if (normalizedReversed.length === edits.length) return document;
|
|
3122
|
+
if (!changed && normalizedReversed.length === edits.length) return document;
|
|
2933
3123
|
return {
|
|
2934
3124
|
...document,
|
|
2935
3125
|
edits: normalizedReversed.reverse()
|
|
2936
3126
|
};
|
|
2937
3127
|
}
|
|
3128
|
+
function editorEditsEqual(left, right) {
|
|
3129
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
3130
|
+
}
|
|
2938
3131
|
function editHandleNodeKey(edit) {
|
|
2939
3132
|
return [
|
|
2940
3133
|
edit.handle.partPath,
|
|
@@ -2957,10 +3150,70 @@ function textRunParagraphEditKey(edit) {
|
|
|
2957
3150
|
paragraphOrderingSlot
|
|
2958
3151
|
].join("\0");
|
|
2959
3152
|
}
|
|
3153
|
+
function normalizeTextRunPropertiesEdit(edit, seenTextRunProperties) {
|
|
3154
|
+
const key = editHandleNodeKey(edit);
|
|
3155
|
+
let seenProperties = seenTextRunProperties.get(key);
|
|
3156
|
+
if (seenProperties === void 0) {
|
|
3157
|
+
seenProperties = /* @__PURE__ */ new Set();
|
|
3158
|
+
seenTextRunProperties.set(key, seenProperties);
|
|
3159
|
+
}
|
|
3160
|
+
const set = {};
|
|
3161
|
+
if (edit.set?.bold !== void 0 && !seenProperties.has("bold")) {
|
|
3162
|
+
seenProperties.add("bold");
|
|
3163
|
+
set.bold = edit.set.bold;
|
|
3164
|
+
}
|
|
3165
|
+
if (edit.set?.italic !== void 0 && !seenProperties.has("italic")) {
|
|
3166
|
+
seenProperties.add("italic");
|
|
3167
|
+
set.italic = edit.set.italic;
|
|
3168
|
+
}
|
|
3169
|
+
if (edit.set?.underline !== void 0 && !seenProperties.has("underline")) {
|
|
3170
|
+
seenProperties.add("underline");
|
|
3171
|
+
set.underline = edit.set.underline;
|
|
3172
|
+
}
|
|
3173
|
+
if (edit.set?.fontSize !== void 0 && !seenProperties.has("fontSize")) {
|
|
3174
|
+
seenProperties.add("fontSize");
|
|
3175
|
+
set.fontSize = edit.set.fontSize;
|
|
3176
|
+
}
|
|
3177
|
+
if (edit.set?.color !== void 0 && !seenProperties.has("color")) {
|
|
3178
|
+
seenProperties.add("color");
|
|
3179
|
+
set.color = edit.set.color;
|
|
3180
|
+
}
|
|
3181
|
+
if (edit.set?.typeface !== void 0 && !seenProperties.has("typeface")) {
|
|
3182
|
+
seenProperties.add("typeface");
|
|
3183
|
+
set.typeface = edit.set.typeface;
|
|
3184
|
+
}
|
|
3185
|
+
const clear = (edit.clear ?? []).filter((property) => !seenProperties.has(property));
|
|
3186
|
+
for (const property of clear) seenProperties.add(property);
|
|
3187
|
+
if (clear.length === 0 && Object.keys(set).length === 0) return void 0;
|
|
3188
|
+
const normalized = {
|
|
3189
|
+
kind: "updateTextRunProperties",
|
|
3190
|
+
handle: edit.handle,
|
|
3191
|
+
...Object.keys(set).length > 0 ? { set } : {},
|
|
3192
|
+
...clear.length > 0 ? { clear } : {}
|
|
3193
|
+
};
|
|
3194
|
+
return normalized;
|
|
3195
|
+
}
|
|
2960
3196
|
|
|
2961
3197
|
// src/browser-editor.ts
|
|
2962
3198
|
var EMU_PER_INCH = 914400;
|
|
2963
3199
|
var DEFAULT_DPI = 96;
|
|
3200
|
+
var EMU_PER_PIXEL = EMU_PER_INCH / DEFAULT_DPI;
|
|
3201
|
+
var DEFAULT_TEXT_BOX_BOUNDS_PX = {
|
|
3202
|
+
x: 96,
|
|
3203
|
+
y: 96,
|
|
3204
|
+
width: 288,
|
|
3205
|
+
height: 72
|
|
3206
|
+
};
|
|
3207
|
+
var DEFAULT_TEXT_BOX_TEXT = "New text box";
|
|
3208
|
+
var IMAGE_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
|
|
3209
|
+
var IMAGE_ACCEPT_BY_CONTENT_TYPE = {
|
|
3210
|
+
"image/png": "image/png,.png",
|
|
3211
|
+
"image/jpeg": "image/jpeg,.jpg,.jpeg",
|
|
3212
|
+
"image/gif": "image/gif,.gif",
|
|
3213
|
+
"image/bmp": "image/bmp,.bmp",
|
|
3214
|
+
"image/tiff": "image/tiff,.tif,.tiff",
|
|
3215
|
+
"image/webp": "image/webp,.webp"
|
|
3216
|
+
};
|
|
2964
3217
|
var BrowserPptxEditorSession = class _BrowserPptxEditorSession {
|
|
2965
3218
|
#session;
|
|
2966
3219
|
#slides = [];
|
|
@@ -2991,25 +3244,31 @@ var BrowserPptxEditorSession = class _BrowserPptxEditorSession {
|
|
|
2991
3244
|
get selection() {
|
|
2992
3245
|
return this.#session.selection;
|
|
2993
3246
|
}
|
|
2994
|
-
response() {
|
|
3247
|
+
response(warnings) {
|
|
2995
3248
|
return {
|
|
2996
3249
|
slides: this.#slides,
|
|
2997
3250
|
history: this.history,
|
|
2998
|
-
...this.selection !== void 0 ? { selection: this.selection } : {}
|
|
3251
|
+
...this.selection !== void 0 ? { selection: this.selection } : {},
|
|
3252
|
+
...warnings !== void 0 && warnings.length > 0 ? { warnings } : {}
|
|
2999
3253
|
};
|
|
3000
3254
|
}
|
|
3001
3255
|
shapes(slideNumber) {
|
|
3002
3256
|
const slide = this.#session.document.slides[slideNumber - 1];
|
|
3003
3257
|
if (slide === void 0) return [];
|
|
3004
|
-
return slide.shapes.flatMap(
|
|
3258
|
+
return slide.shapes.flatMap(
|
|
3259
|
+
(shape, index) => shapeInfo(this.#session.document, shape, index, true, slide.shapes)
|
|
3260
|
+
);
|
|
3005
3261
|
}
|
|
3006
3262
|
async renderCurrentSlides() {
|
|
3007
|
-
const report = await
|
|
3263
|
+
const report = await renderPptxSourceModelToSvg(this.#session.document, {
|
|
3008
3264
|
textOutput: "text",
|
|
3009
3265
|
skipSystemFonts: true,
|
|
3010
3266
|
...this.#renderOptions
|
|
3011
3267
|
});
|
|
3012
|
-
this.#slides = report.slides
|
|
3268
|
+
this.#slides = report.slides.map((slide) => ({
|
|
3269
|
+
...slide,
|
|
3270
|
+
...this.#session.document.slides[slide.slideNumber - 1]?.handle !== void 0 ? { handle: this.#session.document.slides[slide.slideNumber - 1]?.handle } : {}
|
|
3271
|
+
}));
|
|
3013
3272
|
return this.#slides;
|
|
3014
3273
|
}
|
|
3015
3274
|
async apply(command) {
|
|
@@ -3018,7 +3277,45 @@ var BrowserPptxEditorSession = class _BrowserPptxEditorSession {
|
|
|
3018
3277
|
throw new Error(result.message);
|
|
3019
3278
|
}
|
|
3020
3279
|
await this.renderCurrentSlides();
|
|
3021
|
-
return this.response();
|
|
3280
|
+
return this.response(result.warnings);
|
|
3281
|
+
}
|
|
3282
|
+
async addTextBox(slideNumber = 1, options = {}) {
|
|
3283
|
+
const slide = this.#session.document.slides[slideNumber - 1];
|
|
3284
|
+
if (slide?.handle === void 0) {
|
|
3285
|
+
throw new Error("addTextBox: slide handle was not found in PptxSourceModel source");
|
|
3286
|
+
}
|
|
3287
|
+
const existingShapeKeys = new Set(slide.shapes.map(shapeSourceKey));
|
|
3288
|
+
const result = this.#session.apply({
|
|
3289
|
+
kind: "addTextBox",
|
|
3290
|
+
slideHandle: slide.handle,
|
|
3291
|
+
offsetX: pxToEmu(options.x ?? DEFAULT_TEXT_BOX_BOUNDS_PX.x),
|
|
3292
|
+
offsetY: pxToEmu(options.y ?? DEFAULT_TEXT_BOX_BOUNDS_PX.y),
|
|
3293
|
+
width: pxToEmu(options.width ?? DEFAULT_TEXT_BOX_BOUNDS_PX.width),
|
|
3294
|
+
height: pxToEmu(options.height ?? DEFAULT_TEXT_BOX_BOUNDS_PX.height),
|
|
3295
|
+
text: options.text ?? DEFAULT_TEXT_BOX_TEXT,
|
|
3296
|
+
...options.name !== void 0 ? { name: options.name } : {}
|
|
3297
|
+
});
|
|
3298
|
+
if (!result.ok) {
|
|
3299
|
+
throw new Error(result.message);
|
|
3300
|
+
}
|
|
3301
|
+
this.#selectNewShape(slideNumber, existingShapeKeys);
|
|
3302
|
+
await this.renderCurrentSlides();
|
|
3303
|
+
return this.response(result.warnings);
|
|
3304
|
+
}
|
|
3305
|
+
async deleteShape(handle) {
|
|
3306
|
+
const result = this.#session.apply({ kind: "deleteShape", handle });
|
|
3307
|
+
if (!result.ok) {
|
|
3308
|
+
throw new Error(result.message);
|
|
3309
|
+
}
|
|
3310
|
+
await this.renderCurrentSlides();
|
|
3311
|
+
return this.response(result.warnings);
|
|
3312
|
+
}
|
|
3313
|
+
async deleteSelectedShape() {
|
|
3314
|
+
const selection = this.#session.selection;
|
|
3315
|
+
if (selection === void 0) {
|
|
3316
|
+
throw new Error("deleteShape: no selected shape");
|
|
3317
|
+
}
|
|
3318
|
+
return this.deleteShape(selection.shapeHandle);
|
|
3022
3319
|
}
|
|
3023
3320
|
async applyTextBodyDocJson(handle, docJson) {
|
|
3024
3321
|
const textBody = this.#requireEditableShapeTextBody(handle);
|
|
@@ -3029,7 +3326,7 @@ var BrowserPptxEditorSession = class _BrowserPptxEditorSession {
|
|
|
3029
3326
|
throw new Error(result.message);
|
|
3030
3327
|
}
|
|
3031
3328
|
await this.renderCurrentSlides();
|
|
3032
|
-
return this.response();
|
|
3329
|
+
return this.response(result.warnings);
|
|
3033
3330
|
}
|
|
3034
3331
|
selectShape(handle) {
|
|
3035
3332
|
const result = this.#session.selectShape(handle);
|
|
@@ -3069,11 +3366,17 @@ var BrowserPptxEditorSession = class _BrowserPptxEditorSession {
|
|
|
3069
3366
|
}
|
|
3070
3367
|
return shape.textBody;
|
|
3071
3368
|
}
|
|
3369
|
+
#selectNewShape(slideNumber, existingShapeKeys) {
|
|
3370
|
+
const slide = this.#session.document.slides[slideNumber - 1];
|
|
3371
|
+
const addedShape = slide?.shapes.find((shape) => !existingShapeKeys.has(shapeSourceKey(shape)));
|
|
3372
|
+
if (addedShape?.handle === void 0) return;
|
|
3373
|
+
this.#session.selectShape(addedShape.handle);
|
|
3374
|
+
}
|
|
3072
3375
|
};
|
|
3073
3376
|
function createBrowserPptxEditorSession(input, renderOptions) {
|
|
3074
3377
|
return BrowserPptxEditorSession.create(input, renderOptions);
|
|
3075
3378
|
}
|
|
3076
|
-
function shapeInfo(shape, index, editableTransform = true) {
|
|
3379
|
+
function shapeInfo(source, shape, index, editableTransform = true, slideShapes = []) {
|
|
3077
3380
|
const canEditTransform = shape.kind !== "raw" && shape.transform !== void 0 && editableTransform && isEditableTransformShape(shape);
|
|
3078
3381
|
const base = {
|
|
3079
3382
|
id: String(shape.nodeId ?? shape.handle?.nodeId ?? `${shape.kind}:${String(index)}`),
|
|
@@ -3084,17 +3387,21 @@ function shapeInfo(shape, index, editableTransform = true) {
|
|
|
3084
3387
|
bounds: transformBoundsPx(shape.transform),
|
|
3085
3388
|
editableTransform: true
|
|
3086
3389
|
} : {},
|
|
3390
|
+
...editableTransform && isDeletableShape(shape, slideShapes) ? { editableDelete: true } : {},
|
|
3087
3391
|
..."textBody" in shape && shape.textBody !== void 0 ? {
|
|
3088
3392
|
textRuns: collectTextRuns(
|
|
3089
3393
|
shape.textBody.paragraphs.flatMap((paragraph) => paragraph.runs)
|
|
3090
3394
|
)
|
|
3091
3395
|
} : {},
|
|
3092
|
-
...shape.kind === "shape" && canEditTransform && shape.textBody !== void 0 ? editableTextBody(shape.textBody) : {}
|
|
3396
|
+
...shape.kind === "shape" && canEditTransform && shape.textBody !== void 0 ? editableTextBody(shape.textBody) : {},
|
|
3397
|
+
...shape.kind === "image" ? editableImageReplacement(source, shape) : {}
|
|
3093
3398
|
};
|
|
3094
3399
|
if (shape.kind !== "group") return [base];
|
|
3095
3400
|
return [
|
|
3096
3401
|
base,
|
|
3097
|
-
...shape.children.flatMap(
|
|
3402
|
+
...shape.children.flatMap(
|
|
3403
|
+
(child, childIndex) => shapeInfo(source, child, childIndex, false, slideShapes)
|
|
3404
|
+
)
|
|
3098
3405
|
];
|
|
3099
3406
|
}
|
|
3100
3407
|
function shapeName(shape) {
|
|
@@ -3106,6 +3413,20 @@ function isEditableTransformShape(shape) {
|
|
|
3106
3413
|
}
|
|
3107
3414
|
return !shape.rawSidecars?.some((sidecar) => sidecar.node.name === "mc:AlternateContent");
|
|
3108
3415
|
}
|
|
3416
|
+
function isDeletableShape(shape, slideShapes) {
|
|
3417
|
+
if (shape.kind !== "shape" || shape.handle?.nodeId === void 0) {
|
|
3418
|
+
return false;
|
|
3419
|
+
}
|
|
3420
|
+
if (isShapeReferencedByConnector(shape, slideShapes)) {
|
|
3421
|
+
return false;
|
|
3422
|
+
}
|
|
3423
|
+
return !shape.rawSidecars?.some((sidecar) => sidecar.node.name === "mc:AlternateContent");
|
|
3424
|
+
}
|
|
3425
|
+
function isShapeReferencedByConnector(shape, slideShapes) {
|
|
3426
|
+
return slideShapes.some(
|
|
3427
|
+
(candidate) => candidate.kind === "connector" && (candidate.connection?.start?.shapeId === shape.nodeId || candidate.connection?.end?.shapeId === shape.nodeId)
|
|
3428
|
+
);
|
|
3429
|
+
}
|
|
3109
3430
|
function collectTextRuns(runs) {
|
|
3110
3431
|
return runs.flatMap((run) => {
|
|
3111
3432
|
if (run.handle === void 0) return [];
|
|
@@ -3119,6 +3440,134 @@ function editableTextBody(textBody) {
|
|
|
3119
3440
|
return {};
|
|
3120
3441
|
}
|
|
3121
3442
|
}
|
|
3443
|
+
function editableImageReplacement(source, image) {
|
|
3444
|
+
const media = imageMediaPart(source, image);
|
|
3445
|
+
if (media === void 0) return {};
|
|
3446
|
+
const accept = IMAGE_ACCEPT_BY_CONTENT_TYPE[media.contentType];
|
|
3447
|
+
if (accept === void 0) return {};
|
|
3448
|
+
return {
|
|
3449
|
+
editableImageReplacement: {
|
|
3450
|
+
contentType: media.contentType,
|
|
3451
|
+
accept,
|
|
3452
|
+
mediaPartPath: media.partPath,
|
|
3453
|
+
sharedReferenceCount: countImageReferencesToMedia(source, media.partPath)
|
|
3454
|
+
}
|
|
3455
|
+
};
|
|
3456
|
+
}
|
|
3457
|
+
function imageMediaPart(source, image) {
|
|
3458
|
+
if (image.blipRelationshipId === void 0 || image.handle?.partPath === void 0) {
|
|
3459
|
+
return void 0;
|
|
3460
|
+
}
|
|
3461
|
+
const mediaPartPath = imageMediaPartPath(source, image.handle.partPath, image.blipRelationshipId);
|
|
3462
|
+
if (mediaPartPath === void 0) return void 0;
|
|
3463
|
+
return source.packageGraph.media.find((part) => part.partPath === mediaPartPath);
|
|
3464
|
+
}
|
|
3465
|
+
function imageMediaPartPath(source, sourcePartPath, relationshipId) {
|
|
3466
|
+
const relationships = source.packageGraph.relationships.find(
|
|
3467
|
+
(candidate) => candidate.sourcePartPath === sourcePartPath
|
|
3468
|
+
);
|
|
3469
|
+
const relationship = relationships?.relationships.find(
|
|
3470
|
+
(candidate) => candidate.id === relationshipId && candidate.type === IMAGE_REL_TYPE
|
|
3471
|
+
);
|
|
3472
|
+
if (relationship === void 0) return void 0;
|
|
3473
|
+
return resolveInternalRelationshipTarget(sourcePartPath, relationship);
|
|
3474
|
+
}
|
|
3475
|
+
function countImageReferencesToMedia(source, mediaPartPath) {
|
|
3476
|
+
const parsedImageRelationshipKeys = /* @__PURE__ */ new Set();
|
|
3477
|
+
let count = 0;
|
|
3478
|
+
for (const slide of source.slides) {
|
|
3479
|
+
count += countImageReferencesInTree(
|
|
3480
|
+
source,
|
|
3481
|
+
slide.partPath,
|
|
3482
|
+
slide.shapes,
|
|
3483
|
+
mediaPartPath,
|
|
3484
|
+
parsedImageRelationshipKeys
|
|
3485
|
+
);
|
|
3486
|
+
}
|
|
3487
|
+
for (const layout of source.slideLayouts) {
|
|
3488
|
+
count += countImageReferencesInTree(
|
|
3489
|
+
source,
|
|
3490
|
+
layout.partPath,
|
|
3491
|
+
layout.shapes,
|
|
3492
|
+
mediaPartPath,
|
|
3493
|
+
parsedImageRelationshipKeys
|
|
3494
|
+
);
|
|
3495
|
+
}
|
|
3496
|
+
for (const master of source.slideMasters) {
|
|
3497
|
+
count += countImageReferencesInTree(
|
|
3498
|
+
source,
|
|
3499
|
+
master.partPath,
|
|
3500
|
+
master.shapes,
|
|
3501
|
+
mediaPartPath,
|
|
3502
|
+
parsedImageRelationshipKeys
|
|
3503
|
+
);
|
|
3504
|
+
}
|
|
3505
|
+
for (const relationships of source.packageGraph.relationships) {
|
|
3506
|
+
for (const relationship of relationships.relationships) {
|
|
3507
|
+
if (relationship.type !== IMAGE_REL_TYPE) continue;
|
|
3508
|
+
if (parsedImageRelationshipKeys.has(
|
|
3509
|
+
imageRelationshipKey(relationships.sourcePartPath, relationship.id)
|
|
3510
|
+
)) {
|
|
3511
|
+
continue;
|
|
3512
|
+
}
|
|
3513
|
+
if (resolveInternalRelationshipTarget(relationships.sourcePartPath, relationship) === mediaPartPath) {
|
|
3514
|
+
count += 1;
|
|
3515
|
+
}
|
|
3516
|
+
}
|
|
3517
|
+
}
|
|
3518
|
+
return count;
|
|
3519
|
+
}
|
|
3520
|
+
function countImageReferencesInTree(source, sourcePartPath, shapes, mediaPartPath, parsedImageRelationshipKeys) {
|
|
3521
|
+
let count = 0;
|
|
3522
|
+
for (const shape of shapes) {
|
|
3523
|
+
if (shape.kind === "group") {
|
|
3524
|
+
count += countImageReferencesInTree(
|
|
3525
|
+
source,
|
|
3526
|
+
sourcePartPath,
|
|
3527
|
+
shape.children,
|
|
3528
|
+
mediaPartPath,
|
|
3529
|
+
parsedImageRelationshipKeys
|
|
3530
|
+
);
|
|
3531
|
+
continue;
|
|
3532
|
+
}
|
|
3533
|
+
if (shape.kind !== "image" || shape.blipRelationshipId === void 0) continue;
|
|
3534
|
+
if (imageMediaPartPath(source, sourcePartPath, shape.blipRelationshipId) === mediaPartPath) {
|
|
3535
|
+
count += 1;
|
|
3536
|
+
parsedImageRelationshipKeys.add(
|
|
3537
|
+
imageRelationshipKey(sourcePartPath, shape.blipRelationshipId)
|
|
3538
|
+
);
|
|
3539
|
+
}
|
|
3540
|
+
}
|
|
3541
|
+
return count;
|
|
3542
|
+
}
|
|
3543
|
+
function imageRelationshipKey(partPath, relationshipId) {
|
|
3544
|
+
return `${partPath}\0${relationshipId}`;
|
|
3545
|
+
}
|
|
3546
|
+
function resolveInternalRelationshipTarget(sourcePartPath, relationship) {
|
|
3547
|
+
if (relationship.targetMode === "External") return void 0;
|
|
3548
|
+
return unsafeBrandAssertion(
|
|
3549
|
+
normalizePackagePath(
|
|
3550
|
+
relationship.target.startsWith("/") ? relationship.target.slice(1) : joinPackageRelativeTarget(sourcePartPath, relationship.target)
|
|
3551
|
+
)
|
|
3552
|
+
);
|
|
3553
|
+
}
|
|
3554
|
+
function joinPackageRelativeTarget(sourcePartPath, target) {
|
|
3555
|
+
const slash = sourcePartPath.lastIndexOf("/");
|
|
3556
|
+
const baseDir = slash === -1 ? "" : sourcePartPath.slice(0, slash);
|
|
3557
|
+
return baseDir === "" ? target : `${baseDir}/${target}`;
|
|
3558
|
+
}
|
|
3559
|
+
function normalizePackagePath(path) {
|
|
3560
|
+
const segments = [];
|
|
3561
|
+
for (const segment of path.split("/")) {
|
|
3562
|
+
if (segment === "" || segment === ".") continue;
|
|
3563
|
+
if (segment === "..") {
|
|
3564
|
+
segments.pop();
|
|
3565
|
+
continue;
|
|
3566
|
+
}
|
|
3567
|
+
segments.push(segment);
|
|
3568
|
+
}
|
|
3569
|
+
return segments.join("/");
|
|
3570
|
+
}
|
|
3122
3571
|
function transformBoundsPx(transform) {
|
|
3123
3572
|
return {
|
|
3124
3573
|
x: emuToPixels(transform.offsetX),
|
|
@@ -3130,6 +3579,19 @@ function transformBoundsPx(transform) {
|
|
|
3130
3579
|
function emuToPixels(value) {
|
|
3131
3580
|
return value / EMU_PER_INCH * DEFAULT_DPI;
|
|
3132
3581
|
}
|
|
3582
|
+
function pxToEmu(value) {
|
|
3583
|
+
return asEmu(Math.round(value * EMU_PER_PIXEL));
|
|
3584
|
+
}
|
|
3585
|
+
function shapeSourceKey(shape) {
|
|
3586
|
+
const handle = shape.handle;
|
|
3587
|
+
return [
|
|
3588
|
+
shape.kind,
|
|
3589
|
+
handle?.partPath ?? "",
|
|
3590
|
+
handle?.nodeId ?? "",
|
|
3591
|
+
handle?.relationshipId ?? "",
|
|
3592
|
+
handle?.orderingSlot ?? ""
|
|
3593
|
+
].join("\0");
|
|
3594
|
+
}
|
|
3133
3595
|
|
|
3134
3596
|
// src/browser.ts
|
|
3135
3597
|
async function convertPptxToPng(input, options) {
|
|
@@ -3176,5 +3638,6 @@ export {
|
|
|
3176
3638
|
getMappedFont,
|
|
3177
3639
|
getWarningEntries,
|
|
3178
3640
|
getWarningSummary,
|
|
3179
|
-
initResvgWasm2 as initResvgWasm
|
|
3641
|
+
initResvgWasm2 as initResvgWasm,
|
|
3642
|
+
renderPptxSourceModelToSvg
|
|
3180
3643
|
};
|