Commit 0d0625fb53b62d59cd845d93e5354368fcf09834

Authored by wdn127929
1 parent 1a963547

分享小程序封面图裁切成固定比例5:4

@@ -12,14 +12,14 @@ if (flutterRoot == null) { @@ -12,14 +12,14 @@ if (flutterRoot == null) {
12 } 12 }
13 13
14 14
15 -def flutterVersionCode = "443" 15 +def flutterVersionCode = "444"
16 if (flutterVersionCode == null) { 16 if (flutterVersionCode == null) {
17 - flutterVersionCode = '443' 17 + flutterVersionCode = '444'
18 } 18 }
19 19
20 -def flutterVersionName = "4.4.3" 20 +def flutterVersionName = "4.4.4"
21 if (flutterVersionName == null) { 21 if (flutterVersionName == null) {
22 - flutterVersionName = '4.4.3' 22 + flutterVersionName = '4.4.4'
23 } 23 }
24 apply plugin: 'com.android.application' 24 apply plugin: 'com.android.application'
25 apply plugin: 'kotlin-android' 25 apply plugin: 'kotlin-android'
@@ -110,5 +110,10 @@ @@ -110,5 +110,10 @@
110 android:name="com.amap.api.v2.apikey" 110 android:name="com.amap.api.v2.apikey"
111 android:value="13464ddadd6a5d825e79f90e10ba72d2"/> 111 android:value="13464ddadd6a5d825e79f90e10ba72d2"/>
112 112
  113 + <activity
  114 + android:name="com.yalantis.ucrop.UCropActivity"
  115 + android:screenOrientation="portrait"
  116 + android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
  117 +
113 </application> 118 </application>
114 </manifest> 119 </manifest>
@@ -2,4 +2,4 @@ org.gradle.jvmargs=-Xmx1536M @@ -2,4 +2,4 @@ org.gradle.jvmargs=-Xmx1536M
2 # org.gradle.jvmargs=-Xmx2048M 2 # org.gradle.jvmargs=-Xmx2048M
3 android.enableR8=true 3 android.enableR8=true
4 android.useAndroidX=true 4 android.useAndroidX=true
5 -android.enableJetifier=true  
  5 +android.enableJetifier=true
1 import 'package:flutter/services.dart'; 1 import 'package:flutter/services.dart';
2 import 'package:permission_handler/permission_handler.dart'; 2 import 'package:permission_handler/permission_handler.dart';
3 3
  4 +Future<bool> checkPermissionStorage() async {
  5 + var status = await Permission.storage.status;
  6 + if (!status.isGranted) {
  7 + status = await Permission.storage.request();
  8 + if (status.isGranted) {
  9 + return true;
  10 + }
  11 + } else {
  12 + return true;
  13 + }
  14 + return false;
  15 +}
  16 +
4 Future<bool> checkContactPermission() async { 17 Future<bool> checkContactPermission() async {
5 PermissionStatus permissionStatus = await Permission.contacts.status; 18 PermissionStatus permissionStatus = await Permission.contacts.status;
6 if (permissionStatus == PermissionStatus.granted) { 19 if (permissionStatus == PermissionStatus.granted) {
@@ -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,
@@ -43,6 +43,13 @@ packages: @@ -43,6 +43,13 @@ packages:
43 url: "https://pub.flutter-io.cn" 43 url: "https://pub.flutter-io.cn"
44 source: hosted 44 source: hosted
45 version: "4.1.0" 45 version: "4.1.0"
  46 + archive:
  47 + dependency: transitive
  48 + description:
  49 + name: archive
  50 + url: "https://pub.flutter-io.cn"
  51 + source: hosted
  52 + version: "3.3.6"
46 args: 53 args:
47 dependency: transitive 54 dependency: transitive
48 description: 55 description:
@@ -637,6 +644,34 @@ packages: @@ -637,6 +644,34 @@ packages:
637 url: "https://pub.flutter-io.cn" 644 url: "https://pub.flutter-io.cn"
638 source: hosted 645 source: hosted
639 version: "4.0.1" 646 version: "4.0.1"
  647 + image:
  648 + dependency: "direct main"
  649 + description:
  650 + name: image
  651 + url: "https://pub.flutter-io.cn"
  652 + source: hosted
  653 + version: "4.0.15"
  654 + image_cropper:
  655 + dependency: "direct main"
  656 + description:
  657 + name: image_cropper
  658 + url: "https://pub.flutter-io.cn"
  659 + source: hosted
  660 + version: "3.0.1"
  661 + image_cropper_for_web:
  662 + dependency: transitive
  663 + description:
  664 + name: image_cropper_for_web
  665 + url: "https://pub.flutter-io.cn"
  666 + source: hosted
  667 + version: "1.0.3"
  668 + image_cropper_platform_interface:
  669 + dependency: transitive
  670 + description:
  671 + name: image_cropper_platform_interface
  672 + url: "https://pub.flutter-io.cn"
  673 + source: hosted
  674 + version: "3.0.3"
640 image_gallery_saver: 675 image_gallery_saver:
641 dependency: "direct main" 676 dependency: "direct main"
642 description: 677 description:
@@ -903,6 +938,13 @@ packages: @@ -903,6 +938,13 @@ packages:
903 url: "https://pub.flutter-io.cn" 938 url: "https://pub.flutter-io.cn"
904 source: hosted 939 source: hosted
905 version: "0.1.0" 940 version: "0.1.0"
  941 + petitparser:
  942 + dependency: transitive
  943 + description:
  944 + name: petitparser
  945 + url: "https://pub.flutter-io.cn"
  946 + source: hosted
  947 + version: "5.1.0"
906 photo_manager: 948 photo_manager:
907 dependency: transitive 949 dependency: transitive
908 description: 950 description:
@@ -931,6 +973,13 @@ packages: @@ -931,6 +973,13 @@ packages:
931 url: "https://pub.flutter-io.cn" 973 url: "https://pub.flutter-io.cn"
932 source: hosted 974 source: hosted
933 version: "2.1.2" 975 version: "2.1.2"
  976 + pointycastle:
  977 + dependency: transitive
  978 + description:
  979 + name: pointycastle
  980 + url: "https://pub.flutter-io.cn"
  981 + source: hosted
  982 + version: "3.6.2"
934 pool: 983 pool:
935 dependency: transitive 984 dependency: transitive
936 description: 985 description:
@@ -1421,6 +1470,13 @@ packages: @@ -1421,6 +1470,13 @@ packages:
1421 url: "https://pub.flutter-io.cn" 1470 url: "https://pub.flutter-io.cn"
1422 source: hosted 1471 source: hosted
1423 version: "0.2.0+1" 1472 version: "0.2.0+1"
  1473 + xml:
  1474 + dependency: transitive
  1475 + description:
  1476 + name: xml
  1477 + url: "https://pub.flutter-io.cn"
  1478 + source: hosted
  1479 + version: "6.1.0"
1424 yaml: 1480 yaml:
1425 dependency: transitive 1481 dependency: transitive
1426 description: 1482 description:
@@ -181,6 +181,8 @@ dependencies: @@ -181,6 +181,8 @@ dependencies:
181 extended_text_field: ^10.1.1 181 extended_text_field: ^10.1.1
182 image_gallery_saver: ^1.7.1 182 image_gallery_saver: ^1.7.1
183 flutter_image_compress: ^1.1.3 183 flutter_image_compress: ^1.1.3
  184 + image: ^4.0.15
  185 + image_cropper: ^3.0.1
184 186
185 187
186 #表格多选组建 188 #表格多选组建