Excelの各行に画像が挿入されていて、行データと関連付けて画像を取得
いろいろ調べた結果、拡張子「xlsx」を「zip」に変更して解凍すれば構成ファイルが見れますが、画像ファイルと行データとの関連性を見つけられませんでした。
画像と行を紐付けするために、VBAを作成
Excelに列を追加して、ユニークな値(重複しない値)を作成します。
VBAを利用して作成したユニークな値を、画像プロパティの「代替テキスト」の「タイトル」に設定していきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
Sub ボタン99_Click() Dim iRow As Integer For iRow = 2 To 2000 '必須項目の値が無い場合は終了する。 If Len(Cells(iRow, 10).Value) = 0 Then Exit For End If '画像挿入セルを選択 Cells(iRow, 17).Select For Each shp In ActiveSheet.Shapes ' 図形の配置されているセル範囲をオブジェクト変数にセット Set Rng = Range(shp.TopLeftCell, shp.BottomRightCell) ' 図形の配置されているセル範囲と選択されているセル範囲が重なっているときに図形にタイトルを設定 If Not (Intersect(Rng, Selection) Is Nothing) Then '画像タイトルに、行ユニーク値を設定 shp.Title = Cells(iRow, 3).Value Exit For End If Next Next End Sub |
上記のコードは汎用的では無いです。
もし利用する場合は、参考程度でお願いします。
Excelの拡張子を「zip」に変更して解凍
解凍したファイルの中で、2つのファイルを利用します。
一つが「drawing数字.xml」のファイルで、下画像の赤枠ファイルになります。
このファイルの中には、画像情報が保存されています。
xdr:twoCellAnchorごとに、1画像の設定項目があり、VBAで設定したタイトルもxdr:cNvPrのtitle要素として保存されています。
このtitle要素の値と、a:blipのr:embed要素にあるIDを取得しておきます。
もう一つが「_rels」フォルダのファイルになります。
このファイルのRelationshipのId要素が、先に取得したIDと紐付きます。
実際の画像ファイルは、Target要素に設定されていますので、エクセルの行と画像を紐付けて取得できる情報を得ることができます。
文字で書くと、かなり面倒なことを行わないと画像までたどり着けないので簡易的なツールを作成しました。
開発環境はC#2015です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Xml; namespace エクセル画像抽出 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_DragDrop(object sender, DragEventArgs e) { //MessageBox.Show("", "Form1_DragDrop"); string[] files = (string[])e.Data.GetData(DataFormats.FileDrop, false); for (int i = 0; i < files.Length; i++) { set_DrawingDate(files[i]); //textBox1.Text += fileName + "\r\n"; } } private void Form1_DragEnter(object sender, DragEventArgs e) { if (e.Data.GetDataPresent(DataFormats.FileDrop)) { e.Effect = DragDropEffects.All; } else { e.Effect = DragDropEffects.None; } } private void set_DrawingDate(string strFileName) { //ファイル名に指定の文字が存在しない場合 if(strFileName.IndexOf("drawing") == 0 || strFileName.IndexOf(".xml") == 0) { return; } XmlTextReader reader = new XmlTextReader(strFileName); int iRowPos = 0; bool bTitle = false; bool bID = false; string strTitle=""; string strID=""; string strTraget = ""; int iRowIdx = 0; if (strFileName.IndexOf(".rels") >= 0 && dataGridView1.RowCount > 0) { while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: if (reader.Name.IndexOf("Relationship") >= 0) { strTraget = reader.GetAttribute("Target"); strID = reader.GetAttribute("Id"); DataGridViewRow[] rows2 = dataGridView1.Rows.Cast<DataGridViewRow>().Where(x => (string)x.Cells[1].Value == strID).ToArray(); for(int i = 0;i < rows2.Count(); i++) { dataGridView1.Rows[rows2[i].Index].Cells[2].Value = strTraget; } } break; } } } else { //グリッドのクリア dataGridView1.Rows.Clear(); while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: if (reader.Name.IndexOf("xdr:twoCellAnchor") >= 0) { iRowPos++; bTitle = true; bID = true; iRowIdx = dataGridView1.Rows.Add(); } else if (reader.Name.IndexOf("xdr:cNvPr") >= 0) { if (bTitle) { strTitle = reader.GetAttribute("title"); dataGridView1.Rows[iRowPos - 1].Cells[0].Value = strTitle; bTitle = false; } } else if (reader.Name.IndexOf("a:blip") >= 0) { if (bID) { strID = reader.GetAttribute("r:embed"); dataGridView1.Rows[iRowPos - 1].Cells[1].Value = strID; bID = false; } } break; } } } Console.ReadLine(); } private void button1_Click(object sender, EventArgs e) { //グリッドのクリア dataGridView1.Rows.Clear(); } private void button2_Click(object sender, EventArgs e) { if (dataGridView1.RowCount > 0) { var dia = new SaveFileDialog(); if (dia.ShowDialog() == DialogResult.OK) { //retFileName = dia.FileName; //グリッド情報を出力する。 var csv = new CsvWriter(dia.FileName); for (int i = 0; i < dataGridView1.RowCount; i++) { var data = new List<string>(); data.Add(get_Value(dataGridView1.Rows[i].Cells[0].Value)); data.Add(get_Value(dataGridView1.Rows[i].Cells[1].Value)); data.Add(get_Value(dataGridView1.Rows[i].Cells[2].Value)); csv.WriteRow(data); } csv.Close(); csv.Dispose(); } } } private string get_Value(object str) { if (str == null) { return ""; } else { return str.ToString(); } } } } |