SoFunction
Updated on 2025-04-29

C# Npoi How to read cell picture and get the cell position

C# Npoi reads cell picture and gets the cell position

C# Read pictures in excel Get cell position information of the picture (limited to xlsx only)

Main code logic

  1. Open excel directly using zip
  2. The image information in the compressed package is mainly stored in two folders (xl/media, xl/drawings). The former is the picture itself, and the latter is the main information of the picture.
  3. There will be several .xml files starting with drawing in the drawings folder. A sheet page corresponds to a suffix increments according to the number sequence number (for example: the first page is, the second page is, and so on)
  4. After opening, read the document node, and the node meaning comparison table is at the end
  5. After obtaining the rid of the picture in the pic tag, use this id to find the corresponding storage address of the picture in the _rels folder in the same directory (for example, the corresponding one)
twoCellAnchor The node of image information contains the starting cell position of the image under the node. The id of the image is the content of [r:embed]. How many [twoCellAnchor] exists, that is, how many pictures exist.
twoCellAnchor/from Cell information on the starting position of the upper left corner of the picture
twoCellAnchor/to Cell information on the end position of the lower right corner of the picture (current requirements need to ensure that a picture exists in one cell as much as possible, and it is not allowed to cross cells because other processing will not be done)
twoCellAnchor/pic File information of the picture Mainly read [blipFill->blip->r:embed] This information is the id information of the picture and can be read to the location where the file is stored in the media folder.
twoCellAnchor/xfrm To determine the information, the main guess is the size of the picture?
twoCellAnchor/prstGeom How to insert pictures

