uni-app Native.js调用系统裁剪图片、头像裁剪-Android

发布于 1周前 作者 songsunli 来自 Uni-App

uni-app Native.js调用系统裁剪图片、头像裁剪-Android

虽然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


58 回复

大坑啊,竟然没人发现?
var outPutPath = plus.io.convertLocalFileSystemURL("_www/5566.jpg"); 这句要放到onActivityResult最上面,方法体外或在方法体内的第一句,不然第二次回调的时候,根本找不到outPutPath这个变量


来得正是需要的 我来补充几点:
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);

非常好的补充,感谢

var outPutPath = plus.io.convertLocalFileSystemURL("_www/5566.jpg"); 最好换成 var outPutPath = plus.io.convertLocalFileSystemURL("_downloads/image/5566.jpg");
因为打包之后 _www目录是只读的。

js 稳定性 速度肯定跟不上的. 类似之前的压缩图片, 小的而且越压越大的. 大的压缩效果 … 哎.不说了 还好官网出了, 压缩图片 .非常好. 现在希望出个 能拖拉的裁剪的功能. 呵呵

测试了,效果很不错. 输出时 var a = file.exists(); alert(a); 为null 我查看了文件,是存在的. 哪里错误了? 复制的代码 谢谢

outPutPath设置成全局变量就好了

太感谢了 .按照你的指点,可以了.

…你逗我

回复 stock2:你是怎么,调好的,我的alert(a)是false

@117970 根据楼上的outPutPath设置成全局变量 就好了.

怎么弄啊,设置了全局,还是,调好的,我的alert(a)是false

我的跟你问题一样。设置了全局,也是返回false。请问怎么解决的

修正一下我之前补充的: 如果要自由裁切,不指定比例, 则aspectX,aspectY,outputX outputY都无需设置
如果X设置了则Y必须设置 否则保存不了

我想问一下 你有做拍照裁剪吗? 这段代码是把相册和裁剪和一块了 我试了几次没把他们分开,表示安卓的东西不是很懂……

回复 Funk:var uri = data.getData(); 把这个uri换成拍照回来的uri即可

回复 Funk:Android的裁切代码:

/////////////////////裁切成功的回调//////// @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode==RESULT_OK&&data!=null) { //裁切成功

万分感谢 我试试~~~

回复 wenju:直接换uri的问题是它本身是带相册中选择,然后裁剪 所以这样不行 我无法去掉里面的相册选择部分…… 我现在试试你的第二种方法:)

回复 wenju:我去看了一下intent的说明 再结合你的说明 大概明白怎么做了:)

回复 wenju: cropImage是通过什么来调用的? 我发现还是没有触发裁剪……555

回复 wenju:你能帮我看一下吗?http://ask.dcloud.net.cn/question/9560 thx 在此期间 我会继续想的~~~

最后补充下代码 如果进入相册后,不点击选择任何图片,返回. 日志会报错. 增加if (data==undefined) 判断后 直接返回,就避免报错了. var outPutUri = Uri.fromFile(file); if (data==undefined){mui.toast(“您已取消操作”);mui.back();return false;} plus.android.importClass(data);

回复 Funk:拍照回来后在onActivityResult中调用cropImage方法,其中uri=data.getData()就是拍照回来的图片

IOS可咋整呢,哪位高手弄一下啊.

有ios的解决方案么

效果怎么样啊,呵呵,求点评

在真机调试时没有问题,但是打包后就不能实现了。只能执行到这一步 cropIntent.setDataAndType(uri, IMAGE_UNSPECIFIED); ,后面的就不执行了,无法跳到剪切图像窗口。我把权限全勾上也不行。谁来帮忙看看。

var outPutPath = plus.io.convertLocalFileSystemURL("_www/5566.jpg"); 最好换成 var outPutPath = plus.io.convertLocalFileSystemURL("_downloads/image/5566.jpg");

因为打包之后 _www目录是只读的。

回复 alongSelf:还是不行捏。。。你有试过么 我我这里改了路径打包后还是不行。。。。

为什么只能换一次图片 第二次就不行了

这个我有经验. 图片更新的链接后面加个参数?ver=日期时间 就可以了

