Skip to content

trv3wood/PhotoEditor

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Photo Editor - Android 图片编辑应用

Android Kotlin API

一款功能完整的 Android 原生图片编辑应用,采用现代化技术栈开发,支持图片浏览、编辑、裁剪和导出功能。

功能特性

核心功能

1. 首页 (Home Screen)

  • 炫酷视觉效果:自定义 View 实现的 Shimmer 扫光效果卡片
  • 多媒体预览:支持加载并预览多种格式的媒体文件
    • WebP 格式支持
    • GIF 动图支持(使用 Coil GIF 加载器)
    • MP4 视频预览(集成 ExoPlayer)
  • 最近编辑展示:自动显示最近编辑的图片,支持时间戳展示(如 "2 hours ago")
  • 快速操作入口:快速访问相册和编辑功能

2. 相册页 (Album Screen)

  • MediaStore API 集成:异步拉取设备上的所有图片和视频
  • 网格布局展示:使用 Jetpack Paging 3 实现高性能分页加载
  • 缩略图优化:自动加载图片缩略图,提升浏览流畅度
  • 厂商适配:针对小米、华为等主流厂商进行权限和 MediaStore 行为适配
  • 运行时权限:自动请求和管理存储权限(Android 13+ 细粒度权限支持)

3. 编辑器页 (Editor Screen)

  • OpenGL ES 渲染:使用 OpenGL ES 2.0 实现硬件加速图片渲染
  • 手势操作
    • 双指缩放:缩放范围 0.5x - 4x
    • 单指拖拽:平移画布
    • 流畅的实时交互反馈
  • 裁剪功能
    • 多种固定比例:Free / 1:1 / 3:4 / 4:3 / 9:16 / 16:9
    • 可拖拽裁剪框调整大小和位置
    • 自动保持比例约束
  • Undo/Redo 操作
    • 完整的操作历史记录
    • 支持撤销和重做
    • 智能变更检测(避免记录微小调整)
  • 重置功能:一键恢复到初始状态

4. 导出功能

  • 高质量导出:保持原图分辨率导出编辑结果
  • 相册保存:自动将编辑后的图片保存到系统相册
  • 操作合成:精确应用所有编辑操作(缩放、平移、裁剪)到最终图片
  • 自动缓存:导出后的图片自动添加到"最近编辑"列表

技术亮点

  • MVVM 架构:清晰的架构设计,易于维护和扩展
  • Jetpack Compose:现代化的 UI 开发框架
  • OpenGL ES 2.0:硬件加速渲染,高性能图片处理
  • 协程 + Flow:异步操作和响应式编程
  • Material 3 设计:遵循最新的 Material Design 规范
  • 状态管理:不可变状态设计,完善的历史记录管理

项目截图

首页

Home Screen

  • 自定义 Shimmer 扫光效果
  • 最近编辑的图片预览
  • 快速操作按钮

相册页

Album Screen

  • 网格布局展示所有媒体文件
  • 支持图片和视频预览

编辑器页

Editor Screen

  • OpenGL ES 渲染画布
  • 手势操作(缩放、平移)
  • 裁剪模式界面

编辑功能演示

Editing Demo

  • 双指缩放和单指拖拽
  • 裁剪框调整
  • 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)     │  │
│  └──────────────┘  └──────────────┘  └──────────────┘  │
└─────────────────────────────────────────────────────────┘

核心组件

1. EditorViewModel

EditorViewModel.kt

职责

  • 管理编辑器状态(缩放、平移、裁剪等)
  • 实现 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
}

2. GLImageRenderer

GLImageRenderer.kt

职责

  • 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

3. GLImageView

GLImageView.kt

职责

  • 封装 GLSurfaceView
  • 处理触摸手势(ScaleGestureDetector)
  • 与 ViewModel 通信

4. CropOverlay

CropOverlay.kt

职责

  • 绘制裁剪框和遮罩
  • 处理裁剪框拖拽调整
  • 保持裁剪比例约束

5. RecentImagesCache

RecentImagesCache.kt

职责

  • 使用 SharedPreferences 持久化最近编辑的图片
  • 支持添加、获取、清空缓存
  • 自动去重和容量限制(最多 10 张)

OpenGL ES 着色器

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 权限管理

构建与运行

1. 克隆项目

git clone https://github.com/yourusername/PhotoEditor.git
cd PhotoEditor

2. 导入 Android Studio

  1. 打开 Android Studio
  2. 选择 File > Open
  3. 选择项目根目录
  4. 等待 Gradle 同步完成

