@hirokisakabe/pom 9.1.1 → 10.0.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 (73) hide show
  1. package/dist/buildContext.js +2 -6
  2. package/dist/buildContext.js.map +1 -1
  3. package/dist/buildPptx.d.ts +2 -1
  4. package/dist/buildPptx.d.ts.map +1 -1
  5. package/dist/buildPptx.js +4 -9
  6. package/dist/buildPptx.js.map +1 -1
  7. package/dist/calcYogaLayout/calcYogaLayout.js +1 -1
  8. package/dist/calcYogaLayout/calcYogaLayout.js.map +1 -1
  9. package/dist/index.d.ts +2 -1
  10. package/dist/registry/definitions/icon.js +1 -1
  11. package/dist/registry/definitions/list.js.map +1 -1
  12. package/dist/renderPptx/nodes/chart.js +172 -47
  13. package/dist/renderPptx/nodes/chart.js.map +1 -1
  14. package/dist/renderPptx/nodes/flow.js +98 -90
  15. package/dist/renderPptx/nodes/flow.js.map +1 -1
  16. package/dist/renderPptx/nodes/icon.js +36 -24
  17. package/dist/renderPptx/nodes/icon.js.map +1 -1
  18. package/dist/renderPptx/nodes/image.js +5 -22
  19. package/dist/renderPptx/nodes/image.js.map +1 -1
  20. package/dist/renderPptx/nodes/list.js +94 -111
  21. package/dist/renderPptx/nodes/list.js.map +1 -1
  22. package/dist/renderPptx/nodes/matrix.js +95 -70
  23. package/dist/renderPptx/nodes/matrix.js.map +1 -1
  24. package/dist/renderPptx/nodes/processArrow.js +74 -35
  25. package/dist/renderPptx/nodes/processArrow.js.map +1 -1
  26. package/dist/renderPptx/nodes/pyramid.js +37 -16
  27. package/dist/renderPptx/nodes/pyramid.js.map +1 -1
  28. package/dist/renderPptx/nodes/shape.js +66 -37
  29. package/dist/renderPptx/nodes/shape.js.map +1 -1
  30. package/dist/renderPptx/nodes/svg.js +2 -5
  31. package/dist/renderPptx/nodes/svg.js.map +1 -1
  32. package/dist/renderPptx/nodes/table.js +89 -59
  33. package/dist/renderPptx/nodes/table.js.map +1 -1
  34. package/dist/renderPptx/nodes/text.js +1 -18
  35. package/dist/renderPptx/nodes/text.js.map +1 -1
  36. package/dist/renderPptx/nodes/timeline.js +114 -74
  37. package/dist/renderPptx/nodes/timeline.js.map +1 -1
  38. package/dist/renderPptx/nodes/tree.js +81 -79
  39. package/dist/renderPptx/nodes/tree.js.map +1 -1
  40. package/dist/renderPptx/pptxAuthoring.js +381 -0
  41. package/dist/renderPptx/pptxAuthoring.js.map +1 -0
  42. package/dist/renderPptx/renderPptx.js +158 -128
  43. package/dist/renderPptx/renderPptx.js.map +1 -1
  44. package/dist/renderPptx/textOptions.js +7 -8
  45. package/dist/renderPptx/textOptions.js.map +1 -1
  46. package/dist/renderPptx/units.js +3 -3
  47. package/dist/renderPptx/units.js.map +1 -1
  48. package/dist/renderPptx/utils/backgroundBorder.js +70 -48
  49. package/dist/renderPptx/utils/backgroundBorder.js.map +1 -1
  50. package/dist/renderPptx/utils/contentArea.js +1 -1
  51. package/dist/renderPptx/utils/contentArea.js.map +1 -1
  52. package/dist/renderPptx/utils/glimpsePicture.js +111 -0
  53. package/dist/renderPptx/utils/glimpsePicture.js.map +1 -0
  54. package/dist/renderPptx/utils/glimpseShape.js +71 -0
  55. package/dist/renderPptx/utils/glimpseShape.js.map +1 -0
  56. package/dist/renderPptx/utils/glimpseTextBox.js +107 -0
  57. package/dist/renderPptx/utils/glimpseTextBox.js.map +1 -0
  58. package/dist/renderPptx/utils/straightLine.js +33 -15
  59. package/dist/renderPptx/utils/straightLine.js.map +1 -1
  60. package/dist/renderPptx/utils/visualStyle.js +3 -56
  61. package/dist/renderPptx/utils/visualStyle.js.map +1 -1
  62. package/dist/renderPptx/writablePptx.d.ts +23 -0
  63. package/dist/renderPptx/writablePptx.d.ts.map +1 -0
  64. package/dist/renderPptx/writablePptx.js +74 -0
  65. package/dist/renderPptx/writablePptx.js.map +1 -0
  66. package/dist/shared/measureImage.js.map +1 -1
  67. package/package.json +4 -5
  68. package/dist/renderPptx/glimpseTextBoxes.js +0 -347
  69. package/dist/renderPptx/glimpseTextBoxes.js.map +0 -1
  70. package/dist/renderPptx/glowEffects.js +0 -157
  71. package/dist/renderPptx/glowEffects.js.map +0 -1
  72. package/dist/renderPptx/gradientFills.js +0 -154
  73. package/dist/renderPptx/gradientFills.js.map +0 -1
@@ -1,7 +1,9 @@
1
- import { pxToIn, pxToPt } from "../units.js";
1
+ import { pxToEmu } from "../units.js";
2
+ import { addGlimpseShape, arrowEndpoint, createShapeBoundsInput, noneShapeFill, solidShapeFill } from "./glimpseShape.js";
3
+ import { asEmu } from "@pptx-glimpse/document";
2
4
  //#region src/renderPptx/utils/straightLine.ts
3
5
  /**
4
- * boolean | LineArrowOptions から pptxgenjs の arrow type を取得
6
+ * boolean | LineArrowOptions から arrow type を取得
5
7
  */
