【问题标题】:How do I get an in-memory chart (or image) into an in-memory OpenXML document?如何将内存中的图表(或图像)放入内存中的 OpenXML 文档中?
【发布时间】:2012-04-02 19:41:13
【问题描述】:

我正在做噩梦,试图将图表添加到内存中的 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;
}

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

(此问题已被大量编辑,因此某些答案可能与此问题的措辞无关)。

【问题讨论】:

    标签: asp.net-mvc stream openxml mschart


    【解决方案1】:

    我刚刚在一个小测试中测试了你的 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 转换 OpenXmlElementXElement):

    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 文档中。

    然后我使用 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();  
    }     
    

    【讨论】:

    • 是的!这正是我需要的解决方案。剩下的就是让我更正尺寸,但这没问题。非常感谢,做得很好。
    【解决方案2】:

    编辑 3: :o) 好的,我发现了问题。 如果您使用文档内容初始化文档的 MemoryStream,则缓冲区的大小将固定且不可编辑。只是在创建后更改了 init 以编写文档内容,一切似乎都可以正常工作。

    //using (MemoryStream stream = new MemoryStream (docxFile))
    using (MemoryStream stream = new MemoryStream ())
    {
        stream.Write (docxFile, 0, docxFile.Length);
        stream.Position = 0;
        using (WordprocessingDocument docx = WordprocessingDocument.Open (stream, true))
        {
             [....]
    

    干杯

    【讨论】:

    • 不。还是没有解决。对首先必须将图像保存到磁盘然后再读回它的想法犹豫不决。远非理想。
    • 顺便感谢 Atul Verma infoq.com/news/2012/01/worddocgenerator。我在单步执行他的代码时发现了问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-03
    • 1970-01-01
    • 2012-01-25
    • 2021-03-17
    • 1970-01-01
    相关资源
    最近更新 更多