在Yalantis,我们开发了许多不同的安卓app,根据我们的经验来看,几乎每个我们开发的应用都需要图片裁剪的功能。图片裁剪可以用于很多目的,从普通到头像调整到按比例裁剪以及图片变换等更复杂的功能。
考虑到想为我们的所有客户都提供最好的图片编辑工具,我们决定创建 uCrop , 一个安卓版的图片裁剪库。
你可能会想为什么我们不直接使用现有的图片裁剪方案。毕竟,你可以在 Github和 Android Arsenal 上找到许多这样的项目。但是有一点:没有一个满足我们的需求。让我们快速浏览一遍最流行的开源图片裁剪库,然后解释为什么他们都不是很符合要求。
为什么其它的开源库都不好
1. SoundCloud cropping library
我已经在几个项目上成功的使用了SoundCloud的库,但是仍然它有几个问题让我感到很悲剧。
首先,你是通过一个裁剪框操作的,而不是图片本身。如果你需要裁剪图片里面很小的一片区域,这是很蛋疼的,而且从用户体验的角度来讲着也是不对的。我相信Instagram 已经在给了我们一些UX方面的教训,这种可移动的裁剪框已经死去了。
再者,SoundCloud 的裁剪库并不允许我们做任何的旋转。拜托,老大!大家都知道有很多“神奇”的安卓手机里面图片的EXIF 信息是错误的(谢天谢地,我们已经通过 CWAC 解决了这个烂摊子)。再说,许多用户也想能够旋转图片(不仅仅是想旋转90度)。
最后,使用SoundCloud库不能改变宽高比。当然,如果你只是想得到一个正方形的头像,这完全没有问题。但是使用这个库无法实现更多形状的有趣的头像照片。
2. Edmodo Cropper
Edmodo Cropper和SoundCloud 库非常相似,和SoundCloud 也有一下共同的缺陷。但是,这个库允许动态的改变裁剪框的宽高比例。它也有guideline而且有旋转图片的method (但是仅仅是一个method,因此你需要自己弄一个gesture detection 或者一个spinner 来控制手势 )。
3. Scissors
Scissors 是一个比较新的库,最近在一个 Android Weekly issue 上看到之后也非常兴奋。但是5分钟之后就兴奋感就消失了。这是从关于Scissors的 博客 中引用的一段话:
…我们研究了现有的解决方案。没有一个 满足了我们的需求,因此我们决定建立自己的。
这种方式值得表扬。但实际上,不过是又多了一个不能动态旋转图片和改变宽高比例的library 罢了。不过,Scissors倒是集成了一些流行的图片库,比如 Picasso , Glide , 和 Universal Image Loader 。我希望Scissors 在后续的版本能有更多实用的功能。
[ I do like how Scissors implements zoom. The image always scales down to the center of the image, no matter where your fingers are.]
在分析了现有库的缺陷之后,我们决定创建 我们自己的 library ,支持手势和精炼的用户体验。
uCrop: 一个解决了图片裁剪问题的Library
uCrop 是一个让你可以裁剪图片以进一步使用的安卓库。主要功能包括:
- 缩放图片
- 旋转图片
- 改变裁剪的宽高比
- 支持触摸手势:单手指滚动和平移图片,双手指旋转图片,捏图变焦(放大缩小),双击变焦。
- 功能多样化的简便Activity,有精确化缩放和旋转的空间以及一套预定义的宽高比例(1:1, 4:3, 3:4, 2:3, 3:2, 16:9, 9:16 +原始图片的比例)。
uCrop 有一个用于初始化和配置的builder类型的接口。library 本身只需要最小api level 10,但是sample 是在 API level 15+上运行的。
如何在项目中使用uCrop?
在项目中引入库:
compile 'com.yalantis:ucrop:1.0.1'
在AndroidManifest.xml中添加UCropActivity:
<activity android:name="com.yalantis.ucrop.UCropActivity" android:screenOrientation="portrait"/>
uCrop的配置是使用的builder模式:
UCrop.of(sourceUri, destinationUri) .withAspectRatio(16, 9) .withMaxResultSize(maxWidth, maxHeight) .start(context);
重写onActivityResult方法并处理裁剪的结果:
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK || requestCode == UCrop.REQUEST_CROP) { final Uri resultUri = UCrop.getOutput(data); } else if (resultCode == UCrop.RESULT_ERROR) { final Throwable cropError = UCrop.getError(data); } }
如何自定义uCrop?
你可以改变如下设置:
- compression format 压缩格式(e.g. PNG, JPEG, WEBP).
- compression quality压缩质量 [0 - 100] (无损的PNG会忽略质量设置 )
- support for simultaneous gestures
- 从原始图片解码的Bitmap的最大值(如果你想重写默认的行为)。
- 以及更多 (比如color palette)