@hirokisakabe/pom 10.0.0 → 10.2.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.
Files changed (77) hide show
  1. package/README.md +1 -1
  2. package/dist/autoFit/autoFit.js +55 -15
  3. package/dist/autoFit/autoFit.js.map +1 -1
  4. package/dist/autoFit/strategies/reduceFontSize.js.map +1 -1
  5. package/dist/buildContext.js +4 -4
  6. package/dist/buildContext.js.map +1 -1
  7. package/dist/buildPptx.d.ts +3 -2
  8. package/dist/buildPptx.d.ts.map +1 -1
  9. package/dist/buildPptx.js +1 -1
  10. package/dist/buildPptx.js.map +1 -1
  11. package/dist/calcYogaLayout/calcYogaLayout.js.map +1 -1
  12. package/dist/calcYogaLayout/fontLoader.d.ts +13 -0
  13. package/dist/calcYogaLayout/fontLoader.d.ts.map +1 -0
  14. package/dist/calcYogaLayout/fontLoader.js +70 -3
  15. package/dist/calcYogaLayout/fontLoader.js.map +1 -1
  16. package/dist/calcYogaLayout/measureText.d.ts.map +1 -1
  17. package/dist/calcYogaLayout/measureText.js +6 -6
  18. package/dist/calcYogaLayout/measureText.js.map +1 -1
  19. package/dist/diagnostics.d.ts +1 -1
  20. package/dist/diagnostics.d.ts.map +1 -1
  21. package/dist/diagnostics.js.map +1 -1
  22. package/dist/extractSlideMastersAsPptx.d.ts.map +1 -1
  23. package/dist/extractThemeTokensFromPptx.d.ts +0 -1
  24. package/dist/extractThemeTokensFromPptx.d.ts.map +1 -1
  25. package/dist/icons/renderIcon.js +12 -10
  26. package/dist/icons/renderIcon.js.map +1 -1
  27. package/dist/index.d.ts +2 -1
  28. package/dist/parseXml/coercionRules.js.map +1 -1
  29. package/dist/parseXml/parseXml.d.ts +0 -1
  30. package/dist/parseXml/parseXml.d.ts.map +1 -1
  31. package/dist/parseXml/parseXml.js.map +1 -1
  32. package/dist/parseXml/serializeXml.d.ts +0 -1
  33. package/dist/parseXml/serializeXml.d.ts.map +1 -1
  34. package/dist/parseXml/serializeXml.js.map +1 -1
  35. package/dist/registry/definitions/icon.js +1 -1
  36. package/dist/registry/definitions/list.js +1 -1
  37. package/dist/registry/definitions/list.js.map +1 -1
  38. package/dist/registry/definitions/shape.js +1 -1
  39. package/dist/registry/definitions/shape.js.map +1 -1
  40. package/dist/registry/definitions/text.js +1 -1
  41. package/dist/registry/definitions/text.js.map +1 -1
  42. package/dist/renderPptx/authoringContext.js +101 -0
  43. package/dist/renderPptx/authoringContext.js.map +1 -0
  44. package/dist/renderPptx/{pptxAuthoring.js → glimpseAdapter.js} +83 -152
  45. package/dist/renderPptx/glimpseAdapter.js.map +1 -0
  46. package/dist/renderPptx/nodes/arrow.js +49 -7
  47. package/dist/renderPptx/nodes/arrow.js.map +1 -1
  48. package/dist/renderPptx/nodes/chart.js +2 -2
  49. package/dist/renderPptx/nodes/chart.js.map +1 -1
  50. package/dist/renderPptx/nodes/icon.js +1 -1
  51. package/dist/renderPptx/nodes/icon.js.map +1 -1
  52. package/dist/renderPptx/nodes/list.js +11 -19
  53. package/dist/renderPptx/nodes/list.js.map +1 -1
  54. package/dist/renderPptx/nodes/shape.js +18 -19
  55. package/dist/renderPptx/nodes/shape.js.map +1 -1
  56. package/dist/renderPptx/nodes/table.js +12 -21
  57. package/dist/renderPptx/nodes/table.js.map +1 -1
  58. package/dist/renderPptx/nodes/text.js +16 -1
  59. package/dist/renderPptx/nodes/text.js.map +1 -1
  60. package/dist/renderPptx/renderPptx.js +93 -40
  61. package/dist/renderPptx/renderPptx.js.map +1 -1
  62. package/dist/renderPptx/utils/connectorSites.js +58 -0
  63. package/dist/renderPptx/utils/connectorSites.js.map +1 -0
  64. package/dist/renderPptx/utils/glimpsePicture.js +2 -4
  65. package/dist/renderPptx/utils/glimpsePicture.js.map +1 -1
  66. package/dist/renderPptx/utils/glimpseShape.js +3 -3
  67. package/dist/renderPptx/utils/glimpseShape.js.map +1 -1
  68. package/dist/renderPptx/utils/glimpseTextBox.js +3 -30
  69. package/dist/renderPptx/utils/glimpseTextBox.js.map +1 -1
  70. package/dist/renderPptx/utils/straightLine.js.map +1 -1
  71. package/dist/renderPptx/writablePptx.d.ts +1 -1
  72. package/dist/renderPptx/writablePptx.d.ts.map +1 -1
  73. package/dist/types.d.ts +0 -1
  74. package/dist/types.d.ts.map +1 -1
  75. package/dist/types.js +1 -1
  76. package/package.json +10 -6
  77. package/dist/renderPptx/pptxAuthoring.js.map +0 -1
@@ -2,29 +2,37 @@ import { getImageData } from "../shared/measureImage.js";
2
2
  import { resolveBoxSpacing } from "../shared/boxSpacing.js";
3
3
  import { getNodeDef } from "../registry/nodeRegistry.js";
4
4
  import { pxToEmu, pxToPt } from "./units.js";
5
- import { toColorInput } from "./pptxAuthoring.js";
6
- import { createGlimpseRunProperties } from "./utils/glimpseTextBox.js";
5
+ import { createGlimpseRunProperties, enrichPictureInput, enrichShapeInput, toColorInput, toSlideBackgroundGradient } from "./glimpseAdapter.js";
6
+ import "./utils/glimpseTextBox.js";
7
7
  import { imageBytesFromSource } from "./utils/glimpsePicture.js";
8
8
  import { createShapeBoundsInput, noneShapeFill, shapeOutline, solidShapeFill } from "./utils/glimpseShape.js";
9
9
  import "../registry/index.js";
10
10
  import { renderBackgroundAndBorder, renderBorderOnly } from "./utils/backgroundBorder.js";
11
+ import { PptxAuthoringContext } from "./authoringContext.js";
11
12
  import { createWritablePptx } from "./writablePptx.js";
12
- import { addEmptySlideFromLayout, addSlideNumber, asEmu, asPt, createPptx } from "@pptx-glimpse/document";
13
+ import { asEmu, asPt, createPptx } from "@pptx-glimpse/document";
13
14
  //#region src/renderPptx/renderPptx.ts
