@hirokisakabe/pom 9.1.0 → 9.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/buildContext.js +2 -4
  2. package/dist/buildContext.js.map +1 -1
  3. package/dist/buildPptx.d.ts.map +1 -1
  4. package/dist/buildPptx.js +2 -6
  5. package/dist/buildPptx.js.map +1 -1
  6. package/dist/extractSlideMastersAsPptx.js +1 -1
  7. package/dist/renderPptx/glimpseTextBoxes.js +646 -0
  8. package/dist/renderPptx/glimpseTextBoxes.js.map +1 -0
  9. package/dist/renderPptx/nodes/flow.js +95 -90
  10. package/dist/renderPptx/nodes/flow.js.map +1 -1
  11. package/dist/renderPptx/nodes/icon.js +33 -24
  12. package/dist/renderPptx/nodes/icon.js.map +1 -1
  13. package/dist/renderPptx/nodes/image.js +5 -22
  14. package/dist/renderPptx/nodes/image.js.map +1 -1
  15. package/dist/renderPptx/nodes/list.js +96 -111
  16. package/dist/renderPptx/nodes/list.js.map +1 -1
  17. package/dist/renderPptx/nodes/matrix.js +92 -70
  18. package/dist/renderPptx/nodes/matrix.js.map +1 -1
  19. package/dist/renderPptx/nodes/processArrow.js +68 -35
  20. package/dist/renderPptx/nodes/processArrow.js.map +1 -1
  21. package/dist/renderPptx/nodes/pyramid.js +34 -16
  22. package/dist/renderPptx/nodes/pyramid.js.map +1 -1
  23. package/dist/renderPptx/nodes/shape.js +63 -37
  24. package/dist/renderPptx/nodes/shape.js.map +1 -1
  25. package/dist/renderPptx/nodes/svg.js +2 -5
  26. package/dist/renderPptx/nodes/svg.js.map +1 -1
  27. package/dist/renderPptx/nodes/text.js +16 -45
  28. package/dist/renderPptx/nodes/text.js.map +1 -1
  29. package/dist/renderPptx/nodes/timeline.js +108 -74
  30. package/dist/renderPptx/nodes/timeline.js.map +1 -1
  31. package/dist/renderPptx/nodes/tree.js +78 -79
  32. package/dist/renderPptx/nodes/tree.js.map +1 -1
  33. package/dist/renderPptx/renderPptx.js +4 -5
  34. package/dist/renderPptx/renderPptx.js.map +1 -1
  35. package/dist/renderPptx/utils/backgroundBorder.js +85 -49
  36. package/dist/renderPptx/utils/backgroundBorder.js.map +1 -1
  37. package/dist/renderPptx/utils/glimpsePicture.js +130 -0
  38. package/dist/renderPptx/utils/glimpsePicture.js.map +1 -0
  39. package/dist/renderPptx/utils/glimpseShape.js +90 -0
  40. package/dist/renderPptx/utils/glimpseShape.js.map +1 -0
  41. package/dist/renderPptx/utils/glimpseTextBox.js +126 -0
  42. package/dist/renderPptx/utils/glimpseTextBox.js.map +1 -0
  43. package/dist/renderPptx/utils/straightLine.js +29 -14
  44. package/dist/renderPptx/utils/straightLine.js.map +1 -1
  45. package/dist/renderPptx/utils/visualStyle.js +1 -24
  46. package/dist/renderPptx/utils/visualStyle.js.map +1 -1
  47. package/dist/types.js +1 -1
  48. package/package.json +4 -4
  49. package/dist/renderPptx/glowEffects.js +0 -152
  50. package/dist/renderPptx/glowEffects.js.map +0 -1
  51. package/dist/renderPptx/gradientFills.js +0 -167
  52. package/dist/renderPptx/gradientFills.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glimpseTextBoxes.js","names":[],"sources":["../../src/renderPptx/glimpseTextBoxes.ts"],"sourcesContent":["/**\n * Text primitive の @pptx-glimpse/document writer への段階的 swap。\n *\n * 混在期間の合成方式は「pptxgenjs 出力 zip をベースに、swap 済み Text\n * primitive の shape XML だけを glimpse writer で生成して該当 marker shape と\n * 差し替える」方式を採用する。pptxgenjs 側にはまだ Shape / Image / Table /\n * Chart など未 swap primitive と slide master 生成が残っているため、既存 zip を\n * ベースにすると [Content_Types].xml / rels / media parts の管理を現行実装へ\n * 寄せられる。代替案として glimpse の package をベースに未 swap primitive を\n * pptxgenjs から取り込む方式も検討したが、初回スライス時点では pptxgenjs 側の\n * 非 text primitive と master 出力を XML part 単位で切り出す責務が増え、以降の\n * primitive swap より先に package 合成の複雑さが大きくなるため採用しない。\n *\n * marker shape は描画順を保持するためだけに pptxgenjs へ追加し、write 時に\n * glimpse の `<p:sp>` で丸ごと置換する。Text content 自体は pptxgenjs `addText`\n * を経由しない。\n */\nimport {\n addPicture,\n addShape,\n addTextBox,\n asEmu,\n asHundredthPt,\n asOoxmlAngle,\n asOoxmlPercent,\n asPt,\n createPptx,\n type AddTextBoxGradientFillInput,\n type AddShapeInput,\n type AddPictureInput,\n type AddTextBoxInput,\n type AddTextBoxParagraphInput,\n type AddTextBoxRunPropertiesInput,\n type MediaPart,\n type PartPath,\n type PptxSourceModel,\n type PptxSourceModelAddPictureEdit,\n type PptxSourceModelAddShapeEdit,\n type PptxSourceModelAddTextBoxEdit,\n readPptx,\n} from \"@pptx-glimpse/document\";\nimport type {\n BorderStyle,\n PositionedNode,\n ShadowStyle,\n TextGlow,\n TextOutline,\n Underline,\n} from \"../types.ts\";\nimport { parseGradient, parseLinearGradient } from \"../shared/gradient.ts\";\nimport { EMU_PER_IN, pxToEmu, pxToPt } from \"./units.ts\";\nimport { createTextOptions, resolveSubSup } from \"./textOptions.ts\";\n\ntype PptxGenJSInstance = import(\"pptxgenjs\").default;\ntype StreamProps = NonNullable<Parameters<PptxGenJSInstance[\"stream\"]>[0]>;\ntype WriteProps = NonNullable<Parameters<PptxGenJSInstance[\"write\"]>[0]>;\ntype WriteFileProps = NonNullable<\n Parameters<PptxGenJSInstance[\"writeFile\"]>[0]\n>;\ntype BrowserWritablePptx = PptxGenJSInstance & {\n writeFileToBrowser?: (fileName: string, blobContent: Blob) => Promise<string>;\n};\ntype TextPositionedNode = Extract<PositionedNode, { type: \"text\" }>;\n\ntype XmlTransform = (xml: string) => string;\n\nconst MARKER_PREFIX = \"pom-text:\";\nconst SHAPE_MARKER_PREFIX = \"pom-shape:\";\nconst PICTURE_MARKER_PREFIX = \"pom-picture:\";\nconst SLIDE_BACKGROUND_MARKER_BASE = 0x0f7a3d;\nconst HYPERLINK_REL_TYPE =\n \"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink\";\nconst IMAGE_REL_TYPE =\n \"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image\";\n\ninterface GlimpseTextRun {\n text: string;\n properties: AddTextBoxRunPropertiesInput;\n href?: string;\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\nexport function cleanHex(color: string | undefined): string | undefined {\n return color?.replace(/^#/, \"\").toUpperCase();\n}\n\nexport function toColorInput(color: string | undefined) {\n const hex = cleanHex(color);\n return hex ? { kind: \"srgb\" as const, hex } : undefined;\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\nfunction toBaselineInput(\n subscript: boolean | undefined,\n superscript: boolean | undefined,\n) {\n if (subscript) return \"subscript\" as const;\n if (superscript) return \"superscript\" as const;\n return undefined;\n}\n\nfunction toGlowInput(glow: TextGlow | undefined) {\n if (!glow) return undefined;\n return {\n radius: asEmu(Math.round(pxToEmu(glow.size ?? 8))),\n color: toColorInput(glow.color ?? \"FFFFFF\")!,\n };\n}\n\nfunction toOutlineInput(outline: TextOutline | undefined) {\n if (!outline) return undefined;\n return {\n width: asEmu(Math.round(pxToEmu(outline.size ?? 1))),\n color: toColorInput(outline.color ?? \"FFFFFF\"),\n };\n}\n\nfunction toCharSpacing(letterSpacingPx: number | undefined) {\n if (letterSpacingPx === undefined) return undefined;\n return Math.round(pxToPt(letterSpacingPx) * 100);\n}\n\nfunction toTextGradientInput(\n value: string | undefined,\n): AddTextBoxGradientFillInput | undefined {\n if (!value) return undefined;\n const linear = parseLinearGradient(value);\n if (!linear) return undefined;\n const dmlAngle = (((linear.angle - 90) % 360) + 360) % 360;\n return {\n angle: asOoxmlAngle(Math.round(dmlAngle * 60000)),\n stops: linear.stops.map((stop) => ({\n position: asOoxmlPercent(Math.round(stop.position * 1000)),\n color: toColorInput(stop.color)!,\n })),\n };\n}\n\nfunction stripUndefined<T extends Record<string, unknown>>(value: T): T {\n return Object.fromEntries(\n Object.entries(value).filter(([, entry]) => entry !== undefined),\n ) as T;\n}\n\nfunction buildRunProperties(\n node: TextPositionedNode,\n run: NonNullable<TextPositionedNode[\"runs\"]>[number] | undefined,\n gradientFill: AddTextBoxGradientFillInput | undefined,\n): AddTextBoxRunPropertiesInput {\n const fontSizePx = run?.fontSize ?? node.fontSize ?? 24;\n const letterSpacingPx = run?.letterSpacing ?? node.letterSpacing;\n const subSup = run ? resolveSubSup(run, node) : node;\n const color = gradientFill\n ? undefined\n : toColorInput(run?.color ?? node.color);\n\n return stripUndefined({\n fontFace: run?.fontFamily ?? node.fontFamily ?? \"Noto Sans JP\",\n fontSize: asPt(pxToPt(fontSizePx)),\n color,\n gradientFill,\n bold: run?.bold ?? node.bold,\n italic: run?.italic ?? node.italic,\n underline: toUnderlineInput(resolveUnderline(node, run)),\n strike: run?.strike ?? node.strike,\n baseline: toBaselineInput(subSup.subscript, subSup.superscript),\n highlight: toColorInput(run?.highlight ?? node.highlight),\n glow: toGlowInput(node.glow),\n outline: toOutlineInput(node.outline),\n charSpacing: toCharSpacing(letterSpacingPx),\n });\n}\n\nfunction resolveUnderline(\n node: TextPositionedNode,\n run: NonNullable<TextPositionedNode[\"runs\"]>[number] | undefined,\n): Underline | undefined {\n if (run?.underline !== undefined) return run.underline;\n if (node.underline !== undefined) return node.underline;\n return run?.href ? true : undefined;\n}\n\nfunction createParagraphProperties(\n node: TextPositionedNode,\n): AddTextBoxParagraphInput[\"properties\"] {\n const lineHeight = node.lineHeight ?? 1.3;\n const fontSizePx = node.fontSize ?? 24;\n return stripUndefined({\n align: node.textAlign,\n lineSpacing: asHundredthPt(\n Math.round(pxToPt(fontSizePx * lineHeight) * 100),\n ),\n });\n}\n\nfunction buildParagraphs(node: TextPositionedNode): {\n paragraphs: readonly AddTextBoxParagraphInput[];\n hyperlinks: readonly (string | undefined)[];\n} {\n const gradientFill = toTextGradientInput(node.textGradient);\n const sourceRuns: GlimpseTextRun[] =\n node.runs && node.runs.length > 0\n ? node.runs.map((run) => ({\n text: run.text,\n properties: buildRunProperties(node, run, gradientFill),\n href: run.href,\n }))\n : [\n {\n text: node.text ?? \"\",\n properties: buildRunProperties(node, undefined, gradientFill),\n },\n ];\n const paragraphRuns: GlimpseTextRun[][] = [[]];\n for (const run of sourceRuns) {\n const lines = run.text.replace(/\\r*\\n/g, \"\\n\").split(\"\\n\");\n lines.forEach((line, index) => {\n if (index > 0) {\n paragraphRuns.push([]);\n }\n paragraphRuns[paragraphRuns.length - 1]?.push({\n ...run,\n text: line,\n });\n });\n }\n\n return {\n paragraphs: paragraphRuns.map((runs) => ({\n properties: createParagraphProperties(node),\n runs,\n })),\n hyperlinks: paragraphRuns.flatMap((runs) =>\n runs.map((run) => (run.text ? run.href : undefined)),\n ),\n };\n}\n\nfunction withGlowAlpha(xml: string, node: TextPositionedNode): string {\n const glow = node.glow;\n if (!glow) return xml;\n const alpha = Math.round((glow.opacity ?? 0.75) * 100000);\n const color = cleanHex(glow.color ?? \"FFFFFF\");\n const target = `<a:glow rad=\"${Math.round(pxToEmu(glow.size ?? 8))}\"><a:srgbClr val=\"${color}\"/></a:glow>`;\n const replacement = `<a:glow rad=\"${Math.round(pxToEmu(glow.size ?? 8))}\"><a:srgbClr val=\"${color}\"><a:alpha val=\"${alpha}\"/></a:srgbClr></a:glow>`;\n return xml.replaceAll(target, replacement);\n}\n\nfunction withShapeGlowAlpha(xml: string, glow: TextGlow | undefined): string {\n if (!glow) return xml;\n const alpha = Math.round((glow.opacity ?? 0.75) * 100000);\n const color = cleanHex(glow.color ?? \"FFFFFF\");\n const target = `<a:glow rad=\"${Math.round(pxToEmu(glow.size ?? 8))}\"><a:srgbClr val=\"${color}\"/></a:glow>`;\n const replacement = `<a:glow rad=\"${Math.round(pxToEmu(glow.size ?? 8))}\"><a:srgbClr val=\"${color}\"><a:alpha val=\"${alpha}\"/></a:srgbClr></a:glow>`;\n return xml.replaceAll(target, replacement);\n}\n\nfunction colorWithOptionalAlphaXml(\n color: string,\n opacity: number | undefined,\n): string {\n const clean = cleanHex(color) ?? color;\n if (opacity === undefined) return `<a:srgbClr val=\"${clean}\"/>`;\n return `<a:srgbClr val=\"${clean}\"><a:alpha val=\"${Math.round(opacity * 100000)}\"/></a:srgbClr>`;\n}\n\nfunction buildGradFillXml(value: string, opacity?: number): string | undefined {\n const gradient = parseGradient(value);\n if (!gradient) return undefined;\n const gsXml = gradient.value.stops\n .map(\n (stop) =>\n `<a:gs pos=\"${Math.round(stop.position * 1000)}\">${colorWithOptionalAlphaXml(\n stop.color,\n opacity,\n )}</a:gs>`,\n )\n .join(\"\");\n\n if (gradient.kind === \"linear\") {\n const dmlAngle = (((gradient.value.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 const { centerX, centerY } = gradient.value;\n const l = Math.round(centerX * 1000);\n const t = Math.round(centerY * 1000);\n const r = Math.round((100 - centerX) * 1000);\n const b = Math.round((100 - centerY) * 1000);\n return `<a:gradFill flip=\"none\" rotWithShape=\"1\"><a:gsLst>${gsXml}</a:gsLst><a:path path=\"circle\"><a:fillToRect l=\"${l}\" t=\"${t}\" r=\"${r}\" b=\"${b}\"/></a:path></a:gradFill>`;\n}\n\nfunction withSolidFillAlpha(\n xml: string,\n color: string | undefined,\n opacity: number | undefined,\n): string {\n if (color === undefined || opacity === undefined) return xml;\n const clean = cleanHex(color);\n return xml.replaceAll(\n `<a:solidFill><a:srgbClr val=\"${clean}\"/></a:solidFill>`,\n `<a:solidFill>${colorWithOptionalAlphaXml(clean ?? color, opacity)}</a:solidFill>`,\n );\n}\n\nfunction withGradientFill(\n xml: string,\n backgroundGradient: string | undefined,\n opacity: number | undefined,\n preset: string,\n): string {\n if (!backgroundGradient) return xml;\n const gradFill = buildGradFillXml(backgroundGradient, opacity);\n if (!gradFill) return xml;\n if (preset === \"line\") {\n return xml.replace(\n /<a:ln\\b([^>]*)>([\\s\\S]*?)<\\/a:ln>/,\n (match, attrs, body) => {\n const nextBody = (body as string).replace(\n /<a:(?:solidFill|gradFill)\\b[\\s\\S]*?<\\/a:(?:solidFill|gradFill)>|<a:noFill\\/>/,\n gradFill,\n );\n return nextBody === body\n ? match\n : `<a:ln${attrs as string}>${nextBody}</a:ln>`;\n },\n );\n }\n return xml.replace(\n /<a:(?:solidFill|gradFill)\\b[\\s\\S]*?<\\/a:(?:solidFill|gradFill)>|<a:noFill\\/>/,\n gradFill,\n );\n}\n\nfunction withRoundRectAdjust(\n xml: string,\n input: AddShapeInput,\n rectRadius: number | undefined,\n): string {\n if (input.preset !== \"roundRect\" || rectRadius === undefined) return xml;\n // `rectRadius` is the pptxgenjs-compatible option value already resolved by\n // visualStyle.resolveRectRadius. Keep the same formula pptxgenjs uses.\n const adj = Math.round(\n (rectRadius * EMU_PER_IN * 100000) / Math.min(input.width, input.height),\n );\n return xml.replace(\n /<a:prstGeom prst=\"roundRect\"><a:avLst\\/><\\/a:prstGeom>/,\n `<a:prstGeom prst=\"roundRect\"><a:avLst><a:gd name=\"adj\" fmla=\"val ${adj}\"/></a:avLst></a:prstGeom>`,\n );\n}\n\nfunction shadowXml(shadow: ShadowStyle | undefined): string | undefined {\n if (!shadow) return undefined;\n const blur = Math.round((shadow.blur ?? 3) * 12700);\n const dist = Math.round((shadow.offset ?? 23000 / 12700) * 12700);\n const dir = Math.round((shadow.angle ?? 90) * 60000);\n const color = cleanHex(shadow.color ?? \"000000\") ?? \"000000\";\n const alpha = Math.round((shadow.opacity ?? 0.35) * 100000);\n const type = shadow.type ?? \"outer\";\n return `<a:${type}Shdw sx=\"100000\" sy=\"100000\" kx=\"0\" ky=\"0\" algn=\"bl\" blurRad=\"${blur}\" rotWithShape=\"1\" dist=\"${dist}\" dir=\"${dir}\"><a:srgbClr val=\"${color}\"><a:alpha val=\"${alpha}\"/></a:srgbClr></a:${type}Shdw>`;\n}\n\nfunction withShadow(xml: string, shadow: ShadowStyle | undefined): string {\n const effect = shadowXml(shadow);\n if (!effect) return xml;\n if (xml.includes(\"<a:effectLst>\")) {\n return xml.replace(\"</a:effectLst>\", `${effect}</a:effectLst>`);\n }\n return xml.replace(\n \"</p:spPr>\",\n `<a:effectLst>${effect}</a:effectLst></p:spPr>`,\n );\n}\n\nfunction withLineFlip(\n xml: string,\n flipH: boolean | undefined,\n flipV: boolean | undefined,\n): string {\n if (!flipH && !flipV) return xml;\n return xml.replace(\n \"<a:xfrm\",\n `<a:xfrm${flipH ? ' flipH=\"1\"' : \"\"}${flipV ? ' flipV=\"1\"' : \"\"}`,\n );\n}\n\nfunction withLineZeroExtent(\n xml: string,\n preset: string,\n zeroWidth: boolean | undefined,\n zeroHeight: boolean | undefined,\n): string {\n if (preset !== \"line\" || (!zeroWidth && !zeroHeight)) return xml;\n return xml.replace(\n /<a:ext cx=\"(\\d+)\" cy=\"(\\d+)\"\\/>/,\n (_match, cx: string, cy: string) =>\n `<a:ext cx=\"${zeroWidth ? \"0\" : cx}\" cy=\"${zeroHeight ? \"0\" : cy}\"/>`,\n );\n}\n\nfunction withPrstDash(xml: string, dashType: string): string {\n return xml.replace(\n /<a:ln\\b([^>]*)>([\\s\\S]*?)<\\/a:ln>/g,\n (match, attrs, body) => {\n const bodyText = body as string;\n if (bodyText.includes(\"<a:prstDash\")) return match;\n return `<a:ln${attrs as string}>${bodyText.replace(\n /(<a:(?:solidFill|noFill\\/)>[\\s\\S]*?<\\/a:solidFill>|<a:noFill\\/>)/,\n `$1<a:prstDash val=\"${dashType}\"/>`,\n )}</a:ln>`;\n },\n );\n}\n\nfunction withUnsupportedDashStyle(\n xml: string,\n dashType: BorderStyle[\"dashType\"] | undefined,\n): string {\n if (dashType !== \"lgDashDotDot\") return xml;\n return withPrstDash(xml, dashType);\n}\n\nfunction withPptxGenLineArrowDefaults(xml: string, preset: string): string {\n if (preset !== \"line\") return xml;\n const withoutDefaultSizes = xml.replace(\n /<a:(headEnd|tailEnd) type=\"([^\"]+)\" w=\"med\" len=\"med\"\\/>/g,\n '<a:$1 type=\"$2\"/>',\n );\n return withPrstDash(withoutDefaultSizes, \"solid\");\n}\n\nfunction withPptxGenParagraphDefaults(xml: string): string {\n let result = xml.replaceAll('baseline=\"-25000\"', 'baseline=\"-40000\"');\n result = result.replace(/<a:bodyPr\\b([^>]*)\\/>/g, (_match, attrs) => {\n const attrText = attrs as string;\n const withRtl = /(?:^|\\s)rtlCol=/.test(attrText)\n ? attrText\n : `${attrText} rtlCol=\"0\"`;\n const withAnchor = /(?:^|\\s)anchor=/.test(withRtl)\n ? withRtl\n : `${withRtl} anchor=\"t\"`;\n return `<a:bodyPr${withAnchor}/>`;\n });\n result = result.replace(\n /<a:pPr([^>]*)>([\\s\\S]*?)<\\/a:pPr>/g,\n (match, attrs, body) => {\n const attrText = attrs as string;\n const nextAttrs = /(?:^|\\s)indent=/.test(attrText)\n ? attrText\n : `${attrText} indent=\"0\" marL=\"0\"`;\n const bodyText = body as string;\n const nextBody = bodyText.includes(\"<a:buNone/>\")\n ? bodyText\n : `${bodyText}<a:buNone/>`;\n return `<a:pPr${nextAttrs}>${nextBody}</a:pPr>`;\n },\n );\n result = result.replace(\n /<a:p>(?!<a:pPr)/g,\n '<a:p><a:pPr indent=\"0\" marL=\"0\"><a:buNone/></a:pPr>',\n );\n return result;\n}\n\nfunction createTextBoxXml(\n node: TextPositionedNode,\n name: string,\n): { xml: string; hyperlinks: readonly (string | undefined)[] } {\n const textOptions = createTextOptions(node);\n const { paragraphs, hyperlinks } = buildParagraphs(node);\n const input: AddTextBoxInput = {\n offsetX: asEmu(Math.round(textOptions.x * EMU_PER_IN)),\n offsetY: asEmu(Math.round(textOptions.y * EMU_PER_IN)),\n width: asEmu(Math.round(textOptions.w * EMU_PER_IN)),\n height: asEmu(Math.round(textOptions.h * EMU_PER_IN)),\n rotation:\n node.rotate !== undefined\n ? asOoxmlAngle(Math.round(node.rotate * 60000))\n : undefined,\n name,\n body: {\n marginLeft: asEmu(0),\n marginRight: asEmu(0),\n marginTop: asEmu(0),\n marginBottom: asEmu(0),\n },\n paragraphs,\n };\n return {\n xml: createTextBoxXmlFromInput(input, {\n xmlTransform: (xml) => withGlowAlpha(xml, node),\n }),\n hyperlinks,\n };\n}\n\nfunction createTextBoxXmlFromInput(\n input: AddTextBoxInput,\n options?: { xmlTransform?: XmlTransform },\n): string {\n const source = createPptx();\n const slideHandle = source.slides[0]?.handle;\n if (!slideHandle) {\n throw new Error(\"createPptx did not create an editable slide\");\n }\n\n const edited = addTextBox(source, slideHandle, input);\n const edit = edited.edits?.at(-1) as\n PptxSourceModelAddTextBoxEdit | undefined;\n if (edit?.kind !== \"addTextBox\") {\n throw new Error(\"addTextBox did not produce an addTextBox edit\");\n }\n const xml = withPptxGenParagraphDefaults(edit.xml);\n return options?.xmlTransform ? options.xmlTransform(xml) : xml;\n}\n\nexport type GlimpseShapeXmlOptions = {\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\ntype CustomGeometryPointInput = { x: number; y: number } | { close: true };\n\nexport type CustomGeometryXmlInput = {\n width: number;\n height: number;\n points: readonly CustomGeometryPointInput[];\n};\n\nfunction geometryPointXml(point: { x: number; y: number }): string {\n return `<a:pt x=\"${Math.round(point.x * EMU_PER_IN)}\" y=\"${Math.round(\n point.y * EMU_PER_IN,\n )}\"/>`;\n}\n\nfunction buildCustomGeometryXml(\n geometry: CustomGeometryXmlInput,\n): string | undefined {\n const first = geometry.points.find(\n (point): point is { x: number; y: number } => \"x\" in point,\n );\n if (!first) return undefined;\n\n let hasMoveTo = false;\n const commands = geometry.points\n .map((point) => {\n if (\"close\" in point) return hasMoveTo ? \"<a:close/>\" : \"\";\n if (!hasMoveTo) {\n hasMoveTo = true;\n return `<a:moveTo>${geometryPointXml(point)}</a:moveTo>`;\n }\n return `<a:lnTo>${geometryPointXml(point)}</a:lnTo>`;\n })\n .join(\"\");\n\n return (\n \"<a:custGeom><a:avLst/><a:gdLst/><a:ahLst/><a:cxnLst/>\" +\n '<a:rect l=\"l\" t=\"t\" r=\"r\" b=\"b\"/>' +\n `<a:pathLst><a:path w=\"${Math.round(\n geometry.width * EMU_PER_IN,\n )}\" h=\"${Math.round(geometry.height * EMU_PER_IN)}\">${commands}</a:path></a:pathLst>` +\n \"</a:custGeom>\"\n );\n}\n\nfunction withCustomGeometry(\n xml: string,\n geometry: CustomGeometryXmlInput | undefined,\n): string {\n if (!geometry) return xml;\n const customGeometry = buildCustomGeometryXml(geometry);\n if (!customGeometry) return xml;\n return xml.replace(/<a:prstGeom\\b[\\s\\S]*?<\\/a:prstGeom>/, customGeometry);\n}\n\nfunction withOutlineGradientFill(\n xml: string,\n outlineGradient: string | undefined,\n opacity: number | undefined,\n): string {\n if (!outlineGradient) return xml;\n const gradFill = buildGradFillXml(outlineGradient, opacity);\n if (!gradFill) return xml;\n const lineFillPattern =\n /<a:(?:solidFill|gradFill)\\b[\\s\\S]*?<\\/a:(?:solidFill|gradFill)>|<a:noFill\\/>/;\n if (/<a:ln\\b[^>]*\\/>/.test(xml)) {\n return xml.replace(\n /<a:ln\\b([^>]*)\\/>/,\n (_match, attrs: string) => `<a:ln${attrs}>${gradFill}</a:ln>`,\n );\n }\n return xml.replace(\n /(<a:ln\\b[^>]*>)([\\s\\S]*?)(<\\/a:ln>)/,\n (_match, open: string, body: string, close: string) => {\n const nextBody = lineFillPattern.test(body)\n ? body.replace(lineFillPattern, gradFill)\n : `${gradFill}${body}`;\n return `${open}${nextBody}${close}`;\n },\n );\n}\n\nfunction createShapeXml(\n input: AddShapeInput,\n options: GlimpseShapeXmlOptions | undefined,\n): string {\n const source = createPptx();\n const slideHandle = source.slides[0]?.handle;\n if (!slideHandle) {\n throw new Error(\"createPptx did not create an editable slide\");\n }\n\n const edited = addShape(source, slideHandle, input);\n const edit = edited.edits?.at(-1) as PptxSourceModelAddShapeEdit | undefined;\n if (edit?.kind !== \"addShape\") {\n throw new Error(\"addShape did not produce an addShape edit\");\n }\n\n let xml = edit.xml;\n xml = withShapeGlowAlpha(xml, options?.glow);\n xml = withSolidFillAlpha(xml, options?.fillColor, options?.fillOpacity);\n xml = withGradientFill(\n xml,\n options?.backgroundGradient,\n options?.fillOpacity,\n input.preset,\n );\n xml = withOutlineGradientFill(\n xml,\n options?.outlineGradient,\n options?.outlineOpacity ?? options?.fillOpacity,\n );\n xml = withRoundRectAdjust(xml, input, options?.rectRadius);\n xml = withShadow(xml, options?.shadow);\n xml = withUnsupportedDashStyle(xml, options?.dashType);\n xml = withLineFlip(xml, options?.flipH, options?.flipV);\n xml = withLineZeroExtent(\n xml,\n input.preset,\n options?.zeroWidth,\n options?.zeroHeight,\n );\n xml = withPptxGenLineArrowDefaults(xml, input.preset);\n xml = withCustomGeometry(xml, options?.customGeometry);\n return xml;\n}\n\ninterface RegisteredTextBox {\n kind: \"shape\";\n marker: string;\n name: string;\n xml: string;\n hyperlinks: readonly (string | undefined)[];\n}\n\ninterface RegisteredPicture {\n kind: \"picture\";\n marker: string;\n name: string;\n input: AddPictureInput;\n shadow?: ShadowStyle;\n}\n\ninterface RegisteredSlideBackground {\n kind: \"slideBackground\";\n marker: string;\n slideNumber: number;\n xml: string;\n}\n\ntype RegisteredDrawing =\n RegisteredTextBox | RegisteredPicture | RegisteredSlideBackground;\n\nexport class GlimpseTextBoxRegistry {\n private readonly registered: RegisteredDrawing[] = [];\n private textCount = 0;\n private shapeCount = 0;\n private pictureCount = 0;\n private slideBackgroundCount = 0;\n\n register(node: TextPositionedNode): string {\n const index = this.textCount++;\n const marker = `${MARKER_PREFIX}${index}`;\n const name = `Text ${index + 1}`;\n const { xml, hyperlinks } = createTextBoxXml(node, name);\n this.registered.push({ kind: \"shape\", marker, name, xml, hyperlinks });\n return marker;\n }\n\n registerTextBox(\n input: AddTextBoxInput,\n options?: {\n name?: string;\n hyperlinks?: readonly (string | undefined)[];\n xmlTransform?: XmlTransform;\n },\n ): string {\n const index = this.textCount++;\n const marker = `${MARKER_PREFIX}${index}`;\n const name = options?.name ?? `Text ${index + 1}`;\n const xml = createTextBoxXmlFromInput({ ...input, name }, options);\n this.registered.push({\n kind: \"shape\",\n marker,\n name,\n xml,\n hyperlinks: options?.hyperlinks ?? [],\n });\n return marker;\n }\n\n registerShape(\n input: AddShapeInput,\n options?: GlimpseShapeXmlOptions & { name?: string },\n ): string {\n const index = this.shapeCount++;\n const marker = `${SHAPE_MARKER_PREFIX}${index}`;\n const name = options?.name ?? `Shape ${index + 1}`;\n const xml = createShapeXml({ ...input, name }, options);\n this.registered.push({ kind: \"shape\", marker, name, xml, hyperlinks: [] });\n return marker;\n }\n\n registerPicture(\n input: AddPictureInput,\n options?: { name?: string; shadow?: ShadowStyle },\n ): string {\n const index = this.pictureCount++;\n const marker = `${PICTURE_MARKER_PREFIX}${index}`;\n const name = options?.name ?? `Picture ${index + 1}`;\n this.registered.push({\n kind: \"picture\",\n marker,\n name,\n input: { ...input, name },\n shadow: options?.shadow,\n });\n return marker;\n }\n\n registerSlideBackgroundGradient(\n backgroundGradient: string,\n slideNumber: number,\n opacity?: number,\n ): string | undefined {\n const xml = buildGradFillXml(backgroundGradient, opacity);\n if (!xml) return undefined;\n const marker = (SLIDE_BACKGROUND_MARKER_BASE + this.slideBackgroundCount++)\n .toString(16)\n .toUpperCase()\n .padStart(6, \"0\");\n this.registered.push({ kind: \"slideBackground\", marker, slideNumber, xml });\n return marker;\n }\n\n get isEmpty(): boolean {\n return this.registered.length === 0;\n }\n\n get entries(): readonly RegisteredDrawing[] {\n return this.registered;\n }\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction replaceShapeId(xml: string, id: string, name: string): string {\n return xml.replace(\n /<p:cNvPr id=\"[^\"]+\" name=\"[^\"]*\"/,\n `<p:cNvPr id=\"${xmlAttr(id)}\" name=\"${xmlAttr(name)}\"`,\n );\n}\n\nfunction xmlAttr(value: string): string {\n return value\n .replaceAll(\"&\", \"&amp;\")\n .replaceAll('\"', \"&quot;\")\n .replaceAll(\"<\", \"&lt;\")\n .replaceAll(\">\", \"&gt;\");\n}\n\nfunction slideRelsPath(slidePath: string): string {\n const fileName = slidePath.split(\"/\").at(-1);\n return `ppt/slides/_rels/${fileName}.rels`;\n}\n\nclass SlideRelationshipEditor {\n private nextId: number;\n\n private changed = false;\n\n constructor(private xml: string) {\n const ids = Array.from(xml.matchAll(/\\bId=\"rId(\\d+)\"/g), (match) =>\n Number(match[1]),\n );\n this.nextId = Math.max(0, ...ids) + 1;\n }\n\n addHyperlink(href: string): string {\n const id = `rId${this.nextId++}`;\n const rel =\n `<Relationship Id=\"${id}\" Type=\"${HYPERLINK_REL_TYPE}\" ` +\n `Target=\"${xmlAttr(href)}\" TargetMode=\"External\"/>`;\n this.xml = this.xml.replace(\"</Relationships>\", `${rel}</Relationships>`);\n this.changed = true;\n return id;\n }\n\n addImageRelationship(id: string, target: string): void {\n const idPattern = new RegExp(`\\\\bId=\"${escapeRegExp(id)}\"`);\n if (idPattern.test(this.xml)) return;\n const rel =\n `<Relationship Id=\"${xmlAttr(id)}\" Type=\"${IMAGE_REL_TYPE}\" ` +\n `Target=\"${xmlAttr(target)}\"/>`;\n this.xml = this.xml.replace(\"</Relationships>\", `${rel}</Relationships>`);\n const numeric = id.match(/^rId(\\d+)$/)?.[1];\n if (numeric) {\n this.nextId = Math.max(this.nextId, Number(numeric) + 1);\n }\n this.changed = true;\n }\n\n get result(): { xml: string; changed: boolean } {\n return { xml: this.xml, changed: this.changed };\n }\n}\n\nfunction createRelationshipEditor(xml: string | undefined) {\n return new SlideRelationshipEditor(\n xml ??\n '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>' +\n '<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\"></Relationships>',\n );\n}\n\nfunction withHyperlinkRelationships(\n xml: string,\n hyperlinks: readonly (string | undefined)[],\n addRelationship: (href: string) => string,\n): string {\n if (!hyperlinks.some(Boolean)) return xml;\n let index = 0;\n return xml.replace(\n /<a:rPr\\b([^>]*)>([\\s\\S]*?)<\\/a:rPr>/g,\n (match, attrs, body) => {\n const href = hyperlinks[index++];\n if (!href) return match;\n const id = addRelationship(href);\n return `<a:rPr${attrs as string}>${body as string}<a:hlinkClick r:id=\"${id}\"/></a:rPr>`;\n },\n );\n}\n\nfunction findSlideHandle(source: PptxSourceModel, slidePath: string) {\n return source.slides.find((slide) => slide.partPath === slidePath)?.handle;\n}\n\nfunction findMediaPart(source: PptxSourceModel, partPath: PartPath): MediaPart {\n const media = source.packageGraph.media.find(\n (part) => part.partPath === partPath,\n );\n if (!media) {\n throw new Error(`addPicture media part was not found: ${partPath}`);\n }\n return media;\n}\n\nfunction findSlideImageTarget(\n source: PptxSourceModel,\n slidePath: string,\n relationshipId: string,\n): string {\n const relationships = source.packageGraph.relationships.find(\n (group) => group.sourcePartPath === slidePath,\n );\n const relationship = relationships?.relationships.find(\n (candidate) => candidate.id === relationshipId,\n );\n if (!relationship) {\n throw new Error(`addPicture relationship was not found: ${relationshipId}`);\n }\n return relationship.target;\n}\n\nfunction applyGlimpseTextBoxesToXml(\n xml: string,\n registry: GlimpseTextBoxRegistry,\n addRelationship: (href: string) => string,\n): string {\n let result = xml;\n for (const entry of registry.entries) {\n if (entry.kind !== \"shape\") continue;\n const re = new RegExp(\n `<p:sp><p:nvSpPr><p:cNvPr id=\"([^\"]+)\" name=\"${escapeRegExp(\n entry.marker,\n )}\"[\\\\s\\\\S]*?</p:sp>`,\n \"g\",\n );\n result = result.replace(re, (_match, id: string) => {\n const xmlWithIds = replaceShapeId(entry.xml, id, entry.name);\n return withHyperlinkRelationships(\n xmlWithIds,\n entry.hyperlinks,\n addRelationship,\n );\n });\n }\n return result;\n}\n\nfunction applySlideBackgroundGradientsToXml(\n xml: string,\n registry: GlimpseTextBoxRegistry,\n slidePath: string,\n): string {\n let result = xml;\n const slideNumber = Number(slidePath.match(/slide(\\d+)\\.xml$/)?.[1]);\n for (const entry of registry.entries) {\n if (entry.kind !== \"slideBackground\") continue;\n if (entry.slideNumber !== slideNumber) continue;\n const target = `<p:bgPr><a:solidFill><a:srgbClr val=\"${entry.marker}\"/></a:solidFill></p:bgPr>`;\n result = result.replace(target, `<p:bgPr>${entry.xml}</p:bgPr>`);\n }\n return result;\n}\n\nfunction withPptxGenPictureSizingXml(xml: string, hasSizing: boolean): string {\n if (!hasSizing) return xml;\n return xml.replace(\"<a:stretch><a:fillRect/></a:stretch>\", \"<a:stretch/>\");\n}\n\nfunction applyGlimpsePicturesToXml(\n xml: string,\n registry: GlimpseTextBoxRegistry,\n source: PptxSourceModel,\n slidePath: string,\n relationshipEditor: SlideRelationshipEditor,\n addMedia: (media: MediaPart) => void,\n): { xml: string; source: PptxSourceModel } {\n let result = xml;\n let editedSource = source;\n for (const entry of registry.entries) {\n if (entry.kind !== \"picture\") continue;\n const re = new RegExp(\n `<p:sp><p:nvSpPr><p:cNvPr id=\"([^\"]+)\" name=\"${escapeRegExp(\n entry.marker,\n )}\"[\\\\s\\\\S]*?</p:sp>`,\n \"g\",\n );\n result = result.replace(re, (_match, id: string) => {\n const slideHandle = findSlideHandle(editedSource, slidePath);\n if (!slideHandle) {\n throw new Error(`slide handle was not found: ${slidePath}`);\n }\n editedSource = addPicture(editedSource, slideHandle, entry.input);\n const edit = editedSource.edits?.at(-1) as\n PptxSourceModelAddPictureEdit | undefined;\n if (edit?.kind !== \"addPicture\") {\n throw new Error(\"addPicture did not produce an addPicture edit\");\n }\n const media = findMediaPart(editedSource, edit.mediaPartPath);\n addMedia(media);\n relationshipEditor.addImageRelationship(\n edit.relationshipId,\n findSlideImageTarget(editedSource, slidePath, edit.relationshipId),\n );\n const xml = withPptxGenPictureSizingXml(\n replaceShapeId(edit.xml, id, entry.name),\n entry.input.crop !== undefined,\n );\n return withShadow(xml, entry.shadow);\n });\n }\n return { xml: result, source: editedSource };\n}\n\nfunction ensureContentTypeDefault(\n xml: string,\n extension: string,\n contentType: string,\n): string {\n const existing = new RegExp(\n `<Default\\\\s+[^>]*Extension=\"${escapeRegExp(extension)}\"[^>]*/>`,\n );\n if (existing.test(xml)) return xml;\n const entry = `<Default Extension=\"${xmlAttr(extension)}\" ContentType=\"${xmlAttr(\n contentType,\n )}\"/>`;\n return xml.replace(\"</Types>\", `${entry}</Types>`);\n}\n\nasync function applyGlimpseMediaParts(\n zip: import(\"jszip\"),\n mediaParts: Iterable<MediaPart>,\n): Promise<void> {\n const mediaList = Array.from(mediaParts);\n if (mediaList.length === 0) return;\n const contentTypesFile = zip.file(\"[Content_Types].xml\");\n if (!contentTypesFile) {\n throw new Error(\"[Content_Types].xml was not found in pptx output\");\n }\n let contentTypesXml = await contentTypesFile.async(\"text\");\n for (const media of mediaList) {\n zip.file(media.partPath, media.bytes);\n const extension = media.partPath.split(\".\").at(-1);\n if (!extension) continue;\n contentTypesXml = ensureContentTypeDefault(\n contentTypesXml,\n extension,\n media.contentType,\n );\n }\n zip.file(\"[Content_Types].xml\", contentTypesXml);\n}\n\nasync function applyGlimpseTextBoxes(\n data: Uint8Array | ArrayBuffer,\n registry: GlimpseTextBoxRegistry,\n): Promise<import(\"jszip\")> {\n const JSZip = await loadJSZip();\n const zip = await JSZip.loadAsync(data);\n const hasPictures = registry.entries.some(\n (entry) => entry.kind === \"picture\",\n );\n let source = hasPictures\n ? readPptx(data instanceof Uint8Array ? data : new Uint8Array(data))\n : undefined;\n const addedMedia = new Map<string, MediaPart>();\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 relsPath = slideRelsPath(path);\n const relsFile = zip.file(relsPath);\n const relationshipEditor = createRelationshipEditor(\n relsFile ? await relsFile.async(\"text\") : undefined,\n );\n const withSlideBackground = applySlideBackgroundGradientsToXml(\n original,\n registry,\n path,\n );\n const pictureResult = source\n ? applyGlimpsePicturesToXml(\n withSlideBackground,\n registry,\n source,\n path,\n relationshipEditor,\n (media) => {\n addedMedia.set(media.partPath, media);\n },\n )\n : { xml: withSlideBackground, source };\n source = pictureResult.source;\n const replaced = applyGlimpseTextBoxesToXml(\n pictureResult.xml,\n registry,\n (href) => relationshipEditor.addHyperlink(href),\n );\n if (replaced !== original) {\n zip.file(path, replaced);\n }\n const relationships = relationshipEditor.result;\n if (relationships.changed) {\n zip.file(relsPath, relationships.xml);\n }\n }\n await applyGlimpseMediaParts(zip, addedMedia.values());\n return zip;\n}\n\nexport function patchPptxWriteForGlimpseTextBoxes(\n pptx: PptxGenJSInstance,\n registry: GlimpseTextBoxRegistry,\n): void {\n if (registry.isEmpty) return;\n\n const originalWrite = pptx.write.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 applyGlimpseTextBoxes(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({\n type: outputType,\n compression: props?.compression ? \"DEFLATE\" : \"STORE\",\n });\n }\n return zip.generateAsync({\n type: \"blob\",\n compression: props?.compression ? \"DEFLATE\" : \"STORE\",\n });\n };\n pptx.write = patchedWrite;\n\n const patchedStream = async (props?: StreamProps) =>\n pptx.write({\n outputType: \"STREAM\",\n compression: props?.compression,\n });\n pptx.stream = patchedStream;\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 const browserWriter = pptx as BrowserWritablePptx;\n if (typeof browserWriter.writeFileToBrowser !== \"function\") {\n throw new Error(\n \"pptx.writeFile browser download helper is unavailable; use pptx.write({ outputType: 'blob' }) instead\",\n );\n }\n const rawName = props?.fileName ?? \"Presentation.pptx\";\n const fileName = rawName.toLowerCase().endsWith(\".pptx\")\n ? rawName\n : `${rawName}.pptx`;\n const blob = (await patchedWrite({\n outputType: \"blob\",\n compression: props?.compression,\n })) as Blob;\n await browserWriter.writeFileToBrowser(fileName, blob);\n return fileName;\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,7 +1,9 @@
