自ExcelUtility类推出以来,经过项目中的实际使用与不断完善,现在又做了许多的优化并增加了许多的功能,本篇不再讲述原理,直接贴出示例代码以及相关的模板、结果图,以便大家快速掌握,另外这些示例说明我也已同步到GIT中,大家可以下载与学习,不足之处,敬请见谅,谢谢!

一、ExcelUtility类库操作说明(模板导出示例)

1.

        /// <summary>/// 测试方法:测试依据模板+DataTable来生成EXCEL/// </summary>[TestMethod]public void TestExportToExcelWithTemplateByDataTable(){DataTable dt = GetDataTable();//获取数据string templateFilePath = AppDomain.CurrentDomain.BaseDirectory + "/excel.xlsx"; //获得EXCEL模板路径SheetFormatterContainer formatterContainers = new SheetFormatterContainer(); //实例化一个模板数据格式化容器PartFormatterBuilder partFormatterBuilder = new PartFormatterBuilder();//实例化一个局部元素格式化器partFormatterBuilder.AddFormatter("Title", "跨越IT学员");//将模板表格中Title的值设置为跨越IT学员formatterContainers.AppendFormatterBuilder(partFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效CellFormatterBuilder cellFormatterBuilder = new CellFormatterBuilder();//实例化一个单元格格式化器cellFormatterBuilder.AddFormatter("rptdate", DateTime.Today.ToString("yyyy-MM-dd HH:mm"));//将模板表格中rptdate的值设置为当前日期formatterContainers.AppendFormatterBuilder(cellFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效//实例化一个表格格式化器,dt.Select()是将DataTable转换成DataRow[],name表示的模板表格中第一行第一个单元格要填充的数据参数名TableFormatterBuilder<DataRow> tableFormatterBuilder = new TableFormatterBuilder<DataRow>(dt.Select(), "name");tableFormatterBuilder.AddFormatters(new Dictionary<string, Func<DataRow, object>>{{"name",r=>r["Col1"]},//将模板表格中name对应DataTable中的列Col1{"sex",r=>r["Col2"]},//将模板表格中sex对应DataTable中的列Col2{"km",r=>r["Col3"]},//将模板表格中km对应DataTable中的列Col3{"score",r=>r["Col4"]},//将模板表格中score对应DataTable中的列Col4{"result",r=>r["Col5"]}//将模板表格中result对应DataTable中的列Co5});formatterContainers.AppendFormatterBuilder(tableFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效string excelPath = ExcelUtility.Export.ToExcelWithTemplate(templateFilePath, "table", formatterContainers);Assert.IsTrue(File.Exists(excelPath));}

模板如下:

导出结果如下:

2.

        /// <summary>/// 测试方法:测试依据模板+List来生成EXCEL/// </summary>[TestMethod]public void TestExportToExcelWithTemplateByList(){List<Student> studentList = GetStudentList();//获取数据string templateFilePath = AppDomain.CurrentDomain.BaseDirectory + "/excel.xlsx"; //获得EXCEL模板路径SheetFormatterContainer formatterContainers = new SheetFormatterContainer(); //实例化一个模板数据格式化容器PartFormatterBuilder partFormatterBuilder = new PartFormatterBuilder();//实例化一个局部元素格式化器partFormatterBuilder.AddFormatter("Title", "跨越IT学员");//将模板表格中Title的值设置为跨越IT学员formatterContainers.AppendFormatterBuilder(partFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效CellFormatterBuilder cellFormatterBuilder = new CellFormatterBuilder();//实例化一个单元格格式化器cellFormatterBuilder.AddFormatter("rptdate", DateTime.Today.ToString("yyyy-MM-dd HH:mm"));//将模板表格中rptdate的值设置为当前日期formatterContainers.AppendFormatterBuilder(cellFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效//实例化一个表格格式化器,studentList本身就是可枚举的无需转换,name表示的模板表格中第一行第一个单元格要填充的数据参数名TableFormatterBuilder<Student> tableFormatterBuilder = new TableFormatterBuilder<Student>(studentList, "name");tableFormatterBuilder.AddFormatters(new Dictionary<string, Func<Student, object>>{{"name",r=>r.Name},//将模板表格中name对应Student对象中的属性Name{"sex",r=>r.Sex},//将模板表格中sex对应Student对象中的属性Sex{"km",r=>r.KM},//将模板表格中km对应Student对象中的属性KM{"score",r=>r.Score},//将模板表格中score对应Student对象中的属性Score{"result",r=>r.Result}//将模板表格中result对应Student对象中的属性Result});formatterContainers.AppendFormatterBuilder(tableFormatterBuilder);string excelPath = ExcelUtility.Export.ToExcelWithTemplate(templateFilePath, "table", formatterContainers);Assert.IsTrue(File.Exists(excelPath));}

