@hirokisakabe/pom 1.1.3 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +130 -15
  2. package/dist/calcYogaLayout/calcYogaLayout.js +8 -1
  3. package/dist/component.d.ts +90 -0
  4. package/dist/component.d.ts.map +1 -0
  5. package/dist/component.js +123 -0
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +1 -0
  9. package/dist/inputSchema.d.ts +300 -4
  10. package/dist/inputSchema.d.ts.map +1 -1
  11. package/dist/inputSchema.js +31 -1
  12. package/dist/renderPptx/nodes/image.d.ts.map +1 -1
  13. package/dist/renderPptx/nodes/image.js +19 -0
  14. package/dist/renderPptx/nodes/processArrow.d.ts.map +1 -1
  15. package/dist/renderPptx/nodes/processArrow.js +9 -0
  16. package/dist/renderPptx/nodes/shape.d.ts.map +1 -1
  17. package/dist/renderPptx/nodes/shape.js +6 -0
  18. package/dist/renderPptx/nodes/table.d.ts.map +1 -1
  19. package/dist/renderPptx/nodes/table.js +5 -0
  20. package/dist/renderPptx/renderPptx.d.ts +1 -1
  21. package/dist/renderPptx/renderPptx.d.ts.map +1 -1
  22. package/dist/renderPptx/renderPptx.js +31 -5
  23. package/dist/renderPptx/textOptions.d.ts +26 -1
  24. package/dist/renderPptx/textOptions.d.ts.map +1 -1
  25. package/dist/renderPptx/textOptions.js +27 -0
  26. package/dist/renderPptx/utils/backgroundBorder.d.ts +3 -1
  27. package/dist/renderPptx/utils/backgroundBorder.d.ts.map +1 -1
  28. package/dist/renderPptx/utils/backgroundBorder.js +103 -23
  29. package/dist/renderPptx/utils/textDrawing.d.ts +5 -0
  30. package/dist/renderPptx/utils/textDrawing.d.ts.map +1 -1
  31. package/dist/renderPptx/utils/textDrawing.js +6 -1
  32. package/dist/types.d.ts +401 -7
  33. package/dist/types.d.ts.map +1 -1
  34. package/dist/types.js +63 -0
  35. package/package.json +1 -1
