@hirokisakabe/pom 8.7.0 → 8.8.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.
@@ -0,0 +1,147 @@
1
+ import { pxToEmu } from "./units.js";
2
+ //#region src/renderPptx/glowEffects.ts
3
+ async function loadJSZip() {
4
+ const mod = await import("jszip");
5
+ return mod.default ?? mod;
6
+ }
7
+ const MARKER_PREFIX = "pom-glow:";
8
+ /**
9
+ * glow 仕様を一意なマーカー名にマップし、後処理で
10
+ * `<a:effectLst><a:glow>` 要素として挿入できるようにするレジストリ
11
+ */
12
+ var GlowEffectRegistry = class {
13
+ markerBySpec = /* @__PURE__ */ new Map();
14
+ registered = [];
15
+ /**
16
+ * glow を登録し、`objectName` に渡すマーカー文字列を返す。
17
+ * 同じ仕様の glow は同じマーカーを返す。
18
+ */
19
+ register(glow) {
20
+ const sizePx = glow.size ?? 8;
21
+ const opacity = glow.opacity ?? .75;
22
+ const color = (glow.color ?? "FFFFFF").replace(/^#/, "").toUpperCase();
23
+ const specKey = JSON.stringify({
24
+ sizePx,
25
+ opacity,
26
+ color
27
+ });
28
+ const existing = this.markerBySpec.get(specKey);
29
+ if (existing) return existing;
30
+ const marker = `${MARKER_PREFIX}${this.registered.length}`;
31
+ this.markerBySpec.set(specKey, marker);
32
+ this.registered.push({
33
+ marker,
34
+ sizePx,
35
+ opacity,
36
+ color
37
+ });
38
+ return marker;
39
+ }
40
+ get isEmpty() {
41
+ return this.registered.length === 0;
42
+ }
43
+ get entries() {
44
+ return this.registered;
45
+ }
46
+ };
47
+ /**
48
+ * DrawingML の `<a:glow>` 要素を構築する (effectLst で囲まない、内側だけ)
49
+ *
50
+ * - rad (光彩半径): px → EMU
51
+ * - alpha (透明度): 0-1 → 1/1000 % (0-100000)
52
+ */
53
+ function buildGlowXml(entry) {
54
+ const rad = Math.round(pxToEmu(entry.sizePx));
55
+ const alpha = Math.round(entry.opacity * 1e5);
56
+ return `<a:glow rad="${rad}"><a:srgbClr val="${entry.color}"><a:alpha val="${alpha}"/></a:srgbClr></a:glow>`;
57
+ }
58
+ /**
59
+ * 1 つの slide XML を受け取り、登録された glow を該当 shape に適用した XML を返す
60
+ *
61
+ * `<p:cNvPr ... name="pom-glow:N">` を含む `<p:sp>` ブロックを正規表現で検出し、
62
+ * 以下のいずれかで `<a:glow>` を挿入する:
63
+ *
64
+ * 1. 既に `<a:effectLst>...</a:effectLst>` が存在する場合
65
+ * (= pptxgenjs が shape の `shadow` 等で同要素を生成済み):
66
+ * その `effectLst` 内側の末尾 (`</a:effectLst>` の直前) に `<a:glow>` を追加する。
67
+ * OOXML スキーマ上 `<p:spPr>` 内の `<a:effectLst>` は最大 1 個までで、二重に
68
+ * 並べると不正になるため。
69
+ * 2. 既存 `effectLst` が無い場合:
70
+ * `</p:spPr>` の直前に新規 `<a:effectLst><a:glow/></a:effectLst>` を挿入する。
71
+ *
72
+ * pptxgenjs は cNvPr を `<p:cNvPr.../>` (self-closing) と
73
+ * `<p:cNvPr...></p:cNvPr>` (open+close) のどちらの形式でも出力し得るため、
74
+ * cNvPr の閉じ形式に依存せず name 属性のあとから lazy に進める。
75
+ */
76
+ function applyGlowToXml(xml, registry) {
77
+ let result = xml;
78
+ for (const entry of registry.entries) {
79
+ const glowXml = buildGlowXml(entry);
80
+ const re = new RegExp(`(<p:cNvPr[^>]*name="${entry.marker}"[\\s\\S]*?)(</p:spPr>)`, "g");
81
+ result = result.replace(re, (_match, prefix, suffix) => {
82
+ const block = prefix;
83
+ const closingIdx = block.lastIndexOf("</a:effectLst>");
84
+ if (closingIdx >= 0) return `${block.substring(0, closingIdx)}${glowXml}${block.substring(closingIdx)}${suffix}`;
85
+ return `${block}<a:effectLst>${glowXml}</a:effectLst>${suffix}`;
86
+ });
87
+ }
88
+ return result;
89
+ }
90
+ /**
91
+ * 出力 zip 内のスライド XML に glow 効果を挿入する
92
+ */
93
+ async function applyGlowEffects(data, registry) {
94
+ const zip = await (await loadJSZip()).loadAsync(data);
95
+ const slidePaths = Object.keys(zip.files).filter((path) => /^ppt\/slides\/slide\d+\.xml$/.test(path));
96
+ for (const path of slidePaths) {
97
+ const file = zip.file(path);
98
+ if (!file) continue;
99
+ const original = await file.async("text");
100
+ const replaced = applyGlowToXml(original, registry);
101
+ if (replaced !== original) zip.file(path, replaced);
102
+ }
103
+ return zip;
104
+ }
105
+ /**
106
+ * pptx インスタンスの write / writeFile をラップし、出力時に glow 後処理を適用する。
107
+ *
108
+ * 既に他の後処理 (gradientFills 等) によりラップされている場合に備え、
109
+ * 元の関数を保存してチェーン可能にしている。
110
+ */
111
+ function patchPptxWriteForGlowEffects(pptx, registry) {
112
+ if (registry.isEmpty) return;
113
+ const originalWrite = pptx.write.bind(pptx);
114
+ const originalWriteFile = pptx.writeFile.bind(pptx);
115
+ const patchedWrite = async (rawProps) => {
116
+ const props = typeof rawProps === "string" ? { outputType: rawProps } : rawProps;
117
+ const zip = await applyGlowEffects(await originalWrite({ outputType: "uint8array" }), registry);
118
+ const outputType = props?.outputType;
119
+ if (outputType === "STREAM") return zip.generateAsync({
120
+ type: "nodebuffer",
121
+ compression: props?.compression ? "DEFLATE" : "STORE"
122
+ });
123
+ if (outputType) return zip.generateAsync({ type: outputType });
124
+ return zip.generateAsync({
125
+ type: "blob",
126
+ compression: props?.compression ? "DEFLATE" : "STORE"
127
+ });
128
+ };
129
+ pptx.write = patchedWrite;
130
+ const patchedWriteFile = async (rawProps) => {
131
+ const props = typeof rawProps === "string" ? { fileName: rawProps } : rawProps;
132
+ if (!(typeof process !== "undefined" && Boolean(process.versions?.node))) return originalWriteFile(props);
133
+ const rawName = props?.fileName ?? "Presentation.pptx";
134
+ const fileName = rawName.toLowerCase().endsWith(".pptx") ? rawName : `${rawName}.pptx`;
135
+ const buffer = await patchedWrite({
136
+ outputType: "nodebuffer",
137
+ compression: props?.compression
138
+ });
139
+ await (await import("fs")).promises.writeFile(fileName, buffer);
140
+ return fileName;
141
+ };
142
+ pptx.writeFile = patchedWriteFile;
143
+ }
144
+ //#endregion
145
+ export { GlowEffectRegistry, patchPptxWriteForGlowEffects };
146
+
147
+ //# sourceMappingURL=glowEffects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glowEffects.js","names":[],"sources":["../../src/renderPptx/glowEffects.ts"],"sourcesContent":["/**\n * Shape / Icon の glow (光彩) 効果の実現\n *\n * pptxgenjs の Shape options には glow 相当のネイティブサポートがないため\n * (TextPropsOptions の glow は文字グリフ用)、以下の方式で実現する:\n *\n * 1. レンダリング時: glow 指定のある shape に一意なマーカー名を `objectName`\n * として埋め込み、レジストリに登録する。マーカー名は `<p:cNvPr name=\"...\"/>`\n * として PPTX 出力 XML に書き込まれる。\n * 2. 出力時: pptx.write() / writeFile() をラップし、出力 zip 内のスライド XML\n * の該当 `<p:sp>` の `<p:spPr>` 末尾に DrawingML ネイティブの\n * `<a:effectLst><a:glow>...</a:glow></a:effectLst>` を挿入する。\n *\n * 文字列置換採用理由 / 注意点は gradientFills.ts と同様。\n */\nimport type { TextGlow } from \"../types.ts\";\nimport { pxToEmu } from \"./units.ts\";\n\ntype PptxGenJSInstance = import(\"pptxgenjs\").default;\ntype WriteProps = NonNullable<Parameters<PptxGenJSInstance[\"write\"]>[0]>;\ntype WriteFileProps = NonNullable<\n Parameters<PptxGenJSInstance[\"writeFile\"]>[0]\n>;\n\nasync function loadJSZip(): Promise<typeof import(\"jszip\")> {\n const mod = await import(\"jszip\");\n /* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return */\n return (mod as any).default ?? mod;\n /* eslint-enable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return */\n}\n\ninterface RegisteredGlow {\n /** objectName に埋め込むマーカー文字列 */\n marker: string;\n /** size (px) — XML 出力時に EMU に変換する */\n sizePx: number;\n /** opacity 0-1 */\n opacity: number;\n /** 6桁 HEX (# なし、大文字) */\n color: string;\n}\n\nconst MARKER_PREFIX = \"pom-glow:\";\n\n/**\n * glow 仕様を一意なマーカー名にマップし、後処理で\n * `<a:effectLst><a:glow>` 要素として挿入できるようにするレジストリ\n */\nexport class GlowEffectRegistry {\n private readonly markerBySpec = new Map<string, string>();\n private readonly registered: RegisteredGlow[] = [];\n\n /**\n * glow を登録し、`objectName` に渡すマーカー文字列を返す。\n * 同じ仕様の glow は同じマーカーを返す。\n */\n register(glow: TextGlow): string {\n const sizePx = glow.size ?? 8;\n const opacity = glow.opacity ?? 0.75;\n const color = (glow.color ?? \"FFFFFF\").replace(/^#/, \"\").toUpperCase();\n const specKey = JSON.stringify({ sizePx, opacity, color });\n const existing = this.markerBySpec.get(specKey);\n if (existing) return existing;\n\n const index = this.registered.length;\n const marker = `${MARKER_PREFIX}${index}`;\n this.markerBySpec.set(specKey, marker);\n this.registered.push({ marker, sizePx, opacity, color });\n return marker;\n }\n\n get isEmpty(): boolean {\n return this.registered.length === 0;\n }\n\n get entries(): readonly RegisteredGlow[] {\n return this.registered;\n }\n}\n\n/**\n * DrawingML の `<a:glow>` 要素を構築する (effectLst で囲まない、内側だけ)\n *\n * - rad (光彩半径): px → EMU\n * - alpha (透明度): 0-1 → 1/1000 % (0-100000)\n */\nfunction buildGlowXml(entry: RegisteredGlow): string {\n const rad = Math.round(pxToEmu(entry.sizePx));\n const alpha = Math.round(entry.opacity * 100000);\n return `<a:glow rad=\"${rad}\"><a:srgbClr val=\"${entry.color}\"><a:alpha val=\"${alpha}\"/></a:srgbClr></a:glow>`;\n}\n\n/**\n * 1 つの slide XML を受け取り、登録された glow を該当 shape に適用した XML を返す\n *\n * `<p:cNvPr ... name=\"pom-glow:N\">` を含む `<p:sp>` ブロックを正規表現で検出し、\n * 以下のいずれかで `<a:glow>` を挿入する:\n *\n * 1. 既に `<a:effectLst>...</a:effectLst>` が存在する場合\n * (= pptxgenjs が shape の `shadow` 等で同要素を生成済み):\n * その `effectLst` 内側の末尾 (`</a:effectLst>` の直前) に `<a:glow>` を追加する。\n * OOXML スキーマ上 `<p:spPr>` 内の `<a:effectLst>` は最大 1 個までで、二重に\n * 並べると不正になるため。\n * 2. 既存 `effectLst` が無い場合:\n * `</p:spPr>` の直前に新規 `<a:effectLst><a:glow/></a:effectLst>` を挿入する。\n *\n * pptxgenjs は cNvPr を `<p:cNvPr.../>` (self-closing) と\n * `<p:cNvPr...></p:cNvPr>` (open+close) のどちらの形式でも出力し得るため、\n * cNvPr の閉じ形式に依存せず name 属性のあとから lazy に進める。\n */\nfunction applyGlowToXml(xml: string, registry: GlowEffectRegistry): string {\n let result = xml;\n for (const entry of registry.entries) {\n const glowXml = buildGlowXml(entry);\n const re = new RegExp(\n `(<p:cNvPr[^>]*name=\"${entry.marker}\"[\\\\s\\\\S]*?)(</p:spPr>)`,\n \"g\",\n );\n result = result.replace(re, (_match, prefix, suffix) => {\n const block = prefix as string;\n // shape ブロック内に既存の effectLst があるかを `</a:effectLst>` の有無で判定する。\n // 別 shape の effectLst を誤って書き換えないよう、検索範囲は prefix\n // (= 該当 cNvPr 〜 直後の </p:spPr> の手前まで) に限定している。\n const closingIdx = block.lastIndexOf(\"</a:effectLst>\");\n if (closingIdx >= 0) {\n const before = block.substring(0, closingIdx);\n const after = block.substring(closingIdx);\n return `${before}${glowXml}${after}${suffix as string}`;\n }\n return `${block}<a:effectLst>${glowXml}</a:effectLst>${suffix as string}`;\n });\n }\n return result;\n}\n\n/**\n * 出力 zip 内のスライド XML に glow 効果を挿入する\n */\nexport async function applyGlowEffects(\n data: Uint8Array | ArrayBuffer,\n registry: GlowEffectRegistry,\n): Promise<import(\"jszip\")> {\n const JSZip = await loadJSZip();\n const zip = await JSZip.loadAsync(data);\n\n const slidePaths = Object.keys(zip.files).filter((path) =>\n /^ppt\\/slides\\/slide\\d+\\.xml$/.test(path),\n );\n for (const path of slidePaths) {\n const file = zip.file(path);\n if (!file) continue;\n const original = await file.async(\"text\");\n const replaced = applyGlowToXml(original, registry);\n if (replaced !== original) {\n zip.file(path, replaced);\n }\n }\n return zip;\n}\n\n/**\n * pptx インスタンスの write / writeFile をラップし、出力時に glow 後処理を適用する。\n *\n * 既に他の後処理 (gradientFills 等) によりラップされている場合に備え、\n * 元の関数を保存してチェーン可能にしている。\n */\nexport function patchPptxWriteForGlowEffects(\n pptx: PptxGenJSInstance,\n registry: GlowEffectRegistry,\n): void {\n if (registry.isEmpty) return;\n\n const originalWrite = pptx.write.bind(pptx);\n const originalWriteFile = pptx.writeFile.bind(pptx);\n\n const patchedWrite = async (rawProps?: WriteProps | string) => {\n const props: WriteProps | undefined =\n typeof rawProps === \"string\"\n ? ({ outputType: rawProps } as WriteProps)\n : rawProps;\n const data = (await originalWrite({\n outputType: \"uint8array\",\n })) as Uint8Array;\n const zip = await applyGlowEffects(data, registry);\n\n const outputType = props?.outputType;\n if (outputType === \"STREAM\") {\n return zip.generateAsync({\n type: \"nodebuffer\",\n compression: props?.compression ? \"DEFLATE\" : \"STORE\",\n });\n }\n if (outputType) {\n return zip.generateAsync({ type: outputType });\n }\n return zip.generateAsync({\n type: \"blob\",\n compression: props?.compression ? \"DEFLATE\" : \"STORE\",\n });\n };\n pptx.write = patchedWrite;\n\n const patchedWriteFile = async (rawProps?: WriteFileProps | string) => {\n const props: WriteFileProps | undefined =\n typeof rawProps === \"string\" ? { fileName: rawProps } : rawProps;\n const isNode =\n typeof process !== \"undefined\" && Boolean(process.versions?.node);\n if (!isNode) {\n return originalWriteFile(props);\n }\n const rawName = props?.fileName ?? \"Presentation.pptx\";\n const fileName = rawName.toLowerCase().endsWith(\".pptx\")\n ? rawName\n : `${rawName}.pptx`;\n const buffer = (await patchedWrite({\n outputType: \"nodebuffer\",\n compression: props?.compression,\n })) as Buffer;\n const fs = await import(\"fs\");\n await fs.promises.writeFile(fileName, buffer);\n return fileName;\n };\n pptx.writeFile = patchedWriteFile;\n}\n"],"mappings":";;AAwBA,eAAe,YAA6C;CAC1D,MAAM,MAAM,MAAM,OAAO;CAEzB,OAAQ,IAAY,WAAW;AAEjC;AAaA,MAAM,gBAAgB;;;;;AAMtB,IAAa,qBAAb,MAAgC;CAC9B,+BAAgC,IAAI,IAAoB;CACxD,aAAgD,CAAC;;;;;CAMjD,SAAS,MAAwB;EAC/B,MAAM,SAAS,KAAK,QAAQ;EAC5B,MAAM,UAAU,KAAK,WAAW;EAChC,MAAM,SAAS,KAAK,SAAS,SAAA,CAAU,QAAQ,MAAM,EAAE,CAAC,CAAC,YAAY;EACrE,MAAM,UAAU,KAAK,UAAU;GAAE;GAAQ;GAAS;EAAM,CAAC;EACzD,MAAM,WAAW,KAAK,aAAa,IAAI,OAAO;EAC9C,IAAI,UAAU,OAAO;EAGrB,MAAM,SAAS,GAAG,gBADJ,KAAK,WAAW;EAE9B,KAAK,aAAa,IAAI,SAAS,MAAM;EACrC,KAAK,WAAW,KAAK;GAAE;GAAQ;GAAQ;GAAS;EAAM,CAAC;EACvD,OAAO;CACT;CAEA,IAAI,UAAmB;EACrB,OAAO,KAAK,WAAW,WAAW;CACpC;CAEA,IAAI,UAAqC;EACvC,OAAO,KAAK;CACd;AACF;;;;;;;AAQA,SAAS,aAAa,OAA+B;CACnD,MAAM,MAAM,KAAK,MAAM,QAAQ,MAAM,MAAM,CAAC;CAC5C,MAAM,QAAQ,KAAK,MAAM,MAAM,UAAU,GAAM;CAC/C,OAAO,gBAAgB,IAAI,oBAAoB,MAAM,MAAM,kBAAkB,MAAM;AACrF;;;;;;;;;;;;;;;;;;;AAoBA,SAAS,eAAe,KAAa,UAAsC;CACzE,IAAI,SAAS;CACb,KAAK,MAAM,SAAS,SAAS,SAAS;EACpC,MAAM,UAAU,aAAa,KAAK;EAClC,MAAM,KAAK,IAAI,OACb,uBAAuB,MAAM,OAAO,0BACpC,GACF;EACA,SAAS,OAAO,QAAQ,KAAK,QAAQ,QAAQ,WAAW;GACtD,MAAM,QAAQ;GAId,MAAM,aAAa,MAAM,YAAY,gBAAgB;GACrD,IAAI,cAAc,GAGhB,OAAO,GAFQ,MAAM,UAAU,GAAG,UAEnB,IAAI,UADL,MAAM,UAAU,UACG,IAAI;GAEvC,OAAO,GAAG,MAAM,eAAe,QAAQ,gBAAgB;EACzD,CAAC;CACH;CACA,OAAO;AACT;;;;AAKA,eAAsB,iBACpB,MACA,UAC0B;CAE1B,MAAM,MAAM,OAAM,MADE,UAAU,EAAA,CACN,UAAU,IAAI;CAEtC,MAAM,aAAa,OAAO,KAAK,IAAI,KAAK,CAAC,CAAC,QAAQ,SAChD,+BAA+B,KAAK,IAAI,CAC1C;CACA,KAAK,MAAM,QAAQ,YAAY;EAC7B,MAAM,OAAO,IAAI,KAAK,IAAI;EAC1B,IAAI,CAAC,MAAM;EACX,MAAM,WAAW,MAAM,KAAK,MAAM,MAAM;EACxC,MAAM,WAAW,eAAe,UAAU,QAAQ;EAClD,IAAI,aAAa,UACf,IAAI,KAAK,MAAM,QAAQ;CAE3B;CACA,OAAO;AACT;;;;;;;AAQA,SAAgB,6BACd,MACA,UACM;CACN,IAAI,SAAS,SAAS;CAEtB,MAAM,gBAAgB,KAAK,MAAM,KAAK,IAAI;CAC1C,MAAM,oBAAoB,KAAK,UAAU,KAAK,IAAI;CAElD,MAAM,eAAe,OAAO,aAAmC;EAC7D,MAAM,QACJ,OAAO,aAAa,WACf,EAAE,YAAY,SAAS,IACxB;EAIN,MAAM,MAAM,MAAM,iBAAiB,MAHf,cAAc,EAChC,YAAY,aACd,CAAC,GACwC,QAAQ;EAEjD,MAAM,aAAa,OAAO;EAC1B,IAAI,eAAe,UACjB,OAAO,IAAI,cAAc;GACvB,MAAM;GACN,aAAa,OAAO,cAAc,YAAY;EAChD,CAAC;EAEH,IAAI,YACF,OAAO,IAAI,cAAc,EAAE,MAAM,WAAW,CAAC;EAE/C,OAAO,IAAI,cAAc;GACvB,MAAM;GACN,aAAa,OAAO,cAAc,YAAY;EAChD,CAAC;CACH;CACA,KAAK,QAAQ;CAEb,MAAM,mBAAmB,OAAO,aAAuC;EACrE,MAAM,QACJ,OAAO,aAAa,WAAW,EAAE,UAAU,SAAS,IAAI;EAG1D,IAAI,EADF,OAAO,YAAY,eAAe,QAAQ,QAAQ,UAAU,IAAI,IAEhE,OAAO,kBAAkB,KAAK;EAEhC,MAAM,UAAU,OAAO,YAAY;EACnC,MAAM,WAAW,QAAQ,YAAY,CAAC,CAAC,SAAS,OAAO,IACnD,UACA,GAAG,QAAQ;EACf,MAAM,SAAU,MAAM,aAAa;GACjC,YAAY;GACZ,aAAa,OAAO;EACtB,CAAC;EAED,OAAM,MADW,OAAO,MAAA,CACf,SAAS,UAAU,UAAU,MAAM;EAC5C,OAAO;CACT;CACA,KAAK,YAAY;AACnB"}
@@ -58,6 +58,19 @@ function registerBackgroundGradient(value, opacity, registry) {
58
58
  return registry.register(gradient, opacity);
59
59
  }
60
60
  /**
61
+ * textGradient 属性値をパースしてレジストリに登録し、マーカー色を返す。
62
+ * 戻り値のマーカー色を text run の color に渡すと、pptxgenjs が出力する
63
+ * `<a:rPr><a:solidFill><a:srgbClr val="マーカー色"/></a:solidFill></a:rPr>` が
64
+ * 後処理で gradFill に置換され、PowerPoint 上ネイティブの文字グラデーションとして
65
+ * 表示・編集可能になる。
66
+ * パースできない場合 (スキーマ検証済みのため通常発生しない) は undefined を返す。
67
+ */
68
+ function registerTextGradient(value, registry) {
69
+ const gradient = parseLinearGradient(value);
70
+ if (!gradient) return void 0;
71
+ return registry.register(gradient);
72
+ }
73
+ /**
61
74
  * LinearGradient を DrawingML の `<a:gradFill>` 要素に変換する
62
75
  *
63
76
  * - カラーストップ位置: % → 1/1000 % (0-100000)
@@ -134,6 +147,6 @@ function patchPptxWriteForGradientFills(pptx, registry) {
134
147
  pptx.writeFile = patchedWriteFile;
135
148
  }
136
149
  //#endregion
137
- export { GradientFillRegistry, patchPptxWriteForGradientFills, registerBackgroundGradient };
150
+ export { GradientFillRegistry, patchPptxWriteForGradientFills, registerBackgroundGradient, registerTextGradient };
138
151
 
139
152
  //# sourceMappingURL=gradientFills.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"gradientFills.js","names":[],"sources":["../../src/renderPptx/gradientFills.ts"],"sourcesContent":["/**\n * グラデーション塗りの実現\n *\n * pptxgenjs はグラデーション塗りを未サポート\n * (https://github.com/gitbrent/PptxGenJS/issues/102) のため、以下の方式で実現する:\n *\n * 1. レンダリング時: グラデーション指定のある shape をビルド内で一意なマーカー色の\n * 単色塗り (solidFill) として描画し、レジストリに登録する\n * 2. 出力時: pptx.write() / writeFile() をラップし、出力 zip 内のスライド XML の\n * `<a:solidFill><a:srgbClr val=\"マーカー色\"/></a:solidFill>` を\n * DrawingML ネイティブの `<a:gradFill>` に置換する\n *\n * 置換は pptxgenjs が生成する固定パターンに対する完全一致の文字列置換で行う。\n * スライド XML 全体をパーサーで往復させると無関係な要素の表現が変わり得るため、\n * 意図的に文字列置換を採用している。\n */\nimport type { LinearGradient } from \"../shared/gradient.ts\";\nimport { parseLinearGradient } from \"../shared/gradient.ts\";\n\ntype PptxGenJSInstance = import(\"pptxgenjs\").default;\ntype WriteProps = NonNullable<Parameters<PptxGenJSInstance[\"write\"]>[0]>;\ntype WriteFileProps = NonNullable<\n Parameters<PptxGenJSInstance[\"writeFile\"]>[0]\n>;\n\n// JSZip は CJS パッケージのため動的 import で読み込む\nasync function loadJSZip(): Promise<typeof import(\"jszip\")> {\n const mod = await import(\"jszip\");\n /* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return */\n return (mod as any).default ?? mod;\n /* eslint-enable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return */\n}\n\ninterface RegisteredGradientFill {\n /** マーカー色 (6桁大文字 HEX、# なし) */\n marker: string;\n gradient: LinearGradient;\n /** 0-1。指定時は各カラーストップに alpha として反映する */\n opacity?: number;\n}\n\n/** マーカー色の探索開始値。reserveColors で予約済みの色はスキップされる */\nconst MARKER_BASE = 0x0f7a3d;\n\nexport class GradientFillRegistry {\n private readonly reserved = new Set<string>();\n private readonly markerBySpec = new Map<string, string>();\n private readonly registered: RegisteredGradientFill[] = [];\n private nextCandidate = MARKER_BASE;\n\n /**\n * テキスト中に現れる 6桁 HEX をマーカー候補から除外する。\n * 入力 XML 由来のユーザー指定色とマーカーの衝突を防ぐため、\n * register より前に入力 XML 文字列を渡しておく。\n */\n reserveColors(text: string): void {\n for (const match of text.matchAll(/[0-9a-fA-F]{6}/g)) {\n this.reserved.add(match[0].toUpperCase());\n }\n }\n\n /** グラデーションを登録し、対応するマーカー色を返す */\n register(gradient: LinearGradient, opacity?: number): string {\n const specKey = JSON.stringify({ gradient, opacity });\n const existing = this.markerBySpec.get(specKey);\n if (existing) return existing;\n\n let marker: string;\n do {\n marker = this.nextCandidate.toString(16).toUpperCase().padStart(6, \"0\");\n this.nextCandidate = (this.nextCandidate + 1) % 0x1000000;\n } while (this.reserved.has(marker));\n this.reserved.add(marker);\n\n this.markerBySpec.set(specKey, marker);\n this.registered.push({ marker, gradient, opacity });\n return marker;\n }\n\n get isEmpty(): boolean {\n return this.registered.length === 0;\n }\n\n get entries(): readonly RegisteredGradientFill[] {\n return this.registered;\n }\n}\n\n/**\n * backgroundGradient 属性値をパースしてレジストリに登録し、マーカー色を返す。\n * パースできない場合 (スキーマ検証済みのため通常発生しない) は undefined を返す。\n */\nexport function registerBackgroundGradient(\n value: string,\n opacity: number | undefined,\n registry: GradientFillRegistry,\n): string | undefined {\n const gradient = parseLinearGradient(value);\n if (!gradient) return undefined;\n return registry.register(gradient, opacity);\n}\n\n/**\n * LinearGradient を DrawingML の `<a:gradFill>` 要素に変換する\n *\n * - カラーストップ位置: % → 1/1000 % (0-100000)\n * - 角度: CSS 基準 (0deg = 上向き) → DrawingML 基準 (0 = 右向き、1/60000 度)\n */\nfunction buildGradFillXml(gradient: LinearGradient, opacity?: number): string {\n const alphaXml =\n opacity !== undefined\n ? `<a:alpha val=\"${Math.round(opacity * 100000)}\"/>`\n : \"\";\n const gsXml = gradient.stops\n .map((stop) => {\n const pos = Math.round(stop.position * 1000);\n const srgbClr = alphaXml\n ? `<a:srgbClr val=\"${stop.color}\">${alphaXml}</a:srgbClr>`\n : `<a:srgbClr val=\"${stop.color}\"/>`;\n return `<a:gs pos=\"${pos}\">${srgbClr}</a:gs>`;\n })\n .join(\"\");\n const dmlAngle = (((gradient.angle - 90) % 360) + 360) % 360;\n const ang = Math.round(dmlAngle * 60000);\n return `<a:gradFill flip=\"none\" rotWithShape=\"1\"><a:gsLst>${gsXml}</a:gsLst><a:lin ang=\"${ang}\" scaled=\"0\"/></a:gradFill>`;\n}\n\n/**\n * 出力 zip 内のスライド XML のマーカー solidFill を gradFill に置換する\n */\nexport async function applyGradientFills(\n data: Uint8Array | ArrayBuffer,\n registry: GradientFillRegistry,\n): Promise<import(\"jszip\")> {\n const JSZip = await loadJSZip();\n const zip = await JSZip.loadAsync(data);\n\n const slidePaths = Object.keys(zip.files).filter((path) =>\n /^ppt\\/slides\\/slide\\d+\\.xml$/.test(path),\n );\n for (const path of slidePaths) {\n const file = zip.file(path);\n if (!file) continue;\n let xml = await file.async(\"text\");\n let replaced = false;\n for (const { marker, gradient, opacity } of registry.entries) {\n const target = `<a:solidFill><a:srgbClr val=\"${marker}\"/></a:solidFill>`;\n if (!xml.includes(target)) continue;\n xml = xml.replaceAll(target, buildGradFillXml(gradient, opacity));\n replaced = true;\n }\n if (replaced) {\n zip.file(path, xml);\n }\n }\n return zip;\n}\n\n/**\n * pptx インスタンスの write / writeFile をラップし、\n * 出力時にグラデーション後処理を適用する。\n *\n * pptxgenjs の write と同じ outputType / compression の挙動を再現する。\n * writeFile は Node 環境のみ後処理対象 (ブラウザでは pptxgenjs がダウンロード\n * 処理を行うため、元の実装にフォールバックする)。\n */\nexport function patchPptxWriteForGradientFills(\n pptx: PptxGenJSInstance,\n registry: GradientFillRegistry,\n): void {\n if (registry.isEmpty) return;\n\n const originalWrite = pptx.write.bind(pptx);\n const originalWriteFile = pptx.writeFile.bind(pptx);\n\n const patchedWrite = async (rawProps?: WriteProps | string) => {\n // DEPRECATED: pptxgenjs は write(outputType) の文字列 overload を\n // ランタイムでは今も受け付けるため、同様に正規化する\n const props: WriteProps | undefined =\n typeof rawProps === \"string\"\n ? ({ outputType: rawProps } as WriteProps)\n : rawProps;\n const data = (await originalWrite({\n outputType: \"uint8array\",\n })) as Uint8Array;\n const zip = await applyGradientFills(data, registry);\n\n const outputType = props?.outputType;\n if (outputType === \"STREAM\") {\n return zip.generateAsync({\n type: \"nodebuffer\",\n compression: props?.compression ? \"DEFLATE\" : \"STORE\",\n });\n }\n if (outputType) {\n return zip.generateAsync({ type: outputType });\n }\n return zip.generateAsync({\n type: \"blob\",\n compression: props?.compression ? \"DEFLATE\" : \"STORE\",\n });\n };\n pptx.write = patchedWrite;\n\n const patchedWriteFile = async (rawProps?: WriteFileProps | string) => {\n // DEPRECATED: pptxgenjs は writeFile(fileName) の文字列 overload を\n // ランタイムでは今も受け付けるため、同様に正規化する\n const props: WriteFileProps | undefined =\n typeof rawProps === \"string\" ? { fileName: rawProps } : rawProps;\n const isNode =\n typeof process !== \"undefined\" && Boolean(process.versions?.node);\n if (!isNode) {\n return originalWriteFile(props);\n }\n const rawName = props?.fileName ?? \"Presentation.pptx\";\n const fileName = rawName.toLowerCase().endsWith(\".pptx\")\n ? rawName\n : `${rawName}.pptx`;\n const buffer = (await patchedWrite({\n outputType: \"nodebuffer\",\n compression: props?.compression,\n })) as Buffer;\n const fs = await import(\"fs\");\n await fs.promises.writeFile(fileName, buffer);\n return fileName;\n };\n pptx.writeFile = patchedWriteFile;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"gradientFills.js","names":[],"sources":["../../src/renderPptx/gradientFills.ts"],"sourcesContent":["/**\n * グラデーション塗りの実現\n *\n * pptxgenjs はグラデーション塗りを未サポート\n * (https://github.com/gitbrent/PptxGenJS/issues/102) のため、以下の方式で実現する:\n *\n * 1. レンダリング時: グラデーション指定のある shape をビルド内で一意なマーカー色の\n * 単色塗り (solidFill) として描画し、レジストリに登録する\n * 2. 出力時: pptx.write() / writeFile() をラップし、出力 zip 内のスライド XML の\n * `<a:solidFill><a:srgbClr val=\"マーカー色\"/></a:solidFill>` を\n * DrawingML ネイティブの `<a:gradFill>` に置換する\n *\n * 置換は pptxgenjs が生成する固定パターンに対する完全一致の文字列置換で行う。\n * スライド XML 全体をパーサーで往復させると無関係な要素の表現が変わり得るため、\n * 意図的に文字列置換を採用している。\n */\nimport type { LinearGradient } from \"../shared/gradient.ts\";\nimport { parseLinearGradient } from \"../shared/gradient.ts\";\n\ntype PptxGenJSInstance = import(\"pptxgenjs\").default;\ntype WriteProps = NonNullable<Parameters<PptxGenJSInstance[\"write\"]>[0]>;\ntype WriteFileProps = NonNullable<\n Parameters<PptxGenJSInstance[\"writeFile\"]>[0]\n>;\n\n// JSZip は CJS パッケージのため動的 import で読み込む\nasync function loadJSZip(): Promise<typeof import(\"jszip\")> {\n const mod = await import(\"jszip\");\n /* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return */\n return (mod as any).default ?? mod;\n /* eslint-enable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return */\n}\n\ninterface RegisteredGradientFill {\n /** マーカー色 (6桁大文字 HEX、# なし) */\n marker: string;\n gradient: LinearGradient;\n /** 0-1。指定時は各カラーストップに alpha として反映する */\n opacity?: number;\n}\n\n/** マーカー色の探索開始値。reserveColors で予約済みの色はスキップされる */\nconst MARKER_BASE = 0x0f7a3d;\n\nexport class GradientFillRegistry {\n private readonly reserved = new Set<string>();\n private readonly markerBySpec = new Map<string, string>();\n private readonly registered: RegisteredGradientFill[] = [];\n private nextCandidate = MARKER_BASE;\n\n /**\n * テキスト中に現れる 6桁 HEX をマーカー候補から除外する。\n * 入力 XML 由来のユーザー指定色とマーカーの衝突を防ぐため、\n * register より前に入力 XML 文字列を渡しておく。\n */\n reserveColors(text: string): void {\n for (const match of text.matchAll(/[0-9a-fA-F]{6}/g)) {\n this.reserved.add(match[0].toUpperCase());\n }\n }\n\n /** グラデーションを登録し、対応するマーカー色を返す */\n register(gradient: LinearGradient, opacity?: number): string {\n const specKey = JSON.stringify({ gradient, opacity });\n const existing = this.markerBySpec.get(specKey);\n if (existing) return existing;\n\n let marker: string;\n do {\n marker = this.nextCandidate.toString(16).toUpperCase().padStart(6, \"0\");\n this.nextCandidate = (this.nextCandidate + 1) % 0x1000000;\n } while (this.reserved.has(marker));\n this.reserved.add(marker);\n\n this.markerBySpec.set(specKey, marker);\n this.registered.push({ marker, gradient, opacity });\n return marker;\n }\n\n get isEmpty(): boolean {\n return this.registered.length === 0;\n }\n\n get entries(): readonly RegisteredGradientFill[] {\n return this.registered;\n }\n}\n\n/**\n * backgroundGradient 属性値をパースしてレジストリに登録し、マーカー色を返す。\n * パースできない場合 (スキーマ検証済みのため通常発生しない) は undefined を返す。\n */\nexport function registerBackgroundGradient(\n value: string,\n opacity: number | undefined,\n registry: GradientFillRegistry,\n): string | undefined {\n const gradient = parseLinearGradient(value);\n if (!gradient) return undefined;\n return registry.register(gradient, opacity);\n}\n\n/**\n * textGradient 属性値をパースしてレジストリに登録し、マーカー色を返す。\n * 戻り値のマーカー色を text run の color に渡すと、pptxgenjs が出力する\n * `<a:rPr><a:solidFill><a:srgbClr val=\"マーカー色\"/></a:solidFill></a:rPr>` が\n * 後処理で gradFill に置換され、PowerPoint 上ネイティブの文字グラデーションとして\n * 表示・編集可能になる。\n * パースできない場合 (スキーマ検証済みのため通常発生しない) は undefined を返す。\n */\nexport function registerTextGradient(\n value: string,\n registry: GradientFillRegistry,\n): string | undefined {\n const gradient = parseLinearGradient(value);\n if (!gradient) return undefined;\n return registry.register(gradient);\n}\n\n/**\n * LinearGradient を DrawingML の `<a:gradFill>` 要素に変換する\n *\n * - カラーストップ位置: % → 1/1000 % (0-100000)\n * - 角度: CSS 基準 (0deg = 上向き) → DrawingML 基準 (0 = 右向き、1/60000 度)\n */\nfunction buildGradFillXml(gradient: LinearGradient, opacity?: number): string {\n const alphaXml =\n opacity !== undefined\n ? `<a:alpha val=\"${Math.round(opacity * 100000)}\"/>`\n : \"\";\n const gsXml = gradient.stops\n .map((stop) => {\n const pos = Math.round(stop.position * 1000);\n const srgbClr = alphaXml\n ? `<a:srgbClr val=\"${stop.color}\">${alphaXml}</a:srgbClr>`\n : `<a:srgbClr val=\"${stop.color}\"/>`;\n return `<a:gs pos=\"${pos}\">${srgbClr}</a:gs>`;\n })\n .join(\"\");\n const dmlAngle = (((gradient.angle - 90) % 360) + 360) % 360;\n const ang = Math.round(dmlAngle * 60000);\n return `<a:gradFill flip=\"none\" rotWithShape=\"1\"><a:gsLst>${gsXml}</a:gsLst><a:lin ang=\"${ang}\" scaled=\"0\"/></a:gradFill>`;\n}\n\n/**\n * 出力 zip 内のスライド XML のマーカー solidFill を gradFill に置換する\n */\nexport async function applyGradientFills(\n data: Uint8Array | ArrayBuffer,\n registry: GradientFillRegistry,\n): Promise<import(\"jszip\")> {\n const JSZip = await loadJSZip();\n const zip = await JSZip.loadAsync(data);\n\n const slidePaths = Object.keys(zip.files).filter((path) =>\n /^ppt\\/slides\\/slide\\d+\\.xml$/.test(path),\n );\n for (const path of slidePaths) {\n const file = zip.file(path);\n if (!file) continue;\n let xml = await file.async(\"text\");\n let replaced = false;\n for (const { marker, gradient, opacity } of registry.entries) {\n const target = `<a:solidFill><a:srgbClr val=\"${marker}\"/></a:solidFill>`;\n if (!xml.includes(target)) continue;\n xml = xml.replaceAll(target, buildGradFillXml(gradient, opacity));\n replaced = true;\n }\n if (replaced) {\n zip.file(path, xml);\n }\n }\n return zip;\n}\n\n/**\n * pptx インスタンスの write / writeFile をラップし、\n * 出力時にグラデーション後処理を適用する。\n *\n * pptxgenjs の write と同じ outputType / compression の挙動を再現する。\n * writeFile は Node 環境のみ後処理対象 (ブラウザでは pptxgenjs がダウンロード\n * 処理を行うため、元の実装にフォールバックする)。\n */\nexport function patchPptxWriteForGradientFills(\n pptx: PptxGenJSInstance,\n registry: GradientFillRegistry,\n): void {\n if (registry.isEmpty) return;\n\n const originalWrite = pptx.write.bind(pptx);\n const originalWriteFile = pptx.writeFile.bind(pptx);\n\n const patchedWrite = async (rawProps?: WriteProps | string) => {\n // DEPRECATED: pptxgenjs は write(outputType) の文字列 overload を\n // ランタイムでは今も受け付けるため、同様に正規化する\n const props: WriteProps | undefined =\n typeof rawProps === \"string\"\n ? ({ outputType: rawProps } as WriteProps)\n : rawProps;\n const data = (await originalWrite({\n outputType: \"uint8array\",\n })) as Uint8Array;\n const zip = await applyGradientFills(data, registry);\n\n const outputType = props?.outputType;\n if (outputType === \"STREAM\") {\n return zip.generateAsync({\n type: \"nodebuffer\",\n compression: props?.compression ? \"DEFLATE\" : \"STORE\",\n });\n }\n if (outputType) {\n return zip.generateAsync({ type: outputType });\n }\n return zip.generateAsync({\n type: \"blob\",\n compression: props?.compression ? \"DEFLATE\" : \"STORE\",\n });\n };\n pptx.write = patchedWrite;\n\n const patchedWriteFile = async (rawProps?: WriteFileProps | string) => {\n // DEPRECATED: pptxgenjs は writeFile(fileName) の文字列 overload を\n // ランタイムでは今も受け付けるため、同様に正規化する\n const props: WriteFileProps | undefined =\n typeof rawProps === \"string\" ? { fileName: rawProps } : rawProps;\n const isNode =\n typeof process !== \"undefined\" && Boolean(process.versions?.node);\n if (!isNode) {\n return originalWriteFile(props);\n }\n const rawName = props?.fileName ?? \"Presentation.pptx\";\n const fileName = rawName.toLowerCase().endsWith(\".pptx\")\n ? rawName\n : `${rawName}.pptx`;\n const buffer = (await patchedWrite({\n outputType: \"nodebuffer\",\n compression: props?.compression,\n })) as Buffer;\n const fs = await import(\"fs\");\n await fs.promises.writeFile(fileName, buffer);\n return fileName;\n };\n pptx.writeFile = patchedWriteFile;\n}\n"],"mappings":";;AA0BA,eAAe,YAA6C;CAC1D,MAAM,MAAM,MAAM,OAAO;CAEzB,OAAQ,IAAY,WAAW;AAEjC;;AAWA,MAAM,cAAc;AAEpB,IAAa,uBAAb,MAAkC;CAChC,2BAA4B,IAAI,IAAY;CAC5C,+BAAgC,IAAI,IAAoB;CACxD,aAAwD,CAAC;CACzD,gBAAwB;;;;;;CAOxB,cAAc,MAAoB;EAChC,KAAK,MAAM,SAAS,KAAK,SAAS,iBAAiB,GACjD,KAAK,SAAS,IAAI,MAAM,EAAE,CAAC,YAAY,CAAC;CAE5C;;CAGA,SAAS,UAA0B,SAA0B;EAC3D,MAAM,UAAU,KAAK,UAAU;GAAE;GAAU;EAAQ,CAAC;EACpD,MAAM,WAAW,KAAK,aAAa,IAAI,OAAO;EAC9C,IAAI,UAAU,OAAO;EAErB,IAAI;EACJ,GAAG;GACD,SAAS,KAAK,cAAc,SAAS,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC,SAAS,GAAG,GAAG;GACtE,KAAK,iBAAiB,KAAK,gBAAgB,KAAK;EAClD,SAAS,KAAK,SAAS,IAAI,MAAM;EACjC,KAAK,SAAS,IAAI,MAAM;EAExB,KAAK,aAAa,IAAI,SAAS,MAAM;EACrC,KAAK,WAAW,KAAK;GAAE;GAAQ;GAAU;EAAQ,CAAC;EAClD,OAAO;CACT;CAEA,IAAI,UAAmB;EACrB,OAAO,KAAK,WAAW,WAAW;CACpC;CAEA,IAAI,UAA6C;EAC/C,OAAO,KAAK;CACd;AACF;;;;;AAMA,SAAgB,2BACd,OACA,SACA,UACoB;CACpB,MAAM,WAAW,oBAAoB,KAAK;CAC1C,IAAI,CAAC,UAAU,OAAO,KAAA;CACtB,OAAO,SAAS,SAAS,UAAU,OAAO;AAC5C;;;;;;;;;AAUA,SAAgB,qBACd,OACA,UACoB;CACpB,MAAM,WAAW,oBAAoB,KAAK;CAC1C,IAAI,CAAC,UAAU,OAAO,KAAA;CACtB,OAAO,SAAS,SAAS,QAAQ;AACnC;;;;;;;AAQA,SAAS,iBAAiB,UAA0B,SAA0B;CAC5E,MAAM,WACJ,YAAY,KAAA,IACR,iBAAiB,KAAK,MAAM,UAAU,GAAM,EAAE,OAC9C;CACN,MAAM,QAAQ,SAAS,MACpB,KAAK,SAAS;EAKb,OAAO,cAJK,KAAK,MAAM,KAAK,WAAW,GAIhB,EAAE,IAHT,WACZ,mBAAmB,KAAK,MAAM,IAAI,SAAS,gBAC3C,mBAAmB,KAAK,MAAM,KACG;CACvC,CAAC,CAAC,CACD,KAAK,EAAE;CACV,MAAM,aAAc,SAAS,QAAQ,MAAM,MAAO,OAAO;CAEzD,OAAO,qDAAqD,MAAM,wBADtD,KAAK,MAAM,WAAW,GAC0D,EAAE;AAChG;;;;AAKA,eAAsB,mBACpB,MACA,UAC0B;CAE1B,MAAM,MAAM,OAAM,MADE,UAAU,EAAA,CACN,UAAU,IAAI;CAEtC,MAAM,aAAa,OAAO,KAAK,IAAI,KAAK,CAAC,CAAC,QAAQ,SAChD,+BAA+B,KAAK,IAAI,CAC1C;CACA,KAAK,MAAM,QAAQ,YAAY;EAC7B,MAAM,OAAO,IAAI,KAAK,IAAI;EAC1B,IAAI,CAAC,MAAM;EACX,IAAI,MAAM,MAAM,KAAK,MAAM,MAAM;EACjC,IAAI,WAAW;EACf,KAAK,MAAM,EAAE,QAAQ,UAAU,aAAa,SAAS,SAAS;GAC5D,MAAM,SAAS,gCAAgC,OAAO;GACtD,IAAI,CAAC,IAAI,SAAS,MAAM,GAAG;GAC3B,MAAM,IAAI,WAAW,QAAQ,iBAAiB,UAAU,OAAO,CAAC;GAChE,WAAW;EACb;EACA,IAAI,UACF,IAAI,KAAK,MAAM,GAAG;CAEtB;CACA,OAAO;AACT;;;;;;;;;AAUA,SAAgB,+BACd,MACA,UACM;CACN,IAAI,SAAS,SAAS;CAEtB,MAAM,gBAAgB,KAAK,MAAM,KAAK,IAAI;CAC1C,MAAM,oBAAoB,KAAK,UAAU,KAAK,IAAI;CAElD,MAAM,eAAe,OAAO,aAAmC;EAG7D,MAAM,QACJ,OAAO,aAAa,WACf,EAAE,YAAY,SAAS,IACxB;EAIN,MAAM,MAAM,MAAM,mBAAmB,MAHjB,cAAc,EAChC,YAAY,aACd,CAAC,GAC0C,QAAQ;EAEnD,MAAM,aAAa,OAAO;EAC1B,IAAI,eAAe,UACjB,OAAO,IAAI,cAAc;GACvB,MAAM;GACN,aAAa,OAAO,cAAc,YAAY;EAChD,CAAC;EAEH,IAAI,YACF,OAAO,IAAI,cAAc,EAAE,MAAM,WAAW,CAAC;EAE/C,OAAO,IAAI,cAAc;GACvB,MAAM;GACN,aAAa,OAAO,cAAc,YAAY;EAChD,CAAC;CACH;CACA,KAAK,QAAQ;CAEb,MAAM,mBAAmB,OAAO,aAAuC;EAGrE,MAAM,QACJ,OAAO,aAAa,WAAW,EAAE,UAAU,SAAS,IAAI;EAG1D,IAAI,EADF,OAAO,YAAY,eAAe,QAAQ,QAAQ,UAAU,IAAI,IAEhE,OAAO,kBAAkB,KAAK;EAEhC,MAAM,UAAU,OAAO,YAAY;EACnC,MAAM,WAAW,QAAQ,YAAY,CAAC,CAAC,SAAS,OAAO,IACnD,UACA,GAAG,QAAQ;EACf,MAAM,SAAU,MAAM,aAAa;GACjC,YAAY;GACZ,aAAa,OAAO;EACtB,CAAC;EAED,OAAM,MADW,OAAO,MAAA,CACf,SAAS,UAAU,UAAU,MAAM;EAC5C,OAAO;CACT;CACA,KAAK,YAAY;AACnB"}
