表題、そのままの意味です。c#でエクセルファイルを操作するためのOpenXML拡張、「ClosedXML」。こちらを今回導入していました。
なんせ、ASP.netなどで使うとなるとサーバ側実装なのですがこれならExcel(Office)がいらないのです。COM無し。XMLベースのオープンソース仕様らしいので。ライセンスもOK。
使い勝手は大変よろしいのですが…画像を扱えない、ということがわかりまして。
今回の要件では画像を張り付けるのが必須なので、
こりゃあえらいこっちゃ、違うライブラリを模索か?という選択もありましたが…
まずは状況を確認
ClosedXMLを用意します。
Nugetでインストールしてはダメです。
GitHubのフォークして開発されているかたから拝借します。
参考先を参照してClosedXMLのDLLを取得します。
参考:code-labさん
OpenXMLではとにかく画像を扱うのが面倒なので、いくら簡略化されたといえClosedXMLでの操作もなかなか手間がかかりました。
とりあえずエクセルファイルに張り付けてみます。
/***---- 一部を抜粋 ---***/
// シートに張るための画像オブジェクト
XLPicture img = new XLPicture()
{
NoChangeAspect = true,
NoResize = true,
NoMove = true,
ImageStream = System.IO.File.OpenRead(rec.input_value),
};
// 対象セルの番地(アドレス)しか指定できませんでした
XLMarker mark = new XLMarker
{
ColumnId = cell.Address.ColumnNumber,
RowId = cell.Address.RowNumber
};
// マーカーを追加
img.AddMarker(mark);
// シートに追加
worksheet.AddPicture(img);
仕様では、名前付きのセルに対して画像を張り付ける、ということなので結果はこうなります。
なんやねん…そうですな。セルにぴったり収まっています。
これはいろいろマージン等の指定がありますが、セルの幅高さを調整して作成するしかありません。それで仕様は満たせます。…一応。
できれば、レイアウトの自由さのために結合したセルに対して張り付けることができたらよいのですが、これができない。どうしても単独セルのポジションと大きさにしかはりつけない。
うーん、せめて大きさを自由に設定したい…
いろいろ試した結果こうすることができました。
土星より地球のほうが大きいのだ!…ではなく、
範囲の指定をしてやればいいのですが、GitHubの投稿者のコメント読んだりしてわかりました。
↓こうなります。
// 範囲オブジェクトを指定
var range = worksheet.Range(name)
XLPicture img = new XLPicture()
{
NoChangeAspect = true,
NoResize = true,
NoMove = true,
ImageStream = System.IO.File.OpenRead(rec.input_value),
};
// 表示位置、始点
XLMarker mark = new XLMarker
{
ColumnId = range.RangeAddress.FirstAddress.ColumnNumber,
RowId = range.RangeAddress.FirstAddress.RowNumber
};
// マーカー2つ目(範囲指定で一つずらさないといけない)
XLMarker mark2 = new XLMarker()
{
ColumnId = range.RangeAddress.LastAddress.ColumnNumber + 1,
RowId = range.RangeAddress.LastAddress.RowNumber + 1
};
// マーカーでセル範囲を指定する
img.AddMarker(mark);
img.AddMarker(mark2);
worksheet.AddPicture(img);
Rangeの設定もいろいろコツがあるのですが、それは運用マニュアルとかである程度ルール化したうえで、システム側ではこのあたりが限界です。任意の場所に張り付けるのではないのである程度決まったフォーマットに従わないといけない制約に縛られます。(言い訳)
まとめ
エクセル操作についてはClosedXMLで何ら問題ないです。秀逸なライブラリです。
しかし細かく画像処理をしようとおもえばちょっと難ありですね。
ASP.netでやる分には十分です。今後も機会があれば導入しようと思います。