当前位置: 移动技术网 > IT编程>移动开发>Android > Android图片或拍照选择图片功能实例代码

Android图片或拍照选择图片功能实例代码

2019年07月23日  | 移动技术网IT编程  | 我要评论

辛妮欧康纳,西咸新区规划图,chen人网站

前言

一般公司都有更换用户头像功能,需要从图库中选择图片或者拍照,基本还会对图片进行裁剪。最近抽空就做了一些简单的封装,方便以后使用。主要是用了建造者模式,链式调用,方便简单。可以自定义图片路径,附带裁剪和简单压缩功能。使用实例如下:

chooseimagetask.getinstance()
    .createbuilder(this)
    .setfilename("图片名称")//有默认的
    .setfilepath("图片路径")//有默认的
    .setiscrop(false)//裁剪
    .setiscompress(true)//压缩
    .setonselectlistener(this)//监听回调结果
    .settype(chooseimagetask.type_gallery)//类型
    .perform();

相册图片

/**
  * 从系统图库里面选择
  *
  * @param activity
  * @param builder
  */
 private void takeimagefromgallery(activity activity, builder builder) {
  onselectlistener monselectlistener = builder.monselectlistener;
  intent intent = new intent(intent.action_pick, mediastore.images.media.external_content_uri);
  componentname componentname = intent.resolveactivity(activity.getpackagemanager());
  if (componentname != null) {
   activity.startactivityforresult(intent, builder.mtype);
  } else {
   if (monselectlistener != null) {
    monselectlistener.onerror("takeimagefromgallery---> activity is illegal");
   }
  }
 }

说明:componentname componentname = intent.resolveactivity(activity.getpackagemanager())主要用来校验当前跳转的activity,后面几个跳转同样也加上了。

图库图片

/**
  * 从图片类型文件中选择图片
  *
  * @param activity
  */
 private void takeimagefromalbum(activity activity, builder builder) {
  onselectlistener monselectlistener = builder.monselectlistener;
  intent intent = new intent(intent.action_open_document);//api19之后
//  intent intent = new intent(intent.action_get_content);//api19之前
  intent.settype("image/*");
  componentname componentname = intent.resolveactivity(activity.getpackagemanager());
  if (componentname != null) {
   activity.startactivityforresult(intent, builder.mtype);
  } else {
   if (monselectlistener != null) {
    monselectlistener.onerror("takeimagefromalbum---> activity is illegal");
   }
  }
 }

注意:action在不同的android版本中有所变化

拍照

拍照比较特殊的是因为android7.0之后,对于uri的读取采用了fileprovider的方式,所以要特殊处理。在res文件夹下创建xml文件夹,xml文件夹下面再创建拍照图片的存放路径,名称可以随便起,但是要记得取的时候要一致。

 /**
  * 拍照
  *
  * @param activity
  */
 private void takephoto(activity activity, chooseimagetask.builder builder) {
  chooseimagetask.onselectlistener monselectlistener = builder.monselectlistener;
  intent takepictureintent = new intent(mediastore.action_image_capture);
  //校验activity是否存在
  if (takepictureintent.resolveactivity(activity.getpackagemanager()) != null) {
   //判断是否自定义路径并且是否合法
   uri fileuri = uriutils.geturi(activity, new file(builder.mfilepath, builder.mfilename));
   takepictureintent.putextra(mediastore.extra_output, fileuri);
   activity.startactivityforresult(takepictureintent, builder.mtype);
  } else {
   if (monselectlistener != null) {
    monselectlistener.onerror("takephoto---> activity is illegal");
   }
  }
 }
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
 <external-path
  name="external"
  path="." />
</paths>

然后需要在manifest中引用当前的路径,如下:

<provider
   android:name="android.support.v4.content.fileprovider"
   android:authorities="${applicationid}.fileprovider"
   android:exported="false"
   android:granturipermissions="true">
   <meta-data
    android:name="android.support.file_provider_paths"
    android:resource="@xml/choose_image" />
  </provider>

取拍照的uri

 /**
  * 根据文件获取uri
  *
  * @param context
  * @param file
  * @return
  */
 public static uri geturi(context context, file file) {
  uri uri;
  if (build.version.sdk_int >= build.version_codes.n) {
   uri = fileprovider.geturiforfile(context,
     fileprovider的路径 , file);
  } else {
   uri = uri.fromfile(file);
  }
  //这里尽量还是要保证uri不要为空,否则报空指针异常
  return uri;
 }

注意:  android:authorities="${applicationid}.fileprovider"里面一定要填写build.gradle里面的applicationid值,不能填写包名,对于applicationid不了解的可以自行查看。

裁剪图片