6
8
  function resolveArrowType(arrow) {
7
9
  if (arrow === void 0) return;
@@ -12,27 +14,43 @@ function resolveArrowType(arrow) {
12
14
  /**
13
15
  * 始点 (x1, y1) から終点 (x2, y2) への直線を描画する
14
16
  */
15
- function addStraightLine(ctx, { x1, y1, x2, y2 }, { color, lineWidth, dashType, beginArrow, endArrow }) {
17
+ function addStraightLine(ctx, { x1, y1, x2, y2 }, { color, lineWidth, dashType, beginArrow, endArrow, lineGradient, lineGradientOpacity }) {
16
18
  const minX = Math.min(x1, x2);
17
19
  const minY = Math.min(y1, y2);
18
20
  const lineW = Math.abs(x2 - x1);
19
21
  const lineH = Math.abs(y2 - y1);
20
22
  const flipH = x2 < x1;
21
23
  const flipV = y2 < y1;
22
- ctx.slide.addShape(ctx.pptx.ShapeType.line, {
23
- x: pxToIn(minX),
24
- y: pxToIn(minY),
25
- w: pxToIn(lineW),
26
- h: pxToIn(lineH),
24
+ addGlimpseShape(ctx, {
25
+ geometry: {
26
+ kind: "preset",
27
+ preset: "line"
28
+ },
29
+ ...createShapeBoundsInput({
30
+ x: minX,
31
+ y: minY,
32
+ w: lineW,
33
+ h: lineH
34
+ }),
35
+ fill: noneShapeFill(),
36
+ outline: {
37
+ fill: solidShapeFill(color ?? "000000"),
38
+ width: lineWidth !== void 0 ? asEmu(Math.round(pxToEmu(lineWidth))) : asEmu(12700),
39
+ dash: dashType === "lgDashDotDot" ? void 0 : dashType,
40
+ headEnd: arrowEndpoint(resolveArrowType(beginArrow)),
41
+ tailEnd: arrowEndpoint(resolveArrowType(endArrow))
42
+ }
43
+ }, {
44
+ x: minX,
45
+ y: minY,
46
+ w: lineW,
47
+ h: lineH
48
+ }, {
27
49
  flipH,
28
50
  flipV,
29
- line: {
30
- color: color ?? "000000",
31
- width: lineWidth !== void 0 ? pxToPt(lineWidth) : 1,
32
- dashType,
33
- beginArrowType: resolveArrowType(beginArrow),
34
- endArrowType: resolveArrowType(endArrow)
35
- }
51
+ dashType,
52
+ outlineGradient: lineGradient,
53
+ outlineOpacity: lineGradientOpacity
36
54
  });
37
55
  }
38
56
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"straightLine.js","names":[],"sources":["../../../src/renderPptx/utils/straightLine.ts"],"sourcesContent":["/**\n * 2 点間の直線を pptxgenjs の line shape に変換する共通描画処理。\n *\n * pptxgenjs の 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 { pxToIn, pxToPt } from \"../units.ts\";\n\n/**\n * boolean | LineArrowOptions から pptxgenjs の 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\n/**\n * 始点 (x1, y1) から終点 (x2, y2) への直線を描画する\n */\nexport function addStraightLine(\n ctx: RenderContext,\n { x1, y1, x2, y2 }: StraightLinePoints,\n { color, lineWidth, dashType, beginArrow, endArrow }: 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 ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(minX),\n y: pxToIn(minY),\n w: pxToIn(lineW),\n h: pxToIn(lineH),\n flipH,\n flipV,\n line: {\n color: color ?? \"000000\",\n width: lineWidth !== undefined ? pxToPt(lineWidth) : 1,\n dashType,\n beginArrowType: resolveArrowType(beginArrow),\n endArrowType: resolveArrowType(endArrow),\n },\n });\n}\n"],"mappings":";;;;;AAcA,SAAgB,iBACd,OAC4E;CAC5E,IAAI,UAAU,KAAA,GACZ;CAEF,IAAI,UAAU,OACZ,OAAO;CAET,IAAI,UAAU,MACZ,OAAO;CAET,OAAO,MAAM,QAAQ;AACvB;;;;AAYA,SAAgB,gBACd,KACA,EAAE,IAAI,IAAI,IAAI,MACd,EAAE,OAAO,WAAW,UAAU,YAAY,YACpC;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,IAAI,MAAM,SAAS,IAAI,KAAK,UAAU,MAAM;EAC1C,GAAG,OAAO,IAAI;EACd,GAAG,OAAO,IAAI;EACd,GAAG,OAAO,KAAK;EACf,GAAG,OAAO,KAAK;EACf;EACA;EACA,MAAM;GACJ,OAAO,SAAS;GAChB,OAAO,cAAc,KAAA,IAAY,OAAO,SAAS,IAAI;GACrD;GACA,gBAAgB,iBAAiB,UAAU;GAC3C,cAAc,iBAAiB,QAAQ;EACzC;CACF,CAAC;AACH"}
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,28 +1,12 @@
1
- import { pxToPt } from "../units.js";
2
1
  //#region src/renderPptx/utils/visualStyle.ts
3
2
  /**
4
- * 色文字列から "#" を 1 つ取り除き、pptxgenjs が受け付ける HEX 文字列にする。
3
+ * 色文字列から "#" を 1 つ取り除き、OOXML 向けの HEX 文字列にする。
5
4
  * undefined はそのまま返すため `stripHash(color) ?? fallback` の形で使える。
6
5
  */
7
6
  function stripHash(color) {
8
7
  return color?.replace("#", "");
9
8
  }
10
9
  /**
11
- * ShadowStyle を pptxgenjs の shadow オプションに変換する
12
- * type 未指定時は outer をデフォルトとする
13
- */
14
- function convertShadow(shadow) {
15
- if (!shadow) return void 0;
16
- return {
17
- type: shadow.type ?? "outer",
18
- opacity: shadow.opacity,
19
- blur: shadow.blur,
20
- angle: shadow.angle,
21
- offset: shadow.offset,
22
- color: shadow.color
23
- };
24
- }
25
- /**
26
10
  * border が描画対象となる指定 (color / width / dashType のいずれか) を
27
11
  * 持つかを判定する
28
12
  */
@@ -64,50 +48,13 @@ function resolvePerSideBorders(style) {
64
48
  return result;
65
49
  }
66
50
  /**
67
- * BorderStyle を pptxgenjs の line オプションに変換する
68
- * width はユーザー入力 px、pptxgenjs の line.width は pt
69
- *
70
- * @param fallbackColor color 未指定時に使う色。省略時は color を
71
- * undefined のまま渡し pptxgenjs のデフォルトに任せる
72
- */
73
- function convertBorderLine(border, fallbackColor) {
74
- return {
75
- color: border.color ?? fallbackColor,
76
- width: border.width !== void 0 ? pxToPt(border.width) : void 0,
77
- dashType: border.dashType
78
- };
79
- }
80
- /**
81
- * ノードの opacity (0-1、1 = 不透明) を pptxgenjs の
82
- * transparency (0-100、100 = 透明) に変換する
83
- */
84
- function opacityToTransparency(opacity) {
85
- return opacity !== void 0 ? (1 - opacity) * 100 : void 0;
86
- }
87
- /**
88
- * backgroundColor / opacity / グラデーションマーカー色から
89
- * pptxgenjs の fill オプションを解決する
90
- *
91
- * gradientMarker がある場合はマーカー色の単色塗りとして描画し、
92
- * 出力時の後処理で gradFill に置換される (gradientFills.ts 参照)。
93
- * opacity はマーカー側ではなく gradFill のカラーストップの alpha で
94
- * 表現するため、マーカー fill には transparency を付与しない。
95
- */
96
- function resolveBackgroundFill(backgroundColor, opacity, gradientMarker) {
97
- if (gradientMarker) return { color: gradientMarker };
98
- return {
99
- color: backgroundColor,
100
- transparency: opacityToTransparency(opacity)
101
- };
102
- }
103
- /**
104
51
  * borderRadius (px) をノードサイズに対する 0-1 の正規化値
105
- * (pptxgenjs roundRect の rectRadius) に変換する
52
+ * (roundRect の rectRadius) に変換する
106
53
  */
107
54
  function resolveRectRadius(borderRadius, w, h) {
108
55
  return borderRadius ? Math.min(borderRadius / Math.min(w, h) * 2, 1) : void 0;
109
56
  }
110
57
  //#endregion
111
- export { BORDER_SIDES, convertBorderLine, convertShadow, hasVisibleBorder, opacityToTransparency, resolveBackgroundFill, resolvePerSideBorders, resolveRectRadius, stripHash };
58
+ export { BORDER_SIDES, hasVisibleBorder, resolvePerSideBorders, resolveRectRadius, stripHash };
112
59
 
113
60
  //# sourceMappingURL=visualStyle.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"visualStyle.js","names":[],"sources":["../../../src/renderPptx/utils/visualStyle.ts"],"sourcesContent":["/**\n * 見た目属性 (fill / border / shadow / opacity / borderRadius) を\n * pptxgenjs のオプションへ変換する共通 resolver 群。\n *\n * ノードごとに変換ロジックが重複・乖離すると、XML 上は同じ指定でも\n * 描画結果が異なるリスクがあるため、属性値 → pptxgenjs オプションの\n * 純粋変換をここに集約する。\n *\n * 共通化対象の属性カテゴリ:\n * - fill (背景色 + opacity): resolveBackgroundFill / opacityToTransparency\n * - border / line (枠線): hasVisibleBorder / convertBorderLine\n * - shadow (影): convertShadow\n * - borderRadius (角丸): resolveRectRadius\n *\n * 既存 helper との責務境界:\n * - gradientFills.ts: backgroundGradient のマーカー登録と出力時の gradFill 置換。\n * グラデーションはマーカー色 1 色の単色塗りに帰着するため本モジュールでは\n * 解釈せず、マーカー色を resolveBackgroundFill で単色 fill として扱う。\n * - utils/backgroundBorder.ts: 背景色 → 背景画像 → ボーダーの描画順序の\n * オーケストレーション。個々の属性値の変換は本モジュールに委譲する。\n * - textOptions.ts: テキスト系属性 (font / underline / strike など) の変換。\n */\nimport type { BorderStyle, ShadowStyle } from \"../../types.ts\";\nimport { pxToPt } from \"../units.ts\";\n\n/**\n * 色文字列から \"#\" を 1 つ取り除き、pptxgenjs が受け付ける HEX 文字列にする。\n * undefined はそのまま返すため `stripHash(color) ?? fallback` の形で使える。\n */\nexport function stripHash(color: string | undefined): string | undefined {\n return color?.replace(\"#\", \"\");\n}\n\n/**\n * ShadowStyle pptxgenjs の shadow オプションに変換する\n * type 未指定時は outer をデフォルトとする\n */\nexport function convertShadow(shadow: ShadowStyle | undefined):\n | {\n type: \"outer\" | \"inner\";\n opacity?: number;\n blur?: number;\n angle?: number;\n offset?: number;\n color?: string;\n }\n | undefined {\n if (!shadow) return undefined;\n return {\n type: shadow.type ?? \"outer\",\n opacity: shadow.opacity,\n blur: shadow.blur,\n angle: shadow.angle,\n offset: shadow.offset,\n color: shadow.color,\n };\n}\n\n/**\n * border が描画対象となる指定 (color / width / dashType のいずれか) を\n * 持つかを判定する\n */\nexport function hasVisibleBorder(\n border: BorderStyle | undefined,\n): border is BorderStyle {\n return Boolean(\n border &&\n (border.color !== undefined ||\n border.width !== undefined ||\n border.dashType !== undefined),\n );\n}\n\nexport const BORDER_SIDES = [\"top\", \"right\", \"bottom\", \"left\"] as const;\nexport type BorderSide = (typeof BORDER_SIDES)[number];\n\nexport type PerSideBorders = Partial<Record<BorderSide, BorderStyle>>;\n\n/**\n * 4 辺一律の border と辺ごとの borderTop / borderRight / borderBottom /\n * borderLeft をマージし、描画対象となる辺ごとの BorderStyle を返す。\n *\n * - 辺ごとの指定が 1 つも無い場合は undefined を返し、呼び出し側は\n * 従来の 4 辺一律描画 (shape の line オプション) にフォールバックする\n * - 辺ごとの指定がある場合、各辺は border をベースに辺ごとの指定で\n * フィールド単位に上書きした BorderStyle になる (辺ごとの指定が優先)\n * - マージ結果が描画対象とならない辺 (指定なし) は結果に含まれない\n */\nexport function resolvePerSideBorders(style: {\n border?: BorderStyle;\n borderTop?: BorderStyle;\n borderRight?: BorderStyle;\n borderBottom?: BorderStyle;\n borderLeft?: BorderStyle;\n}): PerSideBorders | undefined {\n const overrides: Partial<Record<BorderSide, BorderStyle | undefined>> = {\n top: style.borderTop,\n right: style.borderRight,\n bottom: style.borderBottom,\n left: style.borderLeft,\n };\n\n const hasPerSideOverride = Object.values(overrides).some(hasVisibleBorder);\n if (!hasPerSideOverride) return undefined;\n\n const result: PerSideBorders = {};\n for (const side of BORDER_SIDES) {\n const merged = { ...style.border, ...overrides[side] };\n if (hasVisibleBorder(merged)) {\n result[side] = merged;\n }\n }\n return result;\n}\n\n/**\n * BorderStyle pptxgenjs の line オプションに変換する\n * width はユーザー入力 px、pptxgenjs line.width は pt\n *\n * @param fallbackColor color 未指定時に使う色。省略時は color を\n * undefined のまま渡し pptxgenjs のデフォルトに任せる\n */\nexport function convertBorderLine(\n border: BorderStyle,\n fallbackColor?: string,\n): { color?: string; width?: number; dashType?: BorderStyle[\"dashType\"] } {\n return {\n color: border.color ?? fallbackColor,\n width: border.width !== undefined ? pxToPt(border.width) : undefined,\n dashType: border.dashType,\n };\n}\n\n/**\n * ノードの opacity (0-1、1 = 不透明) を pptxgenjs の\n * transparency (0-100、100 = 透明) に変換する\n */\nexport function opacityToTransparency(\n opacity: number | undefined,\n): number | undefined {\n return opacity !== undefined ? (1 - opacity) * 100 : undefined;\n}\n\n/**\n * backgroundColor / opacity / グラデーションマーカー色から\n * pptxgenjs の fill オプションを解決する\n *\n * gradientMarker がある場合はマーカー色の単色塗りとして描画し、\n * 出力時の後処理で gradFill に置換される (gradientFills.ts 参照)。\n * opacity はマーカー側ではなく gradFill のカラーストップの alpha で\n * 表現するため、マーカー fill には transparency を付与しない。\n */\nexport function resolveBackgroundFill(\n backgroundColor: string | undefined,\n opacity: number | undefined,\n gradientMarker: string | undefined,\n): { color?: string; transparency?: number } {\n if (gradientMarker) return { color: gradientMarker };\n return {\n color: backgroundColor,\n transparency: opacityToTransparency(opacity),\n };\n}\n\n/**\n * borderRadius (px) をノードサイズに対する 0-1 の正規化値\n * (pptxgenjs roundRect の rectRadius) に変換する\n */\nexport function resolveRectRadius(\n borderRadius: number | undefined,\n w: number,\n h: number,\n): number | undefined {\n return borderRadius\n ? Math.min((borderRadius / Math.min(w, h)) * 2, 1)\n : undefined;\n}\n"],"mappings":";;;;;;AA6BA,SAAgB,UAAU,OAA+C;CACvE,OAAO,OAAO,QAAQ,KAAK,EAAE;AAC/B;;;;;AAMA,SAAgB,cAAc,QAShB;CACZ,IAAI,CAAC,QAAQ,OAAO,KAAA;CACpB,OAAO;EACL,MAAM,OAAO,QAAQ;EACrB,SAAS,OAAO;EAChB,MAAM,OAAO;EACb,OAAO,OAAO;EACd,QAAQ,OAAO;EACf,OAAO,OAAO;CAChB;AACF;;;;;AAMA,SAAgB,iBACd,QACuB;CACvB,OAAO,QACL,WACC,OAAO,UAAU,KAAA,KAChB,OAAO,UAAU,KAAA,KACjB,OAAO,aAAa,KAAA,EACxB;AACF;AAEA,MAAa,eAAe;CAAC;CAAO;CAAS;CAAU;AAAM;;;;;;;;;;;AAe7D,SAAgB,sBAAsB,OAMP;CAC7B,MAAM,YAAkE;EACtE,KAAK,MAAM;EACX,OAAO,MAAM;EACb,QAAQ,MAAM;EACd,MAAM,MAAM;CACd;CAGA,IAAI,CADuB,OAAO,OAAO,SAAS,CAAC,CAAC,KAAK,gBACnC,GAAG,OAAO,KAAA;CAEhC,MAAM,SAAyB,CAAC;CAChC,KAAK,MAAM,QAAQ,cAAc;EAC/B,MAAM,SAAS;GAAE,GAAG,MAAM;GAAQ,GAAG,UAAU;EAAM;EACrD,IAAI,iBAAiB,MAAM,GACzB,OAAO,QAAQ;CAEnB;CACA,OAAO;AACT;;;;;;;;AASA,SAAgB,kBACd,QACA,eACwE;CACxE,OAAO;EACL,OAAO,OAAO,SAAS;EACvB,OAAO,OAAO,UAAU,KAAA,IAAY,OAAO,OAAO,KAAK,IAAI,KAAA;EAC3D,UAAU,OAAO;CACnB;AACF;;;;;AAMA,SAAgB,sBACd,SACoB;CACpB,OAAO,YAAY,KAAA,KAAa,IAAI,WAAW,MAAM,KAAA;AACvD;;;;;;;;;;AAWA,SAAgB,sBACd,iBACA,SACA,gBAC2C;CAC3C,IAAI,gBAAgB,OAAO,EAAE,OAAO,eAAe;CACnD,OAAO;EACL,OAAO;EACP,cAAc,sBAAsB,OAAO;CAC7C;AACF;;;;;AAMA,SAAgB,kBACd,cACA,GACA,GACoB;CACpB,OAAO,eACH,KAAK,IAAK,eAAe,KAAK,IAAI,GAAG,CAAC,IAAK,GAAG,CAAC,IAC/C,KAAA;AACN"}
1
+ {"version":3,"file":"visualStyle.js","names":[],"sources":["../../../src/renderPptx/utils/visualStyle.ts"],"sourcesContent":["/**\n * 見た目属性 (fill / border / shadow / opacity / borderRadius) を\n * PPTX 描画用の中間オプションへ変換する共通 resolver 群。\n *\n * ノードごとに変換ロジックが重複・乖離すると、XML 上は同じ指定でも\n * 描画結果が異なるリスクがあるため、属性値から描画オプションへの\n * 純粋変換をここに集約する。\n *\n * 共通化対象の属性カテゴリ:\n * - fill (背景色 + opacity): resolveBackgroundFill / opacityToTransparency\n * - border / line (枠線): hasVisibleBorder / convertBorderLine\n * - shadow (影): convertShadow\n * - borderRadius (角丸): resolveRectRadius\n *\n * 既存 helper との責務境界:\n * - utils/glimpseShape.ts: backgroundGradient writer 生成 XML native\n * gradFill として出力する。\n * - utils/backgroundBorder.ts: 背景色 → 背景画像 → ボーダーの描画順序の\n * オーケストレーション。個々の属性値の変換は本モジュールに委譲する。\n * - textOptions.ts: テキスト系属性 (font / underline / strike など) の変換。\n */\nimport type { BorderStyle, ShadowStyle } from \"../../types.ts\";\nimport { pxToPt } from \"../units.ts\";\n\n/**\n * 色文字列から \"#\" を 1 つ取り除き、OOXML 向けの HEX 文字列にする。\n * undefined はそのまま返すため `stripHash(color) ?? fallback` の形で使える。\n */\nexport function stripHash(color: string | undefined): string | undefined {\n return color?.replace(\"#\", \"\");\n}\n\n/**\n * ShadowStyle を描画用の shadow オプションに変換する\n * type 未指定時は outer をデフォルトとする\n */\nexport function convertShadow(shadow: ShadowStyle | undefined):\n | {\n type: \"outer\" | \"inner\";\n opacity?: number;\n blur?: number;\n angle?: number;\n offset?: number;\n color?: string;\n }\n | undefined {\n if (!shadow) return undefined;\n return {\n type: shadow.type ?? \"outer\",\n opacity: shadow.opacity,\n blur: shadow.blur,\n angle: shadow.angle,\n offset: shadow.offset,\n color: shadow.color,\n };\n}\n\n/**\n * border が描画対象となる指定 (color / width / dashType のいずれか) を\n * 持つかを判定する\n */\nexport function hasVisibleBorder(\n border: BorderStyle | undefined,\n): border is BorderStyle {\n return Boolean(\n border &&\n (border.color !== undefined ||\n border.width !== undefined ||\n border.dashType !== undefined),\n );\n}\n\nexport const BORDER_SIDES = [\"top\", \"right\", \"bottom\", \"left\"] as const;\nexport type BorderSide = (typeof BORDER_SIDES)[number];\n\nexport type PerSideBorders = Partial<Record<BorderSide, BorderStyle>>;\n\n/**\n * 4 辺一律の border と辺ごとの borderTop / borderRight / borderBottom /\n * borderLeft をマージし、描画対象となる辺ごとの BorderStyle を返す。\n *\n * - 辺ごとの指定が 1 つも無い場合は undefined を返し、呼び出し側は\n * 従来の 4 辺一律描画 (shape の line オプション) にフォールバックする\n * - 辺ごとの指定がある場合、各辺は border をベースに辺ごとの指定で\n * フィールド単位に上書きした BorderStyle になる (辺ごとの指定が優先)\n * - マージ結果が描画対象とならない辺 (指定なし) は結果に含まれない\n */\nexport function resolvePerSideBorders(style: {\n border?: BorderStyle;\n borderTop?: BorderStyle;\n borderRight?: BorderStyle;\n borderBottom?: BorderStyle;\n borderLeft?: BorderStyle;\n}): PerSideBorders | undefined {\n const overrides: Partial<Record<BorderSide, BorderStyle | undefined>> = {\n top: style.borderTop,\n right: style.borderRight,\n bottom: style.borderBottom,\n left: style.borderLeft,\n };\n\n const hasPerSideOverride = Object.values(overrides).some(hasVisibleBorder);\n if (!hasPerSideOverride) return undefined;\n\n const result: PerSideBorders = {};\n for (const side of BORDER_SIDES) {\n const merged = { ...style.border, ...overrides[side] };\n if (hasVisibleBorder(merged)) {\n result[side] = merged;\n }\n }\n return result;\n}\n\n/**\n * BorderStyle を描画用の line オプションに変換する\n * width はユーザー入力 px、描画用の line.width は pt\n *\n * @param fallbackColor color 未指定時に使う色。省略時は color を\n * undefined のまま渡し呼び出し側のデフォルトに任せる\n */\nexport function convertBorderLine(\n border: BorderStyle,\n fallbackColor?: string,\n): { color?: string; width?: number; dashType?: BorderStyle[\"dashType\"] } {\n return {\n color: border.color ?? fallbackColor,\n width: border.width !== undefined ? pxToPt(border.width) : undefined,\n dashType: border.dashType,\n };\n}\n\n/**\n * ノードの opacity (0-1、1 = 不透明) を描画用の\n * transparency (0-100、100 = 透明) に変換する\n */\nexport function opacityToTransparency(\n opacity: number | undefined,\n): number | undefined {\n return opacity !== undefined ? (1 - opacity) * 100 : undefined;\n}\n\n/**\n * backgroundColor / opacity / 互換用のグラデーション fallback 色から\n * fill オプションを解決する\n *\n * gradientMarker は既存 helper の互換引数として残している。\n * backgroundGradient utils/glimpseShape.ts 側で native\n * gradFill に変換する。\n */\nexport function resolveBackgroundFill(\n backgroundColor: string | undefined,\n opacity: number | undefined,\n gradientMarker: string | undefined,\n): { color?: string; transparency?: number } {\n if (gradientMarker) return { color: gradientMarker };\n return {\n color: backgroundColor,\n transparency: opacityToTransparency(opacity),\n };\n}\n\n/**\n * borderRadius (px) をノードサイズに対する 0-1 の正規化値\n * (roundRect の rectRadius) に変換する\n */\nexport function resolveRectRadius(\n borderRadius: number | undefined,\n w: number,\n h: number,\n): number | undefined {\n return borderRadius\n ? Math.min((borderRadius / Math.min(w, h)) * 2, 1)\n : undefined;\n}\n"],"mappings":";;;;;AA4BA,SAAgB,UAAU,OAA+C;CACvE,OAAO,OAAO,QAAQ,KAAK,EAAE;AAC/B;;;;;AA+BA,SAAgB,iBACd,QACuB;CACvB,OAAO,QACL,WACC,OAAO,UAAU,KAAA,KAChB,OAAO,UAAU,KAAA,KACjB,OAAO,aAAa,KAAA,EACxB;AACF;AAEA,MAAa,eAAe;CAAC;CAAO;CAAS;CAAU;AAAM;;;;;;;;;;;AAe7D,SAAgB,sBAAsB,OAMP;CAC7B,MAAM,YAAkE;EACtE,KAAK,MAAM;EACX,OAAO,MAAM;EACb,QAAQ,MAAM;EACd,MAAM,MAAM;CACd;CAGA,IAAI,CADuB,OAAO,OAAO,SAAS,CAAC,CAAC,KAAK,gBACnC,GAAG,OAAO,KAAA;CAEhC,MAAM,SAAyB,CAAC;CAChC,KAAK,MAAM,QAAQ,cAAc;EAC/B,MAAM,SAAS;GAAE,GAAG,MAAM;GAAQ,GAAG,UAAU;EAAM;EACrD,IAAI,iBAAiB,MAAM,GACzB,OAAO,QAAQ;CAEnB;CACA,OAAO;AACT;;;;;AAsDA,SAAgB,kBACd,cACA,GACA,GACoB;CACpB,OAAO,eACH,KAAK,IAAK,eAAe,KAAK,IAAI,GAAG,CAAC,IAAK,GAAG,CAAC,IAC/C,KAAA;AACN"}
@@ -0,0 +1,23 @@
1
+ import { Buffer } from "node:buffer";
2
+
3
+ //#region src/renderPptx/writablePptx.d.ts
4
+ type PptxOutputType = "arraybuffer" | "base64" | "binarystring" | "blob" | "nodebuffer" | "uint8array";
5
+ type PptxWriteOptions = {
6
+ outputType?: PptxOutputType;
7
+ };
8
+ type PptxWriteFileOptions = {
9
+ fileName?: string;
10
+ };
11
+ type PptxWriteOutput<T extends PptxOutputType | undefined> = T extends "arraybuffer" ? ArrayBuffer : T extends "base64" | "binarystring" ? string : T extends "nodebuffer" ? Buffer : T extends "uint8array" ? Uint8Array : Blob;
12
+ interface WritablePptx {
13
+ write(): Promise<Blob>;
14
+ write<T extends PptxOutputType>(options: PptxWriteOptions & {
15
+ outputType: T;
16
+ }): Promise<PptxWriteOutput<T>>;
17
+ write(options: PptxWriteOptions): Promise<PptxWriteOutput<PptxOutputType | undefined>>;
18
+ stream(): Promise<Uint8Array>;
19
+ writeFile(options?: PptxWriteFileOptions | string): Promise<string>;
20
+ }
21
+ //#endregion
22
+ export { PptxOutputType, PptxWriteFileOptions, PptxWriteOptions, PptxWriteOutput, WritablePptx };
23
+ //# sourceMappingURL=writablePptx.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writablePptx.d.ts","names":[],"sources":["../../src/renderPptx/writablePptx.ts"],"mappings":";;;KAGY,cAAA;AAAA,KAQA,gBAAA;EACV,UAAA,GAAa,cAAc;AAAA;AAAA,KAGjB,oBAAA;EACV,QAAQ;AAAA;AAAA,KAGE,eAAA,WAA0B,cAAA,gBACpC,CAAA,yBACI,WAAA,GACA,CAAA,8CAEE,CAAA,wBACE,MAAA,GACA,CAAA,wBACE,UAAA,GACA,IAAA;AAAA,UAEK,YAAA;EACf,KAAA,IAAS,OAAA,CAAQ,IAAA;EACjB,KAAA,WAAgB,cAAA,EACd,OAAA,EAAS,gBAAA;IAAqB,UAAA,EAAY,CAAA;EAAA,IACzC,OAAA,CAAQ,eAAA,CAAgB,CAAA;EAC3B,KAAA,CACE,OAAA,EAAS,gBAAA,GACR,OAAA,CAAQ,eAAA,CAAgB,cAAA;EAC3B,MAAA,IAAU,OAAA,CAAQ,UAAA;EAClB,SAAA,CAAU,OAAA,GAAU,oBAAA,YAAgC,OAAA;AAAA"}
@@ -0,0 +1,74 @@
1
+ import { writePptx } from "@pptx-glimpse/document";
2
+ //#region src/renderPptx/writablePptx.ts
3
+ function toArrayBuffer(bytes) {
4
+ return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
5
+ }
6
+ function toBinaryString(bytes) {
7
+ let result = "";
8
+ for (const byte of bytes) result += String.fromCharCode(byte);
9
+ return result;
10
+ }
11
+ function toBase64(bytes) {
12
+ if (typeof Buffer !== "undefined") return Buffer.from(bytes).toString("base64");
13
+ return btoa(toBinaryString(bytes));
14
+ }
15
+ function normalizeFileName(fileName) {
16
+ return fileName.toLowerCase().endsWith(".pptx") ? fileName : `${fileName}.pptx`;
17
+ }
18
+ function downloadInBrowser(fileName, bytes) {
19
+ const blob = new Blob([toArrayBuffer(bytes)], { type: "application/vnd.openxmlformats-officedocument.presentationml.presentation" });
20
+ const url = URL.createObjectURL(blob);
21
+ let anchor;
22
+ const cleanup = () => {
23
+ try {
24
+ anchor?.remove();
25
+ } finally {
26
+ URL.revokeObjectURL(url);
27
+ }
28
+ };
29
+ let cleanupScheduled = false;
30
+ try {
31
+ anchor = document.createElement("a");
32
+ anchor.href = url;
33
+ anchor.download = fileName;
34
+ document.body.append(anchor);
35
+ anchor.click();
36
+ setTimeout(cleanup, 0);
37
+ cleanupScheduled = true;
38
+ } finally {
39
+ if (!cleanupScheduled) cleanup();
40
+ }
41
+ }
42
+ function createWritablePptx(getSource) {
43
+ function write(options) {
44
+ return Promise.resolve().then(() => {
45
+ const bytes = writePptx(getSource());
46
+ switch (options?.outputType) {
47
+ case "arraybuffer": return toArrayBuffer(bytes);
48
+ case "base64": return toBase64(bytes);
49
+ case "binarystring": return toBinaryString(bytes);
50
+ case "nodebuffer": return Buffer.from(bytes);
51
+ case "uint8array": return bytes;
52
+ case "blob":
53
+ case void 0: return new Blob([toArrayBuffer(bytes)], { type: "application/vnd.openxmlformats-officedocument.presentationml.presentation" });
54
+ }
55
+ });
56
+ }
57
+ return {
58
+ write,
59
+ stream() {
60
+ return Promise.resolve().then(() => writePptx(getSource()));
61
+ },
62
+ async writeFile(options) {
63
+ const fileName = normalizeFileName(typeof options === "string" ? options : options?.fileName ?? "Presentation.pptx");
64
+ const bytes = writePptx(getSource());
65
+ if (typeof document !== "undefined") downloadInBrowser(fileName, bytes);
66
+ else await (await import("node:fs/promises")).writeFile(fileName, bytes);
67
+ return fileName;
68
+ }
69
+ };
70
+ }
71
+ //#endregion
72
+ export { createWritablePptx };
73
+
74
+ //# sourceMappingURL=writablePptx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writablePptx.js","names":[],"sources":["../../src/renderPptx/writablePptx.ts"],"sourcesContent":["import { writePptx, type PptxSourceModel } from \"@pptx-glimpse/document\";\nimport type { Buffer as NodeBuffer } from \"node:buffer\";\n\nexport type PptxOutputType =\n | \"arraybuffer\"\n | \"base64\"\n | \"binarystring\"\n | \"blob\"\n | \"nodebuffer\"\n | \"uint8array\";\n\nexport type PptxWriteOptions = {\n outputType?: PptxOutputType;\n};\n\nexport type PptxWriteFileOptions = {\n fileName?: string;\n};\n\nexport type PptxWriteOutput<T extends PptxOutputType | undefined> =\n T extends \"arraybuffer\"\n ? ArrayBuffer\n : T extends \"base64\" | \"binarystring\"\n ? string\n : T extends \"nodebuffer\"\n ? NodeBuffer\n : T extends \"uint8array\"\n ? Uint8Array\n : Blob;\n\nexport interface WritablePptx {\n write(): Promise<Blob>;\n write<T extends PptxOutputType>(\n options: PptxWriteOptions & { outputType: T },\n ): Promise<PptxWriteOutput<T>>;\n write(\n options: PptxWriteOptions,\n ): Promise<PptxWriteOutput<PptxOutputType | undefined>>;\n stream(): Promise<Uint8Array>;\n writeFile(options?: PptxWriteFileOptions | string): Promise<string>;\n}\n\nfunction toArrayBuffer(bytes: Uint8Array): ArrayBuffer {\n return bytes.buffer.slice(\n bytes.byteOffset,\n bytes.byteOffset + bytes.byteLength,\n ) as ArrayBuffer;\n}\n\nfunction toBinaryString(bytes: Uint8Array): string {\n let result = \"\";\n for (const byte of bytes) result += String.fromCharCode(byte);\n return result;\n}\n\nfunction toBase64(bytes: Uint8Array): string {\n if (typeof Buffer !== \"undefined\")\n return Buffer.from(bytes).toString(\"base64\");\n return btoa(toBinaryString(bytes));\n}\n\nfunction normalizeFileName(fileName: string): string {\n return fileName.toLowerCase().endsWith(\".pptx\")\n ? fileName\n : `${fileName}.pptx`;\n}\n\nfunction downloadInBrowser(fileName: string, bytes: Uint8Array): void {\n const blob = new Blob([toArrayBuffer(bytes)], {\n type: \"application/vnd.openxmlformats-officedocument.presentationml.presentation\",\n });\n const url = URL.createObjectURL(blob);\n let anchor: HTMLAnchorElement | undefined;\n const cleanup = () => {\n try {\n anchor?.remove();\n } finally {\n URL.revokeObjectURL(url);\n }\n };\n let cleanupScheduled = false;\n try {\n anchor = document.createElement(\"a\");\n anchor.href = url;\n anchor.download = fileName;\n document.body.append(anchor);\n anchor.click();\n setTimeout(cleanup, 0);\n cleanupScheduled = true;\n } finally {\n if (!cleanupScheduled) cleanup();\n }\n}\n\nexport function createWritablePptx(\n getSource: () => PptxSourceModel,\n): WritablePptx {\n function write(options?: PptxWriteOptions): Promise<unknown> {\n return Promise.resolve().then(() => {\n const bytes = writePptx(getSource());\n switch (options?.outputType) {\n case \"arraybuffer\":\n return toArrayBuffer(bytes);\n case \"base64\":\n return toBase64(bytes);\n case \"binarystring\":\n return toBinaryString(bytes);\n case \"nodebuffer\":\n return Buffer.from(bytes);\n case \"uint8array\":\n return bytes;\n case \"blob\":\n case undefined:\n return new Blob([toArrayBuffer(bytes)], {\n type: \"application/vnd.openxmlformats-officedocument.presentationml.presentation\",\n });\n }\n });\n }\n\n return {\n write: write as WritablePptx[\"write\"],\n stream() {\n return Promise.resolve().then(() => writePptx(getSource()));\n },\n async writeFile(options) {\n const fileName = normalizeFileName(\n typeof options === \"string\"\n ? options\n : (options?.fileName ?? \"Presentation.pptx\"),\n );\n const bytes = writePptx(getSource());\n if (typeof document !== \"undefined\") {\n downloadInBrowser(fileName, bytes);\n } else {\n const fs = await import(\"node:fs/promises\");\n await fs.writeFile(fileName, bytes);\n }\n return fileName;\n },\n };\n}\n"],"mappings":";;AA0CA,SAAS,cAAc,OAAgC;CACrD,OAAO,MAAM,OAAO,MAClB,MAAM,YACN,MAAM,aAAa,MAAM,UAC3B;AACF;AAEA,SAAS,eAAe,OAA2B;CACjD,IAAI,SAAS;CACb,KAAK,MAAM,QAAQ,OAAO,UAAU,OAAO,aAAa,IAAI;CAC5D,OAAO;AACT;AAEA,SAAS,SAAS,OAA2B;CAC3C,IAAI,OAAO,WAAW,aACpB,OAAO,OAAO,KAAK,KAAK,CAAC,CAAC,SAAS,QAAQ;CAC7C,OAAO,KAAK,eAAe,KAAK,CAAC;AACnC;AAEA,SAAS,kBAAkB,UAA0B;CACnD,OAAO,SAAS,YAAY,CAAC,CAAC,SAAS,OAAO,IAC1C,WACA,GAAG,SAAS;AAClB;AAEA,SAAS,kBAAkB,UAAkB,OAAyB;CACpE,MAAM,OAAO,IAAI,KAAK,CAAC,cAAc,KAAK,CAAC,GAAG,EAC5C,MAAM,4EACR,CAAC;CACD,MAAM,MAAM,IAAI,gBAAgB,IAAI;CACpC,IAAI;CACJ,MAAM,gBAAgB;EACpB,IAAI;GACF,QAAQ,OAAO;EACjB,UAAU;GACR,IAAI,gBAAgB,GAAG;EACzB;CACF;CACA,IAAI,mBAAmB;CACvB,IAAI;EACF,SAAS,SAAS,cAAc,GAAG;EACnC,OAAO,OAAO;EACd,OAAO,WAAW;EAClB,SAAS,KAAK,OAAO,MAAM;EAC3B,OAAO,MAAM;EACb,WAAW,SAAS,CAAC;EACrB,mBAAmB;CACrB,UAAU;EACR,IAAI,CAAC,kBAAkB,QAAQ;CACjC;AACF;AAEA,SAAgB,mBACd,WACc;CACd,SAAS,MAAM,SAA8C;EAC3D,OAAO,QAAQ,QAAQ,CAAC,CAAC,WAAW;GAClC,MAAM,QAAQ,UAAU,UAAU,CAAC;GACnC,QAAQ,SAAS,YAAjB;IACE,KAAK,eACH,OAAO,cAAc,KAAK;IAC5B,KAAK,UACH,OAAO,SAAS,KAAK;IACvB,KAAK,gBACH,OAAO,eAAe,KAAK;IAC7B,KAAK,cACH,OAAO,OAAO,KAAK,KAAK;IAC1B,KAAK,cACH,OAAO;IACT,KAAK;IACL,KAAK,KAAA,GACH,OAAO,IAAI,KAAK,CAAC,cAAc,KAAK,CAAC,GAAG,EACtC,MAAM,4EACR,CAAC;GACL;EACF,CAAC;CACH;CAEA,OAAO;EACE;EACP,SAAS;GACP,OAAO,QAAQ,QAAQ,CAAC,CAAC,WAAW,UAAU,UAAU,CAAC,CAAC;EAC5D;EACA,MAAM,UAAU,SAAS;GACvB,MAAM,WAAW,kBACf,OAAO,YAAY,WACf,UACC,SAAS,YAAY,mBAC5B;GACA,MAAM,QAAQ,UAAU,UAAU,CAAC;GACnC,IAAI,OAAO,aAAa,aACtB,kBAAkB,UAAU,KAAK;QAGjC,OAAM,MADW,OAAO,oBAAA,CACf,UAAU,UAAU,KAAK;GAEpC,OAAO;EACT;CACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"measureImage.js","names":[],"sources":["../../src/shared/measureImage.ts"],"sourcesContent":["import * as fs from \"fs\";\nimport { imageSize } from \"image-size\";\nimport type { DiagnosticCollector } from \"../diagnostics.ts\";\n\ntype ImageSizeCache = Map<string, { widthPx: number; heightPx: number }>;\ntype ImageDataCache = Map<string, string>;\n\n/**\n * キャッシュされた画像データ(Base64)を取得する\n * @param src 画像のパス\n * @param cache 画像データキャッシュ\n * @returns Base64形式の画像データ、またはキャッシュがない場合はundefined\n */\nexport function getImageData(\n src: string,\n cache: ImageDataCache,\n): string | undefined {\n return cache.get(src);\n}\n\n/**\n * 画像サイズを事前取得してキャッシュする(非同期)\n * HTTPS URLの画像を処理する際に使用\n * @param src 画像のパス(ローカルパス、base64データ、またはHTTPS URL)\n * @param sizeCache 画像サイズキャッシュ\n * @param dataCache 画像データキャッシュ\n * @returns 画像の幅と高さ(px)\n */\nexport async function prefetchImageSize(\n src: string,\n sizeCache: ImageSizeCache,\n dataCache: ImageDataCache,\n diagnostics: DiagnosticCollector,\n): Promise<{\n widthPx: number;\n heightPx: number;\n}> {\n // キャッシュにあればそれを返す\n const cached = sizeCache.get(src);\n if (cached) {\n return cached;\n }\n\n try {\n let buffer: Uint8Array;\n\n // base64データの場合\n if (src.startsWith(\"data:\")) {\n const base64Data = src.split(\",\")[1];\n buffer = new Uint8Array(Buffer.from(base64Data, \"base64\"));\n }\n // HTTPS/HTTP URLの場合\n else if (src.startsWith(\"https://\") || src.startsWith(\"http://\")) {\n const response = await fetch(src);\n if (!response.ok) {\n throw new Error(`Failed to fetch image: ${response.status}`);\n }\n const arrayBuffer = await response.arrayBuffer();\n buffer = new Uint8Array(arrayBuffer);\n\n // 画像データをBase64形式でキャッシュ(pptxgenjs用)\n const contentType = response.headers.get(\"content-type\") || \"image/png\";\n const base64 = Buffer.from(arrayBuffer).toString(\"base64\");\n dataCache.set(src, `${contentType};base64,${base64}`);\n }\n // ローカルファイルパスの場合\n else {\n buffer = new Uint8Array(fs.readFileSync(src));\n }\n\n const dimensions = imageSize(buffer);\n\n const width = dimensions.width ?? 100; // デフォルト100px\n const height = dimensions.height ?? 100; // デフォルト100px\n\n const result = {\n widthPx: width,\n heightPx: height,\n };\n\n // キャッシュに保存\n sizeCache.set(src, result);\n\n return result;\n } catch (error) {\n // エラーが発生した場合はデフォルトサイズを返す\n diagnostics.add(\n \"IMAGE_MEASURE_FAILED\",\n `Failed to measure image size for ${src}: ${String(error)}`,\n );\n const result = {\n widthPx: 100,\n heightPx: 100,\n };\n sizeCache.set(src, result);\n return result;\n }\n}\n\n/**\n * 画像ファイルのサイズを取得する(同期)\n * 事前にprefetchImageSizeでキャッシュしておくこと\n * @param src 画像のパス(ローカルパス、base64データ、またはHTTPS URL)\n * @param sizeCache 画像サイズキャッシュ\n * @returns 画像の幅と高さ(px)\n */\nexport function measureImage(\n src: string,\n sizeCache: ImageSizeCache,\n diagnostics: DiagnosticCollector,\n): {\n widthPx: number;\n heightPx: number;\n} {\n // キャッシュにあればそれを返す\n const cached = sizeCache.get(src);\n if (cached) {\n return cached;\n }\n\n // キャッシュにない場合(ローカルファイルやbase64のみ同期処理可能)\n try {\n let buffer: Uint8Array;\n\n // base64データの場合\n if (src.startsWith(\"data:\")) {\n const base64Data = src.split(\",\")[1];\n buffer = new Uint8Array(Buffer.from(base64Data, \"base64\"));\n }\n // HTTPS/HTTP URLの場合はキャッシュがないとデフォルト値を返す\n else if (src.startsWith(\"https://\") || src.startsWith(\"http://\")) {\n diagnostics.add(\n \"IMAGE_NOT_PREFETCHED\",\n `Image size for URL ${src} was not prefetched. Using default size.`,\n );\n return {\n widthPx: 100,\n heightPx: 100,\n };\n }\n // ローカルファイルパスの場合\n else {\n buffer = new Uint8Array(fs.readFileSync(src));\n }\n\n const dimensions = imageSize(buffer);\n\n const width = dimensions.width ?? 100; // デフォルト100px\n const height = dimensions.height ?? 100; // デフォルト100px\n\n const result = {\n widthPx: width,\n heightPx: height,\n };\n\n // キャッシュに保存\n sizeCache.set(src, result);\n\n return result;\n } catch (error) {\n // エラーが発生した場合はデフォルトサイズを返す\n diagnostics.add(\n \"IMAGE_MEASURE_FAILED\",\n `Failed to measure image size for ${src}: ${String(error)}`,\n );\n return {\n widthPx: 100,\n heightPx: 100,\n };\n }\n}\n"],"mappings":";;;;;;;;;AAaA,SAAgB,aACd,KACA,OACoB;CACpB,OAAO,MAAM,IAAI,GAAG;AACtB;;;;;;;;;AAUA,eAAsB,kBACpB,KACA,WACA,WACA,aAIC;CAED,MAAM,SAAS,UAAU,IAAI,GAAG;CAChC,IAAI,QACF,OAAO;CAGT,IAAI;EACF,IAAI;EAGJ,IAAI,IAAI,WAAW,OAAO,GAAG;GAC3B,MAAM,aAAa,IAAI,MAAM,GAAG,CAAC,CAAC;GAClC,SAAS,IAAI,WAAW,OAAO,KAAK,YAAY,QAAQ,CAAC;EAC3D,OAEK,IAAI,IAAI,WAAW,UAAU,KAAK,IAAI,WAAW,SAAS,GAAG;GAChE,MAAM,WAAW,MAAM,MAAM,GAAG;GAChC,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,0BAA0B,SAAS,QAAQ;GAE7D,MAAM,cAAc,MAAM,SAAS,YAAY;GAC/C,SAAS,IAAI,WAAW,WAAW;GAGnC,MAAM,cAAc,SAAS,QAAQ,IAAI,cAAc,KAAK;GAC5D,MAAM,SAAS,OAAO,KAAK,WAAW,CAAC,CAAC,SAAS,QAAQ;GACzD,UAAU,IAAI,KAAK,GAAG,YAAY,UAAU,QAAQ;EACtD,OAGE,SAAS,IAAI,WAAW,GAAG,aAAa,GAAG,CAAC;EAG9C,MAAM,aAAa,UAAU,MAAM;EAKnC,MAAM,SAAS;GACb,SAJY,WAAW,SAAS;GAKhC,UAJa,WAAW,UAAU;EAKpC;EAGA,UAAU,IAAI,KAAK,MAAM;EAEzB,OAAO;CACT,SAAS,OAAO;EAEd,YAAY,IACV,wBACA,oCAAoC,IAAI,IAAI,OAAO,KAAK,GAC1D;EACA,MAAM,SAAS;GACb,SAAS;GACT,UAAU;EACZ;EACA,UAAU,IAAI,KAAK,MAAM;EACzB,OAAO;CACT;AACF;;;;;;;;AASA,SAAgB,aACd,KACA,WACA,aAIA;CAEA,MAAM,SAAS,UAAU,IAAI,GAAG;CAChC,IAAI,QACF,OAAO;CAIT,IAAI;EACF,IAAI;EAGJ,IAAI,IAAI,WAAW,OAAO,GAAG;GAC3B,MAAM,aAAa,IAAI,MAAM,GAAG,CAAC,CAAC;GAClC,SAAS,IAAI,WAAW,OAAO,KAAK,YAAY,QAAQ,CAAC;EAC3D,OAEK,IAAI,IAAI,WAAW,UAAU,KAAK,IAAI,WAAW,SAAS,GAAG;GAChE,YAAY,IACV,wBACA,sBAAsB,IAAI,yCAC5B;GACA,OAAO;IACL,SAAS;IACT,UAAU;GACZ;EACF,OAGE,SAAS,IAAI,WAAW,GAAG,aAAa,GAAG,CAAC;EAG9C,MAAM,aAAa,UAAU,MAAM;EAKnC,MAAM,SAAS;GACb,SAJY,WAAW,SAAS;GAKhC,UAJa,WAAW,UAAU;EAKpC;EAGA,UAAU,IAAI,KAAK,MAAM;EAEzB,OAAO;CACT,SAAS,OAAO;EAEd,YAAY,IACV,wBACA,oCAAoC,IAAI,IAAI,OAAO,KAAK,GAC1D;EACA,OAAO;GACL,SAAS;GACT,UAAU;EACZ;CACF;AACF"}
1
+ {"version":3,"file":"measureImage.js","names":[],"sources":["../../src/shared/measureImage.ts"],"sourcesContent":["import * as fs from \"fs\";\nimport { imageSize } from \"image-size\";\nimport type { DiagnosticCollector } from \"../diagnostics.ts\";\n\ntype ImageSizeCache = Map<string, { widthPx: number; heightPx: number }>;\ntype ImageDataCache = Map<string, string>;\n\n/**\n * キャッシュされた画像データ(Base64)を取得する\n * @param src 画像のパス\n * @param cache 画像データキャッシュ\n * @returns Base64形式の画像データ、またはキャッシュがない場合はundefined\n */\nexport function getImageData(\n src: string,\n cache: ImageDataCache,\n): string | undefined {\n return cache.get(src);\n}\n\n/**\n * 画像サイズを事前取得してキャッシュする(非同期)\n * HTTPS URLの画像を処理する際に使用\n * @param src 画像のパス(ローカルパス、base64データ、またはHTTPS URL)\n * @param sizeCache 画像サイズキャッシュ\n * @param dataCache 画像データキャッシュ\n * @returns 画像の幅と高さ(px)\n */\nexport async function prefetchImageSize(\n src: string,\n sizeCache: ImageSizeCache,\n dataCache: ImageDataCache,\n diagnostics: DiagnosticCollector,\n): Promise<{\n widthPx: number;\n heightPx: number;\n}> {\n // キャッシュにあればそれを返す\n const cached = sizeCache.get(src);\n if (cached) {\n return cached;\n }\n\n try {\n let buffer: Uint8Array;\n\n // base64データの場合\n if (src.startsWith(\"data:\")) {\n const base64Data = src.split(\",\")[1];\n buffer = new Uint8Array(Buffer.from(base64Data, \"base64\"));\n }\n // HTTPS/HTTP URLの場合\n else if (src.startsWith(\"https://\") || src.startsWith(\"http://\")) {\n const response = await fetch(src);\n if (!response.ok) {\n throw new Error(`Failed to fetch image: ${response.status}`);\n }\n const arrayBuffer = await response.arrayBuffer();\n buffer = new Uint8Array(arrayBuffer);\n\n // 画像データを Base64 形式でキャッシュ(PPTX authoring 用)\n const contentType = response.headers.get(\"content-type\") || \"image/png\";\n const base64 = Buffer.from(arrayBuffer).toString(\"base64\");\n dataCache.set(src, `${contentType};base64,${base64}`);\n }\n // ローカルファイルパスの場合\n else {\n buffer = new Uint8Array(fs.readFileSync(src));\n }\n\n const dimensions = imageSize(buffer);\n\n const width = dimensions.width ?? 100; // デフォルト100px\n const height = dimensions.height ?? 100; // デフォルト100px\n\n const result = {\n widthPx: width,\n heightPx: height,\n };\n\n // キャッシュに保存\n sizeCache.set(src, result);\n\n return result;\n } catch (error) {\n // エラーが発生した場合はデフォルトサイズを返す\n diagnostics.add(\n \"IMAGE_MEASURE_FAILED\",\n `Failed to measure image size for ${src}: ${String(error)}`,\n );\n const result = {\n widthPx: 100,\n heightPx: 100,\n };\n sizeCache.set(src, result);\n return result;\n }\n}\n\n/**\n * 画像ファイルのサイズを取得する(同期)\n * 事前にprefetchImageSizeでキャッシュしておくこと\n * @param src 画像のパス(ローカルパス、base64データ、またはHTTPS URL)\n * @param sizeCache 画像サイズキャッシュ\n * @returns 画像の幅と高さ(px)\n */\nexport function measureImage(\n src: string,\n sizeCache: ImageSizeCache,\n diagnostics: DiagnosticCollector,\n): {\n widthPx: number;\n heightPx: number;\n} {\n // キャッシュにあればそれを返す\n const cached = sizeCache.get(src);\n if (cached) {\n return cached;\n }\n\n // キャッシュにない場合(ローカルファイルやbase64のみ同期処理可能)\n try {\n let buffer: Uint8Array;\n\n // base64データの場合\n if (src.startsWith(\"data:\")) {\n const base64Data = src.split(\",\")[1];\n buffer = new Uint8Array(Buffer.from(base64Data, \"base64\"));\n }\n // HTTPS/HTTP URLの場合はキャッシュがないとデフォルト値を返す\n else if (src.startsWith(\"https://\") || src.startsWith(\"http://\")) {\n diagnostics.add(\n \"IMAGE_NOT_PREFETCHED\",\n `Image size for URL ${src} was not prefetched. Using default size.`,\n );\n return {\n widthPx: 100,\n heightPx: 100,\n };\n }\n // ローカルファイルパスの場合\n else {\n buffer = new Uint8Array(fs.readFileSync(src));\n }\n\n const dimensions = imageSize(buffer);\n\n const width = dimensions.width ?? 100; // デフォルト100px\n const height = dimensions.height ?? 100; // デフォルト100px\n\n const result = {\n widthPx: width,\n heightPx: height,\n };\n\n // キャッシュに保存\n sizeCache.set(src, result);\n\n return result;\n } catch (error) {\n // エラーが発生した場合はデフォルトサイズを返す\n diagnostics.add(\n \"IMAGE_MEASURE_FAILED\",\n `Failed to measure image size for ${src}: ${String(error)}`,\n );\n return {\n widthPx: 100,\n heightPx: 100,\n };\n }\n}\n"],"mappings":";;;;;;;;;AAaA,SAAgB,aACd,KACA,OACoB;CACpB,OAAO,MAAM,IAAI,GAAG;AACtB;;;;;;;;;AAUA,eAAsB,kBACpB,KACA,WACA,WACA,aAIC;CAED,MAAM,SAAS,UAAU,IAAI,GAAG;CAChC,IAAI,QACF,OAAO;CAGT,IAAI;EACF,IAAI;EAGJ,IAAI,IAAI,WAAW,OAAO,GAAG;GAC3B,MAAM,aAAa,IAAI,MAAM,GAAG,CAAC,CAAC;GAClC,SAAS,IAAI,WAAW,OAAO,KAAK,YAAY,QAAQ,CAAC;EAC3D,OAEK,IAAI,IAAI,WAAW,UAAU,KAAK,IAAI,WAAW,SAAS,GAAG;GAChE,MAAM,WAAW,MAAM,MAAM,GAAG;GAChC,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,0BAA0B,SAAS,QAAQ;GAE7D,MAAM,cAAc,MAAM,SAAS,YAAY;GAC/C,SAAS,IAAI,WAAW,WAAW;GAGnC,MAAM,cAAc,SAAS,QAAQ,IAAI,cAAc,KAAK;GAC5D,MAAM,SAAS,OAAO,KAAK,WAAW,CAAC,CAAC,SAAS,QAAQ;GACzD,UAAU,IAAI,KAAK,GAAG,YAAY,UAAU,QAAQ;EACtD,OAGE,SAAS,IAAI,WAAW,GAAG,aAAa,GAAG,CAAC;EAG9C,MAAM,aAAa,UAAU,MAAM;EAKnC,MAAM,SAAS;GACb,SAJY,WAAW,SAAS;GAKhC,UAJa,WAAW,UAAU;EAKpC;EAGA,UAAU,IAAI,KAAK,MAAM;EAEzB,OAAO;CACT,SAAS,OAAO;EAEd,YAAY,IACV,wBACA,oCAAoC,IAAI,IAAI,OAAO,KAAK,GAC1D;EACA,MAAM,SAAS;GACb,SAAS;GACT,UAAU;EACZ;EACA,UAAU,IAAI,KAAK,MAAM;EACzB,OAAO;CACT;AACF;;;;;;;;AASA,SAAgB,aACd,KACA,WACA,aAIA;CAEA,MAAM,SAAS,UAAU,IAAI,GAAG;CAChC,IAAI,QACF,OAAO;CAIT,IAAI;EACF,IAAI;EAGJ,IAAI,IAAI,WAAW,OAAO,GAAG;GAC3B,MAAM,aAAa,IAAI,MAAM,GAAG,CAAC,CAAC;GAClC,SAAS,IAAI,WAAW,OAAO,KAAK,YAAY,QAAQ,CAAC;EAC3D,OAEK,IAAI,IAAI,WAAW,UAAU,KAAK,IAAI,WAAW,SAAS,GAAG;GAChE,YAAY,IACV,wBACA,sBAAsB,IAAI,yCAC5B;GACA,OAAO;IACL,SAAS;IACT,UAAU;GACZ;EACF,OAGE,SAAS,IAAI,WAAW,GAAG,aAAa,GAAG,CAAC;EAG9C,MAAM,aAAa,UAAU,MAAM;EAKnC,MAAM,SAAS;GACb,SAJY,WAAW,SAAS;GAKhC,UAJa,WAAW,UAAU;EAKpC;EAGA,UAAU,IAAI,KAAK,MAAM;EAEzB,OAAO;CACT,SAAS,OAAO;EAEd,YAAY,IACV,wBACA,oCAAoC,IAAI,IAAI,OAAO,KAAK,GAC1D;EACA,OAAO;GACL,SAAS;GACT,UAAU;EACZ;CACF;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hirokisakabe/pom",
3
- "version": "9.1.1",
3
+ "version": "10.0.0",
4
4
  "description": "AI-friendly PowerPoint generation with a Flexbox layout engine.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -50,7 +50,6 @@
50
50
  },
51
51
  "devDependencies": {
52
52
  "@size-limit/file": "^12.1.0",
53
- "@types/node": "^26.1.0",
54
53
  "@types/opentype.js": "^1.3.10",
55
54
  "@types/pngjs": "6.0.5",
56
55
  "@vitest/coverage-v8": "^4.1.10",
@@ -64,13 +63,13 @@
64
63
  "tsx": "4.23.0"
65
64
  },
66
65
  "dependencies": {
67
- "@pptx-glimpse/document": "0.5.0",
66
+ "@pptx-glimpse/document": "0.9.1",
68
67
  "@resvg/resvg-wasm": "^2.6.2",
69
- "fast-xml-parser": "^5.9.3",
68
+ "@types/node": "^26.1.0",
69
+ "fast-xml-parser": "^5.10.0",
70
70
  "image-size": "2.0.2",
71
71
  "jszip": "^3.10.1",
72
72
  "opentype.js": "^2.0.0",
73
- "pptxgenjs": "4.0.1",
74
73
  "yoga-layout": "3.2.1",
75
74
  "zod": "^4.4.3"
76
75
  },