├── .gitignore ├── .idea ├── .gitignore ├── .name ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── compiler.xml ├── gradle.xml ├── jarRepositories.xml ├── misc.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro ├── release │ ├── app-release.apk │ └── output-metadata.json └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── zero_code │ │ └── editimage │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── zero_code │ │ │ └── editimage │ │ │ ├── GlideEngine.java │ │ │ └── MainActivity.kt │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── ic_launcher_background.xml │ │ └── test.jpg │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── values-night │ │ └── themes.xml │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── themes.xml │ └── test │ └── java │ └── com │ └── zero_code │ └── editimage │ └── ExampleUnitTest.kt ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── lib_edImage ├── .gitignore ├── aar │ └── lib_edImage-release.aar ├── build.gradle ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── zero_code │ │ │ └── libEdImage │ │ │ ├── EditImageView.kt │ │ │ ├── ImageConfig.kt │ │ │ ├── adapter │ │ │ ├── BaseAdapter.kt │ │ │ ├── BaseRecyclerAdapter.java │ │ │ ├── adapter.kt │ │ │ └── animation.kt │ │ │ ├── anim │ │ │ └── EditHomingAnimator.java │ │ │ ├── clip │ │ │ ├── EditClip.java │ │ │ ├── EditClipWindow.java │ │ │ └── EditImageViewPortrait.kt │ │ │ ├── core │ │ │ ├── EditImage.kt │ │ │ ├── EditImageArrows.kt │ │ │ ├── EditImageMode.kt │ │ │ └── EditImagePath.kt │ │ │ ├── elastic │ │ │ ├── EditElastic.java │ │ │ ├── EditElasticAnimator.kt │ │ │ ├── EditPointFEvaluator.kt │ │ │ └── EditRectFEvaluator.kt │ │ │ ├── extend.kt │ │ │ ├── homing │ │ │ ├── EditHoming.java │ │ │ └── EditHomingEvaluator.java │ │ │ ├── model │ │ │ └── ClipViewModel.kt │ │ │ ├── sticker │ │ │ ├── EditSticker.kt │ │ │ ├── EditStickerHelper.java │ │ │ ├── EditStickerMoveHelper.kt │ │ │ ├── EditStickerPortrait.kt │ │ │ └── EditStickerX.java │ │ │ ├── ui │ │ │ ├── EditImageActivity.kt │ │ │ └── text │ │ │ │ ├── EditImageText.kt │ │ │ │ └── EditTextEditDialog.java │ │ │ ├── util │ │ │ ├── IMGUtils.java │ │ │ └── StatusBarUtil.java │ │ │ ├── view │ │ │ ├── Bean.kt │ │ │ ├── EditColorGroup.java │ │ │ ├── EditColorRadio.java │ │ │ ├── EditMosaicGroup.java │ │ │ ├── EditMosaicRadio.java │ │ │ └── PathArrows.kt │ │ │ └── widget │ │ │ ├── EditStickerAdjustHelper.java │ │ │ ├── EditStickerTextView.java │ │ │ └── EditStickerView.java │ └── res │ │ ├── anim │ │ ├── image_dialog_enter.xml │ │ ├── image_dialog_exit.xml │ │ ├── image_fade_in.xml │ │ └── image_fade_out.xml │ │ ├── color │ │ └── image_color_text.xml │ │ ├── layout │ │ ├── activity_edit_image.xml │ │ ├── app_item_null.xml │ │ ├── image_arrows_layout.xml │ │ ├── image_color_layout.xml │ │ ├── image_mosaic_layout.xml │ │ ├── image_text_dialog.xml │ │ └── item_edit_image_tools_layout.xml │ │ ├── mipmap-hdpi │ │ ├── btn_ed_arrow.png │ │ ├── btn_ed_arrowed.png │ │ ├── btn_ed_close.png │ │ ├── btn_ed_cut.png │ │ ├── btn_ed_cuted.png │ │ ├── btn_ed_free.png │ │ ├── btn_ed_freed.png │ │ ├── btn_ed_left.png │ │ ├── btn_ed_level.png │ │ ├── btn_ed_mosaic.png │ │ ├── btn_ed_mosaic2.png │ │ ├── btn_ed_mosaiced.png │ │ ├── btn_ed_ok.png │ │ ├── btn_ed_plumb.png │ │ ├── btn_ed_right.png │ │ ├── btn_ed_text.png │ │ ├── btn_ed_texted.png │ │ ├── btn_ed_texts.png │ │ └── btn_ed_undo.png │ │ ├── mipmap-mdpi │ │ ├── btn_ed_arrow.png │ │ ├── btn_ed_arrowed.png │ │ ├── btn_ed_close.png │ │ ├── btn_ed_cut.png │ │ ├── btn_ed_cuted.png │ │ ├── btn_ed_free.png │ │ ├── btn_ed_freed.png │ │ ├── btn_ed_left.png │ │ ├── btn_ed_level.png │ │ ├── btn_ed_mosaic.png │ │ ├── btn_ed_mosaic2.png │ │ ├── btn_ed_mosaiced.png │ │ ├── btn_ed_ok.png │ │ ├── btn_ed_plumb.png │ │ ├── btn_ed_right.png │ │ ├── btn_ed_text.png │ │ ├── btn_ed_texted.png │ │ ├── btn_ed_texts.png │ │ └── btn_ed_undo.png │ │ ├── mipmap-xhdpi │ │ ├── btn_ed_arrow.png │ │ ├── btn_ed_arrowed.png │ │ ├── btn_ed_close.png │ │ ├── btn_ed_cut.png │ │ ├── btn_ed_cuted.png │ │ ├── btn_ed_free.png │ │ ├── btn_ed_freed.png │ │ ├── btn_ed_left.png │ │ ├── btn_ed_level.png │ │ ├── btn_ed_mosaic.png │ │ ├── btn_ed_mosaic2.png │ │ ├── btn_ed_mosaiced.png │ │ ├── btn_ed_ok.png │ │ ├── btn_ed_plumb.png │ │ ├── btn_ed_right.png │ │ ├── btn_ed_text.png │ │ ├── btn_ed_texted.png │ │ ├── btn_ed_texts.png │ │ ├── btn_ed_undo.png │ │ ├── image_ic_adjust.png │ │ └── image_ic_delete.png │ │ ├── mipmap-xxhdpi │ │ ├── btn_ed_arrow.png │ │ ├── btn_ed_arrowed.png │ │ ├── btn_ed_close.png │ │ ├── btn_ed_cut.png │ │ ├── btn_ed_cuted.png │ │ ├── btn_ed_free.png │ │ ├── btn_ed_freed.png │ │ ├── btn_ed_left.png │ │ ├── btn_ed_level.png │ │ ├── btn_ed_mosaic.png │ │ ├── btn_ed_mosaic2.png │ │ ├── btn_ed_mosaiced.png │ │ ├── btn_ed_ok.png │ │ ├── btn_ed_plumb.png │ │ ├── btn_ed_right.png │ │ ├── btn_ed_text.png │ │ ├── btn_ed_texted.png │ │ ├── btn_ed_texts.png │ │ ├── btn_ed_undo.png │ │ ├── image_ic_adjust.png │ │ └── image_ic_delete.png │ │ ├── mipmap-xxxhdpi │ │ ├── btn_ed_arrow.png │ │ ├── btn_ed_arrowed.png │ │ ├── btn_ed_close.png │ │ ├── btn_ed_cut.png │ │ ├── btn_ed_cuted.png │ │ ├── btn_ed_free.png │ │ ├── btn_ed_freed.png │ │ ├── btn_ed_left.png │ │ ├── btn_ed_level.png │ │ ├── btn_ed_mosaic.png │ │ ├── btn_ed_mosaic2.png │ │ ├── btn_ed_mosaiced.png │ │ ├── btn_ed_ok.png │ │ ├── btn_ed_plumb.png │ │ ├── btn_ed_right.png │ │ ├── btn_ed_text.png │ │ ├── btn_ed_texted.png │ │ ├── btn_ed_texts.png │ │ ├── btn_ed_undo.png │ │ ├── image_ic_adjust.png │ │ └── image_ic_delete.png │ │ ├── values-v21 │ │ └── styles.xml │ │ └── values │ │ ├── colors.xml │ │ ├── ids.xml │ │ ├── image_attrs.xml │ │ ├── image_colors.xml │ │ ├── image_dimens.xml │ │ ├── image_strings.xml │ │ ├── image_styles.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── zero_code │ └── libEdImage │ └── ExampleUnitTest.java ├── resource └── 051600390884_02b7403e8a39a37fa630e48cddd9909a.jpg └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | local.properties 16 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | EditImage -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 119 | 120 | 122 | 123 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🔥🔥🔥EditImage🔥🔥🔥 2 | 3 | ## 介绍 4 | 5 | 🔥🔥🔥基于canvas画布,实现的一款图片轻量级编辑框架,目前支持涂鸦、马赛克、剪裁、文字功能 6 | 7 | 8 | ![image](https://github.com/OneZeroYang/EditImage/blob/main/resource/051600390884_02b7403e8a39a37fa630e48cddd9909a.jpg) 9 | 10 | 11 | 12 | ## TODO 13 | 1. 小概率剪裁框偏差 14 | 2. 动画 15 | 3. 文字边框小概率缩小 16 | 17 | 18 | 19 | ## 集成 20 | 21 | 22 | [![](https://jitpack.io/v/OneZeroYang/EditImage.svg)](https://jitpack.io/#OneZeroYang/EditImage) 23 | 24 | ##### 1. 权限 25 | 26 | 27 | 28 | 29 | 在`AndroidManifest.xml`的`manifest`节点下添加: 30 | 31 | 如下: 32 | 33 | ````xml 34 | 35 | 36 | 37 | ```` 38 | 39 | 注意:Android6.0及以上需要动态权限验证 40 | 41 | ```` 42 | private fun checkPermission() { 43 | //申请权限(Android6.0及以上 需要动态申请危险权限) 44 | if (ContextCompat.checkSelfPermission( 45 | this, 46 | Manifest.permission.WRITE_EXTERNAL_STORAGE 47 | ) != PackageManager.PERMISSION_GRANTED 48 | ) { 49 | //申请权限 50 | ActivityCompat.requestPermissions( 51 | this, arrayOf( 52 | Manifest.permission.WRITE_EXTERNAL_STORAGE, 53 | Manifest.permission.READ_EXTERNAL_STORAGE 54 | ), checkPermissionCode 55 | ) 56 | } else { 57 | // 获取权限成功 58 | } 59 | } 60 | ```` 61 | 62 | ##### 2. 在项目根目录下`build.gradle`文件中 添加 63 | 64 | 65 | maven { url 'https://jitpack.io' } 66 | 67 | 68 | 如下: 69 | ```` 70 | allprojects { 71 | repositories { 72 | ... 73 | maven { url 'https://jitpack.io' } 74 | } 75 | } 76 | ```` 77 | 78 | 79 | 80 | ##### 3. 在`app`目录下`build.gradle`文件中添加 81 | 82 | implementation 'com.github.OneZeroYang:EditImage:Tag' 83 | 84 | 如下: 85 | ```` 86 | dependencies { 87 | implementation 'com.github.OneZeroYang:EditImage:1.1.0' 88 | } 89 | ```` 90 | 91 | ## 注意 92 | 93 | 1. 项目本身最低版本为api19 android 4.4及以上(最低适配版本为4.4) 94 | 2. 如果要使用本库的UI,依赖项目必须开启dataBinding 95 | 96 | 在`app`的`build.gradle`下 `android` 节点下添加如下代码 97 | ```` 98 | dataBinding { 99 | enabled = true 100 | } 101 | ```` 102 | 103 | 104 | 105 | ## 使用 106 | 107 | ##### 1. 快速使用 108 | kotlin: 109 | api 110 | ```` 111 | /** 112 | * 开始编辑图片 113 | * @param src 资源 可以是本地图片 支持 uri path 不支持网络图片 114 | * @param onError 错误的回调 115 | */ 116 | fun Activity.startEditImage( 117 | src: Any, 118 | requestCode: Int, 119 | onError: ((Exception) -> Unit)? = null 120 | ) 121 | 122 | ```` 123 | 124 | 1. startEditImage(uri,requestCode) 125 | 126 | 127 | 2. 在activity实现`onActivityResult`方法 128 | 129 | ```` 130 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { 131 | super.onActivityResult(requestCode, resultCode, data) 132 | if (requestCode == requestCode && resultCode == Activity.RESULT_OK) { 133 | val filePath = data?.getStringExtra("data") //返回结果 134 | } 135 | } 136 | ```` 137 | 138 | 139 | 140 | 注:目前快速使用仅支持kotlin,java请前往`定制化` 141 | 142 | 143 | ##### 2. 定制化 144 | 145 | ###### 基础 146 | 147 | 1. 核心`EditImageView` 148 | 完全使用自定义`view`实现 149 | 150 | 2. 模式 151 | NONE, //默认 152 | DOODLE, //涂鸦 153 | MOSAIC, //马赛克 154 | CLIP, //剪裁 155 | ARROWS //箭头 156 | 157 | 3. 文字/表情/贴图 158 | EditStickerView 159 | 160 | ###### 开始 161 | 162 | 1. 新建一个Activity/Fragment 163 | 164 | 2. 在布局文件里面添加`EditImageView`并初始化 165 | 166 | ```` 167 | 172 | ```` 173 | 注意:`EditImageView` 得 `background` 必须为全黑色不透明 174 | 175 | 3. 初始化控件 176 | 177 | ```` 178 | val mEditView : EditImageView? =null 179 | mEditView=findViewById(R.id.mEditView) 180 | ```` 181 | 182 | 4. 设置编辑模式 183 | ```` 184 | mEditView.mode = EditImageMode.NONE//预览模式 185 | mEditView.mode = EditImageMode.DOODLE//涂鸦模式 186 | mEditView.mode = EditImageMode.MOSAIC//马塞克模式 187 | mEditView.mode = EditImageMode.CLIP//裁剪模式 188 | mEditView.mode = EditImageMode.ARROWS//箭头模式 189 | 190 | ```` 191 | 192 | 注意:当需要添加自定义控件得时候,需要设置模式为预览模式,并调用`addStickerView`,详情见`添加自定义View` 193 | 194 | 5. 预览模式 195 | 196 | 当模式为`EditImageMode.NONE` 时 197 | 预览模式仅支持图片得预览和添加自定义View,包括移动,放大缩小 198 | 199 | 6. 涂鸦 200 | 201 | 当模式为` EditImageMode.DOODLE` 时 202 | 203 | 设置涂鸦颜色: 204 | 205 | ```` 206 | mEditView.setPenColor(color) 207 | ```` 208 | 209 | 撤销上一步涂鸦 210 | 211 | ```` 212 | mEditView.undoDoodle() 213 | ```` 214 | 215 | 7. 马赛克 216 | 217 | 当模式为` EditImageMode.MOSAIC` 时 218 | 219 | 设置马赛克大小 220 | 221 | ```` 222 | mEditView.setMosaicWidth(size) 223 | ```` 224 | 225 | 226 | 撤销上一步马赛克 227 | 228 | ```` 229 | mEditView.undoMosaic() 230 | ```` 231 | 232 | 马赛克大小预设0.2f-0.6f之间 233 | 234 | ```` 235 | public static final Float IMG_MOSAIC_SIZE_1=0.2F; 236 | public static final Float IMG_MOSAIC_SIZE_2=0.3F; 237 | public static final Float IMG_MOSAIC_SIZE_3=0.4F; 238 | public static final Float IMG_MOSAIC_SIZE_4=0.5F; 239 | public static final Float IMG_MOSAIC_SIZE_5=0.6F; 240 | 241 | ```` 242 | 243 | 8. 裁剪 244 | 245 | 当模式为` EditImageMode.CLIP` 时 246 | 247 | 裁剪模式不仅包含裁剪,同时还支持旋转和镜面翻转 248 | 249 | 旋转 250 | 251 | 252 | ```` 253 | mEditView.doRotate(-90f) //left 旋转90° 254 | mEditView.doRotate(90f) //Right 旋转90° 255 | ```` 256 | 257 | 258 | 259 | 镜面翻转 260 | 261 | ```` 262 | mEditView.doVerticalMirror() //垂直镜面反转 263 | mEditView.doHorizontalMirror() //水平镜像反转 264 | ```` 265 | 266 | 取消裁剪 267 | 268 | ```` 269 | mEditView.cancelClip() 270 | ```` 271 | 272 | 重置裁剪 273 | 274 | ```` 275 | mEditView.resetClip() 276 | ```` 277 | 278 | 注意:重置裁剪只会对裁剪部分重置,不会对翻转/旋转生效,对翻转/旋转生效需要自行实现,请参考`com.zero_code.libEdImage.ui.EditImageActivity`源码 279 | 280 | 281 | 确认裁剪 282 | 283 | ```` 284 | mEditView.doClip() 285 | ```` 286 | 287 | 9. 箭头模式 288 | 289 | 当模式为` EditImageMode.ARROWS` 时 290 | 291 | 设置箭头大小 292 | 293 | ```` 294 | mEditView.setArrowsSize(size) 295 | ```` 296 | 注意:箭头大小内置预设为5个等级 1-5 297 | 298 | 设置箭头颜色 299 | 300 | ```` 301 | mEditView.setArrowsColor(color) 302 | ```` 303 | 304 | 撤销上一步箭头 305 | 306 | ```` 307 | mEditView.clearLastArrows() 308 | ```` 309 | 310 | 10. 对保存编辑搞得图片保存为bitmap 311 | 312 | ```` 313 | mEditView.mEditView.saveBitmap() 314 | ```` 315 | 316 | 317 | ## 添加自定义View 318 | 319 | 请自行下载源码查看 320 | 321 | ## 其他api 322 | 323 | 请自行下载源码查看 324 | 325 | 326 | ## 混淆 327 | 328 | ```` 329 | # editImage 330 | -keep public class com.zero_code.libEdImage.EditImageView 331 | -keep public class com.zero_code.libEdImage.core.EditImageMode 332 | -keep class com.zero_code.libEdImage.widget.** { *; } 333 | -keep class com.zero_code.libEdImage.view.** { *; } 334 | ```` 335 | 336 | ## 关于 337 | 如在使用过程中出现任何问题或者BUG,欢迎各位小伙伴提供宝贵得意见 338 | 如果您喜欢这个项目,动动您得小手帮忙点一个star,您的支持,是我前进的最大的动力 339 | QQ:1819405190(添加时,备注 "EditImageView") 340 | 341 | 342 | 343 | ## 测试 344 | 345 | 测试机型 vivo iooq neo 855版本 346 | Android 10 347 | 内存8G 348 | 349 | 1. 自测基本没有致命性异常 350 | 2. 内存根据图片分辨率、大小有所不同,目前编辑3264x2448 分辨率图片最大内存峰值在600M左右,连续快速旋转、翻转会有一定的内存抖动,但不影响正常使用 351 | 3. 使用Android Studio自带内存检测工具没有发现内存泄露的情况 352 | 353 | ## 感谢 354 | felix 核心实现参考 355 | 356 | 357 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'kotlin-android' 4 | id 'kotlin-kapt' 5 | id 'kotlin-android-extensions' 6 | } 7 | def room_version = "2.2.0-rc01" 8 | android { 9 | compileSdkVersion 30 10 | buildToolsVersion "30.0.3" 11 | 12 | defaultConfig { 13 | applicationId "com.batchat.editimage" 14 | minSdkVersion 19 15 | targetSdkVersion 30 16 | versionCode 1 17 | versionName "1.0" 18 | 19 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 20 | } 21 | 22 | buildTypes { 23 | release { 24 | minifyEnabled true 25 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 26 | } 27 | debug { 28 | minifyEnabled true 29 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 30 | } 31 | } 32 | compileOptions { 33 | sourceCompatibility JavaVersion.VERSION_1_8 34 | targetCompatibility JavaVersion.VERSION_1_8 35 | } 36 | kotlinOptions { 37 | jvmTarget = '1.8' 38 | } 39 | 40 | dataBinding { 41 | enabled = true 42 | } 43 | } 44 | 45 | dependencies { 46 | 47 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 48 | implementation 'androidx.core:core-ktx:1.2.0' 49 | implementation 'androidx.appcompat:appcompat:1.1.0' 50 | implementation 'com.google.android.material:material:1.1.0' 51 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 52 | implementation project(path: ':lib_edImage') 53 | testImplementation 'junit:junit:4.+' 54 | androidTestImplementation 'androidx.test.ext:junit:1.1.1' 55 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 56 | 57 | implementation "androidx.room:room-runtime:$room_version" 58 | // For Kotlin use kapt instead of annotationProcessor (注意这个注释) 59 | kapt "androidx.room:room-compiler:$room_version" 60 | 61 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9' 62 | 63 | 64 | 65 | implementation 'com.github.bumptech.glide:glide:4.12.0' 66 | annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0' 67 | // implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.5.9' 68 | 69 | implementation 'com.github.HuanTanSheng:EasyPhotos:3.1.3' 70 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | 24 | #安卓默认会删除一些无用的包,可以用dontshrink来禁止这种行为。 25 | -dontshrink 26 | #不进行优化,建议使用此选项 27 | -dontoptimize 28 | # 屏蔽警告 29 | -ignorewarnings 30 | # 不预校验,加快混淆速度 31 | -dontpreverify 32 | #@Autowired 装配失败的问题 33 | -keepdirectories 34 | #保持packagename 不混淆 35 | -flattenpackagehierarchy 36 | -allowaccessmodification 37 | # 指定不去忽略非公共的库类(不跳过library中的非public的类) 38 | -dontskipnonpubliclibraryclasses 39 | # 指定不去忽略包可见的库类的成员 40 | -dontskipnonpubliclibraryclassmembers 41 | # 指定混淆是采用的算法,后面的参数是一个过滤器 42 | # 这个过滤器是谷歌推荐的算法,一般不做更改 43 | -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* 44 | # 抛出异常时保留代码行号 45 | -keepattributes Exceptions,InnerClasses,Signature,SourceFile,LineNumberTable 46 | # 混淆时记录日志(打印混淆的详细信息) 47 | # 这句话能够使我们的项目混淆后产生映射文件 48 | # 包含有类名->混淆后类名的映射关系 49 | -verbose 50 | 51 | -dontwarn com.google.android.maps.** 52 | -dontwarn android.webkit.WebView 53 | -dontwarn com.umeng.** 54 | -dontwarn com.tencent.weibo.sdk.** 55 | -keep public class javax.** 56 | -keep public class android.webkit.** 57 | -dontwarn android.support.v4.** 58 | -keepattributes SourceFile,LineNumberTable 59 | 60 | #kotlin 61 | -keep class kotlin.** { *; } 62 | -keep class kotlin.Metadata { *; } 63 | -dontwarn kotlin.** 64 | -keepclassmembers class **$WhenMappings { 65 | ; 66 | } 67 | -keepclassmembers class kotlin.Metadata { 68 | public ; 69 | } 70 | -assumenosideeffects class kotlin.jvm.internal.Intrinsics { 71 | static void checkParameterIsNotNull(java.lang.Object, java.lang.String); 72 | } 73 | 74 | -keepclasseswithmembernames class * { 75 | native ; 76 | } 77 | 78 | -keepclassmembers class * extends android.app.Activity { 79 | public void *(android.view.View); 80 | } 81 | -keepclassmembers class * implements android.os.Parcelable { 82 | public static final android.os.Parcelable$Creator *; 83 | } 84 | -keep class **.R$* {*;} 85 | -keepclassmembers enum * { *;} 86 | 87 | -keep public class * extends android.app.Activity 88 | -keep public class * extends android.app.Application 89 | -keep public class * extends android.app.Service 90 | -keep public class * extends android.content.BroadcastReceiver 91 | -keep public class * extends android.content.ContentProvider 92 | -keep public class * extends android.app.backup.BackupAgentHelper 93 | -keep public class * extends android.preference.Preference 94 | 95 | #AndroidX混淆规则 96 | -keep class com.google.android.material.** {*;} 97 | -keep class androidx.** {*;} 98 | -keep public class * extends androidx.* 99 | -keep interface androidx.** {*;} 100 | -dontwarn com.google.android.material.** 101 | -dontnote com.google.android.material.** 102 | -dontwarn androidx.** 103 | 104 | #Glide START 105 | -keep public class * implements com.bumptech.glide.module.GlideModule 106 | -keep class * extends com.bumptech.glide.module.AppGlideModule { 107 | (...); 108 | } 109 | -keep public enum com.bumptech.glide.load.ImageHeaderParser$** { 110 | **[] $VALUES; 111 | public *; 112 | } 113 | -keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder { 114 | *** rewind(); 115 | } 116 | # for DexGuard only 117 | #-keepresourcexmlelements manifest/application/meta-data@value=GlideModule 118 | 119 | #Glide END 120 | 121 | 122 | #PictureSelector 2.0 123 | -keep class com.luck.picture.lib.** { *; } 124 | 125 | -keep class com.huantansheng.easyphotos.models.** { *; } 126 | 127 | 128 | 129 | # editImage 130 | -keep public class com.zero_code.libEdImage.EditImageView 131 | -keep public class com.zero_code.libEdImage.core.EditImageMode 132 | -keep class com.zero_code.libEdImage.widget.** { *; } 133 | -keep class com.zero_code.libEdImage.view.** { *; } 134 | 135 | -------------------------------------------------------------------------------- /app/release/app-release.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OneZeroYang/EditImage/45026df43d3e9d5d9d902192122d37044dedaad5/app/release/app-release.apk -------------------------------------------------------------------------------- /app/release/output-metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "artifactType": { 4 | "type": "APK", 5 | "kind": "Directory" 6 | }, 7 | "applicationId": "com.batchat.editimage", 8 | "variantName": "processReleaseResources", 9 | "elements": [ 10 | { 11 | "type": "SINGLE", 12 | "filters": [], 13 | "versionCode": 1, 14 | "versionName": "1.0", 15 | "outputFile": "app-release.apk" 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/com/zero_code/editimage/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.zero_code.editimage 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.batchat.editimage", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/zero_code/editimage/GlideEngine.java: -------------------------------------------------------------------------------- 1 | package com.zero_code.editimage; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.PointF; 6 | import android.graphics.drawable.Drawable; 7 | import android.net.Uri; 8 | import android.view.View; 9 | import android.widget.ImageView; 10 | 11 | import androidx.annotation.NonNull; 12 | import androidx.annotation.Nullable; 13 | import androidx.core.graphics.drawable.RoundedBitmapDrawable; 14 | import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory; 15 | 16 | import com.bumptech.glide.Glide; 17 | import com.bumptech.glide.request.RequestOptions; 18 | import com.bumptech.glide.request.target.BitmapImageViewTarget; 19 | import com.bumptech.glide.request.target.ImageViewTarget; 20 | import com.huantansheng.easyphotos.engine.ImageEngine; 21 | 22 | 23 | /** 24 | * @author:luck 25 | * @date:2019-11-13 17:02 26 | * @describe:Glide加载引擎 27 | */ 28 | public class GlideEngine implements ImageEngine { 29 | 30 | 31 | 32 | 33 | 34 | 35 | private GlideEngine() { 36 | } 37 | 38 | private static GlideEngine instance; 39 | 40 | public static GlideEngine createGlideEngine() { 41 | if (null == instance) { 42 | synchronized ( GlideEngine.class) { 43 | if (null == instance) { 44 | instance = new GlideEngine(); 45 | } 46 | } 47 | } 48 | return instance; 49 | } 50 | 51 | @Override 52 | public void loadPhoto(@NonNull Context context, @NonNull Uri uri, @NonNull ImageView imageView) { 53 | Glide.with(context) 54 | .load(uri) 55 | .override(200, 200) 56 | .centerCrop() 57 | 58 | .into(imageView); 59 | } 60 | 61 | @Override 62 | public void loadGifAsBitmap(@NonNull Context context, @NonNull Uri gifUri, @NonNull ImageView imageView) { 63 | Glide.with(context) 64 | .load(gifUri) 65 | .override(200, 200) 66 | .centerCrop() 67 | .into(imageView); 68 | } 69 | 70 | @Override 71 | public void loadGif(@NonNull Context context, @NonNull Uri gifUri, @NonNull ImageView imageView) { 72 | Glide.with(context) 73 | .load(gifUri) 74 | .override(200, 200) 75 | .centerCrop() 76 | .into(imageView); 77 | } 78 | 79 | @Override 80 | public Bitmap getCacheBitmap(@NonNull Context context, @NonNull Uri uri, int width, int height) throws Exception { 81 | return Glide.with(context).asBitmap().submit().get(); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/zero_code/editimage/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.zero_code.editimage 2 | 3 | import android.R.attr 4 | import android.app.Activity 5 | import android.content.Intent 6 | import android.graphics.Bitmap 7 | import android.os.Bundle 8 | import android.util.Log 9 | import android.view.View 10 | import androidx.appcompat.app.AppCompatActivity 11 | import com.bumptech.glide.Glide 12 | import com.huantansheng.easyphotos.EasyPhotos 13 | import com.huantansheng.easyphotos.models.album.entity.Photo 14 | import com.zero_code.libEdImage.IS_DEBUG 15 | import com.zero_code.libEdImage.startEditImage 16 | import kotlinx.android.synthetic.main.activity_main.* 17 | import kotlinx.coroutines.CoroutineScope 18 | import kotlinx.coroutines.Dispatchers 19 | import kotlinx.coroutines.MainScope 20 | import kotlinx.coroutines.withContext 21 | 22 | 23 | /** 24 | * 测试用的app 25 | * @author ZeroCode 26 | * @date 2021/5/18 : 11:34 27 | */ 28 | class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() { 29 | 30 | private val test = 31 | "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fyouimg1.c-ctrip.com%2Ftarget%2Ftg%2F035%2F063%2F726%2F3ea4031f045945e1843ae5156749d64c.jpg&refer=http%3A%2F%2Fyouimg1.c-ctrip.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1623049590&t=d510aeb8f12616210691111148795c78".trim() 32 | 33 | override fun onCreate(savedInstanceState: Bundle?) { 34 | super.onCreate(savedInstanceState) 35 | setContentView(R.layout.activity_main) 36 | // launch { 37 | // val bitmap = getBitmap() 38 | // image_canvas.setImageBitmap(bitmap) 39 | // image_canvas.mode= IMGMode.MOSAIC 40 | // } 41 | 42 | 43 | } 44 | 45 | 46 | fun selectImage(view: View) { 47 | selectFromAlbum() 48 | } 49 | 50 | 51 | private suspend fun getBitmap(src: String): Bitmap { 52 | return withContext(Dispatchers.IO) { 53 | Glide.with(this@MainActivity) 54 | .asBitmap() 55 | .load(src) 56 | .submit().get() 57 | } 58 | } 59 | 60 | /** 61 | * 从相册选择 62 | */ 63 | private fun selectFromAlbum() { 64 | EasyPhotos.createAlbum( 65 | this, 66 | false, 67 | true, 68 | GlideEngine.createGlideEngine() 69 | )//参数说明:上下文,是否显示相机按钮,是否使用宽高数据(false时宽高数据为0,扫描速度更快),[配置Glide为图片加载引擎](https://github.com/HuanTanSheng/EasyPhotos/wiki/12-%E9%85%8D%E7%BD%AEImageEngine%EF%BC%8C%E6%94%AF%E6%8C%81%E6%89%80%E6%9C%89%E5%9B%BE%E7%89%87%E5%8A%A0%E8%BD%BD%E5%BA%93) 70 | .start(12) 71 | } 72 | 73 | 74 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { 75 | super.onActivityResult(requestCode, resultCode, data) 76 | if (requestCode == 22 && resultCode == Activity.RESULT_OK) { 77 | //表示返回成功 78 | val filePath = data?.getStringExtra("data") 79 | filePath?.let { 80 | if (IS_DEBUG) Log.e("", it) 81 | Glide.with(this).load(it).into(image) 82 | } 83 | 84 | } else if (requestCode == 12 && resultCode == Activity.RESULT_OK) { 85 | 86 | val resultPhotos: ArrayList = 87 | data?.getParcelableArrayListExtra(EasyPhotos.RESULT_PHOTOS) as ArrayList 88 | 89 | 90 | if (resultPhotos.isNullOrEmpty()) { 91 | return 92 | } 93 | startEditImage(resultPhotos[0].path, 22) 94 | 95 | 96 | // launch { 97 | // val bitmap = getBitmap(selectPic.path) 98 | // image_canvas.setImageBitmap(bitmap) 99 | // image_canvas.mode = IMGMode.NONE 100 | // } 101 | } 102 | } 103 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OneZeroYang/EditImage/45026df43d3e9d5d9d902192122d37044dedaad5/app/src/main/res/drawable/test.jpg -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 |