美文网首页Android
Flutter给图片添加水印

Flutter给图片添加水印

作者: 差点长成一枚帅哥 | 来源:发表于2022-06-29 15:04 被阅读0次

    Flutter给图片添加水印,有两种方法
    第一种:直接操作图片,将水印文字与图片一起编码生成新的图片;

    第二种:用Stack组件,childs中放两个元素,一个是Image,一个是Text,最后用RepaintBoundary将Stack包起来,从Widget中截取获得合成后的水印图(本文介绍的是这种,也是博主推荐的)。 image.png
    图中的日期就是水印。

    首先需要引用到一个第三方库,放于pubspec.yaml

    path_provider: ^2.0.1       #路径管理
    image_picker: ^0.8.4+11     #拍照,相册
    

    接下来看是如何实现的,先看下业务代码调用

    //拍照
    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';
    
    ///图片生产水印
    class WaterMarkPage extends BasePage {
      //任务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);
    
        ///异步将这张图片保存在手机内部存储目录下
        String? localImagePath =  await ImageLoaderUtils.imageLoader.saveImageByUIImage(_image, isEncode: false);
        ///保存完毕后关闭当前页面并将保存的图片路径返回到上一个页面
        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 {
    
      //私有化构造
      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();
        return img;
      }
    
      ///将指定的文件保存到目录空间中。
      ///[image] 这里是使用的ui包下的Image
      ///[picName] 保存到本地的文件(图片)文件名,如test_image
      ///[endFormat]保存到本地的文件(图片)文件格式,如png,
      ///[isReplace]当本地存在同名的文件(图片)时,true就是替换
      ///[isEncode]对保存的文件(图片)进行编码
      ///  最终保存到本地的文件 (图片)的名称为 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) {
          ///当用户没有指定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 "";
          }
        }
        ByteData? byteData = await image.toByteData(format: ImageByteFormat.png);
        Uint8List pngBytes = byteData!.buffer.asUint8List();
        print("保存的图片路径 $appDocPath");
    
        ///将Uint8List的数据格式保存
        await File(appDocPath).writeAsBytes(pngBytes);
    
        return appDocPath;
      }
    }
    

    参考文章 https://biglead.blog.csdn.net/article/details/106874804

    相关文章

      网友评论

        本文标题:Flutter给图片添加水印

        本文链接:https://www.haomeiwen.com/subject/odgtbrtx.html