Android图片或拍照选择图片功能实例代码
前言
一般公司都有更换用户头像功能,需要从图库中选择图片或者拍照,基本还会对图片进行裁剪。最近抽空就做了一些简单的封装,方便以后使用。主要是用了建造者模式,链式调用,方便简单。可以自定义图片路径,附带裁剪和简单压缩功能。使用实例如下:
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,如遇到问题请评论留言。图片或拍照选择图片 (本地下载)
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。