したいこと
C#のBitmapオブジェクトを直接使用して、Excelに画像を追加したい。
C#のImage オブジェクトを直接使用して、Excelに画像を追加したい。
VSTOでExcelに画像を追加したい。
関連
セルの中に画像を挿入する場合はこちらを参照
調査結果
調査結果1
Bitmapオブジェクトから VSTOでMicrosoft.Office.Interop.Excelを使用して直接画像を追加することはできません。
Image オブジェクトから VSTOでMicrosoft.Office.Interop.Excelを使用して直接画像を追加することはできません。
調査結果2
Bitmapオブジェクト, Image オブジェクトを直接使用してどうしても行いたい場合は、EPPlus (オープンソースライブラリ)の関数を使用する。
Drawings.Addpicture()関数[EPPlusの場合]
話は別になりますが,同じようライブラリで ClosedXML, NPOIなども使用できます。
EPPlus : GNU Lesser General Public License v3.0
ClosedXML:MIT License,
NPOI: Apache License 2.0
調査結果3
”Excelファイルを C# と VB.NET で読み込む “正しい” 方法”に書かれているように、Microsoft.Office.Interop.ExcelをExcel外部から呼ぶ場合は注意が必要です。
MSDN公式(日本語)にも同様のことが書かれています。
一方、VSTO等でアドインを作成して使用する場合は、こちらに書かれている機構なので、安心して使えそうです。
調査結果4
Bitmapオブジェクト・Imageオブジェクトを一度ファイルとして保存して、Shapes.AddPicture()関数を使用して、Excelに画像を追加できます。(Word, Excel, PowerPointも同様)
調査結果 – 詳細
経験から
以前にShapes.AddPictureで画像をPowerPointに張り付けるソフトを作成したことがあったのですが、C# で自分でメモリ上に動的に画像を作成した場合、
Bitmap image = new Bitmap(200,100);
のようにBitmap上に画像を作成します。
VSTOでも同じようにこの作成した画像を、Microsoft.Office.Interop.Excel(以下 Interop.Excel) のAddPicture関数にて
Bitmap image = new Bitmap(200,100); ...... 画像作成等..... Shapes.AddPicture("作成した画像", image);
のようにできるかと想像していたのですが、実装する段階になって調べてみましたが、そのような引数の関数は無いことがわかりました。
再調査
VSTO で使用する Interop.Excel (Word, Excel, PowerPointも同様)では、保存した画像を読み込むことのみが可能です。
Shapes.AddPicture、Shapes.AddPicture2を使用して、Excelに画像を追加できるので、一度 Bitmap保存してから追加するしかありません。
調査途中にて
調査をしているとAddPicture(“作成した画像”, image);のように画像を追加できるという、英文の記事があったのですが、これがどうやら、Interop.Excel ではない様子。初めは何をしているのかまったくわかりませんでしたが、EPPlus、ClosedXMLなどの
ライブラリを使っているということで頭の整理ができました。
ただ、一瞬?となったのは、ここに書かれているように、Microsoft.Office.Interop.ExcelをExcel外部から呼ぶ場合は注意が必要との記事です。
ただし、標準的に開発を推奨しているVSTOではそんなことはないだろうと思ったら、やはりそうでした。
その他
一時ファイルはProgramDataの自分で作成したフォルダか、一時フォルダに保存するのが妥当かと思われます。(万一の事態に備えて自分で作成したProgramDataのほうが、ファイルを削除しする際の管理には楽だろうとは思います。)
サンプル
C#のコード
適当にVSTOのExcelサンプルを作成してそこに以下のコードを書いてください。私の場合はリボンにボタンを追加してそこにボタンのクリック関数内に以下のコードを追加しました。
using System.Drawing;
を別途追加しておいてください。
string fileName = @"c:\tmp\img.png"; //200x100サイズのImageオブジェクトを作成する using (Bitmap img = new Bitmap(200, 100)) { //ImageオブジェクトのGraphicsオブジェクトを作成する using (Graphics g = Graphics.FromImage(img)) { //全体を黒で塗りつぶす g.FillRectangle(Brushes.Black, g.VisibleClipBounds); SolidBrush yellowBrush = new SolidBrush(Color.Yellow); //黄色い扇形を描画する g.FillPie(yellowBrush, 60, 10, 80, 80, 30, 300); } try { // Bitmap Imageを保存する img.Save(fileName); } catch(Exception ex) { return; } } //画像を保存できたかの確認 if (!System.IO.File.Exists(fileName)) return; // 現在のワークシート取得 Microsoft.Office.Interop.Excel.Worksheet activeSheet = Globals.ThisAddIn.Application.ActiveSheet; // セルA2選択 Microsoft.Office.Interop.Excel.Range range = activeSheet.Range["A2"]; // 画像貼付 float Left = (float)range.Left; float Top = (float)range.Top; float Width = 0.0F; float Height = 0.0F; Microsoft.Office.Interop.Excel.Shape shape = activeSheet.Shapes.AddPicture(fileName, Microsoft.Office.Core.MsoTriState.msoCTrue, Microsoft.Office.Core.MsoTriState.msoCTrue, Left, Top, Width, Height); // 倍率を100%にする shape.ScaleHeight(1.0F, Microsoft.Office.Core.MsoTriState.msoCTrue); shape.ScaleWidth(1.0F, Microsoft.Office.Core.MsoTriState.msoCTrue);
サンプルコードの実行結果
結論
Bitmapオブジェクト, Image オブジェクトを直接使用して、エクセルに画像を張り付けられないのは少し残念ですが、EPPlus、ClosedXML、NPOIなどもしようできること。また、Microsoft.Office.Interop.ExcelをOffice以外の外部のソフト使用する場合の注意点などもわかったので、収穫は大きかったように思います。