Rumah php教程 php手册 分享我基于NPOI+ExcelReport实现的导入与导出EXCEL类库:ExcelUt

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

Jul 06, 2016 pm 01:30 PM
kongsi berdasarkan capai import

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

自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));
        }
Salin selepas log masuk

模板如下:

导出结果如下:

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));

        }
Salin selepas log masuk

模板同上一个模板

导出结果如下:

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));
        }
Salin selepas log masuk

模板如下:

导出结果如下:

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));

        }
Salin selepas log masuk

模板如下:

导出结果如下:

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));

        }
Salin selepas log masuk

模板如下:

导出结果如下:

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));

        }
Salin selepas log masuk

模板如下:

导出结果如下:

二、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));
        }
Salin selepas log masuk

模板如下:

注意图片若需要为透明背景格式,则必需使用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();
            }
        }


    }
}
Salin selepas log masuk

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);
        }

    }

}
Salin selepas log masuk

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

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

 

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

 


Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

Video Face Swap

Video Face Swap

Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Bagaimana untuk berkongsi Quark Netdisk ke Baidu Netdisk? Bagaimana untuk berkongsi Quark Netdisk ke Baidu Netdisk? Mar 14, 2024 pm 04:40 PM

Quark Netdisk dan Baidu Netdisk adalah kedua-dua alat storan yang sangat mudah Ramai pengguna bertanya sama ada kedua-dua perisian ini boleh dikendalikan? Bagaimana untuk berkongsi Quark Netdisk ke Baidu Netdisk? Biarkan laman web ini memperkenalkan kepada pengguna secara terperinci cara menyimpan fail Quark Network Disk ke Baidu Network Disk. Cara menyimpan fail dari Cakera Rangkaian Quark ke Cakera Rangkaian Baidu Kaedah 1. Jika anda ingin tahu cara memindahkan fail dari Cakera Rangkaian Quark ke Cakera Rangkaian Baidu, mula-mula muat turun fail yang perlu disimpan pada Cakera Rangkaian Quark, dan kemudian buka klien Cakera Rangkaian Baidu , pilih folder tempat fail yang dimampatkan akan disimpan dan klik dua kali untuk membuka folder. 2. Selepas membuka folder, klik "Muat naik" di penjuru kiri sebelah atas tetingkap. 3. Cari fail termampat yang perlu dimuat naik pada komputer anda dan klik untuk memilihnya.

Bagaimana untuk mengimport lagu tempatan daripada NetEase Cloud Music Bagaimana untuk mengimport lagu tempatan Bagaimana untuk mengimport lagu tempatan daripada NetEase Cloud Music Bagaimana untuk mengimport lagu tempatan Mar 13, 2024 am 11:19 AM

Apabila kita menggunakan platform ini untuk mendengar lagu, kebanyakannya harus mempunyai beberapa lagu yang anda ingin dengar. Sudah tentu, beberapa perkara mungkin tidak didengari kerana tiada hak cipta diimport secara tempatan. Pergi ke sana supaya anda boleh mendengar. Kami boleh memuat turun beberapa lagu dan terus menukarnya ke dalam format mp3, supaya ia boleh diimbas pada telefon mudah alih untuk import dan situasi lain. Walau bagaimanapun, bagi kebanyakan pengguna, mereka tidak tahu banyak tentang mengimport kandungan lagu tempatan, jadi untuk menyelesaikan masalah ini dengan baik, hari ini editor juga akan menerangkannya kepada anda Kaedah kandungan membolehkan anda membuat pilihan yang lebih baik tanpa bertanya anda berminat,

Cara berkongsi Muzik Awan NetEase ke WeChat Moments_Tutorial untuk berkongsi Muzik Awan NetEase ke Momen WeChat Cara berkongsi Muzik Awan NetEase ke WeChat Moments_Tutorial untuk berkongsi Muzik Awan NetEase ke Momen WeChat Mar 25, 2024 am 11:41 AM

1. Mula-mula, kami masukkan Muzik Awan NetEase, dan kemudian klik pada antara muka laman utama perisian untuk memasuki antara muka main balik lagu. 2. Kemudian dalam antara muka main balik lagu, cari butang fungsi perkongsian di bahagian atas sebelah kanan, seperti yang ditunjukkan dalam kotak merah dalam rajah di bawah, klik untuk memilih saluran perkongsian dalam saluran perkongsian, klik pilihan "Kongsi ke". bahagian bawah, dan kemudian pilih "WeChat Moments" yang pertama membolehkan anda berkongsi kandungan ke WeChat Moments.

Bagaimana untuk melaksanakan log masuk WeChat dwi pada telefon mudah alih Huawei? Bagaimana untuk melaksanakan log masuk WeChat dwi pada telefon mudah alih Huawei? Mar 24, 2024 am 11:27 AM

