asp.net-mvc – 如何将内存中的图表(或图像)放入内存中的OpenXML文档?

我正在尝试将图表添加到内存中的MemoryStream中,这是一场噩梦.

我正在使用OpenXML动态创建Word文档,并且我还有一个图表,该图表也是从数据库中的数据动态生成的.

我从数据库中获取模板作为字节数组,将其传递给一个方法,该方法还包含一个业务对象,该业务对象包含一堆数据以填充该模板中保存的书签.

这是方法:

public Stream Parse(byte[] array, AudiometryReport AudReport)
{

    using (MemoryStream Stream = new MemoryStream())
    {
        Stream.Write(array, 0, (int)array.Length);
        Stream.Position = 0;

        using (document = WordprocessingDocument.Open(Stream, true))
        {
            XDocument doc = document.MainDocumentPart.GetXDocument();

            List<XElement> bookmarks = doc.Descendants()
                .Where(n => n.NodeType == XmlNodeType.Element && n.Name.LocalName == "bookmarkStart")
                .ToList();

            PropertyInfo[] reportInfo = AudReport.GetType().GetProperties();

            foreach (XElement bm in bookmarks)
            {
                try
                {

                    if (bm.LastAttribute.Value == "AudiometryChart")
                    {
                        string partId = InsertImage(document.MainDocumentPart);

                        var element = AddImageToDocument(document.MainDocumentPart, partId);
                        //var element = InsertImageXElement(partId);

                        //bm.ReplaceWith(new XElement(w + "r", element));
                    }
                    else
                    {
                        string val = reportInfo.Single(x => x.Name == bm.LastAttribute.Value).GetValue(AudReport, null).ToString();

                        bm.ReplaceWith(new XElement(w + "r",
                                new XElement(w + "t", val)));
                    }
                }
                catch
                { }
            }

            document.MainDocumentPart.PutXDocument();
            //foreach (BookmarkStart bm in (IEnumerable<BookmarkStart>)document.MainDocumentPart.Document.Descendants<BookmarkStart>())
            //{
            //    if (bm.Name == "AudiometryChart")
            //    {
            //        // Insert the chart object here.
            //        //AddImage(document);
            //    }
            //    populateStaffDetails(AudReport.Report.Employee, bm);
            //    populateAudiometryDetails(AudReport, bm);
            //}

        }


        MemoryStream s = new MemoryStream();
        Stream.WriteTo(s);
        s.Position = 0;
        return s;
    }

}

InsertImage图像采用MainDocumentPart并从数据库中的图像流中附加新的ImagePart.我将该部分的ID传递回调用方法.

private string InsertImage(MainDocumentPart docPart)
{
    //DrawingsPart dp = docPart.AddNewPart<DrawingsPart>();
    //ImagePart part = dp.AddImagePart(ImagePartType.Png, docPart.GetIdOfPart(dp));
    ImagePart part = docPart.AddImagePart(ImagePartType.Png);
    Chart cht = new ChartBuilder().DoChart(Data, new string[] { "Left", "Right", "Normal" });

    using (MemoryStream ms = new MemoryStream())
    {
        cht.SaveImage(ms, ChartImageFormat.Png);
        ms.Position = 0;

        part.FeedData(ms);
    }

    //int count = dp.ImageParts.Count<ImagePart>();
    int count = docPart.ImageParts.Count<ImagePart>();


    return docPart.GetIdOfPart(part);
}

最后一部分是一些严重的肮脏,需要将一个图像添加到一个word文档,但是到底是什么 – 无论如何它在这里:

private Run AddImageToDocument(MainDocumentPart docPart, string ImageRelId)
{
    string ImageFileName = "Audiometry Chart Example";
    string GraphicDataUri = "http://schemas.openxmlformats.org/drawingml/2006/picture";

    long imageLength = 990000L;
    long imageHeight = 792000L;

    var run = new Run(
        new Drawing(
            new wp.Inline(

                new wp.Extent() { Cx = imageLength, Cy = imageHeight },

                new wp.EffectExtent()
                {
                    LeftEdge = 19050L,
                    TopEdge = 0L,
                    RightEdge = 9525L,
                    BottomEdge = 0L
                },

                new wp.DocProperties()
                {
                    Id = (UInt32Value)1U,
                    Name = "Inline Text Wrapping Picture",
                    Description = ImageFileName
                },

                new wp.NonVisualGraphicFrameDrawingProperties(
                    new a.GraphicFrameLocks() { NoChangeAspect = true }),

                new a.Graphic(
                    new a.GraphicData(
                        new pic.Picture(

                            new pic.NonVisualPictureProperties(
                                new pic.NonVisualDrawingProperties() { Id = (UInt32Value)0U, Name = ImageFileName },
                                new pic.NonVisualPictureDrawingProperties()),

                            new pic.BlipFill(
                                new a.Blip() { Embed = ImageRelId },
                                new a.Stretch(
                                    new a.FillRectangle())),

                            new pic.ShapeProperties(
                                new a.Transform2D(
                                    new a.Offset() { X = 0L, Y = 0L },
                                    new a.Extents() { Cx = imageLength, Cy = imageHeight }),

                                new a.PresetGeometry(
                                    new a.AdjustValueList()) { Preset = a.ShapeTypeValues.Rectangle }))

                        ) { Uri = GraphicDataUri }))
                {
                    DistanceFromTop = (UInt32Value)0U,
                    DistanceFromBottom = (UInt32Value)0U,
                    DistanceFromLeft = (UInt32Value)0U,
                    DistanceFromRight = (UInt32Value)0U
                }
            ));

    return run;
}

因此,我已经解决了内存流因过早关闭而导致问题的问题以及可能的十几个其他不必要的业余花园路径问题,但该图像将不会出现在我的文档中.令人沮丧.建议或神圣的灵感现在非常欢迎.

(这个问题已经过大量编辑,所以有些答案可能与此问题的措辞无关).

最佳答案 我刚刚在一个小测试中测试了你的AddImageToDocument函数

场景使用以下代码:

string partId = ...

Run element = AddImageToDocument(newdoc.MainDocumentPart, partId);

Paragraph p = new Paragraph() { RsidParagraphAddition = "00EA6221", RsidRunAdditionDefault = "008D25CC" };

p.AppendChild(element);

newdoc.MainDocumentPart.Document.Body.Append(p);

// Save the word document here...

一切都按预期工作,图像显示在word文档中.

然后我得出结论,代码中的问题必须是bookmarkStart标记和转换的替换
Run(包含图像)到XElement.

所以,我已经按照以下方式修改了代码(使用XElement.Parse进行转换
一个XElement的OpenXmlElement):

foreach (XElement bm in bookmarks)
{
  try
  {
    if (bm.LastAttribute.Value == "AudiometryChart")
    {
      string partId = InsertImage(document.MainDocumentPart);

      Run element = AddImageToDocument(document.MainDocumentPart, partId);

      bm.ReplaceWith(XElement.Parse(element.OuterXml)); // Use XElement.Parse to convert an OpenXmlElement to an XElement.
    }
    else
    {
      ...                    }
    }
  }
  catch
  {
  }
}

图像现在显示在word文档中.

然后我用the分析了word文档
OpenXml SDK生产力工具,发现bookmarkEnd标签仍然存在于文档中.

要删除这些标记,请使用以下代码:

List<XElement> bookmarksEnd = doc.Descendants()
            .Where(n => n.NodeType == XmlNodeType.Element && n.Name.LocalName == "bookmarkEnd")
            .ToList();

foreach (XElement x in bookmarksEnd)
{
  x.Remove();  
}     
点赞