@@ -1,10 +1,19 @@
1
- import { pxToIn } from "../units.js";
1
+ import { pxToIn, pxToPt } from "../units.js";
2
2
  //#region src/renderPptx/nodes/icon.ts
3
3
  function renderIconNode(node, ctx) {
4
4
  if (node.variant) {
5
5
  const isCircle = node.variant.startsWith("circle");
6
6
  const isFilled = node.variant.endsWith("-filled");
7
7
  const colorValue = (node.bgColor ?? "#E0E0E0").replace(/^#/, "");
8
+ const variantDefaultLine = isFilled ? void 0 : {
9
+ color: colorValue,
10
+ width: 1.5
11
+ };
12
+ const outlineLine = node.outline ? {
13
+ color: node.outline.color ?? variantDefaultLine?.color ?? "FFFFFF",
14
+ width: node.outline.size !== void 0 ? pxToPt(node.outline.size) : variantDefaultLine?.width ?? 1
15
+ } : variantDefaultLine;
16
+ const glowMarker = node.glow ? ctx.buildContext.glowEffects.register(node.glow) : void 0;
8
17
  const shapeType = isCircle ? "ellipse" : "roundRect";
9
18
  const shapeOptions = {
10
19
  x: pxToIn(node.bgX ?? node.x),
@@ -12,12 +21,10 @@ function renderIconNode(node, ctx) {
12
21
  w: pxToIn(node.bgW ?? node.w),
13
22
  h: pxToIn(node.bgH ?? node.h),
14
23
  fill: isFilled ? { color: colorValue } : { type: "none" },
15
- line: isFilled ? void 0 : {
16
- color: colorValue,
17
- width: 1.5
18
- },
24
+ line: outlineLine,
19
25
  rectRadius: isCircle ? void 0 : .1,
20
- rotate: node.rotate
26
+ rotate: node.rotate,
27
+ objectName: glowMarker
21
28
  };
22
29
  ctx.slide.addShape(shapeType, shapeOptions);
23
30
  }
@@ -1 +1 @@
1
- {"version":3,"file":"icon.js","names":[],"sources":["../../../src/renderPptx/nodes/icon.ts"],"sourcesContent":["import type { PositionedNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { pxToIn } from \"../units.ts\";\n\ntype IconPositionedNode = Extract<PositionedNode, { type: \"icon\" }>;\n\nexport function renderIconNode(\n node: IconPositionedNode,\n ctx: RenderContext,\n): void {\n // variant 指定時は背景図形を描画\n if (node.variant) {\n const isCircle = node.variant.startsWith(\"circle\");\n const isFilled = node.variant.endsWith(\"-filled\");\n const bgColor = node.bgColor ?? \"#E0E0E0\";\n const colorValue = bgColor.replace(/^#/, \"\");\n\n const shapeType = isCircle ? \"ellipse\" : \"roundRect\";\n const shapeOptions: Record<string, unknown> = {\n x: pxToIn(node.bgX ?? node.x),\n y: pxToIn(node.bgY ?? node.y),\n w: pxToIn(node.bgW ?? node.w),\n h: pxToIn(node.bgH ?? node.h),\n fill: isFilled ? { color: colorValue } : { type: \"none\" as const },\n line: isFilled ? undefined : { color: colorValue, width: 1.5 },\n rectRadius: isCircle ? undefined : 0.1,\n rotate: node.rotate,\n };\n\n ctx.slide.addShape(shapeType, shapeOptions);\n }\n\n ctx.slide.addImage({\n data: node.iconImageData,\n x: pxToIn(node.iconX ?? node.x),\n y: pxToIn(node.iconY ?? node.y),\n w: pxToIn(node.iconW ?? node.w),\n h: pxToIn(node.iconH ?? node.h),\n rotate: node.rotate,\n });\n}\n"],"mappings":";;AAMA,SAAgB,eACd,MACA,KACM;CAEN,IAAI,KAAK,SAAS;EAChB,MAAM,WAAW,KAAK,QAAQ,WAAW,QAAQ;EACjD,MAAM,WAAW,KAAK,QAAQ,SAAS,SAAS;EAEhD,MAAM,cADU,KAAK,WAAW,UAAA,CACL,QAAQ,MAAM,EAAE;EAE3C,MAAM,YAAY,WAAW,YAAY;EACzC,MAAM,eAAwC;GAC5C,GAAG,OAAO,KAAK,OAAO,KAAK,CAAC;GAC5B,GAAG,OAAO,KAAK,OAAO,KAAK,CAAC;GAC5B,GAAG,OAAO,KAAK,OAAO,KAAK,CAAC;GAC5B,GAAG,OAAO,KAAK,OAAO,KAAK,CAAC;GAC5B,MAAM,WAAW,EAAE,OAAO,WAAW,IAAI,EAAE,MAAM,OAAgB;GACjE,MAAM,WAAW,KAAA,IAAY;IAAE,OAAO;IAAY,OAAO;GAAI;GAC7D,YAAY,WAAW,KAAA,IAAY;GACnC,QAAQ,KAAK;EACf;EAEA,IAAI,MAAM,SAAS,WAAW,YAAY;CAC5C;CAEA,IAAI,MAAM,SAAS;EACjB,MAAM,KAAK;EACX,GAAG,OAAO,KAAK,SAAS,KAAK,CAAC;EAC9B,GAAG,OAAO,KAAK,SAAS,KAAK,CAAC;EAC9B,GAAG,OAAO,KAAK,SAAS,KAAK,CAAC;EAC9B,GAAG,OAAO,KAAK,SAAS,KAAK,CAAC;EAC9B,QAAQ,KAAK;CACf,CAAC;AACH"}
1
+ {"version":3,"file":"icon.js","names":[],"sources":["../../../src/renderPptx/nodes/icon.ts"],"sourcesContent":["import type { PositionedNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { pxToIn, pxToPt } from \"../units.ts\";\n\ntype IconPositionedNode = Extract<PositionedNode, { type: \"icon\" }>;\n\nexport function renderIconNode(\n node: IconPositionedNode,\n ctx: RenderContext,\n): void {\n // variant 指定時は背景図形を描画\n if (node.variant) {\n const isCircle = node.variant.startsWith(\"circle\");\n const isFilled = node.variant.endsWith(\"-filled\");\n const bgColor = node.bgColor ?? \"#E0E0E0\";\n const colorValue = bgColor.replace(/^#/, \"\");\n\n // 背景図形の line のデフォルト: outlined variant は colorValue / 1.5pt、\n // filled variant は undefined (枠線なし)。\n const variantDefaultLine = isFilled\n ? undefined\n : { color: colorValue, width: 1.5 };\n // outline 指定時は variant のデフォルト line とフィールド単位でマージする。\n // outline 側で省略された属性は variant default の値を引き継ぐので、例えば\n // outlined variant に `outline.color` だけ指定すると、太さは 1.5pt のまま\n // 色だけ outline で上書きされる。\n const outlineLine = node.outline\n ? {\n color: node.outline.color ?? variantDefaultLine?.color ?? \"FFFFFF\",\n width:\n node.outline.size !== undefined\n ? pxToPt(node.outline.size)\n : (variantDefaultLine?.width ?? 1),\n }\n : variantDefaultLine;\n\n const glowMarker = node.glow\n ? ctx.buildContext.glowEffects.register(node.glow)\n : undefined;\n\n const shapeType = isCircle ? \"ellipse\" : \"roundRect\";\n const shapeOptions: Record<string, unknown> = {\n x: pxToIn(node.bgX ?? node.x),\n y: pxToIn(node.bgY ?? node.y),\n w: pxToIn(node.bgW ?? node.w),\n h: pxToIn(node.bgH ?? node.h),\n fill: isFilled ? { color: colorValue } : { type: \"none\" as const },\n line: outlineLine,\n rectRadius: isCircle ? undefined : 0.1,\n rotate: node.rotate,\n objectName: glowMarker,\n };\n\n ctx.slide.addShape(shapeType, shapeOptions);\n }\n\n ctx.slide.addImage({\n data: node.iconImageData,\n x: pxToIn(node.iconX ?? node.x),\n y: pxToIn(node.iconY ?? node.y),\n w: pxToIn(node.iconW ?? node.w),\n h: pxToIn(node.iconH ?? node.h),\n rotate: node.rotate,\n });\n}\n"],"mappings":";;AAMA,SAAgB,eACd,MACA,KACM;CAEN,IAAI,KAAK,SAAS;EAChB,MAAM,WAAW,KAAK,QAAQ,WAAW,QAAQ;EACjD,MAAM,WAAW,KAAK,QAAQ,SAAS,SAAS;EAEhD,MAAM,cADU,KAAK,WAAW,UAAA,CACL,QAAQ,MAAM,EAAE;EAI3C,MAAM,qBAAqB,WACvB,KAAA,IACA;GAAE,OAAO;GAAY,OAAO;EAAI;EAKpC,MAAM,cAAc,KAAK,UACrB;GACE,OAAO,KAAK,QAAQ,SAAS,oBAAoB,SAAS;GAC1D,OACE,KAAK,QAAQ,SAAS,KAAA,IAClB,OAAO,KAAK,QAAQ,IAAI,IACvB,oBAAoB,SAAS;EACtC,IACA;EAEJ,MAAM,aAAa,KAAK,OACpB,IAAI,aAAa,YAAY,SAAS,KAAK,IAAI,IAC/C,KAAA;EAEJ,MAAM,YAAY,WAAW,YAAY;EACzC,MAAM,eAAwC;GAC5C,GAAG,OAAO,KAAK,OAAO,KAAK,CAAC;GAC5B,GAAG,OAAO,KAAK,OAAO,KAAK,CAAC;GAC5B,GAAG,OAAO,KAAK,OAAO,KAAK,CAAC;GAC5B,GAAG,OAAO,KAAK,OAAO,KAAK,CAAC;GAC5B,MAAM,WAAW,EAAE,OAAO,WAAW,IAAI,EAAE,MAAM,OAAgB;GACjE,MAAM;GACN,YAAY,WAAW,KAAA,IAAY;GACnC,QAAQ,KAAK;GACb,YAAY;EACd;EAEA,IAAI,MAAM,SAAS,WAAW,YAAY;CAC5C;CAEA,IAAI,MAAM,SAAS;EACjB,MAAM,KAAK;EACX,GAAG,OAAO,KAAK,SAAS,KAAK,CAAC;EAC9B,GAAG,OAAO,KAAK,SAAS,KAAK,CAAC;EAC9B,GAAG,OAAO,KAAK,SAAS,KAAK,CAAC;EAC9B,GAAG,OAAO,KAAK,SAAS,KAAK,CAAC;EAC9B,QAAQ,KAAK;CACf,CAAC;AACH"}
@@ -3,16 +3,38 @@ import { getContentAreaIn } from "../utils/contentArea.js";
3
3
  import { convertStrike, convertUnderline } from "../textOptions.js";
4
4
  import { convertBorderLine, convertShadow } from "../utils/visualStyle.js";
5
5
  //#region src/renderPptx/nodes/shape.ts
6
+ /**
7
+ * outline (Text と同じ書式の `outline.size` / `outline.color`) と
8
+ * 既存 `line` 属性 (`line.color` / `line.width` / `line.dashType`) を
9
+ * 1 つの BorderStyle にマージする。
10
+ *
11
+ * フィールド単位のマージで、`outline` の指定があるフィールドは `line` を
12
+ * 上書きするが、`outline` 側で省略されたフィールドは `line` の値を引き継ぎ、
13
+ * `line` にも値が無い場合は Text outline と同じ既定値 (`width: 1pt 相当` /
14
+ * `color: FFFFFF`) を採用する。`dashType` は `outline` に対応フィールドが
15
+ * 無いため `line.dashType` をそのまま使う。
16
+ */
17
+ function resolveShapeLine(line, outline) {
18
+ if (!outline) return line;
19
+ return {
20
+ color: outline.color ?? line?.color ?? "FFFFFF",
21
+ width: outline.size ?? line?.width ?? 1,
22
+ dashType: line?.dashType
23
+ };
24
+ }
6
25
  function renderShapeNode(node, ctx) {
26
+ const lineSpec = resolveShapeLine(node.line, node.outline);
27
+ const glowMarker = node.glow ? ctx.buildContext.glowEffects.register(node.glow) : void 0;
7
28
  const shapeOptions = {
8
29
  ...getContentAreaIn(node),
9
30
  fill: node.fill ? {
10
31
  color: node.fill.color,
11
32
  transparency: node.fill.transparency
12
33
  } : void 0,
13
- line: node.line ? convertBorderLine(node.line) : void 0,
34
+ line: lineSpec ? convertBorderLine(lineSpec) : void 0,
14
35
  shadow: convertShadow(node.shadow),
15
- rotate: node.rotate
36
+ rotate: node.rotate,
37
+ objectName: glowMarker
16
38
  };
17
39
  if (node.text) {
18
40
  const fontSizePx = node.fontSize ?? 24;
@@ -1 +1 @@
1
- {"version":3,"file":"shape.js","names":[],"sources":["../../../src/renderPptx/nodes/shape.ts"],"sourcesContent":["import type { PositionedNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { pxToPt } from \"../units.ts\";\nimport { convertUnderline, convertStrike } from \"../textOptions.ts\";\nimport { getContentAreaIn } from \"../utils/contentArea.ts\";\nimport { convertBorderLine, convertShadow } from \"../utils/visualStyle.ts\";\n\ntype ShapePositionedNode = Extract<PositionedNode, { type: \"shape\" }>;\n\nexport function renderShapeNode(\n node: ShapePositionedNode,\n ctx: RenderContext,\n): void {\n const shapeOptions = {\n ...getContentAreaIn(node),\n fill: node.fill\n ? {\n color: node.fill.color,\n transparency: node.fill.transparency,\n }\n : undefined,\n line: node.line ? convertBorderLine(node.line) : undefined,\n shadow: convertShadow(node.shadow),\n rotate: node.rotate,\n };\n\n if (node.text) {\n const fontSizePx = node.fontSize ?? 24;\n const lineHeight = node.lineHeight ?? 1.3;\n // テキストがある場合:addTextでshapeを指定\n ctx.slide.addText(node.text, {\n ...shapeOptions,\n shape: node.shapeType,\n fontSize: pxToPt(fontSizePx),\n fontFace: node.fontFamily ?? \"Noto Sans JP\",\n color: node.color,\n bold: node.bold,\n italic: node.italic,\n underline: convertUnderline(node.underline),\n strike: convertStrike(node.strike),\n subscript: node.subscript,\n superscript: node.superscript,\n highlight: node.highlight,\n align: node.textAlign ?? \"center\",\n valign: \"middle\" as const,\n // Text と同じく行送りを固定値 (spcPts) で指定し、計測高さ\n // (行数 × fontSize × lineHeight) と実描画の行高さを一致させる (#846)。\n // valign middle のためテキストブロックは枠内中央に配置され、\n // Text のような描画 y 補正は不要\n lineSpacing: pxToPt(fontSizePx * lineHeight),\n });\n } else {\n // テキストがない場合:addShapeを使用\n ctx.slide.addShape(node.shapeType, shapeOptions);\n }\n}\n"],"mappings":";;;;;AASA,SAAgB,gBACd,MACA,KACM;CACN,MAAM,eAAe;EACnB,GAAG,iBAAiB,IAAI;EACxB,MAAM,KAAK,OACP;GACE,OAAO,KAAK,KAAK;GACjB,cAAc,KAAK,KAAK;EAC1B,IACA,KAAA;EACJ,MAAM,KAAK,OAAO,kBAAkB,KAAK,IAAI,IAAI,KAAA;EACjD,QAAQ,cAAc,KAAK,MAAM;EACjC,QAAQ,KAAK;CACf;CAEA,IAAI,KAAK,MAAM;EACb,MAAM,aAAa,KAAK,YAAY;EACpC,MAAM,aAAa,KAAK,cAAc;EAEtC,IAAI,MAAM,QAAQ,KAAK,MAAM;GAC3B,GAAG;GACH,OAAO,KAAK;GACZ,UAAU,OAAO,UAAU;GAC3B,UAAU,KAAK,cAAc;GAC7B,OAAO,KAAK;GACZ,MAAM,KAAK;GACX,QAAQ,KAAK;GACb,WAAW,iBAAiB,KAAK,SAAS;GAC1C,QAAQ,cAAc,KAAK,MAAM;GACjC,WAAW,KAAK;GAChB,aAAa,KAAK;GAClB,WAAW,KAAK;GAChB,OAAO,KAAK,aAAa;GACzB,QAAQ;GAKR,aAAa,OAAO,aAAa,UAAU;EAC7C,CAAC;CACH,OAEE,IAAI,MAAM,SAAS,KAAK,WAAW,YAAY;AAEnD"}
1
+ {"version":3,"file":"shape.js","names":[],"sources":["../../../src/renderPptx/nodes/shape.ts"],"sourcesContent":["import type { BorderStyle, PositionedNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { pxToPt } from \"../units.ts\";\nimport { convertUnderline, convertStrike } from \"../textOptions.ts\";\nimport { getContentAreaIn } from \"../utils/contentArea.ts\";\nimport { convertBorderLine, convertShadow } from \"../utils/visualStyle.ts\";\n\ntype ShapePositionedNode = Extract<PositionedNode, { type: \"shape\" }>;\n\n/**\n * outline (Text と同じ書式の `outline.size` / `outline.color`) と\n * 既存 `line` 属性 (`line.color` / `line.width` / `line.dashType`) を\n * 1 つの BorderStyle にマージする。\n *\n * フィールド単位のマージで、`outline` の指定があるフィールドは `line` を\n * 上書きするが、`outline` 側で省略されたフィールドは `line` の値を引き継ぎ、\n * `line` にも値が無い場合は Text outline と同じ既定値 (`width: 1pt 相当` /\n * `color: FFFFFF`) を採用する。`dashType` は `outline` に対応フィールドが\n * 無いため `line.dashType` をそのまま使う。\n */\nfunction resolveShapeLine(\n line: BorderStyle | undefined,\n outline: { size?: number; color?: string } | undefined,\n): BorderStyle | undefined {\n if (!outline) return line;\n return {\n color: outline.color ?? line?.color ?? \"FFFFFF\",\n width: outline.size ?? line?.width ?? 1,\n dashType: line?.dashType,\n };\n}\n\nexport function renderShapeNode(\n node: ShapePositionedNode,\n ctx: RenderContext,\n): void {\n const lineSpec = resolveShapeLine(node.line, node.outline);\n const glowMarker = node.glow\n ? ctx.buildContext.glowEffects.register(node.glow)\n : undefined;\n\n const shapeOptions = {\n ...getContentAreaIn(node),\n fill: node.fill\n ? {\n color: node.fill.color,\n transparency: node.fill.transparency,\n }\n : undefined,\n line: lineSpec ? convertBorderLine(lineSpec) : undefined,\n shadow: convertShadow(node.shadow),\n rotate: node.rotate,\n objectName: glowMarker,\n };\n\n if (node.text) {\n const fontSizePx = node.fontSize ?? 24;\n const lineHeight = node.lineHeight ?? 1.3;\n // テキストがある場合:addTextでshapeを指定\n ctx.slide.addText(node.text, {\n ...shapeOptions,\n shape: node.shapeType,\n fontSize: pxToPt(fontSizePx),\n fontFace: node.fontFamily ?? \"Noto Sans JP\",\n color: node.color,\n bold: node.bold,\n italic: node.italic,\n underline: convertUnderline(node.underline),\n strike: convertStrike(node.strike),\n subscript: node.subscript,\n superscript: node.superscript,\n highlight: node.highlight,\n align: node.textAlign ?? \"center\",\n valign: \"middle\" as const,\n // Text と同じく行送りを固定値 (spcPts) で指定し、計測高さ\n // (行数 × fontSize × lineHeight) と実描画の行高さを一致させる (#846)。\n // valign middle のためテキストブロックは枠内中央に配置され、\n // Text のような描画 y 補正は不要\n lineSpacing: pxToPt(fontSizePx * lineHeight),\n });\n } else {\n // テキストがない場合:addShapeを使用\n ctx.slide.addShape(node.shapeType, shapeOptions);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAoBA,SAAS,iBACP,MACA,SACyB;CACzB,IAAI,CAAC,SAAS,OAAO;CACrB,OAAO;EACL,OAAO,QAAQ,SAAS,MAAM,SAAS;EACvC,OAAO,QAAQ,QAAQ,MAAM,SAAS;EACtC,UAAU,MAAM;CAClB;AACF;AAEA,SAAgB,gBACd,MACA,KACM;CACN,MAAM,WAAW,iBAAiB,KAAK,MAAM,KAAK,OAAO;CACzD,MAAM,aAAa,KAAK,OACpB,IAAI,aAAa,YAAY,SAAS,KAAK,IAAI,IAC/C,KAAA;CAEJ,MAAM,eAAe;EACnB,GAAG,iBAAiB,IAAI;EACxB,MAAM,KAAK,OACP;GACE,OAAO,KAAK,KAAK;GACjB,cAAc,KAAK,KAAK;EAC1B,IACA,KAAA;EACJ,MAAM,WAAW,kBAAkB,QAAQ,IAAI,KAAA;EAC/C,QAAQ,cAAc,KAAK,MAAM;EACjC,QAAQ,KAAK;EACb,YAAY;CACd;CAEA,IAAI,KAAK,MAAM;EACb,MAAM,aAAa,KAAK,YAAY;EACpC,MAAM,aAAa,KAAK,cAAc;EAEtC,IAAI,MAAM,QAAQ,KAAK,MAAM;GAC3B,GAAG;GACH,OAAO,KAAK;GACZ,UAAU,OAAO,UAAU;GAC3B,UAAU,KAAK,cAAc;GAC7B,OAAO,KAAK;GACZ,MAAM,KAAK;GACX,QAAQ,KAAK;GACb,WAAW,iBAAiB,KAAK,SAAS;GAC1C,QAAQ,cAAc,KAAK,MAAM;GACjC,WAAW,KAAK;GAChB,aAAa,KAAK;GAClB,WAAW,KAAK;GAChB,OAAO,KAAK,aAAa;GACzB,QAAQ;GAKR,aAAa,OAAO,aAAa,UAAU;EAC7C,CAAC;CACH,OAEE,IAAI,MAAM,SAAS,KAAK,WAAW,YAAY;AAEnD"}
@@ -1,8 +1,10 @@
1
1
  import { pxToPt } from "../units.js";
2
2
  import { convertGlow, convertOutline, convertStrike, convertUnderline, createTextOptions, resolveSubSup } from "../textOptions.js";
3
+ import { registerTextGradient } from "../gradientFills.js";
3
4
  //#region src/renderPptx/nodes/text.ts
4
5
  function renderTextNode(node, ctx) {
5
6
  const textOptions = createTextOptions(node);
7
+ const textGradientMarker = node.textGradient ? registerTextGradient(node.textGradient, ctx.buildContext.gradientFills) : void 0;
6
8
  if (node.runs && node.runs.length > 0) {
7
9
  const fontSizePx = node.fontSize ?? 24;
8
10
  const fontFamily = node.fontFamily ?? "Noto Sans JP";
@@ -15,7 +17,7 @@ function renderTextNode(node, ctx) {
15
17
  options: {
16
18
  fontSize: pxToPt(runFontSizePx),
17
19
  fontFace: run.fontFamily ?? fontFamily,
18
- color: run.color ?? node.color,
20
+ color: textGradientMarker ?? run.color ?? node.color,
19
21
  bold: run.bold ?? node.bold,
20
22
  italic: run.italic ?? node.italic,
21
23
  underline: convertUnderline(run.underline ?? node.underline),
@@ -41,7 +43,10 @@ function renderTextNode(node, ctx) {
41
43
  margin: textOptions.margin,
42
44
  lineSpacing: textOptions.lineSpacing
43
45
  });
44
- } else ctx.slide.addText(node.text ?? "", textOptions);
46
+ } else ctx.slide.addText(node.text ?? "", {
47
+ ...textOptions,
48
+ color: textGradientMarker ?? textOptions.color
49
+ });
45
50
  }
46
51
  //#endregion
47
52
  export { renderTextNode };
@@ -1 +1 @@
1
- {"version":3,"file":"text.js","names":[],"sources":["../../../src/renderPptx/nodes/text.ts"],"sourcesContent":["import type { PositionedNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport {\n createTextOptions,\n convertUnderline,\n convertStrike,\n convertGlow,\n convertOutline,\n resolveSubSup,\n} from \"../textOptions.ts\";\nimport { pxToPt } from \"../units.ts\";\n\ntype TextPositionedNode = Extract<PositionedNode, { type: \"text\" }>;\n\nexport function renderTextNode(\n node: TextPositionedNode,\n ctx: RenderContext,\n): void {\n const textOptions = createTextOptions(node);\n\n if (node.runs && node.runs.length > 0) {\n const fontSizePx = node.fontSize ?? 24;\n const fontFamily = node.fontFamily ?? \"Noto Sans JP\";\n const textItems = node.runs.map((run) => {\n const letterSpacingPx = run.letterSpacing ?? node.letterSpacing;\n const runFontSizePx = run.fontSize ?? fontSizePx;\n const subSup = resolveSubSup(run, node);\n return {\n text: run.text,\n options: {\n fontSize: pxToPt(runFontSizePx),\n fontFace: run.fontFamily ?? fontFamily,\n color: run.color ?? node.color,\n bold: run.bold ?? node.bold,\n italic: run.italic ?? node.italic,\n underline: convertUnderline(run.underline ?? node.underline),\n strike: convertStrike(run.strike ?? node.strike),\n subscript: subSup.subscript,\n superscript: subSup.superscript,\n highlight: run.highlight ?? node.highlight,\n // glow / outline はノード単位指定のみ (run 単位はスコープ外)\n glow: convertGlow(node.glow),\n outline: convertOutline(node.outline),\n charSpacing:\n letterSpacingPx !== undefined ? pxToPt(letterSpacingPx) : undefined,\n ...(run.href ? { hyperlink: { url: run.href } } : {}),\n },\n };\n });\n ctx.slide.addText(textItems, {\n x: textOptions.x,\n y: textOptions.y,\n w: textOptions.w,\n h: textOptions.h,\n rotate: textOptions.rotate,\n align: textOptions.align,\n valign: textOptions.valign,\n margin: textOptions.margin,\n lineSpacing: textOptions.lineSpacing,\n });\n } else {\n ctx.slide.addText(node.text ?? \"\", textOptions);\n }\n}\n"],"mappings":";;;AAcA,SAAgB,eACd,MACA,KACM;CACN,MAAM,cAAc,kBAAkB,IAAI;CAE1C,IAAI,KAAK,QAAQ,KAAK,KAAK,SAAS,GAAG;EACrC,MAAM,aAAa,KAAK,YAAY;EACpC,MAAM,aAAa,KAAK,cAAc;EACtC,MAAM,YAAY,KAAK,KAAK,KAAK,QAAQ;GACvC,MAAM,kBAAkB,IAAI,iBAAiB,KAAK;GAClD,MAAM,gBAAgB,IAAI,YAAY;GACtC,MAAM,SAAS,cAAc,KAAK,IAAI;GACtC,OAAO;IACL,MAAM,IAAI;IACV,SAAS;KACP,UAAU,OAAO,aAAa;KAC9B,UAAU,IAAI,cAAc;KAC5B,OAAO,IAAI,SAAS,KAAK;KACzB,MAAM,IAAI,QAAQ,KAAK;KACvB,QAAQ,IAAI,UAAU,KAAK;KAC3B,WAAW,iBAAiB,IAAI,aAAa,KAAK,SAAS;KAC3D,QAAQ,cAAc,IAAI,UAAU,KAAK,MAAM;KAC/C,WAAW,OAAO;KAClB,aAAa,OAAO;KACpB,WAAW,IAAI,aAAa,KAAK;KAEjC,MAAM,YAAY,KAAK,IAAI;KAC3B,SAAS,eAAe,KAAK,OAAO;KACpC,aACE,oBAAoB,KAAA,IAAY,OAAO,eAAe,IAAI,KAAA;KAC5D,GAAI,IAAI,OAAO,EAAE,WAAW,EAAE,KAAK,IAAI,KAAK,EAAE,IAAI,CAAC;IACrD;GACF;EACF,CAAC;EACD,IAAI,MAAM,QAAQ,WAAW;GAC3B,GAAG,YAAY;GACf,GAAG,YAAY;GACf,GAAG,YAAY;GACf,GAAG,YAAY;GACf,QAAQ,YAAY;GACpB,OAAO,YAAY;GACnB,QAAQ,YAAY;GACpB,QAAQ,YAAY;GACpB,aAAa,YAAY;EAC3B,CAAC;CACH,OACE,IAAI,MAAM,QAAQ,KAAK,QAAQ,IAAI,WAAW;AAElD"}
1
+ {"version":3,"file":"text.js","names":[],"sources":["../../../src/renderPptx/nodes/text.ts"],"sourcesContent":["import type { PositionedNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport {\n createTextOptions,\n convertUnderline,\n convertStrike,\n convertGlow,\n convertOutline,\n resolveSubSup,\n} from \"../textOptions.ts\";\nimport { registerTextGradient } from \"../gradientFills.ts\";\nimport { pxToPt } from \"../units.ts\";\n\ntype TextPositionedNode = Extract<PositionedNode, { type: \"text\" }>;\n\nexport function renderTextNode(\n node: TextPositionedNode,\n ctx: RenderContext,\n): void {\n const textOptions = createTextOptions(node);\n\n // textGradient はマーカー色で text run color に適用し、\n // 出力時の後処理で gradFill に置換される (gradientFills.ts 参照)。\n // node 単位の指定として全 run の color を上書きする (run 単位指定はスコープ外)。\n const textGradientMarker = node.textGradient\n ? registerTextGradient(node.textGradient, ctx.buildContext.gradientFills)\n : undefined;\n\n if (node.runs && node.runs.length > 0) {\n const fontSizePx = node.fontSize ?? 24;\n const fontFamily = node.fontFamily ?? \"Noto Sans JP\";\n const textItems = node.runs.map((run) => {\n const letterSpacingPx = run.letterSpacing ?? node.letterSpacing;\n const runFontSizePx = run.fontSize ?? fontSizePx;\n const subSup = resolveSubSup(run, node);\n return {\n text: run.text,\n options: {\n fontSize: pxToPt(runFontSizePx),\n fontFace: run.fontFamily ?? fontFamily,\n color: textGradientMarker ?? run.color ?? node.color,\n bold: run.bold ?? node.bold,\n italic: run.italic ?? node.italic,\n underline: convertUnderline(run.underline ?? node.underline),\n strike: convertStrike(run.strike ?? node.strike),\n subscript: subSup.subscript,\n superscript: subSup.superscript,\n highlight: run.highlight ?? node.highlight,\n // glow / outline はノード単位指定のみ (run 単位はスコープ外)\n glow: convertGlow(node.glow),\n outline: convertOutline(node.outline),\n charSpacing:\n letterSpacingPx !== undefined ? pxToPt(letterSpacingPx) : undefined,\n ...(run.href ? { hyperlink: { url: run.href } } : {}),\n },\n };\n });\n ctx.slide.addText(textItems, {\n x: textOptions.x,\n y: textOptions.y,\n w: textOptions.w,\n h: textOptions.h,\n rotate: textOptions.rotate,\n align: textOptions.align,\n valign: textOptions.valign,\n margin: textOptions.margin,\n lineSpacing: textOptions.lineSpacing,\n });\n } else {\n ctx.slide.addText(node.text ?? \"\", {\n ...textOptions,\n color: textGradientMarker ?? textOptions.color,\n });\n }\n}\n"],"mappings":";;;;AAeA,SAAgB,eACd,MACA,KACM;CACN,MAAM,cAAc,kBAAkB,IAAI;CAK1C,MAAM,qBAAqB,KAAK,eAC5B,qBAAqB,KAAK,cAAc,IAAI,aAAa,aAAa,IACtE,KAAA;CAEJ,IAAI,KAAK,QAAQ,KAAK,KAAK,SAAS,GAAG;EACrC,MAAM,aAAa,KAAK,YAAY;EACpC,MAAM,aAAa,KAAK,cAAc;EACtC,MAAM,YAAY,KAAK,KAAK,KAAK,QAAQ;GACvC,MAAM,kBAAkB,IAAI,iBAAiB,KAAK;GAClD,MAAM,gBAAgB,IAAI,YAAY;GACtC,MAAM,SAAS,cAAc,KAAK,IAAI;GACtC,OAAO;IACL,MAAM,IAAI;IACV,SAAS;KACP,UAAU,OAAO,aAAa;KAC9B,UAAU,IAAI,cAAc;KAC5B,OAAO,sBAAsB,IAAI,SAAS,KAAK;KAC/C,MAAM,IAAI,QAAQ,KAAK;KACvB,QAAQ,IAAI,UAAU,KAAK;KAC3B,WAAW,iBAAiB,IAAI,aAAa,KAAK,SAAS;KAC3D,QAAQ,cAAc,IAAI,UAAU,KAAK,MAAM;KAC/C,WAAW,OAAO;KAClB,aAAa,OAAO;KACpB,WAAW,IAAI,aAAa,KAAK;KAEjC,MAAM,YAAY,KAAK,IAAI;KAC3B,SAAS,eAAe,KAAK,OAAO;KACpC,aACE,oBAAoB,KAAA,IAAY,OAAO,eAAe,IAAI,KAAA;KAC5D,GAAI,IAAI,OAAO,EAAE,WAAW,EAAE,KAAK,IAAI,KAAK,EAAE,IAAI,CAAC;IACrD;GACF;EACF,CAAC;EACD,IAAI,MAAM,QAAQ,WAAW;GAC3B,GAAG,YAAY;GACf,GAAG,YAAY;GACf,GAAG,YAAY;GACf,GAAG,YAAY;GACf,QAAQ,YAAY;GACpB,OAAO,YAAY;GACnB,QAAQ,YAAY;GACpB,QAAQ,YAAY;GACpB,aAAa,YAAY;EAC3B,CAAC;CACH,OACE,IAAI,MAAM,QAAQ,KAAK,QAAQ,IAAI;EACjC,GAAG;EACH,OAAO,sBAAsB,YAAY;CAC3C,CAAC;AAEL"}
@@ -3,8 +3,8 @@ import { resolveBoxSpacing } from "../shared/boxSpacing.js";
3
3
  import { getNodeDef } from "../registry/nodeRegistry.js";
4
4
  import { pxToIn, pxToPt } from "./units.js";
5
5
  import { convertStrike, convertUnderline } from "./textOptions.js";
6
- import "../registry/index.js";
7
6
  import { registerBackgroundGradient } from "./gradientFills.js";
7
+ import "../registry/index.js";
8
8
  import { renderBackgroundAndBorder, renderBorderOnly } from "./utils/backgroundBorder.js";
9
9
  //#region src/renderPptx/renderPptx.ts
10
10
  async function loadPptxGenJS() {
@@ -1,6 +1,13 @@
1
+ const EMU_PER_IN = 914400;
1
2
  const pxToIn = (px) => px / 96;
2
3
  const pxToPt = (px) => px * 72 / 96;
3
4
  /**
5
+ * px を DrawingML の EMU (English Metric Unit) に変換する。
6
+ * 1 inch = 914400 EMU、96 DPI 基準で 1 px = 9525 EMU。
7
+ * `<a:glow rad="...">` など EMU を直接埋め込む XML 後処理で使う。
8
+ */
9
+ const pxToEmu = (px) => px * EMU_PER_IN / 96;
10
+ /**
4
11
  * px 単位の矩形を pptxgenjs の位置オプション (inch 単位の x/y/w/h) に
5
12
  * まとめて変換する。addShape / addText 等のオプションへ spread して使う。
6
13
  */
@@ -11,6 +18,6 @@ const rectPxToIn = (rect) => ({
11
18
  h: pxToIn(rect.h)
12
19
  });
13
20
  //#endregion
14
- export { pxToIn, pxToPt, rectPxToIn };
21
+ export { pxToEmu, pxToIn, pxToPt, rectPxToIn };
15
22
 
16
23
  //# sourceMappingURL=units.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"units.js","names":[],"sources":["../../src/renderPptx/units.ts"],"sourcesContent":["export const PX_PER_IN = 96;\n\nexport const pxToIn = (px: number) => px / PX_PER_IN;\n\nexport const pxToPt = (px: number) => (px * 72) / PX_PER_IN;\n\n/**\n * px 単位の矩形を pptxgenjs の位置オプション (inch 単位の x/y/w/h) に\n * まとめて変換する。addShape / addText 等のオプションへ spread して使う。\n */\nexport const rectPxToIn = (rect: {\n x: number;\n y: number;\n w: number;\n h: number;\n}) => ({\n x: pxToIn(rect.x),\n y: pxToIn(rect.y),\n w: pxToIn(rect.w),\n h: pxToIn(rect.h),\n});\n"],"mappings":"AAEA,MAAa,UAAU,OAAe,KAAA;AAEtC,MAAa,UAAU,OAAgB,KAAK,KAAA;;;;;AAM5C,MAAa,cAAc,UAKpB;CACL,GAAG,OAAO,KAAK,CAAC;CAChB,GAAG,OAAO,KAAK,CAAC;CAChB,GAAG,OAAO,KAAK,CAAC;CAChB,GAAG,OAAO,KAAK,CAAC;AAClB"}
1
+ {"version":3,"file":"units.js","names":[],"sources":["../../src/renderPptx/units.ts"],"sourcesContent":["export const PX_PER_IN = 96;\nexport const EMU_PER_IN = 914400;\n\nexport const pxToIn = (px: number) => px / PX_PER_IN;\n\nexport const pxToPt = (px: number) => (px * 72) / PX_PER_IN;\n\n/**\n * px を DrawingML の EMU (English Metric Unit) に変換する。\n * 1 inch = 914400 EMU、96 DPI 基準で 1 px = 9525 EMU。\n * `<a:glow rad=\"...\">` など EMU を直接埋め込む XML 後処理で使う。\n */\nexport const pxToEmu = (px: number) => (px * EMU_PER_IN) / PX_PER_IN;\n\n/**\n * px 単位の矩形を pptxgenjs の位置オプション (inch 単位の x/y/w/h) に\n * まとめて変換する。addShape / addText 等のオプションへ spread して使う。\n */\nexport const rectPxToIn = (rect: {\n x: number;\n y: number;\n w: number;\n h: number;\n}) => ({\n x: pxToIn(rect.x),\n y: pxToIn(rect.y),\n w: pxToIn(rect.w),\n h: pxToIn(rect.h),\n});\n"],"mappings":"AACA,MAAa,aAAa;AAE1B,MAAa,UAAU,OAAe,KAAA;AAEtC,MAAa,UAAU,OAAgB,KAAK,KAAA;;;;;;AAO5C,MAAa,WAAW,OAAgB,KAAK,aAAA;;;;;AAM7C,MAAa,cAAc,UAKpB;CACL,GAAG,OAAO,KAAK,CAAC;CAChB,GAAG,OAAO,KAAK,CAAC;CAChB,GAAG,OAAO,KAAK,CAAC;CAChB,GAAG,OAAO,KAAK,CAAC;AAClB"}
@@ -1,7 +1,7 @@
1
1
  import { getImageData } from "../../shared/measureImage.js";
2
2
  import { pxToIn, rectPxToIn } from "../units.js";
3
- import { BORDER_SIDES, convertBorderLine, convertShadow, hasVisibleBorder, resolveBackgroundFill, resolvePerSideBorders, resolveRectRadius } from "./visualStyle.js";
4
3
  import { registerBackgroundGradient } from "../gradientFills.js";
4
+ import { BORDER_SIDES, convertBorderLine, convertShadow, hasVisibleBorder, resolveBackgroundFill, resolvePerSideBorders, resolveRectRadius } from "./visualStyle.js";
5
5
  //#region src/renderPptx/utils/backgroundBorder.ts
6
6
  /**
7
7
  * ノードの背景色・背景画像・ボーダー・影を描画する
package/dist/types.d.ts CHANGED
@@ -303,6 +303,7 @@ declare const textNodeSchema: z.ZodObject<{
303
303
  rotate: z.ZodOptional<z.ZodNumber>;
304
304
  fontSize: z.ZodOptional<z.ZodNumber>;
305
305
  color: z.ZodOptional<z.ZodString>;
306
+ textGradient: z.ZodOptional<z.ZodString>;
306
307
  textAlign: z.ZodOptional<z.ZodEnum<{
307
308
  right: "right";
308
309
  left: "left";
@@ -1078,6 +1079,15 @@ declare const iconNodeSchema: z.ZodObject<{
1078
1079
  "square-outlined": "square-outlined";
1079
1080
  }>>;
1080
1081
  bgColor: z.ZodOptional<z.ZodString>;
1082
+ glow: z.ZodOptional<z.ZodObject<{
1083
+ size: z.ZodOptional<z.ZodNumber>;
1084
+ opacity: z.ZodOptional<z.ZodNumber>;
1085
+ color: z.ZodOptional<z.ZodString>;
1086
+ }, z.core.$strip>>;
1087
+ outline: z.ZodOptional<z.ZodObject<{
1088
+ size: z.ZodOptional<z.ZodNumber>;
1089
+ color: z.ZodOptional<z.ZodString>;
1090
+ }, z.core.$strip>>;
1081
1091
  rotate: z.ZodOptional<z.ZodNumber>;
1082
1092
  }, z.core.$strip>;
1083
1093
  type IconNode = z.infer<typeof iconNodeSchema>;
@@ -1752,6 +1762,15 @@ declare const shapeNodeSchema: z.ZodObject<{
1752
1762
  sysDot: "sysDot";
1753
1763
  }>>;
1754
1764
  }, z.core.$strip>>;
1765
+ glow: z.ZodOptional<z.ZodObject<{
1766
+ size: z.ZodOptional<z.ZodNumber>;
1767
+ opacity: z.ZodOptional<z.ZodNumber>;
1768
+ color: z.ZodOptional<z.ZodString>;
1769
+ }, z.core.$strip>>;
1770
+ outline: z.ZodOptional<z.ZodObject<{
1771
+ size: z.ZodOptional<z.ZodNumber>;
1772
+ color: z.ZodOptional<z.ZodString>;
1773
+ }, z.core.$strip>>;
1755
1774
  fontSize: z.ZodOptional<z.ZodNumber>;
1756
1775
  color: z.ZodOptional<z.ZodString>;
1757
1776
  textAlign: z.ZodOptional<z.ZodEnum<{
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"mappings":"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"}
package/dist/types.js CHANGED
@@ -1,5 +1,5 @@
1
- import { ICON_DATA } from "./icons/iconData.js";
2
1
  import { parseLinearGradient } from "./shared/gradient.js";
2
+ import { ICON_DATA } from "./icons/iconData.js";
3
3
  import { z } from "zod";
4
4
  //#region src/types.ts
5
5
  const lengthSchema = z.union([
@@ -353,6 +353,7 @@ const textNodeSchema = basePOMNodeSchema.extend({
353
353
  rotate: z.number().optional(),
354
354
  fontSize: z.number().optional(),
355
355
  color: z.string().optional(),
356
+ textGradient: backgroundGradientSchema.optional(),
356
357
  textAlign: z.enum([
357
358
  "left",
358
359
  "center",
@@ -459,6 +460,8 @@ const iconNodeSchema = basePOMNodeSchema.extend({
459
460
  color: iconColorSchema,
460
461
  variant: iconVariantSchema,
461
462
  bgColor: iconColorSchema,
463
+ glow: textGlowSchema.optional(),
464
+ outline: textOutlineSchema.optional(),
462
465
  rotate: z.number().optional()
463
466
  });
464
467
  const svgNodeSchema = basePOMNodeSchema.extend({
@@ -509,6 +512,8 @@ const shapeNodeSchema = basePOMNodeSchema.extend({
509
512
  rotate: z.number().optional(),
510
513
  fill: fillStyleSchema.optional(),
511
514
  line: borderStyleSchema.optional(),
515
+ glow: textGlowSchema.optional(),
516
+ outline: textOutlineSchema.optional(),
512
517
  fontSize: z.number().optional(),
513
518
  color: z.string().optional(),
514
519
  textAlign: z.enum([