PDFエクスポート
v1.4.0 から、ReoGrid インスタンスはアクティブなワークシートを本物のベクター PDF(テキスト・罫線・塗り・セル結合・セルアンカー画像)に出力できます。外部ライブラリもサーバー往復も不要で、ワークシートのデータからブラウザ内で生成します。
Note: PDFエクスポートは Pro 版で利用可能です。
フォントは必須です。 PDF レンダラーはグリフ輪郭を埋め込むため、エクスポートには実際のフォントのバイト列が必要です。
locale('ja'/'zh-CN'/'zh-TW'/'ko')を指定すれば ReoGrid がフォントを解決します。自前のバイト列をfontに渡すこともできます。どちらも指定しない場合はエクスポートが例外を投げます。これにより日本語・中国語・韓国語が正しく描画されます。
クイックスタート
import { createReogrid, preloadPdfFont } from '@reogrid/pro'
const grid = createReogrid({ workspace: '#app' })
// ロケールのフォントを一度だけ、自分で制御できる非同期地点で取得する
await preloadPdfFont('ja')
// レンダリングとダウンロードを 1 回で
grid.saveAsPdf({ locale: 'ja', filename: 'report.pdf' })
saveAsPdf() はレンダリングしてブラウザのダウンロードを起動します。生のバイト列が欲しい場合(アップロードやプレビューなど)は exportPdf() を使います。
const bytes: Uint8Array = grid.exportPdf({ locale: 'ja' })
// 例:プレビュー URL 用に Blob へラップ
const url = URL.createObjectURL(new Blob([bytes], { type: 'application/pdf' }))
なぜ
preloadPdfFontを分けているのか。 エクスポートは意図的に同期です。saveAsPdfは生成したリンクのクリックで終わりますが、その前にawaitが入るとユーザージェスチャーのコンテキストが失われ、ポップアップブロッカーに阻まれます。そこでダウンロードは呼び出し側が選んだ時点で一度だけ行い、以降のエクスポートは即座に完了します。数 MB のフォント取得がsaveAsPdf()の内部に隠れないという利点もあります。
ロケール
locale は、ReoGrid が取得方法を知っているフォントを指す名前です。標準で 4 つが登録されています。
| ロケール | フォント | 用途 |
|---|---|---|
'ja' | Noto Sans JP | 日本語 |
'zh-CN' | Noto Sans SC | 簡体字中国語 |
'zh-TW' | Noto Sans TC | 繁体字中国語 |
'ko' | Noto Sans KR | 韓国語 |
import { preloadPdfFont, registerPdfFont } from '@reogrid/pro'
await preloadPdfFont('zh-CN') // アプリ起動時に一度
grid.saveAsPdf({ locale: 'zh-CN' }) // 以降はいつでも
ロケールの選択は重要です。日本語フォントは簡体字中国語のビジネス頻出語の約 3 分の 1 しかカバーしないため、中国語のテキストを 'ja' でエクスポートすると残りが豆腐(□□□)になります。
独自のロケールも登録できます(ローダー・URL・手元のバイト列のいずれでも可)。
registerPdfFont('th', () => loadFont('/fonts/NotoSansThai-Subset.ttf'))
await preloadPdfFont('th')
grid.saveAsPdf({ locale: 'th' })
バイト列で登録した場合は即座にロード済みとなり、preload は不要です。ネットワークを完全に回避したい場合(アプリに同梱したフォントやパッケージから読み込んだフォント)はこの方法を使ってください。
関連ヘルパー(いずれも @reogrid/pro からエクスポート): isPdfFontRegistered、isPdfFontLoaded、getPdfFont、getRegisteredPdfFontTags、clearPdfFontCache。
フォントパッケージ(CDN 不要・オフライン対応)
組み込みロケールは公開 CDN からフルの上流フォントを取得します。Noto Sans SC だけで約 17 MB あり、その CDN は中国本土からは低速で、しばしば到達できません。本番環境では対応するサブセットパッケージをインストールして登録してください。バイト列は npm から来るため実行時のネットワークが一切不要になり、企業導入で一般的なオフラインのイントラネットでも動作します。
npm install @reogrid/font-sc # zh-CN — 他に font-tc / font-jp / font-kr
import { registerPdfFont, preloadPdfFont } from '@reogrid/pro'
import { loadNotoSansSC } from '@reogrid/font-sc'
registerPdfFont('zh-CN', loadNotoSansSC) // ロケールをパッケージに向ける
await preloadPdfFont('zh-CN') // アプリ起動時に一度
grid.saveAsPdf({ locale: 'zh-CN', filename: 'report.pdf' })
| パッケージ | ロケール | ローダー | 収録文字数 | 転送量 |
|---|---|---|---|---|
@reogrid/font-sc | 'zh-CN' | loadNotoSansSC | 7,709(GB 2312) | 約 2,593 KB |
@reogrid/font-tc | 'zh-TW' | loadNotoSansTC | 13,682(Big5) | 約 4,840 KB |
@reogrid/font-jp | 'ja' | loadNotoSansJP | 6,974(JIS X 0208) | 約 2,673 KB |
@reogrid/font-kr | 'ko' | loadNotoSansKR | 3,196(KS X 1001) | 約 494 KB |
各サブセットは、その言語の伝統的な国家標準を第 2 水準まで収録しています。人名・地名は第 2 水準にあり、顧客名が豆腐になる方がダウンロードが少し大きくなるより問題が大きいためです。バイト列は動的インポートの背後に置かれるため、バンドラーは専用チャンクに分離します。PDF を出力しないアプリはダウンロードしません。
自前のフォントバイト列を渡す
ReoGrid が知らない書体を使う場合は font を指定します。生の TrueType glyf バイト列(ArrayBuffer | Uint8Array)を渡し、font と locale の両方を指定した場合は font が優先されます。入手方法は 3 通りです。
import { loadDefaultJapaneseFont, loadFont, DEFAULT_JAPANESE_FONT_URL } from '@reogrid/pro'
// 1. 同梱の既定フォント — Noto Sans JP(約 9.6 MB、公開 CDN から取得・キャッシュ)
const a = await loadDefaultJapaneseFont()
// 2. 自前でホストするサブセット(本番推奨 — はるかに軽量)
const b = await loadFont('https://cdn.example.com/fonts/NotoSansJP-Subset.ttf')
// 3. すでに手元にあるバイト列(<input type="file"> や fetch など)
const c = new Uint8Array(await file.arrayBuffer())
どちらのヘルパーも、ダウンロードしたバイト列をメモリおよび Cache Storage にキャッシュするため、約 9.6 MB の既定フォントの取得はブラウザごとに最大 1 回です。本番環境では実際に必要なグリフだけをサブセット化してホストし、その URL を loadFont に渡してください(DEFAULT_JAPANESE_FONT_URL は同じソースからサブセットを作りたい場合に公開されています)。
fontはフォント名ではありません。font: 'Arial'は動作しません — このオプションはフォントファイルのバイト列を受け取ります。グリフのアウトライン自体を PDF に埋め込むことで、閲覧側の環境にフォントがインストールされていなくても同じ表示になるためです。上記の方法でファイルを読み込んでから渡してください。名前を渡した場合は次のエラーになります。exportWorksheetPdf: `font` must be TrueType (glyf) font bytes, not a font-family name (got "Arial"). Either name a locale — …ロケールを誤って
fontに渡した場合はそれを認識し、{ locale: 'zh-CN' }として渡すよう案内します。フォントは
glyfアウトラインを持つ TrueType である必要があります。OpenType/CFF(OTTO— 多くの.otfファイル)は未対応で、専用のエラーになります。
ExportPdfOptions
| オプション | 型 | 既定値 | 説明 |
|---|---|---|---|
locale | 'ja' | 'zh-CN' | 'zh-TW' | 'ko' または登録済みのタグ | — | 埋め込むフォント。レジストリ経由で解決されます。事前に preload が必要です。font を指定しない場合は必須。 |
font | ArrayBuffer | Uint8Array | — | 埋め込み可能な TrueType(glyf)フォントのバイト列。locale より優先されます。locale を指定しない場合は必須。 |
pageSize | 'A3'|'A4'|'A5'|'B4'|'B5'|'Letter'|'Legal'|'Tabloid'|'Executive' または { widthMm, heightMm } | 'A4' | 用紙サイズ。 |
orientation | 'portrait' | 'landscape' | 'portrait' | ページの向き。 |
marginMm | number | { top, right, bottom, left } | 12 | 余白(mm、数値は全辺共通)。 |
range | PdfExportRange | 使用範囲 | 出力するセル範囲。 |
showGridLines | boolean | ワークシートの設定 | グリッド線を描画。既定では worksheet.setShowGridLines()(画面表示)に従うため、明示的に指定しない限り PDF は画面と一致します。 |
scale | number | 1 | 一様な内容スケール(0.1〜4)。fitToWidth 時は無視。 |
fitToWidth | boolean | false | 全列が 1 ページ幅に収まるよう縮小。 |
usePageBreaks | boolean | false | 画面上の改ページプレビューとまったく同じように改ページ(後述)。 |
images | WorksheetImageInfo[] | シートの画像 | セルにアンカーする画像。 |
showImages | boolean | true | セルアンカー画像を描画。 |
title | string | — | ドキュメントタイトル(PDF メタデータ)。 |
saveAsPdf はさらに filename?: string を受け取ります。省略時は読み込み済みドキュメントのベース名(getDocumentName() / setDocumentName() 参照)、ファイル未読込のときは worksheet.pdf になります。
usePageBreaks による複数ページ出力
既定では exportPdf は使用範囲を pageSize / orientation / marginMm / scale オプションでページに割り付けます。usePageBreaks: true を指定すると、代わりにワークシート独自のページングモデルで改ページします — PDF は ページレイアウト の改ページプレビューとまったく同じ位置(手動改ページ・印刷範囲・フィットスケールを含む)で改ページされます。
// 用紙・向き・余白・スケール・ページ帯はすべて
// worksheet.getPrintSettings() と計算済みの改ページから取得されます。
grid.worksheet.setPrintSettings({ paperSize: 'A4', orientation: 'landscape' })
grid.worksheet.insertRowPageBreak(40) // 40 行目から新しいページ
await preloadPdfFont('ja')
grid.saveAsPdf({ locale: 'ja', usePageBreaks: true, filename: 'ledger.pdf' })
usePageBreaks が有効なとき、オプション側の pageSize / orientation / marginMm / scale / fitToWidth / range は無視されます — 代わりに ページレイアウト で設定してください。改ページ対象が何もないシートの場合はオプション側にフォールバックします。
React の例:PDF 出力ボタン
import { useEffect, useRef } from 'react'
import { Reogrid } from '@reogrid/pro/react'
import { preloadPdfFont } from '@reogrid/pro'
import type { ReogridInstance } from '@reogrid/pro/react'
function App() {
const gridRef = useRef<ReogridInstance>(null)
// フォントの取得はマウント時に一度だけ。クリックハンドラ内で await すると、
// ダウンロードリンクに必要なユーザージェスチャーが失われます。
useEffect(() => { void preloadPdfFont('ja') }, [])
function handleExport() {
gridRef.current?.saveAsPdf({ locale: 'ja', usePageBreaks: true, filename: 'report.pdf' })
}
return (
<>
<button onClick={handleExport}>PDF 出力</button>
<Reogrid ref={gridRef} style={{ flex: 1 }} />
</>
)
}
Vue の例:PDF 出力ボタン
Vue コンポーネントは、テンプレート ref の instance プロパティ(gridRef.value?.instance)としてグリッドを公開します。出力の呼び出し自体は他のフレームワークと同じです。
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { Reogrid, type ReogridInstance } from '@reogrid/pro/vue'
import { preloadPdfFont } from '@reogrid/pro'
const gridRef = ref<{ instance: ReogridInstance | null } | null>(null)
// フォントの取得はマウント時に一度だけ。クリックハンドラ内で await すると、
// ダウンロードリンクに必要なユーザージェスチャーが失われます。
onMounted(() => { void preloadPdfFont('ja') })
function exportPdf() {
gridRef.value?.instance?.saveAsPdf({ locale: 'ja', usePageBreaks: true, filename: 'report.pdf' })
}
</script>
<template>
<button @click="exportPdf">PDF 出力</button>
<Reogrid ref="gridRef" style="width: 100%; height: 400px" />
</template>