The following is the encapsulated code

 public class ExcelImgHelper
 {
     #region constant
     /// <summary>
     /// File id and file path folder path     /// </summary>
     private const string DrawingRels = "xl/drawings/_rels/drawing_id_.";

     /// <summary>
     /// Picture information file     /// </summary>
     private const string Drawing = "xl/drawings/drawing_id_.xml";

     #region Picture information main tags
     private const string twoCellAnchor = "twoCellAnchor";
     private const string embed = "embed";
     private const string link = "link";
     private const string prst = "prst";

     #endregion Picture information main tags
     #endregion Constant
     #region path information
     /// <summary>
     /// Excel file address     /// </summary>
     private string ExcelPath { get; }

     /// <summary>
     /// Unzipped folder     /// </summary>
     private string ExcelZipPath { get; }

     /// <summary>
     /// Compressed package *Note: The current path is compressed file package.zip     /// </summary>
     private string ExcelZipFilePath { get; }

     #endregion path information
     private List<ExcelImgInfo> ExcelImgInfos = new List<ExcelImgInfo>();

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

         //The location of the folder after decompression is the same as the source file.         var dir = (filePath);
         //Get file name         var fileName = (filePath);
         //Compressed package path         var zipFilePath = dir + "\\" + fileName + ".zip";

         //Copy as a compressed package         (filePath, zipFilePath);

         //Decompress the file         if (UnZipFile(filePath, out string UnZipFilePath))
         {
             ExcelPath = filePath;
             ExcelZipPath = UnZipFilePath;
             ExcelZipFilePath = zipFilePath;

             ExcelImgInfos = Analysis();
         }
         else
         {
             throw new Exception("Decompression failed");
         }
     }

     /// <summary>
     /// parse pictures in excel     /// </summary>
     /// <returns></returns>
     private List<ExcelImgInfo> Analysis()
     {
         List<ExcelImgPathAndId> imgs = new List<ExcelImgPathAndId>();
         List<ExcelImgInfo> excelImgInfos = new List<ExcelImgInfo>();

         //Read all pictures and location information         FindPicPathByID(ref imgs);

         //Default namespace         XNamespace xdr_namespace = "/drawingml/2006/spreadsheetDrawing";
         XNamespace a_namespace = "/drawingml/2006/main";
         XNamespace r_namespace = "/officeDocument/2006/relationships";

         //Load the image information document xml (the replaced file name corresponds to the number of pages. Here it can be optimized to pass in a specified id)         XDocument xdoc = (ExcelZipPath + ("_id_", "1"));

         //Load the default namespace in the document         var root = ;
         foreach (var item in ())
         {
             if ( == "xdr")
             {
                 xdr_namespace = ;
             }
             else if ( == "a")
             {
                 a_namespace = ;
             }
         }

         //Read the content in the twoCellAnchor tag **Core part**         foreach (var node in (xdr_namespace + twoCellAnchor))
         {
             //The content order of sub-tags in twoCellAnchor tags is always: from->to->pic             //So read it in sequence here             var NodeFrom = (XElement);
             var NodeTo = (XElement);
             var NodePic = (XElement);

             //Find the blipFill node and find the namespace of the r node             var blipFill = (XElement)(((XElement)).FirstNode);
             r_namespace =  ?  : r_namespace;

             //Find the spPr node             var spPr = (XElement);

             //Get picture ID             var ImgId = ((r_namespace + embed) != null ? (r_namespace + embed) : (r_namespace + link)).();

             //Get from             var From = new Position()
             {
                 Col = (((XElement)).Value),
                 ColOff = (((XElement)).Value),
                 Row = (((XElement)).Value),
                 RowOff = (((XElement)).Value)
             };
             //Get to             var To = new Position()
             {
                 Col = (((XElement)).Value),
                 ColOff = (((XElement)).Value),
                 Row = (((XElement)).Value),
                 RowOff = (((XElement)).Value)
             };

             //Get picture insertion method             var PrstGeom = ((XElement)).Attribute(prst).();

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

             //Get the actual location of the picture             var PathOfPicture = (e =>  == ImgId)?.Path;
             //The picture here is a relative position and needs to be processed to become an absolute path             PathOfPicture = ("../", ExcelZipPath + "xl\\").Replace("/", "\\");

             //At this point, all nodes that need to be used will be removed and the data will be assembled.             ExcelImgInfo excelImgInfo = new ExcelImgInfo(
                 imgId: ImgId,
                 from: From,
                 to: To,
                 prstGeom: PrstGeom,
                 xfrm_off: xfrm_offData,
                 xfrm_ext: xfrm_extData,
                 pathOfPicture: PathOfPicture);

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

     /// <summary>
     /// Unzip the file     /// </summary>
     /// <param name="zipFilePath">Compressed file path</param>     /// <param name="path">Return to compressed folder path</param>     /// <param name="unZipDir">The decompressed file storage path is empty. When it is empty, the default is the same as the compressed file. The folder with the same name as the compressed file.</param>     /// &lt;returns&gt;&lt;/returns&gt;
     private bool UnZipFile(string zipFilePath, out string path, string unZipDir = null)
     {
         if (zipFilePath == )
         {
             path = null;
             return false;
         }

         if (!(zipFilePath))
         {
             path = null;
             return false;
         }
         // When the decompressed folder is empty, the default is the same as the compressed file in the same level directory as the compressed file, and the folder with the same name as the compressed file is         if ((unZipDir))
             unZipDir = ((zipFilePath), (zipFilePath));

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

         if (!(unZipDir))
             (unZipDir);
         try
         {
             using (ZipInputStream s = new ZipInputStream((zipFilePath)))
             {
                 ZipEntry theEntry;
                 while ((theEntry = ()) != null)
                 {
                     string directoryName = ();
                     string fileName = ();
                     if ( &gt; 0)
                     {
                         (unZipDir + directoryName);
                     }
                     if (!("\\"))
                         directoryName += "\\";
                     if (fileName != )
                     {
                         using (FileStream streamWriter = (unZipDir + ))
                         {
                             int size = 2048;
                             byte[] data = new byte[2048];
                             while (true)
                             {
                                 size = (data, 0, );
                                 if (size &gt; 0)
                                 {
                                     (data, 0, size);
                                 }
                                 else
                                 {
                                     break;
                                 }
                             }
                         }
                     }
                 }
             }
         }
         catch
         {
             path = null;
             return false;
         }
         path = unZipDir;

         return true;
     }

     /// &lt;summary&gt;
     /// Get all file ids and paths     /// &lt;/summary&gt;
     /// &lt;param name="imgs"&gt;&lt;/param&gt;
     /// &lt;param name="_id"&gt;&lt;/param&gt;
     private void FindPicPathByID(ref List&lt;ExcelImgPathAndId&gt; imgs, int _id = 1)
     {
         string _file = (ExcelZipPath + ("_id_", _id.ToString()));

         if (!(_file))
         {
             throw new DirectoryNotFoundException(_file);
         }

         XDocument xDoc = (_file);
         var root = ;
         foreach (XElement node in ())
         {
             var attrs = ();
             string Id = "";
             string Target = "";
             foreach (var attr in attrs)
             {
                 if ( == "Id")
                     Id = ();
                 else if ( == "Target")
                     Target = ();
             }
             (new ExcelImgPathAndId()
             {
                 Id = Id,
                 Path = Target
             });
         }
     }

     /// &lt;summary&gt;
     /// Get Excel pictures and location information     /// &lt;/summary&gt;
     /// &lt;returns&gt;&lt;/returns&gt;
     public List&lt;ExcelImgInfo&gt; GetAllImgs()
     {
         return ExcelImgInfos;
     }

     /// &lt;summary&gt;
     /// Delete the unzipped file     /// &lt;/summary&gt;
     public void Dispose()
     {
         (ExcelZipFilePath);
         DirectoryInfo di = new DirectoryInfo(ExcelZipPath);
         (true);
     }
 }

