最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C# Npoi如何讀取單元格圖片并獲取所在單元格位置

 更新時間:2025年04月29日 09:43:25   作者:umarururururu  
這篇文章主要介紹了C# Npoi如何讀取單元格圖片并獲取所在單元格位置,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

C# Npoi讀取單元格圖片并獲取所在單元格位置

C#在excel中讀取圖片 獲取圖片的單元格位置信息(僅限于xlsx)

主要的代碼邏輯

  1. 將excel使用zip直接打開
  2. 壓縮包內(nèi)圖片信息主要存放在兩個文件夾中(xl/media,xl/drawings)前者是圖片本身,后者是圖片的主要信息
  3. 在drawings文件夾下會存在若干以drawing開頭的.xml文件,一個sheet頁對應一個drawing.xml后綴按照數(shù)字序號遞增(例如:第一頁為drawing1.xml,第二頁為drawing2.xml以此類推)
  4. 打開drawing.xml后,讀取文檔節(jié)點,節(jié)點含義對照表在末尾
  5. 在pic標簽中獲取到圖片的rid后通過該id在同級目錄下的_rels文件夾下找到對應的drawing.xml.rels中讀取圖片的存放地址(例如drawing1.xml對應drawing1.xml.rels)
twoCellAnchor圖片信息的節(jié)點 節(jié)點下包含了圖片的起始單元格位置 圖片的id即[r:embed]的內(nèi)容 存在多少個[twoCellAnchor]即存在多少個圖片
twoCellAnchor/from圖片左上角開始位置單元格信息
twoCellAnchor/to圖片右下角結束位置單元格信息 (當前需求需要盡量保證一張圖片存在一個單元格中,不允許跨單元格 因為不會對其做其他的處理)
twoCellAnchor/pic圖片的文件信息 主要讀取 [blipFill->blip->r:embed]此信息為圖片的id信息可以讀取到文件在media文件夾中存放的位置
twoCellAnchor/xfrm待確定該信息,主要猜想為圖片的大小?
twoCellAnchor/prstGeom圖片的插入方式

