虽然HTML5+规范提供了图像裁剪api,http://html5plus.org/doc/zh_cn/zip.html。
但仍有开发者希望可以调用Android的系统api裁剪图片。
下面的代码是Native.js实现此功能,调用相册获取图片后,通过调用系统API进行裁剪 。
该方式是一种可视操作来剪裁的,区别于5+规范中的compressImage,compressImage是无界面操作,但稳定性好!
而调用系统API可视化进行剪裁稳定性较差,有些手机不支持ACTION_PICK方式进行API调用裁剪!
应一些开发者的要求这里贴出代码,有问题直接咨询谢谢。
var IMAGE_UNSPECIFIED = "image/*";
var PHOTOZOOM = 2; // 获取完图片返回key
var PHOTOLAT = 1; // 剪裁完毕后返回key
var main = plus.android.runtimeMainActivity();
var Intent = plus.android.importClass("android.content.Intent");
var MediaStore = plus.android.importClass("android.provider.MediaStore");
var File = plus.android.importClass("java.io.File");
var Uri = plus.android.importClass("android.net.Uri");
var intent = new Intent(Intent.ACTION_PICK, null);
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_UNSPECIFIED);
main.startActivityForResult(intent, PHOTOZOOM);
main.onActivityResult = function(requestCode, resultCode, data) {
var outPutPath = plus.io.convertLocalFileSystemURL("__downloads/5566.jpg");
if (PHOTOZOOM == requestCode) {
var file = new File(outPutPath);
// 输出目录uri
var outPutUri = Uri.fromFile(file);
plus.android.importClass(data);
var uri = data.getData();
var cropIntent = new Intent("com.android.camera.action.CROP");
cropIntent.setDataAndType(uri, IMAGE_UNSPECIFIED);
// 截图完毕后 输出目录
cropIntent.putExtra(MediaStore.EXTRA_OUTPUT, outPutUri);
cropIntent.putExtra("crop", "true");
// aspectX aspectY 是宽高的比例
cropIntent.putExtra("aspectX", 1);
cropIntent.putExtra("aspectY", 1);
// outputX outputY 是裁剪图片宽高
cropIntent.putExtra("outputX", 64);
cropIntent.putExtra("outputY", 64);
cropIntent.putExtra("return-data", true);
main.startActivityForResult(cropIntent, PHOTOLAT);
} else if (requestCode == PHOTOLAT) {
// 判断 剪裁完后的图片输出是否存在
var file = new File(outPutPath);
var a = file.exists();
alert(a);
}
};
关于图片压缩的多种方案及对比,可以参考这里http://ask.dcloud.net.cn/article/123
24 个回复
天才书生
大坑啊,竟然没人发现?
var outPutPath = plus.io.convertLocalFileSystemURL("_www/5566.jpg");
这句要放到onActivityResult最上面,方法体外或在方法体内的第一句,不然第二次回调的时候,根本找不到outPutPath这个变量
wenju - https://www.mescroll.com -- 精致的下拉刷新和上拉加载组件
来得正是需要的 我来补充几点:
1.如果需要自由裁切,不设置1:1正方形比例,那么可去掉aspectX和aspectY的设置,
2.如果设置的输出尺寸比较大,比如outputX=640 那有的手机返回不了数据,可把return-data设置成false;
我的项目是要求用户上传产品图,尺寸最少640px,高度不限;那么不能设置1:1比例,而且outputX outputY 是必须设置的,不然保存不了;我是这么做的outputX=640; 而outputY=1280//尽量设置高一点,一般图片不会超过640:1280的这个比例
避免黑边的出现,还需设置intent.putExtra("scale", true);intent.putExtra("scaleUpIfNeeded", true);
DCloud_Android_ST (作者)
非常好的补充,感谢
2015-08-03 21:05
alongSelf
var outPutPath = plus.io.convertLocalFileSystemURL("_www/5566.jpg");
最好换成
var outPutPath = plus.io.convertLocalFileSystemURL("_downloads/image/5566.jpg");
因为打包之后 _www目录是只读的。
stock2
js 稳定性 速度肯定跟不上的. 类似之前的压缩图片, 小的而且越压越大的. 大的压缩效果 ... 哎.不说了
还好官网出了, 压缩图片 .非常好.
现在希望出个 能拖拉的裁剪的功能. 呵呵
stock2
测试了,效果很不错. 输出时 var a = file.exists(); alert(a);
为null
我查看了文件,是存在的. 哪里错误了? 复制的代码 谢谢
Funk
outPutPath设置成全局变量就好了
2015-08-14 12:27
stock2
太感谢了 .按照你的指点,可以了.
2015-08-17 08:50
炸鸡排超人
.....你逗我
2015-09-11 11:18
趴趴熊
回复 stock2:你是怎么,调好的,我的alert(a)是false
2015-12-10 16:04
stock2
@117970 根据楼上的outPutPath设置成全局变量 就好了.
2015-12-10 18:29
sheep子涵
怎么弄啊,设置了全局,还是,调好的,我的alert(a)是false
2016-08-25 16:45
b***@sina.cn
我的跟你问题一样。设置了全局,也是返回false。请问怎么解决的
2017-03-22 17:53
wenju - https://www.mescroll.com -- 精致的下拉刷新和上拉加载组件
修正一下我之前补充的:
如果要自由裁切,不指定比例,
则aspectX,aspectY,outputX outputY都无需设置
如果X设置了则Y必须设置 否则保存不了
Funk
我想问一下 你有做拍照裁剪吗? 这段代码是把相册和裁剪和一块了 我试了几次没把他们分开,表示安卓的东西不是很懂……
2015-08-18 12:34
wenju
回复 Funk:var uri = data.getData(); 把这个uri换成拍照回来的uri即可
2015-08-18 14:24
wenju
回复 Funk:Android的裁切代码:
/**
/
public static void cropImage(Activity activity, Uri uri, String outPath,
int outputX, int outputY, int requestCode, int aspectX, int aspectY) {
String path = UriPathUtil.getPath(activity, uri);
Uri mUril = UriPathUtil.getImageContentUri(activity, new File(path));
if (mUril != null) {
uri = mUril;
}
// 裁剪图片意图
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/");
intent.putExtra("crop", "true");
// 裁剪框的比例
if (aspectX>0&&aspectY>0) {
intent.putExtra("aspectX", aspectX);
intent.putExtra("aspectY", aspectY);
}
// 裁剪后输出图片的尺寸大小
if(outputX>0&&outputY>0){
intent.putExtra("outputX", outputX);
intent.putExtra("outputY", outputY);
}
// 去黑边
intent.putExtra("scale", true);
intent.putExtra("scaleUpIfNeeded", true);
// 图片格式
intent.putExtra("outputFormat", "JPEG");
intent.putExtra("noFaceDetection", true);
// 裁切大图
intent.putExtra("return-data", false);
intent.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(new File(outPath)));
// 调用系统裁切界面
activity.startActivityForResult(intent, requestCode);
}
/////////////////////裁切成功的回调////////
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode==RESULT_OK&&data!=null) {
//裁切成功
2015-08-18 14:27
Funk
万分感谢 我试试~~~
2015-08-21 09:36
Funk
回复 wenju:直接换uri的问题是它本身是带相册中选择,然后裁剪 所以这样不行 我无法去掉里面的相册选择部分…… 我现在试试你的第二种方法:)
2015-08-21 14:50
Funk
回复 wenju:我去看了一下intent的说明 再结合你的说明 大概明白怎么做了:)
2015-08-21 15:07
Funk
回复 wenju: cropImage是通过什么来调用的? 我发现还是没有触发裁剪……555
2015-08-21 15:30
Funk
回复 wenju:你能帮我看一下吗?http://ask.dcloud.net.cn/question/9560 thx 在此期间 我会继续想的~~~
2015-08-21 15:45
stock2
最后补充下代码 如果进入相册后,不点击选择任何图片,返回. 日志会报错.
增加if (data==undefined) 判断后 直接返回,就避免报错了.
var outPutUri = Uri.fromFile(file);
if (data==undefined){mui.toast("您已取消操作");mui.back();return false;}
plus.android.importClass(data);
wenju - https://www.mescroll.com -- 精致的下拉刷新和上拉加载组件
回复 Funk:拍照回来后在onActivityResult中调用cropImage方法,其中uri=data.getData()就是拍照回来的图片
脉搏
IOS可咋整呢,哪位高手弄一下啊.
ywg369
有ios的解决方案么
2016-04-01 11:10
4***@qq.com
同问
2018-03-05 14:31
zhaoyari
效果怎么样啊,呵呵,求点评
趴趴熊
在真机调试时没有问题,但是打包后就不能实现了。只能执行到这一步
cropIntent.setDataAndType(uri, IMAGE_UNSPECIFIED);
,后面的就不执行了,无法跳到剪切图像窗口。我把权限全勾上也不行。谁来帮忙看看。
alongSelf
var outPutPath = plus.io.convertLocalFileSystemURL("_www/5566.jpg");
最好换成
var outPutPath = plus.io.convertLocalFileSystemURL("_downloads/image/5566.jpg");
因为打包之后 _www目录是只读的。
2016-03-03 16:00
笑一阵
回复 alongSelf:还是不行捏。。。你有试过么 我我这里改了路径打包后还是不行。。。。
2016-07-06 12:10
slj
为什么只能换一次图片 第二次就不行了
stock2
这个我有经验. 图片更新的链接后面加个参数?ver=日期时间 就可以了
2015-12-30 09:54
笑一阵
回复 stock2:head.src=outPutPath+"?ver="+d.getTime(); 请问是这样么 还是不行诶
2016-06-13 10:33
stock2
前提是,.图片能正常获取到,只是不刷新,被缓存导致. 通过日期每次不一样,就更新.
2017-03-23 11:43
老王
能不能再来个 IOS 版本的
ywg369
有ios处理方式么
2016-04-01 11:10
4***@qq.com
同问
2018-03-05 14:31
ywg369
IOS的如何实现此效果呢
4***@qq.com
同问
2018-03-05 14:31
学长
参照的是上面的实例,截取完毕后返回的requestCode码也是1(表明图像是裁剪完毕了)但是根目录下并没有保存有5566.jpg的图片。我是用的debug模式来调试的,是什么原因呢
8***@qq.com
我的也是没保存
2016-05-31 13:33
笑一阵
这段代码是怎么调用的。。小白请教。。
m***@163.com
同求
2017-07-19 02:46
1***@163.com
为啥调用后,选择相册图片后,又一次打开了相册
4***@qq.com
可有一个完整的demo,求demo
9***@qq.com
java.lang.NullPointerException: Attempt to invoke virtual method 'char[] java.lang.String.toCharArray()' on a null object reference;at new java.io.File
z***@gmail.com
为什么选择完照片后会一直不断地调用裁剪 一直调用
cxian - 帅
mark
w***@qq.com
保存时发生错误,保存失败
c***@hotmail.com
应该是outPutPath参数指向的文件夹不存在导致的,我刚也遇到这个问题
2018-10-09 17:31
4***@qq.com
回复 c***@hotmail.com: 有没有demo啊
2019-05-30 12:02
4***@qq.com
各位老铁有没有demo啊!
f***@foxmail.com
APP在真机调试是可以获取到裁剪的路径,但是打包之后就报错说图片路径不存在,这是怎么回事