tech-book-labs
データユーティリティ · 最終検証 2026-05-10 · pptxgenjs 4.x · 初公開 2026-05-10

pptxgenjs でブラウザだけで .pptx を生成する

PptxGenJS v4 を使った PowerPoint ファイル(.pptx)のクライアント生成パターン — addSlide / addText / addTable / addChart の最小構成、レイアウトサイズ(LAYOUT_WIDE)とテンプレ運用、ブラウザの writeFile / Node の writeFile / stream を出力先別に整理、画像/SVG 埋め込みの注意を触れる demo 付きで実装メモ化。

pptxgenjs powerpoint report-generation browser

検証日: 2026-05-10

使用バージョン: pptxgenjs@4.x

対象: 売上レポートや週次レポートを 手で PowerPoint に貼り直す 運用を、ブラウザ(またはサーバ)で自動生成に置き換えたい人

PptxGenJS v4 で .pptx ファイルをクライアント完結で生成 するパターン。addSlide / addText / addTable / addChart の最小構成、レイアウトサイズ(LAYOUT_WIDE)とテンプレ運用、ブラウザ ↔ Node の出力切替、画像 / SVG 埋め込みの注意を動く demo で確認します。

触って試す

タイトル / サブタイトル / 作者を入れて生成すると、3 スライド構成(タイトル / 表 / 棒グラフ)の .pptx がブラウザだけで作られダウンロードされる。

1. なぜ pptxgenjs か

「データから PowerPoint を自動生成」したい時の選択肢:

  • pptxgenjs:JS 製、ブラウザ + Node 両対応、グラフ / 表 / 画像 / SVG 全部入り
  • python-pptx:Python 製、サーバ運用に向く。ブラウザでは動かない
  • Apache POI:Java 製、エンタープライズ用、運用がやや重い
  • office.js / Microsoft Graph API:認証必要、PowerPoint アプリと連携する用途
  • 手動 ZIP + XML:.pptx は Open XML(zip)なので作れるが、検証が地獄

ブラウザ完結で .pptx を作れる」「Node でも同じ API」のは pptxgenjs が事実上唯一の選択肢。

2. 最小構成

pnpm add で導入 → 1 つのスライドを作って書き出す最小コード:

pnpm add pptxgenjs
import PptxGenJS from "pptxgenjs";

const pptx = new PptxGenJS();
pptx.layout = "LAYOUT_WIDE";        // 16:9 の 13.333 x 7.5 inch
pptx.author = "Editorial";
pptx.title = "Q2 Report";

const slide = pptx.addSlide();
slide.background = { color: "0F172A" };
slide.addText("Q2 Report", {
  x: 0.5, y: 1.6, w: 12, h: 1.2,
  fontSize: 40, bold: true, color: "FFFFFF",
});

// ブラウザ:ダウンロードを発火
await pptx.writeFile({ fileName: "report.pptx" });

// Node:ファイル保存
// await pptx.writeFile({ fileName: "/tmp/report.pptx" });

// 共通:バイナリで取り出し(Blob / Buffer / Uint8Array)
const blob = await pptx.write({ outputType: "blob" });

ポイント:

  • 座標は inch 単位(x: 0.5 = 0.5 インチ ≒ 1.27cm)
  • 色は HEX 文字列の # 抜き("FFFFFF" で白)
  • pptx.layout で画面サイズが切り替わる:LAYOUT_WIDE / LAYOUT_16x9 / LAYOUT_4x3 / LAYOUT_16x10
  • writeFile はブラウザでは「ダウンロード」、Node では「ファイル保存」と環境で挙動が変わる
.pptx 生成パイプライン — 内部は OOXML を zip にまとめる、最後の出力先は環境で切替 (クリックで拡大)

3. テキスト / 段落

addText は 1 つのテキストボックスを作る。文字列を直接渡せば単純テキスト、配列にすると 段落配列(部分書式を混在可能):

slide.addText("見出し", { x: 0.5, y: 0.3, w: 12, h: 0.6, fontSize: 28, bold: true });

// 段落配列(複数段落の混在)
slide.addText(
  [
    { text: "重要:", options: { bold: true, color: "DC2626" } },
    { text: " 売上は前年比 +18%、目標は達成。\n" },
    { text: "ただし KPI の達成度は地域差が大きい。" },
  ],
  { x: 0.5, y: 1.5, w: 12, h: 2, fontSize: 16 },
);