3. 配置签名(可选)

如需生成 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")
            // ...
        }
    }
}

4. 构建 APK

Debug 版本

./gradlew assembleDebug

输出位置:app/build/outputs/apk/debug/app-debug.apk

Release 版本

./gradlew assembleRelease

输出位置:app/build/outputs/apk/release/app-release.apk

5. 构建 AAB(Android App Bundle)

./gradlew bundleRelease

输出位置:app/build/outputs/bundle/release/app-release.aab

6. 运行到设备

  1. 连接 Android 设备或启动模拟器
  2. 确保启用 USB 调试
  3. 点击 Android Studio 的 Run 按钮或执行:
./gradlew installDebug

项目结构

PhotoEditor/
├── 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 及以下: 请求传统存储权限

开发过程与技术难点

1. OpenGL ES 渲染集成

挑战:将 OpenGL ES (View 系统) 与 Jetpack Compose 集成

解决方案

  • 使用 AndroidView 包装 GLSurfaceView
  • 通过 ViewModel 桥接 Compose 状态与 OpenGL 渲染
  • 实现自定义渲染模式(RENDERMODE_WHEN_DIRTY)优化性能

2. Undo/Redo 状态管理

挑战:记录和恢复复杂的编辑状态

解决方案

  • 设计密封类 EditorOperation 表示不同类型的操作
  • 使用双栈结构管理操作历史
  • 实现智能变更检测,过滤微小调整
  • 延迟记录(手势结束时才记录)

3. MediaStore 厂商适配

挑战:不同厂商的 MediaStore 实现差异

解决方案

  • 统一使用 ContentResolver 查询接口
  • 针对不同 Android 版本适配查询参数
  • 处理权限弹窗的时序问题
  • 使用 Paging 3 处理大量媒体文件

4. 裁剪框交互设计

挑战:实现流畅且精确的裁剪框拖拽

解决方案

  • 自定义 View(CropOverlay)处理触摸事件
  • 计算触摸点与裁剪框各部分的碰撞检测
  • 实现比例约束算法
  • 边界检测防止裁剪框超出画布

5. 图片导出与保存

挑战:保持原图分辨率并正确应用所有编辑操作

解决方案

  • 使用 Bitmap 和 Canvas 进行 CPU 端图像处理
  • 计算裁剪区域在原图上的精确坐标
  • 通过 Matrix 应用缩放和平移变换
  • 使用 MediaStore API 保存到相册(适配 Android 10+)

性能优化

1. 渲染优化

  • OpenGL ES 硬件加速
  • 按需渲染模式(避免无意义的重绘)
  • 异步纹理加载

2. 内存优化

  • 及时回收 Bitmap
  • OpenGL 资源在 onSurfaceDestroyed 时清理
  • 图片缩略图加载(相册页)

3. 列表优化

  • Jetpack Paging 3 分页加载
  • Coil 图片库缓存机制
  • LazyColumn/LazyRow 的原生优化

测试

单元测试

./gradlew test

UI 测试

./gradlew connectedAndroidTest

测试覆盖

  • EditorViewModel 状态管理逻辑
  • Undo/Redo 操作栈
  • 裁剪框边界检测
  • 图片导出流程

已知问题与限制

  1. 大图内存:加载超大图片(如 4K+)可能导致内存压力,建议添加分辨率限制或采样
  2. 滤镜效果:当前版本未实现滤镜功能,可通过 Fragment Shader 扩展
  3. 多图编辑:暂不支持批量编辑功能
  4. 云存储:未实现云端同步功能

未来规划

短期目标

  • 实现常用滤镜效果(灰度、复古、黑白等)
  • 添加图片旋转功能
  • 支持亮度/对比度/饱和度调整
  • 优化大图加载性能

长期目标

  • 文字和贴纸功能
  • 自定义滤镜编辑器
  • 批量编辑功能
  • 云端备份与同步
  • AI 智能抠图
  • HDR 支持

技术文档

详细的技术实现文档请参考:

贡献指南

欢迎提交 Issue 和 Pull Request!

提交 PR 前请确保:

  1. 代码通过 Lint 检查
  2. 添加必要的单元测试
  3. 更新相关文档
  4. 遵循项目代码风格

许可证

本项目仅供学习和交流使用。

致谢

感谢以下开源项目:


Note: 本项目作为 Android 开发作业提交,展示了完整的图片编辑应用开发流程。

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages