画像
ワークシートにはフローティング画像を置けます — 請求書のロゴ、帳票の印影、カタログの商品写真など。v1.6.0 から完全に編集可能になりました。コードからでもファイル選択からでも挿入でき、ドラッグで移動、グリップのドラッグでリサイズでき、xlsx に保存しても消えません。
v1.6.0 より前、画像は読み取り専用でした。xlsx から読み込んだ画像は表示はされるものの、ブックを保存すると黙って捨てられていました。この問題は解消し、エクスポートは実体のある
xl/media・xl/drawingsパートを書き出します。
エディション: 画像は Pro の機能です。Lite では表示と編集が無効ですが、読み出し(getImage / getImages / getImageRect)とファイル取り込みは利用できます。そのため Lite で開いた文書を書き戻しても、画像は保たれます。
画像を挿入する
addImage(source, anchor, options?) は同期的に動作し、新しい画像の id を返します。
const ws = grid.worksheet
// バイト列から — Uint8Array・ArrayBuffer・data: URL のいずれか
const id = ws.addImage(bytes, { row: 1, column: 1, width: 240, height: 120 })
ファイル選択からは addImageFromFile() を使います。File / Blob を受け取り、既定で画像本来のサイズを使います。
const input = document.querySelector('input[type=file]')
input.addEventListener('change', async () => {
const file = input.files?.[0]
if (file) await ws.addImageFromFile(file, { row: 1, column: 1 })
})
アンカー
画像の位置はアンカーで表します。Excel と同じ 3 種類があり、以下の短縮形は自動的に正規化されます。
| 書き方 | アンカー種別 | 動作 |
|---|---|---|
{ row, column, width, height } | oneCell | 左上をセルに固定。セルと一緒に動き、サイズは固定 |
{ from, to } | twoCell | 2 つのセル角にまたがる。セルと一緒に動き、サイズも変わる |
{ x, y, width, height } | absolute | シートに固定。行・列の影響を受けない |
// oneCell — セルがどこへ動いてもサイズを保つロゴ
ws.addImage(bytes, { row: 0, column: 0, width: 180, height: 60 })
// twoCell — B3:D10 を埋め、それらの列幅に追従する写真
ws.addImage(bytes, {
from: { row: 2, column: 1 },
to: { row: 10, column: 4 },
})
// absolute — シート上の固定位置に置く透かし
ws.addImage(bytes, { x: 40, y: 20, width: 240, height: 120 })
セルアンカーの位置には、セル左上からのピクセル単位のオフセット offsetX / offsetY も指定できます。
アンカーは行・列の挿入と削除に追従します。Excel と同じく、ロゴの下の行を削除してもロゴは消えず、twoCell の画像はまたがる行が縮めば一緒に縮みます。
オプション
ws.addImage(bytes, anchor, {
name: '会社ロゴ', // Excel のシェイプ名
mimeType: 'image/png', // バイト列から推測せず、型を明示する
})
マウスで編集する
Pro のシートでは、標準で以下の操作ができます。
| 操作 | 結果 |
|---|---|
| 画像をクリック | 選択し、8 つのリサイズグリップを表示 |
| 本体をドラッグ | 移動 |
| グリップをドラッグ | リサイズ(Shift で縦横比を維持) |
| Delete | 選択中の画像を削除 |
ドラッグ 1 回が Ctrl+Z 1 手に対応します。
画像を表示したまま、API も使えるまま、操作だけを止めるには次のようにします。
ws.setImageEditEnabled(false)
シート保護をかけた場合も同じ状態になります。
機能ごと無効にする(描画されず、クリックもできず、PDF エクスポートにも出ない)場合は次のようにします。
ws.setImagesEnabled(false)
この呼び出しはモデルに触れないため、画像は xlsx・JSON を往復し続けます。Lite が内部で行っているのはこれです。
コードから編集する
// 移動 — セルアンカー、またはコンテンツ座標のピクセル位置へ
ws.moveImage(id, { row: 5, column: 2 })
ws.moveImage(id, { x: 300, y: 180 })
// リサイズ(ピクセル単位)
ws.resizeImage(id, { width: 320, height: 160 })
// アンカーごと差し替える(oneCell → twoCell など)
ws.setImageAnchor(id, { from: { row: 2, column: 1 }, to: { row: 10, column: 4 } })
// 削除
ws.removeImage(id)
いずれも適用できたときに true、id が見つからないときに false を返します。
画像を読み出す
const images = ws.getImages()
images.forEach((image) => {
console.log(image.id) // 一意な id
console.log(image.name) // Excel のシェイプ名(ファイルにあれば)
console.log(image.mimeType) // 'image/png'、'image/jpeg' など
console.log(image.data) // Uint8Array — 生のバイト列
console.log(image.anchor) // { type: 'oneCell' | 'twoCell' | 'absolute', … }
})
// id を指定して 1 枚取得
const image = ws.getImage(id)
// 現在の位置(シートのコンテンツ座標。ヘッダー分を含み、スクロールは未適用)
const rect = ws.getImageRect(id) // { x, y, width, height } | null
WorksheetImageInfo
| プロパティ | 型 | 説明 |
|---|---|---|
id | string | 一意な識別子 |
name | string? | 表示名(Excel のシェイプ名) |
mimeType | string | バイト列の MIME タイプ |
data | Uint8Array | 生の画像バイト列 |
anchor | WorksheetImagePlacement | 正規化された配置情報 — oneCell / twoCell / absolute |
グリッドの外に表示する
サイドバーやダウンロードリンクに表示するには、createImageUrl() で blob URL を作り、不要になったら破棄します。
const url = ws.createImageUrl(id)
const img = document.createElement('img')
img.src = url
document.body.appendChild(img)
// あとで — blob URL は破棄するまで残ります
ws.revokeImageUrl(id)
グリッド自身の画像レイヤーは内部で URL を管理しているので、自分で作った URL だけを管理すれば十分です。
変更を検知する
onImagesChange() は画像リストが変わるたびに発火します。購読した直後にも現在の画像で 1 度呼ばれます。
const unsubscribe = ws.onImagesChange((images) => {
console.log(`画像 ${images.length} 枚`)
})
unsubscribe()
ファイル入出力
| 形式 | 画像の扱い |
|---|---|
| xlsx | 実体のある xl/media + xl/drawings パートで完全に往復。同一の画像は 1 つにまとめて格納されます。 |
| ReoGrid JSON | sheet.images に base64 で往復。toJson({ includeImages: false }) でバイト列を省略できます。 |
| PDF エクスポート | 描画されます。印刷倍率と改ページに従います。 |
| ブラウザ印刷 | v1.6.0 から描画されます。toPagedHtmlDocument({ showImages }) でシートの設定を上書きできます。 |
画像はバイト単位でそのまま往復するため、画像を含む JSON は写真と同じ大きさになります。JSON を通信フォーマットとして使っていて、バイト列がそれを圧倒する場合は次のように省略してください。
const doc = grid.toJson({ includeImages: false })
ヘッドレスでの取り込み
ブラウザ用の読み込みメソッド(grid.loadXlsx や、ワークシートの loadSheetFromBuffer)は DOM を必要とします。顧客の .xlsx をブラウザ外でテンプレートに変換するビルドツールでは、エクスポートされた XlsxImporter を使い、画像を明示的に渡してください。
import { XlsxImporter, convertImageInfo } from '@reogrid/pro'
const importer = new XlsxImporter(worksheet)
const result = importer.load(bytes)
for (const image of result.images) {
worksheet.loadImageFromImport(convertImageInfo(image))
}
React の例
import { useState } from 'react'
import { Reogrid } from '@reogrid/pro/react'
import type { ReogridInstance } from '@reogrid/pro/react'
import type { WorksheetImageInfo } from '@reogrid/pro'
export default function App() {
const [images, setImages] = useState<WorksheetImageInfo[]>([])
const [ws, setWs] = useState<ReogridInstance['worksheet'] | null>(null)
function onReady({ worksheet }: ReogridInstance) {
setWs(worksheet)
worksheet.onImagesChange(setImages)
}
async function onPick(e: React.ChangeEvent<HTMLInputElement>) {
const file = e.target.files?.[0]
if (file && ws) await ws.addImageFromFile(file, { row: 1, column: 1 })
}
return (
<>
<input type="file" accept="image/*" onChange={onPick} />
<Reogrid onReady={onReady} style={{ width: '100%', height: '400px' }} />
<p>画像 {images.length} 枚</p>
</>
)
}
補足
- 対応形式。 PNG・JPEG・GIF・SVG・BMP・TIFF・WebP(ブラウザの
<img>要素がデコードできる範囲に依存します)。 - メモリ。
createImageUrl()が作る blob URL はrevokeImageUrl()を呼ぶまで残ります。 - Lite。 画像は表示も編集もされませんが、取り込み・
getImages()・書き出しでは保持されるため、Lite のビューアーが Pro 文書の画像を壊すことはありません。
関連ページ
- 画像のデモ — 請求書のロゴと承認印を、ドラッグで移動・グリップでリサイズ。
- XLSX インポート・エクスポート —
xl/mediaの往復が行われる場所。 - ReoGrid JSON —
includeImages。 - PDF エクスポート — 出力文書の画像。
- HTML で印刷 —
showImages。 - シート保護 — シート保護は画像の操作も止めます。
弊社サイトの品質向上のため、コメントをご記入ください。