Home php教程 php手册 Share my import and export EXCEL class library based on NPOI ExcelReport: ExcelUt

Share my import and export EXCEL class library based on NPOI ExcelReport: ExcelUt

Jul 06, 2016 pm 01:30 PM
share based on accomplish 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));
        }
Copy after login

模板如下:

导出结果如下:

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

        }
Copy after login

模板同上一个模板

导出结果如下:

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));
        }
Copy after login

模板如下:

导出结果如下:

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

        }
Copy after login

模板如下:

导出结果如下:

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

        }
Copy after login

模板如下:

导出结果如下:

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

        }
Copy after login

模板如下:

导出结果如下:

二、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));
        }
Copy after login

模板如下:

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


    }
}
Copy after login

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

    }

}
Copy after login

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

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

 

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

 


Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

How to share Quark Netdisk to Baidu Netdisk? How to share Quark Netdisk to Baidu Netdisk? Mar 14, 2024 pm 04:40 PM

Quark Netdisk and Baidu Netdisk are very convenient storage tools. Many users are asking whether these two softwares are interoperable? How to share Quark Netdisk to Baidu Netdisk? Let this site introduce to users in detail how to save Quark network disk files to Baidu network disk. How to save files from Quark Network Disk to Baidu Network Disk Method 1. If you want to know how to transfer files from Quark Network Disk to Baidu Network Disk, first download the files that need to be saved on Quark Network Disk, and then open the Baidu Network Disk client. , select the folder where the compressed file is to be saved, and double-click to open the folder. 2. After opening the folder, click "Upload" in the upper left corner of the window. 3. Find the compressed file that needs to be uploaded on your computer and click to select it.

How to import local songs from NetEase Cloud Music How to import local songs How to import local songs from NetEase Cloud Music How to import local songs Mar 13, 2024 am 11:19 AM

When we use this platform to listen to songs, most of them should have some songs that you want to listen to. Of course, some things may not be listened to because there is no copyright. Of course, we can also directly use some songs imported locally. Go up there so you can listen. We can download some songs and directly convert them into mp3 formats, so that they can be scanned on the mobile phone for import and other situations. However, for most users, they don’t know much about importing local song content, so in order to solve these problems well, today the editor will also explain it to you. The content method allows you to make better choices without asking. If you are interested,

How to share NetEase Cloud Music to WeChat Moments_Tutorial on sharing NetEase Cloud Music to WeChat Moments How to share NetEase Cloud Music to WeChat Moments_Tutorial on sharing NetEase Cloud Music to WeChat Moments Mar 25, 2024 am 11:41 AM

1. First, we enter NetEase Cloud Music, and then click on the software homepage interface to enter the song playback interface. 2. Then in the song playback interface, find the sharing function button in the upper right corner, as shown in the red box in the figure below, click to select the sharing channel; in the sharing channel, click the &quot;Share to&quot; option at the bottom, and then select the first &quot;WeChat Moments&quot; allows you to share content to WeChat Moments.

How to implement dual WeChat login on Huawei mobile phones? How to implement dual WeChat login on Huawei mobile phones? Mar 24, 2024 am 11:27 AM

How to implement dual WeChat login on Huawei mobile phones? With the rise of social media, WeChat has become one of the indispensable communication tools in people's daily lives. However, many people may encounter a problem: logging into multiple WeChat accounts at the same time on the same mobile phone. For Huawei mobile phone users, it is not difficult to achieve dual WeChat login. This article will introduce how to achieve dual WeChat login on Huawei mobile phones. First of all, the EMUI system that comes with Huawei mobile phones provides a very convenient function - dual application opening. Through the application dual opening function, users can simultaneously

PHP Programming Guide: Methods to Implement Fibonacci Sequence PHP Programming Guide: Methods to Implement Fibonacci Sequence Mar 20, 2024 pm 04:54 PM

The programming language PHP is a powerful tool for web development, capable of supporting a variety of different programming logics and algorithms. Among them, implementing the Fibonacci sequence is a common and classic programming problem. In this article, we will introduce how to use the PHP programming language to implement the Fibonacci sequence, and attach specific code examples. The Fibonacci sequence is a mathematical sequence defined as follows: the first and second elements of the sequence are 1, and starting from the third element, the value of each element is equal to the sum of the previous two elements. The first few elements of the sequence

How to share files with friends on Baidu Netdisk How to share files with friends on Baidu Netdisk Mar 25, 2024 pm 06:52 PM

Recently, Baidu Netdisk Android client has ushered in a new version 8.0.0. This version not only brings many changes, but also adds many practical functions. Among them, the most eye-catching is the enhancement of the folder sharing function. Now, users can easily invite friends to join and share important files in work and life, achieving more convenient collaboration and sharing. So how do you share the files you need to share with your friends? Below, the editor of this site will give you a detailed introduction. I hope it can help you! 1) Open Baidu Cloud APP, first click to select the relevant folder on the homepage, and then click the [...] icon in the upper right corner of the interface; (as shown below) 2) Then click [+] in the &quot;Shared Members&quot; column 】, and finally check all

How to solve the problem of garbled characters when importing Chinese data into Oracle? How to solve the problem of garbled characters when importing Chinese data into Oracle? Mar 10, 2024 am 09:54 AM

Title: Methods and code examples to solve the problem of garbled characters when importing Chinese data into Oracle. When importing Chinese data into Oracle database, garbled characters often appear. This may be due to incorrect database character set settings or encoding conversion problems during the import process. . In order to solve this problem, we can take some methods to ensure that the imported Chinese data can be displayed correctly. The following are some solutions and specific code examples: 1. Check the database character set settings In the Oracle database, the character set settings are

How to implement the WeChat clone function on Huawei mobile phones How to implement the WeChat clone function on Huawei mobile phones Mar 24, 2024 pm 06:03 PM

How to implement the WeChat clone function on Huawei mobile phones With the popularity of social software and people's increasing emphasis on privacy and security, the WeChat clone function has gradually become the focus of people's attention. The WeChat clone function can help users log in to multiple WeChat accounts on the same mobile phone at the same time, making it easier to manage and use. It is not difficult to implement the WeChat clone function on Huawei mobile phones. You only need to follow the following steps. Step 1: Make sure that the mobile phone system version and WeChat version meet the requirements. First, make sure that your Huawei mobile phone system version has been updated to the latest version, as well as the WeChat App.

See all articles