|
@@ -28,11 +28,13 @@ import 'package:provider/provider.dart'; |
|
@@ -28,11 +28,13 @@ import 'package:provider/provider.dart'; |
|
28
|
import 'package:url_launcher/url_launcher.dart';
|
28
|
import 'package:url_launcher/url_launcher.dart';
|
|
29
|
import 'package:crypto/crypto.dart';
|
29
|
import 'package:crypto/crypto.dart';
|
|
30
|
import 'package:flutter_image_compress/flutter_image_compress.dart';
|
30
|
import 'package:flutter_image_compress/flutter_image_compress.dart';
|
|
31
|
-import 'dart:convert';
|
|
|
|
32
|
-import 'package:webview_flutter/webview_flutter.dart';
|
|
|
|
33
|
|
31
|
|
|
34
|
-import '../app.dart';
|
|
|
|
35
|
-import 'package:http/http.dart' as http;
|
32
|
+import 'package:image/image.dart' as IMG;
|
|
|
|
33
|
+import 'dart:ui' as ui;
|
|
|
|
34
|
+import 'package:permission_handler/permission_handler.dart';
|
|
|
|
35
|
+import 'package:path_provider/path_provider.dart';
|
|
|
|
36
|
+import 'package:image_cropper/image_cropper.dart';
|
|
|
|
37
|
+// import 'dart:typed_data';
|
|
36
|
|
38
|
|
|
37
|
typedef BookTimeSetCallback = void Function(bool needChange);
|
39
|
typedef BookTimeSetCallback = void Function(bool needChange);
|
|
38
|
|
40
|
|
|
@@ -1166,7 +1168,7 @@ class Utils { |
|
@@ -1166,7 +1168,7 @@ class Utils { |
|
1166
|
String _userName = "gh_487873d353b3";
|
1168
|
String _userName = "gh_487873d353b3";
|
|
1167
|
String _path = "pack-cookbook/pages/index?rid=$rid&identity=2&sid=$sid";
|
1169
|
String _path = "pack-cookbook/pages/index?rid=$rid&identity=2&sid=$sid";
|
|
1168
|
String _description = "OneKey";
|
1170
|
String _description = "OneKey";
|
|
1169
|
- Uint8List source = await testComporessList(_thumbnail);
|
1171
|
+ Uint8List source = await testComporessList(context, _thumbnail);
|
|
1170
|
var model = new WeChatShareMiniProgramModel(
|
1172
|
var model = new WeChatShareMiniProgramModel(
|
|
1171
|
webPageUrl: _webPageUrl,
|
1173
|
webPageUrl: _webPageUrl,
|
|
1172
|
userName: _userName,
|
1174
|
userName: _userName,
|
|
@@ -1200,7 +1202,7 @@ class Utils { |
|
@@ -1200,7 +1202,7 @@ class Utils { |
|
1200
|
String _path =
|
1202
|
String _path =
|
|
1201
|
"pack-cookbook/pages/success?rid=$rid&identity=2&hasOnlyShow=1";
|
1203
|
"pack-cookbook/pages/success?rid=$rid&identity=2&hasOnlyShow=1";
|
|
1202
|
String _description = "OneKey";
|
1204
|
String _description = "OneKey";
|
|
1203
|
- Uint8List source = await testComporessList(_thumbnail);
|
1205
|
+ Uint8List source = await testComporessList(context, _thumbnail);
|
|
1204
|
var model = new WeChatShareMiniProgramModel(
|
1206
|
var model = new WeChatShareMiniProgramModel(
|
|
1205
|
webPageUrl: _webPageUrl,
|
1207
|
webPageUrl: _webPageUrl,
|
|
1206
|
userName: _userName,
|
1208
|
userName: _userName,
|
|
@@ -1261,9 +1263,11 @@ class Utils { |
|
@@ -1261,9 +1263,11 @@ class Utils { |
|
1261
|
/// 下载图片
|
1263
|
/// 下载图片
|
|
1262
|
static downloadFile(String url) async {
|
1264
|
static downloadFile(String url) async {
|
|
1263
|
// if (await Permission.storage.request().isGranted) {
|
1265
|
// if (await Permission.storage.request().isGranted) {
|
|
|
|
1266
|
+
|
|
1264
|
var response = await Dio()
|
1267
|
var response = await Dio()
|
|
1265
|
.get(url, options: Options(responseType: ResponseType.bytes));
|
1268
|
.get(url, options: Options(responseType: ResponseType.bytes));
|
|
1266
|
Uint8List result = Uint8List.fromList(response.data);
|
1269
|
Uint8List result = Uint8List.fromList(response.data);
|
|
|
|
1270
|
+
|
|
1267
|
return result;
|
1271
|
return result;
|
|
1268
|
// print(result);
|
1272
|
// print(result);
|
|
1269
|
// if (result["isSuccess"]) {
|
1273
|
// if (result["isSuccess"]) {
|
|
@@ -1277,36 +1281,166 @@ class Utils { |
|
@@ -1277,36 +1281,166 @@ class Utils { |
|
1277
|
}
|
1281
|
}
|
|
1278
|
|
1282
|
|
|
1279
|
/// 图片压缩 Uint8List -> Uint8List
|
1283
|
/// 图片压缩 Uint8List -> Uint8List
|
|
1280
|
- static Future<Uint8List> testComporessList(String url) async {
|
|
|
|
1281
|
- Uint8List result = await downloadFile(url);
|
|
|
|
1282
|
- if (result.length < 200 * 1024) {
|
|
|
|
1283
|
- return result;
|
|
|
|
1284
|
- }
|
|
|
|
1285
|
- var quality = 100;
|
|
|
|
1286
|
- if (result.length > 4 * 1024 * 1024) {
|
1284
|
+ static Future<Uint8List> testComporessList(
|
|
|
|
1285
|
+ BuildContext context, String url) async {
|
|
|
|
1286
|
+ Loading.showLoading(context);
|
|
|
|
1287
|
+ Uint8List list = await downloadFile(url); //下载图片
|
|
|
|
1288
|
+ Uint8List result = await resizeImage(list); //重置图片尺寸
|
|
|
|
1289
|
+ Uint8List resultnew = await realComporessList(result); //压缩图片
|
|
|
|
1290
|
+
|
|
|
|
1291
|
+ Loading.hideLoading(context);
|
|
|
|
1292
|
+ return resultnew;
|
|
|
|
1293
|
+ // if (result.length < 128 * 1024) {
|
|
|
|
1294
|
+ // return result;
|
|
|
|
1295
|
+ // } else {
|
|
|
|
1296
|
+ // result = await realComporessList(result);
|
|
|
|
1297
|
+ // return result;
|
|
|
|
1298
|
+ // }
|
|
|
|
1299
|
+ }
|
|
|
|
1300
|
+
|
|
|
|
1301
|
+ static realComporessList(Uint8List list) async {
|
|
|
|
1302
|
+ int minHeight = 457; // 指定最小分辨率的高度
|
|
|
|
1303
|
+ int minWidth = 572; // 指定最小分辨率的宽度
|
|
|
|
1304
|
+ int quality = imageQuality(list.length);
|
|
|
|
1305
|
+ Uint8List result = await FlutterImageCompress.compressWithList(
|
|
|
|
1306
|
+ list,
|
|
|
|
1307
|
+ minWidth: minWidth,
|
|
|
|
1308
|
+ minHeight: minHeight,
|
|
|
|
1309
|
+ quality: quality,
|
|
|
|
1310
|
+ );
|
|
|
|
1311
|
+ debugPrint("压缩后图片的大小:${size(result.length)}");
|
|
|
|
1312
|
+ return result;
|
|
|
|
1313
|
+ }
|
|
|
|
1314
|
+
|
|
|
|
1315
|
+ /// 根据传入的图片字节长度,返回指定的图片质量
|
|
|
|
1316
|
+ static int imageQuality(int length) {
|
|
|
|
1317
|
+ debugPrint("压缩前图片的大小:${size(length)}");
|
|
|
|
1318
|
+ int quality = 100; // 图片质量指数
|
|
|
|
1319
|
+ int m = 1024 * 1024; // 1 兆
|
|
|
|
1320
|
+ if (length < 0.5 * m) {
|
|
|
|
1321
|
+ quality = 70;
|
|
|
|
1322
|
+ debugPrint("图片小于 0.5 兆,质量设置为 70");
|
|
|
|
1323
|
+ } else if (length >= 0.5 * m && length < 1 * m) {
|
|
|
|
1324
|
+ quality = 60;
|
|
|
|
1325
|
+ debugPrint("图片大于 0.5 兆小于 1 兆,质量设置为 60");
|
|
|
|
1326
|
+ } else if (length >= 1 * m && length < 2 * m) {
|
|
1287
|
quality = 50;
|
1327
|
quality = 50;
|
|
1288
|
- } else if (result.length > 2 * 1024 * 1024) {
|
1328
|
+ debugPrint("图片大于 1 兆小于 2 兆,质量设置为 50");
|
|
|
|
1329
|
+ } else if (length >= 2 * m && length < 3 * m) {
|
|
1289
|
quality = 60;
|
1330
|
quality = 60;
|
|
1290
|
- } else if (result.length > 1 * 1024 * 1024) {
|
|
|
|
1291
|
- quality = 70;
|
|
|
|
1292
|
- } else if (result.length > 0.5 * 1024 * 1024) {
|
|
|
|
1293
|
- quality = 80;
|
|
|
|
1294
|
- } else if (result.length > 0.25 * 1024 * 1024) {
|
|
|
|
1295
|
- quality = 90;
|
1331
|
+ debugPrint("图片大于 2 兆小于 3 兆,质量设置为 40");
|
|
|
|
1332
|
+ } else if (length >= 3 * m && length < 4 * m) {
|
|
|
|
1333
|
+ quality = 30;
|
|
|
|
1334
|
+ debugPrint("图片大于 3 兆小于 4 兆,质量设置为 30");
|
|
|
|
1335
|
+ } else {
|
|
|
|
1336
|
+ quality = 20;
|
|
|
|
1337
|
+ debugPrint("图片大于 4 兆,质量设置为 20");
|
|
|
|
1338
|
+ }
|
|
|
|
1339
|
+ return quality;
|
|
|
|
1340
|
+ }
|
|
|
|
1341
|
+
|
|
|
|
1342
|
+//裁剪图片,改变图片大小
|
|
|
|
1343
|
+ static Future<Uint8List> resizeImage(Uint8List data) async {
|
|
|
|
1344
|
+ /**
|
|
|
|
1345
|
+
|
|
|
|
1346
|
+ //image插件改变图片尺寸 copyCrop、copyResize 两个方法
|
|
|
|
1347
|
+ Uint8List resizedData = data;
|
|
|
|
1348
|
+ IMG.Image decodedImage = IMG.decodeImage(data);
|
|
|
|
1349
|
+ print(decodedImage.width);
|
|
|
|
1350
|
+ print(decodedImage.height);
|
|
|
|
1351
|
+ var cropSize = min(decodedImage.width, decodedImage.height);
|
|
|
|
1352
|
+ int offsetX =
|
|
|
|
1353
|
+ (decodedImage.width - min(decodedImage.width, decodedImage.height)) ~/
|
|
|
|
1354
|
+ 2;
|
|
|
|
1355
|
+ int offsetY =
|
|
|
|
1356
|
+ (decodedImage.height - min(decodedImage.width, decodedImage.height)) ~/
|
|
|
|
1357
|
+ 2;
|
|
|
|
1358
|
+ IMG.Image resized = IMG.copyCrop(decodedImage,
|
|
|
|
1359
|
+ x: offsetX, y: offsetY, width: 572, height: 457);
|
|
|
|
1360
|
+ // IMG.Image resized = IMG.copyResize(decodedImage,
|
|
|
|
1361
|
+ // width: 572, interpolation: IMG.Interpolation.cubic);
|
|
|
|
1362
|
+ resizedData = IMG.encodeJpg(resized);
|
|
|
|
1363
|
+ print(size(resizedData.length));
|
|
|
|
1364
|
+ ui.Image im = await fun1(resizedData);
|
|
|
|
1365
|
+ print(im.width);
|
|
|
|
1366
|
+ print(im.height);
|
|
|
|
1367
|
+ return resizedData;
|
|
|
|
1368
|
+ */
|
|
|
|
1369
|
+//image_cropper插件,中心点裁剪固定比例的图片
|
|
|
|
1370
|
+ String imgPath = await saveImage(data);
|
|
|
|
1371
|
+ Uint8List afterImg = data;
|
|
|
|
1372
|
+ if (imgPath != null) {
|
|
|
|
1373
|
+ final croppedImage = await ImageCropper().cropImage(
|
|
|
|
1374
|
+ sourcePath: imgPath,
|
|
|
|
1375
|
+ cropStyle: CropStyle.rectangle,
|
|
|
|
1376
|
+ compressQuality: 100,
|
|
|
|
1377
|
+ compressFormat: ImageCompressFormat.jpg,
|
|
|
|
1378
|
+ aspectRatioPresets: [CropAspectRatioPreset.ratio5x4],
|
|
|
|
1379
|
+ // aspectRatio: const CropAspectRatio(ratioX: 0.8, ratioY: 1.0)
|
|
|
|
1380
|
+ );
|
|
|
|
1381
|
+ print(croppedImage);
|
|
|
|
1382
|
+ File yourFile = File(croppedImage.path);
|
|
|
|
1383
|
+
|
|
|
|
1384
|
+ afterImg = await yourFile.readAsBytes();
|
|
1296
|
}
|
1385
|
}
|
|
1297
|
|
1386
|
|
|
1298
|
- var resizeBytes = await FlutterImageCompress.compressWithList(
|
|
|
|
1299
|
- result,
|
|
|
|
1300
|
- minHeight: 500,
|
|
|
|
1301
|
- minWidth: 400,
|
|
|
|
1302
|
- quality: quality,
|
|
|
|
1303
|
- // rotate: 135,
|
|
|
|
1304
|
- );
|
1387
|
+ IMG.Image decodedImage = IMG.decodeImage(data);
|
|
|
|
1388
|
+ print(decodedImage.width);
|
|
|
|
1389
|
+ print(decodedImage.height);
|
|
|
|
1390
|
+
|
|
|
|
1391
|
+ IMG.Image decodedImageafterImg = IMG.decodeImage(afterImg);
|
|
|
|
1392
|
+ print(decodedImageafterImg.width);
|
|
|
|
1393
|
+ print(decodedImageafterImg.height);
|
|
|
|
1394
|
+ debugPrint("newnenwnewnnwen图片的大小:${size(afterImg.length)}");
|
|
|
|
1395
|
+ return afterImg;
|
|
|
|
1396
|
+ }
|
|
|
|
1397
|
+
|
|
|
|
1398
|
+ //将回调拿到的Uint8List格式的图片转换为File格式
|
|
|
|
1399
|
+ static Future<String> saveImage(Uint8List imageByte) async {
|
|
|
|
1400
|
+ bool isGranted = await checkPermissionStorage();
|
|
|
|
1401
|
+ if (isGranted) {
|
|
|
|
1402
|
+ //获取临时目录
|
|
|
|
1403
|
+ var tempDir = await getTemporaryDirectory();
|
|
|
|
1404
|
+ //生成file文件格式
|
|
|
|
1405
|
+ var file =
|
|
|
|
1406
|
+ await File('${tempDir.path}/image_${DateTime.now().millisecond}.jpg')
|
|
|
|
1407
|
+ .create();
|
|
|
|
1408
|
+ //转成file文件
|
|
|
|
1409
|
+ file.writeAsBytesSync(imageByte);
|
|
|
|
1410
|
+ print("${file.path}");
|
|
|
|
1411
|
+ return file.path;
|
|
|
|
1412
|
+ // setState(() {
|
|
|
|
1413
|
+ // path = file.path;
|
|
|
|
1414
|
+ // // turn(file);
|
|
|
|
1415
|
+ // _imageUint8=imageByte;
|
|
|
|
1416
|
+ // });
|
|
|
|
1417
|
+ }
|
|
|
|
1418
|
+ return null;
|
|
|
|
1419
|
+ }
|
|
1305
|
|
1420
|
|
|
1306
|
- print("压缩前:${result.length / 1024}");
|
|
|
|
1307
|
- print("压缩后:${resizeBytes.length / 1024}");
|
1421
|
+ /// 根据传入的字节长度,转换成相应的 M 和 KB
|
|
|
|
1422
|
+ static String size(int length) {
|
|
|
|
1423
|
+ String res = "";
|
|
|
|
1424
|
+ final int unit = 1024;
|
|
|
|
1425
|
+ final int m = unit * unit; // 1M
|
|
|
|
1426
|
+ // 如果小于 1 兆,显示 KB
|
|
|
|
1427
|
+ if (length < 1 * m) {
|
|
|
|
1428
|
+ res = (length / unit).toStringAsFixed(0) + " KB";
|
|
|
|
1429
|
+ }
|
|
|
|
1430
|
+ // 如果大于 1 兆,显示 MB,并保留一位小数
|
|
|
|
1431
|
+ if (length >= 1 * m) {
|
|
|
|
1432
|
+ res = (length / m).toStringAsFixed(1) + " MB";
|
|
|
|
1433
|
+ }
|
|
|
|
1434
|
+ return res;
|
|
|
|
1435
|
+ }
|
|
|
|
1436
|
+
|
|
|
|
1437
|
+ /// Uint8List 转 Image 方式一
|
|
1308
|
|
1438
|
|
|
1309
|
- return resizeBytes;
|
1439
|
+ /// Uint8List 转 Image 方式二
|
|
|
|
1440
|
+ static Future<ui.Image> fun1(Uint8List list) async {
|
|
|
|
1441
|
+ ui.Codec codec = await ui.instantiateImageCodec(list);
|
|
|
|
1442
|
+ ui.FrameInfo frame = await codec.getNextFrame();
|
|
|
|
1443
|
+ return frame.image;
|
|
1310
|
}
|
1444
|
}
|
|
1311
|
|
1445
|
|
|
1312
|
//分享邀请函
|
1446
|
//分享邀请函
|
|
@@ -1328,7 +1462,8 @@ class Utils { |
|
@@ -1328,7 +1462,8 @@ class Utils { |
|
1328
|
String _path =
|
1462
|
String _path =
|
|
1329
|
"pages/customer/index?id=$rid&hasInvitation=1&hasSellerShare=1&uid=$uid";
|
1463
|
"pages/customer/index?id=$rid&hasInvitation=1&hasSellerShare=1&uid=$uid";
|
|
1330
|
String _description = "进入查看包间详情,转发同行好友,还可一键导航到饭店";
|
1464
|
String _description = "进入查看包间详情,转发同行好友,还可一键导航到饭店";
|
|
1331
|
- Uint8List source = await testComporessList(_thumbnail);
|
1465
|
+ Uint8List source = await testComporessList(context, _thumbnail);
|
|
|
|
1466
|
+
|
|
1332
|
//跳转小程序
|
1467
|
//跳转小程序
|
|
1333
|
var model = new WeChatShareMiniProgramModel(
|
1468
|
var model = new WeChatShareMiniProgramModel(
|
|
1334
|
webPageUrl: _webPageUrl,
|
1469
|
webPageUrl: _webPageUrl,
|