/**
  * 图片类型的裁剪
  *
  * @param activity
  * @param uri
  * @param outputuri
  */
 public void handlecropimage(activity activity, uri uri, uri outputuri) {
  //打开系统自带的裁剪图片的intent
  intent intent = new intent("com.android.camera.action.crop");
  if (build.version.sdk_int >= build.version_codes.n) {
   //添加这一句表示对目标应用临时授权该uri所代表的文件
   intent.addflags(intent.flag_grant_read_uri_permission);
   intent.addflags(intent.flag_grant_write_uri_permission);
  }
  intent.setdataandtype(uri, "image/*");
  intent.putextra("scale", true);
  // 设置裁剪区域的宽高比例
  intent.putextra("aspectx", 1);
  intent.putextra("aspecty", 1);
  // 设置裁剪区域的宽度和高度
  intent.putextra("outputx", 350);
  intent.putextra("outputy", 350);
  // 人脸识别
  intent.putextra("nofacedetection", true);
  // 图片输出格式
  intent.putextra("outputformat", bitmap.compressformat.jpeg.tostring());
  // 若为false则表示不返回数据
  intent.putextra("return-data", false);
  //输出图片到指定位置
  intent.putextra(mediastore.extra_output, outputuri);
  activity.startactivityforresult(intent, chooseimagetask.type_crop);
 }

注意: intent.putextra("return-data", false);如果返回值为true的话,直接返回bitmap,为了统一压缩之后通过回调的形式返回,所以返回值为false,输出成outputuri。

图片旋转角度处理

有些手机拍照或者选取图片的时候会出现图片有旋转角度问题,所以要根据旋转的角度来重新生成新的图片,符合要求。

/**
  * 读取图片的旋转的角度
  *
  * @param path 图片绝对路径
  * @return 图片的旋转角度
  */
 public static int getbitmapdegree(string path) {
  int degree = 0;
  try {
   // 从指定路径下读取图片,并获取其exif信息
   exifinterface exifinterface = new exifinterface(path);
   // 获取图片的旋转信息
   int orientation = exifinterface.getattributeint(exifinterface.tag_orientation,
     exifinterface.orientation_normal);
   switch (orientation) {
    case exifinterface.orientation_rotate_90:
     degree = 90;
     break;
    case exifinterface.orientation_rotate_180:
     degree = 180;
     break;
    case exifinterface.orientation_rotate_270:
     degree = 270;
     break;
   }
  } catch (ioexception e) {
   e.printstacktrace();
  }
  return degree;
 }
/**
  * 旋转图片,使图片保持正确的方向。
  *
  * @param bitmap 原始图片
  * @param degrees 原始图片的角度
  * @return bitmap 旋转后的图片
  */
 public static bitmap rotatebitmap(bitmap bitmap, int degrees) {
  if (degrees == 0 || null == bitmap) {
   return bitmap;
  }
  matrix matrix = new matrix();
  matrix.setrotate(degrees, bitmap.getwidth() / 2, bitmap.getheight() / 2);
  bitmap bmp = bitmap.createbitmap(bitmap, 0, 0, bitmap.getwidth(), bitmap.getheight(), matrix, true);
  bitmap.recycle();
  return bmp;
 }

回调处理

通过在activity的onactivityresult中处理关于图片选择结果的回调,然后再根据类型处理不同的结果

 /**
  * 代理activity的返回值过程然后
  *
  * @param requestcode
  * @param resultcode
  * @param data
  */
 public void handleresult(int requestcode, int resultcode, @nullable intent data, builder builder) {
  if (resultcode != activity.result_ok) {
   return;
  }

  switch (requestcode) {
   case type_photo:// 拍照
    handlephoto(builder);
    break;
   case type_album://
    //跳转到裁剪页面
    handlegallery(data, builder);
    break;
   case type_gallery:// 图库选择图片
    //跳转到裁剪页面
    handlegallery(data, builder);
    break;
   case type_crop:
    handlecropresult(builder);
    break;
  }
 }

图片压缩

通过循环的方式压缩选取的图片

/**
  * 质量压缩方法
  *
  * @param image
  * @return
  */
 public static bitmap compressimage(bitmap image) {

  bytearrayoutputstream baos = new bytearrayoutputstream();
  image.compress(bitmap.compressformat.jpeg, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
  int options = 100;
  while (baos.tobytearray().length / 1024 > 100) { //循环判断如果压缩后图片是否大于100kb,大于继续压缩
   baos.reset();//重置baos即清空baos
   //第一个参数 :图片格式 ,第二个参数: 图片质量,100为最高,0为最差 ,第三个参数:保存压缩后的数据的流
   image.compress(bitmap.compressformat.jpeg, options, baos);//这里压缩options%,把压缩后的数据存放到baos中
   options -= 10;//每次都减少10
  }
  bytearrayinputstream isbm = new bytearrayinputstream(baos.tobytearray());//把压缩后的数据baos存放到bytearrayinputstream中
  bitmap bitmap = bitmapfactory.decodestream(isbm, null, null);//把bytearrayinputstream数据生成图片
  return bitmap;
 }

总结

大致过程如上所示,但是一定要android6.0之后申请动态权限,全部功能已经写了demo,已经上传github,如需要请移步github,如遇到问题请评论留言。图片或拍照选择图片 ()

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对移动技术网的支持。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网