在網(wǎng)上翻了一圈發(fā)現(xiàn)并沒有人貢獻這方面的代碼可能是技術(shù)含量太低了,我這里記錄以下
用到的工具
1.權(quán)限管理http://www.reibang.com/p/35b37c012351
2.dio 網(wǎng)絡(luò) http://www.reibang.com/p/fdd12bb921c2
3. 圖片的操作 http://www.reibang.com/p/bf97573eb69e http://www.reibang.com/p/c276b27520c0
實現(xiàn)原理
通過拍照/選取圖片 (image_picker)
裁切尺寸大小圖片(image_cropper)
將文件轉(zhuǎn)成Base64 上傳百度AI進行輪廓裁剪(百度AI)
通過Canvas繪畫合成
將文件保存到本地并顯示在widget上
選取圖片
///選擇一個圖片
///[from] 是相機還是圖庫
///可選參數(shù)
///[maxWidth] 寬度,
///[maxHeight] 高度,
///[imageQuality] 質(zhì)量
static pickSinglePic(ImageFrom from,
{double? maxWidth, double? maxHeight, int? imageQuality}) async {
ImageSource source;
switch (from) {
case ImageFrom.camera:
source = ImageSource.camera;
break;
case ImageFrom.gallery:
source = ImageSource.gallery;
break;
}
final pickerImages = await ImagePicker().pickImage(
source: source,
imageQuality: imageQuality,
maxWidth: maxWidth,
maxHeight: maxHeight,
);
return pickerImages;
}
裁切圖片大小
///裁切圖片
///[image] 圖片路徑或文件
///[width] 寬度
///[height] 高度
///[aspectRatio] 比例
///[androidUiSettings]UI 參數(shù)
///[iOSUiSettings] ios的ui 參數(shù)
static cropImage(
{required image,
required width,
required height,
aspectRatio,
androidUiSettings,
iOSUiSettings}) async {
String imagePth = "";
if (image is String) {
imagePth = image;
} else if (image is File) {
imagePth = image.path;
} else {
throw ("文件路徑錯誤");
}
final croppedFile = await ImageCropper().cropImage(
sourcePath: imagePth,
maxWidth: FormatUtil.num2int(width),
maxHeight: FormatUtil.num2int(height),
aspectRatio: aspectRatio ??
CropAspectRatio(
ratioX: FormatUtil.num2double(width),
ratioY: FormatUtil.num2double(height)),
uiSettings: [
androidUiSettings ??
AndroidUiSettings(
toolbarTitle:
'圖片裁切(${FormatUtil.num2int(width)}*${FormatUtil.num2int(height)})',
toolbarColor: Colors.blue,
toolbarWidgetColor: Colors.white,
initAspectRatio: CropAspectRatioPreset.original,
hideBottomControls: false,
lockAspectRatio: true),
iOSUiSettings ??
IOSUiSettings(
title: 'Cropper',
),
],
);
return croppedFile;
}
將獲取到的圖片轉(zhuǎn)成Base64 上傳
///圖片轉(zhuǎn)base64 無頭
///[file] 文件
///[base64] String 類型的base64
static file2Base64(File file) async {
Uint8List imageBytes = await file2Uint8List(file);
String base64 = base64Encode(imageBytes);
return base64;
}
///文件轉(zhuǎn) Uint8List
static file2Uint8List(File file) async {
Uint8List imageBytes = await file.readAsBytes();
return imageBytes;
}
上傳百度AI
static Future<String> getToken() async {
/// 第一個必穿參數(shù) 第二個第三個自己去百度Ai官網(wǎng)申請 免費額度一萬次
Map<String, dynamic> param = {
"grant_type": "client_credentials",
"client_id": clientId,
"client_secret": clientSecret
};
Response<dynamic> response =
await DioClient().doPost(Api.getToken, queryParameters: param);
return response.data["access_token"];
}
/// 獲取文件Base64的前景照 這里用的fromData傳輸
static Future<String> getBase64(Map<String, dynamic> param) async {
Response<dynamic> response = await DioClient().doPost(Api.uploadURL,
data: FormData.fromMap(param),
options: Options(contentType: "application/x-www-form-urlencoded"));
return response.data["foreground"];
}
獲取到的Base64畫到Cnvas上
///創(chuàng)建一個圖片的 ByteData
///[width] 圖片寬度
///[height] 圖片高度
///[bgColor] 背景顏色
///[imageFile] base64的圖片路徑(無頭)
static generateImageData(
{required double width,
required double height,
bgColor = Colors.white,
imageFile}) async {
///canvas的記錄工具 用來保存canvas的
final recorder = ui.PictureRecorder();
///canvas 繪圖工具
Canvas canvas = Canvas(recorder);
///畫筆 顏色為傳入顏色 狀態(tài)是填充
Paint paint = Paint();
paint.color = bgColor;
paint.style = PaintingStyle.fill;
///底下跟我畫個背景
canvas.drawRect(Rect.fromLTWH(0, 0, width, height), paint);
///頂上再畫個人
paint.color = Colors.black;
paint.style = PaintingStyle.stroke;
paint.strokeWidth = 10;
ui.Image image = await base64ToImage(imageFile,
width: width.toInt(), height: height.toInt());
canvas.drawImage(image, Offset.zero, paint);
// 轉(zhuǎn)換成圖片
///記錄畫的canvas
Picture picture = recorder.endRecording();
return await picture2ByteData(picture, width, height);
}
將Picture轉(zhuǎn)成ByteData再轉(zhuǎn)成Uint8list負責顯示和保存
///獲取到的picture 轉(zhuǎn)換成 ByteData
///[picture] canvas畫然后記錄的文件
///[width] 寬度
///[height] 高度
static Future<ByteData?> picture2ByteData(
ui.Picture picture, double width, double height) async {
ui.Image img = await picture.toImage(width.toInt(), height.toInt());
debugPrint('img的尺寸: $img');
ByteData? byteData = await img.toByteData(format: ui.ImageByteFormat.png);
return byteData;
}
/// 將ByteData 轉(zhuǎn)成 Uint8List
/// [data] ByteData數(shù)據(jù)
/// return [Uint8List] Uint8List
static byteData2Uint8List(ByteData data) {
return data.buffer.asUint8List();
}
保存圖片
///保存Uint8List 到相冊
///[image]Uint8List 數(shù)組
///[quality] 質(zhì)量
///[name] 保存的名字
static saveImage2Album(image, {quality = 100, name = "photo"}) async {
final result =
await ImageGallerySaver.saveImage(image, quality: quality, name: name);
return result;
}
完整demo 在 https://gitee.com/half_city/flutter_identification_photo