回复 stock2:head.src=outPutPath+"?ver="+d.getTime(); 请问是这样么 还是不行诶

前提是,.图片能正常获取到,只是不刷新,被缓存导致. 通过日期每次不一样,就更新.

能不能再来个 IOS 版本的

有ios处理方式么

IOS的如何实现此效果呢

参照的是上面的实例,截取完毕后返回的requestCode码也是1(表明图像是裁剪完毕了)但是根目录下并没有保存有5566.jpg的图片。我是用的debug模式来调试的,是什么原因呢

我的也是没保存

这段代码是怎么调用的。。小白请教。。

为啥调用后,选择相册图片后,又一次打开了相册

可有一个完整的demo,求demo

java.lang.NullPointerException: Attempt to invoke virtual method ‘char[] java.lang.String.toCharArray()’ on a null object reference;at new java.io.File

为什么选择完照片后会一直不断地调用裁剪 一直调用

保存时发生错误,保存失败

应该是outPutPath参数指向的文件夹不存在导致的,我刚也遇到这个问题

回复 c***@hotmail.com: 有没有demo啊

各位老铁有没有demo啊!

APP在真机调试是可以获取到裁剪的路径,但是打包之后就报错说图片路径不存在,这是怎么回事

在uni-app中,使用Native.js调用Android系统的图片裁剪功能,可以通过调用Android的原生API来实现。以下是一个简单的示例代码,展示如何通过Native.js在Android平台上裁剪图片。

首先,确保你的uni-app项目已经启用了Native.js支持。然后,你可以使用以下代码:

  1. pages/index/index.vue中编写页面代码
<template>
  <view>
    <button @click="chooseAndCropImage">选择并裁剪图片</button>
    <image v-if="croppedImagePath" :src="croppedImagePath" style="width: 100px; height: 100px;"></image>
  </view>
</template>

<script>
export default {
  data() {
    return {
      croppedImagePath: ''
    };
  },
  methods: {
    chooseAndCropImage() {
      // 调用Native.js方法
      plus.android.importClass('android.provider.MediaStore');
      const intent = new plus.android.intent.Intent(plus.android.invoke(MediaStore, 'ACTION_IMAGE_CAPTURE'));
      // 设置裁剪参数(这里需要自定义裁剪Activity或调用系统裁剪功能,以下仅为示例)
      // 注意:实际裁剪逻辑可能需要使用第三方库或自定义Activity实现
      // 这里假设有一个裁剪Activity的Intent Filter匹配这个Action
      intent.setAction('com.example.CROP_IMAGE');
      intent.putExtra('outputX', 100);
      intent.putExtra('outputY', 100);
      intent.putExtra('aspectX', 1);
      intent.putExtra('aspectY', 1);
      intent.putExtra('scale', true);
      intent.putExtra('return-data', true);
      
      plus.android.runtimeMainActivity().startActivityForResult(intent, 1, (requestCode, resultCode, data) => {
        if (resultCode === plus.android.constants.Activity.RESULT_OK && data) {
          const extras = data.getExtras();
          const croppedBitmap = extras.get('data');
          // 将Bitmap转换为文件路径(这里省略具体实现,需自行处理)
          // this.croppedImagePath = ...;
        }
      });
    }
  }
};
</script>

注意

  • 上面的代码示例中,intent.setAction('com.example.CROP_IMAGE'); 是一个假设的Action,实际中你需要有一个匹配的Activity来处理这个Intent,或者调用系统提供的裁剪功能(这通常需要更复杂的处理,包括保存临时文件、调用裁剪Activity等)。
  • extras.get('data') 获取的是裁剪后的Bitmap对象,你需要将其转换为文件路径才能在uni-app中显示。这部分逻辑没有包含在示例中,因为涉及Bitmap到文件路径的转换,通常需要借助Android的存储API。
  • 由于Android系统裁剪功能的多样性和复杂性,实际项目中可能需要更详细的处理,包括处理不同Android版本的兼容性、处理权限问题等。

希望这个示例能帮助你理解如何在uni-app中使用Native.js调用Android系统的图片裁剪功能。

回到顶部