自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中的列Col1
tableFormatterBuilder.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 #endregion string 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学员d
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 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篇-模板导出综合示例)的更多相关文章

  1. 分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility (续3篇-导出时动态生成多Sheet EXCEL)

    ExcelUtility 类库经过我(梦在旅途)近期不断的优化与新增功能,现已基本趋向稳定,功能上也基本可以满足绝大部份的EXCEL导出需求,该类库已在我们公司大型ERP系统全面使用,效果不错,今天应 ...

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

    上周六我发表的文章<分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility>受到了大家的热烈支持与推荐,再此表示感谢,该ExcelUtility ...

  3. 分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility

    1. ExcelUtility功能:  1.将数据导出到EXCEL(支持XLS,XLSX,支持多种类型模板,支持列宽自适应)  类名:ExcelUtility. Export  2.将EXCEL ...

  4. 【EXCEL终极总结分享】基于NPOI扩展封装的简易操作工具类库(简单灵活易用,支持导出、导入、上传等常见操作)

    对于EXCEL的导入.导出,我之前已分享过多次,比如: 第一种方案:<我写的一个ExcelHelper通用类,可用于读取或生成数据>这个主要是利用把EXCEL当成一个DB来进行获取数据,导 ...

  5. NPOI+ExcelReport

    分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUtility (续2篇-模板导出综合示例)   自ExcelUtility类推出以来,经过项目中的实际使用与不断完 ...

  6. .net mvc利用NPOI导入导出excel

    1.导出Excel :首先引用NPOI包(Action一定要用FileResult) /// <summary> /// 批量导出需要导出的列表 /// </summary> ...

  7. NPOI导入导出Excel

    .net mvc利用NPOI导入导出excel 注意:如何导出的提交方式ajax导出是失效的! 解决方案是:js处理l两个表单的提交  代码:  第一步. 在页面里面加入2个隐藏的iframe, 如下 ...

  8. net mvc 利用NPOI导入导出excel

    1.导出Excel : 首先引用NPOI包(Action一定要用FileResult) /// <summary> /// 批量导出需要导出的列表 /// </summary> ...

  9. .NET导入导出Excel方法总结

    最近,应项目的需求,需要实现Excel的导入导出功能,对于Web架构的Excel导入导出功能,比较传统的实现方式是: 1)导入Excel:将Excel文件上传到服务器的某一文件夹下,然后在服务端完成E ...

随机推荐

  1. Opencv算法学习二

    1.直方图:图片中像素值分布情况的坐标图. 直方图均衡化:按一定规律拉伸像素值,提高像素值少的点,增加原图的对比度,使人感觉更清晰的函数. equalizeHist( src, dst ); 2.ha ...

  2. Microsoft开源跨平台的序列化库——Bond

    上个月Microsoft开源了Bond,一个跨平台的模式化数据处理框架.Bond支持跨语言的序列化/反序列化,支持强大的泛型机制能够对数据进行有效地处理.该框架在Microsoft公司内部的高扩展服务 ...

  3. mono 3.10.0 正式发布:性能进一步改进

    Mono是Xamarin资助的一个项目,是微软的.NET框架的开源实现.它使得使用C#.F#和其他.NET语言进行跨平台开发成为可能.Xamarin在Mono之上构建了跨平台开发工具以及像Xamari ...

  4. 安卓动态调试七种武器之离别钩 – Hooking(下)

    0x00 序 随着移动安全越来越火,各种调试工具也都层出不穷,但因为环境和需求的不同,并没有工具是万能的.另外工具是死的,人是活的,如果能搞懂工具的原理再结合上自身的经验,你也可以创造出属于自己的调试 ...

  5. 备忘-Android ViewPager 子页监听事件

    @Override public Object instantiateItem(View arg0, int arg1) { ((ViewPager) arg0).addView(mListViews ...

  6. PHP的pcntl多进程

    PHP使用PCNTL系列的函数也能做到多进程处理一个事务.比如我需要从数据库中获取80w条的数据,再做一系列后续的处理,这个时候,用单进程?你可以等到明年今天了...所以应该使用pcntl函数了. 假 ...

  7. Lua table之弱引用

    Lua采用了基于垃圾收集的内存管理机制,因此对于程序员来说,在很多时候内存问题都将不再困扰他们.然而任何垃圾收集器都不是万能的,在有些特殊情况下,垃圾收集器是无法准确的判断是否应该将当前对象清理.这样 ...

  8. Atitit图像处理的用途

    Atitit图像处理的用途 1.1. 分类识别 (人脸检测,肤色识别,人类检测:1 1.2. 炫丽的动态按钮生成:色相旋转+自己的草书等图片合成,图片自动裁剪1 1.3. 集成调用自绘gui接口:识别 ...

  9. Excel 导入到Datatable 中,再使用常规方法写入数据库

    首先呢?要看你的电脑的office版本,我的是office 2013 .为了使用oledb程序,需要安装一个引擎.名字为AccessDatabaseEngine.exe.这里不过多介绍了哦.它的数据库 ...

  10. 轻量级前端MVVM框架avalon - 控制器

    引子: 最近工作挺忙,avalon只能断断续续的写下去了,大概看了下angular的源码,看到小一半就比较难坚持了,是块硬骨头,慢慢啃吧 不过angular的的文档中用词还是很优雅: HTML编译器 ...