Excel画像抽出

Excelの各行に画像が挿入されていて、行データと関連付けて画像を取得

いろいろ調べた結果、拡張子「xlsx」を「zip」に変更して解凍すれば構成ファイルが見れますが、画像ファイルと行データとの関連性を見つけられませんでした。

 

画像と行を紐付けするために、VBAを作成

Excelに列を追加して、ユニークな値(重複しない値)を作成します。

VBAを利用して作成したユニークな値を、画像プロパティの「代替テキスト」の「タイトル」に設定していきます。

 

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」のファイルで、下画像の赤枠ファイルになります。

excel 画像抽出

このファイルの中には、画像情報が保存されています。

xdr:twoCellAnchorごとに、1画像の設定項目があり、VBAで設定したタイトルもxdr:cNvPrのtitle要素として保存されています。

このtitle要素の値と、a:blipのr:embed要素にあるIDを取得しておきます。

 

 

もう一つが「_rels」フォルダのファイルになります。

このファイルのRelationshipのId要素が、先に取得したIDと紐付きます。

実際の画像ファイルは、Target要素に設定されていますので、エクセルの行と画像を紐付けて取得できる情報を得ることができます。

エクセル 画像抽出

 

文字で書くと、かなり面倒なことを行わないと画像までたどり着けないので簡易的なツールを作成しました。

開発環境はC#2015です。

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();
            }
        }
    }
}

 

 

By にど寝

もともと名古屋でシステムエンジニアをしてましたが、現在は地元に帰省してネットショップの社内システムエンジニアをしてます。  

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です