前言
最近做flutter项目有个需求是将数据导出excel表格,原本需求是图片以链接的形式导出,直接去pubdev上搜官方的excel插件就能实现,后来需求变成导出的图片要在excel文件中直接显示出来,官方的excel插件只支持写入文本,去pubdev上看到了别的插件syncfusion_flutter_xlsio
里面有插入图片的api
这里插入的是本地图片,既然它可以实现插入图片,那么接下来要解决如何把网络图片插入进去
// 插件中的这段代码是写入图片的关键
// 先是拿到图片的文件流Uint8List格式
final List<int> bytes = File('image.png').readAsBytesSync();
// 将文件流写入
final Picture picture = sheet.picutes.addStream(1, 1, bytes);
那么要考虑如何将在线图片地址转成Uint8List格式,先在项目中引入需要的库
import 'dart:io';
import 'package:image/image.dart' as imgLib;
import 'package:dio/dio.dart';
import 'dart:convert';
import 'package:syncfusion_flutter_xlsio/xlsio.dart' as Flutter_xlsio;
import 'package:path_provider/path_provider.dart' as path_provider;
这里封装一个同步的方法拿到图片的文件流
// url为网络图片地址
Future netImageToBase64(url) async {
var response = await Dio()
.get(url, options: Options(responseType: ResponseType.bytes));
print(
"Uint8List.fromList(response.data)===${Uint8List.fromList(response.data)}");
// 以这种方式拿到了Uint8List格式的图片数据流,接下来可以为所欲为了
// 这里是压缩图片的操作,如果不压缩的话图片会很大占用Excel很多行和列
// 先转成Image格式,使用Image的Api调整图片然后再转回Uint8List格式
imgLib.Image image = imgLib.decodeImage(Uint8List.fromList(response.data));
//拷贝图像并调整大小(保持图片长宽比例不变).thumbnail是调整时候的图片这时是Image类型
imgLib.Image thumbnail = imgLib.copyResize(image, height: 120);
将图片解码成Uint8List
final List<int> bytesTmp = imgLib.encodePng(thumbnail);
return bytesTmp;
}
调用示例注意下面代码中的dataList是我用来接收数据的List类型的变量,代码里没有显示定义
Future<void> generateExcel() async {
// 创建一个Excel文档.
final Flutter_xlsio.Workbook workbook = new Flutter_xlsio.Workbook();
//通过索引访问工作表第0个sheet.
final Flutter_xlsio.Worksheet sheet = workbook.worksheets[0];
sheet.getRangeByName('A1').columnWidth = 20.00;
sheet.getRangeByName('A2').rowHeight = 100.00;
sheet.getRangeByName('B1').columnWidth = 13.82;
sheet.getRangeByName('C1').columnWidth = 20.00;
sheet.getRangeByName('D1').columnWidth = 13.82;
sheet.getRangeByName('E1').columnWidth = 50.00;
// 垂直方向文字
sheet.getRangeByName('A2').cellStyle.vAlign = Flutter_xlsio.VAlignType.top;
// 设置标题
sheet.getRangeByName('A1').setText('任务编号');
sheet.getRangeByName('B1').setText('提交人id');
sheet.getRangeByName('C1').setText('提交时间');
sheet.getRangeByName('D1').setText('任务状态');
sheet.getRangeByName('E1').setText('验证图片');
// 这里循环取数据
for (int i = 0; i < dataList.length; i++) {
sheet.getRangeByIndex(i + 2, 1).setText(dataList[i]['tid'].toString());
sheet
.getRangeByIndex(i + 2, 2)
.setText(dataList[i]['uid'].toString());
sheet
.getRangeByIndex(i + 2, 3)
.setText(dataList[i]['create_time'].toString());
sheet
.getRangeByIndex(i + 2, 4)
.setText(dataList[i]['taskstatus'].toString());
// 开始存图
Uint8List imageBytes =
await netImageToBase64(dataList[i]['imgurl1']);
sheet.pictures.addStream(i + 2, 5, imageBytes);
}
List<int> bytes = workbook.saveAsStream();
workbook.dispose();
final Directory directory =
await path_provider.getApplicationDocumentsDirectory();
final String path = directory.path;
final File file = File('$path/output.xlsx');
file.writeAsBytes(bytes);
// 触发分享
Share.shareFiles(["$path/output.xlsx"], text: 'Great picture');
}
写如图片的重要代码就是循环体里的这部分
Uint8List imageBytes =
await netImageToBase64(dataList[i]['imgurl1']);
最后还可以配合一个插件触发安卓自带的分享,可以直接将文件分享到微信QQ等,版本可去pubdev自行获取,调用方式在上述示例代码中已详细列出
import 'package:share/share.dart';// 引入
// 调用
Share.shareFiles(["$path/output.xlsx"], text: 'Great picture');
写入之后的文件
总结
主要实现了将网络图片写入Excel文件,写入逻辑还没有优化,第一次写这种需求,据了解是服务端是可以做,在服务端生成后你直接拿到下载地址或者文件流都可以,但是没有办法,我迫不得已只能前端来写。有问题的话大家可以留言一起交流。