画像をシートに読み込むVBA

Visual Basic for Applications (VBA)

画像ファイルをシートに読み込んで表示します。
画像ファイルをシートに表示する

シートに表示するパターンとしては、画像ファイルの原寸サイズを表示する場合と、画像の縦横比は維持したままサイズを変更する場合、画像の縦横比は無視して変更する場合の3通りを説明します。なお以降でイメージと表現しているのはExcelシート上の画像(Shapeオブジェクト)のこととします。

基本

画像ファイルをシート上に表示するには、ShapesオブジェクトのAddPictureメソッドを利用します。

AddPicture(Filename, LinkToFile SaveWithDocument, Top, Left, Height, Width)
引数名 内容
1 Filename String 読み込む画像ファイルのフルパス
2 LinkToFile MsoTriState列挙型 エクセルブック起動時に画像ファイルのリンク情報を元に読み込む(msoFalse)か、エクセルブックにイメージを保存しておくか(msoTrue)。
3 SaveWithDocument MsoTriState列挙型 エクセルブック保存時に一緒にイメージを保存する(msoTrue)か、画像ファイルのリンク情報のみ保存するか(msoFalse)。
4 Top Single イメージの上端部のシート上での位置(ポイント)。
5 Left Single イメージの左端部のシート上での位置(ポイント)。
6 Height Single イメージの高さ(ポイント)。原寸表示の場合は-1。
7 Width Single イメージの幅(ポイント)。原寸表示の場合は-1。

原寸で表示

ShapeオブジェクトのAddPictureメソッドの第6引数(幅)と第7引数(高さ)にそれぞれ-1をセットすることで画像ファイルの原寸サイズのイメージになります。
原寸で表示

下記コードでは、読み込んだ画像を原寸サイズのままshp変数に保存しています。

Dim imgRng As Range
Set imgRng = WorkSheets(1).Range("C2")

Dim shp As Shape
' 画像ファイルの原寸で表示する(第6,第7引数を-1にする)
Set shp = WorkSheets(1).Shapes.AddPicture([ファイル名], msoFalse, msoTrue, imgRng.Left, imgRng.Top, -1, -1)
    

縦横比を維持して幅または高さを変更

ShapeオブジェクトのLockAspectRatioプロパティにmsoTrueを指定することで縦横比を固定とすることができます。デフォルトはmsoFalseで縦横比は固定されていません。または縦横比を固定すると、「高さ」または「幅」のどちらかを変更することで、もう一方が自動で変更されます。
縦横比を維持したまま高さを半分に(自動で幅も半分になる)

下記コードでは、読み込んだ画像をshp変数に保存し、縦横比を固定にして画像幅を50ポイントに変更しています(縦横比を固定にしているので自動で高さも変更されます)。

Dim imgRng As Range
Set imgRng = WorkSheets(1).Range("C2")

Dim shp As Shape
' 画像ファイルを原寸で読み込んで、縦横比を固定にした後にイメージの幅を50にする(高さは縦横比に応じて自動で変わる)
Set shp = WorkSheets(1).Shapes.AddPicture([ファイル名], msoFalse, msoTrue, imgRng.Left, imgRng.Top, -1, -1)
With shp
    .LockAspectRatio = msoTrue  ' 縦横比の固定
    .Width = 50     ' 画像の幅を50ポイントに
End With

縦横比は無視して幅・高さ変更

ShapeオブジェクトのAddPictureメソッドの第6引数(幅)と第7引数(高さ)を指定することで、そのサイズのShapeオブジェクトにすることができます。
縦横比を維持しないで高さのみ半分にする

下記サンプルコードでは幅を128ポイント、高さ64ポイントで表示しています。

Dim imgRng As Range
Set imgRng = WorkSheets(1).Range("C2")

Dim shp As Shape
' 画像ファイルを 幅128ポイント 高さ64ポイントで読み込む場合
Set shp = WorkSheets(1).Shapes.AddPicture([ファイル名], msoFalse, msoTrue, imgRng.Left, imgRng.Top, 128, 64)

読み込みパフォーマンス

画像ファイルが少なかったり、シート上に表示するイメージが少なかっったりする場合はあまり気にならないのですが、1000件を超えるイメージをシートに表示するなど件数が増えると表示するのにも時間がかかります。

ここでは、画像を読み込んでシートに表示するのにどれぐらい時間がかかるかを計測して比較してみました。計測環境は、Excel2010で5Kb程度の画像ファイルを1500件読み込ん計測しました。なお画像ファイルは50ファイルを使い回すことにしました。

1つめは、全てのイメージを画像ファイルから読み込む方法です。同じイメージがあったとしても画像ファイルから読み込む方法です(表では「全て読み込む」)。
画像ファイルから全て読み込む

2つめは、1度読み込んだ画像をメモリーに保存しておき、2回目以降その画像をコピーして利用する方法です(表では「再利用」)。
初回は画像ファイルから、2回目以降は既存イメージをコピー

全て読み込む 再利用
1 20.42秒 6.10秒
2 20.23秒 6.08秒
3 18.80秒 6.10秒

今回の環境では、画像をコピーした場合の方(表の「再利用」)が、都度画像ファイルにアクセスして読み込む(表の「全て読み込む」)より1/3の時間で行うことができています。やはりファイルアクセス部分がネックとなって時間がかかっているようです。

イメージの重複が多ければ、イメージをコピーして表示する方が格段に早くなりますが、イメージの重複が少ない場合はそれほど恩恵を得られません。重複イメージの量に応じて再利用するか全て読み込むかを決めていくことになります。

イメージの再利用は、ShapeオブジェクトのDuplicateメソッドでコピーすることができます。いかに簡単なサンプルコードを載せておきます。実際にはDictionaryオブジェクトを使ってShapeオブジェクトを管理して利用する方法になると思います。

Dim imgRng As Range
Set imgRng = WorkSheets(1).Range("C2")

dim firstShape As Shape
' 画像ファイルから読み込んで、firstShape変数にイメージを保存
set firstShape = WorkSheets(1).Shapes.AddPicture([ファイル名], msoFalse, msoTrue, imgRng.Left, imgRng.Top, 40, 50)

dim shp as Shape
' shp変数にコピーされたShapeオブジェクトを保存する
set shp = firstShape.Duplicate()