以下是封裝完成的代碼

 public class ExcelImgHelper
 {
     #region 常量

     /// <summary>
     /// 文件id與文件路徑文件夾路徑
     /// </summary>
     private const string DrawingRels = "xl/drawings/_rels/drawing_id_.xml.rels";

     /// <summary>
     /// 圖片信息文件
     /// </summary>
     private const string Drawing = "xl/drawings/drawing_id_.xml";

     #region 圖片信息主要標簽

     private const string twoCellAnchor = "twoCellAnchor";
     private const string embed = "embed";
     private const string link = "link";
     private const string prst = "prst";

     #endregion 圖片信息主要標簽

     #endregion 常量

     #region 路徑信息

     /// <summary>
     /// excel文件地址
     /// </summary>
     private string ExcelPath { get; }

     /// <summary>
     /// 解壓的文件夾
     /// </summary>
     private string ExcelZipPath { get; }

     /// <summary>
     /// 壓縮包 *注意 與上方需要區(qū)分開當前路勁是壓縮文件包.zip
     /// </summary>
     private string ExcelZipFilePath { get; }

     #endregion 路徑信息

     private List<ExcelImgInfo> ExcelImgInfos = new List<ExcelImgInfo>();

     public ExcelImgHelper(string filePath)
     {
         if (string.IsNullOrEmpty(filePath))
         {
             throw new ArgumentNullException(nameof(filePath));
         }

         //解壓后文件夾存放的位置 與源文件同目錄
         var dir = Path.GetDirectoryName(filePath);
         //獲取文件名
         var fileName = Path.GetFileNameWithoutExtension(filePath);
         //壓縮包路徑
         var zipFilePath = dir + "\\" + fileName + ".zip";

         //復制為壓縮包
         File.Copy(filePath, zipFilePath);

         //解壓文件
         if (UnZipFile(filePath, out string UnZipFilePath))
         {
             ExcelPath = filePath;
             ExcelZipPath = UnZipFilePath;
             ExcelZipFilePath = zipFilePath;

             ExcelImgInfos = Analysis();
         }
         else
         {
             throw new Exception("解壓失敗");
         }
     }

     /// <summary>
     /// 解析excel中的圖片
     /// </summary>
     /// <returns></returns>
     private List<ExcelImgInfo> Analysis()
     {
         List<ExcelImgPathAndId> imgs = new List<ExcelImgPathAndId>();
         List<ExcelImgInfo> excelImgInfos = new List<ExcelImgInfo>();

         //讀取所有圖片以及位置信息
         FindPicPathByID(ref imgs);

         //默認命名空間
         XNamespace xdr_namespace = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing";
         XNamespace a_namespace = "http://schemas.openxmlformats.org/drawingml/2006/main";
         XNamespace r_namespace = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";

         //加載圖片信息文檔xml(替換的文件名與頁數(shù)對應 此處可以優(yōu)化為傳入指定id)
         XDocument xdoc = XDocument.Load(ExcelZipPath + Drawing.Replace("_id_", "1"));

         //加載文檔中的默認命名空間
         var root = xdoc.Root;
         foreach (var item in root.Attributes())
         {
             if (item.Name.LocalName == "xdr")
             {
                 xdr_namespace = item.Value;
             }
             else if (item.Name.LocalName == "a")
             {
                 a_namespace = item.Value;
             }
         }

         //讀取twoCellAnchor標簽中的內(nèi)容 **核心部分**
         foreach (var node in xdoc.Descendants(xdr_namespace + twoCellAnchor))
         {
             //twoCellAnchor標簽中子標簽內(nèi)容順序永遠為:from->to->pic
             //所以此處順序讀取即可
             var NodeFrom = (XElement)node.FirstNode;
             var NodeTo = (XElement)NodeFrom.NextNode;
             var NodePic = (XElement)NodeTo.NextNode;

             //找到blipFill節(jié)點,并找到r節(jié)點的命名空間
             var blipFill = (XElement)(((XElement)NodePic.FirstNode.NextNode).FirstNode);
             r_namespace = blipFill.FirstAttribute.IsNamespaceDeclaration ? blipFill.FirstAttribute.Value : r_namespace;

             //找到spPr節(jié)點
             var spPr = (XElement)NodePic.FirstNode.NextNode.NextNode;

             //獲取圖片Id
             var ImgId = (blipFill.Attribute(r_namespace + embed) != null ? blipFill.Attribute(r_namespace + embed) : blipFill.Attribute(r_namespace + link)).Value.ToString();

             //獲取from
             var From = new Position()
             {
                 Col = int.Parse(((XElement)NodeFrom.FirstNode).Value),
                 ColOff = int.Parse(((XElement)NodeFrom.FirstNode.NextNode).Value),
                 Row = int.Parse(((XElement)NodeFrom.FirstNode.NextNode.NextNode).Value),
                 RowOff = int.Parse(((XElement)NodeFrom.FirstNode.NextNode.NextNode.NextNode).Value)
             };
             //獲取to
             var To = new Position()
             {
                 Col = int.Parse(((XElement)NodeTo.FirstNode).Value),
                 ColOff = int.Parse(((XElement)NodeTo.FirstNode.NextNode).Value),
                 Row = int.Parse(((XElement)NodeTo.FirstNode.NextNode.NextNode).Value),
                 RowOff = int.Parse(((XElement)NodeTo.FirstNode.NextNode.NextNode.NextNode).Value)
             };

             //獲取圖片插入方式
             var PrstGeom = ((XElement)spPr.FirstNode.NextNode).Attribute(prst).Value.ToString();

             //
             var xfrm = ((XElement)spPr.FirstNode);
             var xfrm_off = ((XElement)xfrm.FirstNode);
             var xfrm_ext = ((XElement)xfrm.FirstNode.NextNode);
             List<int> xfrm_offData = new List<int>
                 {
                     int.Parse(xfrm_off.Attribute("x").Value.ToString()),
                     int.Parse(xfrm_off.Attribute("y").Value.ToString())
                 };
             List<int> xfrm_extData = new List<int>
                 {
                     int.Parse(xfrm_ext.Attribute("cx").Value.ToString()),
                     int.Parse(xfrm_ext.Attribute("cy").Value.ToString())
                 };

             //獲取圖片實際位置
             var PathOfPicture = imgs.FirstOrDefault(e => e.Id == ImgId)?.Path;
             //此處圖片為相對位置需要處理成為絕對路徑
             PathOfPicture = PathOfPicture.Replace("../", ExcelZipPath + "xl\\").Replace("/", "\\");

             //至此 所有需要使用的節(jié)點全部取出 開始組裝數(shù)據(jù)
             ExcelImgInfo excelImgInfo = new ExcelImgInfo(
                 imgId: ImgId,
                 from: From,
                 to: To,
                 prstGeom: PrstGeom,
                 xfrm_off: xfrm_offData,
                 xfrm_ext: xfrm_extData,
                 pathOfPicture: PathOfPicture);

             excelImgInfos.Add(excelImgInfo);
         }
         //Dispose();
         return excelImgInfos;
     }

     /// <summary>
     /// 解壓文件
     /// </summary>
     /// <param name="zipFilePath">壓縮文件路徑</param>
     /// <param name="path">返回壓縮文件夾路徑</param>
     /// <param name="unZipDir">解壓文件存放路徑,為空時默認與壓縮文件同一級目錄下,跟壓縮文件同名的文件夾</param>
     /// <returns></returns>
     private bool UnZipFile(string zipFilePath, out string path, string unZipDir = null)
     {
         if (zipFilePath == string.Empty)
         {
             path = null;
             return false;
         }

         if (!System.IO.File.Exists(zipFilePath))
         {
             path = null;
             return false;
         }
         //解壓文件夾為空時默認與壓縮文件同一級目錄下,跟壓縮文件同名的文件夾
         if (string.IsNullOrWhiteSpace(unZipDir))
             unZipDir = zipFilePath.Replace(Path.GetFileName(zipFilePath), Path.GetFileNameWithoutExtension(zipFilePath));

         if (!unZipDir.EndsWith("\\"))
             unZipDir += "\\";

         if (!Directory.Exists(unZipDir))
             Directory.CreateDirectory(unZipDir);
         try
         {
             using (ZipInputStream s = new ZipInputStream(System.IO.File.OpenRead(zipFilePath)))
             {
                 ZipEntry theEntry;
                 while ((theEntry = s.GetNextEntry()) != null)
                 {
                     string directoryName = Path.GetDirectoryName(theEntry.Name);
                     string fileName = Path.GetFileName(theEntry.Name);
                     if (directoryName.Length > 0)
                     {
                         Directory.CreateDirectory(unZipDir + directoryName);
                     }
                     if (!directoryName.EndsWith("\\"))
                         directoryName += "\\";
                     if (fileName != String.Empty)
                     {
                         using (FileStream streamWriter = System.IO.File.Create(unZipDir + theEntry.Name))
                         {
                             int size = 2048;
                             byte[] data = new byte[2048];
                             while (true)
                             {
                                 size = s.Read(data, 0, data.Length);
                                 if (size > 0)
                                 {
                                     streamWriter.Write(data, 0, size);
                                 }
                                 else
                                 {
                                     break;
                                 }
                             }
                         }
                     }
                 }
             }
         }
         catch
         {
             path = null;
             return false;
         }
         path = unZipDir;

         return true;
     }

     /// <summary>
     /// 獲取全部文件id與路徑
     /// </summary>
     /// <param name="imgs"></param>
     /// <param name="_id"></param>
     private void FindPicPathByID(ref List<ExcelImgPathAndId> imgs, int _id = 1)
     {
         string _file = Path.Combine(ExcelZipPath + DrawingRels.Replace("_id_", _id.ToString()));

         if (!File.Exists(_file))
         {
             throw new DirectoryNotFoundException(_file);
         }

         XDocument xDoc = XDocument.Load(_file);
         var root = xDoc.Root;
         foreach (XElement node in root.Nodes())
         {
             var attrs = node.Attributes();
             string Id = "";
             string Target = "";
             foreach (var attr in attrs)
             {
                 if (attr.Name == "Id")
                     Id = attr.Value.ToString();
                 else if (attr.Name == "Target")
                     Target = attr.Value.ToString();
             }
             imgs.Add(new ExcelImgPathAndId()
             {
                 Id = Id,
                 Path = Target
             });
         }
     }

     /// <summary>
     /// 獲取excel圖片以及位置信息
     /// </summary>
     /// <returns></returns>
     public List<ExcelImgInfo> GetAllImgs()
     {
         return ExcelImgInfos;
     }

     /// <summary>
     /// 刪除解壓的文件
     /// </summary>
     public void Dispose()
     {
         File.Delete(ExcelZipFilePath);
         DirectoryInfo di = new DirectoryInfo(ExcelZipPath);
         di.Delete(true);
     }
 }