模板同上一个模板

导出结果如下:

3.

        /// <summary>/// 测试方法:测试依据模板+DataTable来生成多表格EXCEL(注意:由于ExcelReport框架限制,目前仅支持模板文件格式为:xls)/// </summary>[TestMethod]public void TestExportToRepeaterExcelWithTemplateByDataTable(){DataTable dt = GetDataTable();//获取数据string templateFilePath = AppDomain.CurrentDomain.BaseDirectory + "/excel2.xls"; //获得EXCEL模板路径SheetFormatterContainer formatterContainers = new SheetFormatterContainer(); //实例化一个模板数据格式化容器//实例化一个可重复表格格式化器,dt.Select()是将DataTable转换成DataRow[],rpt_begin表示的模板表格开始位置参数名,rpt_end表示的模板表格结束位置参数名RepeaterFormatterBuilder<DataRow> tableFormatterBuilder = new RepeaterFormatterBuilder<DataRow>(dt.Select(), "rpt_begin", "rpt_end");tableFormatterBuilder.AddFormatters(new Dictionary<string, Func<DataRow, object>>{{"sex",r=>r["Col2"]},//将模板表格中sex对应DataTable中的列Col2{"km",r=>r["Col3"]},//将模板表格中km对应DataTable中的列Col3{"score",r=>r["Col4"]},//将模板表格中score对应DataTable中的列Col4{"result",r=>r["Col5"]}//将模板表格中result对应DataTable中的列Co5});PartFormatterBuilder<DataRow> partFormatterBuilder2 = new PartFormatterBuilder<DataRow>();//实例化一个可嵌套的局部元素格式化器partFormatterBuilder2.AddFormatter("name", r => r["Col1"]);//将模板表格中name对应DataTable中的列Col1tableFormatterBuilder.AppendFormatterBuilder(partFormatterBuilder2);//添加到可重复表格格式化器中,作为其子格式化器CellFormatterBuilder<DataRow> cellFormatterBuilder = new CellFormatterBuilder<DataRow>();//实例化一个可嵌套的单元格格式化器cellFormatterBuilder.AddFormatter("rptdate", r => DateTime.Today.ToString("yyyy-MM-dd HH:mm"));//将模板表格中rptdate的值设置为当前日期tableFormatterBuilder.AppendFormatterBuilder(cellFormatterBuilder);//添加到可重复表格格式化器中,作为其子格式化器formatterContainers.AppendFormatterBuilder(tableFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效string excelPath = ExcelUtility.Export.ToExcelWithTemplate(templateFilePath, "multtable", formatterContainers);Assert.IsTrue(File.Exists(excelPath));}

模板如下:

导出结果如下:

4.

        /// <summary>/// 测试方法:测试依据复杂模板(含固定表格,可重复表格)+DataTable来生成EXCEL (注意:由于ExcelReport框架限制,目前仅支持模板文件格式为:xls)/// </summary>[TestMethod]public void TestExportToExcelWithTemplateByList2(){var schoolLevelList = SchoolLevel.GetList();var classList = ClassInfo.GetList();string templateFilePath = AppDomain.CurrentDomain.BaseDirectory + "/mb.xls"; //获得EXCEL模板路径SheetFormatterContainer formatterContainers = new SheetFormatterContainer(); //实例化一个模板数据格式化容器PartFormatterBuilder partFormatterBuilder = new PartFormatterBuilder();partFormatterBuilder.AddFormatter("school", "跨越小学");formatterContainers.AppendFormatterBuilder(partFormatterBuilder);TableFormatterBuilder<SchoolLevel> tableFormatterBuilder = new TableFormatterBuilder<SchoolLevel>(schoolLevelList, "lv");//实例化一个表格格式化器tableFormatterBuilder.AddFormatters(new Dictionary<string, Func<SchoolLevel, object>>{{"lv",r=>r.LevelName}, //模板参数与数据源SchoolLevel属性对应关系,下同{"clscount",r=>r.ClassCount},{"lvmaster",r=>r.Master}});formatterContainers.AppendFormatterBuilder(tableFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效RepeaterFormatterBuilder<ClassInfo> repeaterFormatterBuilder = new RepeaterFormatterBuilder<ClassInfo>(classList, "lv_begin", "lv_end");//实例化一个可重复表格格式化器repeaterFormatterBuilder.AddFormatters(new Dictionary<string, Func<ClassInfo, object>> { {"class",r=>r.ClassName}, //模板参数与数据源ClassInfo属性对应关系,下同{"stucount",r=>r.StudentCount},{"clsmaster",r=>r.Master},{"lvitem",r=>r.LevelName}});formatterContainers.AppendFormatterBuilder(repeaterFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效string excelPath = ExcelUtility.Export.ToExcelWithTemplate(templateFilePath, "school", formatterContainers);Assert.IsTrue(File.Exists(excelPath));}

