一款功能完整的 Android 原生图片编辑应用,采用现代化技术栈开发,支持图片浏览、编辑、裁剪和导出功能。
- 炫酷视觉效果:自定义 View 实现的 Shimmer 扫光效果卡片
- 多媒体预览:支持加载并预览多种格式的媒体文件
- WebP 格式支持
- GIF 动图支持(使用 Coil GIF 加载器)
- MP4 视频预览(集成 ExoPlayer)
- 最近编辑展示:自动显示最近编辑的图片,支持时间戳展示(如 "2 hours ago")
- 快速操作入口:快速访问相册和编辑功能
- MediaStore API 集成:异步拉取设备上的所有图片和视频
- 网格布局展示:使用 Jetpack Paging 3 实现高性能分页加载
- 缩略图优化:自动加载图片缩略图,提升浏览流畅度
- 厂商适配:针对小米、华为等主流厂商进行权限和 MediaStore 行为适配
- 运行时权限:自动请求和管理存储权限(Android 13+ 细粒度权限支持)
- OpenGL ES 渲染:使用 OpenGL ES 2.0 实现硬件加速图片渲染
- 手势操作:
- 双指缩放:缩放范围 0.5x - 4x
- 单指拖拽:平移画布
- 流畅的实时交互反馈
- 裁剪功能:
- 多种固定比例:Free / 1:1 / 3:4 / 4:3 / 9:16 / 16:9
- 可拖拽裁剪框调整大小和位置
- 自动保持比例约束
- Undo/Redo 操作:
- 完整的操作历史记录
- 支持撤销和重做
- 智能变更检测(避免记录微小调整)
- 重置功能:一键恢复到初始状态
- 高质量导出:保持原图分辨率导出编辑结果
- 相册保存:自动将编辑后的图片保存到系统相册
- 操作合成:精确应用所有编辑操作(缩放、平移、裁剪)到最终图片
- 自动缓存:导出后的图片自动添加到"最近编辑"列表
- MVVM 架构:清晰的架构设计,易于维护和扩展
- Jetpack Compose:现代化的 UI 开发框架
- OpenGL ES 2.0:硬件加速渲染,高性能图片处理
- 协程 + Flow:异步操作和响应式编程
- Material 3 设计:遵循最新的 Material Design 规范
- 状态管理:不可变状态设计,完善的历史记录管理
- 自定义 Shimmer 扫光效果
- 最近编辑的图片预览
- 快速操作按钮
- 网格布局展示所有媒体文件
- 支持图片和视频预览
- OpenGL ES 渲染画布
- 手势操作(缩放、平移)
- 裁剪模式界面
- 双指缩放和单指拖拽
- 裁剪框调整
- Undo/Redo 操作
┌─────────────────────────────────────────────────────────┐
│ Presentation Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ HomeScreen │ │ AlbumScreen │ │EditorScreen │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────┐
│ ViewModel Layer │
│ ┌──────────────────┐ │
│ │ EditorViewModel │ │
│ │ - State Mgmt │ │
│ │ - Undo/Redo │ │
│ └──────────────────┘ │
└─────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────┐
│ Data/Repository Layer │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │MediaRepository│ │ImageExport │ │RecentImages │ │
│ │ │ │Repository │ │Cache │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────┐
│ Rendering Layer │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │GLImageView │ │GLImageRenderer│ │CropOverlay │ │
│ │ (OpenGL ES) │ │ (Shaders) │ │ (Canvas) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
职责:
- 管理编辑器状态(缩放、平移、裁剪等)
- 实现 Undo/Redo 操作栈
- 处理状态变更和历史记录
Undo/Redo 实现:
// 使用双栈结构实现 Undo/Redo
private val undoStack = Stack<EditorOperation>()
private val redoStack = Stack<EditorOperation>()
// 智能变更检测,避免记录微小调整
private fun hasSignificantChange(old: EditorState, new: EditorState): Boolean {
val scaleDiff = kotlin.math.abs(old.scale - new.scale)
val translateXDiff = kotlin.math.abs(old.translateX - new.translateX)
val translateYDiff = kotlin.math.abs(old.translateY - new.translateY)
return scaleDiff > 0.01f || translateXDiff > 5f || translateYDiff > 5f
}职责:
- OpenGL ES 着色器程序管理
- 图片纹理加载和渲染
- MVP 矩阵变换
渲染管线:
CPU Side: GPU Side:
───────── ─────────
Bitmap Texture Memory
↓ ↓
Load from Uri → Upload to GPU → Texture Binding
↓ ↓
Transform Matrix → MVP Matrix → Vertex Shader
↓ ↓
Vertex Data ──────────────────→ Rasterization
↓
Fragment Shader
↓
Frame Buffer
职责:
- 封装 GLSurfaceView
- 处理触摸手势(ScaleGestureDetector)
- 与 ViewModel 通信
职责:
- 绘制裁剪框和遮罩
- 处理裁剪框拖拽调整
- 保持裁剪比例约束
职责:
- 使用 SharedPreferences 持久化最近编辑的图片
- 支持添加、获取、清空缓存
- 自动去重和容量限制(最多 10 张)
Vertex Shader:
uniform mat4 uMVPMatrix;
attribute vec4 aPosition;
attribute vec2 aTexCoord;
varying vec2 vTexCoord;
void main() {
gl_Position = uMVPMatrix * aPosition;
vTexCoord = aTexCoord;
}Fragment Shader:
precision mediump float;
varying vec2 vTexCoord;
uniform sampler2D uTexture;
void main() {
gl_FragColor = texture2D(uTexture, vTexCoord);
}- Android Studio: Ladybug | 2024.2.1 或更高版本
- JDK: 11 或更高版本
- Android SDK:
- Compile SDK: 36
- Min SDK: 24 (Android 7.0)
- Target SDK: 36
| 库名称 | 版本 | 用途 |
|---|---|---|
| Jetpack Compose | BOM | UI 框架 |
| Material 3 | Latest | UI 组件 |
| ViewModel Compose | Latest | 状态管理 |
| Coil | Latest | 图片加载 |
| Coil GIF | Latest | GIF 支持 |
| ExoPlayer | Latest | 视频播放 |
| Paging 3 | Latest | 分页加载 |
| Accompanist Permissions | Latest | 权限管理 |
git clone https://github.com/yourusername/PhotoEditor.git
cd PhotoEditor- 打开 Android Studio
- 选择
File > Open - 选择项目根目录
- 等待 Gradle 同步完成
如需生成 Release 版本,在 app/build.gradle.kts 中配置签名信息:
android {
signingConfigs {
create("release") {
storeFile = file("your-keystore.jks")
storePassword = "your-store-password"
keyAlias = "your-key-alias"
keyPassword = "your-key-password"
}
}
buildTypes {
release {
signingConfig = signingConfigs.getByName("release")
// ...
}
}
}Debug 版本:
./gradlew assembleDebug输出位置:app/build/outputs/apk/debug/app-debug.apk
Release 版本:
./gradlew assembleRelease输出位置:app/build/outputs/apk/release/app-release.apk
./gradlew bundleRelease输出位置:app/build/outputs/bundle/release/app-release.aab
- 连接 Android 设备或启动模拟器
- 确保启用 USB 调试
- 点击 Android Studio 的 Run 按钮或执行:
./gradlew installDebugPhotoEditor/
├── app/
│ ├── src/
│ │ ├── main/
│ │ │ ├── java/com/example/photoeditor/
│ │ │ │ ├── cache/ # 缓存管理
│ │ │ │ │ └── RecentImagesCache.kt
│ │ │ │ ├── editor/ # 编辑器核心
│ │ │ │ │ ├── EditorViewModel.kt
│ │ │ │ │ ├── EditorState.kt
│ │ │ │ │ ├── GLImageRenderer.kt
│ │ │ │ │ ├── GLImageView.kt
│ │ │ │ │ └── CropOverlay.kt
│ │ │ │ ├── repository/ # 数据层
│ │ │ │ │ ├── MediaRepository.kt
│ │ │ │ │ └── ImageExportRepository.kt
│ │ │ │ ├── ui/
│ │ │ │ │ ├── screen/ # UI 页面
│ │ │ │ │ │ ├── HomeScreen.kt
│ │ │ │ │ │ ├── AlbumScreen.kt
│ │ │ │ │ │ └── EditorScreen.kt
│ │ │ │ │ └── theme/ # 主题配置
│ │ │ │ └── MainActivity.kt
│ │ │ ├── res/ # 资源文件
│ │ │ └── AndroidManifest.xml
│ │ └── test/ # 单元测试
│ └── build.gradle.kts
├── docs/ # 文档
│ ├── EDITOR_README.md
│ └── RECENT_EDIT_README.md
├── screenshots/ # 截图
├── build.gradle.kts
├── settings.gradle.kts
├── CLAUDE.md # 项目要求
└── README.md
<!-- 读取媒体文件(Android 13+) -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<!-- 读取外部存储(Android 12 及以下) -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<!-- 写入外部存储(导出图片) -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />应用使用 Accompanist Permissions 库优雅地处理运行时权限请求,在不同 Android 版本上自动适配:
- Android 13+: 请求细粒度媒体权限
- Android 10-12: 使用 Scoped Storage
- Android 9 及以下: 请求传统存储权限
挑战:将 OpenGL ES (View 系统) 与 Jetpack Compose 集成
解决方案:
- 使用
AndroidView包装 GLSurfaceView - 通过 ViewModel 桥接 Compose 状态与 OpenGL 渲染
- 实现自定义渲染模式(RENDERMODE_WHEN_DIRTY)优化性能
挑战:记录和恢复复杂的编辑状态
解决方案:
- 设计密封类
EditorOperation表示不同类型的操作 - 使用双栈结构管理操作历史
- 实现智能变更检测,过滤微小调整
- 延迟记录(手势结束时才记录)
挑战:不同厂商的 MediaStore 实现差异
解决方案:
- 统一使用 ContentResolver 查询接口
- 针对不同 Android 版本适配查询参数
- 处理权限弹窗的时序问题
- 使用 Paging 3 处理大量媒体文件
挑战:实现流畅且精确的裁剪框拖拽
解决方案:
- 自定义 View(CropOverlay)处理触摸事件
- 计算触摸点与裁剪框各部分的碰撞检测
- 实现比例约束算法
- 边界检测防止裁剪框超出画布
挑战:保持原图分辨率并正确应用所有编辑操作
解决方案:
- 使用 Bitmap 和 Canvas 进行 CPU 端图像处理
- 计算裁剪区域在原图上的精确坐标
- 通过 Matrix 应用缩放和平移变换
- 使用 MediaStore API 保存到相册(适配 Android 10+)
- OpenGL ES 硬件加速
- 按需渲染模式(避免无意义的重绘)
- 异步纹理加载
- 及时回收 Bitmap
- OpenGL 资源在 onSurfaceDestroyed 时清理
- 图片缩略图加载(相册页)
- Jetpack Paging 3 分页加载
- Coil 图片库缓存机制
- LazyColumn/LazyRow 的原生优化
./gradlew test./gradlew connectedAndroidTest- EditorViewModel 状态管理逻辑
- Undo/Redo 操作栈
- 裁剪框边界检测
- 图片导出流程
- 大图内存:加载超大图片(如 4K+)可能导致内存压力,建议添加分辨率限制或采样
- 滤镜效果:当前版本未实现滤镜功能,可通过 Fragment Shader 扩展
- 多图编辑:暂不支持批量编辑功能
- 云存储:未实现云端同步功能
- 实现常用滤镜效果(灰度、复古、黑白等)
- 添加图片旋转功能
- 支持亮度/对比度/饱和度调整
- 优化大图加载性能
- 文字和贴纸功能
- 自定义滤镜编辑器
- 批量编辑功能
- 云端备份与同步
- AI 智能抠图
- HDR 支持
详细的技术实现文档请参考:
欢迎提交 Issue 和 Pull Request!
- 代码通过 Lint 检查
- 添加必要的单元测试
- 更新相关文档
- 遵循项目代码风格
本项目仅供学习和交流使用。
感谢以下开源项目:
Note: 本项目作为 Android 开发作业提交,展示了完整的图片编辑应用开发流程。