@@ -17,7 +17,7 @@
17
17
  * ```
18
18
  */
19
19
  import { z } from "zod";
20
- import { lengthSchema, paddingSchema, borderStyleSchema, borderDashSchema, fillStyleSchema, shadowStyleSchema, alignItemsSchema, justifyContentSchema, shapeTypeSchema, tableColumnSchema, tableRowSchema, chartTypeSchema, chartDataSchema, bulletOptionsSchema, radarStyleSchema, timelineDirectionSchema, timelineItemSchema, matrixAxisSchema, matrixQuadrantsSchema, matrixItemSchema, treeLayoutSchema, treeNodeShapeSchema, treeConnectorStyleSchema, flowDirectionSchema, flowNodeItemSchema, flowConnectionSchema, flowConnectorStyleSchema, processArrowDirectionSchema, processArrowStepSchema, lineArrowSchema, } from "./types.js";
20
+ import { lengthSchema, paddingSchema, borderStyleSchema, borderDashSchema, fillStyleSchema, shadowStyleSchema, alignItemsSchema, justifyContentSchema, shapeTypeSchema, tableColumnSchema, tableRowSchema, chartTypeSchema, chartDataSchema, bulletOptionsSchema, radarStyleSchema, timelineDirectionSchema, timelineItemSchema, matrixAxisSchema, matrixQuadrantsSchema, matrixItemSchema, treeLayoutSchema, treeNodeShapeSchema, treeConnectorStyleSchema, flowDirectionSchema, flowNodeItemSchema, flowConnectionSchema, flowConnectorStyleSchema, processArrowDirectionSchema, processArrowStepSchema, lineArrowSchema, underlineSchema, backgroundImageSchema, } from "./types.js";
21
21
  // ===== Base Node Schema =====
22
22
  export const inputBaseNodeSchema = z.object({
23
23
  w: lengthSchema.optional(),
@@ -28,8 +28,10 @@ export const inputBaseNodeSchema = z.object({
28
28
  maxH: z.number().optional(),
29
29
  padding: paddingSchema.optional(),
30
30
  backgroundColor: z.string().optional(),
31
+ backgroundImage: backgroundImageSchema.optional(),
31
32
  border: borderStyleSchema.optional(),
32
33
  borderRadius: z.number().optional(),
34
+ opacity: z.number().min(0).max(1).optional(),
33
35
  });
34
36
  // ===== Node Schemas =====
35
37
  export const inputTextNodeSchema = inputBaseNodeSchema.extend({
@@ -39,13 +41,26 @@ export const inputTextNodeSchema = inputBaseNodeSchema.extend({
39
41
  color: z.string().optional(),
40
42
  alignText: z.enum(["left", "center", "right"]).optional(),
41
43
  bold: z.boolean().optional(),
44
+ italic: z.boolean().optional(),
45
+ underline: underlineSchema.optional(),
46
+ strike: z.boolean().optional(),
47
+ highlight: z.string().optional(),
42
48
  fontFamily: z.string().optional(),
43
49
  lineSpacingMultiple: z.number().optional(),
44
50
  bullet: z.union([z.boolean(), bulletOptionsSchema]).optional(),
45
51
  });
52
+ export const inputImageSizingSchema = z.object({
53
+ type: z.enum(["contain", "cover", "crop"]),
54
+ w: z.number().optional(),
55
+ h: z.number().optional(),
56
+ x: z.number().optional(),
57
+ y: z.number().optional(),
58
+ });
46
59
  export const inputImageNodeSchema = inputBaseNodeSchema.extend({
47
60
  type: z.literal("image"),
48
61
  src: z.string(),
62
+ sizing: inputImageSizingSchema.optional(),
63
+ shadow: shadowStyleSchema.optional(),
49
64
  });
50
65
  export const inputTableNodeSchema = inputBaseNodeSchema.extend({
51
66
  type: z.literal("table"),
@@ -63,6 +78,11 @@ export const inputShapeNodeSchema = inputBaseNodeSchema.extend({
63
78
  fontPx: z.number().optional(),
64
79
  color: z.string().optional(),
65
80
  alignText: z.enum(["left", "center", "right"]).optional(),
81
+ bold: z.boolean().optional(),
82
+ italic: z.boolean().optional(),
83
+ underline: underlineSchema.optional(),
84
+ strike: z.boolean().optional(),
85
+ highlight: z.string().optional(),
66
86
  });
67
87
  export const inputChartNodeSchema = inputBaseNodeSchema.extend({
68
88
  type: z.literal("chart"),
@@ -121,6 +141,10 @@ export const inputProcessArrowNodeSchema = inputBaseNodeSchema.extend({
121
141
  gap: z.number().optional(),
122
142
  fontPx: z.number().optional(),
123
143
  bold: z.boolean().optional(),
144
+ italic: z.boolean().optional(),
145
+ underline: underlineSchema.optional(),
146
+ strike: z.boolean().optional(),
147
+ highlight: z.string().optional(),
124
148
  });
125
149
  export const inputLineNodeSchema = inputBaseNodeSchema.extend({
126
150
  type: z.literal("line"),
@@ -138,6 +162,7 @@ export const inputLineNodeSchema = inputBaseNodeSchema.extend({
138
162
  const inputBoxNodeSchemaBase = inputBaseNodeSchema.extend({
139
163
  type: z.literal("box"),
140
164
  children: z.lazy(() => inputPomNodeSchema),
165
+ shadow: shadowStyleSchema.optional(),
141
166
  });
142
167
  const inputVStackNodeSchemaBase = inputBaseNodeSchema.extend({
143
168
  type: z.literal("vstack"),
@@ -212,6 +237,10 @@ export const inputMasterTextObjectSchema = z.object({
212
237
  fontFamily: z.string().optional(),
213
238
  color: z.string().optional(),
214
239
  bold: z.boolean().optional(),
240
+ italic: z.boolean().optional(),
241
+ underline: underlineSchema.optional(),
242
+ strike: z.boolean().optional(),
243
+ highlight: z.string().optional(),
215
244
  alignText: z.enum(["left", "center", "right"]).optional(),
216
245
  });
217
246
  export const inputMasterImageObjectSchema = z.object({
@@ -258,6 +287,7 @@ export const inputSlideMasterBackgroundSchema = z.union([
258
287
  z.object({ color: z.string() }),
259
288
  z.object({ path: z.string() }),
260
289
  z.object({ data: z.string() }),
290
+ z.object({ image: z.string() }),
261
291
  ]);
262
292
  export const inputSlideMasterMarginSchema = z.union([
263
293
  z.number(),
@@ -1 +1 @@
1
- {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../../src/renderPptx/nodes/image.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,KAAK,mBAAmB,GAAG,OAAO,CAAC,cAAc,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAEtE,wBAAgB,eAAe,CAC7B,IAAI,EAAE,mBAAmB,EACzB,GAAG,EAAE,aAAa,GACjB,IAAI,CAeN"}
1
+ {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../../src/renderPptx/nodes/image.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,KAAK,mBAAmB,GAAG,OAAO,CAAC,cAAc,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAEtE,wBAAgB,eAAe,CAC7B,IAAI,EAAE,mBAAmB,EACzB,GAAG,EAAE,aAAa,GACjB,IAAI,CAmCN"}
@@ -5,7 +5,26 @@ export function renderImageNode(node, ctx) {
5
5
  y: pxToIn(node.y),
6
6
  w: pxToIn(node.w),
7
7
  h: pxToIn(node.h),
8
+ shadow: node.shadow
9
+ ? {
10
+ type: node.shadow.type,
11
+ opacity: node.shadow.opacity,
12
+ blur: node.shadow.blur,
13
+ angle: node.shadow.angle,
14
+ offset: node.shadow.offset,
15
+ color: node.shadow.color,
16
+ }
17
+ : undefined,
8
18
  };
19
+ if (node.sizing) {
20
+ imageOptions.sizing = {
21
+ type: node.sizing.type,
22
+ w: pxToIn(node.sizing.w ?? node.w),
23
+ h: pxToIn(node.sizing.h ?? node.h),
24
+ ...(node.sizing.x !== undefined && { x: pxToIn(node.sizing.x) }),
25
+ ...(node.sizing.y !== undefined && { y: pxToIn(node.sizing.y) }),
26
+ };
27
+ }
9
28
  if (node.imageData) {
10
29
  // Base64 データがある場合は data プロパティを使用(リモート画像)
11
30
  ctx.slide.addImage({ ...imageOptions, data: node.imageData });
@@ -1 +1 @@
1
- {"version":3,"file":"processArrow.d.ts","sourceRoot":"","sources":["../../../src/renderPptx/nodes/processArrow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,KAAK,0BAA0B,GAAG,OAAO,CACvC,cAAc,EACd;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,CACzB,CAAC;AAEF,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,0BAA0B,EAChC,GAAG,EAAE,aAAa,GACjB,IAAI,CAsCN"}
1
+ {"version":3,"file":"processArrow.d.ts","sourceRoot":"","sources":["../../../src/renderPptx/nodes/processArrow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD,KAAK,0BAA0B,GAAG,OAAO,CACvC,cAAc,EACd;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,CACzB,CAAC;AAEF,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,0BAA0B,EAChC,GAAG,EAAE,aAAa,GACjB,IAAI,CAsCN"}
@@ -1,4 +1,5 @@
1
1
  import { pxToIn, pxToPt } from "../units.js";
2
+ import { convertUnderline, convertStrike } from "../textOptions.js";
2
3
  export function renderProcessArrowNode(node, ctx) {
3
4
  const direction = node.direction ?? "horizontal";
4
5
  const steps = node.steps;
@@ -40,6 +41,10 @@ function renderHorizontalProcessArrow(node, ctx, steps, stepCount, itemWidth, it
40
41
  fontFace: "Noto Sans JP",
41
42
  color: textColor,
42
43
  bold: node.bold ?? false,
44
+ italic: node.italic,
45
+ underline: convertUnderline(node.underline),
46
+ strike: convertStrike(node.strike),
47
+ highlight: node.highlight,
43
48
  align: "center",
44
49
  valign: "middle",
45
50
  });
@@ -68,6 +73,10 @@ function renderVerticalProcessArrow(node, ctx, steps, stepCount, itemWidth, item
68
73
  fontFace: "Noto Sans JP",
69
74
  color: textColor,
70
75
  bold: node.bold ?? false,
76
+ italic: node.italic,
77
+ underline: convertUnderline(node.underline),
78
+ strike: convertStrike(node.strike),
79
+ highlight: node.highlight,
71
80
  align: "center",
72
81
  valign: "middle",
73
82
  });
@@ -1 +1 @@
1
- {"version":3,"file":"shape.d.ts","sourceRoot":"","sources":["../../../src/renderPptx/nodes/shape.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,KAAK,mBAAmB,GAAG,OAAO,CAAC,cAAc,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAEtE,wBAAgB,eAAe,CAC7B,IAAI,EAAE,mBAAmB,EACzB,GAAG,EAAE,aAAa,GACjB,IAAI,CAgDN"}
1
+ {"version":3,"file":"shape.d.ts","sourceRoot":"","sources":["../../../src/renderPptx/nodes/shape.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD,KAAK,mBAAmB,GAAG,OAAO,CAAC,cAAc,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAEtE,wBAAgB,eAAe,CAC7B,IAAI,EAAE,mBAAmB,EACzB,GAAG,EAAE,aAAa,GACjB,IAAI,CAqDN"}
@@ -1,4 +1,5 @@
1
1
  import { pxToIn, pxToPt } from "../units.js";
2
+ import { convertUnderline, convertStrike } from "../textOptions.js";
2
3
  export function renderShapeNode(node, ctx) {
3
4
  const shapeOptions = {
4
5
  x: pxToIn(node.x),
@@ -37,6 +38,11 @@ export function renderShapeNode(node, ctx) {
37
38
  fontSize: pxToPt(node.fontPx ?? 24),
38
39
  fontFace: "Noto Sans JP",
39
40
  color: node.color,
41
+ bold: node.bold,
42
+ italic: node.italic,
43
+ underline: convertUnderline(node.underline),
44
+ strike: convertStrike(node.strike),
45
+ highlight: node.highlight,
40
46
  align: node.alignText ?? "center",
41
47
  valign: "middle",
42
48
  lineSpacingMultiple: 1.3,
@@ -1 +1 @@
1
- {"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../../src/renderPptx/nodes/table.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD,KAAK,mBAAmB,GAAG,OAAO,CAAC,cAAc,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAEtE,wBAAgB,eAAe,CAC7B,IAAI,EAAE,mBAAmB,EACzB,GAAG,EAAE,aAAa,GACjB,IAAI,CA+BN"}
1
+ {"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../../src/renderPptx/nodes/table.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAKjD,KAAK,mBAAmB,GAAG,OAAO,CAAC,cAAc,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAEtE,wBAAgB,eAAe,CAC7B,IAAI,EAAE,mBAAmB,EACzB,GAAG,EAAE,aAAa,GACjB,IAAI,CAmCN"}
@@ -1,11 +1,16 @@
1
1
  import { resolveColumnWidths, resolveRowHeights } from "../../table/utils.js";
2
2
  import { pxToIn, pxToPt } from "../units.js";
3
+ import { convertUnderline, convertStrike } from "../textOptions.js";
3
4
  export function renderTableNode(node, ctx) {
4
5
  const tableRows = node.rows.map((row) => row.cells.map((cell) => {
5
6
  const cellOptions = {
6
7
  fontSize: pxToPt(cell.fontPx ?? 18),
7
8
  color: cell.color,
8
9
  bold: cell.bold,
10
+ italic: cell.italic,
11
+ underline: convertUnderline(cell.underline),
12
+ strike: convertStrike(cell.strike),
13
+ highlight: cell.highlight,
9
14
  align: cell.alignText ?? "left",
10
15
  fill: cell.backgroundColor
11
16
  ? { color: cell.backgroundColor }
@@ -3,7 +3,7 @@ type SlidePx = {
3
3
  w: number;
4
4
  h: number;
5
5
  };
6
- export { createTextOptions } from "./textOptions.ts";
6
+ export { createTextOptions, convertUnderline, convertStrike, } from "./textOptions.ts";
7
7
  export { PX_PER_IN, pxToIn, pxToPt } from "./units.ts";
8
8
  /**
9
9
  * PositionedNode ツリーを PptxGenJS スライドに変換する
@@ -1 +1 @@
1
- {"version":3,"file":"renderPptx.d.ts","sourceRoot":"","sources":["../../src/renderPptx/renderPptx.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EACV,cAAc,EACd,kBAAkB,EAEnB,MAAM,aAAa,CAAC;AAkBrB,KAAK,OAAO,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AA+IvD;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,EAAE,OAAO,EAChB,MAAM,CAAC,EAAE,kBAAkB,+BAgJ5B"}
1
+ {"version":3,"file":"renderPptx.d.ts","sourceRoot":"","sources":["../../src/renderPptx/renderPptx.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EACV,cAAc,EACd,kBAAkB,EAEnB,MAAM,aAAa,CAAC;AAoBrB,KAAK,OAAO,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AACxC,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,GACd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAqJvD;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,EAAE,OAAO,EAChB,MAAM,CAAC,EAAE,kBAAkB,+BAqK5B"}
@@ -6,9 +6,11 @@ const pptxModule = require("pptxgenjs");
6
6
  /* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access */
7
7
  const PptxGenJS = pptxModule.default ?? pptxModule;
8
8
  import { pxToIn, pxToPt } from "./units.js";
9
+ import { convertUnderline, convertStrike } from "./textOptions.js";
10
+ import { getImageData } from "../calcYogaLayout/measureImage.js";
9
11
  import { renderBackgroundAndBorder } from "./utils/backgroundBorder.js";
10
12
  import { renderTextNode, renderImageNode, renderTableNode, renderShapeNode, renderChartNode, renderTimelineNode, renderMatrixNode, renderTreeNode, renderFlowNode, renderProcessArrowNode, renderLineNode, } from "./nodes/index.js";
11
- export { createTextOptions } from "./textOptions.js";
13
+ export { createTextOptions, convertUnderline, convertStrike, } from "./textOptions.js";
12
14
  export { PX_PER_IN, pxToIn, pxToPt } from "./units.js";
13
15
  const DEFAULT_MASTER_NAME = "POM_MASTER";
14
16
  /**
@@ -29,6 +31,10 @@ function convertMasterObject(obj) {
29
31
  fontFace: obj.fontFamily,
30
32
  color: obj.color,
31
33
  bold: obj.bold,
34
+ italic: obj.italic,
35
+ underline: convertUnderline(obj.underline),
36
+ strike: convertStrike(obj.strike),
37
+ highlight: obj.highlight,
32
38
  align: obj.alignText,
33
39
  },
34
40
  },
@@ -105,6 +111,9 @@ function defineSlideMasterFromOptions(pptx, master) {
105
111
  else if ("data" in master.background) {
106
112
  masterProps.background = { data: master.background.data };
107
113
  }
114
+ else if ("image" in master.background) {
115
+ masterProps.background = { path: master.background.image };
116
+ }
108
117
  }
109
118
  // margin の変換 (px -> inches)
110
119
  if (master.margin !== undefined) {
@@ -164,10 +173,25 @@ export function renderPptx(pages, slidePx, master) {
164
173
  // ルートノードの backgroundColor はスライドの background プロパティとして適用
165
174
  // これにより、マスタースライドのオブジェクトを覆い隠さない
166
175
  // line ノードは backgroundColor を持たないためスキップ
176
+ // ただし opacity が指定されている場合は slide.background では透過を表現できないため、
177
+ // renderBackgroundAndBorder で描画する
167
178
  const rootBackgroundColor = data.type !== "line" ? data.backgroundColor : undefined;
168
- if (rootBackgroundColor) {
179
+ const rootHasOpacity = data.type !== "line" && "opacity" in data && data.opacity !== undefined;
180
+ if (rootBackgroundColor && !rootHasOpacity) {
169
181
  slide.background = { color: rootBackgroundColor };
170
182
  }
183
+ // ルートノードの backgroundImage はスライドの background プロパティとして適用
184
+ // backgroundColor と backgroundImage の両方がある場合、backgroundImage が優先
185
+ const rootBackgroundImage = data.type !== "line" ? data.backgroundImage : undefined;
186
+ if (rootBackgroundImage) {
187
+ const cachedData = getImageData(rootBackgroundImage.src);
188
+ if (cachedData) {
189
+ slide.background = { data: cachedData };
190
+ }
191
+ else {
192
+ slide.background = { path: rootBackgroundImage.src };
193
+ }
194
+ }
171
195
  /**
172
196
  * node をスライドにレンダリングする
173
197
  * @param isRoot ルートノードかどうか(ルートノードの background は slide.background で処理済み)
@@ -175,9 +199,11 @@ export function renderPptx(pages, slidePx, master) {
175
199
  function renderNode(node, isRoot = false) {
176
200
  // line ノードは backgroundColor/border を持たないため、background/border の描画をスキップ
177
201
  if (node.type !== "line") {
178
- // ルートノードの backgroundColor は既に slide.background に適用済みなのでスキップ
179
- if (isRoot && rootBackgroundColor) {
180
- // border のみ描画(backgroundColor はスキップ)
202
+ // ルートノードの backgroundColor/backgroundImage は既に slide.background に適用済みなのでスキップ
203
+ // ただし opacity がある場合は slide.background では透過を表現できないため通常描画
204
+ if (isRoot &&
205
+ (rootBackgroundImage || (rootBackgroundColor && !rootHasOpacity))) {
206
+ // border のみ描画(backgroundColor/backgroundImage はスキップ)
181
207
  const { border, borderRadius } = node;
182
208
  const hasBorder = Boolean(border &&
183
209
  (border.color !== undefined ||
@@ -1,7 +1,18 @@
1
- import type { PositionedNode, BulletOptions } from "../types.ts";
1
+ import type { PositionedNode, BulletOptions, Underline, UnderlineStyle } from "../types.ts";
2
2
  type TextNode = Extract<PositionedNode, {
3
3
  type: "text";
4
4
  }>;
5
+ /**
6
+ * underline プロパティを pptxgenjs 形式に変換する
7
+ */
8
+ export declare function convertUnderline(underline: Underline | undefined): {
9
+ style?: UnderlineStyle;
10
+ color?: string;
11
+ } | undefined;
12
+ /**
13
+ * strike プロパティを pptxgenjs 形式に変換する
14
+ */
15
+ export declare function convertStrike(strike: boolean | undefined): "sngStrike" | undefined;
5
16
  type PptxBulletOptions = {
6
17
  type?: "bullet" | "number";
7
18
  indent?: number;
@@ -22,6 +33,13 @@ export declare function createTextOptions(node: TextNode): {
22
33
  lineSpacingMultiple: number;
23
34
  color: string;
24
35
  bold: boolean;
36
+ italic: boolean;
37
+ underline: {
38
+ style?: UnderlineStyle;
39
+ color?: string;
40
+ };
41
+ strike: "sngStrike";
42
+ highlight: string;
25
43
  } | {
26
44
  bullet: boolean | PptxBulletOptions;
27
45
  x: number;
@@ -36,6 +54,13 @@ export declare function createTextOptions(node: TextNode): {
36
54
  lineSpacingMultiple: number;
37
55
  color: string;
38
56
  bold: boolean;
57
+ italic: boolean;
58
+ underline: {
59
+ style?: UnderlineStyle;
60
+ color?: string;
61
+ };
62
+ strike: "sngStrike";
63
+ highlight: string;
39
64
  };
40
65
  export {};
41
66
  //# sourceMappingURL=textOptions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"textOptions.d.ts","sourceRoot":"","sources":["../../src/renderPptx/textOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjE,KAAK,QAAQ,GAAG,OAAO,CAAC,cAAc,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE1D,KAAK,iBAAiB,GAAG;IACvB,IAAI,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IACzC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,OAAO,GAAG,aAAa,GAC9B,iBAAiB,GAAG,OAAO,CAqB7B;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4B/C"}
1
+ {"version":3,"file":"textOptions.d.ts","sourceRoot":"","sources":["../../src/renderPptx/textOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EACb,SAAS,EACT,cAAc,EACf,MAAM,aAAa,CAAC;AAGrB,KAAK,QAAQ,GAAG,OAAO,CAAC,cAAc,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE1D;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,SAAS,GAAG,SAAS,GAC/B;IAAE,KAAK,CAAC,EAAE,cAAc,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAQxD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,OAAO,GAAG,SAAS,GAC1B,WAAW,GAAG,SAAS,CAGzB;AAED,KAAK,iBAAiB,GAAG;IACvB,IAAI,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IACzC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,OAAO,GAAG,aAAa,GAC9B,iBAAiB,GAAG,OAAO,CAqB7B;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,QAAQ;;;;;;;;;;;;;;;gBApDnC,cAAc;gBAAU,MAAM;;;;;;;;;;;;;;;;;;;;gBAA9B,cAAc;gBAAU,MAAM;;;;EAoF1C"}
@@ -1,4 +1,27 @@
1
1
  import { pxToIn, pxToPt } from "./units.js";
2
+ /**
3
+ * underline プロパティを pptxgenjs 形式に変換する
4
+ */
5
+ export function convertUnderline(underline) {
6
+ if (underline === undefined)
7
+ return undefined;
8
+ if (underline === false)
9
+ return undefined;
10
+ if (underline === true)
11
+ return { style: "sng" };
12
+ return {
13
+ style: underline.style,
14
+ color: underline.color,
15
+ };
16
+ }
17
+ /**
18
+ * strike プロパティを pptxgenjs 形式に変換する
19
+ */
20
+ export function convertStrike(strike) {
21
+ if (strike)
22
+ return "sngStrike";
23
+ return undefined;
24
+ }
2
25
  export function createBulletOptions(bullet) {
3
26
  if (typeof bullet === "boolean") {
4
27
  return bullet;
@@ -35,6 +58,10 @@ export function createTextOptions(node) {
35
58
  lineSpacingMultiple,
36
59
  color: node.color,
37
60
  bold: node.bold,
61
+ italic: node.italic,
62
+ underline: convertUnderline(node.underline),
63
+ strike: convertStrike(node.strike),
64
+ highlight: node.highlight,
38
65
  };
39
66
  if (node.bullet !== undefined) {
40
67
  return {
@@ -1,8 +1,10 @@
1
1
  import type { PositionedNode } from "../../types.ts";
2
2
  import type { RenderContext } from "../types.ts";
3
3
  /**
4
- * ノードの背景色とボーダーを描画する
4
+ * ノードの背景色・背景画像・ボーダー・影を描画する
5
5
  * 全ノードタイプで最初に呼び出される共通処理
6
+ *
7
+ * 描画順序: 背景色 → 背景画像 → ボーダー
6
8
  */
7
9
  export declare function renderBackgroundAndBorder(node: PositionedNode, ctx: RenderContext): void;
8
10
  //# sourceMappingURL=backgroundBorder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"backgroundBorder.d.ts","sourceRoot":"","sources":["../../../src/renderPptx/utils/backgroundBorder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,cAAc,EACpB,GAAG,EAAE,aAAa,GACjB,IAAI,CA+CN"}
1
+ {"version":3,"file":"backgroundBorder.d.ts","sourceRoot":"","sources":["../../../src/renderPptx/utils/backgroundBorder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAe,MAAM,gBAAgB,CAAC;AAElE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAcjD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,cAAc,EACpB,GAAG,EAAE,aAAa,GACjB,IAAI,CAyHN"}
@@ -1,28 +1,34 @@
1
+ import { getImageData } from "../../calcYogaLayout/measureImage.js";
1
2
  import { pxToIn, pxToPt } from "../units.js";
3
+ function convertShadow(shadow) {
4
+ return {
5
+ type: shadow.type,
6
+ opacity: shadow.opacity,
7
+ blur: shadow.blur,
8
+ angle: shadow.angle,
9
+ offset: shadow.offset,
10
+ color: shadow.color,
11
+ };
12
+ }
2
13
  /**
3
- * ノードの背景色とボーダーを描画する
14
+ * ノードの背景色・背景画像・ボーダー・影を描画する
4
15
  * 全ノードタイプで最初に呼び出される共通処理
16
+ *
17
+ * 描画順序: 背景色 → 背景画像 → ボーダー
5
18
  */
6
19
  export function renderBackgroundAndBorder(node, ctx) {
7
- const { backgroundColor, border, borderRadius } = node;
20
+ const { backgroundColor, backgroundImage, border, borderRadius } = node;
21
+ const shadow = "shadow" in node ? node.shadow : undefined;
8
22
  const hasBackground = Boolean(backgroundColor);
23
+ const hasBackgroundImage = Boolean(backgroundImage);
9
24
  const hasBorder = Boolean(border &&
10
25
  (border.color !== undefined ||
11
26
  border.width !== undefined ||
12
27
  border.dashType !== undefined));
13
- if (!hasBackground && !hasBorder) {
28
+ const hasShadow = Boolean(shadow);
29
+ if (!hasBackground && !hasBackgroundImage && !hasBorder && !hasShadow) {
14
30
  return;
15
31
  }
16
- const fill = hasBackground
17
- ? { color: backgroundColor }
18
- : { type: "none" };
19
- const line = hasBorder
20
- ? {
21
- color: border?.color ?? "000000",
22
- width: border?.width !== undefined ? pxToPt(border.width) : undefined,
23
- dashType: border?.dashType,
24
- }
25
- : { type: "none" };
26
32
  // borderRadius がある場合は roundRect を使用し、rectRadius を計算
27
33
  const shapeType = borderRadius
28
34
  ? ctx.pptx.ShapeType.roundRect
@@ -31,14 +37,88 @@ export function renderBackgroundAndBorder(node, ctx) {
31
37
  const rectRadius = borderRadius
32
38
  ? Math.min((borderRadius / Math.min(node.w, node.h)) * 2, 1)
33
39
  : undefined;
34
- const shapeOptions = {
35
- x: pxToIn(node.x),
36
- y: pxToIn(node.y),
37
- w: pxToIn(node.w),
38
- h: pxToIn(node.h),
39
- fill,
40
- line,
41
- rectRadius,
42
- };
43
- ctx.slide.addShape(shapeType, shapeOptions);
40
+ // backgroundImage がない場合は従来通り1回の addShape で処理
41
+ if (!hasBackgroundImage) {
42
+ const fill = hasBackground
43
+ ? {
44
+ color: backgroundColor,
45
+ transparency: node.opacity !== undefined ? (1 - node.opacity) * 100 : undefined,
46
+ }
47
+ : { type: "none" };
48
+ const line = hasBorder
49
+ ? {
50
+ color: border?.color ?? "000000",
51
+ width: border?.width !== undefined ? pxToPt(border.width) : undefined,
52
+ dashType: border?.dashType,
53
+ }
54
+ : { type: "none" };
55
+ ctx.slide.addShape(shapeType, {
56
+ x: pxToIn(node.x),
57
+ y: pxToIn(node.y),
58
+ w: pxToIn(node.w),
59
+ h: pxToIn(node.h),
60
+ fill,
61
+ line,
62
+ rectRadius,
63
+ shadow: shadow ? convertShadow(shadow) : undefined,
64
+ });
65
+ return;
66
+ }
67
+ // backgroundImage がある場合は分割描画: 背景色 → 背景画像 → ボーダー
68
+ // 1. 背景色
69
+ if (hasBackground) {
70
+ ctx.slide.addShape(shapeType, {
71
+ x: pxToIn(node.x),
72
+ y: pxToIn(node.y),
73
+ w: pxToIn(node.w),
74
+ h: pxToIn(node.h),
75
+ fill: {
76
+ color: backgroundColor,
77
+ transparency: node.opacity !== undefined ? (1 - node.opacity) * 100 : undefined,
78
+ },
79
+ line: { type: "none" },
80
+ rectRadius,
81
+ });
82
+ }
83
+ // 2. 背景画像
84
+ if (backgroundImage) {
85
+ const sizing = backgroundImage.sizing ?? "cover";
86
+ const imageOptions = {
87
+ x: pxToIn(node.x),
88
+ y: pxToIn(node.y),
89
+ w: pxToIn(node.w),
90
+ h: pxToIn(node.h),
91
+ sizing: {
92
+ type: sizing,
93
+ w: pxToIn(node.w),
94
+ h: pxToIn(node.h),
95
+ },
96
+ };
97
+ const cachedData = getImageData(backgroundImage.src);
98
+ if (cachedData) {
99
+ ctx.slide.addImage({ ...imageOptions, data: cachedData });
100
+ }
101
+ else {
102
+ ctx.slide.addImage({ ...imageOptions, path: backgroundImage.src });
103
+ }
104
+ }
105
+ // 3. ボーダー
106
+ if (hasBorder || hasShadow) {
107
+ ctx.slide.addShape(shapeType, {
108
+ x: pxToIn(node.x),
109
+ y: pxToIn(node.y),
110
+ w: pxToIn(node.w),
111
+ h: pxToIn(node.h),
112
+ fill: { type: "none" },
113
+ line: hasBorder
114
+ ? {
115
+ color: border?.color ?? "000000",
116
+ width: border?.width !== undefined ? pxToPt(border.width) : undefined,
117
+ dashType: border?.dashType,
118
+ }
119
+ : { type: "none" },
120
+ rectRadius,
121
+ shadow: shadow ? convertShadow(shadow) : undefined,
122
+ });
123
+ }
44
124
  }
@@ -1,3 +1,4 @@
1
+ import type { Underline } from "../../types.ts";
1
2
  import type { RenderContext } from "../types.ts";
2
3
  export type SimpleTextOptions = {
3
4
  x: number;
@@ -9,6 +10,10 @@ export type SimpleTextOptions = {
9
10
  fontFace?: string;
10
11
  color?: string;
11
12
  bold?: boolean;
13
+ italic?: boolean;
14
+ underline?: Underline;
15
+ strike?: boolean;
16
+ highlight?: string;
12
17
  align?: "left" | "center" | "right";
13
18
  valign?: "top" | "middle" | "bottom";
14
19
  };
@@ -1 +1 @@
1
- {"version":3,"file":"textDrawing.d.ts","sourceRoot":"","sources":["../../../src/renderPptx/utils/textDrawing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACpC,MAAM,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;CACtC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,iBAAiB,GACzB,IAAI,CA2BN"}
1
+ {"version":3,"file":"textDrawing.d.ts","sourceRoot":"","sources":["../../../src/renderPptx/utils/textDrawing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACpC,MAAM,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;CACtC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,iBAAiB,GACzB,IAAI,CAmCN"}
@@ -1,10 +1,11 @@
1
1
  import { pxToIn, pxToPt } from "../units.js";
2
+ import { convertUnderline, convertStrike } from "../textOptions.js";
2
3
  /**
3
4
  * シンプルなテキストを描画する
4
5
  * timeline, matrix, tree, flow などの複雑ノードで使用
5
6
  */
6
7
  export function drawSimpleText(ctx, options) {
7
- const { x, y, w, h, text, fontSize = 12, fontFace = "Noto Sans JP", color = "000000", bold, align = "left", valign = "top", } = options;
8
+ const { x, y, w, h, text, fontSize = 12, fontFace = "Noto Sans JP", color = "000000", bold, italic, underline, strike, highlight, align = "left", valign = "top", } = options;
8
9
  ctx.slide.addText(text, {
9
10
  x: pxToIn(x),
10
11
  y: pxToIn(y),
@@ -14,6 +15,10 @@ export function drawSimpleText(ctx, options) {
14
15
  fontFace,
15
16
  color,
16
17
  bold,
18
+ italic,
19
+ underline: convertUnderline(underline),
20
+ strike: convertStrike(strike),
21
+ highlight,
17
22
  align,
18
23
  valign,
19
24
  });