模板如下:

导出结果如下:

5.

        /// <summary>/// 测试方法:测试依据复杂模板(含固定表格,可重复表格中嵌套表格)+DataTable来生成EXCEL (注意:由于ExcelReport框架限制,目前仅支持模板文件格式为:xls)/// </summary>[TestMethod]public void TestExportToExcelWithTemplateByList3(){var schoolLevelList = SchoolLevel.GetList();var classList = ClassInfo.GetListWithLevels();string templateFilePath = AppDomain.CurrentDomain.BaseDirectory + "/mb1.xls"; //获得EXCEL模板路径SheetFormatterContainer formatterContainers = new SheetFormatterContainer(); //实例化一个模板数据格式化容器PartFormatterBuilder partFormatterBuilder = new PartFormatterBuilder();partFormatterBuilder.AddFormatter("school", "跨越小学");formatterContainers.AppendFormatterBuilder(partFormatterBuilder);TableFormatterBuilder<SchoolLevel> tableFormatterBuilder = new TableFormatterBuilder<SchoolLevel>(schoolLevelList, "lv");//实例化一个表格格式化器tableFormatterBuilder.AddFormatters(new Dictionary<string, Func<SchoolLevel, object>>{{"lv",r=>r.LevelName}, //模板参数与数据源SchoolLevel属性对应关系,下同{"clscount",r=>r.ClassCount},{"lvmaster",r=>r.Master}});formatterContainers.AppendFormatterBuilder(tableFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效RepeaterFormatterBuilder<KeyValuePair<string, List<ClassInfo>>> repeaterFormatterBuilder = new RepeaterFormatterBuilder<KeyValuePair<string, List<ClassInfo>>>(classList, "lv_begin", "lv_end");repeaterFormatterBuilder.AddFormatter("lvitem",r=>r.Key);TableFormatterBuilder<KeyValuePair<string, List<ClassInfo>>,ClassInfo> tableFormatterBuilder2=new TableFormatterBuilder<KeyValuePair<string, List<ClassInfo>>,ClassInfo>(r=>r.Value,"class");tableFormatterBuilder2.AddFormatter("class",r=>r.ClassName);tableFormatterBuilder2.AddFormatter("stucount",r=>r.StudentCount);tableFormatterBuilder2.AddFormatter("clsmaster",r=>r.Master);repeaterFormatterBuilder.AppendFormatterBuilder(tableFormatterBuilder2);formatterContainers.AppendFormatterBuilder(repeaterFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效string excelPath = ExcelUtility.Export.ToExcelWithTemplate(templateFilePath, "school", formatterContainers);Assert.IsTrue(File.Exists(excelPath));}

模板如下:

导出结果如下:

6.

        /// <summary>/// 测试方法:测试依据复杂模板(多工作薄,且含固定表格,可重复表格)+DataSet来生成EXCEL,只支持XLS/// </summary>[TestMethod]public void TestExportToExcelWithTemplateByDataSet(){var ds = GetDataSet();string templateFilePath = AppDomain.CurrentDomain.BaseDirectory + "/mb2.xls"; //获得EXCEL模板路径Dictionary<string, SheetFormatterContainer> formatterContainerDic = new Dictionary<string, SheetFormatterContainer>(); //实例化一个模板数据格式化容器数组,包含两个SheetFormatterContainer用于格式化两个工作薄#region 创建第一个工作薄格式化容器,并设置相关参数对应关系SheetFormatterContainer formatterContainer1 = new SheetFormatterContainer();PartFormatterBuilder partFormatterBuilder = new PartFormatterBuilder();partFormatterBuilder.AddFormatter("school", "跨越小学");formatterContainer1.AppendFormatterBuilder(partFormatterBuilder);TableFormatterBuilder<DataRow> tableFormatterBuilder = new TableFormatterBuilder<DataRow>(ds.Tables[0].Select(), "lv");//实例化一个表格格式化器tableFormatterBuilder.AddFormatters(new Dictionary<string, Func<DataRow, object>>{{"lv",r=>r["Col1"]}, //模板参数与数据源DataTable属性对应关系,下同{"clscount",r=>r["Col2"]},{"lvmaster",r=>r["Col3"]}});formatterContainer1.AppendFormatterBuilder(tableFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效RepeaterFormatterBuilder<DataRow> repeaterFormatterBuilder = new RepeaterFormatterBuilder<DataRow>(ds.Tables[1].Select(), "lv_begin", "lv_end");//实例化一个可重复表格格式化器repeaterFormatterBuilder.AddFormatters(new Dictionary<string, Func<DataRow, object>> { {"class",r=>r["Col1"]}, //模板参数与数据源ClassInfo属性对应关系,下同{"stucount",r=>r["Col2"]},{"clsmaster",r=>r["Col3"]},{"lvitem",r=>r["Col4"]}});formatterContainer1.AppendFormatterBuilder(repeaterFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效formatterContainerDic.Add("table1", formatterContainer1);//添加到工作薄格式容器数组中,注意此处的Key值为模板上工作薄的名称,此处即为:table1#endregion#region 创建第二个工作薄格式化容器,并设置相关参数对应关系SheetFormatterContainer formatterContainer2 = new SheetFormatterContainer(); //实例化一个模板数据格式化容器PartFormatterBuilder partFormatterBuilder2 = new PartFormatterBuilder();//实例化一个局部元素格式化器partFormatterBuilder2.AddFormatter("Title", "跨越IT学员");//将模板表格中Title的值设置为跨越IT学员formatterContainer2.AppendFormatterBuilder(partFormatterBuilder2);//添加到工作薄格式容器中,注意只有添加进去了才会生效CellFormatterBuilder cellFormatterBuilder2 = new CellFormatterBuilder();//实例化一个单元格格式化器cellFormatterBuilder2.AddFormatter("rptdate", DateTime.Today.ToString("yyyy-MM-dd HH:mm"));//将模板表格中rptdate的值设置为当前日期formatterContainer2.AppendFormatterBuilder(cellFormatterBuilder2);//添加到工作薄格式容器中,注意只有添加进去了才会生效//实例化一个表格格式化器,dt.Select()是将DataTable转换成DataRow[],name表示的模板表格中第一行第一个单元格要填充的数据参数名TableFormatterBuilder<DataRow> tableFormatterBuilder2 = new TableFormatterBuilder<DataRow>(ds.Tables[2].Select(), "name");tableFormatterBuilder2.AddFormatters(new Dictionary<string, Func<DataRow, object>>{{"name",r=>r["Col1"]},//将模板表格中name对应DataTable中的列Col1{"sex",r=>r["Col2"]},//将模板表格中sex对应DataTable中的列Col2{"km",r=>r["Col3"]},//将模板表格中km对应DataTable中的列Col3{"score",r=>r["Col4"]},//将模板表格中score对应DataTable中的列Col4{"result",r=>r["Col5"]}//将模板表格中result对应DataTable中的列Co5});formatterContainer2.AppendFormatterBuilder(tableFormatterBuilder2);//添加到工作薄格式容器中,注意只有添加进去了才会生效formatterContainerDic.Add("table2", formatterContainer2);//添加到工作薄格式容器数组中,注意此处的Key值为模板上工作薄的名称,此处即为:table2#endregionstring excelPath = ExcelUtility.Export.ToExcelWithTemplate(templateFilePath, formatterContainerDic);Assert.IsTrue(File.Exists(excelPath));}

模板如下:

    

导出结果如下:

   

二、ExcelUtility类库操作说明(嵌入图片示例)

一、 制作模板(含图片)
1. 制作模板的文件格式需为兼容格式,即:xls或xlt;
2. 模板变量(或称为占位符)定义与之前相同,即:$[变量名];
3. 图片变量定义如下:
a) 绘制一个图形,图形形状尽可能的与要显示的图片相同,比如:印章,则可绘制一个圆形;
b) 图形必需是透明背景,边框可要可不要,建议留着,这样后续调整比较方便,如下图中的蓝色透明背景圆形:

c) 图形大小尽可能与要显示的图片大小相同,如下图示:

由于EXCEL上大小默认采用厘米,而图片一般采用像素,所以需要自己换算一下像素对应的厘米数(也可将EXCEL计算单位设为像素,方法自行网上查找);也可网上下载单位转换工具
另外图形属性建议设置成如下图:

温馨提示:图形形状、属性若未设置一般不影响导出效果,但不排除其它异常情况,图形大小是一定要设置,且尽可能与要显示图形大小(高、宽)相同,否则有可能造成导出变形

代码示例:

    /// <summary>/// 测试方法:测试依据模板+DataTable+图片来生成包含图片的EXCEL,只支持XLS/// </summary>[TestMethod]public void TestInsertPic(){DataTable dt = GetDataTable();//获取数据string templateFilePath = AppDomain.CurrentDomain.BaseDirectory + "/excel.xls"; //获得EXCEL模板路径SheetFormatterContainer formatterContainers = new SheetFormatterContainer(); //实例化一个模板数据格式化容器PartFormatterBuilder partFormatterBuilder = new PartFormatterBuilder();//实例化一个局部元素格式化器partFormatterBuilder.AddFormatter("Title", "跨越IT学员");//将模板表格中Title的值设置为跨越IT学员dformatterContainers.AppendFormatterBuilder(partFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效CellFormatterBuilder cellFormatterBuilder = new CellFormatterBuilder();//实例化一个单元格格式化器cellFormatterBuilder.AddFormatter("rptdate", DateTime.Today.ToString("yyyy-MM-dd HH:mm"));//将模板表格中rptdate的值设置为当前日期formatterContainers.AppendFormatterBuilder(cellFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效//实例化一个表格格式化器,dt.Select()是将DataTable转换成DataRow[],name表示的模板表格中第一行第一个单元格要填充的数据参数名TableFormatterBuilder<DataRow> tableFormatterBuilder = new TableFormatterBuilder<DataRow>(dt.Select(), "name");tableFormatterBuilder.AddFormatters(new Dictionary<string, Func<DataRow, object>>{{"name",r=>r["Col1"]},//将模板表格中name对应DataTable中的列Col1{"sex",r=>r["Col2"]},//将模板表格中sex对应DataTable中的列Col2{"km",r=>r["Col3"]},//将模板表格中km对应DataTable中的列Col3{"score",r=>r["Col4"]},//将模板表格中score对应DataTable中的列Col4{"result",r=>r["Col5"]}//将模板表格中result对应DataTable中的列Co5});formatterContainers.AppendFormatterBuilder(tableFormatterBuilder);//添加到工作薄格式容器中,注意只有添加进去了才会生效string picPath = AppDomain.CurrentDomain.BaseDirectory + "\\tz.png";//图片路径PictureWithShapeFormatterBuilder pictureBuilder = new PictureWithShapeFormatterBuilder();//实例化一个图片关联图形格式化器//pictureBuilder.AddFormatter(picPath);//当sheet中只有一个图形时,我们可以省略指定区域,那么默认就是把整个工作薄区域当成一个寻找图形区域,若sheet中包含多个,则应指定区域,替换成如下语句pictureBuilder.AddFormatter(picPath,5,60000, 0, 3, false);//第一个参数为图片路径,中间4个参数为数字型指定图形寻找的工作薄区域(行索引,列索引,索引从0开始计),最后一个为是否自适应大小,一般不建议使用,除非压缩图片formatterContainers.AppendFormatterBuilder(pictureBuilder);string excelPath = ExcelUtility.Export.ToExcelWithTemplate(templateFilePath, "table", formatterContainers);Assert.IsTrue(File.Exists(excelPath));}

模板如下:

注意图片若需要为透明背景格式,则必需使用PNG格式,NPOI支持的图片主要格式有:PNG,JPG

导出结果如下:

温馨提示:
pictureBuilder.AddFormatter(picPath);//当sheet中只有一个图形时,我们可以省略指定区域,那么默认就是把整个工作薄区域当成一个寻找图形区域,若sheet中包含多个,则应指定区域,替换成如下语句
pictureBuilder.AddFormatter(picPath,5,60000, 0, 3, false);//第一个参数为图片路径,中间4个参数为数字型指定图形寻找的工作薄区域(行索引(起止),列索引(起止),索引从0开始计),最后一个为是否自适应大小,一般不建议使用,除非压缩图片