ポイント:

  • addText は 1 つのテキストボックスを作る。複数段落を入れたいなら配列で渡す
  • { text, options } の配列で部分的に色やサイズを変えられる
  • 改行は \n(段落区切り)、太字は bold: true

4. 表(table)

addTable2 次元配列(各セルは文字列 or { text, options })を渡す。ヘッダ行は太字 + 塗りつぶしで強調:

slide.addTable(
  [
    // ヘッダ行
    [
      { text: "地域", options: { bold: true, fill: { color: "1E293B" }, color: "FFFFFF" } },
      { text: "売上",  options: { bold: true, fill: { color: "1E293B" }, color: "FFFFFF" } },
    ],
    ["関東", "12,400"],
    ["関西", "7,800"],
  ],
  {
    x: 0.5, y: 1.2, w: 12,
    fontSize: 14,
    border: { type: "solid", color: "CBD5E1", pt: 0.75 },
    rowH: 0.4,                          // 行高(inch)
  },
);

ポイント:

  • セルは 文字列 or { text, options }(部分書式)
  • fill: { color: "..." } で背景色、border で罫線
  • 列幅は colW: [1, 2, 1.5](inch 配列) か w を指定して自動分割

5. グラフ(chart)

データから直接グラフを描ける(Excel に出力されるのと同じネイティブグラフ):

slide.addChart(
  pptx.ChartType.bar,
  [
    {
      name: "売上",
      labels: ["関東", "関西", "中部", "九州", "北海道"],
      values: [12400, 7800, 5200, 3100, 1800],
    },
  ],
  {
    x: 0.5, y: 1.0, w: 12, h: 5.5,
    chartColors: ["3B82F6"],
    showLegend: false,
    showValue: true,
    catAxisLabelFontSize: 12,
    valAxisLabelFontSize: 10,
  },
);

種類:

ChartType.*用途
bar / bar3Dカテゴリ別の量比較
line / line3D時系列
pie / doughnut構成比(2-5 カテゴリまで)
area / area3D累積、stacked 推移
scatter相関
radar複数軸の比較
bubble3 軸(x, y, size)

複数シリーズ:

slide.addChart(pptx.ChartType.line, [
  { name: "売上", labels, values: [...] },
  { name: "目標", labels, values: [...] },
], { x, y, w, h, chartColors: ["3B82F6", "EF4444"] });

「色 / 凡例 / 軸ラベル」のオプションが多いので、実物は pptx.ChartType.* の TypeScript 型で補完を見ながら詰める。

6. 画像(image)

URL / dataURL / SVG 文字列を addImage に渡す。ブラウザでは CORS の制約があるため、外部画像は dataURL に変換してから渡すと安全:

// URL から
slide.addImage({ path: "https://example.com/logo.png", x: 0.5, y: 0.3, w: 1.5, h: 0.5 });

// data URL
slide.addImage({ data: "data:image/png;base64,iVBOR...", x: 0.5, y: 1, w: 4, h: 3 });

// SVG(中身を文字列で)
slide.addImage({ data: `data:image/svg+xml;base64,${btoa(svgString)}`, x: 0.5, y: 1, w: 4, h: 3 });

ポイント:

  • CORS 制限:外部 URL の画像は CORS 設定が無いと読めないことがある。dataURL に変換(canvas → toDataURL)してから渡すと安全
  • SVG は base64 で data:image/svg+xml:そのまま path で渡すとブラウザによっては失敗
  • 大きい画像はファイルサイズに直結:5MB 級の写真を 10 枚入れると .pptx が 50MB 超に

7. レイアウトサイズ / マスター

pptx.layoutサイズ用途
LAYOUT_16x910 x 5.625 inch標準 16:9
LAYOUT_WIDE13.333 x 7.5 inch16:9 ワイド(現代の社内テンプレ)
LAYOUT_4x310 x 7.5 inch古い 4:3 プロジェクター
LAYOUT_16x1010 x 6.25 inch一部 LCD

カスタム:

pptx.defineLayout({ name: "CUSTOM", width: 16, height: 9 });
pptx.layout = "CUSTOM";

マスターで「全スライド共通の背景 / ロゴ / フッター」を定義:

pptx.defineSlideMaster({
  title: "BRAND",
  background: { color: "FFFFFF" },
  objects: [
    { image: { x: 0.2, y: 0.2, w: 1, h: 0.4, path: "/logo.png" } },
    { text: { text: "© 2026 Editorial", options: { x: 0.5, y: 7.0, w: 12, h: 0.3, fontSize: 9, color: "94A3B8" } } },
  ],
  slideNumber: { x: 12.5, y: 7.0, fontSize: 10, color: "94A3B8" },
});