需要用到的輔助類

 /// <summary>
 /// 提取出來的圖片信息類
 /// </summary>
 public class ExcelImgInfo
 {
     public ExcelImgInfo()
     {
     }

     public ExcelImgInfo(string imgId, Position from, Position to, string prstGeom, List<int> xfrm_off, List<int> xfrm_ext, string pathOfPicture)
     {
         try
         {
             ImgId = imgId;
             From = from;
             To = to;
             PrstGeom = prstGeom;
             this.xfrm_off = xfrm_off;
             this.xfrm_ext = xfrm_ext;
             PathOfPicture = pathOfPicture;

             if (File.Exists(PathOfPicture))
             {
                 //將圖片讀取到內(nèi)存中并且不鎖定文件
                 FileStream fileStream = new FileStream(PathOfPicture, FileMode.Open, FileAccess.Read);

                 int byteLength = (int)fileStream.Length;
                 byte[] fileBytes = new byte[byteLength];
                 fileStream.Read(fileBytes, 0, byteLength);
                 fileStream.Close();

                 using (MemoryStream ms = new MemoryStream(fileBytes))
                 {
                     ms.Write(fileBytes, 0, fileBytes.Length);
                     ExcelImage = Image.FromStream(ms, true);
                 }
                 imgByteArray = fileBytes;
             }
             else
             {
                 throw new FileNotFoundException("圖片位置錯誤");
             }
         }
         catch (Exception e)
         {
             throw new Exception($" 圖片對象初始化時錯誤:[{imgId}]\n{e.Message}\n{e.StackTrace}");
         }
     }

     /// <summary>
     /// 圖片Id
     /// </summary>
     public string ImgId { get; protected set; }

     /// <summary>
     /// 開始的單元格
     /// </summary>
     public Position From { get; protected set; }

     /// <summary>
     /// 結束的單元格
     /// </summary>
     public Position To { get; protected set; }

     /// <summary>
     /// 圖片插入方式
     /// </summary>
     public string PrstGeom { get; protected set; }

     /// <summary>
     /// [0]:x
     /// [1]:y
     /// </summary>
     public List<int> xfrm_off { get; protected set; } = new List<int>();

     /// <summary>
     /// [0]:cx
     /// [1]:cy
     /// </summary>
     public List<int> xfrm_ext { get; protected set; } = new List<int>();

     /// <summary>
     /// 圖片地址
     /// </summary>
     public string PathOfPicture { get; protected set; }

     /// <summary>
     /// 圖片數(shù)據(jù)
     /// </summary>
     public Image ExcelImage { get; protected set; }

     /// <summary>
     /// 圖片數(shù)組
     /// </summary>
     public byte[] imgByteArray { get; protected set; }

     public void Dispose()
     {
         //ExcelImage.Dispose();
     }
 }
 /// <summary>
 /// 文件Id與路徑
 /// </summary>
 public class ExcelImgPathAndId
 {
     public string Id { get; set; }

     public string Path { get; set; }
 }
 /// <summary>
 /// 位置信息
 /// </summary>
 public class Position
 {
     public int Col { get; set; }
     public int ColOff { get; set; }
     public int Row { get; set; }
     public int RowOff { get; set; }
 }