Auxiliary classes required

 /// &lt;summary&gt;
 /// Extracted picture information /// &lt;/summary&gt;
 public class ExcelImgInfo
 {
     public ExcelImgInfo()
     {
     }

     public ExcelImgInfo(string imgId, Position from, Position to, string prstGeom, List&lt;int&gt; xfrm_off, List&lt;int&gt; 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 ((PathOfPicture))
             {
                 //Read the image into memory and do not lock the file                 FileStream fileStream = new FileStream(PathOfPicture, , );

                 int byteLength = (int);
                 byte[] fileBytes = new byte[byteLength];
                 (fileBytes, 0, byteLength);
                 ();

                 using (MemoryStream ms = new MemoryStream(fileBytes))
                 {
                     (fileBytes, 0, );
                     ExcelImage = (ms, true);
                 }
                 imgByteArray = fileBytes;
             }
             else
             {
                 throw new FileNotFoundException("Image location error");
             }
         }
         catch (Exception e)
         {
             throw new Exception($" Error when initializing image object:[{imgId}]\n{}\n{}");
         }
     }

     /// &lt;summary&gt;
     /// Picture Id     /// &lt;/summary&gt;
     public string ImgId { get; protected set; }

     /// &lt;summary&gt;
     /// Start cell     /// &lt;/summary&gt;
     public Position From { get; protected set; }

     /// &lt;summary&gt;
     /// Ended cell     /// &lt;/summary&gt;
     public Position To { get; protected set; }

     /// &lt;summary&gt;
     /// Picture insertion method     /// &lt;/summary&gt;
     public string PrstGeom { get; protected set; }

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

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

     /// &lt;summary&gt;
     /// Picture address     /// &lt;/summary&gt;
     public string PathOfPicture { get; protected set; }

     /// &lt;summary&gt;
     /// Picture data     /// &lt;/summary&gt;
     public Image ExcelImage { get; protected set; }

     /// &lt;summary&gt;
     /// Picture array     /// &lt;/summary&gt;
     public byte[] imgByteArray { get; protected set; }

     public void Dispose()
     {
         //();
     }
 }
 /// &lt;summary&gt;
 /// File ID and path /// &lt;/summary&gt;
 public class ExcelImgPathAndId
 {
     public string Id { get; set; }

     public string Path { get; set; }
 }
 /// &lt;summary&gt;
 /// Location information /// &lt;/summary&gt;
 public class Position
 {
     public int Col { get; set; }
     public int ColOff { get; set; }
     public int Row { get; set; }
     public int RowOff { get; set; }
 }

Summarize

The above is personal experience. I hope you can give you a reference and I hope you can support me more.