Flutter給圖片添加水印,有兩種方法
第一種:直接操作圖片怎囚,將水印文字與圖片一起編碼生成新的圖片;
圖中的日期就是水印颗圣。
首先需要引用到一個第三方庫,放于pubspec.yaml
中
path_provider: ^2.0.1 #路徑管理
image_picker: ^0.8.4+11 #拍照屁使,相冊
接下來看是如何實現(xiàn)的在岂,先看下業(yè)務(wù)代碼調(diào)用
//拍照
XFile? file = await ImagePicker.platform.getImage(source: ImageSource.camera);
//拍照圖傳至WaterMarkPage返回水印圖
Get.to(WaterMarkPage(file!.path))?.then((newSignImg){
//上傳水印圖
ApiCommonRequest.uploadFile(HttpUrls.api_img_upload, newSignImg, Constants.FILE_IMAGE, onSuccess: (String fileUrl) {
print("圖片上傳成功:${fileUrl}");
});
});
然后重點看下WaterMarkPage.dart代碼是如何生成水印圖的
import 'dart:io';
import 'dart:ui' as ui;
import 'package:app_flutter/base/base_page.dart';
import 'package:app_flutter/constant/font_styles.dart';
import 'package:app_flutter/pages/task/view/icon_text_button.dart';
import 'package:app_flutter/utils/date_utils.dart';
import 'package:app_flutter/utils/image_loader_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
///圖片生產(chǎn)水印
class WaterMarkPage extends BasePage {
//任務(wù)ID
late String imagePath;
WaterMarkPage(this.imagePath, {Key? key}) : super(key: key);
@override
State<WaterMarkPage> createState() => _WaterMarkPageState();
}
class _WaterMarkPageState extends BasePageState<WaterMarkPage> {
GlobalKey _globalKey = GlobalKey();
@override
AppBar buildAppBar() {
return AppBar(
title: Text(
"簽到圖片",
style: FontStyles.black(fontSize: 34.sp),
),
elevation: 0,
leading: BackButton(
color: Colors.black,
),
backgroundColor: Colors.transparent,
centerTitle: true,
actions: [
IconTextButton(
padding: EdgeInsets.only(right: 25.w),
text: "保存",
tapCallback: saveSignImg),
],
);
}
/**
* 保存簽到圖片
*/
Future<void> saveSignImg() async {
///通過globalkey將Widget保存為ui.Image
ui.Image _image = await ImageLoaderUtils.imageLoader.getImageFromWidget(_globalKey);
///異步將這張圖片保存在手機(jī)內(nèi)部存儲目錄下
String? localImagePath = await ImageLoaderUtils.imageLoader.saveImageByUIImage(_image, isEncode: false);
///保存完畢后關(guān)閉當(dāng)前頁面并將保存的圖片路徑返回到上一個頁面
Get.back(result: localImagePath);
}
@override
Widget buildBody(BuildContext context) {
return Container(
alignment: Alignment.center,
child: RepaintBoundary(
key: _globalKey,
child: Stack(
children: [
Image.file(
File(widget.imagePath),
width: 1.sw,
fit: BoxFit.fitWidth,
),
Positioned(
top: 2,
right: 2,
child: Text(
MDateUtils.dateNow(),
style: FontStyles.value(fontSize: 30.sp, color: Colors.white),
))
],
),
)
);
}
}
上面部分代碼沒有參考價值,主要參考saveSignImg()
方法即可蛮寂;
最后提供ImageLoaderUtils.dart
源碼
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'dart:ui';
import 'package:crypto/crypto.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';
/// 圖片加載工具類
class ImageLoaderUtils {
//私有化構(gòu)造
ImageLoaderUtils._();
//單例模式創(chuàng)建
static final ImageLoaderUtils imageLoader = ImageLoaderUtils._();
// 將一個Widget轉(zhuǎn)為image.Image對象
Future<ui.Image> getImageFromWidget(GlobalKey globalKey) async {
// globalKey為需要圖像化的widget的key
RenderRepaintBoundary? boundary =
globalKey.currentContext?.findRenderObject() as RenderRepaintBoundary?;
// 轉(zhuǎn)換為圖像
ui.Image img = await boundary!.toImage();
return img;
}
///將指定的文件保存到目錄空間中蔽午。
///[image] 這里是使用的ui包下的Image
///[picName] 保存到本地的文件(圖片)文件名,如test_image
///[endFormat]保存到本地的文件(圖片)文件格式酬蹋,如png及老,
///[isReplace]當(dāng)本地存在同名的文件(圖片)時,true就是替換
///[isEncode]對保存的文件(圖片)進(jìn)行編碼
/// 最終保存到本地的文件 (圖片)的名稱為 picName.endFormat
Future<String> saveImageByUIImage(ui.Image image,
{String? picName,
String endFormat = "png",
bool isReplace = true,
bool isEncode = true}) async {
///獲取本地磁盤路徑
/*
* 在Android平臺中獲取的是/data/user/0/com.studyyoun.flutterbookcode/app_flutter
* 此方法在在iOS平臺獲取的是Documents路徑
*/
Directory appDocDir = await getApplicationDocumentsDirectory();
String appDocPath = appDocDir.path;
///拼接目錄
if (picName == null || picName.trim().length == 0) {
///當(dāng)用戶沒有指定picName時范抓,取當(dāng)前的時間命名
picName = "${DateTime.now().millisecond.toString()}.$endFormat";
} else {
picName = "$picName.$endFormat";
}
if (isEncode) {
///對保存的圖片名字加密
picName = md5.convert(utf8.encode(picName)).toString();
}
appDocPath = "$appDocPath/$picName";
///校驗圖片是否存在
var file = File(appDocPath);
bool exist = await file.exists();
if (exist) {
if (isReplace) {
///如果圖片存在就進(jìn)行刪除替換
///如果新的圖片加載失敗骄恶,那么舊的圖片也被刪除了
await file.delete();
} else {
///如果圖片存在就不進(jìn)行下載
return "";
}
}
ByteData? byteData = await image.toByteData(format: ImageByteFormat.png);
Uint8List pngBytes = byteData!.buffer.asUint8List();
print("保存的圖片路徑 $appDocPath");
///將Uint8List的數(shù)據(jù)格式保存
await File(appDocPath).writeAsBytes(pngBytes);
return appDocPath;
}
}
參考文章 https://biglead.blog.csdn.net/article/details/106874804