總結

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • C#基于Extension Method(擴展方法)獲得文件大小的方法

    C#基于Extension Method(擴展方法)獲得文件大小的方法

    這篇文章主要介紹了C#基于Extension Method(擴展方法)獲得文件大小的方法,實例分析了C#擴展方法的定義與文件操作的相關技巧,需要的朋友可以參考下
    2015-06-06
  • C#中Response.Write常見問題匯總

    C#中Response.Write常見問題匯總

    這篇文章主要介紹了C#中Response.Write常見問題匯總,總結了C#中Response.Write的常用技巧,非常實用,需要的朋友可以參考下
    2014-09-09
  • C#實現(xiàn)自動生成電子印章

    C#實現(xiàn)自動生成電子印章

    網(wǎng)絡辦公正逐漸成為常態(tài),無紙化辦公也是一個潮流。本文將利用C#語言實現(xiàn)自動生成電子印章功能,文中的示例代碼講解詳細,感興趣的可以了解一下
    2022-08-08
  • 詳解C#打開和關閉可執(zhí)行文件

    詳解C#打開和關閉可執(zhí)行文件

    這篇文章主要介紹了C#打開和關閉可執(zhí)行文件,以QQ應用程序為例,需要的朋友可以參考下
    2015-12-12
  • C# LiteDB處理時間序列數(shù)據(jù)的高性能解決方案

    C# LiteDB處理時間序列數(shù)據(jù)的高性能解決方案

    LiteDB作為.NET生態(tài)下的輕量級嵌入式NoSQL數(shù)據(jù)庫,一直是時間序列處理的優(yōu)選方案,本文將為大家大家簡單介紹一下LiteDB處理時間序列數(shù)據(jù)的高性能解決方案,希望對大家有所幫助
    2025-08-08
  • C#二維數(shù)組基本用法實例

    C#二維數(shù)組基本用法實例

    這篇文章主要介紹了C#二維數(shù)組基本用法,以實例形式分析了C#中二維數(shù)組的定義、初始化、遍歷及打印等用法,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-10-10
  • C#將PPT文件轉換成PDF文件

    C#將PPT文件轉換成PDF文件

    今天小編就為大家分享一篇關于C#將PPT文件轉換成PDF文件,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • C#中控件動態(tài)添加事件綁定的時機詳解

    C#中控件動態(tài)添加事件綁定的時機詳解

    這篇文章主要給大家介紹了在C#中為控件動態(tài)添加事件綁定的時機的相關資料,文中介紹的非常詳細,對大家具有一定的參考學習價值,需要的朋友們下面跟著小編一起來學習學習吧。
    2017-06-06
  • C#字符串內(nèi)存分配與駐留池學習分享

    C#字符串內(nèi)存分配與駐留池學習分享

    這篇文章主要介紹了C#字符串內(nèi)存分配與駐留池學習分享,大家參考使用吧
    2013-12-12
  • C#?xml序列化實現(xiàn)及遇到的坑

    C#?xml序列化實現(xiàn)及遇到的坑

    在C#中,當我們需要將對象存儲到文件或通過網(wǎng)絡發(fā)送時,我們可以使用XML序列化將C#對象轉換為XML文檔,以便于存儲、傳輸和還原,本文主要介紹了C#?xml序列化實現(xiàn)及遇到的坑,感興趣的可以了解一下
    2023-09-09

最新評論

凤台县| 稷山县| 山阳县| 广平县| 定远县| 常熟市| 宁波市| 宜阳县| 安阳县| 阿拉善左旗| 苍山县| 德令哈市| 南安市| 鸡泽县| 巴南区| 青海省| 凤翔县| 吉首市| 云浮市| 洛扎县| 那坡县| 赣州市| 隆林| 仙游县| 册亨县| 丹阳市| 东阿县| 肥乡县| 昂仁县| 台北市| 阿勒泰市| 陈巴尔虎旗| 墨脱县| 巴楚县| 怀柔区| 凤城市| 鄂托克旗| 枣庄市| 大埔区| 聂拉木县| 扶风县|