1
- import { pxToIn, pxToPt } from "../units.js";
2
1
  import { withContentBounds } from "../utils/contentArea.js";
3
- import { stripHash } from "../utils/visualStyle.js";
2
+ import { addGlimpseTextBox, createGlimpseParagraphs } from "../utils/glimpseTextBox.js";
3
+ import { addGlimpseShape, createShapeBoundsInput, shapeOutline, solidShapeFill } from "../utils/glimpseShape.js";
4
+ import { addStraightLine } from "../utils/straightLine.js";
4
5
  import { measureFlow } from "../../calcYogaLayout/measureCompositeNodes.js";
6
+ import { stripHash } from "../utils/visualStyle.js";
5
7
  import { resolveScaledContentArea } from "../utils/scaleToFit.js";
6
8
  //#region src/renderPptx/nodes/flow.ts
7
9
  function renderFlowNode(node, ctx) {
@@ -30,12 +32,14 @@ function renderFlowNode(node, ctx) {
30
32
  const labelY = (fromLayout.y + fromLayout.height / 2 + toLayout.y + toLayout.height / 2) / 2;
31
33
  const labelW = 60 * scaleFactor;
32
34
  const labelH = 20 * scaleFactor;
33
- ctx.slide.addText(conn.label, {
34
- x: pxToIn(labelX - labelW / 2),
35
- y: pxToIn(labelY - labelH / 2),
36
- w: pxToIn(labelW),
37
- h: pxToIn(labelH),
38
- fontSize: pxToPt(10 * scaleFactor),
35
+ addGlimpseTextBox(ctx, {
36
+ x: labelX - labelW / 2,
37
+ y: labelY - labelH / 2,
38
+ w: labelW,
39
+ h: labelH
40
+ }, {
41
+ text: conn.label,
42
+ fontSize: 10 * scaleFactor,
39
43
  fontFace: "Noto Sans JP",
40
44
  color: stripHash(conn.labelColor) ?? stripHash(connectorStyle.labelColor) ?? "64748B",
41
45
  align: "center",
@@ -48,23 +52,31 @@ function renderFlowNode(node, ctx) {
48
52
  if (!layout) continue;
49
53
  const fillColor = item.color ?? defaultColor;
50
54
  const textColor = item.textColor ?? "FFFFFF";
51
- ctx.slide.addText(item.text, {
52
- x: pxToIn(layout.x),
53
- y: pxToIn(layout.y),
54
- w: pxToIn(layout.width),
55
- h: pxToIn(layout.height),
56
- shape: item.shape,
57
- fill: { color: fillColor },
58
- line: {
55
+ addGlimpseShape(ctx, {
56
+ preset: item.shape,
57
+ ...createShapeBoundsInput({
58
+ x: layout.x,
59
+ y: layout.y,
60
+ w: layout.width,
61
+ h: layout.height
62
+ }),
63
+ fill: solidShapeFill(fillColor),
64
+ outline: shapeOutline({
59
65
  color: "333333",
60
- width: pxToPt(1 * scaleFactor)
61
- },
62
- fontSize: pxToPt(14 * scaleFactor),
63
- fontFace: "Noto Sans JP",
64
- color: textColor,
65
- align: "center",
66
- valign: "middle"
67
- });
66
+ width: 1 * scaleFactor
67
+ }),
68
+ body: { anchor: "middle" },
69
+ paragraphs: createGlimpseParagraphs(item.text, {
70
+ fontSize: 14 * scaleFactor,
71
+ fontFace: "Noto Sans JP",
72
+ color: textColor
73
+ }, { align: "center" })
74
+ }, {
75
+ x: layout.x,
76
+ y: layout.y,
77
+ w: layout.width,
78
+ h: layout.height
79
+ }, { fillColor });
68
80
  }
69
81
  }
70
82
  function calculateHorizontalLayout(node, layouts, nodeCount, nodeWidth, nodeHeight, nodeGap, scaleFactor) {
@@ -116,16 +128,15 @@ function drawConnection(ctx, direction, fromLayout, toLayout, lineColor, lineWid
116
128
  }
117
129
  const isHorizontalLine = Math.abs(startY - endY) < 1;
118
130
  const isVerticalLine = Math.abs(startX - endX) < 1;
119
- if (isHorizontalLine || isVerticalLine) ctx.slide.addShape(ctx.pptx.ShapeType.line, {
120
- x: pxToIn(Math.min(startX, endX)),
121
- y: pxToIn(Math.min(startY, endY)),
122
- w: pxToIn(Math.abs(endX - startX)),
123
- h: pxToIn(Math.abs(endY - startY)),
124
- line: {
125
- color: lineColor,
126
- width: pxToPt(lineWidth),
127
- endArrowType: arrowType
128
- }
131
+ if (isHorizontalLine || isVerticalLine) addStraightLine(ctx, {
132
+ x1: startX,
133
+ y1: startY,
134
+ x2: endX,
135
+ y2: endY
136
+ }, {
137
+ color: lineColor,
138
+ lineWidth,
139
+ endArrow: { type: arrowType }
129
140
  });
130
141
  else drawLShapedConnection(ctx, direction, startX, startY, endX, endY, lineColor, lineWidth, arrowType);
131
142
  }
@@ -133,68 +144,62 @@ function drawLShapedConnection(ctx, direction, startX, startY, endX, endY, lineC
133
144
  const midX = (startX + endX) / 2;
134
145
  const midY = (startY + endY) / 2;
135
146
  if (direction === "horizontal") {
136
- ctx.slide.addShape(ctx.pptx.ShapeType.line, {
137
- x: pxToIn(startX),
138
- y: pxToIn(startY),
139
- w: pxToIn(midX - startX),
140
- h: 0,
141
- line: {
142
- color: lineColor,
143
- width: pxToPt(lineWidth)
144
- }
147
+ addStraightLine(ctx, {
148
+ x1: startX,
149
+ y1: startY,
150
+ x2: midX,
151
+ y2: startY
152
+ }, {
153
+ color: lineColor,
154
+ lineWidth
145
155
  });
146
- ctx.slide.addShape(ctx.pptx.ShapeType.line, {
147
- x: pxToIn(midX),
148
- y: pxToIn(Math.min(startY, endY)),
149
- w: 0,
150
- h: pxToIn(Math.abs(endY - startY)),
151
- line: {
152
- color: lineColor,
153
- width: pxToPt(lineWidth)
154
- }
156
+ addStraightLine(ctx, {
157
+ x1: midX,
158
+ y1: startY,
159
+ x2: midX,
160
+ y2: endY
161
+ }, {
162
+ color: lineColor,
163
+ lineWidth
155
164
  });
156
- ctx.slide.addShape(ctx.pptx.ShapeType.line, {
157
- x: pxToIn(midX),
158
- y: pxToIn(endY),
159
- w: pxToIn(endX - midX),
160
- h: 0,
161
- line: {
162
- color: lineColor,
163
- width: pxToPt(lineWidth),
164
- endArrowType: arrowType
165
- }
165
+ addStraightLine(ctx, {
166
+ x1: midX,
167
+ y1: endY,
168
+ x2: endX,
169
+ y2: endY
170
+ }, {
171
+ color: lineColor,
172
+ lineWidth,
173
+ endArrow: { type: arrowType }
166
174
  });
167
175
  } else {
168
- ctx.slide.addShape(ctx.pptx.ShapeType.line, {
169
- x: pxToIn(startX),
170
- y: pxToIn(startY),
171
- w: 0,
172
- h: pxToIn(midY - startY),
173
- line: {
174
- color: lineColor,
175
- width: pxToPt(lineWidth)
176
- }
176
+ addStraightLine(ctx, {
177
+ x1: startX,
178
+ y1: startY,
179
+ x2: startX,
180
+ y2: midY
181
+ }, {
182
+ color: lineColor,
183
+ lineWidth
177
184
  });
178
- ctx.slide.addShape(ctx.pptx.ShapeType.line, {
179
- x: pxToIn(Math.min(startX, endX)),
180
- y: pxToIn(midY),
181
- w: pxToIn(Math.abs(endX - startX)),
182
- h: 0,
183
- line: {
184
- color: lineColor,
185
- width: pxToPt(lineWidth)
186
- }
185
+ addStraightLine(ctx, {
186
+ x1: startX,
187
+ y1: midY,
188
+ x2: endX,
189
+ y2: midY
190
+ }, {
191
+ color: lineColor,
192
+ lineWidth
187
193
  });
188
- ctx.slide.addShape(ctx.pptx.ShapeType.line, {
189
- x: pxToIn(endX),
190
- y: pxToIn(midY),
191
- w: 0,
192
- h: pxToIn(endY - midY),
193
- line: {
194
- color: lineColor,
195
- width: pxToPt(lineWidth),
196
- endArrowType: arrowType
197
- }
194
+ addStraightLine(ctx, {
195
+ x1: endX,
196
+ y1: midY,
197
+ x2: endX,
198
+ y2: endY
199
+ }, {
200
+ color: lineColor,
201
+ lineWidth,
202
+ endArrow: { type: arrowType }
198
203
  });
199
204
  }
200
205
  }
@@ -1 +1 @@
1
- {"version":3,"file":"flow.js","names":[],"sources":["../../../src/renderPptx/nodes/flow.ts"],"sourcesContent":["import type { PositionedNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { stripHash } from \"../utils/visualStyle.ts\";\nimport { pxToIn, pxToPt } from \"../units.ts\";\nimport { measureFlow } from \"../../calcYogaLayout/measureCompositeNodes.ts\";\nimport { resolveScaledContentArea } from \"../utils/scaleToFit.ts\";\nimport { withContentBounds } from \"../utils/contentArea.ts\";\n\ntype FlowPositionedNode = Extract<PositionedNode, { type: \"flow\" }>;\n\ninterface FlowNodeLayout {\n id: string;\n x: number;\n y: number;\n width: number;\n height: number;\n item: FlowPositionedNode[\"nodes\"][0];\n}\n\nexport function renderFlowNode(\n node: FlowPositionedNode,\n ctx: RenderContext,\n): void {\n const direction = node.direction ?? \"horizontal\";\n const nodeWidth = node.nodeWidth ?? 120;\n const nodeHeight = node.nodeHeight ?? 60;\n const nodeGap = node.nodeGap ?? 80;\n const connectorStyle = node.connectorStyle ?? {};\n const defaultColor = \"1D4ED8\";\n\n // スケール係数を計算(コンテンツ領域基準)\n const { content, scaleFactor } = resolveScaledContentArea(\n node,\n measureFlow(node),\n ctx,\n );\n\n const scaledNodeWidth = nodeWidth * scaleFactor;\n const scaledNodeHeight = nodeHeight * scaleFactor;\n const scaledNodeGap = nodeGap * scaleFactor;\n\n const layouts = new Map<string, FlowNodeLayout>();\n const nodeCount = node.nodes.length;\n\n // コンテンツ領域を使用するための仮想ノードを作成\n const contentNode = withContentBounds(node, content);\n\n // ノードのレイアウトを計算\n if (direction === \"horizontal\") {\n calculateHorizontalLayout(\n contentNode,\n layouts,\n nodeCount,\n scaledNodeWidth,\n scaledNodeHeight,\n scaledNodeGap,\n scaleFactor,\n );\n } else {\n calculateVerticalLayout(\n contentNode,\n layouts,\n nodeCount,\n scaledNodeWidth,\n scaledNodeHeight,\n scaledNodeGap,\n scaleFactor,\n );\n }\n\n // 接続線を描画(ノードより先に描画して背面に配置)\n for (const conn of node.connections) {\n const fromLayout = layouts.get(conn.from);\n const toLayout = layouts.get(conn.to);\n\n if (!fromLayout || !toLayout) continue;\n\n const lineColor = conn.color ?? connectorStyle.color ?? \"333333\";\n const lineWidth = (connectorStyle.width ?? 2) * scaleFactor;\n const arrowType = connectorStyle.arrowType ?? \"triangle\";\n\n drawConnection(\n ctx,\n direction,\n fromLayout,\n toLayout,\n lineColor,\n lineWidth,\n arrowType,\n );\n\n // ラベルを描画\n if (conn.label) {\n const labelX =\n (fromLayout.x +\n fromLayout.width / 2 +\n toLayout.x +\n toLayout.width / 2) /\n 2;\n const labelY =\n (fromLayout.y +\n fromLayout.height / 2 +\n toLayout.y +\n toLayout.height / 2) /\n 2;\n\n const labelW = 60 * scaleFactor;\n const labelH = 20 * scaleFactor;\n\n ctx.slide.addText(conn.label, {\n x: pxToIn(labelX - labelW / 2),\n y: pxToIn(labelY - labelH / 2),\n w: pxToIn(labelW),\n h: pxToIn(labelH),\n fontSize: pxToPt(10 * scaleFactor),\n fontFace: \"Noto Sans JP\",\n color:\n stripHash(conn.labelColor) ??\n stripHash(connectorStyle.labelColor) ??\n \"64748B\",\n align: \"center\",\n valign: \"middle\",\n });\n }\n }\n\n // ノードを描画\n for (const item of node.nodes) {\n const layout = layouts.get(item.id);\n if (!layout) continue;\n\n const fillColor = item.color ?? defaultColor;\n const textColor = item.textColor ?? \"FFFFFF\";\n\n // 図形を描画\n ctx.slide.addText(item.text, {\n x: pxToIn(layout.x),\n y: pxToIn(layout.y),\n w: pxToIn(layout.width),\n h: pxToIn(layout.height),\n shape: item.shape,\n fill: { color: fillColor },\n line: { color: \"333333\", width: pxToPt(1 * scaleFactor) },\n fontSize: pxToPt(14 * scaleFactor),\n fontFace: \"Noto Sans JP\",\n color: textColor,\n align: \"center\",\n valign: \"middle\",\n });\n }\n}\n\nfunction calculateHorizontalLayout(\n node: FlowPositionedNode,\n layouts: Map<string, FlowNodeLayout>,\n nodeCount: number,\n nodeWidth: number,\n nodeHeight: number,\n nodeGap: number,\n scaleFactor: number,\n): void {\n const totalWidth = nodeCount * nodeWidth + (nodeCount - 1) * nodeGap;\n const startX = node.x + (node.w - totalWidth) / 2;\n const centerY = node.y + node.h / 2;\n\n node.nodes.forEach((item, index) => {\n const w = (item.width ?? nodeWidth / scaleFactor) * scaleFactor;\n const h = (item.height ?? nodeHeight / scaleFactor) * scaleFactor;\n layouts.set(item.id, {\n id: item.id,\n x: startX + index * (nodeWidth + nodeGap) + (nodeWidth - w) / 2,\n y: centerY - h / 2,\n width: w,\n height: h,\n item,\n });\n });\n}\n\nfunction calculateVerticalLayout(\n node: FlowPositionedNode,\n layouts: Map<string, FlowNodeLayout>,\n nodeCount: number,\n nodeWidth: number,\n nodeHeight: number,\n nodeGap: number,\n scaleFactor: number,\n): void {\n const totalHeight = nodeCount * nodeHeight + (nodeCount - 1) * nodeGap;\n const startY = node.y + (node.h - totalHeight) / 2;\n const centerX = node.x + node.w / 2;\n\n node.nodes.forEach((item, index) => {\n const w = (item.width ?? nodeWidth / scaleFactor) * scaleFactor;\n const h = (item.height ?? nodeHeight / scaleFactor) * scaleFactor;\n layouts.set(item.id, {\n id: item.id,\n x: centerX - w / 2,\n y: startY + index * (nodeHeight + nodeGap) + (nodeHeight - h) / 2,\n width: w,\n height: h,\n item,\n });\n });\n}\n\nfunction drawConnection(\n ctx: RenderContext,\n direction: \"horizontal\" | \"vertical\",\n fromLayout: FlowNodeLayout,\n toLayout: FlowNodeLayout,\n lineColor: string,\n lineWidth: number,\n arrowType: \"none\" | \"arrow\" | \"diamond\" | \"oval\" | \"stealth\" | \"triangle\",\n): void {\n let startX: number, startY: number, endX: number, endY: number;\n\n if (direction === \"horizontal\") {\n // 水平: 右端から左端へ\n startX = fromLayout.x + fromLayout.width;\n startY = fromLayout.y + fromLayout.height / 2;\n endX = toLayout.x;\n endY = toLayout.y + toLayout.height / 2;\n } else {\n // 垂直: 下端から上端へ\n startX = fromLayout.x + fromLayout.width / 2;\n startY = fromLayout.y + fromLayout.height;\n endX = toLayout.x + toLayout.width / 2;\n endY = toLayout.y;\n }\n\n // 直線接続(シンプルなケース)\n const isHorizontalLine = Math.abs(startY - endY) < 1;\n const isVerticalLine = Math.abs(startX - endX) < 1;\n\n if (isHorizontalLine || isVerticalLine) {\n // 直線で描画\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(Math.min(startX, endX)),\n y: pxToIn(Math.min(startY, endY)),\n w: pxToIn(Math.abs(endX - startX)),\n h: pxToIn(Math.abs(endY - startY)),\n line: {\n color: lineColor,\n width: pxToPt(lineWidth),\n endArrowType: arrowType,\n },\n });\n } else {\n // L字型接続\n drawLShapedConnection(\n ctx,\n direction,\n startX,\n startY,\n endX,\n endY,\n lineColor,\n lineWidth,\n arrowType,\n );\n }\n}\n\nfunction drawLShapedConnection(\n ctx: RenderContext,\n direction: \"horizontal\" | \"vertical\",\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n lineColor: string,\n lineWidth: number,\n arrowType: \"none\" | \"arrow\" | \"diamond\" | \"oval\" | \"stealth\" | \"triangle\",\n): void {\n const midX = (startX + endX) / 2;\n const midY = (startY + endY) / 2;\n\n if (direction === \"horizontal\") {\n // 水平→垂直→水平\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(startX),\n y: pxToIn(startY),\n w: pxToIn(midX - startX),\n h: 0,\n line: { color: lineColor, width: pxToPt(lineWidth) },\n });\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(midX),\n y: pxToIn(Math.min(startY, endY)),\n w: 0,\n h: pxToIn(Math.abs(endY - startY)),\n line: { color: lineColor, width: pxToPt(lineWidth) },\n });\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(midX),\n y: pxToIn(endY),\n w: pxToIn(endX - midX),\n h: 0,\n line: {\n color: lineColor,\n width: pxToPt(lineWidth),\n endArrowType: arrowType,\n },\n });\n } else {\n // 垂直→水平→垂直\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(startX),\n y: pxToIn(startY),\n w: 0,\n h: pxToIn(midY - startY),\n line: { color: lineColor, width: pxToPt(lineWidth) },\n });\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(Math.min(startX, endX)),\n y: pxToIn(midY),\n w: pxToIn(Math.abs(endX - startX)),\n h: 0,\n line: { color: lineColor, width: pxToPt(lineWidth) },\n });\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(endX),\n y: pxToIn(midY),\n w: 0,\n h: pxToIn(endY - midY),\n line: {\n color: lineColor,\n width: pxToPt(lineWidth),\n endArrowType: arrowType,\n },\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"flow.js","names":[],"sources":["../../../src/renderPptx/nodes/flow.ts"],"sourcesContent":["import type { PositionedNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { stripHash } from \"../utils/visualStyle.ts\";\nimport { measureFlow } from \"../../calcYogaLayout/measureCompositeNodes.ts\";\nimport { resolveScaledContentArea } from \"../utils/scaleToFit.ts\";\nimport { withContentBounds } from \"../utils/contentArea.ts\";\nimport { addStraightLine } from \"../utils/straightLine.ts\";\nimport {\n addGlimpseShape,\n createShapeBoundsInput,\n shapeOutline,\n solidShapeFill,\n} from \"../utils/glimpseShape.ts\";\nimport {\n createGlimpseParagraphs,\n addGlimpseTextBox,\n} from \"../utils/glimpseTextBox.ts\";\n\ntype FlowPositionedNode = Extract<PositionedNode, { type: \"flow\" }>;\n\ninterface FlowNodeLayout {\n id: string;\n x: number;\n y: number;\n width: number;\n height: number;\n item: FlowPositionedNode[\"nodes\"][0];\n}\n\nexport function renderFlowNode(\n node: FlowPositionedNode,\n ctx: RenderContext,\n): void {\n const direction = node.direction ?? \"horizontal\";\n const nodeWidth = node.nodeWidth ?? 120;\n const nodeHeight = node.nodeHeight ?? 60;\n const nodeGap = node.nodeGap ?? 80;\n const connectorStyle = node.connectorStyle ?? {};\n const defaultColor = \"1D4ED8\";\n\n // スケール係数を計算(コンテンツ領域基準)\n const { content, scaleFactor } = resolveScaledContentArea(\n node,\n measureFlow(node),\n ctx,\n );\n\n const scaledNodeWidth = nodeWidth * scaleFactor;\n const scaledNodeHeight = nodeHeight * scaleFactor;\n const scaledNodeGap = nodeGap * scaleFactor;\n\n const layouts = new Map<string, FlowNodeLayout>();\n const nodeCount = node.nodes.length;\n\n // コンテンツ領域を使用するための仮想ノードを作成\n const contentNode = withContentBounds(node, content);\n\n // ノードのレイアウトを計算\n if (direction === \"horizontal\") {\n calculateHorizontalLayout(\n contentNode,\n layouts,\n nodeCount,\n scaledNodeWidth,\n scaledNodeHeight,\n scaledNodeGap,\n scaleFactor,\n );\n } else {\n calculateVerticalLayout(\n contentNode,\n layouts,\n nodeCount,\n scaledNodeWidth,\n scaledNodeHeight,\n scaledNodeGap,\n scaleFactor,\n );\n }\n\n // 接続線を描画(ノードより先に描画して背面に配置)\n for (const conn of node.connections) {\n const fromLayout = layouts.get(conn.from);\n const toLayout = layouts.get(conn.to);\n\n if (!fromLayout || !toLayout) continue;\n\n const lineColor = conn.color ?? connectorStyle.color ?? \"333333\";\n const lineWidth = (connectorStyle.width ?? 2) * scaleFactor;\n const arrowType = connectorStyle.arrowType ?? \"triangle\";\n\n drawConnection(\n ctx,\n direction,\n fromLayout,\n toLayout,\n lineColor,\n lineWidth,\n arrowType,\n );\n\n // ラベルを描画\n if (conn.label) {\n const labelX =\n (fromLayout.x +\n fromLayout.width / 2 +\n toLayout.x +\n toLayout.width / 2) /\n 2;\n const labelY =\n (fromLayout.y +\n fromLayout.height / 2 +\n toLayout.y +\n toLayout.height / 2) /\n 2;\n\n const labelW = 60 * scaleFactor;\n const labelH = 20 * scaleFactor;\n\n addGlimpseTextBox(\n ctx,\n {\n x: labelX - labelW / 2,\n y: labelY - labelH / 2,\n w: labelW,\n h: labelH,\n },\n {\n text: conn.label,\n fontSize: 10 * scaleFactor,\n fontFace: \"Noto Sans JP\",\n color:\n stripHash(conn.labelColor) ??\n stripHash(connectorStyle.labelColor) ??\n \"64748B\",\n align: \"center\",\n valign: \"middle\",\n },\n );\n }\n }\n\n // ノードを描画\n for (const item of node.nodes) {\n const layout = layouts.get(item.id);\n if (!layout) continue;\n\n const fillColor = item.color ?? defaultColor;\n const textColor = item.textColor ?? \"FFFFFF\";\n\n // 図形を描画\n addGlimpseShape(\n ctx,\n {\n preset: item.shape,\n ...createShapeBoundsInput({\n x: layout.x,\n y: layout.y,\n w: layout.width,\n h: layout.height,\n }),\n fill: solidShapeFill(fillColor),\n outline: shapeOutline({ color: \"333333\", width: 1 * scaleFactor }),\n body: { anchor: \"middle\" },\n paragraphs: createGlimpseParagraphs(\n item.text,\n {\n fontSize: 14 * scaleFactor,\n fontFace: \"Noto Sans JP\",\n color: textColor,\n },\n { align: \"center\" },\n ),\n },\n { x: layout.x, y: layout.y, w: layout.width, h: layout.height },\n { fillColor },\n );\n }\n}\n\nfunction calculateHorizontalLayout(\n node: FlowPositionedNode,\n layouts: Map<string, FlowNodeLayout>,\n nodeCount: number,\n nodeWidth: number,\n nodeHeight: number,\n nodeGap: number,\n scaleFactor: number,\n): void {\n const totalWidth = nodeCount * nodeWidth + (nodeCount - 1) * nodeGap;\n const startX = node.x + (node.w - totalWidth) / 2;\n const centerY = node.y + node.h / 2;\n\n node.nodes.forEach((item, index) => {\n const w = (item.width ?? nodeWidth / scaleFactor) * scaleFactor;\n const h = (item.height ?? nodeHeight / scaleFactor) * scaleFactor;\n layouts.set(item.id, {\n id: item.id,\n x: startX + index * (nodeWidth + nodeGap) + (nodeWidth - w) / 2,\n y: centerY - h / 2,\n width: w,\n height: h,\n item,\n });\n });\n}\n\nfunction calculateVerticalLayout(\n node: FlowPositionedNode,\n layouts: Map<string, FlowNodeLayout>,\n nodeCount: number,\n nodeWidth: number,\n nodeHeight: number,\n nodeGap: number,\n scaleFactor: number,\n): void {\n const totalHeight = nodeCount * nodeHeight + (nodeCount - 1) * nodeGap;\n const startY = node.y + (node.h - totalHeight) / 2;\n const centerX = node.x + node.w / 2;\n\n node.nodes.forEach((item, index) => {\n const w = (item.width ?? nodeWidth / scaleFactor) * scaleFactor;\n const h = (item.height ?? nodeHeight / scaleFactor) * scaleFactor;\n layouts.set(item.id, {\n id: item.id,\n x: centerX - w / 2,\n y: startY + index * (nodeHeight + nodeGap) + (nodeHeight - h) / 2,\n width: w,\n height: h,\n item,\n });\n });\n}\n\nfunction drawConnection(\n ctx: RenderContext,\n direction: \"horizontal\" | \"vertical\",\n fromLayout: FlowNodeLayout,\n toLayout: FlowNodeLayout,\n lineColor: string,\n lineWidth: number,\n arrowType: \"none\" | \"arrow\" | \"diamond\" | \"oval\" | \"stealth\" | \"triangle\",\n): void {\n let startX: number, startY: number, endX: number, endY: number;\n\n if (direction === \"horizontal\") {\n // 水平: 右端から左端へ\n startX = fromLayout.x + fromLayout.width;\n startY = fromLayout.y + fromLayout.height / 2;\n endX = toLayout.x;\n endY = toLayout.y + toLayout.height / 2;\n } else {\n // 垂直: 下端から上端へ\n startX = fromLayout.x + fromLayout.width / 2;\n startY = fromLayout.y + fromLayout.height;\n endX = toLayout.x + toLayout.width / 2;\n endY = toLayout.y;\n }\n\n // 直線接続(シンプルなケース)\n const isHorizontalLine = Math.abs(startY - endY) < 1;\n const isVerticalLine = Math.abs(startX - endX) < 1;\n\n if (isHorizontalLine || isVerticalLine) {\n // 直線で描画\n addStraightLine(\n ctx,\n { x1: startX, y1: startY, x2: endX, y2: endY },\n { color: lineColor, lineWidth, endArrow: { type: arrowType } },\n );\n } else {\n // L字型接続\n drawLShapedConnection(\n ctx,\n direction,\n startX,\n startY,\n endX,\n endY,\n lineColor,\n lineWidth,\n arrowType,\n );\n }\n}\n\nfunction drawLShapedConnection(\n ctx: RenderContext,\n direction: \"horizontal\" | \"vertical\",\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n lineColor: string,\n lineWidth: number,\n arrowType: \"none\" | \"arrow\" | \"diamond\" | \"oval\" | \"stealth\" | \"triangle\",\n): void {\n const midX = (startX + endX) / 2;\n const midY = (startY + endY) / 2;\n\n if (direction === \"horizontal\") {\n // 水平→垂直→水平\n addStraightLine(\n ctx,\n { x1: startX, y1: startY, x2: midX, y2: startY },\n { color: lineColor, lineWidth },\n );\n addStraightLine(\n ctx,\n { x1: midX, y1: startY, x2: midX, y2: endY },\n { color: lineColor, lineWidth },\n );\n addStraightLine(\n ctx,\n { x1: midX, y1: endY, x2: endX, y2: endY },\n { color: lineColor, lineWidth, endArrow: { type: arrowType } },\n );\n } else {\n // 垂直→水平→垂直\n addStraightLine(\n ctx,\n { x1: startX, y1: startY, x2: startX, y2: midY },\n { color: lineColor, lineWidth },\n );\n addStraightLine(\n ctx,\n { x1: startX, y1: midY, x2: endX, y2: midY },\n { color: lineColor, lineWidth },\n );\n addStraightLine(\n ctx,\n { x1: endX, y1: midY, x2: endX, y2: endY },\n { color: lineColor, lineWidth, endArrow: { type: arrowType } },\n );\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,8 @@
1
- import { pxToIn, pxToPt } from "../units.js";
1
+ import { pxToEmu } from "../units.js";
2
+ import { toColorInput } from "../glimpseTextBoxes.js";
3
+ import { addGlimpsePicture, imageBytesFromSource } from "../utils/glimpsePicture.js";
4
+ import { addGlimpseShape, createShapeBoundsInput, createShapeRotationInput, noShapeOutline, noneShapeFill, shapeOutline, solidShapeFill } from "../utils/glimpseShape.js";
5
+ import { asEmu } from "@pptx-glimpse/document";
2
6
  //#region src/renderPptx/nodes/icon.ts
3
7
  function renderIconNode(node, ctx) {
4
8
  if (node.variant) {
@@ -7,35 +11,40 @@ function renderIconNode(node, ctx) {
7
11
  const colorValue = (node.bgColor ?? "#E0E0E0").replace(/^#/, "");
8
12
  const variantDefaultLine = isFilled ? void 0 : {
9
13
  color: colorValue,
10
- width: 1.5
14
+ width: 2
11
15
  };
12
16
  const outlineLine = node.outline ? {
13
17
  color: node.outline.color ?? variantDefaultLine?.color ?? "FFFFFF",
14
- width: node.outline.size !== void 0 ? pxToPt(node.outline.size) : variantDefaultLine?.width ?? 1
18
+ width: node.outline.size !== void 0 ? node.outline.size : variantDefaultLine?.width ?? 1
15
19
  } : variantDefaultLine;
16
- const glowMarker = node.glow ? ctx.buildContext.glowEffects.register(node.glow) : void 0;
17
- const shapeType = isCircle ? "ellipse" : "roundRect";
18
- const shapeOptions = {
19
- x: pxToIn(node.bgX ?? node.x),
20
- y: pxToIn(node.bgY ?? node.y),
21
- w: pxToIn(node.bgW ?? node.w),
22
- h: pxToIn(node.bgH ?? node.h),
23
- fill: isFilled ? { color: colorValue } : { type: "none" },
24
- line: outlineLine,
25
- rectRadius: isCircle ? void 0 : .1,
26
- rotate: node.rotate,
27
- objectName: glowMarker
20
+ const bounds = {
21
+ x: node.bgX ?? node.x,
22
+ y: node.bgY ?? node.y,
23
+ w: node.bgW ?? node.w,
24
+ h: node.bgH ?? node.h
28
25
  };
29
- ctx.slide.addShape(shapeType, shapeOptions);
26
+ addGlimpseShape(ctx, {
27
+ preset: isCircle ? "ellipse" : "roundRect",
28
+ ...createShapeBoundsInput(bounds),
29
+ rotation: createShapeRotationInput(node.rotate),
30
+ fill: isFilled ? solidShapeFill(colorValue) : noneShapeFill(),
31
+ outline: outlineLine ? shapeOutline(outlineLine) : noShapeOutline(),
32
+ effects: node.glow ? { glow: {
33
+ radius: asEmu(Math.round(pxToEmu(node.glow.size ?? 8))),
34
+ color: toColorInput(node.glow.color ?? "FFFFFF")
35
+ } } : void 0
36
+ }, bounds, {
37
+ fillColor: isFilled ? colorValue : void 0,
38
+ glow: node.glow,
39
+ rectRadius: isCircle ? void 0 : .1
40
+ });
30
41
  }
31
- ctx.slide.addImage({
32
- data: node.iconImageData,
33
- x: pxToIn(node.iconX ?? node.x),
34
- y: pxToIn(node.iconY ?? node.y),
35
- w: pxToIn(node.iconW ?? node.w),
36
- h: pxToIn(node.iconH ?? node.h),
37
- rotate: node.rotate
38
- });
42
+ addGlimpsePicture(ctx, {
43
+ x: node.iconX ?? node.x,
44
+ y: node.iconY ?? node.y,
45
+ w: node.iconW ?? node.w,
46
+ h: node.iconH ?? node.h
47
+ }, imageBytesFromSource("", node.iconImageData), { rotate: node.rotate });
39
48
  }
40
49
  //#endregion
41
50
  export { renderIconNode };
@@ -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, 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"}
1
+ {"version":3,"file":"icon.js","names":[],"sources":["../../../src/renderPptx/nodes/icon.ts"],"sourcesContent":["import { asEmu } from \"@pptx-glimpse/document\";\nimport type { PositionedNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { toColorInput } from \"../glimpseTextBoxes.ts\";\nimport { pxToEmu } from \"../units.ts\";\nimport {\n addGlimpsePicture,\n imageBytesFromSource,\n} from \"../utils/glimpsePicture.ts\";\nimport {\n addGlimpseShape,\n createShapeBoundsInput,\n createShapeRotationInput,\n noShapeOutline,\n noneShapeFill,\n shapeOutline,\n solidShapeFill,\n} from \"../utils/glimpseShape.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 相当 (2px)、\n // filled variant は undefined (枠線なし)。\n const variantDefaultLine = isFilled\n ? undefined\n : { color: colorValue, width: 2 };\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 ? node.outline.size\n : (variantDefaultLine?.width ?? 1),\n }\n : variantDefaultLine;\n\n const bounds = {\n x: node.bgX ?? node.x,\n y: node.bgY ?? node.y,\n w: node.bgW ?? node.w,\n h: node.bgH ?? node.h,\n };\n const shapeType = isCircle ? \"ellipse\" : \"roundRect\";\n\n addGlimpseShape(\n ctx,\n {\n preset: shapeType,\n ...createShapeBoundsInput(bounds),\n rotation: createShapeRotationInput(node.rotate),\n fill: isFilled ? solidShapeFill(colorValue) : noneShapeFill(),\n outline: outlineLine ? shapeOutline(outlineLine) : noShapeOutline(),\n effects: node.glow\n ? {\n glow: {\n radius: asEmu(Math.round(pxToEmu(node.glow.size ?? 8))),\n color: toColorInput(node.glow.color ?? \"FFFFFF\")!,\n },\n }\n : undefined,\n },\n bounds,\n {\n fillColor: isFilled ? colorValue : undefined,\n glow: node.glow,\n rectRadius: isCircle ? undefined : 0.1,\n },\n );\n }\n\n addGlimpsePicture(\n ctx,\n {\n x: node.iconX ?? node.x,\n y: node.iconY ?? node.y,\n w: node.iconW ?? node.w,\n h: node.iconH ?? node.h,\n },\n imageBytesFromSource(\"\", node.iconImageData),\n { rotate: node.rotate },\n );\n}\n"],"mappings":";;;;;;AAqBA,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;EAAE;EAKlC,MAAM,cAAc,KAAK,UACrB;GACE,OAAO,KAAK,QAAQ,SAAS,oBAAoB,SAAS;GAC1D,OACE,KAAK,QAAQ,SAAS,KAAA,IAClB,KAAK,QAAQ,OACZ,oBAAoB,SAAS;EACtC,IACA;EAEJ,MAAM,SAAS;GACb,GAAG,KAAK,OAAO,KAAK;GACpB,GAAG,KAAK,OAAO,KAAK;GACpB,GAAG,KAAK,OAAO,KAAK;GACpB,GAAG,KAAK,OAAO,KAAK;EACtB;EAGA,gBACE,KACA;GACE,QALc,WAAW,YAAY;GAMrC,GAAG,uBAAuB,MAAM;GAChC,UAAU,yBAAyB,KAAK,MAAM;GAC9C,MAAM,WAAW,eAAe,UAAU,IAAI,cAAc;GAC5D,SAAS,cAAc,aAAa,WAAW,IAAI,eAAe;GAClE,SAAS,KAAK,OACV,EACE,MAAM;IACJ,QAAQ,MAAM,KAAK,MAAM,QAAQ,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC;IACtD,OAAO,aAAa,KAAK,KAAK,SAAS,QAAQ;GACjD,EACF,IACA,KAAA;EACN,GACA,QACA;GACE,WAAW,WAAW,aAAa,KAAA;GACnC,MAAM,KAAK;GACX,YAAY,WAAW,KAAA,IAAY;EACrC,CACF;CACF;CAEA,kBACE,KACA;EACE,GAAG,KAAK,SAAS,KAAK;EACtB,GAAG,KAAK,SAAS,KAAK;EACtB,GAAG,KAAK,SAAS,KAAK;EACtB,GAAG,KAAK,SAAS,KAAK;CACxB,GACA,qBAAqB,IAAI,KAAK,aAAa,GAC3C,EAAE,QAAQ,KAAK,OAAO,CACxB;AACF"}
@@ -1,28 +1,11 @@
1
- import { pxToIn, rectPxToIn } from "../units.js";
2
1
  import { getContentArea } from "../utils/contentArea.js";
3
- import { convertShadow } from "../utils/visualStyle.js";
2
+ import { addGlimpsePicture, imageBytesFromSource } from "../utils/glimpsePicture.js";
4
3
  //#region src/renderPptx/nodes/image.ts
5
4
  function renderImageNode(node, ctx) {
6
- const content = getContentArea(node);
7
- const imageOptions = {
8
- ...rectPxToIn(content),
9
- shadow: convertShadow(node.shadow),
10
- rotate: node.rotate
11
- };
12
- if (node.sizing) imageOptions.sizing = {
13
- type: node.sizing.type,
14
- w: pxToIn(node.sizing.w ?? content.w),
15
- h: pxToIn(node.sizing.h ?? content.h),
16
- ...node.sizing.x !== void 0 && { x: pxToIn(node.sizing.x) },
17
- ...node.sizing.y !== void 0 && { y: pxToIn(node.sizing.y) }
18
- };
19
- if (node.imageData) ctx.slide.addImage({
20
- ...imageOptions,
21
- data: node.imageData
22
- });
23
- else ctx.slide.addImage({
24
- ...imageOptions,
25
- path: node.src
5
+ addGlimpsePicture(ctx, getContentArea(node), imageBytesFromSource(node.src, node.imageData), {
6
+ rotate: node.rotate,
7
+ sizing: node.sizing,
8
+ shadow: node.shadow
26
9
  });
27
10
  }
28
11
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"image.js","names":[],"sources":["../../../src/renderPptx/nodes/image.ts"],"sourcesContent":["import type { PositionedNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { pxToIn, rectPxToIn } from \"../units.ts\";\nimport { getContentArea } from \"../utils/contentArea.ts\";\nimport { convertShadow } from \"../utils/visualStyle.ts\";\n\ntype ImagePositionedNode = Extract<PositionedNode, { type: \"image\" }>;\n\nexport function renderImageNode(\n node: ImagePositionedNode,\n ctx: RenderContext,\n): void {\n const content = getContentArea(node);\n const imageOptions: Record<string, unknown> = {\n ...rectPxToIn(content),\n shadow: convertShadow(node.shadow),\n rotate: node.rotate,\n };\n\n if (node.sizing) {\n imageOptions.sizing = {\n type: node.sizing.type,\n w: pxToIn(node.sizing.w ?? content.w),\n h: pxToIn(node.sizing.h ?? content.h),\n ...(node.sizing.x !== undefined && { x: pxToIn(node.sizing.x) }),\n ...(node.sizing.y !== undefined && { y: pxToIn(node.sizing.y) }),\n };\n }\n\n if (node.imageData) {\n // Base64 データがある場合は data プロパティを使用(リモート画像)\n ctx.slide.addImage({ ...imageOptions, data: node.imageData });\n } else {\n // ローカルパスの場合は path プロパティを使用\n ctx.slide.addImage({ ...imageOptions, path: node.src });\n }\n}\n"],"mappings":";;;;AAQA,SAAgB,gBACd,MACA,KACM;CACN,MAAM,UAAU,eAAe,IAAI;CACnC,MAAM,eAAwC;EAC5C,GAAG,WAAW,OAAO;EACrB,QAAQ,cAAc,KAAK,MAAM;EACjC,QAAQ,KAAK;CACf;CAEA,IAAI,KAAK,QACP,aAAa,SAAS;EACpB,MAAM,KAAK,OAAO;EAClB,GAAG,OAAO,KAAK,OAAO,KAAK,QAAQ,CAAC;EACpC,GAAG,OAAO,KAAK,OAAO,KAAK,QAAQ,CAAC;EACpC,GAAI,KAAK,OAAO,MAAM,KAAA,KAAa,EAAE,GAAG,OAAO,KAAK,OAAO,CAAC,EAAE;EAC9D,GAAI,KAAK,OAAO,MAAM,KAAA,KAAa,EAAE,GAAG,OAAO,KAAK,OAAO,CAAC,EAAE;CAChE;CAGF,IAAI,KAAK,WAEP,IAAI,MAAM,SAAS;EAAE,GAAG;EAAc,MAAM,KAAK;CAAU,CAAC;MAG5D,IAAI,MAAM,SAAS;EAAE,GAAG;EAAc,MAAM,KAAK;CAAI,CAAC;AAE1D"}
1
+ {"version":3,"file":"image.js","names":[],"sources":["../../../src/renderPptx/nodes/image.ts"],"sourcesContent":["import type { PositionedNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { getContentArea } from \"../utils/contentArea.ts\";\nimport {\n addGlimpsePicture,\n imageBytesFromSource,\n} from \"../utils/glimpsePicture.ts\";\n\ntype ImagePositionedNode = Extract<PositionedNode, { type: \"image\" }>;\n\nexport function renderImageNode(\n node: ImagePositionedNode,\n ctx: RenderContext,\n): void {\n const content = getContentArea(node);\n addGlimpsePicture(\n ctx,\n content,\n imageBytesFromSource(node.src, node.imageData),\n {\n rotate: node.rotate,\n sizing: node.sizing,\n shadow: node.shadow,\n },\n );\n}\n"],"mappings":";;;AAUA,SAAgB,gBACd,MACA,KACM;CAEN,kBACE,KAFc,eAAe,IAGvB,GACN,qBAAqB,KAAK,KAAK,KAAK,SAAS,GAC7C;EACE,QAAQ,KAAK;EACb,QAAQ,KAAK;EACb,QAAQ,KAAK;CACf,CACF;AACF"}