ReoGrid ReoGrid Web

画像

ワークシートにはフローティング画像を置けます — 請求書のロゴ、帳票の印影、カタログの商品写真など。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 }twoCell2 つのセル角にまたがる。セルと一緒に動き、サイズも変わる
{ 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

プロパティ型説明
idstring一意な識別子
namestring?表示名(Excel のシェイプ名)
mimeTypestringバイト列の MIME タイプ
dataUint8Array生の画像バイト列
anchorWorksheetImagePlacement正規化された配置情報 — 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 JSONsheet.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 文書の画像を壊すことはありません。

関連ページ

このページは役に立ちましたか?
ニュースレター

開発の最新情報をお届けします

新しいリリース・機能追加・お知らせをいち早く受け取るには、
メーリングリストにご登録ください。