const slide = pptx.addSlide({ masterName: "BRAND" });

会社テンプレに合わせる」のはマスター + addText の組合せで作り込む。

8. ブラウザ vs Node の違い

ブラウザNode
writeFile({fileName})ダウンロードを発火ファイル書込
write({outputType: "blob"})Blob を返すBuffer を返す(outputType: "nodebuffer" で明示)
stream()Blob を返すReadable を返す
画像 pathURL or dataURLURL or filesystem path

サーバ生成 → email 添付の例(Node):

const pptx = new PptxGenJS();
// ... compose slides
const buf = await pptx.write({ outputType: "nodebuffer" });
await transporter.sendMail({
  to: "user@example.com",
  attachments: [{ filename: "report.pptx", content: buf }],
});

API は同一なので、ブラウザでプレビュー → サーバで定期生成を同じコードベースで運用できる。

9. テンプレ駆動 + データ駆動の構成パターン

「データ → スライド組立」を関数化して、入力データ別に同じテンプレを当てる構成。複数顧客 / 月次レポートの 量産 に強い:

type ReportData = { region: string; total: number; growth: number }[];

function buildReport(data: ReportData, opts: { title: string; author: string }) {
  const pptx = new PptxGenJS();
  pptx.layout = "LAYOUT_WIDE";
  pptx.author = opts.author;
  pptx.title = opts.title;

  buildTitleSlide(pptx, opts.title);
  buildTableSlide(pptx, data);
  buildChartSlide(pptx, data);
  return pptx;
}

function buildTitleSlide(pptx: PptxGenJS, title: string) { /* ... */ }
function buildTableSlide(pptx: PptxGenJS, data: ReportData) { /* ... */ }
function buildChartSlide(pptx: PptxGenJS, data: ReportData) { /* ... */ }

ポイント:

  • 「スライド 1 つ = 関数 1 つ」 で分割すると、テンプレ変更が局所化する
  • データを引数に(計算済を渡す)。スライド関数は表示だけに専念
  • 共通ヘルパ:色、フォント、padding を const COLORS = {...} / const FONT = {...} で共有

つまずいたポイント

  • 画像が出ない:外部 URL は CORS、relative path はブラウザでは効かない。dataURL に統一すると安全
  • .pptx を Keynote で開くとレイアウトが崩れる:Keynote の互換は Office よりルーズ。社外配布は PDF も同梱
  • チャートの色が反映されない:chartColorsHEX(# なし)の文字列配列。配列要素数 < シリーズ数だと循環
  • 生成が重い:画像を多く貼ると blob 化に数秒〜。ブラウザでは Worker 化「生成中…」UI を出す
  • TypeScript の型補完が弱い:pptx.ChartType.bar は型が string 扱い。as const でリテラルを保つか、定数オブジェクトを別途定義
  • fontFace が反映されない:閲覧端末にそのフォントが入っていない場合、PowerPoint は代替フォントで表示。ブランドフォントは 画像化PowerPoint テンプレに埋め込み

関連 Topic / 関連書籍

この記事と関係する tech-book.net の Topic と、それぞれの Topic に紐づく書籍:

tech-book.net /books/9784297144944

JavaScriptによるはじめてのアルゴリズム入門

河西 朝雄
詳細を tech-book.net で見る
tech-book.net /books/9784873118086

Python と JavaScriptではじめるデータビジュアライゼーション

Kyran Dale/嶋田 健志/木下 哲也
詳細を tech-book.net で見る
tech-book.net /books/9784839966645

React Native+Expoではじめるスマホアプリ開発 : JavaScriptによるアプリ構築の実際

松澤 太郎 · マイナビ出版 · 2018年

「React Native」は、Facebookが開発しているスマートフォンアプリ向けの開発環境です。ほとんどのコードをJav…

詳細を tech-book.net で見る
tech-book.net /books/9784627857216

はじめてのWebデザイン&amp;プログラミング : HTML、CSS、JavaScript、PHPの基本

村上 祐治
詳細を tech-book.net で見る
tech-book.net /books/9784297138714

フロントエンドの知識地図ーー 一冊でHTML/CSS/JavaScriptの開発技術が学べる本

株式会社ICS 池田 泰延/西原 翼/松本 ゆき
詳細を tech-book.net で見る