【问题标题】:C# & OpenXML: Insert an image into an excel documentC# & OpenXML:将图像插入到 Excel 文档中
【发布时间】:2011-04-26 17:15:05
【问题描述】:

我正在使用 this 代码的修改版本来创建 Excel 文档、添加单元格和样式单元格。我正在尝试修改此代码,以便也能够将图像添加到工作表中。我无处可去,网络上确实没有任何帮助。我正在尝试通读 OpenXML 生产力工具差异。这有点无益。这里有人能指出我正确的方向吗?

谢谢。

【问题讨论】:

    标签: c# image excel openxml


    【解决方案1】:

    我查看了 Vincent Tan 和 David Yates 的答案。由于我花了几个小时的编码来满足以下简单要求,因此我将在此处发布我的解决方案,以便下一个人可以节省一些时间。

    要求:

    • 将图像添加到现有 Excel 电子表格/工作表的特定单元格
    • 创建新电子表格并将图像添加到特定单元格
    • 将图像添加到 WorksheetPart 的特定单元格(以便在保存之前执行其他操作)
    • 从流中添加图像
    • 从文件中添加图片
    • 使用不同的图片格式

    用法

    // Add via file to existing spreadsheet
    try
    {
        ExcelTools.AddImage(false, filePath, "Sheet name",
                            imagePath, "Image description",
                            2 /* column */, 2 /* row */);
    }
    catch ...
    
    // Add via stream to existing spreadsheet
    try
    {
        ExcelTools.AddImage(false, filePath, "Sheet name",
                            imageStream, "Image description",
                            2 /* column */, 2 /* row */);
    }
    catch ...
    
    // Create spreadsheet and add image via path
    try
    {
        ExcelTools.AddImage(true, filePath, "Sheet name",
                            imagePath, "Image description",
                            2 /* column */, 2 /* row */);
    }
    catch ...
    
    // Create spreadsheet and add image via stream
    try
    {
        ExcelTools.AddImage(true, filePath, "Sheet name",
                            imageStream, "Image description",
                            2 /* column */, 2 /* row */);
    }
    catch ...
    
    // Add multiple images or apply further changes
    try
    {
        // Open spreadsheet
        spreadsheetDocument = SpreadsheetDocument.Open(excelFile, true);
    
        // Get WorksheetPart
        worksheetPart = ExcelTools.GetWorksheetPartByName(spreadsheetDocument, "Some sheet name");
    
        AddImage(worksheetPart, imagePath1, "My first image", 1, 1); // A1
        AddImage(worksheetPart, imagePath2, "My second image", 1, 5); // A5
        AddImage(worksheetPart, imagePath3, "My third image", 2, 7); // B7
    
        // Other operations if needed
    
        worksheetPart.Worksheet.Save();
    
        spreadsheetDocument.Close();
    }
    catch ...
    

    代码:

    using System;
    using System.Data;
    using System.Linq;
    using System.IO;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.Collections.Generic;
    using DocumentFormat.OpenXml;
    using DocumentFormat.OpenXml.Packaging;
    using DocumentFormat.OpenXml.Spreadsheet;
    using A = DocumentFormat.OpenXml.Drawing;
    using Xdr = DocumentFormat.OpenXml.Drawing.Spreadsheet;
    
    namespace Utilities
    {
        public class ExcelTools
        {
            public static ImagePartType GetImagePartTypeByBitmap(Bitmap image)
            {
                if (ImageFormat.Bmp.Equals(image.RawFormat))
                    return ImagePartType.Bmp;
                else if (ImageFormat.Gif.Equals(image.RawFormat))
                    return ImagePartType.Gif;
                else if (ImageFormat.Png.Equals(image.RawFormat))
                    return ImagePartType.Png;
                else if (ImageFormat.Tiff.Equals(image.RawFormat))
                    return ImagePartType.Tiff;
                else if (ImageFormat.Icon.Equals(image.RawFormat))
                    return ImagePartType.Icon;
                else if (ImageFormat.Jpeg.Equals(image.RawFormat))
                    return ImagePartType.Jpeg;
                else if (ImageFormat.Emf.Equals(image.RawFormat))
                    return ImagePartType.Emf;
                else if (ImageFormat.Wmf.Equals(image.RawFormat))
                    return ImagePartType.Wmf;
                else
                    throw new Exception("Image type could not be determined.");
            }
    
            public static WorksheetPart GetWorksheetPartByName(SpreadsheetDocument document, string sheetName)
            {
                IEnumerable<Sheet> sheets =
                   document.WorkbookPart.Workbook.GetFirstChild<Sheets>().
                   Elements<Sheet>().Where(s => s.Name == sheetName);
    
                if (sheets.Count() == 0)
                {
                    // The specified worksheet does not exist
                    return null;
                }
    
                string relationshipId = sheets.First().Id.Value;
                return (WorksheetPart)document.WorkbookPart.GetPartById(relationshipId);
            }
    
            public static void AddImage(bool createFile, string excelFile, string sheetName,
                                        string imageFileName, string imgDesc,
                                        int colNumber, int rowNumber)
            {
                using (var imageStream = new FileStream(imageFileName, FileMode.Open))
                {
                    AddImage(createFile, excelFile, sheetName, imageStream, imgDesc, colNumber, rowNumber);
                }
            }
    
            public static void AddImage(WorksheetPart worksheetPart,
                                        string imageFileName, string imgDesc,
                                        int colNumber, int rowNumber)
            {
                using (var imageStream = new FileStream(imageFileName, FileMode.Open))
                {
                    AddImage(worksheetPart, imageStream, imgDesc, colNumber, rowNumber);
                }
            }
    
            public static void AddImage(bool createFile, string excelFile, string sheetName,
                                        Stream imageStream, string imgDesc,
                                        int colNumber, int rowNumber)
            {
                SpreadsheetDocument spreadsheetDocument = null;
                WorksheetPart worksheetPart = null;
                if (createFile)
                {
                    // Create a spreadsheet document by supplying the filepath
                    spreadsheetDocument = SpreadsheetDocument.Create(excelFile, SpreadsheetDocumentType.Workbook);
    
                    // Add a WorkbookPart to the document
                    WorkbookPart workbookpart = spreadsheetDocument.AddWorkbookPart();
                    workbookpart.Workbook = new Workbook();
    
                    // Add a WorksheetPart to the WorkbookPart
                    worksheetPart = workbookpart.AddNewPart<WorksheetPart>();
                    worksheetPart.Worksheet = new Worksheet(new SheetData());
    
                    // Add Sheets to the Workbook
                    Sheets sheets = spreadsheetDocument.WorkbookPart.Workbook.
                        AppendChild<Sheets>(new Sheets());
    
                    // Append a new worksheet and associate it with the workbook
                    Sheet sheet = new Sheet()
                    {
                        Id = spreadsheetDocument.WorkbookPart.GetIdOfPart(worksheetPart),
                        SheetId = 1,
                        Name = sheetName
                    };
                    sheets.Append(sheet);
                }
                else
                {
                    // Open spreadsheet
                    spreadsheetDocument = SpreadsheetDocument.Open(excelFile, true);
    
                    // Get WorksheetPart
                    worksheetPart = GetWorksheetPartByName(spreadsheetDocument, sheetName);
                }
    
                AddImage(worksheetPart, imageStream, imgDesc, colNumber, rowNumber);
    
                worksheetPart.Worksheet.Save();
    
                spreadsheetDocument.Close();
            }
    
            public static void AddImage(WorksheetPart worksheetPart,
                                        Stream imageStream, string imgDesc,
                                        int colNumber, int rowNumber)
            {
                // We need the image stream more than once, thus we create a memory copy
                MemoryStream imageMemStream = new MemoryStream();
                imageStream.Position = 0;
                imageStream.CopyTo(imageMemStream);
                imageStream.Position = 0;
    
                var drawingsPart = worksheetPart.DrawingsPart;
                if (drawingsPart == null)
                    drawingsPart = worksheetPart.AddNewPart<DrawingsPart>();
    
                if (!worksheetPart.Worksheet.ChildElements.OfType<Drawing>().Any())
                {
                    worksheetPart.Worksheet.Append(new Drawing { Id = worksheetPart.GetIdOfPart(drawingsPart) });
                }
    
                if (drawingsPart.WorksheetDrawing == null)
                {
                    drawingsPart.WorksheetDrawing = new Xdr.WorksheetDrawing();
                }
    
                var worksheetDrawing = drawingsPart.WorksheetDrawing;
    
                Bitmap bm = new Bitmap(imageMemStream);
                var imagePart = drawingsPart.AddImagePart(GetImagePartTypeByBitmap(bm));
                imagePart.FeedData(imageStream);
    
                A.Extents extents = new A.Extents();
                var extentsCx = bm.Width * (long)(914400 / bm.HorizontalResolution);
                var extentsCy = bm.Height * (long)(914400 / bm.VerticalResolution);
                bm.Dispose();
    
                var colOffset = 0;
                var rowOffset = 0;
    
                var nvps = worksheetDrawing.Descendants<Xdr.NonVisualDrawingProperties>();
                var nvpId = nvps.Count() > 0
                    ? (UInt32Value)worksheetDrawing.Descendants<Xdr.NonVisualDrawingProperties>().Max(p => p.Id.Value) + 1
                    : 1U;
    
                var oneCellAnchor = new Xdr.OneCellAnchor(
                    new Xdr.FromMarker
                    {
                        ColumnId = new Xdr.ColumnId((colNumber - 1).ToString()),
                        RowId = new Xdr.RowId((rowNumber - 1).ToString()),
                        ColumnOffset = new Xdr.ColumnOffset(colOffset.ToString()),
                        RowOffset = new Xdr.RowOffset(rowOffset.ToString())
                    },
                    new Xdr.Extent { Cx = extentsCx, Cy = extentsCy },
                    new Xdr.Picture(
                        new Xdr.NonVisualPictureProperties(
                            new Xdr.NonVisualDrawingProperties { Id = nvpId, Name = "Picture " + nvpId, Description = imgDesc },
                            new Xdr.NonVisualPictureDrawingProperties(new A.PictureLocks { NoChangeAspect = true })
                        ),
                        new Xdr.BlipFill(
                            new A.Blip { Embed = drawingsPart.GetIdOfPart(imagePart), CompressionState = A.BlipCompressionValues.Print },
                            new A.Stretch(new A.FillRectangle())
                        ),
                        new Xdr.ShapeProperties(
                            new A.Transform2D(
                                new A.Offset { X = 0, Y = 0 },
                                new A.Extents { Cx = extentsCx, Cy = extentsCy }
                            ),
                            new A.PresetGeometry { Preset = A.ShapeTypeValues.Rectangle }
                        )
                    ),
                    new Xdr.ClientData()
                );
    
                worksheetDrawing.Append(oneCellAnchor);
            }
        }
    }
    

    【讨论】:

    • 我认为重要的是要注意你在这里甚至使用 System.Drawing..
    • 对不起,我不明白你的意思。使用 System.Drawing 有什么意义?
    • 我是在 .NET Core 中完成的,我必须添加 System.Drawing.Common nuget 包才能拥有 System.Drawing 库
    • 啊,现在我明白了。可以通过手动提供图像的类型、高度和宽度来避免 System.Drawing。这是必须重写的代码: Bitmap bm = new Bitmap(imageMemStream); var imagePart = drawingPart.AddImagePart(GetImagePartTypeByBitmap(bm)); imagePart.FeedData(imageStream); A.Extents 范围 = new A.Extents(); var extentsCx = bm.Width * (long)(914400 / bm.Horizo​​ntalResolution); var extentsCy = bm.Height * (long)(914400 / bm.VerticalResolution); bm.Dispose();
    • GetImagePartTypeByBitmap(Bitmap image) 可以去掉。
    【解决方案2】:

    我在博客文章中写了一些关于此的内容: http://polymathprogrammer.com/2009/12/21/advanced-styling-in-excel-open-xml/

    请注意,它最初是为 Open XML SDK 2.0 CTP 版本编写的,因此请注意从 NumberFormat 类到 NumberingFormat 类的更改(当 SDK 2.0 最终确定时)

    如果您想将代码隔离为仅图像插入,请查看此处: http://polymathprogrammer.com/2009/11/30/how-to-insert-an-image-in-excel-open-xml/

    【讨论】:

    • 以上链接失效
    【解决方案3】:

    这是一个 link 到一个 MSDN 示例,您可以下载代码。

    还有Eric White's example and You Tube video

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多