Bagaimana untuk melaksanakan log masuk WeChat dwi pada telefon mudah alih Huawei? Dengan kebangkitan media sosial, WeChat telah menjadi salah satu alat komunikasi yang sangat diperlukan dalam kehidupan seharian orang ramai. Walau bagaimanapun, ramai orang mungkin menghadapi masalah: log masuk ke beberapa akaun WeChat pada masa yang sama pada telefon mudah alih yang sama. Bagi pengguna telefon mudah alih Huawei, tidak sukar untuk mencapai log masuk WeChat dwi Artikel ini akan memperkenalkan cara mencapai log masuk WeChat dwi pada telefon mudah alih Huawei. Pertama sekali, sistem EMUI yang disertakan dengan telefon mudah alih Huawei menyediakan fungsi yang sangat mudah - pembukaan dua aplikasi. Melalui fungsi pembukaan dwi aplikasi, pengguna boleh serentak

Panduan Pengaturcaraan PHP: Kaedah untuk Melaksanakan Jujukan Fibonacci Panduan Pengaturcaraan PHP: Kaedah untuk Melaksanakan Jujukan Fibonacci Mar 20, 2024 pm 04:54 PM

Bahasa pengaturcaraan PHP ialah alat yang berkuasa untuk pembangunan web, yang mampu menyokong pelbagai logik dan algoritma pengaturcaraan yang berbeza. Antaranya, melaksanakan jujukan Fibonacci adalah masalah pengaturcaraan biasa dan klasik. Dalam artikel ini, kami akan memperkenalkan cara menggunakan bahasa pengaturcaraan PHP untuk melaksanakan jujukan Fibonacci, dan melampirkan contoh kod tertentu. Jujukan Fibonacci ialah jujukan matematik yang ditakrifkan seperti berikut: unsur pertama dan kedua bagi jujukan ialah 1, dan bermula dari unsur ketiga, nilai setiap unsur adalah sama dengan jumlah dua unsur sebelumnya. Beberapa elemen pertama urutan

Cara berkongsi fail dengan rakan di Baidu Netdisk Cara berkongsi fail dengan rakan di Baidu Netdisk Mar 25, 2024 pm 06:52 PM

Baru-baru ini, klien Android Baidu Netdisk telah memperkenalkan versi baharu 8.0.0 Versi ini bukan sahaja membawa banyak perubahan, tetapi juga menambah banyak fungsi praktikal. Antaranya, yang paling menarik perhatian ialah peningkatan fungsi perkongsian folder. Kini, pengguna boleh dengan mudah menjemput rakan untuk menyertai dan berkongsi fail penting dalam kerja dan kehidupan, mencapai kerjasama dan perkongsian yang lebih mudah. Jadi bagaimana anda berkongsi fail yang anda perlukan untuk berkongsi dengan rakan-rakan anda Di bawah, editor laman web ini akan memberikan pengenalan terperinci kepada anda. 1) Buka Baidu Cloud APP, mula-mula klik untuk memilih folder yang berkaitan pada halaman utama, dan kemudian klik ikon [...] di penjuru kanan sebelah atas antara muka (seperti yang ditunjukkan di bawah) 2) Kemudian klik [+] masuk; lajur "Ahli Dikongsi" 】, dan akhirnya semak semua

Bagaimana untuk menyelesaikan masalah aksara yang kacau apabila mengimport data Cina ke Oracle? Bagaimana untuk menyelesaikan masalah aksara yang kacau apabila mengimport data Cina ke Oracle? Mar 10, 2024 am 09:54 AM

Tajuk: Kaedah dan contoh kod untuk menyelesaikan masalah aksara bercelaru apabila mengimport data Cina ke dalam Oracle Apabila mengimport data Cina ke pangkalan data Oracle, aksara bercelaru sering muncul Ini mungkin disebabkan oleh tetapan set aksara pangkalan data atau masalah penukaran pengekodan semasa import proses. . Untuk menyelesaikan masalah ini, kami boleh mengambil beberapa kaedah untuk memastikan data Cina yang diimport dapat dipaparkan dengan betul. Berikut ialah beberapa penyelesaian dan contoh kod khusus: 1. Semak tetapan set aksara pangkalan data Dalam pangkalan data Oracle, tetapan set aksara adalah

Bagaimana untuk melaksanakan fungsi klon WeChat pada telefon mudah alih Huawei Bagaimana untuk melaksanakan fungsi klon WeChat pada telefon mudah alih Huawei Mar 24, 2024 pm 06:03 PM

Bagaimana untuk melaksanakan fungsi klon WeChat pada telefon mudah alih Huawei Dengan populariti perisian sosial dan penekanan yang semakin meningkat terhadap privasi dan keselamatan orang ramai, fungsi klon WeChat telah beransur-ansur menjadi tumpuan perhatian. Fungsi klon WeChat boleh membantu pengguna log masuk ke berbilang akaun WeChat pada telefon mudah alih yang sama pada masa yang sama, menjadikannya lebih mudah untuk diurus dan digunakan. Tidak sukar untuk melaksanakan fungsi klon WeChat pada telefon mudah alih Huawei Anda hanya perlu mengikuti langkah berikut. Langkah 1: Pastikan versi sistem telefon mudah alih dan versi WeChat memenuhi keperluan Pertama, pastikan versi sistem telefon mudah alih Huawei anda telah dikemas kini kepada versi terkini, serta Apl WeChat.

See all articles