我有Epplus库同样的问题。
后,我发现没有解决如何在我的代码解决这个问题,我查了一下这个库的source code。 Epplus创建总是擅长的图片作为twoCellAnchor
图。在xlsx
文件,你可以用这个代码中找到drawingXYZ.xml
:
<xdr:twoCellAnchor editAs="oneCell">
<xdr:from> ... </xdr:from>
<xdr:to> ... </xdr:to>
<xdr:pic>
...
</xdr:twoCellAnchor>
因此,画面总是连接到两个单元,这是不是Epplus库的可变部分。您可以在ExcelDrawing.cs文件中找到这部分代码。
XmlElement drawNode = _drawingsXml.CreateElement(
"xdr", "twoCellAnchor", ExcelPackage.schemaSheetDrawings);
colNode.AppendChild(drawNode);
你可以很容易地创建自己的dll副本。好消息是你只需要修改两个文件来解决这个问题。所以..
从this site下载Epplus库的源代码副本,并在Visual Studio中打开。
我们需要产生的drawing
代码oneCellAnchor,所以我们必须删除图片<xdr:to>
元素,创造元素<xdr:ext />
与图片的尺寸作为参数。
新的XML结构是这样的:
<xdr:oneCellAnchor editAs="oneCell">
<xdr:from> ... </xdr:from>
<xdr:ext cx="1234567" cy="7654321" />
<xdr:pic>
...
</xdr:oneCellAnchor>
好了,所以,如何做到这一点?
变化Epplus代码
ExcelDrawings.cs(link to file here)
- 起初,我们修改内部
ExcelDrawings.cs
方法CreateDrawingXml()
。为了保留原有的功能,我们添加一个可选参数(如果创建oneCellAnchor
)与默认值。并且在方法中,基于此参数,我们创建一个或两个单元格锚点并创建或不创建元素。
这种方法代码重要组成部分:
private XmlElement CreateDrawingXml(bool twoCell = true) {
if (DrawingXml.OuterXml == "")
{ ... } // not changed
XmlNode colNode= _drawingsXml.SelectSingleNode("//xdr:wsDr", NameSpaceManager);
//First change in method code
XmlElement drawNode;
if (twoCell)
drawNode = _drawingsXml.CreateElement(
"xdr", "twoCellAnchor", ExcelPackage.schemaSheetDrawings);
else
drawNode = _drawingsXml.CreateElement(
"xdr", "oneCellAnchor", ExcelPackage.schemaSheetDrawings);
colNode.AppendChild(drawNode);
//Add from position Element; // Not changed
XmlElement fromNode = _drawingsXml.CreateElement(
"xdr", "from", ExcelPackage.schemaSheetDrawings);
drawNode.AppendChild(fromNode);
fromNode.InnerXml = "<xdr:col>0</xdr:col><xdr:colOff>0</xdr:colOff>"
+ "<xdr:row>0</xdr:row><xdr:rowOff>0</xdr:rowOff>";
//Add to position Element;
//Second change in method
if (twoCell)
{
XmlElement toNode = _drawingsXml.CreateElement(
"xdr", "to", ExcelPackage.schemaSheetDrawings);
drawNode.AppendChild(toNode);
toNode.InnerXml = "<xdr:col>10</xdr:col><xdr:colOff>0</xdr:colOff>"
+ "<xdr:row>10</xdr:row><xdr:rowOff>0</xdr:rowOff>";
}
return drawNode;
}
然后我们修改两个方法AddPicture
同一个文件内:
public ExcelPicture AddPicture(string Name, Image image, Uri Hyperlink)
{
if (image != null) {
if (_drawingNames.ContainsKey(Name.ToLower())) {
throw new Exception("Name already exists in the drawings collection");
}
XmlElement drawNode = CreateDrawingXml(false);
// Change: we need create element with dimensions
// like: <xdr:ext cx="3857625" cy="1047750" />
XmlElement xdrext = _drawingsXml.CreateElement(
"xdr", "ext", ExcelPackage.schemaSheetDrawings);
xdrext.SetAttribute("cx",
(image.Width * ExcelDrawing.EMU_PER_PIXEL).ToString());
xdrext.SetAttribute("cy",
(image.Height * ExcelDrawing.EMU_PER_PIXEL).ToString());
drawNode.AppendChild(xdrext);
// End of change, next part of method is the same:
drawNode.SetAttribute("editAs", "oneCell");
...
}
}
这种方法与FileInfo
作为输入参数:
public ExcelPicture AddPicture(string Name, FileInfo ImageFile, Uri Hyperlink)
{
if (ImageFile != null) {
if (_drawingNames.ContainsKey(Name.ToLower())) {
throw new Exception("Name already exists in the drawings collection");
}
XmlElement drawNode = CreateDrawingXml(false);
// Change: First create ExcelPicture object and calculate EMU dimensions
ExcelPicture pic = new ExcelPicture(this, drawNode, ImageFile, Hyperlink);
XmlElement xdrext = _drawingsXml.CreateElement(
"xdr", "ext", ExcelPackage.schemaSheetDrawings);
xdrext.SetAttribute("cx",
(pic.Image.Width * ExcelDrawing.EMU_PER_PIXEL).ToString());
xdrext.SetAttribute("cy",
(pic.Image.Height * ExcelDrawing.EMU_PER_PIXEL).ToString());
drawNode.AppendChild(xdrext);
// End of change, next part of method is the same (without create pic object)
drawNode.SetAttribute("editAs", "oneCell");
...
}
}
所以,这都是重要的代码。现在我们必须更改用于搜索节点的代码并保持元素的顺序。
在private void AddDrawings()
我们改变xpath
来自:
XmlNodeList list = _drawingsXml.SelectNodes(
"//xdr:twoCellAnchor", NameSpaceManager);
对此:
XmlNodeList list = _drawingsXml.SelectNodes(
"//(xdr:twoCellAnchor or xdr:oneCellAnchor)", NameSpaceManager);
这是所有在这个文件中,现在我们改变
ExcelPicture。CS(link to file here)进行追加下面的代码在构造函数中这样
原始代码中找到节点:
node.SelectSingleNode("xdr:to",NameSpaceManager);
因为我们没有创造总是<xdr:to>
元素,我们更改此代码:
internal ExcelPicture(ExcelDrawings drawings, XmlNode node
, Image image, Uri hyperlink)
: base(drawings, node, "xdr:pic/xdr:nvPicPr/xdr:cNvPr/@name")
{
XmlElement picNode = node.OwnerDocument.CreateElement(
"xdr", "pic", ExcelPackage.schemaSheetDrawings);
// Edited: find xdr:to, or xdr:ext if xdr:to not exists
XmlNode befor = node.SelectSingleNode("xdr:to",NameSpaceManager);
if (befor != null && befor.Name == "xdr:to")
node.InsertAfter(picNode, befor);
else {
befor = node.SelectSingleNode("xdr:ext", NameSpaceManager);
node.InsertAfter(picNode, befor);
}
// End of change, next part of constructor is unchanged
_hyperlink = hyperlink;
...
}
对于FileInfo作为输入参数的第二个构造函数也是如此:
internal ExcelPicture(ExcelDrawings drawings, XmlNode node
, FileInfo imageFile, Uri hyperlink)
: base(drawings, node, "xdr:pic/xdr:nvPicPr/xdr:cNvPr/@name")
{
XmlElement picNode = node.OwnerDocument.CreateElement(
"xdr", "pic", ExcelPackage.schemaSheetDrawings);
// Edited: find xdr:to, or xdr:ext if xdr:to not exists
XmlNode befor = node.SelectSingleNode("xdr:to", NameSpaceManager);
if (befor != null && befor.Name == "xdr:to")
node.InsertAfter(picNode, befor);
else {
befor = node.SelectSingleNode("xdr:ext", NameSpaceManager);
node.InsertAfter(picNode, befor);
}
// End of change, next part of constructor is unchanged
_hyperlink = hyperlink;
...
现在,图片被创建为oneCellAnchor
。如果您愿意,您可以为展位变体创建多个AddPicture
方法。最后一步是建立这个项目并创建自己的自定义EPPlus.dll
。然后关闭您的项目,它使用的DLL和复制新文件EPPlus.dll
,EPPlus.pdb
,EPPlus.XML
您的项目中(备份和更换原来的DLL文件)在同一个地方(所以你不需要做任何改变你的项目引用或设置) 。
然后打开并重建项目和尝试,如果这个解决您的问题。
看起来像是一个很好的项目拉动请求。 https://epplus.codeplex.com/sourcecontrol/list/contributions – 2014-02-14 10:40:53
ps。我发现这个资源https://epplus.codeplex.com/workitem/14675这表明,绘图应该有editas道具设置。那里你可以选择绝对的,一个单元,两个单元 – 2014-07-11 13:49:44