题记
—— 执剑天涯,从你的点滴积累开始,所及之处,必精益求精,即是折腾每一天。

重要消息

  • 网易云【玩转大前端】配套课程

  • EDU配套 教程

  • Flutter开发的点滴积累系列文章


添加水印,两种实现思路,一种是将图片与水印解码,然后混编再编码,另一种是通过Widget的方式合成。

在这里采用的实现思路是使用层叠布局Stack加载图片以及水印部分,水印部分可能是一个现成的图片也可能是一个文字等其他样式的组件,然后将这个Stack使用RepaintBoundary组件包裹起来,然后通过Widget生成图片的功能从而达到实现保存图片为水印效果。

如图下图所示,加载的本地资源目录下的一张图片,点击右上角的对勾然后将图片与右下角的文字合面一起生成一张新图片保存在手机目录存储中。


然后在Android Studio控制台中输入的日志如下:

flutter: 保存的图片地址为/Users/androidlongs/Library/Developer/CoreSimulator/Devices/DD736D17-AB7D-47CA-81C5-2D5283944F6B/data/Containers/Data/Application/AE08A4F2-9DFE-4A23-80A7-7BEB153A30B0/Documents/723.png

因为这里使用的是 ios 模拟器,所以这里保存在了模拟器使用的内存空间中,打开保存的路径查看

从保存到的图片中可以看到水印已经添加上去了

在这里将显示将上述所有显示与操作的UI功能封装在一个StatefulWidget,在这里可以使用一种新的方式打开这个页面,当显示的图片没有填充屏幕时,四周会是暗色半透明效果,也就是打开的Widet页面背景透明,代码如下:

///背景透明的跳转
Navigator.of(context).push(PageRouteBuilder(opaque: false,pageBuilder: (context, animation, secondaryAnimation) {return ImageWatermarkPage();})).then((value) {if(value!=null){///print("保存的图片地址为$value");}


对于页面ImageWatermarkPage就是实现了显示图片以及水印展示功能,代码如下:

class ImageWatermarkPage extends StatefulWidget {@override_RawImageState createState() => _RawImageState();
}class _RawImageState extends State<ImageWatermarkPage> {///生成图像的层叠布局Stack的主键GlobalKey _globalKey = GlobalKey();///正在保存中bool isSaving = false;@overrideWidget build(BuildContext context) {return Scaffold(///页面背景为半透明的灰色backgroundColor: Color(0x50cdcdcd),///填充布局body:Stack(///约束未设置位置的子Widget剧中对齐alignment: Alignment.center,children: [///生成目标图像的图片与水印部分buildWaterImageWidget(),///保存水印图片的操作部分buildSaveWidget(),///取消操作的部分buildCancleWidget(),///正在保存图像时显示的进度buildLoadingWidget(),],),);}... 省略
}

生成目标图像的图片与水印部分封装在buildWaterImageWidget方法中,在这里就是通过RepaintBoundary组件将图片与水印部分通过层叠布局结合在一起的UI构建,代码如下:

  ///生成目标图像的图片与水印部分Widget buildWaterImageWidget() {///可以为其子元素创建一个单独的子树///相当于总树Widgets上的一个小分叉树枝return RepaintBoundary(key: _globalKey,///用于生成图像的Widgetchild: Container(///全屏显示width: MediaQuery.of(context).size.width,height: MediaQuery.of(context).size.height,child: Stack(children: [Image.asset("assets/images/2.0x/s03.jpeg",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: Text("这里是水印",style: TextStyle(fontSize: 14,color: Colors.white),),),)],),),);}

对于方法buildSaveWidget就是封装了构建保存对勾以及功能的方法,代码如下:

 ///保存水印图片的操作部分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.Imageui.Image _image = await ImageLoaderUtils.imageLoader.getImageFromWidget(_globalKey);///异步将这张图片保存在手机内部存储目录下String localImagePath =  await ImageUtils.imageUtils.saveImageByUIImage(_image, isEncode: false);///保存完毕后关闭当前页面并将保存的图片路径返回到上一个页面Navigator.of(context).pop(localImagePath);},),);}

取消操作的部分就是页面左上角的关闭按钮,功能比较简单在buildCancleWidget方法中构建,代码如下:

///取消操作的部分Widget buildCancleWidget() {return  Positioned(top: 40,left: 20,child: IconButton(icon: Icon(Icons.clear,color: Colors.red,size: 33,),onPressed: () {Navigator.of(context).pop();},),);}

buildLoadingWidget方法中封装了当用户点击保存时,更新 isSaving的值为true,然后在页面上显示一个小圆圈,以给用户一个正在操作中的提示反馈,代码如下:

  ///正在保存图像时显示的进度///一个小圆圈Widget buildLoadingWidget() {return isSaving?CircularProgressIndicator():Container();}

在这里将Widget保存为图像的方法ImageLoaderUtils的getImageFromWidget方法以及将Image保存到手机存储中的方法saveImageByUIImage代码如下:

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: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的keyRenderRepaintBoundary boundary = globalKey.currentContext.findRenderObject();// 转换为图像ui.Image img = await boundary.toImage();return img;}///将指定的文件保存到目录空间中。///[image] 这里是使用的ui包下的Image///[picName] 保存到本地的文件(图片)文件名,如test_image///[endFormat]保存到本地的文件(图片)文件格式,如png,///[isReplace]当本地存在同名的文件(图片)时,true就是替换///[isEncode]对保存的文件(图片)进行编码///  最终保存到本地的文件 (图片)的名称为 picName.endFormatFuture<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) {///当用户没有指定picName时,取当前的时间命名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) {///如果图片存在就进行删除替换///如果新的图片加载失败,那么旧的图片也被删除了await file.delete();} else {///如果图片存在就不进行下载return null;}}ByteData byteData = await image.toByteData(format: ImageByteFormat.png);Uint8List pngBytes = byteData.buffer.asUint8List();print("保存的图片路径 $appDocPath");///将Uint8List的数据格式保存await File(appDocPath).writeAsBytes(pngBytes);return appDocPath;}}

在这里使用到了path_provider来获取手机的存储目录,所以需要添加依赖:

  #获取手机存储目录path_provider: ^1.6.9

关于path_provider的最新版本可在pub中国仓库中进行查看点击这里查看

Flutter图片添加水印功能,Flutter保存Widget为图片相关推荐

  1. php绘图技术加水印,PHP图片添加水印功能示例小结

    本文实例总结了PHP图片添加水印功能.分享给大家供大家参考,具体如下: 例1.很简单图下添加水印函数 /** * 追加水印 * * @param string $source_img 原始图片url ...

  2. html中实现添加水印的功能,JS模拟实现图片添加水印功能

    JS模拟实现图片添加水印功能 ======================================================== 今天看到网友发帖求助如果在图片上自动添加水印的功能,于是 ...

  3. JS模拟实现图片添加水印功能

    JS模拟实现图片添加水印功能 ======================================================== 今天看到网友发帖求助如果在图片上自动添加水印的功能,于是 ...

  4. Java图片添加水印功能

    图片添加水印 需求是需要添加多个斜的水印,如果只是添加单个水印可以参考这个:传送门 直接上代码: private static void waterMarkAdd(String sourceFile, ...

  5. html2canvas给图片添加水印,小程序用Canvas给图片加水印,拼接图片,制作名片

    Canvas是微信小程序中的一个原生组件,因此我们在使用它的时候要特别注意微信小程序对原生组件的使用说明.canvas这个组件其实就是一个画布,你可以在上面画很多你用其他方式不好实现的内容.下面我就将 ...

  6. PHP用gd库给图片添加水印,php用GD库给图片添加水印

    php用GD库给图片添加文字水印,整个代码比较简单,DEMO如下: /*打开图片*/ //1.配置图片路径 $src = "aeroplane.jpg"; //2.获取图片信息 $ ...

  7. ios 从assets加载图片_Flutter图片添加水印功能,Flutter保存Widget为图片

    添加水印,两种实现思路,一种是将图片与水印解码,然后混编再编码,另一种是通过Widget的方式合成. 在这里采用的实现思路是使用层叠布局Stack加载图片以及水印部分,水印部分可能是一个现成的图片也可 ...

  8. php给网页加水印_php实现图片添加水印功能

    /** * 图片加水印(适用于png/jpg/gif格式) * * @author flynetcn * * @param $srcImg 原图片 * @param $waterImg 水印图片 * ...

  9. android 图片查看功能吗,Android仿百度图片查看功能

    我们知道,进入百度图片后,输入一个关键字后,首先看到的是很多缩略图,当我们点击某张缩略图时,我们就可以进入到大图显示页面,在大图显示页面,中包含了一个图片画廊,同时当前大图为刚刚我们点击的那张图片.现 ...

最新文章

  1. python统计字符串个数_python字符串中字符出现次数(python获取字符串个数)
  2. 识别字符串中的表达式
  3. [LCS]LCS2005服务器应用程序
  4. O(n^2)以及O(nlogn)时间复杂度的排序算法
  5. 史上最完整的MySQL注入
  6. 推荐系统专利:一种信息推荐系统及方法
  7. 不用for循环快速合并txt文本文件
  8. vm安装centos,黑屏或黑屏且左上角有光标闪动
  9. python 二维码生成器_python二维码生成器
  10. 计算机启动后需重启才能正常显示,电脑开机老是要重启N次后才能正常
  11. python入门学习_PythonTip
  12. 基于python的毕业论文邮箱收发系统_基于python语言的自动化邮件发送总结
  13. 【MicroPython ESP32】I2C功能使用介绍
  14. ros2上怎样才能玩rmf?
  15. 计算机图形学(四)几何变换_5_三维空间的几何变换_1_三维平移
  16. nginx变量传递给php,php-从nginx将参数传递给auth_request模块
  17. 重磅,2020广播电视科技创新奖揭晓
  18. 大学计算机教学内容体系,大学计算机教学内容体系建设与改革论文
  19. python 游戏辅助脚本_python版微信跳一跳游戏辅助
  20. 端口大全汇总--后续有更新会添加

热门文章

  1. 日紫白飞星算法_紫白飞星择日法
  2. Excel工具类(详细版)
  3. 无鸭不过秋,这样吃鸭润燥解乏!
  4. 可可网络验证9.3、9.5版本
  5. UPC 维修栅栏(基本状态转移)
  6. 全面质量管理理论中的五个影响产品质量的主要因素
  7. 2021年中国定制家具行业现状分析:“量身定制”需求逐年增加[图]
  8. 将安卓手机屏幕内容投射到电脑屏幕上
  9. 倪光南院士 你该检讨一下了
  10. ubuntu 17\18.04 调节鼠标指针速度