如果图形可能随单元格进行位置调整,那么在指定图形区域时需注意,如果图形会随单元格下移,那么结束行索引(MinRow)就需要指定一个可能的最大值或不指定,如果图形会随单元格右移,那么结束列索引(MinColumn)就需要指定一个可能的最大值或不指定,如果存在多个图形区域,则上述情况都必需给定具体值(可能的最大值),以免造成区域交叉,从而导致图片显示不正确,如下示例:

//图形可能下移,可能右移,那么将结束行设为可能最大值:60000,结束列设为可能最大值:255
pictureBuilder.AddFormatter(picPath, 5, 60000, 0, 255, false);

//此处只指定开始行与开始列,与上面差不多,但建议使用上面的用法
pictureBuilder.AddFormatter(new PictureWithShapeInfo(picPath, new SheetRange() {MinRow=5,MinColumn=0 },false));

特别说明:

1.本类库是基于NPOI+ExcelReport,所有功能凡我的类库能够实现的,NPOI与ExcelReport都可以实现,只是用法及复杂程度不同而矣,我封装的目的就是为了降低大家的学习难度,提高使用效率,免费且开源,源代码同步更新至开源社区的GIT目录中,具体地址请看我该系列之前的文章有列出,在此就不再说明。

2.上述图片关联图形显示功能我是在ExcelReport基础上增加了一个PictureWithShapeFormatter类及其相关的类:PictureWithShapeInfo、SheetRange,因没有关联GIT,所以是在本地更新的,这几个类的代码如下:

PictureWithShapeFormatter:

using NPOI.Extend;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace ExcelReport
{public class PictureWithShapeFormatter : ElementFormatter{private PictureWithShapeInfo PictureInfo = null;public PictureWithShapeFormatter(PictureWithShapeInfo pictureInfo){this.PictureInfo = pictureInfo;}public override void Format(SheetAdapter sheetAdapter){var sheet = sheetAdapter.CurrentSheet;var shapes = PictureInfo.GetShapes(sheet);bool isCompatible = false;if (sheet is HSSFSheet){isCompatible = true;}if (shapes == null || shapes.Count <= 0){throw new Exception(string.Format("未能获取到工作薄[{0}]指定区域的图形对象列表!", sheet.SheetName));}byte[] bytes = System.IO.File.ReadAllBytes(PictureInfo.FilePath);int pictureIdx = -1;IDrawing drawing = null;IClientAnchor anchor = null;if (isCompatible){var shape = shapes[0] as HSSFShape;anchor = shape.Anchor as IClientAnchor;drawing = shape.Patriarch;shape.LineStyle = LineStyle.None;}else{var shape = shapes[0] as XSSFShape;anchor = shape.GetAnchor() as IClientAnchor;drawing = shape.GetDrawing();shape.LineStyle = LineStyle.None;}pictureIdx = sheet.Workbook.AddPicture(bytes, PictureInfo.PictureType);var picture = drawing.CreatePicture(anchor, pictureIdx);if (PictureInfo.AutoSize){picture.Resize();}}}
}

PictureWithShapeInfo、SheetRange:

using NPOI.SS.UserModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using NPOI.HSSF.UserModel;
using NPOI.XSSF.UserModel;
using NPOI.Extend;namespace ExcelReport
{/// <summary>/// 图片关联图形信息/// 作者:Zuowenjun/// </summary>public class PictureWithShapeInfo{private SheetRange _SheetRange = new SheetRange();public string FilePath { get; set; }public PictureType PictureType { get; set; }public SheetRange ShapeRange{get { return _SheetRange; }set{if (value != null){_SheetRange = value;}}}public bool AutoSize { get; set; }public PictureWithShapeInfo(){ }public PictureWithShapeInfo(string filePath, SheetRange shapeRange = null, bool autoSize = false){this.FilePath = filePath;this.ShapeRange = shapeRange;this.AutoSize = autoSize;this.PictureType = GetPictureType(filePath);}public List<object> GetShapes(ISheet sheet){List<object> shapeAllList = new List<object>();var shapeContainer = sheet.DrawingPatriarch;if (sheet is HSSFSheet){var shapeContainerHSSF = sheet.DrawingPatriarch as HSSFShapeContainer;if (null != shapeContainer){var shapeList = shapeContainerHSSF.Children;foreach (var shape in shapeList){if (shape is HSSFShape && shape.Anchor is HSSFClientAnchor){var anchor = shape.Anchor as HSSFClientAnchor;if (IsInternalOrIntersect(ShapeRange.MinRow, ShapeRange.MaxRow, ShapeRange.MinColumn, ShapeRange.MaxColumn, anchor.Row1, anchor.Row2, anchor.Col1, anchor.Col2, true)){shapeAllList.Add(shape);}}}}}else{var documentPartList = (sheet as XSSFSheet).GetRelations();foreach (var documentPart in documentPartList){if (documentPart is XSSFDrawing){var drawing = (XSSFDrawing)documentPart;var shapeList = drawing.GetShapes();foreach (var shape in shapeList){var anchorResult = shape.GetAnchor();if (shape is XSSFShape && anchorResult is XSSFClientAnchor){var anchor = anchorResult as XSSFClientAnchor;if (IsInternalOrIntersect(ShapeRange.MinRow, ShapeRange.MaxRow, ShapeRange.MinColumn, ShapeRange.MaxColumn, anchor.Row1, anchor.Row2, anchor.Col1, anchor.Col2, true)){shapeAllList.Add(shape);}}}}}}return shapeAllList;}private PictureType GetPictureType(string filePath){string ext = Path.GetExtension(filePath).ToUpper();switch (ext){case ".JPG": { return PictureType.JPEG; }case ".PNG": { return PictureType.PNG; }default: { return PictureType.None; }}}private bool IsInternalOrIntersect(int? rangeMinRow, int? rangeMaxRow, int? rangeMinCol, int? rangeMaxCol,int pictureMinRow, int pictureMaxRow, int pictureMinCol, int pictureMaxCol, bool onlyInternal){int _rangeMinRow = rangeMinRow ?? pictureMinRow;int _rangeMaxRow = rangeMaxRow ?? pictureMaxRow;int _rangeMinCol = rangeMinCol ?? pictureMinCol;int _rangeMaxCol = rangeMaxCol ?? pictureMaxCol;if (onlyInternal){return (_rangeMinRow <= pictureMinRow && _rangeMaxRow >= pictureMaxRow &&_rangeMinCol <= pictureMinCol && _rangeMaxCol >= pictureMaxCol);}else{return ((Math.Abs(_rangeMaxRow - _rangeMinRow) + Math.Abs(pictureMaxRow - pictureMinRow) >= Math.Abs(_rangeMaxRow + _rangeMinRow - pictureMaxRow - pictureMinRow)) &&(Math.Abs(_rangeMaxCol - _rangeMinCol) + Math.Abs(pictureMaxCol - pictureMinCol) >= Math.Abs(_rangeMaxCol + _rangeMinCol - pictureMaxCol - pictureMinCol)));}}}/// <summary>/// 工作薄区域/// 作者:Zuowenjun/// </summary>public class SheetRange{public int? MinRow { get; set; }public int? MaxRow { get; set; }public int? MinColumn { get; set; }public int? MaxColumn { get; set; }public SheetRange(){ }public SheetRange(int minRow, int maxRow, int minColumn, int maxColumn){this.MinRow = minRow;this.MaxRow = maxRow;this.MinColumn = minColumn;this.MaxColumn = maxColumn;}public override bool Equals(object obj){bool equalResult = false;equalResult = base.Equals(obj);if (!equalResult){var otherSheetRange = obj as SheetRange;if (otherSheetRange != null){equalResult = (this.MinRow <= otherSheetRange.MinRow && this.MaxRow >= otherSheetRange.MaxRow&& this.MinColumn <= otherSheetRange.MinColumn && this.MaxColumn >= otherSheetRange.MaxColumn);}}return equalResult;}public override int GetHashCode(){return this.ToString().GetHashCode();}public override string ToString(){return string.Format("MinRow:{0},MaxRow:{1},MinColumn:{2},MaxColumn:{3}", this.MinRow, this.MaxRow, this.MinColumn, this.MaxColumn);}}}

分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility 其它相关文章链接:

分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility
分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility (续篇)

分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility (续2篇-模板导出综合示例)...相关推荐

  1. Npoi html导入到excel,.net mvc 利用NPOI导入导出excel

    因近期项目做到,所以记录一下: 1.导出Excel: 首先引用NPOI包,从这里下载>download (Action一定要用FileResult) /// /// 批量导出需要导出的列表 // ...

  2. ASP.NET Core 导入导出Excel xlsx 文件

    ASP.NET Core 使用EPPlus.Core导入导出Excel xlsx 文件,EPPlus.Core支持Excel 2007/2010 xlsx文件导入导出,可以运行在Windows, Li ...

  3. Vue + Element 实现导入导出Excel

    1.首先搭建Vue 项目(具体可参考以前文章,不再详述:https://blog.csdn.net/qq_42540989/article/details/89853923) 2.引入Element( ...

  4. csv和excel php 解析_PHP 高效导入导出Excel(csv)方法之fgetcsv()和fputcsv()函数

    CSV,是Comma Separated Value(逗号分隔值)的英文缩写,通常都是纯文本文件. 一.CSV数据导入函数fgetcsv() fgetcsv() 函数从文件指针中读入一行并解析 CSV ...

  5. 使用PHPExcel实现Excel文件的导入和导出(模板导出)

    在之前有写过一篇文章讲述了使用PHP快速生成excel表格文件并下载,这种方式生成Excel文件,生成速度很快,但是有缺点是: 1.单纯的生成Excel文件,生成的文件没有样式,单元格属性(填充色,宽 ...

  6. ruoyi导入导出Excel

    导入导出excel:使用若依自带的工具ExcelUtil:(例子:SysUserController) 导入之前需要生成一个excel模板给用户填写(前端通过接口获取模板名字,再调用下载接口commo ...

  7. Spring Boot使用EasyExcel导入导出Excel

    一.导入依赖 <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</a ...

  8. EasyExcel导入导出excel 复杂表头 表头校验 数据校验

    目录 EasyExcel特点 一.导入excel案例 二.读取excel的相关技术点 1.读取excel的方式 2.读取sheet数量 3.指定从第几行开始读数据 三.导出excel 1.前端发起请求 ...

  9. java使用EasyExcel实现导入导出几种方式(导入、模板导出、和不需要模板的导出)

    java通过EasyExcel实现导入导出(导入.模板导出.和不需要模板的导出) 此文章只是涉及到简单的导入导出 通过实体模板导入数据 无实体模板导入数据 导出数据 通过模板导出数据 使用到的mave ...

最新文章

  1. 关于 top、left 结合 translate 实现居中的原理探讨
  2. PHP正则表达式规则及常用方法整理
  3. VS2015编译Boost1.64
  4. [导入]XML for Analysis(XMLA)开发详解-(3)各版本的SQL Server及Windows下配置XMLA over HTTP访问SASS(OLAP)的文档合集...
  5. 一致性代码段和非一致性代码段【转】
  6. spring中的jdk动态代理(代码步骤)
  7. CMake基础 第2节 分离编译
  8. 数据库激荡 40 年,深入解析 PostgreSQL、NewSQL 演进历程
  9. javascript 面向对象的理解、数据属性的特征,基本数据类型、三大引用类型,方法
  10. ubuntu18重启vncserver_Ubuntu 18.04 LTS安装vncserver虚拟网络控制台
  11. vs2017怎么安装python_vs2017怎么添加python
  12. 2022年湖北工业大学招生简章之高起专、专升本非全日制学历提升
  13. BCompare替代UltraCompare(UltraEdit)
  14. 图层蒙版和快速蒙版、路径
  15. Mybase7延长试用期
  16. Cocos合成大西瓜案例-下
  17. python生僻字如何转码_Python检测生僻字的实现方法
  18. mysql polygon_查找POINT是否在MySQL 5.7中的POLYGON中
  19. 7-12 谁是赢家 (10分)
  20. ubuntu20.04超简单的安装海康相机与海康sdk调试问题

热门文章

  1. python增删改查的框架_python的Web框架,Django的ORM,模型基础,MySQL连接配置及增删改查...
  2. 3D中OBJ文件格式详解
  3. Handler为什么可能会造成内存泄漏以及可用的四种解决方法
  4. linux视频学习6(mysql的安装/)
  5. CSS盒子模型之CSS3可伸缩框属性(Flexible Box)
  6. Tesorflow源代码安装方式以及错误的解决方法
  7. 解决HttpServletRequest的输入流只能读取一次的问题(转)
  8. Java多线程引发的性能问题,怎么解决?
  9. stale element reference: element is not attached to the page document 异常
  10. Eclipse中创建SpringBoot项目流程,及报错解决方案