7

Epplus ライブラリを使用して、Asp.Net C# で Excel 2010 以降の互換ファイルを生成しています。現時点で最新のバージョン 3.1.2 を使用しています。

次のような写真を追加する前に、最初に行の高さを設定しています。

ExcelPackage pck = new ExcelPackage();
var ws = pck.Workbook.Worksheets.Add("sheet 1");
while (i < dt.Rows.Count + offset)
{
    ws.Row(i).Height = 84;
    i++;
}

dtDataRows を持つ私の DataTable です。高さを設定した後、行を再度ループして写真を追加しています

while (i < dt.Rows.Count + offset)
{
    var prodImg = ws.Drawings.AddPicture(dr["code"].ToString(), new FileInfo(path));
    prodImg.SetPosition(i - 1, 0, 14, 0);
    prodImg.SetSize(75);
}

これは機能しますが、機能しません:

var prodImg = ws.Drawings.AddPicture(dr["code"].ToString(), new FileInfo(path));
int w = prodImg.Image.Width;
int h = prodImg.Image.Height;

if (h > 140) // because height of 84 is 140 pixels in excel
{
    double scale = h / 140.0;
    w = (int)Math.Floor(w / scale);
    h = 140;
}

int xOff = (150 - w) / 2;
int yOff = (140 - h) / 2;

prodImg.SetPosition(i - 1, xOff, 11, yOff);
prodImg.SetSize(w, h);

これにより、画像が中心から外れ、画像がサイズ変更されません。そして、同じループにあるこのコード:

var prodImgDm = ws.Drawings.AddPicture("bcdm" + dr["code"].ToString(), new FileInfo(pathDm));
prodImgDm.SetPosition(i - 1, 25, 15, 40);
prodImgDm.SetSize(100);

これは時々機能します。写真prodImgDmは静的な幅と高さを持つデータマトリックス画像であり、常に小さい/小さいため、サイズを変更する必要はありません。したがってSetSize、一部の行では機能しませんが、他の行では機能しません。コードが同じなので、本当に奇妙です。ライブラリや Excel にあるものである可能性があります。もしかして私の使い方が悪いのでしょうか?epplus 画像の専門家はいますか?

前もって感謝します!!

百聞は一見に如かずということもあるので、ここにスクリーンショットを示します。ご覧のとおり、製品の画像はセル内で水平方向にも垂直方向にも配置されていません。そして、右端のデータマトリックスは、私が設定しても120%程度にスケーリングされることがあるSetSize(100)ので、私には本当に奇妙です。したがって、最後のデータマトリックスのサイズは正しいです...私はすでにこのSOスレッドを見つけましたが、それは役に立たないと思います。

epplusの画像

edit 2013/04/09 Essenpillai が設定のヒントを教えてくれました

pck.DoAdjustDrawings = false;

しかし、それは私にさらに奇妙なイメージを与えました:

doadjustdrawings

データマトリックスはまだ行単位で変化しています。行は問題ありませんが、他の行はそうではありません。ean13 コードが広すぎます。

4

3 に答える 3

2

Epplus ライブラリにも同じ問題があります。
コードでこれを解決する方法が見つからなかった後、このライブラリのソースコードをチェックしました。Epplus は常にtwoCellAnchor図面として Excel 画像を作成します。このコードでxlsx見つけることができるファイルで:drawingXYZ.xml

<xdr:twoCellAnchor editAs="oneCell">
  <xdr:from> ... </xdr:from>
  <xdr:to> ... </xdr:to>
  <xdr:pic>
  ...
</xdr:twoCellAnchor>

そのため、画像は常に 2 つのセルに接続されており、これは Epplus ライブラリの可変部分ではありません。コードのこの部分は、ExcelDrawing.csファイルにあります。

  XmlElement drawNode = _drawingsXml.CreateElement(
    "xdr", "twoCellAnchor", ExcelPackage.schemaSheetDrawings);
  colNode.AppendChild(drawNode);

この dll の独自のコピーを簡単に作成できます。幸いなことに、この問題を修正するには、 2 つのファイルを変更するだけで済みます。そう..

このサイトから Epplus ライブラリのソース コードのコピーをダウンロードし、Visual Studio で開きます。

oneCellAnchordrawingとしてコードを生成する必要があるため、画像の要素を削除し、画像のサイズをパラメーターとして要素を作成する必要があります。 新しい xml 構造は次のようになります。<xdr:to><xdr:ext />

<xdr:oneCellAnchor editAs="oneCell">
  <xdr:from> ... </xdr:from>
  <xdr:ext cx="1234567" cy="7654321" />
  <xdr:pic>
  ...
</xdr:oneCellAnchor>

わかりました、それで、これを行う方法は?

Epplusコードの変更

ExcelDrawings.cs (ファイルへのリンクはこちら)

  1. まず、CreateDrawingXml()内のメソッドを変更しExcelDrawings.csます。元の機能を保持するためにoneCellAnchor、デフォルト値を持つオプションのパラメーター ( create の場合) を追加します。メソッドでは、このパラメーターに基づいて、1 つまたは 2 つのセル アンカーを作成し、<xdr:to>要素を作成するかどうかを指定します。

このメソッド コードの重要な部分:

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次に、同じファイル内の2 つのメソッドを変更します。

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 (ファイルへのリンクはこちら)を変更します。

元のコードは、次のようにコンストラクターに次のコードを追加するためのノードを検索します。

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 を使用する 2 番目のコンストラクターについても同じです。

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.dllEPPlus.pdb、をコピーEPPlus.XMLします (元の dll ファイルをバックアップして置き換えます) (したがって、プロジェクトの参照や設定を変更する必要はありません)。
次に、プロジェクトを開いて再構築し、これで問題が解決するかどうか試してください。

于 2014-02-14T10:20:15.207 に答える