You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter:图片叠加合成保存并分享功能实现问询

你要实现的这个功能叫做图像合成(Image Composition)——简单来说就是把两张图片在像素层面合并成一张新图。在Flutter里,我们可以通过image库处理像素级操作,配合path_provider获取存储路径保存合成图,最后用你已经在用的share库完成分享。下面是具体实现步骤:


第一步:添加依赖

在pubspec.yaml中补充以下依赖,然后执行flutter pub get安装:

dependencies:
  flutter:
    sdk: flutter
  image_picker: ^0.8.4+4 # 保持你当前使用的兼容版本
  share: ^2.0.4
  image: ^3.0.1          # 核心图像合成库
  path_provider: ^2.0.8  # 获取本地存储路径
  permission_handler: ^8.3.0 # 处理Android存储权限

第二步:实现图像合成与保存函数

在你的_MyHomePageState类中添加以下函数:

import 'package:image/image.dart' as img;
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:http/http.dart' as http;
import 'package:flutter/services.dart';

// 请求Android存储权限
Future<bool> _requestStoragePermission() async {
  var status = await Permission.storage.status;
  if (!status.isGranted) {
    status = await Permission.storage.request();
  }
  return status.isGranted;
}

// 合成图片并保存到本地
Future<File> _combineImages() async {
  if (_imageFile == null) return null;

  // 1. 先请求存储权限
  bool hasPermission = await _requestStoragePermission();
  if (!hasPermission) {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('需要存储权限来保存图片')),
    );
    return null;
  }

  try {
    // 2. 加载原图的像素数据
    img.Image originalImage = img.decodeImage(await _imageFile.readAsBytes());
    if (originalImage == null) throw Exception('无法加载选中的图片');

    // 3. 加载Logo(这里用网络图,也可以替换为本地Asset)
    var logoResponse = await http.get(Uri.parse('http://father-home.ru/wp-content/uploads/2018/05/cropped-logo8.png'));
    img.Image logoImage = img.decodeImage(logoResponse.bodyBytes);
    if (logoImage == null) throw Exception('无法加载Logo');

    // 4. 调整Logo大小(按原图宽度的1/5缩放,保持比例)
    int logoWidth = originalImage.width ~/ 5;
    int logoHeight = (logoImage.height * (logoWidth / logoImage.width)).toInt();
    img.Image resizedLogo = img.copyResize(logoImage, width: logoWidth, height: logoHeight);

    // 5. 将Logo绘制到原图左下角(保留16px边距)
    int offsetX = 16;
    int offsetY = originalImage.height - resizedLogo.height - 16;
    img.copyInto(
      originalImage,
      resizedLogo,
      dstX: offsetX,
      dstY: offsetY,
    );

    // 6. 保存合成后的图片到应用私有目录
    Directory appDir = await getApplicationDocumentsDirectory();
    String savePath = '${appDir.path}/composed_${DateTime.now().millisecondsSinceEpoch}.png';
    File saveFile = File(savePath);
    await saveFile.writeAsBytes(img.encodePng(originalImage));

    return saveFile;
  } catch (e) {
    print('合成图片出错: $e');
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('合成失败: ${e.toString()}')),
    );
    return null;
  }
}

如果你的Logo是本地Asset,替换Logo加载部分为:

// 加载本地Asset Logo
ByteData logoData = await rootBundle.load('assets/your_logo.png');
img.Image logoImage = img.decodeImage(logoData.buffer.asUint8List());

记得在pubspec.yaml中声明Asset:

assets:
  - assets/your_logo.png

第三步:修改分享函数

把你原来的_onShare函数替换为:

void _onShare() async {
  File composedFile = await _combineImages();
  if (composedFile != null) {
    await Share.shareFiles([composedFile.path], text: '分享合成后的图片');
  }
}

第四步:Android权限配置

在android/app/src/main/AndroidManifest.xml中添加权限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

针对Android 10及以上,在application标签内添加:

android:requestLegacyExternalStorage="true"

最后:恢复预览Logo的UI代码

你之前注释掉的预览Logo代码可以保留,让用户在合成前就能看到效果:

Positioned(
  bottom: 16,
  left: 16,
  width: 100,
  height: 100,
  child: Image.network(
    'http://father-home.ru/wp-content/uploads/2018/05/cropped-logo8.png'))

整个流程的核心逻辑是:加载两张图片的像素数据 → 调整Logo尺寸 → 将Logo像素复制到原图指定位置 → 保存合成图 → 分享文件。这样就能实现你需要的功能啦!

内容的提问来源于stack exchange,提问作者Singorenko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:43:59