分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility (续2篇-模板导出综合示例)...
自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 (续2篇-模板导出综合示例)...相关推荐
- Npoi html导入到excel,.net mvc 利用NPOI导入导出excel
因近期项目做到,所以记录一下: 1.导出Excel: 首先引用NPOI包,从这里下载>download (Action一定要用FileResult) /// /// 批量导出需要导出的列表 // ...
- ASP.NET Core 导入导出Excel xlsx 文件
ASP.NET Core 使用EPPlus.Core导入导出Excel xlsx 文件,EPPlus.Core支持Excel 2007/2010 xlsx文件导入导出,可以运行在Windows, Li ...
- Vue + Element 实现导入导出Excel
1.首先搭建Vue 项目(具体可参考以前文章,不再详述:https://blog.csdn.net/qq_42540989/article/details/89853923) 2.引入Element( ...
- csv和excel php 解析_PHP 高效导入导出Excel(csv)方法之fgetcsv()和fputcsv()函数
CSV,是Comma Separated Value(逗号分隔值)的英文缩写,通常都是纯文本文件. 一.CSV数据导入函数fgetcsv() fgetcsv() 函数从文件指针中读入一行并解析 CSV ...
- 使用PHPExcel实现Excel文件的导入和导出(模板导出)
在之前有写过一篇文章讲述了使用PHP快速生成excel表格文件并下载,这种方式生成Excel文件,生成速度很快,但是有缺点是: 1.单纯的生成Excel文件,生成的文件没有样式,单元格属性(填充色,宽 ...
- ruoyi导入导出Excel
导入导出excel:使用若依自带的工具ExcelUtil:(例子:SysUserController) 导入之前需要生成一个excel模板给用户填写(前端通过接口获取模板名字,再调用下载接口commo ...
- Spring Boot使用EasyExcel导入导出Excel
一.导入依赖 <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</a ...
- EasyExcel导入导出excel 复杂表头 表头校验 数据校验
目录 EasyExcel特点 一.导入excel案例 二.读取excel的相关技术点 1.读取excel的方式 2.读取sheet数量 3.指定从第几行开始读数据 三.导出excel 1.前端发起请求 ...
- java使用EasyExcel实现导入导出几种方式(导入、模板导出、和不需要模板的导出)
java通过EasyExcel实现导入导出(导入.模板导出.和不需要模板的导出) 此文章只是涉及到简单的导入导出 通过实体模板导入数据 无实体模板导入数据 导出数据 通过模板导出数据 使用到的mave ...
最新文章
- 关于 top、left 结合 translate 实现居中的原理探讨
- PHP正则表达式规则及常用方法整理
- VS2015编译Boost1.64
- [导入]XML for Analysis(XMLA)开发详解-(3)各版本的SQL Server及Windows下配置XMLA over HTTP访问SASS(OLAP)的文档合集...
- 一致性代码段和非一致性代码段【转】
- spring中的jdk动态代理(代码步骤)
- CMake基础 第2节 分离编译
- 数据库激荡 40 年,深入解析 PostgreSQL、NewSQL 演进历程
- javascript 面向对象的理解、数据属性的特征,基本数据类型、三大引用类型,方法
- ubuntu18重启vncserver_Ubuntu 18.04 LTS安装vncserver虚拟网络控制台
- vs2017怎么安装python_vs2017怎么添加python
- 2022年湖北工业大学招生简章之高起专、专升本非全日制学历提升
- BCompare替代UltraCompare(UltraEdit)
- 图层蒙版和快速蒙版、路径
- Mybase7延长试用期
- Cocos合成大西瓜案例-下
- python生僻字如何转码_Python检测生僻字的实现方法
- mysql polygon_查找POINT是否在MySQL 5.7中的POLYGON中
- 7-12 谁是赢家 (10分)
- ubuntu20.04超简单的安装海康相机与海康sdk调试问题
热门文章
- python增删改查的框架_python的Web框架,Django的ORM,模型基础,MySQL连接配置及增删改查...
- 3D中OBJ文件格式详解
- Handler为什么可能会造成内存泄漏以及可用的四种解决方法
- linux视频学习6(mysql的安装/)
- CSS盒子模型之CSS3可伸缩框属性(Flexible Box)
- Tesorflow源代码安装方式以及错误的解决方法
- 解决HttpServletRequest的输入流只能读取一次的问题(转)
- Java多线程引发的性能问题,怎么解决?
- stale element reference: element is not attached to the page document 异常
- Eclipse中创建SpringBoot项目流程,及报错解决方案