@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.
- package/dist/buildContext.js +2 -6
- package/dist/buildContext.js.map +1 -1
- package/dist/buildPptx.d.ts +2 -1
- package/dist/buildPptx.d.ts.map +1 -1
- package/dist/buildPptx.js +4 -9
- package/dist/buildPptx.js.map +1 -1
- package/dist/calcYogaLayout/calcYogaLayout.js +1 -1
- package/dist/calcYogaLayout/calcYogaLayout.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/registry/definitions/icon.js +1 -1
- package/dist/registry/definitions/list.js.map +1 -1
- package/dist/renderPptx/nodes/chart.js +172 -47
- package/dist/renderPptx/nodes/chart.js.map +1 -1
- package/dist/renderPptx/nodes/flow.js +98 -90
- package/dist/renderPptx/nodes/flow.js.map +1 -1
- package/dist/renderPptx/nodes/icon.js +36 -24
- package/dist/renderPptx/nodes/icon.js.map +1 -1
- package/dist/renderPptx/nodes/image.js +5 -22
- package/dist/renderPptx/nodes/image.js.map +1 -1
- package/dist/renderPptx/nodes/list.js +94 -111
- package/dist/renderPptx/nodes/list.js.map +1 -1
- package/dist/renderPptx/nodes/matrix.js +95 -70
- package/dist/renderPptx/nodes/matrix.js.map +1 -1
- package/dist/renderPptx/nodes/processArrow.js +74 -35
- package/dist/renderPptx/nodes/processArrow.js.map +1 -1
- package/dist/renderPptx/nodes/pyramid.js +37 -16
- package/dist/renderPptx/nodes/pyramid.js.map +1 -1
- package/dist/renderPptx/nodes/shape.js +66 -37
- package/dist/renderPptx/nodes/shape.js.map +1 -1
- package/dist/renderPptx/nodes/svg.js +2 -5
- package/dist/renderPptx/nodes/svg.js.map +1 -1
- package/dist/renderPptx/nodes/table.js +89 -59
- package/dist/renderPptx/nodes/table.js.map +1 -1
- package/dist/renderPptx/nodes/text.js +1 -18
- package/dist/renderPptx/nodes/text.js.map +1 -1
- package/dist/renderPptx/nodes/timeline.js +114 -74
- package/dist/renderPptx/nodes/timeline.js.map +1 -1
- package/dist/renderPptx/nodes/tree.js +81 -79
- package/dist/renderPptx/nodes/tree.js.map +1 -1
- package/dist/renderPptx/pptxAuthoring.js +381 -0
- package/dist/renderPptx/pptxAuthoring.js.map +1 -0
- package/dist/renderPptx/renderPptx.js +158 -128
- package/dist/renderPptx/renderPptx.js.map +1 -1
- package/dist/renderPptx/textOptions.js +7 -8
- package/dist/renderPptx/textOptions.js.map +1 -1
- package/dist/renderPptx/units.js +3 -3
- package/dist/renderPptx/units.js.map +1 -1
- package/dist/renderPptx/utils/backgroundBorder.js +70 -48
- package/dist/renderPptx/utils/backgroundBorder.js.map +1 -1
- package/dist/renderPptx/utils/contentArea.js +1 -1
- package/dist/renderPptx/utils/contentArea.js.map +1 -1
- package/dist/renderPptx/utils/glimpsePicture.js +111 -0
- package/dist/renderPptx/utils/glimpsePicture.js.map +1 -0
- package/dist/renderPptx/utils/glimpseShape.js +71 -0
- package/dist/renderPptx/utils/glimpseShape.js.map +1 -0
- package/dist/renderPptx/utils/glimpseTextBox.js +107 -0
- package/dist/renderPptx/utils/glimpseTextBox.js.map +1 -0
- package/dist/renderPptx/utils/straightLine.js +33 -15
- package/dist/renderPptx/utils/straightLine.js.map +1 -1
- package/dist/renderPptx/utils/visualStyle.js +3 -56
- package/dist/renderPptx/utils/visualStyle.js.map +1 -1
- package/dist/renderPptx/writablePptx.d.ts +23 -0
- package/dist/renderPptx/writablePptx.d.ts.map +1 -0
- package/dist/renderPptx/writablePptx.js +74 -0
- package/dist/renderPptx/writablePptx.js.map +1 -0
- package/dist/shared/measureImage.js.map +1 -1
- package/package.json +4 -5
- package/dist/renderPptx/glimpseTextBoxes.js +0 -347
- package/dist/renderPptx/glimpseTextBoxes.js.map +0 -1
- package/dist/renderPptx/glowEffects.js +0 -157
- package/dist/renderPptx/glowEffects.js.map +0 -1
- package/dist/renderPptx/gradientFills.js +0 -154
- package/dist/renderPptx/gradientFills.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getImageData } from "../../shared/measureImage.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { addGlimpsePicture, imageBytesFromSource } from "./glimpsePicture.js";
|
|
3
|
+
import { addGlimpseShape, backgroundShapeFill, createShapeBoundsInput, noShapeOutline, noneShapeFill, shapeOutline } from "./glimpseShape.js";
|
|
4
|
+
import { BORDER_SIDES, hasVisibleBorder, resolvePerSideBorders, resolveRectRadius } from "./visualStyle.js";
|
|
5
5
|
//#region src/renderPptx/utils/backgroundBorder.ts
|
|
6
6
|
/**
|
|
7
7
|
* ノードの背景色・背景画像・ボーダー・影を描画する
|
|
@@ -11,62 +11,74 @@ import { registerBackgroundGradient } from "../gradientFills.js";
|
|
|
11
11
|
*/
|
|
12
12
|
function renderBackgroundAndBorder(node, ctx) {
|
|
13
13
|
const { backgroundColor, backgroundGradient, backgroundImage, border, borderRadius, shadow } = node;
|
|
14
|
-
const gradientMarker = backgroundGradient ? registerBackgroundGradient(backgroundGradient, node.opacity, ctx.buildContext.gradientFills) : void 0;
|
|
15
14
|
const perSideBorders = resolveEffectivePerSideBorders(node, ctx);
|
|
16
|
-
const hasBackground = Boolean(backgroundColor) || Boolean(
|
|
15
|
+
const hasBackground = Boolean(backgroundColor) || Boolean(backgroundGradient);
|
|
17
16
|
const hasBackgroundImage = Boolean(backgroundImage);
|
|
18
17
|
const hasUniformBorder = !perSideBorders && hasVisibleBorder(border);
|
|
19
18
|
const hasShadow = Boolean(shadow);
|
|
20
19
|
if (!hasBackground && !hasBackgroundImage && !hasUniformBorder && !perSideBorders && !hasShadow) return;
|
|
21
|
-
const shapeType = borderRadius ?
|
|
20
|
+
const shapeType = borderRadius ? "roundRect" : "rect";
|
|
22
21
|
const rectRadius = resolveRectRadius(borderRadius, node.w, node.h);
|
|
23
22
|
if (!hasBackgroundImage) {
|
|
24
23
|
if (hasBackground || hasUniformBorder || hasShadow) {
|
|
25
|
-
const fill = hasBackground ?
|
|
26
|
-
const line = hasUniformBorder ?
|
|
27
|
-
ctx
|
|
28
|
-
|
|
24
|
+
const fill = hasBackground ? backgroundShapeFill(backgroundColor, backgroundGradient) : noneShapeFill();
|
|
25
|
+
const line = hasUniformBorder ? shapeOutline(border, "000000") : noShapeOutline();
|
|
26
|
+
addGlimpseShape(ctx, {
|
|
27
|
+
geometry: {
|
|
28
|
+
kind: "preset",
|
|
29
|
+
preset: shapeType
|
|
30
|
+
},
|
|
31
|
+
...createShapeBoundsInput(node),
|
|
29
32
|
fill,
|
|
30
|
-
line
|
|
33
|
+
outline: line
|
|
34
|
+
}, node, {
|
|
35
|
+
fillColor: backgroundColor,
|
|
36
|
+
fillOpacity: node.opacity,
|
|
37
|
+
backgroundGradient,
|
|
38
|
+
shadow,
|
|
31
39
|
rectRadius,
|
|
32
|
-
|
|
40
|
+
dashType: border?.dashType
|
|
33
41
|
});
|
|
34
42
|
}
|
|
35
43
|
renderPerSideBorderLines(node, perSideBorders, ctx);
|
|
36
44
|
return;
|
|
37
45
|
}
|
|
38
|
-
if (hasBackground) ctx
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
if (hasBackground) addGlimpseShape(ctx, {
|
|
47
|
+
geometry: {
|
|
48
|
+
kind: "preset",
|
|
49
|
+
preset: shapeType
|
|
50
|
+
},
|
|
51
|
+
...createShapeBoundsInput(node),
|
|
52
|
+
fill: backgroundShapeFill(backgroundColor, backgroundGradient),
|
|
53
|
+
outline: noShapeOutline()
|
|
54
|
+
}, node, {
|
|
55
|
+
fillColor: backgroundColor,
|
|
56
|
+
fillOpacity: node.opacity,
|
|
57
|
+
backgroundGradient,
|
|
58
|
+
rectRadius,
|
|
59
|
+
dashType: border?.dashType
|
|
43
60
|
});
|
|
44
61
|
if (backgroundImage) {
|
|
45
62
|
const sizing = backgroundImage.sizing ?? "cover";
|
|
46
|
-
const imageOptions = {
|
|
47
|
-
...rectPxToIn(node),
|
|
48
|
-
sizing: {
|
|
49
|
-
type: sizing,
|
|
50
|
-
w: pxToIn(node.w),
|
|
51
|
-
h: pxToIn(node.h)
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
63
|
const cachedData = getImageData(backgroundImage.src, ctx.buildContext.imageDataCache);
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
...imageOptions,
|
|
61
|
-
path: backgroundImage.src
|
|
62
|
-
});
|
|
64
|
+
addGlimpsePicture(ctx, node, imageBytesFromSource(backgroundImage.src, cachedData), { sizing: {
|
|
65
|
+
type: sizing,
|
|
66
|
+
w: node.w,
|
|
67
|
+
h: node.h
|
|
68
|
+
} });
|
|
63
69
|
}
|
|
64
|
-
if (hasUniformBorder || hasShadow) ctx
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
70
|
+
if (hasUniformBorder || hasShadow) addGlimpseShape(ctx, {
|
|
71
|
+
geometry: {
|
|
72
|
+
kind: "preset",
|
|
73
|
+
preset: shapeType
|
|
74
|
+
},
|
|
75
|
+
...createShapeBoundsInput(node),
|
|
76
|
+
fill: noneShapeFill(),
|
|
77
|
+
outline: hasUniformBorder ? shapeOutline(border, "000000") : noShapeOutline()
|
|
78
|
+
}, node, {
|
|
79
|
+
shadow,
|
|
68
80
|
rectRadius,
|
|
69
|
-
|
|
81
|
+
dashType: border?.dashType
|
|
70
82
|
});
|
|
71
83
|
renderPerSideBorderLines(node, perSideBorders, ctx);
|
|
72
84
|
}
|
|
@@ -96,12 +108,17 @@ function renderBorderOnly(node, ctx) {
|
|
|
96
108
|
return;
|
|
97
109
|
}
|
|
98
110
|
if (!hasVisibleBorder(border)) return;
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
111
|
+
addGlimpseShape(ctx, {
|
|
112
|
+
geometry: {
|
|
113
|
+
kind: "preset",
|
|
114
|
+
preset: borderRadius ? "roundRect" : "rect"
|
|
115
|
+
},
|
|
116
|
+
...createShapeBoundsInput(node),
|
|
117
|
+
fill: noneShapeFill(),
|
|
118
|
+
outline: shapeOutline(border, "000000")
|
|
119
|
+
}, node, {
|
|
120
|
+
rectRadius: resolveRectRadius(borderRadius, node.w, node.h),
|
|
121
|
+
dashType: border.dashType
|
|
105
122
|
});
|
|
106
123
|
}
|
|
107
124
|
/**
|
|
@@ -140,10 +157,15 @@ function renderPerSideBorderLines(node, perSideBorders, ctx) {
|
|
|
140
157
|
for (const side of BORDER_SIDES) {
|
|
141
158
|
const style = perSideBorders[side];
|
|
142
159
|
if (!style) continue;
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
160
|
+
addGlimpseShape(ctx, {
|
|
161
|
+
geometry: {
|
|
162
|
+
kind: "preset",
|
|
163
|
+
preset: "line"
|
|
164
|
+
},
|
|
165
|
+
...createShapeBoundsInput(edges[side]),
|
|
166
|
+
fill: noneShapeFill(),
|
|
167
|
+
outline: shapeOutline(style, "000000")
|
|
168
|
+
}, edges[side], { dashType: style.dashType });
|
|
147
169
|
}
|
|
148
170
|
}
|
|
149
171
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backgroundBorder.js","names":[],"sources":["../../../src/renderPptx/utils/backgroundBorder.ts"],"sourcesContent":["import type { PositionedNode } from \"../../types.ts\";\nimport { getImageData } from \"../../shared/measureImage.ts\";\nimport {
|
|
1
|
+
{"version":3,"file":"backgroundBorder.js","names":[],"sources":["../../../src/renderPptx/utils/backgroundBorder.ts"],"sourcesContent":["import type { PositionedNode } from \"../../types.ts\";\nimport { getImageData } from \"../../shared/measureImage.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport {\n BORDER_SIDES,\n hasVisibleBorder,\n resolvePerSideBorders,\n resolveRectRadius,\n type PerSideBorders,\n} from \"./visualStyle.ts\";\nimport { addGlimpsePicture, imageBytesFromSource } from \"./glimpsePicture.ts\";\nimport {\n addGlimpseShape,\n backgroundShapeFill,\n createShapeBoundsInput,\n noShapeOutline,\n noneShapeFill,\n shapeOutline,\n} from \"./glimpseShape.ts\";\n\n/**\n * ノードの背景色・背景画像・ボーダー・影を描画する\n * 全ノードタイプで最初に呼び出される共通処理\n *\n * 描画順序: 背景色 → 背景画像 → ボーダー\n */\nexport function renderBackgroundAndBorder(\n node: PositionedNode,\n ctx: RenderContext,\n): void {\n const {\n backgroundColor,\n backgroundGradient,\n backgroundImage,\n border,\n borderRadius,\n shadow,\n } = node;\n\n const perSideBorders = resolveEffectivePerSideBorders(node, ctx);\n\n const hasBackground = Boolean(backgroundColor) || Boolean(backgroundGradient);\n const hasBackgroundImage = Boolean(backgroundImage);\n // 辺ごとの指定がある場合、一律 border は各辺へのマージで反映済みのため\n // shape の line としては描画しない\n const hasUniformBorder = !perSideBorders && hasVisibleBorder(border);\n const hasShadow = Boolean(shadow);\n\n if (\n !hasBackground &&\n !hasBackgroundImage &&\n !hasUniformBorder &&\n !perSideBorders &&\n !hasShadow\n ) {\n return;\n }\n\n // borderRadius がある場合は roundRect を使用し、rectRadius を計算\n const shapeType = borderRadius ? \"roundRect\" : \"rect\";\n const rectRadius = resolveRectRadius(borderRadius, node.w, node.h);\n\n // backgroundImage がない場合は従来通り1回の addShape で処理\n if (!hasBackgroundImage) {\n if (hasBackground || hasUniformBorder || hasShadow) {\n const fill = hasBackground\n ? backgroundShapeFill(backgroundColor, backgroundGradient)\n : noneShapeFill();\n\n const line = hasUniformBorder\n ? shapeOutline(border, \"000000\")\n : noShapeOutline();\n\n addGlimpseShape(\n ctx,\n {\n geometry: { kind: \"preset\", preset: shapeType },\n ...createShapeBoundsInput(node),\n fill,\n outline: line,\n },\n node,\n {\n fillColor: backgroundColor,\n fillOpacity: node.opacity,\n backgroundGradient,\n shadow,\n rectRadius,\n dashType: border?.dashType,\n },\n );\n }\n\n renderPerSideBorderLines(node, perSideBorders, ctx);\n return;\n }\n\n // backgroundImage がある場合は分割描画: 背景色 → 背景画像 → ボーダー\n\n // 1. 背景色\n if (hasBackground) {\n addGlimpseShape(\n ctx,\n {\n geometry: { kind: \"preset\", preset: shapeType },\n ...createShapeBoundsInput(node),\n fill: backgroundShapeFill(backgroundColor, backgroundGradient),\n outline: noShapeOutline(),\n },\n node,\n {\n fillColor: backgroundColor,\n fillOpacity: node.opacity,\n backgroundGradient,\n rectRadius,\n dashType: border?.dashType,\n },\n );\n }\n\n // 2. 背景画像\n if (backgroundImage) {\n const sizing = backgroundImage.sizing ?? \"cover\";\n const cachedData = getImageData(\n backgroundImage.src,\n ctx.buildContext.imageDataCache,\n );\n addGlimpsePicture(\n ctx,\n node,\n imageBytesFromSource(backgroundImage.src, cachedData),\n {\n sizing: { type: sizing, w: node.w, h: node.h },\n },\n );\n }\n\n // 3. ボーダー\n if (hasUniformBorder || hasShadow) {\n addGlimpseShape(\n ctx,\n {\n geometry: { kind: \"preset\", preset: shapeType },\n ...createShapeBoundsInput(node),\n fill: noneShapeFill(),\n outline: hasUniformBorder\n ? shapeOutline(border, \"000000\")\n : noShapeOutline(),\n },\n node,\n {\n shadow,\n rectRadius,\n dashType: border?.dashType,\n },\n );\n }\n\n renderPerSideBorderLines(node, perSideBorders, ctx);\n}\n\n/**\n * 辺ごとの border 指定を解決する。borderRadius との併用は角の接続処理が\n * 複雑になるためサポートせず、警告を発して 4 辺一律の border に\n * フォールバックする\n */\nfunction resolveEffectivePerSideBorders(\n node: PositionedNode,\n ctx: RenderContext,\n): PerSideBorders | undefined {\n const perSideBorders = resolvePerSideBorders(node);\n if (perSideBorders && node.borderRadius !== undefined) {\n ctx.buildContext.diagnostics.add(\n \"PER_SIDE_BORDER_WITH_RADIUS\",\n 'borderTop / borderRight / borderBottom / borderLeft cannot be combined with borderRadius — falling back to the uniform \"border\" style',\n );\n return undefined;\n }\n return perSideBorders;\n}\n\n/**\n * ノードの border のみを描画する (背景・影は描画しない)。\n * ルートノードの backgroundColor / backgroundImage を slide.background に\n * 適用した後、border だけを個別に描画するパス用\n */\nexport function renderBorderOnly(\n node: PositionedNode,\n ctx: RenderContext,\n): void {\n const { border, borderRadius } = node;\n\n const perSideBorders = resolveEffectivePerSideBorders(node, ctx);\n if (perSideBorders) {\n renderPerSideBorderLines(node, perSideBorders, ctx);\n return;\n }\n\n if (!hasVisibleBorder(border)) return;\n\n const shapeType = borderRadius ? \"roundRect\" : \"rect\";\n\n addGlimpseShape(\n ctx,\n {\n geometry: { kind: \"preset\", preset: shapeType },\n ...createShapeBoundsInput(node),\n fill: noneShapeFill(),\n outline: shapeOutline(border, \"000000\"),\n },\n node,\n {\n rectRadius: resolveRectRadius(borderRadius, node.w, node.h),\n dashType: border.dashType,\n },\n );\n}\n\n/**\n * 辺ごとの border をノードの各辺に沿った line shape として描画する。\n * shape の line オプション (4 辺一律) では表現できないため、辺ごとに\n * 独立した line shape を追加する\n */\nfunction renderPerSideBorderLines(\n node: PositionedNode,\n perSideBorders: PerSideBorders | undefined,\n ctx: RenderContext,\n): void {\n if (!perSideBorders) return;\n\n const edges = {\n top: { x: node.x, y: node.y, w: node.w, h: 0 },\n right: { x: node.x + node.w, y: node.y, w: 0, h: node.h },\n bottom: { x: node.x, y: node.y + node.h, w: node.w, h: 0 },\n left: { x: node.x, y: node.y, w: 0, h: node.h },\n } as const;\n\n for (const side of BORDER_SIDES) {\n const style = perSideBorders[side];\n if (!style) continue;\n\n addGlimpseShape(\n ctx,\n {\n geometry: { kind: \"preset\", preset: \"line\" },\n ...createShapeBoundsInput(edges[side]),\n fill: noneShapeFill(),\n outline: shapeOutline(style, \"000000\"),\n },\n edges[side],\n {\n dashType: style.dashType,\n },\n );\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contentArea.js","names":[],"sources":["../../../src/renderPptx/utils/contentArea.ts"],"sourcesContent":["import {\n resolveBoxSpacing,\n type BoxSpacingInput,\n} from \"../../shared/boxSpacing.ts\";\nimport { rectPxToIn } from \"../units.ts\";\n\ninterface ContentArea {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\n/**\n * ノードの padding を考慮したコンテンツ描画領域を計算する。\n * background/border はノード全体の領域 (node.x/y/w/h) に描画し、\n * コンテンツはこの関数で返される領域に描画する。\n */\nexport function getContentArea(node: {\n x: number;\n y: number;\n w: number;\n h: number;\n padding?: BoxSpacingInput;\n}): ContentArea {\n if (node.padding === undefined) {\n return { x: node.x, y: node.y, w: node.w, h: node.h };\n }\n\n const { top, right, bottom, left } = resolveBoxSpacing(node.padding);\n\n return {\n x: node.x + left,\n y: node.y + top,\n w: Math.max(0, node.w - left - right),\n h: Math.max(0, node.h - top - bottom),\n };\n}\n\n/**\n *
|
|
1
|
+
{"version":3,"file":"contentArea.js","names":[],"sources":["../../../src/renderPptx/utils/contentArea.ts"],"sourcesContent":["import {\n resolveBoxSpacing,\n type BoxSpacingInput,\n} from \"../../shared/boxSpacing.ts\";\nimport { rectPxToIn } from \"../units.ts\";\n\ninterface ContentArea {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\n/**\n * ノードの padding を考慮したコンテンツ描画領域を計算する。\n * background/border はノード全体の領域 (node.x/y/w/h) に描画し、\n * コンテンツはこの関数で返される領域に描画する。\n */\nexport function getContentArea(node: {\n x: number;\n y: number;\n w: number;\n h: number;\n padding?: BoxSpacingInput;\n}): ContentArea {\n if (node.padding === undefined) {\n return { x: node.x, y: node.y, w: node.w, h: node.h };\n }\n\n const { top, right, bottom, left } = resolveBoxSpacing(node.padding);\n\n return {\n x: node.x + left,\n y: node.y + top,\n w: Math.max(0, node.w - left - right),\n h: Math.max(0, node.h - top - bottom),\n };\n}\n\n/**\n * コンテンツ描画領域を互換用の位置オプション (inch 単位の x/y/w/h)\n * として返す。コンテンツを領域いっぱいに描画する renderer はこれを\n * addShape / addText 等のオプションへ spread するだけでよい。\n */\nexport function getContentAreaIn(\n node: Parameters<typeof getContentArea>[0],\n): ReturnType<typeof rectPxToIn> {\n return rectPxToIn(getContentArea(node));\n}\n\n/**\n * ノードの x/y/w/h を指定領域 (通常はコンテンツ領域) で置き換えた\n * 仮想ノードを返す。padding を解決済みの領域を基準に下位の描画関数へ\n * ノードを渡すために使う。\n */\nexport function withContentBounds<\n T extends { x: number; y: number; w: number; h: number },\n>(node: T, bounds: ContentArea): T {\n return { ...node, x: bounds.x, y: bounds.y, w: bounds.w, h: bounds.h };\n}\n"],"mappings":";;;;;;;;AAkBA,SAAgB,eAAe,MAMf;CACd,IAAI,KAAK,YAAY,KAAA,GACnB,OAAO;EAAE,GAAG,KAAK;EAAG,GAAG,KAAK;EAAG,GAAG,KAAK;EAAG,GAAG,KAAK;CAAE;CAGtD,MAAM,EAAE,KAAK,OAAO,QAAQ,SAAS,kBAAkB,KAAK,OAAO;CAEnE,OAAO;EACL,GAAG,KAAK,IAAI;EACZ,GAAG,KAAK,IAAI;EACZ,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,OAAO,KAAK;EACpC,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,MAAM,MAAM;CACtC;AACF;;;;;;AAOA,SAAgB,iBACd,MAC+B;CAC/B,OAAO,WAAW,eAAe,IAAI,CAAC;AACxC;;;;;;AAOA,SAAgB,kBAEd,MAAS,QAAwB;CACjC,OAAO;EAAE,GAAG;EAAM,GAAG,OAAO;EAAG,GAAG,OAAO;EAAG,GAAG,OAAO;EAAG,GAAG,OAAO;CAAE;AACvE"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { pxToEmu } from "../units.js";
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import { asEmu, asOoxmlAngle, asOoxmlPercent } from "@pptx-glimpse/document";
|
|
4
|
+
//#region src/renderPptx/utils/glimpsePicture.ts
|
|
5
|
+
const FALLBACK_PNG = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=";
|
|
6
|
+
function dataToBytes(data) {
|
|
7
|
+
const base64 = data.includes(",") ? data.split(",").at(-1) : data;
|
|
8
|
+
return new Uint8Array(Buffer.from(base64 ?? "", "base64"));
|
|
9
|
+
}
|
|
10
|
+
function isPngOrJpeg(bytes) {
|
|
11
|
+
const isPng = bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71;
|
|
12
|
+
const isJpeg = bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255;
|
|
13
|
+
return isPng || isJpeg;
|
|
14
|
+
}
|
|
15
|
+
function supportedOrFallback(bytes) {
|
|
16
|
+
return isPngOrJpeg(bytes) ? bytes : dataToBytes(FALLBACK_PNG);
|
|
17
|
+
}
|
|
18
|
+
function imageBytesFromSource(src, data) {
|
|
19
|
+
if (data) return supportedOrFallback(dataToBytes(data));
|
|
20
|
+
if (src.startsWith("data:")) return supportedOrFallback(dataToBytes(src));
|
|
21
|
+
if (src.startsWith("http://") || src.startsWith("https://")) return dataToBytes(FALLBACK_PNG);
|
|
22
|
+
try {
|
|
23
|
+
return supportedOrFallback(new Uint8Array(fs.readFileSync(src)));
|
|
24
|
+
} catch {
|
|
25
|
+
return dataToBytes(FALLBACK_PNG);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function positiveEmu(valuePx) {
|
|
29
|
+
return asEmu(Math.max(1, Math.round(pxToEmu(valuePx))));
|
|
30
|
+
}
|
|
31
|
+
function createPictureRotationInput(rotate) {
|
|
32
|
+
return rotate !== void 0 ? asOoxmlAngle(Math.round(rotate * 6e4)) : void 0;
|
|
33
|
+
}
|
|
34
|
+
function pct(value) {
|
|
35
|
+
return asOoxmlPercent(Math.round(value));
|
|
36
|
+
}
|
|
37
|
+
function createSizingCrop(sizing, content) {
|
|
38
|
+
const box = {
|
|
39
|
+
x: sizing.x ?? 0,
|
|
40
|
+
y: sizing.y ?? 0,
|
|
41
|
+
w: sizing.w ?? content.w,
|
|
42
|
+
h: sizing.h ?? content.h
|
|
43
|
+
};
|
|
44
|
+
const img = {
|
|
45
|
+
w: content.w,
|
|
46
|
+
h: content.h
|
|
47
|
+
};
|
|
48
|
+
if (sizing.type === "crop") {
|
|
49
|
+
const cropBase = {
|
|
50
|
+
w: content.w,
|
|
51
|
+
h: content.h
|
|
52
|
+
};
|
|
53
|
+
return {
|
|
54
|
+
bounds: {
|
|
55
|
+
...content,
|
|
56
|
+
w: box.w,
|
|
57
|
+
h: box.h
|
|
58
|
+
},
|
|
59
|
+
crop: {
|
|
60
|
+
left: pct(1e5 * (box.x / cropBase.w)),
|
|
61
|
+
right: pct(1e5 * ((cropBase.w - (box.x + box.w)) / cropBase.w)),
|
|
62
|
+
top: pct(1e5 * (box.y / cropBase.h)),
|
|
63
|
+
bottom: pct(1e5 * ((cropBase.h - (box.y + box.h)) / cropBase.h))
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const imgRatio = img.h / img.w;
|
|
68
|
+
const boxRatio = box.h / box.w;
|
|
69
|
+
const isCoverBoxBased = boxRatio > imgRatio;
|
|
70
|
+
const isContainWidthBased = boxRatio > imgRatio;
|
|
71
|
+
const width = sizing.type === "cover" ? isCoverBoxBased ? box.h / imgRatio : box.w : isContainWidthBased ? box.w : box.h / imgRatio;
|
|
72
|
+
const height = sizing.type === "cover" ? isCoverBoxBased ? box.h : box.w * imgRatio : isContainWidthBased ? box.w * imgRatio : box.h;
|
|
73
|
+
const horizontal = 1e5 * .5 * (1 - box.w / width);
|
|
74
|
+
const vertical = 1e5 * .5 * (1 - box.h / height);
|
|
75
|
+
return {
|
|
76
|
+
bounds: {
|
|
77
|
+
...content,
|
|
78
|
+
w: box.w,
|
|
79
|
+
h: box.h
|
|
80
|
+
},
|
|
81
|
+
crop: {
|
|
82
|
+
left: pct(horizontal),
|
|
83
|
+
right: pct(horizontal),
|
|
84
|
+
top: pct(vertical),
|
|
85
|
+
bottom: pct(vertical)
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function addGlimpsePicture(ctx, content, bytes, options) {
|
|
90
|
+
const sizingResult = options?.sizing ? createSizingCrop(options.sizing, content) : {
|
|
91
|
+
bounds: content,
|
|
92
|
+
crop: void 0
|
|
93
|
+
};
|
|
94
|
+
const input = {
|
|
95
|
+
bytes,
|
|
96
|
+
offsetX: asEmu(Math.round(pxToEmu(content.x))),
|
|
97
|
+
offsetY: asEmu(Math.round(pxToEmu(content.y))),
|
|
98
|
+
width: positiveEmu(sizingResult.bounds.w),
|
|
99
|
+
height: positiveEmu(sizingResult.bounds.h),
|
|
100
|
+
rotation: createPictureRotationInput(options?.rotate),
|
|
101
|
+
crop: sizingResult.crop
|
|
102
|
+
};
|
|
103
|
+
ctx.buildContext.pptxAuthoring.registerPicture(input, {
|
|
104
|
+
name: options?.name,
|
|
105
|
+
shadow: options?.shadow
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
//#endregion
|
|
109
|
+
export { addGlimpsePicture, imageBytesFromSource };
|
|
110
|
+
|
|
111
|
+
//# sourceMappingURL=glimpsePicture.js.map
|
|
@@ -0,0 +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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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { parseGradient } from "../../shared/gradient.js";
|
|
2
|
+
import { pxToEmu } from "../units.js";
|
|
3
|
+
import { toColorInput } from "../pptxAuthoring.js";
|
|
4
|
+
import { asEmu, asOoxmlAngle } from "@pptx-glimpse/document";
|
|
5
|
+
//#region src/renderPptx/utils/glimpseShape.ts
|
|
6
|
+
function positiveEmu(valuePx) {
|
|
7
|
+
return asEmu(Math.max(1, Math.round(pxToEmu(valuePx))));
|
|
8
|
+
}
|
|
9
|
+
function createShapeBoundsInput(bounds) {
|
|
10
|
+
return {
|
|
11
|
+
offsetX: asEmu(Math.round(pxToEmu(bounds.x))),
|
|
12
|
+
offsetY: asEmu(Math.round(pxToEmu(bounds.y))),
|
|
13
|
+
width: positiveEmu(bounds.w),
|
|
14
|
+
height: positiveEmu(bounds.h)
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function createShapeRotationInput(rotate) {
|
|
18
|
+
return rotate !== void 0 ? asOoxmlAngle(Math.round(rotate * 6e4)) : void 0;
|
|
19
|
+
}
|
|
20
|
+
function solidShapeFill(color) {
|
|
21
|
+
const clean = toColorInput(color);
|
|
22
|
+
return clean ? {
|
|
23
|
+
kind: "solid",
|
|
24
|
+
color: clean
|
|
25
|
+
} : void 0;
|
|
26
|
+
}
|
|
27
|
+
function noneShapeFill() {
|
|
28
|
+
return { kind: "none" };
|
|
29
|
+
}
|
|
30
|
+
function gradientFallbackColor(value) {
|
|
31
|
+
return parseGradient(value)?.value.stops[0]?.color;
|
|
32
|
+
}
|
|
33
|
+
function backgroundShapeFill(backgroundColor, backgroundGradient) {
|
|
34
|
+
if (backgroundGradient) return solidShapeFill(gradientFallbackColor(backgroundGradient));
|
|
35
|
+
return solidShapeFill(backgroundColor);
|
|
36
|
+
}
|
|
37
|
+
function dashStyle(dashType) {
|
|
38
|
+
return dashType;
|
|
39
|
+
}
|
|
40
|
+
function shapeOutline(border, fallbackColor) {
|
|
41
|
+
if (!border) return void 0;
|
|
42
|
+
const fill = solidShapeFill(border.color ?? fallbackColor);
|
|
43
|
+
if (border.width === void 0 && fill === void 0 && border.dashType === void 0) return;
|
|
44
|
+
return {
|
|
45
|
+
width: border.width !== void 0 ? asEmu(Math.round(pxToEmu(border.width))) : void 0,
|
|
46
|
+
fill,
|
|
47
|
+
dash: dashStyle(border.dashType)
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function noShapeOutline() {
|
|
51
|
+
return { fill: noneShapeFill() };
|
|
52
|
+
}
|
|
53
|
+
function arrowEndpoint(type) {
|
|
54
|
+
if (type === void 0 || type === "none") return void 0;
|
|
55
|
+
return {
|
|
56
|
+
type,
|
|
57
|
+
width: "med",
|
|
58
|
+
length: "med"
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function addGlimpseShape(ctx, input, bounds, options) {
|
|
62
|
+
ctx.buildContext.pptxAuthoring.registerShape(input, {
|
|
63
|
+
...options,
|
|
64
|
+
zeroWidth: bounds.w === 0,
|
|
65
|
+
zeroHeight: bounds.h === 0
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
69
|
+
export { addGlimpseShape, arrowEndpoint, backgroundShapeFill, createShapeBoundsInput, createShapeRotationInput, noShapeOutline, noneShapeFill, shapeOutline, solidShapeFill };
|
|
70
|
+
|
|
71
|
+
//# sourceMappingURL=glimpseShape.js.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { pxToEmu, pxToPt } from "../units.js";
|
|
2
|
+
import { toColorInput } from "../pptxAuthoring.js";
|
|
3
|
+
import { asEmu, asHundredthPt, asOoxmlAngle, asOoxmlPercent, asPt } from "@pptx-glimpse/document";
|
|
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
|
+
function createGlimpseParagraph(text, style, options = {}) {
|
|
33
|
+
const fontSizePx = style.fontSize ?? 24;
|
|
34
|
+
return {
|
|
35
|
+
properties: {
|
|
36
|
+
align: options.align,
|
|
37
|
+
lineSpacing: options.lineHeight !== void 0 ? asHundredthPt(Math.round(pxToPt(fontSizePx * options.lineHeight) * 100)) : void 0
|
|
38
|
+
},
|
|
39
|
+
runs: [{
|
|
40
|
+
text,
|
|
41
|
+
properties: createGlimpseRunProperties(style)
|
|
42
|
+
}]
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function createGlimpseParagraphs(text, style, options = {}) {
|
|
46
|
+
return text.replace(/\r*\n/g, "\n").split("\n").map((line) => createGlimpseParagraph(line, style, options));
|
|
47
|
+
}
|
|
48
|
+
function textBoxInput(bounds, options, paragraphs) {
|
|
49
|
+
const margin = options.margin !== void 0 ? asEmu(Math.round(pxToEmu(options.margin))) : void 0;
|
|
50
|
+
return {
|
|
51
|
+
offsetX: asEmu(Math.round(pxToEmu(bounds.x))),
|
|
52
|
+
offsetY: asEmu(Math.round(pxToEmu(bounds.y))),
|
|
53
|
+
width: asEmu(Math.max(1, Math.round(pxToEmu(bounds.w)))),
|
|
54
|
+
height: asEmu(Math.max(1, Math.round(pxToEmu(bounds.h)))),
|
|
55
|
+
rotation: options.rotate !== void 0 ? asOoxmlAngle(Math.round(options.rotate * 6e4)) : void 0,
|
|
56
|
+
body: {
|
|
57
|
+
marginLeft: margin,
|
|
58
|
+
marginRight: margin,
|
|
59
|
+
marginTop: margin,
|
|
60
|
+
marginBottom: margin,
|
|
61
|
+
anchor: options.valign,
|
|
62
|
+
autoFit: options.autoFit ? "shape" : void 0
|
|
63
|
+
},
|
|
64
|
+
paragraphs
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function withListProperties(paragraphs, options) {
|
|
68
|
+
if (!options.bullet) return paragraphs;
|
|
69
|
+
const bullet = options.bullet.kind === "bullet" ? {
|
|
70
|
+
type: "character",
|
|
71
|
+
character: "•",
|
|
72
|
+
size: asOoxmlPercent(1e5)
|
|
73
|
+
} : {
|
|
74
|
+
type: "auto-number",
|
|
75
|
+
scheme: isSupportedAutoNumScheme(options.bullet.scheme) ? options.bullet.scheme : "arabicPeriod",
|
|
76
|
+
startAt: options.bullet.startAt ?? 1,
|
|
77
|
+
fontFace: "+mj-lt",
|
|
78
|
+
size: asOoxmlPercent(1e5)
|
|
79
|
+
};
|
|
80
|
+
return paragraphs.map((paragraph) => ({
|
|
81
|
+
...paragraph,
|
|
82
|
+
properties: {
|
|
83
|
+
...paragraph.properties,
|
|
84
|
+
marginLeft: asEmu(342900),
|
|
85
|
+
indent: asEmu(-342900),
|
|
86
|
+
lineSpacing: {
|
|
87
|
+
type: "percent",
|
|
88
|
+
value: asOoxmlPercent(Math.round((options.lineHeight ?? 1.3) * 1e5))
|
|
89
|
+
},
|
|
90
|
+
bullet
|
|
91
|
+
}
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
function addGlimpseTextBox(ctx, bounds, options = {}) {
|
|
95
|
+
const paragraphs = withListProperties(options.paragraphs ?? createGlimpseParagraphs(options.text ?? "", options, {
|
|
96
|
+
align: options.align,
|
|
97
|
+
lineHeight: options.lineHeight
|
|
98
|
+
}), options);
|
|
99
|
+
ctx.buildContext.pptxAuthoring.registerTextBox(textBoxInput(bounds, options, paragraphs), { hyperlinks: options.hyperlinks });
|
|
100
|
+
}
|
|
101
|
+
function isSupportedAutoNumScheme(value) {
|
|
102
|
+
return value === "arabicPeriod" || value === "arabicParenR" || value === "romanUcPeriod" || value === "romanLcPeriod" || value === "alphaUcPeriod" || value === "alphaLcPeriod" || value === "alphaLcParenR" || value === "alphaUcParenR" || value === "arabicPlain";
|
|
103
|
+
}
|
|
104
|
+
//#endregion
|
|
105
|
+
export { addGlimpseTextBox, createGlimpseParagraphs, createGlimpseRunProperties };
|
|
106
|
+
|
|
107
|
+
//# sourceMappingURL=glimpseTextBox.js.map
|
|
@@ -0,0 +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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"}
|