图片拼图工具应用
欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net
适配的第三方库地址:
- image_picker - 图片选择
- image - 图片处理(纯Dart库)
- image_gallery_saver - 图片保存
- share_plus - 分享功能
一、项目概述
运行效果图





1.1 应用简介
图片拼图工具是一款创意十足的图片拼接应用,帮助用户将多张图片拼接成精美的拼图作品。应用提供11种拼图模板,支持2-9张图片的灵活组合,用户可自定义边框样式、圆角效果、拼图比例和背景颜色,打造独一无二的拼图效果。完成的拼图可一键保存到相册或分享到社交平台,让美好瞬间更加精彩。
应用以活力的粉色为主色调,象征创意与活力。涵盖创建、模板、历史、设置四大模块。用户可以轻松选择图片、挑选模板、调整样式、生成拼图,实现图片的创意组合。
1.2 核心功能
| 功能模块 | 功能描述 | 实现方式 |
|---|---|---|
| 图片选择 | 从相册选择多张图片 | image_picker |
| 模板选择 | 11种拼图模板可选 | 模板枚举 |
| 边框样式 | 无边框、细、中、粗边框 | 样式设置 |
| 圆角效果 | 直角到圆形五种圆角 | 样式设置 |
| 拼图比例 | 正方形、4:3、16:9等 | 比例设置 |
| 背景颜色 | 多种背景色可选 | 颜色选择 |
| 图片排序 | 拖拽调整图片顺序 | ReorderableListView |
| 保存相册 | 将拼图保存到相册 | image_gallery_saver |
| 分享功能 | 分享拼图到社交平台 | share_plus |
1.3 拼图模板定义
| 序号 | 模板名称 | 图片数 | 行数 | 列数 | 描述 |
|---|---|---|---|---|---|
| 1 | 2宫格 | 2 | 1 | 2 | 横向排列2张 |
| 2 | 3宫格 | 3 | 1 | 3 | 横向排列3张 |
| 3 | 4宫格 | 4 | 2 | 2 | 经典2×2布局 |
| 4 | 6宫格 | 6 | 2 | 3 | 2×3布局 |
| 5 | 9宫格 | 9 | 3 | 3 | 经典3×3布局 |
| 6 | 横向2图 | 2 | 1 | 2 | 横向拼接 |
| 7 | 横向3图 | 3 | 1 | 3 | 横向拼接 |
| 8 | 纵向2图 | 2 | 2 | 1 | 纵向拼接 |
| 9 | 纵向3图 | 3 | 3 | 1 | 纵向拼接 |
| 10 | 左1右2 | 3 | 2 | 2 | 左侧大图右侧小图 |
| 11 | 上1下2 | 3 | 2 | 2 | 上方大图下方小图 |
1.4 边框样式定义
| 序号 | 样式名称 | 宽度 | 描述 |
|---|---|---|---|
| 1 | 无边框 | 0px | 图片无缝拼接 |
| 2 | 细边框 | 2px | 细线分隔 |
| 3 | 中等 | 4px | 适中边框 |
| 4 | 粗边框 | 8px | 明显分隔 |
1.5 圆角样式定义
| 序号 | 样式名称 | 圆角 | 描述 |
|---|---|---|---|
| 1 | 直角 | 0px | 锐利边角 |
| 2 | 小圆角 | 8px | 微微圆润 |
| 3 | 中圆角 | 16px | 适中圆角 |
| 4 | 大圆角 | 32px | 明显圆角 |
| 5 | 圆形 | 100px | 完全圆形 |
1.6 拼图比例定义
| 序号 | 比例名称 | 比例值 | 适用场景 |
|---|---|---|---|
| 1 | 正方形 | 1:1 | Instagram、头像 |
| 2 | 4:3 | 4:3 | 传统照片 |
| 3 | 3:4 | 3:4 | 竖版照片 |
| 4 | 16:9 | 16:9 | 宽屏展示 |
| 5 | 9:16 | 9:16 | 手机壁纸 |
1.7 技术栈
| 技术领域 | 技术选型 | 版本要求 |
|---|---|---|
| 开发框架 | Flutter | >= 3.0.0 |
| 编程语言 | Dart | >= 2.17.0 |
| 设计规范 | Material Design 3 | - |
| 图片选择 | image_picker | >= 1.0.4 |
| 图片处理 | image | >= 4.1.7 |
| 图片保存 | image_gallery_saver | >= 2.0.3 |
| 分享功能 | share_plus | >= 7.2.2 |
| 目标平台 | 鸿蒙OS / Android / iOS | API 21+ |
1.8 项目结构
lib/
└── main_image_collage.dart
├── ImageCollageApp # 应用入口
├── CollageTemplate # 拼图模板枚举
├── BorderStyle # 边框样式枚举
├── CornerStyle # 圆角样式枚举
├── CollageRatio # 拼图比例枚举
├── CollageImage # 图片信息模型
├── ImageCollageHomePage # 主页面(底部导航)
├── _buildCreatePage # 创建页面
├── _buildTemplatesPage # 模板页面
├── _buildHistoryPage # 历史记录页
├── _buildSettingsPage # 设置页
├── _generateCollageImage # 生成拼图图片
└── _buildCollageGrid # 拼图网格预览
二、系统架构
2.1 整体架构图
Data Layer
Business Layer
Presentation Layer
主页面
ImageCollageHomePage
创建页
模板页
历史页
设置页
模板选择器
拼图预览
图片选择器
样式设置
模板网格
历史列表
图片选择器
ImagePicker
拼图生成器
CollageGenerator
保存管理器
SaveManager
CollageImage
图片信息
CollageTemplate
拼图模板
BorderStyle
边框样式
CornerStyle
圆角样式
CollageRatio
拼图比例
2.2 类图设计
uses
uses
uses
uses
manages
ImageCollageApp
+Widget build()
<<enumeration>>
CollageTemplate
+String label
+int count
+int rows
+int cols
+IconData icon
+grid2()
+grid3()
+grid4()
+grid6()
+grid9()
+horizontal2()
+horizontal3()
+vertical2()
+vertical3()
+left1right2()
+top1bottom2()
<<enumeration>>
BorderStyle
+String label
+double width
+none()
+thin()
+medium()
+thick()
<<enumeration>>
CornerStyle
+String label
+double radius
+none()
+small()
+medium()
+large()
+round()
<<enumeration>>
CollageRatio
+String label
+double ratio
+square()
+ratio43()
+ratio34()
+ratio169()
+ratio916()
CollageImage
+String id
+File file
+String name
+int order
ImageCollageHomePage
-int _currentIndex
-List<CollageImage> _selectedImages
-CollageTemplate _selectedTemplate
-BorderStyle _borderStyle
-CornerStyle _cornerStyle
-CollageRatio _collageRatio
+pickImages()
+removeImage()
+reorderImages()
+generateCollageImage()
+saveCollage()
+shareCollage()
2.3 页面导航流程
边框
圆角
比例
背景
保存
分享
重排
应用启动
创建页
选择模板
选择图片
预览拼图
调整样式
设置边框样式
设置圆角效果
设置拼图比例
设置背景颜色
操作选择
保存到相册
分享拼图
拖拽调整顺序
模板页
浏览所有模板
选择模板
历史页
查看历史拼图
2.4 拼图生成流程
文件系统 拼图生成器 创建页 用户 文件系统 拼图生成器 创建页 用户 loop [处理每张图片] 选择模板和图片 显示拼图预览 点击保存/分享 生成拼图图片 计算画布尺寸 填充背景颜色 读取原图 返回图片数据 解码图片 调整尺寸 合成到画布 保存拼图文件 返回文件路径 保存/分享成功
三、核心模块设计
3.1 数据模型设计
3.1.1 拼图模板枚举 (CollageTemplate)
dart
enum CollageTemplate {
grid2(label: '2宫格', count: 2, rows: 1, cols: 2, icon: Icons.grid_view),
grid3(label: '3宫格', count: 3, rows: 1, cols: 3, icon: Icons.view_week),
grid4(label: '4宫格', count: 4, rows: 2, cols: 2, icon: Icons.grid_4x4),
grid6(label: '6宫格', count: 6, rows: 2, cols: 3, icon: Icons.apps),
grid9(label: '9宫格', count: 9, rows: 3, cols: 3, icon: Icons.apps_outlined),
// ... 其他模板
final String label;
final int count;
final int rows;
final int cols;
final IconData icon;
const CollageTemplate({
required this.label,
required this.count,
required this.rows,
required this.cols,
required this.icon,
});
}
3.1.2 边框样式枚举 (BorderStyle)
dart
enum BorderStyle {
none(label: '无边框', width: 0),
thin(label: '细边框', width: 2),
medium(label: '中等', width: 4),
thick(label: '粗边框', width: 8);
final String label;
final double width;
const BorderStyle({
required this.label,
required this.width,
});
}
3.1.3 图片信息模型 (CollageImage)
dart
class CollageImage {
final String id;
final File file;
final String name;
final int order;
const CollageImage({
required this.id,
required this.file,
required this.name,
required this.order,
});
}
3.1.4 模板使用分布
35% 25% 15% 15% 10% 拼图模板使用分布示例 4宫格 9宫格 6宫格 2宫格 其他
3.2 页面结构设计
3.2.1 主页面布局
ImageCollageHomePage
IndexedStack
创建页
模板页
历史页
设置页
NavigationBar
创建 Tab
模板 Tab
历史 Tab
设置 Tab
3.2.2 创建页结构
创建页
SliverAppBar
模板选择器
拼图预览
图片选择器
样式设置
操作按钮
横向滚动模板列表
拼图网格预览
可排序列表
拖拽排序
边框样式
圆角样式
拼图比例
背景颜色
3.2.3 模板页结构
模板页
SliverAppBar
模板网格
3列网格布局
模板卡片
图标
名称
图片数
3.3 拼图生成逻辑
左1右2
上1下2
普通
是
否
开始生成
计算画布尺寸
创建空白画布
填充背景颜色
遍历图片列表
读取图片文件
解码图片数据
计算单元格位置
特殊模板?
左侧大图右侧小图
上方大图下方小图
标准网格布局
调整图片尺寸
合成到画布
还有图片?
编码输出图片
返回结果
3.4 图片排序逻辑
拖拽开始
记录起始位置
拖拽移动
更新视觉位置
拖拽结束
获取目标位置
移除原位置元素
插入到新位置
更新所有元素顺序
刷新UI
四、UI设计规范
4.1 配色方案
应用以活力的粉色为主色调,象征创意与活力:
| 颜色类型 | 色值 | 用途 |
|---|---|---|
| 主色 | #E91E63 (Pink) | 导航、主题元素 |
| 辅助色 | #F48FB1 | 次要按钮 |
| 第三色 | #FCE4EC | 背景装饰 |
| 强调色 | #C2185B | 重要操作 |
| 背景色 | #FAFAFA | 页面背景 |
| 卡片背景 | #FFFFFF | 信息卡片 |
| 成功色 | #4CAF50 | 保存成功 |
| 分享色 | #2196F3 | 分享按钮 |
4.2 模板配色
| 模板类型 | 背景色建议 | 适用场景 |
|---|---|---|
| 4宫格 | 白色/黑色 | 日常拼图 |
| 9宫格 | 白色 | 社交分享 |
| 横向拼接 | 黑色 | 风景展示 |
| 纵向拼接 | 白色 | 人物展示 |
| 特殊模板 | 灰色 | 创意拼图 |
4.3 字体规范
| 元素 | 字号 | 字重 | 颜色 |
|---|---|---|---|
| 页面标题 | 24px | Bold | 主色 |
| 模板名称 | 14px | Bold | 黑色 |
| 图片数量 | 12px | Regular | 灰色 |
| 按钮文字 | 14px | Medium | 白色 |
| 提示文字 | 12px | Regular | 灰色 |
4.4 组件规范
4.4.1 模板选择器
┌─────────────────────────────────────┐
│ 选择模板 3/4 │
│ │
│ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │
│ │ ▦ │ │ ▦ │ │ ▦ │ │ ▦ │ │ ▦ │ │
│ │2格│ │3格│ │4格│ │6格│ │9格│ │
│ └───┘ └───┘ └───┘ └───┘ └───┘ │
└─────────────────────────────────────┘
4.4.2 拼图预览
┌─────────────────────────────────────┐
│ 拼图预览 │
│ │
│ ┌─────────────────────────────┐ │
│ │ ┌─────┐ ┌─────┐ ┌─────┐ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ 图1 │ │ 图2 │ │ 图3 │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ └─────┘ └─────┘ └─────┘ │ │
│ │ ┌─────┐ ┌─────┐ ┌─────┐ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ 图4 │ │ 图5 │ │ 图6 │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ └─────┘ └─────┘ └─────┘ │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────┘
4.4.3 图片选择器
┌─────────────────────────────────────┐
│ 已选图片 [添加] [清空] │
│ │
│ ≡ [图片] image_001.jpg ✕ │
│ 位置 1 │
│ │
│ ≡ [图片] image_002.jpg ✕ │
│ 位置 2 │
│ │
│ ≡ [图片] image_003.jpg ✕ │
│ 位置 3 │
└─────────────────────────────────────┘
4.4.4 样式设置
┌─────────────────────────────────────┐
│ 样式设置 │
│ │
│ 边框样式 │
│ [无边框] [细边框] [中等] [粗边框] │
│ │
│ 圆角样式 │
│ [直角] [小圆角] [中圆角] [大圆角] [圆形]│
│ │
│ 拼图比例 │
│ [正方形] [4:3] [3:4] [16:9] [9:16] │
│ │
│ 背景颜色 │
│ ● ○ ○ ○ ○ │
│ 黑色 白色 灰色 蓝色 粉色 │
└─────────────────────────────────────┘
4.4.5 操作按钮
┌─────────────────────────────────────┐
│ │
│ [💾 保存到相册] │
│ │
│ [📤 分享拼图] │
│ │
└─────────────────────────────────────┘
五、核心功能实现
5.1 图片选择实现
dart
Future<void> _pickImages() async {
try {
final remaining = _selectedTemplate.count - _selectedImages.length;
if (remaining <= 0) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('已达到模板最大图片数')),
);
return;
}
final List<XFile> images = await _imagePicker.pickMultiImage();
if (images.isEmpty) return;
int addedCount = 0;
for (var image in images) {
if (_selectedImages.length >= _selectedTemplate.count) break;
final collageImage = CollageImage(
id: 'img_${DateTime.now().millisecondsSinceEpoch}_${image.name}',
file: File(image.path),
name: image.name,
order: _selectedImages.length,
);
setState(() {
_selectedImages.add(collageImage);
});
addedCount++;
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('选择图片失败: $e')),
);
}
}
5.2 拼图生成实现
dart
Future<img.Image?> _generateCollageImage() async {
if (_selectedImages.isEmpty) return null;
final outputSize = 1200;
final borderPx = _borderStyle.width.toInt();
final totalWidth = outputSize;
final totalHeight = _collageRatio.ratio >= 1
? (outputSize / _collageRatio.ratio).round()
: outputSize;
final result = img.Image(width: totalWidth, height: totalHeight);
// 填充背景
final bgColor = img.ColorRgba8(
_backgroundColor.red,
_backgroundColor.green,
_backgroundColor.blue,
255,
);
img.fill(result, color: bgColor);
final template = _selectedTemplate;
final cols = template.cols;
final rows = template.rows;
final cellWidth = (totalWidth - borderPx * (cols + 1)) ~/ cols;
final cellHeight = (totalHeight - borderPx * (rows + 1)) ~/ rows;
for (int i = 0; i < _selectedImages.length && i < template.count; i++) {
final imageItem = _selectedImages[i];
final bytes = await imageItem.file.readAsBytes();
final decodedImage = img.decodeImage(bytes);
if (decodedImage == null) continue;
final row = i ~/ cols;
final col = i % cols;
final resizedImage = img.copyResize(
decodedImage,
width: cellWidth,
height: cellHeight,
);
final x = borderPx + col * (cellWidth + borderPx);
final y = borderPx + row * (cellHeight + borderPx);
img.compositeImage(result, resizedImage, dstX: x, dstY: y);
}
return result;
}
5.3 图片排序实现
dart
void _reorderImages(int oldIndex, int newIndex) {
setState(() {
if (newIndex > oldIndex) {
newIndex -= 1;
}
final item = _selectedImages.removeAt(oldIndex);
_selectedImages.insert(newIndex, item);
// 更新顺序
for (int i = 0; i < _selectedImages.length; i++) {
_selectedImages[i] = CollageImage(
id: _selectedImages[i].id,
file: _selectedImages[i].file,
name: _selectedImages[i].name,
order: i,
);
}
});
}
5.4 保存拼图实现
dart
Future<void> _saveCollage() async {
if (_selectedImages.isEmpty) return;
setState(() {
_isProcessing = true;
});
try {
final collageImage = await _generateCollageImage();
if (collageImage == null) {
throw Exception('生成拼图失败');
}
final tempDir = await getTemporaryDirectory();
final filePath = '${tempDir.path}/collage_${DateTime.now().millisecondsSinceEpoch}.png';
final file = File(filePath);
await file.writeAsBytes(img.encodePng(collageImage));
final bytes = await file.readAsBytes();
final result = await ImageGallerySaver.saveImage(
bytes,
quality: 100,
name: 'collage_${DateTime.now().millisecondsSinceEpoch}',
);
setState(() {
_isProcessing = false;
});
if (result['isSuccess'] == true) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('拼图已保存到相册')),
);
}
} catch (e) {
setState(() {
_isProcessing = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('保存失败: $e')),
);
}
}
5.5 分享拼图实现
dart
Future<void> _shareCollage() async {
if (_selectedImages.isEmpty) return;
setState(() {
_isProcessing = true;
});
try {
final collageImage = await _generateCollageImage();
if (collageImage == null) {
throw Exception('生成拼图失败');
}
final tempDir = await getTemporaryDirectory();
final filePath = '${tempDir.path}/collage_share_${DateTime.now().millisecondsSinceEpoch}.png';
final file = File(filePath);
await file.writeAsBytes(img.encodePng(collageImage));
setState(() {
_isProcessing = false;
});
await Share.shareXFiles(
[XFile(filePath)],
text: '分享我的拼图',
);
} catch (e) {
setState(() {
_isProcessing = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('分享失败: $e')),
);
}
}
六、交互设计
6.1 图片选择流程
文件系统 图片选择器 创建页 用户 文件系统 图片选择器 创建页 用户 loop [处理每张图- 片] 点击添加图片 打开相册 显示图片列表 选择图片 返回选中图片 创建CollageImage 添加到列表 显示已选图片
6.2 拼图生成流程
否
是
是
否
点击保存/分享
是否有图片?
提示选择图片
设置处理状态
计算画布尺寸
创建空白画布
填充背景颜色
遍历图片列表
读取原图
解码图片
计算位置尺寸
调整图片大小
合成到画布
还有图片?
编码输出PNG
保存/分享文件
6.3 样式调整流程
满意
满意
选择模板
选择图片
预览拼图
调整边框
调整圆角
调整比例
调整背景
保存拼图
分享拼图
七、扩展功能规划
7.1 后续版本规划
2024-01-07 2024-01-14 2024-01-21 2024-01-28 2024-02-04 2024-02-11 2024-02-18 2024-02-25 2024-03-03 2024-03-10 2024-03-17 2024-03-24 2024-03-31 2024-04-07 基础UI框架 模板选择功能 拼图生成功能 更多模板 滤镜效果 文字贴纸 自由拼图 智能布局 模板社区 V1.0 基础版本 V1.1 增强版本 V1.2 进阶版本 图片拼图工具开发计划
7.2 功能扩展建议
7.2.1 滤镜效果
滤镜功能:
- 亮度对比度调整
- 色彩饱和度
- 复古滤镜
- 黑白滤镜
7.2.2 文字贴纸
贴纸功能:
- 添加文字
- 表情贴纸
- 日期水印
- 自定义贴纸
7.2.3 自由拼图
自由功能:
- 自由拖拽位置
- 自由缩放大小
- 图层管理
- 自定义模板保存
八、注意事项
8.1 开发注意事项
-
内存管理:处理大图片时注意内存释放
-
权限申请:确保存储权限正确申请
-
图片质量:输出高质量拼图图片
-
模板适配:特殊模板需要单独处理布局逻辑
-
用户体验:实时预览拼图效果
8.2 常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 图片选择失败 | 权限未授予 | 引导用户授权 |
| 拼图生成失败 | 内存不足 | 分批处理图片 |
| 保存失败 | 存储空间不足 | 提示清理空间 |
| 图片变形 | 比例不匹配 | 使用cover模式 |
| 预览卡顿 | 图片过大 | 压缩预览图 |
8.3 使用技巧
🖼️ 图片拼图工具使用技巧 🖼️
选择技巧
- 根据图片数量选择模板
- 注意图片比例一致性
- 选择合适的拼图比例
- 预览效果再保存
排版技巧
- 重要图片放显眼位置
- 色彩搭配要协调
- 适当使用边框分隔
- 背景色与图片呼应
分享技巧
- 选择适合平台的比例
- 注意图片清晰度
- 添加文字说明
- 选择合适时机分享
九、运行说明
9.1 环境要求
| 环境 | 版本要求 |
|---|---|
| Flutter SDK | >= 3.0.0 |
| Dart SDK | >= 2.17.0 |
| 鸿蒙OS | API 21+ |
| Android | API 21+ |
| iOS | 12.0+ |
9.2 依赖配置
在 pubspec.yaml 中添加以下依赖:
yaml
dependencies:
flutter:
sdk: flutter
image_picker: ^1.0.4
image: ^4.1.7
image_gallery_saver: ^2.0.3
share_plus: ^7.2.2
path_provider: ^2.1.4
9.3 运行命令
bash
# 查看可用设备
flutter devices
# 运行到Web服务器
flutter run -d web-server -t lib/main_image_collage.dart --web-port 8148
# 运行到鸿蒙设备
flutter run -d 127.0.0.1:5555 lib/main_image_collage.dart
# 运行到Android设备
flutter run -d android lib/main_image_collage.dart
# 代码分析
flutter analyze lib/main_image_collage.dart
9.4 权限配置
Android权限 (android/app/src/main/AndroidManifest.xml)
xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
iOS权限 (ios/Runner/Info.plist)
xml
<key>NSPhotoLibraryUsageDescription</key>
<string>需要相册权限选择和保存图片</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>需要相册权限保存拼图</string>
十、总结
图片拼图工具应用通过整合图片选择、模板选择、样式设置、拼图生成、保存分享等功能,为用户提供了一站式的图片拼接解决方案。应用支持11种拼图模板,涵盖2-9张图片的灵活组合,用户可自定义边框样式、圆角效果、拼图比例和背景颜色,打造独一无二的拼图效果。
核心功能涵盖图片选择、模板选择、边框样式、圆角效果、拼图比例、背景颜色、图片排序、保存相册、分享功能九大模块。用户可以轻松选择图片、挑选模板、调整样式、生成拼图,实现图片的创意组合。
应用采用 Material Design 3 设计规范,以活力的粉色为主色调,象征创意与活力。通过本应用,希望能够帮助用户更高效地进行图片拼图创作,让美好瞬间更加精彩。
图片拼图工具------让创意无限可能