14
- function buildIdPositionMap(node, diagnostics) {
15
- const map = /* @__PURE__ */ new Map();
15
+ function buildIdMaps(node, diagnostics) {
16
+ const positions = /* @__PURE__ */ new Map();
17
+ const nodes = /* @__PURE__ */ new Map();
16
18
  function traverse(n) {
17
- if (n.id) if (map.has(n.id)) diagnostics.add("DUPLICATE_NODE_ID", `Duplicate node id "${n.id}" — only the first occurrence will be used for Arrow references`);
18
- else map.set(n.id, {
19
- x: n.x,
20
- y: n.y,
21
- w: n.w,
22
- h: n.h
23
- });
19
+ if (n.id) if (positions.has(n.id)) diagnostics.add("DUPLICATE_NODE_ID", `Duplicate node id "${n.id}" — only the first occurrence will be used for Arrow references`);
20
+ else {
21
+ positions.set(n.id, {
22
+ x: n.x,
23
+ y: n.y,
24
+ w: n.w,
25
+ h: n.h
26
+ });
27
+ nodes.set(n.id, n);
28
+ }
24
29
  if (n.type === "vstack" || n.type === "hstack" || n.type === "layer") for (const child of n.children) traverse(child);
25
30
  }
26
31
  traverse(node);
27
- return map;
32
+ return {
33
+ positions,
34
+ nodes
35
+ };
28
36
  }
29
37
  /**
30
38
  * zIndex でソートして描画順を制御する(安定ソート)
@@ -71,13 +79,13 @@ function masterTextRunProperties(obj) {
71
79
  fontSize: obj.fontSize === void 0 ? void 0 : properties.fontSize
72
80
  };
73
81
  }
74
- function addMasterContent(buildContext, master) {
75
- const target = buildContext.pptxAuthoring.source.slideMasters[0]?.handle;
82
+ function addMasterContent(buildContext, authoring, master) {
83
+ const target = authoring.source.slideMasters[0]?.handle;
76
84
  if (!target) throw new Error("createPptx did not create a slide master handle");
77
- buildContext.pptxAuthoring.selectSlide(target);
85
+ authoring.selectTarget(target);
78
86
  for (const obj of master.objects ?? []) switch (obj.type) {
79
87
  case "text":
80
- buildContext.pptxAuthoring.registerTextBox({
88
+ authoring.addTextBox({
81
89
  ...masterBounds(obj),
82
90
  body: {
83
91
  anchor: "middle",
@@ -101,13 +109,13 @@ function addMasterContent(buildContext, master) {
101
109
  });
102
110
  break;
103
111
  case "image":
104
- buildContext.pptxAuthoring.registerPicture({
112
+ authoring.addPicture(enrichPictureInput({
105
113
  ...masterBounds(obj),
106
114
  bytes: imageBytesFromSource(obj.src, getImageData(obj.src, buildContext.imageDataCache))
107
- });
115
+ }, void 0));
108
116
  break;
109
117
  case "rect":
110
- buildContext.pptxAuthoring.registerShape({
118
+ authoring.addShape(enrichShapeInput({
111
119
  ...masterBounds(obj),
112
120
  geometry: {
113
121
  kind: "preset",
@@ -118,10 +126,10 @@ function addMasterContent(buildContext, master) {
118
126
  }, {
119
127
  fillColor: obj.fill?.color,
120
128
  fillOpacity: obj.fill?.transparency === void 0 ? void 0 : 1 - obj.fill.transparency / 100
121
- });
129
+ }));
122
130
  break;
123
131
  case "line":
124
- buildContext.pptxAuthoring.registerShape({
132
+ authoring.addShape({
125
133
  ...masterBounds(obj),
126
134
  geometry: {
127
135
  kind: "preset",
@@ -137,7 +145,7 @@ function addMasterContent(buildContext, master) {
137
145
  }
138
146
  if (master.slideNumber) {
139
147
  const value = master.slideNumber;
140
- buildContext.pptxAuthoring.replaceSource(addSlideNumber(buildContext.pptxAuthoring.source, target, {
148
+ authoring.addSlideNumber({
141
149
  offsetX: asEmu(Math.round(pxToEmu(value.x))),
142
150
  offsetY: asEmu(Math.round(pxToEmu(value.y))),
143
151
  width: value.w === void 0 ? asEmu(8e5) : asEmu(Math.round(pxToEmu(value.w))),
@@ -147,7 +155,7 @@ function addMasterContent(buildContext, master) {
147
155
  fontSize: value.fontSize ? asPt(pxToPt(value.fontSize)) : void 0,
148
156
  color: toColorInput(value.color)
149
157
  }
150
- }));
158
+ });
151
159
  }
152
160
  }
153
161
  /**
@@ -159,7 +167,7 @@ function addMasterContent(buildContext, master) {
159
167
  */
160
168
  function renderPptx(pages, slidePx, buildContext, master) {
161
169
  const margin = master?.margin === void 0 ? void 0 : resolveBoxSpacing(master.margin);
162
- let source = createPptx({
170
+ const authoring = new PptxAuthoringContext(createPptx({
163
171
  slideSize: {
164
172
  width: asEmu(Math.round(pxToEmu(slidePx.w))),
165
173
  height: asEmu(Math.round(pxToEmu(slidePx.h)))
@@ -177,40 +185,60 @@ function renderPptx(pages, slidePx, buildContext, master) {
177
185
  left: asEmu(Math.round(pxToEmu(margin.left)))
178
186
  } : void 0
179
187
  }
180
- });
181
- buildContext.pptxAuthoring.initialize(source, margin !== void 0);
182
- if (master) addMasterContent(buildContext, master);
188
+ }), margin !== void 0);
189
+ if (master) addMasterContent(buildContext, authoring, master);
183
190
  for (const [pageIndex, data] of pages.entries()) {
184
191
  if (pageIndex > 0) {
185
- const layoutPartPath = buildContext.pptxAuthoring.source.slideLayouts[0]?.partPath;
192
+ const layoutPartPath = authoring.source.slideLayouts[0]?.partPath;
186
193
  if (!layoutPartPath) throw new Error("createPptx did not create a slide layout");
187
- source = addEmptySlideFromLayout(buildContext.pptxAuthoring.source, { layoutPartPath });
188
- buildContext.pptxAuthoring.replaceSource(source);
194
+ const slideHandle = authoring.addEmptySlideFromLayout({ layoutPartPath });
195
+ authoring.selectTarget(slideHandle);
196
+ } else {
197
+ const slideHandle = authoring.source.slides[pageIndex]?.handle;
198
+ if (!slideHandle) throw new Error(`slide handle was not found: ${pageIndex + 1}`);
199
+ authoring.selectTarget(slideHandle);
189
200
  }
190
- const slideHandle = buildContext.pptxAuthoring.source.slides[pageIndex]?.handle;
191
- if (!slideHandle) throw new Error(`slide handle was not found: ${pageIndex + 1}`);
192
- buildContext.pptxAuthoring.selectSlide(slideHandle);
201
+ const idMaps = buildIdMaps(data, buildContext.diagnostics);
193
202
  const ctx = {
194
203
  buildContext,
195
- idPositionMap: buildIdPositionMap(data, buildContext.diagnostics)
204
+ authoring,
205
+ idPositionMap: idMaps.positions,
206
+ idNodeMap: idMaps.nodes,
207
+ connectorTargetMap: /* @__PURE__ */ new Map()
196
208
  };
209
+ const deferredArrows = [];
197
210
  const isLinelike = data.type === "line" || data.type === "arrow";
198
211
  const rootBackgroundColor = !isLinelike ? data.backgroundColor : void 0;
199
212
  const rootBackgroundGradient = !isLinelike ? data.backgroundGradient : void 0;
200
213
  const rootHasOpacity = !isLinelike && "opacity" in data && data.opacity !== void 0;
201
- const rootGradientApplied = rootBackgroundGradient && !rootHasOpacity ? buildContext.pptxAuthoring.setSlideBackgroundGradient(rootBackgroundGradient) : false;
202
- if (!rootGradientApplied && rootBackgroundColor && !rootBackgroundGradient && !rootHasOpacity) buildContext.pptxAuthoring.setSlideBackgroundSolid(rootBackgroundColor);
214
+ const rootGradient = rootBackgroundGradient && !rootHasOpacity ? toSlideBackgroundGradient(rootBackgroundGradient) : void 0;
215
+ const rootGradientApplied = rootGradient !== void 0;
216
+ if (rootGradient) authoring.setSlideBackground(rootGradient);
217
+ if (!rootGradientApplied && rootBackgroundColor && !rootBackgroundGradient && !rootHasOpacity) authoring.setSlideBackground({
218
+ kind: "solid",
219
+ color: toColorInput(rootBackgroundColor)
220
+ });
203
221
  const rootBackgroundImage = !isLinelike ? data.backgroundImage : void 0;
204
222
  if (rootBackgroundImage) {
205
223
  const cachedData = getImageData(rootBackgroundImage.src, buildContext.imageDataCache);
206
- buildContext.pptxAuthoring.setSlideBackgroundImage(imageBytesFromSource(rootBackgroundImage.src, cachedData));
224
+ authoring.setSlideBackground({
225
+ kind: "image",
226
+ bytes: imageBytesFromSource(rootBackgroundImage.src, cachedData)
227
+ });
207
228
  }
208
229
  /**
209
230
  * node をスライドにレンダリングする
210
231
  * @param isRoot ルートノードかどうか(ルートノードの background は slide.background で処理済み)
211
232
  */
212
233
  function renderNode(node, isRoot = false) {
213
- if (node.type !== "line" && node.type !== "arrow") if (isRoot && (rootBackgroundImage || (rootBackgroundColor || rootGradientApplied) && !rootHasOpacity)) renderBorderOnly(node, ctx);
234
+ if (node.type === "arrow") {
235
+ deferredArrows.push({
236
+ node,
237
+ insertionIndex: authoring.currentTargetShapeHandles().length
238
+ });
239
+ return;
240
+ }
241
+ if (node.type !== "line") if (isRoot && (rootBackgroundImage || (rootBackgroundColor || rootGradientApplied) && !rootHasOpacity)) renderBorderOnly(node, ctx);
214
242
  else renderBackgroundAndBorder(node, ctx);
215
243
  const def = getNodeDef(node.type);
216
244
  switch (def.category) {
@@ -227,8 +255,33 @@ function renderPptx(pages, slidePx, buildContext, master) {
227
255
  }
228
256
  }
229
257
  renderNode(data, true);
258
+ const baseShapeOrder = [...authoring.currentTargetShapeHandles()];
259
+ const authoredArrows = [];
260
+ for (const arrow of deferredArrows) {
261
+ const beforeCount = authoring.currentTargetShapeHandles().length;
262
+ renderArrowNodeFromRegistry(arrow.node, ctx);
263
+ const after = authoring.currentTargetShapeHandles();
264
+ if (after.length === beforeCount + 1) authoredArrows.push({
265
+ insertionIndex: arrow.insertionIndex,
266
+ handle: after.at(-1)
267
+ });
268
+ }
269
+ if (authoredArrows.length > 0) {
270
+ const orderedHandles = [];
271
+ for (let index = 0; index <= baseShapeOrder.length; index += 1) {
272
+ for (const arrow of authoredArrows) if (arrow.insertionIndex === index) orderedHandles.push(arrow.handle);
273
+ const baseHandle = baseShapeOrder[index];
274
+ if (baseHandle) orderedHandles.push(baseHandle);
275
+ }
276
+ authoring.reorderCurrentTargetShapes(orderedHandles);
277
+ }
230
278
  }
231
- return createWritablePptx(() => buildContext.pptxAuthoring.source);
279
+ return createWritablePptx(() => authoring.source);
280
+ }
281
+ function renderArrowNodeFromRegistry(node, ctx) {
282
+ const def = getNodeDef("arrow");
283
+ if (!def.render) throw new Error("No render function registered for Arrow");
284
+ def.render(node, ctx);
232
285
  }
233
286
  //#endregion
234
287
  export { renderPptx };
@@ -1 +1 @@
1
- {"version":3,"file":"renderPptx.js","names":[],"sources":["../../src/renderPptx/renderPptx.ts"],"sourcesContent":["import {\n addEmptySlideFromLayout,\n addSlideNumber,\n asEmu,\n asPt,\n createPptx,\n type AddTextBoxRunPropertiesInput,\n type CreatePptxBackground,\n} from \"@pptx-glimpse/document\";\nimport type { PositionedNode, SlideMasterOptions } from \"../types.ts\";\nimport type { BuildContext } from \"../buildContext.ts\";\nimport type { RenderContext, NodeBounds } from \"./types.ts\";\nimport { pxToEmu, pxToPt } from \"./units.ts\";\nimport { getImageData } from \"../shared/measureImage.ts\";\nimport { resolveBoxSpacing } from \"../shared/boxSpacing.ts\";\nimport {\n renderBackgroundAndBorder,\n renderBorderOnly,\n} from \"./utils/backgroundBorder.ts\";\nimport { getNodeDef } from \"../registry/index.ts\";\nimport { toColorInput } from \"./pptxAuthoring.ts\";\nimport { createGlimpseRunProperties } from \"./utils/glimpseTextBox.ts\";\nimport {\n createShapeBoundsInput,\n noneShapeFill,\n shapeOutline,\n solidShapeFill,\n} from \"./utils/glimpseShape.ts\";\nimport { imageBytesFromSource } from \"./utils/glimpsePicture.ts\";\nimport { createWritablePptx } from \"./writablePptx.ts\";\n\ntype SlidePx = { w: number; h: number };\n\nfunction buildIdPositionMap(\n node: PositionedNode,\n diagnostics: import(\"../buildContext.ts\").BuildContext[\"diagnostics\"],\n): Map<string, NodeBounds> {\n const map = new Map<string, NodeBounds>();\n\n function traverse(n: PositionedNode) {\n if (n.id) {\n if (map.has(n.id)) {\n diagnostics.add(\n \"DUPLICATE_NODE_ID\",\n `Duplicate node id \"${n.id}\" — only the first occurrence will be used for Arrow references`,\n );\n } else {\n map.set(n.id, { x: n.x, y: n.y, w: n.w, h: n.h });\n }\n }\n if (n.type === \"vstack\" || n.type === \"hstack\" || n.type === \"layer\") {\n for (const child of n.children) {\n traverse(child);\n }\n }\n }\n\n traverse(node);\n return map;\n}\n\n/**\n * zIndex でソートして描画順を制御する(安定ソート)\n * zIndex が小さいノードが先に描画される(PowerPoint は追加順に重ねるため)\n */\nfunction sortByZIndex<T extends { zIndex?: number }>(children: T[]): T[] {\n // すべての子要素に zIndex が未設定の場合はそのまま返す\n if (children.every((c) => c.zIndex === undefined)) return children;\n return [...children].sort((a, b) => (a.zIndex ?? 0) - (b.zIndex ?? 0));\n}\n\nfunction masterBackground(\n master: SlideMasterOptions | undefined,\n buildContext: BuildContext,\n): CreatePptxBackground | undefined {\n const background = master?.background;\n if (!background) return undefined;\n if (\"color\" in background) {\n return { kind: \"solid\", color: toColorInput(background.color)! };\n }\n if (\"data\" in background) {\n return { kind: \"image\", bytes: imageBytesFromSource(\"\", background.data) };\n }\n const src = \"path\" in background ? background.path : background.image;\n return {\n kind: \"image\",\n bytes: imageBytesFromSource(\n src,\n getImageData(src, buildContext.imageDataCache),\n ),\n };\n}\n\nfunction masterBounds(obj: { x: number; y: number; w: number; h: number }) {\n return createShapeBoundsInput(obj);\n}\n\nfunction masterTextRunProperties(\n obj: Extract<\n NonNullable<SlideMasterOptions[\"objects\"]>[number],\n { type: \"text\" }\n >,\n): AddTextBoxRunPropertiesInput {\n const properties = createGlimpseRunProperties({\n fontSize: obj.fontSize,\n fontFace: obj.fontFamily,\n color: obj.color,\n bold: obj.bold,\n italic: obj.italic,\n underline: obj.underline,\n strike: obj.strike,\n highlight: obj.highlight,\n });\n return {\n ...properties,\n fontFace: obj.fontFamily === undefined ? undefined : properties.fontFace,\n fontSize: obj.fontSize === undefined ? undefined : properties.fontSize,\n };\n}\n\nfunction addMasterContent(\n buildContext: BuildContext,\n master: SlideMasterOptions,\n): void {\n const target = buildContext.pptxAuthoring.source.slideMasters[0]?.handle;\n if (!target)\n throw new Error(\"createPptx did not create a slide master handle\");\n buildContext.pptxAuthoring.selectSlide(target);\n for (const obj of master.objects ?? []) {\n switch (obj.type) {\n case \"text\":\n buildContext.pptxAuthoring.registerTextBox({\n ...masterBounds(obj),\n body: {\n anchor: \"middle\",\n marginLeft: asEmu(91440),\n marginRight: asEmu(91440),\n marginTop: asEmu(91440),\n marginBottom: asEmu(91440),\n },\n paragraphs: [\n {\n properties: {\n align: obj.textAlign,\n marginLeft: asEmu(0),\n indent: asEmu(0),\n bullet: { type: \"none\" },\n },\n runs: [\n {\n text: obj.text,\n properties: masterTextRunProperties(obj),\n },\n ],\n },\n ],\n });\n break;\n case \"image\":\n buildContext.pptxAuthoring.registerPicture({\n ...masterBounds(obj),\n bytes: imageBytesFromSource(\n obj.src,\n getImageData(obj.src, buildContext.imageDataCache),\n ),\n });\n break;\n case \"rect\":\n buildContext.pptxAuthoring.registerShape(\n {\n ...masterBounds(obj),\n geometry: { kind: \"preset\", preset: \"rect\" },\n fill: obj.fill\n ? solidShapeFill(obj.fill.color ?? \"FFFFFF\")\n : noneShapeFill(),\n outline: obj.border ? shapeOutline(obj.border) : undefined,\n },\n {\n fillColor: obj.fill?.color,\n fillOpacity:\n obj.fill?.transparency === undefined\n ? undefined\n : 1 - obj.fill.transparency / 100,\n },\n );\n break;\n case \"line\":\n buildContext.pptxAuthoring.registerShape({\n ...masterBounds(obj),\n geometry: { kind: \"preset\", preset: \"line\" },\n fill: noneShapeFill(),\n outline: shapeOutline(obj.line ?? { color: \"000000\", width: 1 }),\n });\n break;\n }\n }\n if (master.slideNumber) {\n const value = master.slideNumber;\n buildContext.pptxAuthoring.replaceSource(\n addSlideNumber(buildContext.pptxAuthoring.source, target, {\n offsetX: asEmu(Math.round(pxToEmu(value.x))),\n offsetY: asEmu(Math.round(pxToEmu(value.y))),\n width:\n value.w === undefined\n ? asEmu(800000)\n : asEmu(Math.round(pxToEmu(value.w))),\n height:\n value.h === undefined\n ? asEmu(300000)\n : asEmu(Math.round(pxToEmu(value.h))),\n properties: {\n fontFace: value.fontFamily,\n fontSize: value.fontSize ? asPt(pxToPt(value.fontSize)) : undefined,\n color: toColorInput(value.color),\n },\n }),\n );\n }\n}\n\n/**\n * PositionedNode ツリーを glimpse の PPTX source model に変換する\n * @param pages PositionedNode ツリーの配列(各要素が1ページ)\n * @param slidePx スライド全体のサイズ(px)\n * @param master スライドマスターオプション(省略可能)\n * @returns PPTX の write / writeFile / stream 互換 facade\n */\nexport function renderPptx(\n pages: PositionedNode[],\n slidePx: SlidePx,\n buildContext: BuildContext,\n master?: SlideMasterOptions,\n) {\n const margin =\n master?.margin === undefined ? undefined : resolveBoxSpacing(master.margin);\n let source = createPptx({\n slideSize: {\n width: asEmu(Math.round(pxToEmu(slidePx.w))),\n height: asEmu(Math.round(pxToEmu(slidePx.h))),\n },\n slideMaster: {\n name: master?.title ?? \"POM_MASTER\",\n background: masterBackground(master, buildContext),\n },\n slideLayout: {\n name: \"POM_LAYOUT\",\n margin: margin\n ? {\n top: asEmu(Math.round(pxToEmu(margin.top))),\n right: asEmu(Math.round(pxToEmu(margin.right))),\n bottom: asEmu(Math.round(pxToEmu(margin.bottom))),\n left: asEmu(Math.round(pxToEmu(margin.left))),\n }\n : undefined,\n },\n });\n buildContext.pptxAuthoring.initialize(source, margin !== undefined);\n if (master) addMasterContent(buildContext, master);\n\n for (const [pageIndex, data] of pages.entries()) {\n if (pageIndex > 0) {\n const layoutPartPath =\n buildContext.pptxAuthoring.source.slideLayouts[0]?.partPath;\n if (!layoutPartPath)\n throw new Error(\"createPptx did not create a slide layout\");\n source = addEmptySlideFromLayout(buildContext.pptxAuthoring.source, {\n layoutPartPath,\n });\n buildContext.pptxAuthoring.replaceSource(source);\n }\n const slideHandle =\n buildContext.pptxAuthoring.source.slides[pageIndex]?.handle;\n if (!slideHandle)\n throw new Error(`slide handle was not found: ${pageIndex + 1}`);\n buildContext.pptxAuthoring.selectSlide(slideHandle);\n const idPositionMap = buildIdPositionMap(data, buildContext.diagnostics);\n const ctx: RenderContext = { buildContext, idPositionMap };\n\n // ルートノードの backgroundColor はスライドの background プロパティとして適用\n // これにより、マスタースライドのオブジェクトを覆い隠さない\n // line/arrow ノードは backgroundColor を持たないためスキップ\n // ただし opacity が指定されている場合は slide.background では透過を表現できないため、\n // renderBackgroundAndBorder で描画する\n const isLinelike = data.type === \"line\" || data.type === \"arrow\";\n const rootBackgroundColor = !isLinelike ? data.backgroundColor : undefined;\n const rootBackgroundGradient = !isLinelike\n ? data.backgroundGradient\n : undefined;\n const rootHasOpacity =\n !isLinelike && \"opacity\" in data && data.opacity !== undefined;\n const rootGradientApplied =\n rootBackgroundGradient && !rootHasOpacity\n ? buildContext.pptxAuthoring.setSlideBackgroundGradient(\n rootBackgroundGradient,\n )\n : false;\n if (\n !rootGradientApplied &&\n rootBackgroundColor &&\n !rootBackgroundGradient &&\n !rootHasOpacity\n ) {\n buildContext.pptxAuthoring.setSlideBackgroundSolid(rootBackgroundColor);\n }\n\n // ルートノードの backgroundImage はスライドの background プロパティとして適用\n // backgroundColor と backgroundImage の両方がある場合、backgroundImage が優先\n const rootBackgroundImage = !isLinelike ? data.backgroundImage : undefined;\n if (rootBackgroundImage) {\n const cachedData = getImageData(\n rootBackgroundImage.src,\n buildContext.imageDataCache,\n );\n buildContext.pptxAuthoring.setSlideBackgroundImage(\n imageBytesFromSource(rootBackgroundImage.src, cachedData),\n );\n }\n\n /**\n * node をスライドにレンダリングする\n * @param isRoot ルートノードかどうか(ルートノードの background は slide.background で処理済み)\n */\n function renderNode(node: PositionedNode, isRoot = false) {\n // line/arrow ノードは backgroundColor/border を持たないため、background/border の描画をスキップ\n if (node.type !== \"line\" && node.type !== \"arrow\") {\n // ルートノードの backgroundColor/backgroundImage は既に slide.background に適用済みなのでスキップ\n // ただし opacity がある場合は slide.background では透過を表現できないため通常描画\n if (\n isRoot &&\n (rootBackgroundImage ||\n ((rootBackgroundColor || rootGradientApplied) && !rootHasOpacity))\n ) {\n // border のみ描画(backgroundColor/backgroundImage はスキップ)\n renderBorderOnly(node, ctx);\n } else {\n renderBackgroundAndBorder(node, ctx);\n }\n }\n\n const def = getNodeDef(node.type);\n\n switch (def.category) {\n case \"leaf\":\n if (!def.render) {\n throw new Error(\n `No render function registered for leaf node: ${node.type}`,\n );\n }\n def.render(node, ctx);\n break;\n\n case \"multi-child\":\n case \"absolute-child\": {\n const containerNode = node as Extract<\n PositionedNode,\n { type: \"vstack\" | \"hstack\" | \"layer\" }\n >;\n // zIndex でソートして描画順を制御(値が小さいものが先に描画される)\n for (const child of sortByZIndex(containerNode.children)) {\n renderNode(child);\n }\n break;\n }\n }\n }\n\n renderNode(data, true); // ルートノードとして処理\n }\n\n return createWritablePptx(() => buildContext.pptxAuthoring.source);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"renderPptx.js","names":[],"sources":["../../src/renderPptx/renderPptx.ts"],"sourcesContent":["import {\n asEmu,\n asPt,\n createPptx,\n type AddTextBoxRunPropertiesInput,\n type CreatePptxBackground,\n} from \"@pptx-glimpse/document\";\nimport type { PositionedNode, SlideMasterOptions } from \"../types.ts\";\nimport type { BuildContext } from \"../buildContext.ts\";\nimport type { RenderContext, NodeBounds } from \"./types.ts\";\nimport { pxToEmu, pxToPt } from \"./units.ts\";\nimport { getImageData } from \"../shared/measureImage.ts\";\nimport { resolveBoxSpacing } from \"../shared/boxSpacing.ts\";\nimport {\n renderBackgroundAndBorder,\n renderBorderOnly,\n} from \"./utils/backgroundBorder.ts\";\nimport { getNodeDef } from \"../registry/index.ts\";\nimport {\n enrichPictureInput,\n enrichShapeInput,\n toColorInput,\n toSlideBackgroundGradient,\n} from \"./glimpseAdapter.ts\";\nimport { PptxAuthoringContext } from \"./authoringContext.ts\";\nimport { createGlimpseRunProperties } from \"./utils/glimpseTextBox.ts\";\nimport {\n createShapeBoundsInput,\n noneShapeFill,\n shapeOutline,\n solidShapeFill,\n} from \"./utils/glimpseShape.ts\";\nimport { imageBytesFromSource } from \"./utils/glimpsePicture.ts\";\nimport { createWritablePptx } from \"./writablePptx.ts\";\n\ntype SlidePx = { w: number; h: number };\n\nfunction buildIdMaps(\n node: PositionedNode,\n diagnostics: import(\"../buildContext.ts\").BuildContext[\"diagnostics\"],\n): {\n positions: Map<string, NodeBounds>;\n nodes: Map<string, PositionedNode>;\n} {\n const positions = new Map<string, NodeBounds>();\n const nodes = new Map<string, PositionedNode>();\n\n function traverse(n: PositionedNode) {\n if (n.id) {\n if (positions.has(n.id)) {\n diagnostics.add(\n \"DUPLICATE_NODE_ID\",\n `Duplicate node id \"${n.id}\" — only the first occurrence will be used for Arrow references`,\n );\n } else {\n positions.set(n.id, { x: n.x, y: n.y, w: n.w, h: n.h });\n nodes.set(n.id, n);\n }\n }\n if (n.type === \"vstack\" || n.type === \"hstack\" || n.type === \"layer\") {\n for (const child of n.children) {\n traverse(child);\n }\n }\n }\n\n traverse(node);\n return { positions, nodes };\n}\n\n/**\n * zIndex でソートして描画順を制御する(安定ソート)\n * zIndex が小さいノードが先に描画される(PowerPoint は追加順に重ねるため)\n */\nfunction sortByZIndex<T extends { zIndex?: number }>(children: T[]): T[] {\n // すべての子要素に zIndex が未設定の場合はそのまま返す\n if (children.every((c) => c.zIndex === undefined)) return children;\n return [...children].sort((a, b) => (a.zIndex ?? 0) - (b.zIndex ?? 0));\n}\n\nfunction masterBackground(\n master: SlideMasterOptions | undefined,\n buildContext: BuildContext,\n): CreatePptxBackground | undefined {\n const background = master?.background;\n if (!background) return undefined;\n if (\"color\" in background) {\n return { kind: \"solid\", color: toColorInput(background.color)! };\n }\n if (\"data\" in background) {\n return { kind: \"image\", bytes: imageBytesFromSource(\"\", background.data) };\n }\n const src = \"path\" in background ? background.path : background.image;\n return {\n kind: \"image\",\n bytes: imageBytesFromSource(\n src,\n getImageData(src, buildContext.imageDataCache),\n ),\n };\n}\n\nfunction masterBounds(obj: { x: number; y: number; w: number; h: number }) {\n return createShapeBoundsInput(obj);\n}\n\nfunction masterTextRunProperties(\n obj: Extract<\n NonNullable<SlideMasterOptions[\"objects\"]>[number],\n { type: \"text\" }\n >,\n): AddTextBoxRunPropertiesInput {\n const properties = createGlimpseRunProperties({\n fontSize: obj.fontSize,\n fontFace: obj.fontFamily,\n color: obj.color,\n bold: obj.bold,\n italic: obj.italic,\n underline: obj.underline,\n strike: obj.strike,\n highlight: obj.highlight,\n });\n return {\n ...properties,\n fontFace: obj.fontFamily === undefined ? undefined : properties.fontFace,\n fontSize: obj.fontSize === undefined ? undefined : properties.fontSize,\n };\n}\n\nfunction addMasterContent(\n buildContext: BuildContext,\n authoring: PptxAuthoringContext,\n master: SlideMasterOptions,\n): void {\n const target = authoring.source.slideMasters[0]?.handle;\n if (!target)\n throw new Error(\"createPptx did not create a slide master handle\");\n authoring.selectTarget(target);\n for (const obj of master.objects ?? []) {\n switch (obj.type) {\n case \"text\":\n authoring.addTextBox({\n ...masterBounds(obj),\n body: {\n anchor: \"middle\",\n marginLeft: asEmu(91440),\n marginRight: asEmu(91440),\n marginTop: asEmu(91440),\n marginBottom: asEmu(91440),\n },\n paragraphs: [\n {\n properties: {\n align: obj.textAlign,\n marginLeft: asEmu(0),\n indent: asEmu(0),\n bullet: { type: \"none\" },\n },\n runs: [\n {\n text: obj.text,\n properties: masterTextRunProperties(obj),\n },\n ],\n },\n ],\n });\n break;\n case \"image\":\n authoring.addPicture(\n enrichPictureInput(\n {\n ...masterBounds(obj),\n bytes: imageBytesFromSource(\n obj.src,\n getImageData(obj.src, buildContext.imageDataCache),\n ),\n },\n undefined,\n ),\n );\n break;\n case \"rect\":\n authoring.addShape(\n enrichShapeInput(\n {\n ...masterBounds(obj),\n geometry: { kind: \"preset\", preset: \"rect\" },\n fill: obj.fill\n ? solidShapeFill(obj.fill.color ?? \"FFFFFF\")\n : noneShapeFill(),\n outline: obj.border ? shapeOutline(obj.border) : undefined,\n },\n {\n fillColor: obj.fill?.color,\n fillOpacity:\n obj.fill?.transparency === undefined\n ? undefined\n : 1 - obj.fill.transparency / 100,\n },\n ),\n );\n break;\n case \"line\":\n authoring.addShape({\n ...masterBounds(obj),\n geometry: { kind: \"preset\", preset: \"line\" },\n fill: noneShapeFill(),\n outline: shapeOutline(obj.line ?? { color: \"000000\", width: 1 }),\n });\n break;\n }\n }\n if (master.slideNumber) {\n const value = master.slideNumber;\n authoring.addSlideNumber({\n offsetX: asEmu(Math.round(pxToEmu(value.x))),\n offsetY: asEmu(Math.round(pxToEmu(value.y))),\n width:\n value.w === undefined\n ? asEmu(800000)\n : asEmu(Math.round(pxToEmu(value.w))),\n height:\n value.h === undefined\n ? asEmu(300000)\n : asEmu(Math.round(pxToEmu(value.h))),\n properties: {\n fontFace: value.fontFamily,\n fontSize: value.fontSize ? asPt(pxToPt(value.fontSize)) : undefined,\n color: toColorInput(value.color),\n },\n });\n }\n}\n\n/**\n * PositionedNode ツリーを glimpse の PPTX source model に変換する\n * @param pages PositionedNode ツリーの配列(各要素が1ページ)\n * @param slidePx スライド全体のサイズ(px)\n * @param master スライドマスターオプション(省略可能)\n * @returns PPTX の write / writeFile / stream 互換 facade\n */\nexport function renderPptx(\n pages: PositionedNode[],\n slidePx: SlidePx,\n buildContext: BuildContext,\n master?: SlideMasterOptions,\n) {\n const margin =\n master?.margin === undefined ? undefined : resolveBoxSpacing(master.margin);\n const source = createPptx({\n slideSize: {\n width: asEmu(Math.round(pxToEmu(slidePx.w))),\n height: asEmu(Math.round(pxToEmu(slidePx.h))),\n },\n slideMaster: {\n name: master?.title ?? \"POM_MASTER\",\n background: masterBackground(master, buildContext),\n },\n slideLayout: {\n name: \"POM_LAYOUT\",\n margin: margin\n ? {\n top: asEmu(Math.round(pxToEmu(margin.top))),\n right: asEmu(Math.round(pxToEmu(margin.right))),\n bottom: asEmu(Math.round(pxToEmu(margin.bottom))),\n left: asEmu(Math.round(pxToEmu(margin.left))),\n }\n : undefined,\n },\n });\n const authoring = new PptxAuthoringContext(source, margin !== undefined);\n if (master) addMasterContent(buildContext, authoring, master);\n\n for (const [pageIndex, data] of pages.entries()) {\n if (pageIndex > 0) {\n const layoutPartPath = authoring.source.slideLayouts[0]?.partPath;\n if (!layoutPartPath)\n throw new Error(\"createPptx did not create a slide layout\");\n const slideHandle = authoring.addEmptySlideFromLayout({\n layoutPartPath,\n });\n authoring.selectTarget(slideHandle);\n } else {\n const slideHandle = authoring.source.slides[pageIndex]?.handle;\n if (!slideHandle)\n throw new Error(`slide handle was not found: ${pageIndex + 1}`);\n authoring.selectTarget(slideHandle);\n }\n const idMaps = buildIdMaps(data, buildContext.diagnostics);\n const ctx: RenderContext = {\n buildContext,\n authoring,\n idPositionMap: idMaps.positions,\n idNodeMap: idMaps.nodes,\n connectorTargetMap: new Map(),\n };\n const deferredArrows: {\n node: Extract<PositionedNode, { type: \"arrow\" }>;\n insertionIndex: number;\n }[] = [];\n\n // ルートノードの backgroundColor はスライドの background プロパティとして適用\n // これにより、マスタースライドのオブジェクトを覆い隠さない\n // line/arrow ノードは backgroundColor を持たないためスキップ\n // ただし opacity が指定されている場合は slide.background では透過を表現できないため、\n // renderBackgroundAndBorder で描画する\n const isLinelike = data.type === \"line\" || data.type === \"arrow\";\n const rootBackgroundColor = !isLinelike ? data.backgroundColor : undefined;\n const rootBackgroundGradient = !isLinelike\n ? data.backgroundGradient\n : undefined;\n const rootHasOpacity =\n !isLinelike && \"opacity\" in data && data.opacity !== undefined;\n const rootGradient =\n rootBackgroundGradient && !rootHasOpacity\n ? toSlideBackgroundGradient(rootBackgroundGradient)\n : undefined;\n const rootGradientApplied = rootGradient !== undefined;\n if (rootGradient) authoring.setSlideBackground(rootGradient);\n if (\n !rootGradientApplied &&\n rootBackgroundColor &&\n !rootBackgroundGradient &&\n !rootHasOpacity\n ) {\n authoring.setSlideBackground({\n kind: \"solid\",\n color: toColorInput(rootBackgroundColor)!,\n });\n }\n\n // ルートノードの backgroundImage はスライドの background プロパティとして適用\n // backgroundColor と backgroundImage の両方がある場合、backgroundImage が優先\n const rootBackgroundImage = !isLinelike ? data.backgroundImage : undefined;\n if (rootBackgroundImage) {\n const cachedData = getImageData(\n rootBackgroundImage.src,\n buildContext.imageDataCache,\n );\n authoring.setSlideBackground({\n kind: \"image\",\n bytes: imageBytesFromSource(rootBackgroundImage.src, cachedData),\n });\n }\n\n /**\n * node をスライドにレンダリングする\n * @param isRoot ルートノードかどうか(ルートノードの background は slide.background で処理済み)\n */\n function renderNode(node: PositionedNode, isRoot = false) {\n // Native connector は接続先の authored shape handle が必要なため、\n // 通常ノードをすべて追加した後に authoring し、最後にこの位置へ戻す。\n if (node.type === \"arrow\") {\n deferredArrows.push({\n node,\n insertionIndex: authoring.currentTargetShapeHandles().length,\n });\n return;\n }\n\n // Arrow は上で defer 済み。Line は backgroundColor/border を持たない。\n if (node.type !== \"line\") {\n // ルートノードの backgroundColor/backgroundImage は既に slide.background に適用済みなのでスキップ\n // ただし opacity がある場合は slide.background では透過を表現できないため通常描画\n if (\n isRoot &&\n (rootBackgroundImage ||\n ((rootBackgroundColor || rootGradientApplied) && !rootHasOpacity))\n ) {\n // border のみ描画(backgroundColor/backgroundImage はスキップ)\n renderBorderOnly(node, ctx);\n } else {\n renderBackgroundAndBorder(node, ctx);\n }\n }\n\n const def = getNodeDef(node.type);\n\n switch (def.category) {\n case \"leaf\":\n if (!def.render) {\n throw new Error(\n `No render function registered for leaf node: ${node.type}`,\n );\n }\n def.render(node, ctx);\n break;\n\n case \"multi-child\":\n case \"absolute-child\": {\n const containerNode = node as Extract<\n PositionedNode,\n { type: \"vstack\" | \"hstack\" | \"layer\" }\n >;\n // zIndex でソートして描画順を制御(値が小さいものが先に描画される)\n for (const child of sortByZIndex(containerNode.children)) {\n renderNode(child);\n }\n break;\n }\n }\n }\n\n renderNode(data, true); // ルートノードとして処理\n const baseShapeOrder = [...authoring.currentTargetShapeHandles()];\n const authoredArrows: {\n insertionIndex: number;\n handle: (typeof baseShapeOrder)[number];\n }[] = [];\n for (const arrow of deferredArrows) {\n const beforeCount = authoring.currentTargetShapeHandles().length;\n renderArrowNodeFromRegistry(arrow.node, ctx);\n const after = authoring.currentTargetShapeHandles();\n if (after.length === beforeCount + 1) {\n authoredArrows.push({\n insertionIndex: arrow.insertionIndex,\n handle: after.at(-1)!,\n });\n }\n }\n if (authoredArrows.length > 0) {\n const orderedHandles: (typeof baseShapeOrder)[number][] = [];\n for (let index = 0; index <= baseShapeOrder.length; index += 1) {\n for (const arrow of authoredArrows) {\n if (arrow.insertionIndex === index) orderedHandles.push(arrow.handle);\n }\n const baseHandle = baseShapeOrder[index];\n if (baseHandle) orderedHandles.push(baseHandle);\n }\n authoring.reorderCurrentTargetShapes(orderedHandles);\n }\n }\n\n return createWritablePptx(() => authoring.source);\n}\n\nfunction renderArrowNodeFromRegistry(\n node: Extract<PositionedNode, { type: \"arrow\" }>,\n ctx: RenderContext,\n): void {\n const def = getNodeDef(\"arrow\");\n if (!def.render) throw new Error(\"No render function registered for Arrow\");\n def.render(node, ctx);\n}\n"],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ //#region src/renderPptx/utils/connectorSites.ts
2
+ const cardinalConnectorShapeTypes = /* @__PURE__ */ new Set([
3
+ "rect",
4
+ "roundRect",
5
+ "ellipse"
6
+ ]);
7
+ function supportsCardinalConnectorSites(shapeType) {
8
+ return cardinalConnectorShapeTypes.has(shapeType);
9
+ }
10
+ /**
11
+ * DrawingML の rect / roundRect / ellipse / text box に共通する4接続点。
12
+ * index は geometry 固有のローカル座標系に属するため、画面上の座標だけを
13
+ * shape の中心まわりに回転し、index 自体は維持する。
14
+ */
15
+ function cardinalConnectorSites(bounds, rotate = 0) {
16
+ const centerX = bounds.x + bounds.w / 2;
17
+ const centerY = bounds.y + bounds.h / 2;
18
+ const sites = [
19
+ {
20
+ index: 0,
21
+ x: centerX,
22
+ y: bounds.y
23
+ },
24
+ {
25
+ index: 1,
26
+ x: bounds.x,
27
+ y: centerY
28
+ },
29
+ {
30
+ index: 2,
31
+ x: centerX,
32
+ y: bounds.y + bounds.h
33
+ },
34
+ {
35
+ index: 3,
36
+ x: bounds.x + bounds.w,
37
+ y: centerY
38
+ }
39
+ ];
40
+ const normalized = (rotate % 360 + 360) % 360;
41
+ if (normalized === 0) return sites;
42
+ const radians = normalized * Math.PI / 180;
43
+ const cos = Math.cos(radians);
44
+ const sin = Math.sin(radians);
45
+ return sites.map((site) => {
46
+ const dx = site.x - centerX;
47
+ const dy = site.y - centerY;
48
+ return {
49
+ index: site.index,
50
+ x: centerX + dx * cos - dy * sin,
51
+ y: centerY + dx * sin + dy * cos
52
+ };
53
+ });
54
+ }
55
+ //#endregion
56
+ export { cardinalConnectorSites, supportsCardinalConnectorSites };
57
+
58
+ //# sourceMappingURL=connectorSites.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connectorSites.js","names":[],"sources":["../../../src/renderPptx/utils/connectorSites.ts"],"sourcesContent":["import type { PositionedNode } from \"../../types.ts\";\nimport type { NodeBounds } from \"../types.ts\";\n\nexport type ConnectorSite = {\n index: 0 | 1 | 2 | 3;\n x: number;\n y: number;\n};\n\ntype ShapeType = Extract<PositionedNode, { type: \"shape\" }>[\"shapeType\"];\n\nconst cardinalConnectorShapeTypes: ReadonlySet<ShapeType> = new Set([\n \"rect\",\n \"roundRect\",\n \"ellipse\",\n]);\n\nexport function supportsCardinalConnectorSites(shapeType: ShapeType): boolean {\n return cardinalConnectorShapeTypes.has(shapeType);\n}\n\n/**\n * DrawingML の rect / roundRect / ellipse / text box に共通する4接続点。\n * index は geometry 固有のローカル座標系に属するため、画面上の座標だけを\n * shape の中心まわりに回転し、index 自体は維持する。\n */\nexport function cardinalConnectorSites(\n bounds: NodeBounds,\n rotate = 0,\n): readonly ConnectorSite[] {\n const centerX = bounds.x + bounds.w / 2;\n const centerY = bounds.y + bounds.h / 2;\n const sites: readonly ConnectorSite[] = [\n { index: 0, x: centerX, y: bounds.y },\n { index: 1, x: bounds.x, y: centerY },\n { index: 2, x: centerX, y: bounds.y + bounds.h },\n { index: 3, x: bounds.x + bounds.w, y: centerY },\n ];\n const normalized = ((rotate % 360) + 360) % 360;\n if (normalized === 0) return sites;\n\n const radians = (normalized * Math.PI) / 180;\n const cos = Math.cos(radians);\n const sin = Math.sin(radians);\n return sites.map((site) => {\n const dx = site.x - centerX;\n const dy = site.y - centerY;\n return {\n index: site.index,\n x: centerX + dx * cos - dy * sin,\n y: centerY + dx * sin + dy * cos,\n };\n });\n}\n"],"mappings":";AAWA,MAAM,8CAAsD,IAAI,IAAI;CAClE;CACA;CACA;AACF,CAAC;AAED,SAAgB,+BAA+B,WAA+B;CAC5E,OAAO,4BAA4B,IAAI,SAAS;AAClD;;;;;;AAOA,SAAgB,uBACd,QACA,SAAS,GACiB;CAC1B,MAAM,UAAU,OAAO,IAAI,OAAO,IAAI;CACtC,MAAM,UAAU,OAAO,IAAI,OAAO,IAAI;CACtC,MAAM,QAAkC;EACtC;GAAE,OAAO;GAAG,GAAG;GAAS,GAAG,OAAO;EAAE;EACpC;GAAE,OAAO;GAAG,GAAG,OAAO;GAAG,GAAG;EAAQ;EACpC;GAAE,OAAO;GAAG,GAAG;GAAS,GAAG,OAAO,IAAI,OAAO;EAAE;EAC/C;GAAE,OAAO;GAAG,GAAG,OAAO,IAAI,OAAO;GAAG,GAAG;EAAQ;CACjD;CACA,MAAM,cAAe,SAAS,MAAO,OAAO;CAC5C,IAAI,eAAe,GAAG,OAAO;CAE7B,MAAM,UAAW,aAAa,KAAK,KAAM;CACzC,MAAM,MAAM,KAAK,IAAI,OAAO;CAC5B,MAAM,MAAM,KAAK,IAAI,OAAO;CAC5B,OAAO,MAAM,KAAK,SAAS;EACzB,MAAM,KAAK,KAAK,IAAI;EACpB,MAAM,KAAK,KAAK,IAAI;EACpB,OAAO;GACL,OAAO,KAAK;GACZ,GAAG,UAAU,KAAK,MAAM,KAAK;GAC7B,GAAG,UAAU,KAAK,MAAM,KAAK;EAC/B;CACF,CAAC;AACH"}
@@ -1,4 +1,5 @@
1
1
  import { pxToEmu } from "../units.js";
2
+ import { enrichPictureInput } from "../glimpseAdapter.js";
2
3
  import * as fs from "fs";
3
4
  import { asEmu, asOoxmlAngle, asOoxmlPercent } from "@pptx-glimpse/document";
4
5
  //#region src/renderPptx/utils/glimpsePicture.ts
@@ -100,10 +101,7 @@ function addGlimpsePicture(ctx, content, bytes, options) {
100
101
  rotation: createPictureRotationInput(options?.rotate),
101
102
  crop: sizingResult.crop
102
103
  };
103
- ctx.buildContext.pptxAuthoring.registerPicture(input, {
104
- name: options?.name,
105
- shadow: options?.shadow
106
- });
104
+ ctx.authoring.addPicture(enrichPictureInput(input, options?.shadow), options?.name);
107
105
  }
108
106
  //#endregion
109
107
  export { addGlimpsePicture, imageBytesFromSource };
@@ -1 +1 @@
1
- {"version":3,"file":"glimpsePicture.js","names":[],"sources":["../../../src/renderPptx/utils/glimpsePicture.ts"],"sourcesContent":["import * as fs from \"fs\";\nimport {\n asEmu,\n asOoxmlAngle,\n asOoxmlPercent,\n type AddPictureCropInput,\n type AddPictureInput,\n} from \"@pptx-glimpse/document\";\nimport type { ShadowStyle } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { pxToEmu } from \"../units.ts\";\n\ntype PictureBoundsPx = { x: number; y: number; w: number; h: number };\ntype ImageSizing = {\n type: \"contain\" | \"cover\" | \"crop\";\n w?: number;\n h?: number;\n x?: number;\n y?: number;\n};\n\nconst FALLBACK_PNG =\n \"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=\";\n\nfunction dataToBytes(data: string): Uint8Array {\n const base64 = data.includes(\",\") ? data.split(\",\").at(-1) : data;\n return new Uint8Array(Buffer.from(base64 ?? \"\", \"base64\"));\n}\n\nfunction isPngOrJpeg(bytes: Uint8Array): boolean {\n const isPng =\n bytes[0] === 0x89 &&\n bytes[1] === 0x50 &&\n bytes[2] === 0x4e &&\n bytes[3] === 0x47;\n const isJpeg = bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff;\n return isPng || isJpeg;\n}\n\nfunction supportedOrFallback(bytes: Uint8Array): Uint8Array {\n return isPngOrJpeg(bytes) ? bytes : dataToBytes(FALLBACK_PNG);\n}\n\nexport function imageBytesFromSource(src: string, data?: string): Uint8Array {\n if (data) return supportedOrFallback(dataToBytes(data));\n if (src.startsWith(\"data:\")) return supportedOrFallback(dataToBytes(src));\n if (src.startsWith(\"http://\") || src.startsWith(\"https://\")) {\n return dataToBytes(FALLBACK_PNG);\n }\n try {\n return supportedOrFallback(new Uint8Array(fs.readFileSync(src)));\n } catch {\n return dataToBytes(FALLBACK_PNG);\n }\n}\n\nfunction positiveEmu(valuePx: number) {\n return asEmu(Math.max(1, Math.round(pxToEmu(valuePx))));\n}\n\nfunction createPictureRotationInput(rotate: number | undefined) {\n return rotate !== undefined\n ? asOoxmlAngle(Math.round(rotate * 60000))\n : undefined;\n}\n\nfunction pct(value: number) {\n return asOoxmlPercent(Math.round(value));\n}\n\nfunction createSizingCrop(\n sizing: ImageSizing,\n content: PictureBoundsPx,\n): { bounds: PictureBoundsPx; crop?: AddPictureCropInput } {\n const box = {\n x: sizing.x ?? 0,\n y: sizing.y ?? 0,\n w: sizing.w ?? content.w,\n h: sizing.h ?? content.h,\n };\n const img = { w: content.w, h: content.h };\n\n if (sizing.type === \"crop\") {\n const cropBase = { w: content.w, h: content.h };\n return {\n bounds: { ...content, w: box.w, h: box.h },\n crop: {\n left: pct(100000 * (box.x / cropBase.w)),\n right: pct(100000 * ((cropBase.w - (box.x + box.w)) / cropBase.w)),\n top: pct(100000 * (box.y / cropBase.h)),\n bottom: pct(100000 * ((cropBase.h - (box.y + box.h)) / cropBase.h)),\n },\n };\n }\n\n const imgRatio = img.h / img.w;\n const boxRatio = box.h / box.w;\n const isCoverBoxBased = boxRatio > imgRatio;\n const isContainWidthBased = boxRatio > imgRatio;\n const width =\n sizing.type === \"cover\"\n ? isCoverBoxBased\n ? box.h / imgRatio\n : box.w\n : isContainWidthBased\n ? box.w\n : box.h / imgRatio;\n const height =\n sizing.type === \"cover\"\n ? isCoverBoxBased\n ? box.h\n : box.w * imgRatio\n : isContainWidthBased\n ? box.w * imgRatio\n : box.h;\n const horizontal = 100000 * 0.5 * (1 - box.w / width);\n const vertical = 100000 * 0.5 * (1 - box.h / height);\n\n return {\n bounds: { ...content, w: box.w, h: box.h },\n crop: {\n left: pct(horizontal),\n right: pct(horizontal),\n top: pct(vertical),\n bottom: pct(vertical),\n },\n };\n}\n\nexport function addGlimpsePicture(\n ctx: RenderContext,\n content: PictureBoundsPx,\n bytes: Uint8Array,\n options?: {\n rotate?: number;\n sizing?: ImageSizing;\n name?: string;\n shadow?: ShadowStyle;\n },\n): void {\n const sizingResult = options?.sizing\n ? createSizingCrop(options.sizing, content)\n : { bounds: content, crop: undefined };\n const input: AddPictureInput = {\n bytes,\n offsetX: asEmu(Math.round(pxToEmu(content.x))),\n offsetY: asEmu(Math.round(pxToEmu(content.y))),\n width: positiveEmu(sizingResult.bounds.w),\n height: positiveEmu(sizingResult.bounds.h),\n rotation: createPictureRotationInput(options?.rotate),\n crop: sizingResult.crop,\n };\n ctx.buildContext.pptxAuthoring.registerPicture(input, {\n name: options?.name,\n shadow: options?.shadow,\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"glimpsePicture.js","names":[],"sources":["../../../src/renderPptx/utils/glimpsePicture.ts"],"sourcesContent":["import * as fs from \"fs\";\nimport {\n asEmu,\n asOoxmlAngle,\n asOoxmlPercent,\n type AddPictureCropInput,\n type AddPictureInput,\n} from \"@pptx-glimpse/document\";\nimport type { ShadowStyle } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { pxToEmu } from \"../units.ts\";\nimport { enrichPictureInput } from \"../glimpseAdapter.ts\";\n\ntype PictureBoundsPx = { x: number; y: number; w: number; h: number };\ntype ImageSizing = {\n type: \"contain\" | \"cover\" | \"crop\";\n w?: number;\n h?: number;\n x?: number;\n y?: number;\n};\n\nconst FALLBACK_PNG =\n \"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=\";\n\nfunction dataToBytes(data: string): Uint8Array {\n const base64 = data.includes(\",\") ? data.split(\",\").at(-1) : data;\n return new Uint8Array(Buffer.from(base64 ?? \"\", \"base64\"));\n}\n\nfunction isPngOrJpeg(bytes: Uint8Array): boolean {\n const isPng =\n bytes[0] === 0x89 &&\n bytes[1] === 0x50 &&\n bytes[2] === 0x4e &&\n bytes[3] === 0x47;\n const isJpeg = bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff;\n return isPng || isJpeg;\n}\n\nfunction supportedOrFallback(bytes: Uint8Array): Uint8Array {\n return isPngOrJpeg(bytes) ? bytes : dataToBytes(FALLBACK_PNG);\n}\n\nexport function imageBytesFromSource(src: string, data?: string): Uint8Array {\n if (data) return supportedOrFallback(dataToBytes(data));\n if (src.startsWith(\"data:\")) return supportedOrFallback(dataToBytes(src));\n if (src.startsWith(\"http://\") || src.startsWith(\"https://\")) {\n return dataToBytes(FALLBACK_PNG);\n }\n try {\n return supportedOrFallback(new Uint8Array(fs.readFileSync(src)));\n } catch {\n return dataToBytes(FALLBACK_PNG);\n }\n}\n\nfunction positiveEmu(valuePx: number) {\n return asEmu(Math.max(1, Math.round(pxToEmu(valuePx))));\n}\n\nfunction createPictureRotationInput(rotate: number | undefined) {\n return rotate !== undefined\n ? asOoxmlAngle(Math.round(rotate * 60000))\n : undefined;\n}\n\nfunction pct(value: number) {\n return asOoxmlPercent(Math.round(value));\n}\n\nfunction createSizingCrop(\n sizing: ImageSizing,\n content: PictureBoundsPx,\n): { bounds: PictureBoundsPx; crop?: AddPictureCropInput } {\n const box = {\n x: sizing.x ?? 0,\n y: sizing.y ?? 0,\n w: sizing.w ?? content.w,\n h: sizing.h ?? content.h,\n };\n const img = { w: content.w, h: content.h };\n\n if (sizing.type === \"crop\") {\n const cropBase = { w: content.w, h: content.h };\n return {\n bounds: { ...content, w: box.w, h: box.h },\n crop: {\n left: pct(100000 * (box.x / cropBase.w)),\n right: pct(100000 * ((cropBase.w - (box.x + box.w)) / cropBase.w)),\n top: pct(100000 * (box.y / cropBase.h)),\n bottom: pct(100000 * ((cropBase.h - (box.y + box.h)) / cropBase.h)),\n },\n };\n }\n\n const imgRatio = img.h / img.w;\n const boxRatio = box.h / box.w;\n const isCoverBoxBased = boxRatio > imgRatio;\n const isContainWidthBased = boxRatio > imgRatio;\n const width =\n sizing.type === \"cover\"\n ? isCoverBoxBased\n ? box.h / imgRatio\n : box.w\n : isContainWidthBased\n ? box.w\n : box.h / imgRatio;\n const height =\n sizing.type === \"cover\"\n ? isCoverBoxBased\n ? box.h\n : box.w * imgRatio\n : isContainWidthBased\n ? box.w * imgRatio\n : box.h;\n const horizontal = 100000 * 0.5 * (1 - box.w / width);\n const vertical = 100000 * 0.5 * (1 - box.h / height);\n\n return {\n bounds: { ...content, w: box.w, h: box.h },\n crop: {\n left: pct(horizontal),\n right: pct(horizontal),\n top: pct(vertical),\n bottom: pct(vertical),\n },\n };\n}\n\nexport function addGlimpsePicture(\n ctx: RenderContext,\n content: PictureBoundsPx,\n bytes: Uint8Array,\n options?: {\n rotate?: number;\n sizing?: ImageSizing;\n name?: string;\n shadow?: ShadowStyle;\n },\n): void {\n const sizingResult = options?.sizing\n ? createSizingCrop(options.sizing, content)\n : { bounds: content, crop: undefined };\n const input: AddPictureInput = {\n bytes,\n offsetX: asEmu(Math.round(pxToEmu(content.x))),\n offsetY: asEmu(Math.round(pxToEmu(content.y))),\n width: positiveEmu(sizingResult.bounds.w),\n height: positiveEmu(sizingResult.bounds.h),\n rotation: createPictureRotationInput(options?.rotate),\n crop: sizingResult.crop,\n };\n ctx.authoring.addPicture(\n enrichPictureInput(input, options?.shadow),\n options?.name,\n );\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { parseGradient } from "../../shared/gradient.js";
2
2
  import { pxToEmu } from "../units.js";
3
- import { toColorInput } from "../pptxAuthoring.js";
3
+ import { enrichShapeInput, toColorInput } from "../glimpseAdapter.js";
4
4
  import { asEmu, asOoxmlAngle } from "@pptx-glimpse/document";
5
5
  //#region src/renderPptx/utils/glimpseShape.ts
6
6
  function positiveEmu(valuePx) {
@@ -59,11 +59,11 @@ function arrowEndpoint(type) {
59
59
  };
60
60
  }
61
61
  function addGlimpseShape(ctx, input, bounds, options) {
62
- ctx.buildContext.pptxAuthoring.registerShape(input, {
62
+ return ctx.authoring.addShape(enrichShapeInput(input, {
63
63
  ...options,
64
64
  zeroWidth: bounds.w === 0,
65
65
  zeroHeight: bounds.h === 0
66
- });
66
+ }), options?.name);
67
67
  }
68
68
  //#endregion
69
69
  export { addGlimpseShape, arrowEndpoint, backgroundShapeFill, createShapeBoundsInput, createShapeRotationInput, noShapeOutline, noneShapeFill, shapeOutline, solidShapeFill };
@@ -1 +1 @@
1
- {"version":3,"file":"glimpseShape.js","names":[],"sources":["../../../src/renderPptx/utils/glimpseShape.ts"],"sourcesContent":["import {\n asEmu,\n asOoxmlAngle,\n type AddShapeFillInput,\n type AddShapeInput,\n type AddShapeOutlineInput,\n type SourceArrowEndpoint,\n type SourceDashStyle,\n} from \"@pptx-glimpse/document\";\nimport type { BorderStyle, ShadowStyle, TextGlow } from \"../../types.ts\";\nimport { parseGradient } from \"../../shared/gradient.ts\";\nimport { toColorInput, type CustomGeometryXmlInput } from \"../pptxAuthoring.ts\";\nimport { pxToEmu } from \"../units.ts\";\nimport type { RenderContext } from \"../types.ts\";\n\ntype ShapeBoundsPx = { x: number; y: number; w: number; h: number };\n\nexport type GlimpseShapeStyleOptions = {\n fillColor?: string;\n fillOpacity?: number;\n backgroundGradient?: string;\n outlineGradient?: string;\n outlineOpacity?: number;\n glow?: TextGlow;\n shadow?: ShadowStyle;\n rectRadius?: number;\n dashType?: BorderStyle[\"dashType\"];\n flipH?: boolean;\n flipV?: boolean;\n zeroWidth?: boolean;\n zeroHeight?: boolean;\n customGeometry?: CustomGeometryXmlInput;\n};\n\nfunction positiveEmu(valuePx: number) {\n return asEmu(Math.max(1, Math.round(pxToEmu(valuePx))));\n}\n\nexport function createShapeBoundsInput(bounds: ShapeBoundsPx) {\n return {\n offsetX: asEmu(Math.round(pxToEmu(bounds.x))),\n offsetY: asEmu(Math.round(pxToEmu(bounds.y))),\n width: positiveEmu(bounds.w),\n height: positiveEmu(bounds.h),\n };\n}\n\nexport function createShapeRotationInput(rotate: number | undefined) {\n return rotate !== undefined\n ? asOoxmlAngle(Math.round(rotate * 60000))\n : undefined;\n}\n\nexport function solidShapeFill(\n color: string | undefined,\n): AddShapeFillInput | undefined {\n const clean = toColorInput(color);\n return clean ? { kind: \"solid\", color: clean } : undefined;\n}\n\nexport function noneShapeFill(): AddShapeFillInput {\n return { kind: \"none\" };\n}\n\nfunction gradientFallbackColor(value: string): string | undefined {\n const gradient = parseGradient(value);\n return gradient?.value.stops[0]?.color;\n}\n\nexport function backgroundShapeFill(\n backgroundColor: string | undefined,\n backgroundGradient: string | undefined,\n): AddShapeFillInput | undefined {\n if (backgroundGradient) {\n const color = gradientFallbackColor(backgroundGradient);\n return solidShapeFill(color);\n }\n return solidShapeFill(backgroundColor);\n}\n\nfunction dashStyle(\n dashType: BorderStyle[\"dashType\"],\n): SourceDashStyle | undefined {\n return dashType;\n}\n\nexport function shapeOutline(\n border: BorderStyle | undefined,\n fallbackColor?: string,\n): AddShapeOutlineInput | undefined {\n if (!border) return undefined;\n const fill = solidShapeFill(border.color ?? fallbackColor);\n if (\n border.width === undefined &&\n fill === undefined &&\n border.dashType === undefined\n ) {\n return undefined;\n }\n return {\n width:\n border.width !== undefined\n ? asEmu(Math.round(pxToEmu(border.width)))\n : undefined,\n fill,\n dash: dashStyle(border.dashType),\n };\n}\n\nexport function noShapeOutline(): AddShapeOutlineInput {\n return { fill: noneShapeFill() };\n}\n\nexport function arrowEndpoint(\n type:\n \"none\" | \"arrow\" | \"diamond\" | \"oval\" | \"stealth\" | \"triangle\" | undefined,\n): SourceArrowEndpoint | undefined {\n if (type === undefined || type === \"none\") return undefined;\n return { type, width: \"med\", length: \"med\" };\n}\n\nexport function addGlimpseShape(\n ctx: RenderContext,\n input: AddShapeInput,\n bounds: ShapeBoundsPx,\n options?: GlimpseShapeStyleOptions & { name?: string },\n): void {\n ctx.buildContext.pptxAuthoring.registerShape(input, {\n ...options,\n zeroWidth: bounds.w === 0,\n zeroHeight: bounds.h === 0,\n });\n}\n"],"mappings":";;;;;AAkCA,SAAS,YAAY,SAAiB;CACpC,OAAO,MAAM,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,OAAO,CAAC,CAAC,CAAC;AACxD;AAEA,SAAgB,uBAAuB,QAAuB;CAC5D,OAAO;EACL,SAAS,MAAM,KAAK,MAAM,QAAQ,OAAO,CAAC,CAAC,CAAC;EAC5C,SAAS,MAAM,KAAK,MAAM,QAAQ,OAAO,CAAC,CAAC,CAAC;EAC5C,OAAO,YAAY,OAAO,CAAC;EAC3B,QAAQ,YAAY,OAAO,CAAC;CAC9B;AACF;AAEA,SAAgB,yBAAyB,QAA4B;CACnE,OAAO,WAAW,KAAA,IACd,aAAa,KAAK,MAAM,SAAS,GAAK,CAAC,IACvC,KAAA;AACN;AAEA,SAAgB,eACd,OAC+B;CAC/B,MAAM,QAAQ,aAAa,KAAK;CAChC,OAAO,QAAQ;EAAE,MAAM;EAAS,OAAO;CAAM,IAAI,KAAA;AACnD;AAEA,SAAgB,gBAAmC;CACjD,OAAO,EAAE,MAAM,OAAO;AACxB;AAEA,SAAS,sBAAsB,OAAmC;CAEhE,OADiB,cAAc,KACjB,CAAC,EAAE,MAAM,MAAM,EAAE,EAAE;AACnC;AAEA,SAAgB,oBACd,iBACA,oBAC+B;CAC/B,IAAI,oBAEF,OAAO,eADO,sBAAsB,kBACV,CAAC;CAE7B,OAAO,eAAe,eAAe;AACvC;AAEA,SAAS,UACP,UAC6B;CAC7B,OAAO;AACT;AAEA,SAAgB,aACd,QACA,eACkC;CAClC,IAAI,CAAC,QAAQ,OAAO,KAAA;CACpB,MAAM,OAAO,eAAe,OAAO,SAAS,aAAa;CACzD,IACE,OAAO,UAAU,KAAA,KACjB,SAAS,KAAA,KACT,OAAO,aAAa,KAAA,GAEpB;CAEF,OAAO;EACL,OACE,OAAO,UAAU,KAAA,IACb,MAAM,KAAK,MAAM,QAAQ,OAAO,KAAK,CAAC,CAAC,IACvC,KAAA;EACN;EACA,MAAM,UAAU,OAAO,QAAQ;CACjC;AACF;AAEA,SAAgB,iBAAuC;CACrD,OAAO,EAAE,MAAM,cAAc,EAAE;AACjC;AAEA,SAAgB,cACd,MAEiC;CACjC,IAAI,SAAS,KAAA,KAAa,SAAS,QAAQ,OAAO,KAAA;CAClD,OAAO;EAAE;EAAM,OAAO;EAAO,QAAQ;CAAM;AAC7C;AAEA,SAAgB,gBACd,KACA,OACA,QACA,SACM;CACN,IAAI,aAAa,cAAc,cAAc,OAAO;EAClD,GAAG;EACH,WAAW,OAAO,MAAM;EACxB,YAAY,OAAO,MAAM;CAC3B,CAAC;AACH"}
1
+ {"version":3,"file":"glimpseShape.js","names":[],"sources":["../../../src/renderPptx/utils/glimpseShape.ts"],"sourcesContent":["import {\n asEmu,\n asOoxmlAngle,\n type AddShapeFillInput,\n type AddShapeInput,\n type AddShapeOutlineInput,\n type SourceArrowEndpoint,\n type SourceDashStyle,\n type SourceHandle,\n} from \"@pptx-glimpse/document\";\nimport type { BorderStyle, ShadowStyle, TextGlow } from \"../../types.ts\";\nimport { parseGradient } from \"../../shared/gradient.ts\";\nimport {\n enrichShapeInput,\n toColorInput,\n type CustomGeometryXmlInput,\n} from \"../glimpseAdapter.ts\";\nimport { pxToEmu } from \"../units.ts\";\nimport type { RenderContext } from \"../types.ts\";\n\ntype ShapeBoundsPx = { x: number; y: number; w: number; h: number };\n\nexport type GlimpseShapeStyleOptions = {\n fillColor?: string;\n fillOpacity?: number;\n backgroundGradient?: string;\n outlineGradient?: string;\n outlineOpacity?: number;\n glow?: TextGlow;\n shadow?: ShadowStyle;\n rectRadius?: number;\n dashType?: BorderStyle[\"dashType\"];\n flipH?: boolean;\n flipV?: boolean;\n zeroWidth?: boolean;\n zeroHeight?: boolean;\n customGeometry?: CustomGeometryXmlInput;\n};\n\nfunction positiveEmu(valuePx: number) {\n return asEmu(Math.max(1, Math.round(pxToEmu(valuePx))));\n}\n\nexport function createShapeBoundsInput(bounds: ShapeBoundsPx) {\n return {\n offsetX: asEmu(Math.round(pxToEmu(bounds.x))),\n offsetY: asEmu(Math.round(pxToEmu(bounds.y))),\n width: positiveEmu(bounds.w),\n height: positiveEmu(bounds.h),\n };\n}\n\nexport function createShapeRotationInput(rotate: number | undefined) {\n return rotate !== undefined\n ? asOoxmlAngle(Math.round(rotate * 60000))\n : undefined;\n}\n\nexport function solidShapeFill(\n color: string | undefined,\n): AddShapeFillInput | undefined {\n const clean = toColorInput(color);\n return clean ? { kind: \"solid\", color: clean } : undefined;\n}\n\nexport function noneShapeFill(): AddShapeFillInput {\n return { kind: \"none\" };\n}\n\nfunction gradientFallbackColor(value: string): string | undefined {\n const gradient = parseGradient(value);\n return gradient?.value.stops[0]?.color;\n}\n\nexport function backgroundShapeFill(\n backgroundColor: string | undefined,\n backgroundGradient: string | undefined,\n): AddShapeFillInput | undefined {\n if (backgroundGradient) {\n const color = gradientFallbackColor(backgroundGradient);\n return solidShapeFill(color);\n }\n return solidShapeFill(backgroundColor);\n}\n\nfunction dashStyle(\n dashType: BorderStyle[\"dashType\"],\n): SourceDashStyle | undefined {\n return dashType;\n}\n\nexport function shapeOutline(\n border: BorderStyle | undefined,\n fallbackColor?: string,\n): AddShapeOutlineInput | undefined {\n if (!border) return undefined;\n const fill = solidShapeFill(border.color ?? fallbackColor);\n if (\n border.width === undefined &&\n fill === undefined &&\n border.dashType === undefined\n ) {\n return undefined;\n }\n return {\n width:\n border.width !== undefined\n ? asEmu(Math.round(pxToEmu(border.width)))\n : undefined,\n fill,\n dash: dashStyle(border.dashType),\n };\n}\n\nexport function noShapeOutline(): AddShapeOutlineInput {\n return { fill: noneShapeFill() };\n}\n\nexport function arrowEndpoint(\n type:\n \"none\" | \"arrow\" | \"diamond\" | \"oval\" | \"stealth\" | \"triangle\" | undefined,\n): SourceArrowEndpoint | undefined {\n if (type === undefined || type === \"none\") return undefined;\n return { type, width: \"med\", length: \"med\" };\n}\n\nexport function addGlimpseShape(\n ctx: RenderContext,\n input: AddShapeInput,\n bounds: ShapeBoundsPx,\n options?: GlimpseShapeStyleOptions & { name?: string },\n): SourceHandle {\n return ctx.authoring.addShape(\n enrichShapeInput(input, {\n ...options,\n zeroWidth: bounds.w === 0,\n zeroHeight: bounds.h === 0,\n }),\n options?.name,\n );\n}\n"],"mappings":";;;;;AAuCA,SAAS,YAAY,SAAiB;CACpC,OAAO,MAAM,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,OAAO,CAAC,CAAC,CAAC;AACxD;AAEA,SAAgB,uBAAuB,QAAuB;CAC5D,OAAO;EACL,SAAS,MAAM,KAAK,MAAM,QAAQ,OAAO,CAAC,CAAC,CAAC;EAC5C,SAAS,MAAM,KAAK,MAAM,QAAQ,OAAO,CAAC,CAAC,CAAC;EAC5C,OAAO,YAAY,OAAO,CAAC;EAC3B,QAAQ,YAAY,OAAO,CAAC;CAC9B;AACF;AAEA,SAAgB,yBAAyB,QAA4B;CACnE,OAAO,WAAW,KAAA,IACd,aAAa,KAAK,MAAM,SAAS,GAAK,CAAC,IACvC,KAAA;AACN;AAEA,SAAgB,eACd,OAC+B;CAC/B,MAAM,QAAQ,aAAa,KAAK;CAChC,OAAO,QAAQ;EAAE,MAAM;EAAS,OAAO;CAAM,IAAI,KAAA;AACnD;AAEA,SAAgB,gBAAmC;CACjD,OAAO,EAAE,MAAM,OAAO;AACxB;AAEA,SAAS,sBAAsB,OAAmC;CAEhE,OADiB,cAAc,KACjB,CAAC,EAAE,MAAM,MAAM,EAAE,EAAE;AACnC;AAEA,SAAgB,oBACd,iBACA,oBAC+B;CAC/B,IAAI,oBAEF,OAAO,eADO,sBAAsB,kBACV,CAAC;CAE7B,OAAO,eAAe,eAAe;AACvC;AAEA,SAAS,UACP,UAC6B;CAC7B,OAAO;AACT;AAEA,SAAgB,aACd,QACA,eACkC;CAClC,IAAI,CAAC,QAAQ,OAAO,KAAA;CACpB,MAAM,OAAO,eAAe,OAAO,SAAS,aAAa;CACzD,IACE,OAAO,UAAU,KAAA,KACjB,SAAS,KAAA,KACT,OAAO,aAAa,KAAA,GAEpB;CAEF,OAAO;EACL,OACE,OAAO,UAAU,KAAA,IACb,MAAM,KAAK,MAAM,QAAQ,OAAO,KAAK,CAAC,CAAC,IACvC,KAAA;EACN;EACA,MAAM,UAAU,OAAO,QAAQ;CACjC;AACF;AAEA,SAAgB,iBAAuC;CACrD,OAAO,EAAE,MAAM,cAAc,EAAE;AACjC;AAEA,SAAgB,cACd,MAEiC;CACjC,IAAI,SAAS,KAAA,KAAa,SAAS,QAAQ,OAAO,KAAA;CAClD,OAAO;EAAE;EAAM,OAAO;EAAO,QAAQ;CAAM;AAC7C;AAEA,SAAgB,gBACd,KACA,OACA,QACA,SACc;CACd,OAAO,IAAI,UAAU,SACnB,iBAAiB,OAAO;EACtB,GAAG;EACH,WAAW,OAAO,MAAM;EACxB,YAAY,OAAO,MAAM;CAC3B,CAAC,GACD,SAAS,IACX;AACF"}
@@ -1,34 +1,7 @@
1
1
  import { pxToEmu, pxToPt } from "../units.js";
2
- import { toColorInput } from "../pptxAuthoring.js";
3
- import { asEmu, asHundredthPt, asOoxmlAngle, asOoxmlPercent, asPt } from "@pptx-glimpse/document";
2
+ import { createGlimpseRunProperties } from "../glimpseAdapter.js";
3
+ import { asEmu, asHundredthPt, asOoxmlAngle, asOoxmlPercent } from "@pptx-glimpse/document";
4
4
  //#region src/renderPptx/utils/glimpseTextBox.ts
5
- function toUnderlineInput(underline) {
6
- if (underline === void 0 || underline === false) return void 0;
7
- if (underline === true) return true;
8
- return {
9
- style: underline.style,
10
- color: toColorInput(underline.color)
11
- };
12
- }
13
- function createGlimpseRunProperties(style) {
14
- return {
15
- fontFace: style.fontFace ?? "Noto Sans JP",
16
- fontSize: asPt(pxToPt(style.fontSize ?? 24)),
17
- color: toColorInput(style.color),
18
- bold: style.bold,
19
- italic: style.italic,
20
- underline: toUnderlineInput(style.underline),
21
- strike: style.strike,
22
- baseline: style.subscript ? {
23
- type: "percent",
24
- value: asOoxmlPercent(-4e4)
25
- } : style.superscript ? {
26
- type: "percent",
27
- value: asOoxmlPercent(3e4)
28
- } : void 0,
29
- highlight: toColorInput(style.highlight)
30
- };
31
- }
32
5
  function createGlimpseParagraph(text, style, options = {}) {
33
6
  const fontSizePx = style.fontSize ?? 24;
34
7
  return {
@@ -96,7 +69,7 @@ function addGlimpseTextBox(ctx, bounds, options = {}) {
96
69
  align: options.align,
97
70
  lineHeight: options.lineHeight
98
71
  }), options);
99
- ctx.buildContext.pptxAuthoring.registerTextBox(textBoxInput(bounds, options, paragraphs), { hyperlinks: options.hyperlinks });
72
+ ctx.authoring.addTextBox(textBoxInput(bounds, options, paragraphs));
100
73
  }
101
74
  function isSupportedAutoNumScheme(value) {
102
75
  return value === "arabicPeriod" || value === "arabicParenR" || value === "romanUcPeriod" || value === "romanLcPeriod" || value === "alphaUcPeriod" || value === "alphaLcPeriod" || value === "alphaLcParenR" || value === "alphaUcParenR" || value === "arabicPlain";
@@ -1 +1 @@
1
- {"version":3,"file":"glimpseTextBox.js","names":[],"sources":["../../../src/renderPptx/utils/glimpseTextBox.ts"],"sourcesContent":["import {\n asEmu,\n asHundredthPt,\n asOoxmlAngle,\n asOoxmlPercent,\n asPt,\n type AddTextBoxInput,\n type AddTextBoxParagraphInput,\n type AddTextBoxRunPropertiesInput,\n type SourceAutoNumScheme,\n} from \"@pptx-glimpse/document\";\nimport type { Underline } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { pxToEmu, pxToPt } from \"../units.ts\";\nimport { toColorInput } from \"../pptxAuthoring.ts\";\n\ntype TextBoundsPx = { x: number; y: number; w: number; h: number };\n\ntype TextBoxVerticalAlign = \"top\" | \"middle\" | \"bottom\";\n\nexport type GlimpseTextRunStyle = {\n fontSize?: number;\n fontFace?: string;\n color?: string;\n bold?: boolean;\n italic?: boolean;\n underline?: Underline;\n strike?: boolean;\n subscript?: boolean;\n superscript?: boolean;\n highlight?: string;\n};\n\nexport type GlimpseTextBoxOptions = GlimpseTextRunStyle & {\n text?: string;\n align?: \"left\" | \"center\" | \"right\";\n valign?: TextBoxVerticalAlign;\n lineHeight?: number;\n rotate?: number;\n autoFit?: boolean;\n margin?: number;\n bullet?: ListBulletOptions;\n};\n\nexport type ListBulletOptions =\n | { kind: \"bullet\" }\n | {\n kind: \"number\";\n scheme?: string;\n startAt?: number;\n };\n\nfunction toUnderlineInput(underline: Underline | undefined) {\n if (underline === undefined || underline === false) return undefined;\n if (underline === true) return true;\n return {\n style: underline.style,\n color: toColorInput(underline.color),\n };\n}\n\nexport function createGlimpseRunProperties(\n style: GlimpseTextRunStyle,\n): AddTextBoxRunPropertiesInput {\n return {\n fontFace: style.fontFace ?? \"Noto Sans JP\",\n fontSize: asPt(pxToPt(style.fontSize ?? 24)),\n color: toColorInput(style.color),\n bold: style.bold,\n italic: style.italic,\n underline: toUnderlineInput(style.underline),\n strike: style.strike,\n baseline: style.subscript\n ? { type: \"percent\", value: asOoxmlPercent(-40000) }\n : style.superscript\n ? { type: \"percent\", value: asOoxmlPercent(30000) }\n : undefined,\n highlight: toColorInput(style.highlight),\n };\n}\n\nfunction createGlimpseParagraph(\n text: string,\n style: GlimpseTextRunStyle,\n options: Pick<GlimpseTextBoxOptions, \"align\" | \"lineHeight\"> = {},\n): AddTextBoxParagraphInput {\n const fontSizePx = style.fontSize ?? 24;\n return {\n properties: {\n align: options.align,\n lineSpacing:\n options.lineHeight !== undefined\n ? asHundredthPt(\n Math.round(pxToPt(fontSizePx * options.lineHeight) * 100),\n )\n : undefined,\n },\n runs: [{ text, properties: createGlimpseRunProperties(style) }],\n };\n}\n\nexport function createGlimpseParagraphs(\n text: string,\n style: GlimpseTextRunStyle,\n options: Pick<GlimpseTextBoxOptions, \"align\" | \"lineHeight\"> = {},\n): AddTextBoxParagraphInput[] {\n return text\n .replace(/\\r*\\n/g, \"\\n\")\n .split(\"\\n\")\n .map((line) => createGlimpseParagraph(line, style, options));\n}\n\nfunction textBoxInput(\n bounds: TextBoundsPx,\n options: GlimpseTextBoxOptions,\n paragraphs: readonly AddTextBoxParagraphInput[],\n): AddTextBoxInput {\n const margin =\n options.margin !== undefined\n ? asEmu(Math.round(pxToEmu(options.margin)))\n : undefined;\n return {\n offsetX: asEmu(Math.round(pxToEmu(bounds.x))),\n offsetY: asEmu(Math.round(pxToEmu(bounds.y))),\n width: asEmu(Math.max(1, Math.round(pxToEmu(bounds.w)))),\n height: asEmu(Math.max(1, Math.round(pxToEmu(bounds.h)))),\n rotation:\n options.rotate !== undefined\n ? asOoxmlAngle(Math.round(options.rotate * 60000))\n : undefined,\n body: {\n marginLeft: margin,\n marginRight: margin,\n marginTop: margin,\n marginBottom: margin,\n anchor: options.valign,\n autoFit: options.autoFit ? \"shape\" : undefined,\n },\n paragraphs,\n };\n}\n\nfunction withListProperties(\n paragraphs: readonly AddTextBoxParagraphInput[],\n options: GlimpseTextBoxOptions,\n): readonly AddTextBoxParagraphInput[] {\n if (!options.bullet) return paragraphs;\n const bullet =\n options.bullet.kind === \"bullet\"\n ? {\n type: \"character\" as const,\n character: \"•\",\n size: asOoxmlPercent(100000),\n }\n : {\n type: \"auto-number\" as const,\n scheme: isSupportedAutoNumScheme(options.bullet.scheme)\n ? options.bullet.scheme\n : \"arabicPeriod\",\n startAt: options.bullet.startAt ?? 1,\n fontFace: \"+mj-lt\",\n size: asOoxmlPercent(100000),\n };\n return paragraphs.map((paragraph) => ({\n ...paragraph,\n properties: {\n ...paragraph.properties,\n marginLeft: asEmu(342900),\n indent: asEmu(-342900),\n lineSpacing: {\n type: \"percent\",\n value: asOoxmlPercent(Math.round((options.lineHeight ?? 1.3) * 100000)),\n },\n bullet,\n },\n }));\n}\n\nexport function addGlimpseTextBox(\n ctx: RenderContext,\n bounds: TextBoundsPx,\n options: GlimpseTextBoxOptions & {\n paragraphs?: readonly AddTextBoxParagraphInput[];\n hyperlinks?: readonly (string | undefined)[];\n } = {},\n): void {\n const paragraphs = withListProperties(\n options.paragraphs ??\n createGlimpseParagraphs(options.text ?? \"\", options, {\n align: options.align,\n lineHeight: options.lineHeight,\n }),\n options,\n );\n ctx.buildContext.pptxAuthoring.registerTextBox(\n textBoxInput(bounds, options, paragraphs),\n {\n hyperlinks: options.hyperlinks,\n },\n );\n}\n\nfunction isSupportedAutoNumScheme(\n value: string | undefined,\n): value is SourceAutoNumScheme {\n return (\n value === \"arabicPeriod\" ||\n value === \"arabicParenR\" ||\n value === \"romanUcPeriod\" ||\n value === \"romanLcPeriod\" ||\n value === \"alphaUcPeriod\" ||\n value === \"alphaLcPeriod\" ||\n value === \"alphaLcParenR\" ||\n value === \"alphaUcParenR\" ||\n value === \"arabicPlain\"\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"glimpseTextBox.js","names":[],"sources":["../../../src/renderPptx/utils/glimpseTextBox.ts"],"sourcesContent":["import {\n asEmu,\n asHundredthPt,\n asOoxmlAngle,\n asOoxmlPercent,\n type AddTextBoxInput,\n type AddTextBoxParagraphInput,\n type SourceAutoNumScheme,\n} from \"@pptx-glimpse/document\";\nimport type { RenderContext } from \"../types.ts\";\nimport { pxToEmu, pxToPt } from \"../units.ts\";\nimport {\n createGlimpseRunProperties,\n type GlimpseTextRunStyle,\n} from \"../glimpseAdapter.ts\";\n\ntype TextBoundsPx = { x: number; y: number; w: number; h: number };\n\ntype TextBoxVerticalAlign = \"top\" | \"middle\" | \"bottom\";\n\nexport type { GlimpseTextRunStyle } from \"../glimpseAdapter.ts\";\n\nexport type GlimpseTextBoxOptions = GlimpseTextRunStyle & {\n text?: string;\n align?: \"left\" | \"center\" | \"right\";\n valign?: TextBoxVerticalAlign;\n lineHeight?: number;\n rotate?: number;\n autoFit?: boolean;\n margin?: number;\n bullet?: ListBulletOptions;\n};\n\nexport type ListBulletOptions =\n | { kind: \"bullet\" }\n | {\n kind: \"number\";\n scheme?: string;\n startAt?: number;\n };\n\nexport { createGlimpseRunProperties } from \"../glimpseAdapter.ts\";\n\nfunction createGlimpseParagraph(\n text: string,\n style: GlimpseTextRunStyle,\n options: Pick<GlimpseTextBoxOptions, \"align\" | \"lineHeight\"> = {},\n): AddTextBoxParagraphInput {\n const fontSizePx = style.fontSize ?? 24;\n return {\n properties: {\n align: options.align,\n lineSpacing:\n options.lineHeight !== undefined\n ? asHundredthPt(\n Math.round(pxToPt(fontSizePx * options.lineHeight) * 100),\n )\n : undefined,\n },\n runs: [{ text, properties: createGlimpseRunProperties(style) }],\n };\n}\n\nexport function createGlimpseParagraphs(\n text: string,\n style: GlimpseTextRunStyle,\n options: Pick<GlimpseTextBoxOptions, \"align\" | \"lineHeight\"> = {},\n): AddTextBoxParagraphInput[] {\n return text\n .replace(/\\r*\\n/g, \"\\n\")\n .split(\"\\n\")\n .map((line) => createGlimpseParagraph(line, style, options));\n}\n\nfunction textBoxInput(\n bounds: TextBoundsPx,\n options: GlimpseTextBoxOptions,\n paragraphs: readonly AddTextBoxParagraphInput[],\n): AddTextBoxInput {\n const margin =\n options.margin !== undefined\n ? asEmu(Math.round(pxToEmu(options.margin)))\n : undefined;\n return {\n offsetX: asEmu(Math.round(pxToEmu(bounds.x))),\n offsetY: asEmu(Math.round(pxToEmu(bounds.y))),\n width: asEmu(Math.max(1, Math.round(pxToEmu(bounds.w)))),\n height: asEmu(Math.max(1, Math.round(pxToEmu(bounds.h)))),\n rotation:\n options.rotate !== undefined\n ? asOoxmlAngle(Math.round(options.rotate * 60000))\n : undefined,\n body: {\n marginLeft: margin,\n marginRight: margin,\n marginTop: margin,\n marginBottom: margin,\n anchor: options.valign,\n autoFit: options.autoFit ? \"shape\" : undefined,\n },\n paragraphs,\n };\n}\n\nfunction withListProperties(\n paragraphs: readonly AddTextBoxParagraphInput[],\n options: GlimpseTextBoxOptions,\n): readonly AddTextBoxParagraphInput[] {\n if (!options.bullet) return paragraphs;\n const bullet =\n options.bullet.kind === \"bullet\"\n ? {\n type: \"character\" as const,\n character: \"•\",\n size: asOoxmlPercent(100000),\n }\n : {\n type: \"auto-number\" as const,\n scheme: isSupportedAutoNumScheme(options.bullet.scheme)\n ? options.bullet.scheme\n : \"arabicPeriod\",\n startAt: options.bullet.startAt ?? 1,\n fontFace: \"+mj-lt\",\n size: asOoxmlPercent(100000),\n };\n return paragraphs.map((paragraph) => ({\n ...paragraph,\n properties: {\n ...paragraph.properties,\n marginLeft: asEmu(342900),\n indent: asEmu(-342900),\n lineSpacing: {\n type: \"percent\",\n value: asOoxmlPercent(Math.round((options.lineHeight ?? 1.3) * 100000)),\n },\n bullet,\n },\n }));\n}\n\nexport function addGlimpseTextBox(\n ctx: RenderContext,\n bounds: TextBoundsPx,\n options: GlimpseTextBoxOptions & {\n paragraphs?: readonly AddTextBoxParagraphInput[];\n } = {},\n): void {\n const paragraphs = withListProperties(\n options.paragraphs ??\n createGlimpseParagraphs(options.text ?? \"\", options, {\n align: options.align,\n lineHeight: options.lineHeight,\n }),\n options,\n );\n ctx.authoring.addTextBox(textBoxInput(bounds, options, paragraphs));\n}\n\nfunction isSupportedAutoNumScheme(\n value: string | undefined,\n): value is SourceAutoNumScheme {\n return (\n value === \"arabicPeriod\" ||\n value === \"arabicParenR\" ||\n value === \"romanUcPeriod\" ||\n value === \"romanLcPeriod\" ||\n value === \"alphaUcPeriod\" ||\n value === \"alphaLcPeriod\" ||\n value === \"alphaLcParenR\" ||\n value === \"alphaUcParenR\" ||\n value === \"arabicPlain\"\n );\n}\n"],"mappings":";;;;AA2CA,SAAS,uBACP,MACA,OACA,UAA+D,CAAC,GACtC;CAC1B,MAAM,aAAa,MAAM,YAAY;CACrC,OAAO;EACL,YAAY;GACV,OAAO,QAAQ;GACf,aACE,QAAQ,eAAe,KAAA,IACnB,cACE,KAAK,MAAM,OAAO,aAAa,QAAQ,UAAU,IAAI,GAAG,CAC1D,IACA,KAAA;EACR;EACA,MAAM,CAAC;GAAE;GAAM,YAAY,2BAA2B,KAAK;EAAE,CAAC;CAChE;AACF;AAEA,SAAgB,wBACd,MACA,OACA,UAA+D,CAAC,GACpC;CAC5B,OAAO,KACJ,QAAQ,UAAU,IAAI,CAAC,CACvB,MAAM,IAAI,CAAC,CACX,KAAK,SAAS,uBAAuB,MAAM,OAAO,OAAO,CAAC;AAC/D;AAEA,SAAS,aACP,QACA,SACA,YACiB;CACjB,MAAM,SACJ,QAAQ,WAAW,KAAA,IACf,MAAM,KAAK,MAAM,QAAQ,QAAQ,MAAM,CAAC,CAAC,IACzC,KAAA;CACN,OAAO;EACL,SAAS,MAAM,KAAK,MAAM,QAAQ,OAAO,CAAC,CAAC,CAAC;EAC5C,SAAS,MAAM,KAAK,MAAM,QAAQ,OAAO,CAAC,CAAC,CAAC;EAC5C,OAAO,MAAM,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,OAAO,CAAC,CAAC,CAAC,CAAC;EACvD,QAAQ,MAAM,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,OAAO,CAAC,CAAC,CAAC,CAAC;EACxD,UACE,QAAQ,WAAW,KAAA,IACf,aAAa,KAAK,MAAM,QAAQ,SAAS,GAAK,CAAC,IAC/C,KAAA;EACN,MAAM;GACJ,YAAY;GACZ,aAAa;GACb,WAAW;GACX,cAAc;GACd,QAAQ,QAAQ;GAChB,SAAS,QAAQ,UAAU,UAAU,KAAA;EACvC;EACA;CACF;AACF;AAEA,SAAS,mBACP,YACA,SACqC;CACrC,IAAI,CAAC,QAAQ,QAAQ,OAAO;CAC5B,MAAM,SACJ,QAAQ,OAAO,SAAS,WACpB;EACE,MAAM;EACN,WAAW;EACX,MAAM,eAAe,GAAM;CAC7B,IACA;EACE,MAAM;EACN,QAAQ,yBAAyB,QAAQ,OAAO,MAAM,IAClD,QAAQ,OAAO,SACf;EACJ,SAAS,QAAQ,OAAO,WAAW;EACnC,UAAU;EACV,MAAM,eAAe,GAAM;CAC7B;CACN,OAAO,WAAW,KAAK,eAAe;EACpC,GAAG;EACH,YAAY;GACV,GAAG,UAAU;GACb,YAAY,MAAM,MAAM;GACxB,QAAQ,MAAM,OAAO;GACrB,aAAa;IACX,MAAM;IACN,OAAO,eAAe,KAAK,OAAO,QAAQ,cAAc,OAAO,GAAM,CAAC;GACxE;GACA;EACF;CACF,EAAE;AACJ;AAEA,SAAgB,kBACd,KACA,QACA,UAEI,CAAC,GACC;CACN,MAAM,aAAa,mBACjB,QAAQ,cACN,wBAAwB,QAAQ,QAAQ,IAAI,SAAS;EACnD,OAAO,QAAQ;EACf,YAAY,QAAQ;CACtB,CAAC,GACH,OACF;CACA,IAAI,UAAU,WAAW,aAAa,QAAQ,SAAS,UAAU,CAAC;AACpE;AAEA,SAAS,yBACP,OAC8B;CAC9B,OACE,UAAU,kBACV,UAAU,kBACV,UAAU,mBACV,UAAU,mBACV,UAAU,mBACV,UAAU,mBACV,UAAU,mBACV,UAAU,mBACV,UAAU;AAEd"}
@@ -1 +1 @@
1
- {"version":3,"file":"straightLine.js","names":[],"sources":["../../../src/renderPptx/utils/straightLine.ts"],"sourcesContent":["/**\n * 2 点間の直線を line shape に変換する共通描画処理。\n *\n * line shape は左上座標 (x, y) + サイズ (w, h) で表現され、\n * 線の向き (始点→終点) は flipH / flipV で表すため、端点座標からの\n * 変換ロジックを Line / Arrow ノードで共有する。\n */\nimport type { LineArrow, LineNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { asEmu } from \"@pptx-glimpse/document\";\nimport { pxToEmu } from \"../units.ts\";\nimport {\n addGlimpseShape,\n arrowEndpoint,\n createShapeBoundsInput,\n noneShapeFill,\n solidShapeFill,\n} from \"./glimpseShape.ts\";\n\n/**\n * boolean | LineArrowOptions から arrow type を取得\n */\nexport function resolveArrowType(\n arrow: LineArrow | undefined,\n): \"none\" | \"arrow\" | \"diamond\" | \"oval\" | \"stealth\" | \"triangle\" | undefined {\n if (arrow === undefined) {\n return undefined;\n }\n if (arrow === false) {\n return \"none\";\n }\n if (arrow === true) {\n return \"triangle\"; // デフォルト\n }\n return arrow.type ?? \"triangle\";\n}\n\ntype StraightLinePoints = { x1: number; y1: number; x2: number; y2: number };\n\ntype StraightLineStyle = Pick<\n LineNode,\n \"color\" | \"lineWidth\" | \"dashType\" | \"beginArrow\" | \"endArrow\"\n> & {\n lineGradient?: string;\n lineGradientOpacity?: number;\n};\n\n/**\n * 始点 (x1, y1) から終点 (x2, y2) への直線を描画する\n */\nexport function addStraightLine(\n ctx: RenderContext,\n { x1, y1, x2, y2 }: StraightLinePoints,\n {\n color,\n lineWidth,\n dashType,\n beginArrow,\n endArrow,\n lineGradient,\n lineGradientOpacity,\n }: StraightLineStyle,\n): void {\n const minX = Math.min(x1, x2);\n const minY = Math.min(y1, y2);\n const lineW = Math.abs(x2 - x1);\n const lineH = Math.abs(y2 - y1);\n\n // 線の方向を判定して flip を決定\n // flipH: 右から左へ向かう線\n // flipV: 下から上へ向かう線\n const flipH = x2 < x1;\n const flipV = y2 < y1;\n\n addGlimpseShape(\n ctx,\n {\n geometry: { kind: \"preset\", preset: \"line\" },\n ...createShapeBoundsInput({ x: minX, y: minY, w: lineW, h: lineH }),\n fill: noneShapeFill(),\n outline: {\n fill: solidShapeFill(color ?? \"000000\"),\n width:\n lineWidth !== undefined\n ? asEmu(Math.round(pxToEmu(lineWidth)))\n : asEmu(12700),\n dash: dashType === \"lgDashDotDot\" ? undefined : dashType,\n headEnd: arrowEndpoint(resolveArrowType(beginArrow)),\n tailEnd: arrowEndpoint(resolveArrowType(endArrow)),\n },\n },\n { x: minX, y: minY, w: lineW, h: lineH },\n {\n flipH,\n flipV,\n dashType,\n outlineGradient: lineGradient,\n outlineOpacity: lineGradientOpacity,\n },\n );\n}\n"],"mappings":";;;;;;;AAsBA,SAAgB,iBACd,OAC4E;CAC5E,IAAI,UAAU,KAAA,GACZ;CAEF,IAAI,UAAU,OACZ,OAAO;CAET,IAAI,UAAU,MACZ,OAAO;CAET,OAAO,MAAM,QAAQ;AACvB;;;;AAeA,SAAgB,gBACd,KACA,EAAE,IAAI,IAAI,IAAI,MACd,EACE,OACA,WACA,UACA,YACA,UACA,cACA,uBAEI;CACN,MAAM,OAAO,KAAK,IAAI,IAAI,EAAE;CAC5B,MAAM,OAAO,KAAK,IAAI,IAAI,EAAE;CAC5B,MAAM,QAAQ,KAAK,IAAI,KAAK,EAAE;CAC9B,MAAM,QAAQ,KAAK,IAAI,KAAK,EAAE;CAK9B,MAAM,QAAQ,KAAK;CACnB,MAAM,QAAQ,KAAK;CAEnB,gBACE,KACA;EACE,UAAU;GAAE,MAAM;GAAU,QAAQ;EAAO;EAC3C,GAAG,uBAAuB;GAAE,GAAG;GAAM,GAAG;GAAM,GAAG;GAAO,GAAG;EAAM,CAAC;EAClE,MAAM,cAAc;EACpB,SAAS;GACP,MAAM,eAAe,SAAS,QAAQ;GACtC,OACE,cAAc,KAAA,IACV,MAAM,KAAK,MAAM,QAAQ,SAAS,CAAC,CAAC,IACpC,MAAM,KAAK;GACjB,MAAM,aAAa,iBAAiB,KAAA,IAAY;GAChD,SAAS,cAAc,iBAAiB,UAAU,CAAC;GACnD,SAAS,cAAc,iBAAiB,QAAQ,CAAC;EACnD;CACF,GACA;EAAE,GAAG;EAAM,GAAG;EAAM,GAAG;EAAO,GAAG;CAAM,GACvC;EACE;EACA;EACA;EACA,iBAAiB;EACjB,gBAAgB;CAClB,CACF;AACF"}
1
+ {"version":3,"file":"straightLine.js","names":[],"sources":["../../../src/renderPptx/utils/straightLine.ts"],"sourcesContent":["/**\n * 2 点間の直線を line shape に変換する共通描画処理。\n *\n * line shape は左上座標 (x, y) + サイズ (w, h) で表現され、\n * 線の向き (始点→終点) は flipH / flipV で表す。arrow endpoint の\n * 型変換だけは native connector Arrow と共有する。\n */\nimport type { LineArrow, LineNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { asEmu } from \"@pptx-glimpse/document\";\nimport { pxToEmu } from \"../units.ts\";\nimport {\n addGlimpseShape,\n arrowEndpoint,\n createShapeBoundsInput,\n noneShapeFill,\n solidShapeFill,\n} from \"./glimpseShape.ts\";\n\n/**\n * boolean | LineArrowOptions から arrow type を取得\n */\nexport function resolveArrowType(\n arrow: LineArrow | undefined,\n): \"none\" | \"arrow\" | \"diamond\" | \"oval\" | \"stealth\" | \"triangle\" | undefined {\n if (arrow === undefined) {\n return undefined;\n }\n if (arrow === false) {\n return \"none\";\n }\n if (arrow === true) {\n return \"triangle\"; // デフォルト\n }\n return arrow.type ?? \"triangle\";\n}\n\ntype StraightLinePoints = { x1: number; y1: number; x2: number; y2: number };\n\ntype StraightLineStyle = Pick<\n LineNode,\n \"color\" | \"lineWidth\" | \"dashType\" | \"beginArrow\" | \"endArrow\"\n> & {\n lineGradient?: string;\n lineGradientOpacity?: number;\n};\n\n/**\n * 始点 (x1, y1) から終点 (x2, y2) への直線を描画する\n */\nexport function addStraightLine(\n ctx: RenderContext,\n { x1, y1, x2, y2 }: StraightLinePoints,\n {\n color,\n lineWidth,\n dashType,\n beginArrow,\n endArrow,\n lineGradient,\n lineGradientOpacity,\n }: StraightLineStyle,\n): void {\n const minX = Math.min(x1, x2);\n const minY = Math.min(y1, y2);\n const lineW = Math.abs(x2 - x1);\n const lineH = Math.abs(y2 - y1);\n\n // 線の方向を判定して flip を決定\n // flipH: 右から左へ向かう線\n // flipV: 下から上へ向かう線\n const flipH = x2 < x1;\n const flipV = y2 < y1;\n\n addGlimpseShape(\n ctx,\n {\n geometry: { kind: \"preset\", preset: \"line\" },\n ...createShapeBoundsInput({ x: minX, y: minY, w: lineW, h: lineH }),\n fill: noneShapeFill(),\n outline: {\n fill: solidShapeFill(color ?? \"000000\"),\n width:\n lineWidth !== undefined\n ? asEmu(Math.round(pxToEmu(lineWidth)))\n : asEmu(12700),\n dash: dashType === \"lgDashDotDot\" ? undefined : dashType,\n headEnd: arrowEndpoint(resolveArrowType(beginArrow)),\n tailEnd: arrowEndpoint(resolveArrowType(endArrow)),\n },\n },\n { x: minX, y: minY, w: lineW, h: lineH },\n {\n flipH,\n flipV,\n dashType,\n outlineGradient: lineGradient,\n outlineOpacity: lineGradientOpacity,\n },\n );\n}\n"],"mappings":";;;;;;;AAsBA,SAAgB,iBACd,OAC4E;CAC5E,IAAI,UAAU,KAAA,GACZ;CAEF,IAAI,UAAU,OACZ,OAAO;CAET,IAAI,UAAU,MACZ,OAAO;CAET,OAAO,MAAM,QAAQ;AACvB;;;;AAeA,SAAgB,gBACd,KACA,EAAE,IAAI,IAAI,IAAI,MACd,EACE,OACA,WACA,UACA,YACA,UACA,cACA,uBAEI;CACN,MAAM,OAAO,KAAK,IAAI,IAAI,EAAE;CAC5B,MAAM,OAAO,KAAK,IAAI,IAAI,EAAE;CAC5B,MAAM,QAAQ,KAAK,IAAI,KAAK,EAAE;CAC9B,MAAM,QAAQ,KAAK,IAAI,KAAK,EAAE;CAK9B,MAAM,QAAQ,KAAK;CACnB,MAAM,QAAQ,KAAK;CAEnB,gBACE,KACA;EACE,UAAU;GAAE,MAAM;GAAU,QAAQ;EAAO;EAC3C,GAAG,uBAAuB;GAAE,GAAG;GAAM,GAAG;GAAM,GAAG;GAAO,GAAG;EAAM,CAAC;EAClE,MAAM,cAAc;EACpB,SAAS;GACP,MAAM,eAAe,SAAS,QAAQ;GACtC,OACE,cAAc,KAAA,IACV,MAAM,KAAK,MAAM,QAAQ,SAAS,CAAC,CAAC,IACpC,MAAM,KAAK;GACjB,MAAM,aAAa,iBAAiB,KAAA,IAAY;GAChD,SAAS,cAAc,iBAAiB,UAAU,CAAC;GACnD,SAAS,cAAc,iBAAiB,QAAQ,CAAC;EACnD;CACF,GACA;EAAE,GAAG;EAAM,GAAG;EAAM,GAAG;EAAO,GAAG;CAAM,GACvC;EACE;EACA;EACA;EACA,iBAAiB;EACjB,gBAAgB;CAClB,CACF;AACF"}
@@ -1,5 +1,5 @@
1
+ import "@pptx-glimpse/document";
1
2
  import { Buffer } from "node:buffer";
2
-
3
3
  //#region src/renderPptx/writablePptx.d.ts
4
4
  type PptxOutputType = "arraybuffer" | "base64" | "binarystring" | "blob" | "nodebuffer" | "uint8array";
5
5
  type PptxWriteOptions = {