如何使用 EPPlus 在 excel 文件 (xlsx) 中获取以像素为单位的 shape/picture 坐标
How to get a shape/picture coordinates in pixels in an excel file (xlsx) using EPPlus
有没有人使用 epplus 成功获得 excel 2010 文件中 sheet 中形状或图片的 x 和 y 坐标(以像素为单位)?
不幸的是,它并不漂亮。您真正需要的函数是 ExcelDrawingBase.cs
文件中的 GetPixelTop
和 GetPixelLeft
,但它们被标记为 internal
:http://epplus.codeplex.com/SourceControl/latest#EPPlus/Drawing/ExcelDrawingBase.cs。所以不修改源码是无法真正调用的。
最简单的方法就是重新创建您自己的版本。这是一个快速 cut/paste(确保在投入生产之前做好 QA):
public int DrawingPixelX(ExcelWorksheet worksheet, ExcelDrawing drawing)
{
const int emuPerPixel = ExcelDrawing.EMU_PER_PIXEL;
decimal mdw = worksheet.Workbook.MaxFontWidth;
var pix = 0;
for (var i = 1; i <= drawing.From.Column; i++)
pix += (int)decimal.Truncate(((256 * (decimal)worksheet.Column(i).Width + decimal.Truncate(128 / mdw)) / 256) * mdw);
pix += drawing.From.ColumnOff / emuPerPixel;
return pix;
}
public int DrawingPixelY(ExcelWorksheet worksheet, ExcelDrawing drawing)
{
const int emuPerPixel = ExcelDrawing.EMU_PER_PIXEL;
var piy = 0;
for (var i = 1; i <= drawing.From.Row; i++)
piy += (int)(worksheet.Row(i).Height / 0.75);
piy += drawing.From.RowOff / emuPerPixel;
return piy;
}
你可以这样使用它:
var workbook = package.Workbook;
var ws = workbook.Worksheets.First();
var pic = ws.Drawings.First();
Console.WriteLine(DrawingPixelX(ws, pic));
Console.WriteLine(DrawingPixelY(ws, pic));
我得到的左图和上图分别为 141 和 43。
我终于找到了一个使用内部 xml 数据的解决方案,似乎 excel 正在使用一个名为 EMU
的度量单位,即 equal to 1/9525 pixel
。解决方案如下
public static Rectangle GetDimensions(string shapeName, ExcelWorksheet sheet)
{
const int EMU = 9525;
var shapeBaseNodexPath = string.Format("//*[@name='{0}']", shapeName);
//get node that contains name of the shape
var shapeNameNode = sheet.Drawings.DrawingXml.SelectSingleNode(shapeBaseNode);
if (shapeNameNode == null)
throw new ArgumentException("Invalid shape name");
//go 2 levels up and select shape properties node <a:xfrm> node
var propertiesNode = shapeNameNode
.SelectSingleNode("../../*[local-name() = 'spPr']/*[local-name() = 'xfrm']");
if (propertiesNode == null)
throw new InvalidOperationException("Could not parse Excel file xml data");
//get coodinates and size nodes
var locationNode = propertiesNode.SelectSingleNode("*[local-name() = 'off']");
var sizeNode = propertiesNode.SelectSingleNode("*[local-name() = 'ext']");
//create Rectangle
int x, y, w, h = 0;
x = int.Parse(locationNode.Attributes["x"].Value) / EMU;
y = int.Parse(locationNode.Attributes["y"].Value) / EMU;
w = int.Parse(sizeNode.Attributes["cx"].Value) / EMU;
h = int.Parse(sizeNode.Attributes["cy"].Value) / EMU;
return new Rectangle(x, y, w, h);
}
您可以从内部 ExcelDrawing
内部字段 _widht
和 _height
中读取它。感谢@Ernie 指向 ExcelDrawingBase.cs
.
shape = (ExcelShape) xls.Workbook.Worksheets[1].Drawings["MyShape"];
var width = (int) shape.GetType()
.GetProperty("_width", BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(shape);
var height = (int) shape.GetType()
.GetProperty("_height", BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(shape);
编辑:此方法仅在 EPP 4 上测试,当前版本 EPP 5 内部实现可能已更改。
有没有人使用 epplus 成功获得 excel 2010 文件中 sheet 中形状或图片的 x 和 y 坐标(以像素为单位)?
不幸的是,它并不漂亮。您真正需要的函数是 ExcelDrawingBase.cs
文件中的 GetPixelTop
和 GetPixelLeft
,但它们被标记为 internal
:http://epplus.codeplex.com/SourceControl/latest#EPPlus/Drawing/ExcelDrawingBase.cs。所以不修改源码是无法真正调用的。
最简单的方法就是重新创建您自己的版本。这是一个快速 cut/paste(确保在投入生产之前做好 QA):
public int DrawingPixelX(ExcelWorksheet worksheet, ExcelDrawing drawing)
{
const int emuPerPixel = ExcelDrawing.EMU_PER_PIXEL;
decimal mdw = worksheet.Workbook.MaxFontWidth;
var pix = 0;
for (var i = 1; i <= drawing.From.Column; i++)
pix += (int)decimal.Truncate(((256 * (decimal)worksheet.Column(i).Width + decimal.Truncate(128 / mdw)) / 256) * mdw);
pix += drawing.From.ColumnOff / emuPerPixel;
return pix;
}
public int DrawingPixelY(ExcelWorksheet worksheet, ExcelDrawing drawing)
{
const int emuPerPixel = ExcelDrawing.EMU_PER_PIXEL;
var piy = 0;
for (var i = 1; i <= drawing.From.Row; i++)
piy += (int)(worksheet.Row(i).Height / 0.75);
piy += drawing.From.RowOff / emuPerPixel;
return piy;
}
你可以这样使用它:
var workbook = package.Workbook;
var ws = workbook.Worksheets.First();
var pic = ws.Drawings.First();
Console.WriteLine(DrawingPixelX(ws, pic));
Console.WriteLine(DrawingPixelY(ws, pic));
我得到的左图和上图分别为 141 和 43。
我终于找到了一个使用内部 xml 数据的解决方案,似乎 excel 正在使用一个名为 EMU
的度量单位,即 equal to 1/9525 pixel
。解决方案如下
public static Rectangle GetDimensions(string shapeName, ExcelWorksheet sheet)
{
const int EMU = 9525;
var shapeBaseNodexPath = string.Format("//*[@name='{0}']", shapeName);
//get node that contains name of the shape
var shapeNameNode = sheet.Drawings.DrawingXml.SelectSingleNode(shapeBaseNode);
if (shapeNameNode == null)
throw new ArgumentException("Invalid shape name");
//go 2 levels up and select shape properties node <a:xfrm> node
var propertiesNode = shapeNameNode
.SelectSingleNode("../../*[local-name() = 'spPr']/*[local-name() = 'xfrm']");
if (propertiesNode == null)
throw new InvalidOperationException("Could not parse Excel file xml data");
//get coodinates and size nodes
var locationNode = propertiesNode.SelectSingleNode("*[local-name() = 'off']");
var sizeNode = propertiesNode.SelectSingleNode("*[local-name() = 'ext']");
//create Rectangle
int x, y, w, h = 0;
x = int.Parse(locationNode.Attributes["x"].Value) / EMU;
y = int.Parse(locationNode.Attributes["y"].Value) / EMU;
w = int.Parse(sizeNode.Attributes["cx"].Value) / EMU;
h = int.Parse(sizeNode.Attributes["cy"].Value) / EMU;
return new Rectangle(x, y, w, h);
}
您可以从内部 ExcelDrawing
内部字段 _widht
和 _height
中读取它。感谢@Ernie 指向 ExcelDrawingBase.cs
.
shape = (ExcelShape) xls.Workbook.Worksheets[1].Drawings["MyShape"];
var width = (int) shape.GetType()
.GetProperty("_width", BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(shape);
var height = (int) shape.GetType()
.GetProperty("_height", BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(shape);
编辑:此方法仅在 EPP 4 上测试,当前版本 EPP 5 内部实现可能已更改。