flutter图片加水印

729 阅读4分钟

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(),
        ],
      ),
    );
  }
}