flutter图片加水印
使用方法:拍张照片,将照片转换成File类型,我这里需要展示的水印是定位,所以传了一个Position过去方便使用,可以根据自身情况进行修改。一切准备就绪之后直接跳转到预览页ImageWatermarkPage.dart
主要是使用ImageLoaderUtils.imageLoader.getImageFromWidget(_globalKey)将节点转换成图片
///通过globalkey将Widget保存为ui.Image
ui.Image _image =
await ImageLoaderUtils.imageLoader.getImageFromWidget(_globalKey);
///异步将这张图片保存在手机内部存储目录下
String localImagePath =
await ImageLoaderUtils.saveImageByUIImage(_image, Map());
File fileaaa = File(localImagePath);
使用例:
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ImageWatermarkPage(
imgFile: img,// 需要加水印的file文件
position: _position,// 传递过去的定位
))).then((value) => {
setState(() {
img = value;// 显示加水印后的图片
})
});
工具类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 {
//私有化构造
ImageLoaderUtils._();
//单例模式创建
static final ImageLoaderUtils imageLoader = ImageLoaderUtils._();
// 将一个Widget转为image.Image对象
Future<ui.Image> getImageFromWidget(GlobalKey globalKey) async {
// globalKey为需要图像化的widget的key
RenderRepaintBoundary? boundary =
globalKey.currentContext?.findRenderObject() as RenderRepaintBoundary?;
// 转换为图像
ui.Image img = await boundary!.toImage(pixelRatio: 6);
return img;
}
///将指定的文件保存到目录空间中。
///[image] 这里是使用的ui包下的Image
///[picName] 保存到本地的文件(图片)文件名,如test_image
///[endFormat]保存到本地的文件(图片)文件格式,如png,
///[isReplace]当本地存在同名的文件(图片)时,true就是替换
///[isEncode]对保存的文件(图片)进行编码
/// 最终保存到本地的文件 (图片)的名称为 picName.endFormat
static Future<String> saveImageByUIImage(
ui.Image image, Map<dynamic, bool> map,
{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) {
///当用户没有指定picName时,取当前的时间命名
picName = "${DateTime.now().millisecond.toString()}.$endFormat";
} else {
picName = "$picName.$endFormat";
}
if (isEncode) {
///对保存的图片名字加密
picName = picName.toString();
}
appDocPath = "$appDocPath/$picName";
///校验图片是否存在
var file = File(appDocPath);
bool exist = await file.exists();
if (exist) {
if (isReplace) {
///如果图片存在就进行删除替换
///如果新的图片加载失败,那么旧的图片也被删除了
await file.delete();
} else {
///如果图片存在就不进行下载
return "";
}
}
ByteData? byteData = await image.toByteData(format: ImageByteFormat.png);
Uint8List pngBytes = byteData!.buffer.asUint8List();
print("保存的图片路径 $appDocPath");
///将Uint8List的数据格式保存
await File(appDocPath).writeAsBytes(pngBytes);
return appDocPath;
}
}
预览图片加水印后的页面ImageWatermarkPage.dart
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:geolocator/geolocator.dart';
import 'package:path_provider/path_provider.dart';
import 'ImageLoaderUtils.dart';
class ImageWatermarkPage extends StatefulWidget {
late final File imgFile;
late final Position position;
ImageWatermarkPage({required this.imgFile, required this.position})
: super(); // 这里也需要些@required
@override
_RawImageState createState() => _RawImageState();
}
class _RawImageState extends State<ImageWatermarkPage> {
///生成图像的层叠布局Stack的主键
GlobalKey _globalKey = GlobalKey();
DateTime date = DateTime.now();
///正在保存中
bool isSaving = false;
///生成目标图像的图片与水印部分
Widget buildWaterImageWidget() {
///可以为其子元素创建一个单独的子树
///相当于总树Widgets上的一个小分叉树枝
return RepaintBoundary(
///用于生成图像的Widget
child: Container(
///全屏显示
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Stack(
children: [
Center(
child: RepaintBoundary(
key: _globalKey,
child: Stack(
children: [
Image.file(
widget.imgFile,
fit: BoxFit.fill,
// width: MediaQuery.of(context).size.width,
// height: MediaQuery.of(context).size.height,
),
///右下角的水印部分
Positioned(
bottom: 20,
right: 20,
child: Container(
padding: EdgeInsets.only(
left: 8, right: 8, top: 2, bottom: 2),
decoration: BoxDecoration(
border:
Border.all(color: Colors.red, width: 1.0)),
child: Column(children: [
Text(
widget.position.latitude.toString(),
style: TextStyle(
fontSize: 14, color: Colors.white),
),
Text(
widget.position.latitude.toString(),
style: TextStyle(
fontSize: 14, color: Colors.white),
),
Text(
date.toString(),
style: TextStyle(
fontSize: 14, color: Colors.white),
)
]),
),
)
],
))),
// Image.asset(
// "image/img.png",
// fit: BoxFit.fill,
// width: MediaQuery.of(context).size.width,
// height: MediaQuery.of(context).size.height,
// ),
],
),
),
);
}
///保存水印图片的操作部分
Widget buildSaveWidget() {
///小对勾按钮显示在右上角
return Positioned(
top: 40,
right: 20,
child: IconButton(
icon: Icon(
Icons.check_circle,
color: Colors.blue,
size: 33,
),
onPressed: () async {
///更新页面显示
setState(() {
isSaving = true;
});
///通过globalkey将Widget保存为ui.Image
ui.Image _image =
await ImageLoaderUtils.imageLoader.getImageFromWidget(_globalKey);
///异步将这张图片保存在手机内部存储目录下
String localImagePath =
await ImageLoaderUtils.saveImageByUIImage(_image, Map());
File fileaaa = File(localImagePath);
///保存完毕后关闭当前页面并将保存的图片路径返回到上一个页面
Navigator.of(context).pop(fileaaa);
},
),
);
}
///取消操作的部分
Widget buildCancleWidget() {
return Positioned(
top: 40,
left: 20,
child: IconButton(
icon: Icon(
Icons.clear,
color: Colors.red,
size: 33,
),
onPressed: () {
Navigator.of(context).pop();
},
),
);
}
///正在保存图像时显示的进度
///一个小圆圈
Widget buildLoadingWidget() {
return isSaving ? CircularProgressIndicator() : Container();
}
@override
Widget build(BuildContext context) {
return Scaffold(
///页面背景为半透明的灰色
backgroundColor: Color(0x50cdcdcd),
///填充布局
body: Stack(
///约束未设置位置的子Widget剧中对齐
alignment: Alignment.center,
children: [
///生成目标图像的图片与水印部分
buildWaterImageWidget(),
///保存水印图片的操作部分
buildSaveWidget(),
///取消操作的部分
buildCancleWidget(),
///正在保存图像时显示的进度
buildLoadingWidget(),
],
),
);
}
}