android 拍照无法生成图片,Android生成二維碼--拍照或從相冊選取圖片
拍照或從相冊選擇圖片是我們日常開發中經常使用到的,可以說是必須掌握的東西。上一篇我介紹了如何生成自定義二維碼《Android生成自定義二維碼》,其中logo和代替黑色色塊的圖片都是寫死的,所以現在我們就來實現拍照或者從相冊選取圖片這個功能。
先看效果圖:
拍照
1.啟動相機程序
拍照可以直接啟動系統的相機程序,代碼如下
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE"); intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); startActivityForResult(intent, TAKE_PHOTO);
這里我們利用一個隱式Intent來啟動相機程序,其中action類型:android.media.action.IMAGE_CAPTURE 表示啟動相機應用並請求一張圖片。創建了Intent對象,還需指定圖片的保存路徑,調用Intent的putExtra()方法並傳入保存路徑即可,最后調用startActivityForResult啟動活動,重寫onActivityResult()方法就能得到返回值。
2.指定保存路徑
上面的intent中指定了保存路徑,也就是代碼中的imageUri。首先需要創建一個File對象用來存放圖片,並使用getExternalCacheDir()方法將圖片放入SD卡當前應用包名下的緩存目錄中。
接着需要將File對象轉換成Uri對象,需要進行版本判斷,7.0以下直接調用Uri的fromFile方法,得到的是圖片本地真實路徑。7.0以上直接使用真實路徑會被認為不安全,會拋出異常,所以需要使用特殊的內容提供器FileProvider,它是ContentProvider的一個子類,作用便是將受限的Uri轉換為可共享的Uri。
既然使用內容提供器,當然需要進行注冊了,AndroidManifest.xml中加入:
meta-data標簽中的內容是用來添加一個共享目錄的,引用了一個resource資源,所以需要在 res/xml 目錄下新建這個 xml 文件,用於存放應用需要共享的目錄文件。
接下來在代碼中調用FileProvider的getUriForFile()方法生成Uri對象,需要傳入三個參數,第一個參數是上下文,第二個參數便是 Manifest 文件中注冊 FileProvider 時設置的 authorities 屬性值,第三個參數為要共享的文件,也就是之前創建的File對象。
完整代碼
/*** 拍照*/
private voidtakePhoto() {//創建File對象,用於存儲拍照后的圖片
File outputImage = new File(getExternalCacheDir(), "output_image.jpg");try{if(outputImage.exists()) { outputImage.delete(); } outputImage.createNewFile(); }catch(IOException e) { e.printStackTrace(); }if (Build.VERSION.SDK_INT < 24) { imageUri=Uri.fromFile(outputImage); }else{ imageUri= FileProvider.getUriForFile(MainActivity.this, "com.example.xch.generateqrcode.fileprovider", outputImage); }//啟動相機程序
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE"); intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); startActivityForResult(intent, TAKE_PHOTO); }
獲取拍照結果:
@Overrideprotected void onActivityResult(int requestCode, intresultCode, Intent data) {switch(requestCode) {caseTAKE_PHOTO:if (resultCode ==RESULT_OK) {try{//讀取拍照結果
logoBitmap =BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri)); }catch(Exception e) { e.printStackTrace(); } }break;default:break; } }
讀取拍照結果利用ContentResolver的openInputStream()方法,並傳入剛才圖片的保存路徑即可獲取圖片字節流,再利用BitmapFactory的decodeStream()方法轉為Bitmap格式,如果擔心OOM,可先進行壓縮。
最后別忘了在AndroidManifest.xml中加入權限
從相冊選擇圖片
打開相冊
同樣用Intent,action類型為android.intent.action.GET_CONTENT ,並給intent設置type為圖片,如下:
Intent intent = new Intent("android.intent.action.GET_CONTENT"); intent.setType("image/*"); startActivityForResult(intent, CHOOSE_PHOTO);
獲取結果
在回調onActivityResult即可對返回結果進行處理
@Overrideprotected void onActivityResult(int requestCode, intresultCode, Intent data) {switch(requestCode) {caseCHOOSE_PHOTO:if (resultCode ==RESULT_OK) {//判斷手機系統版本號
if (Build.VERSION.SDK_INT >= 19) {//4.4及以上系統使用這個方法處理圖片
handleImageOnKitKat(data); }else{//4.4以下系統使用這個方法處理圖片
handleImageBeforeKitKat(data); } }break;default:break; } }
由於Android 4.4開始,不再返回圖片真實的Uri,而是一個封裝過的Uri,因此需要分別進行處理。Android 4.4之前直接調用getImagePath()方法通過Uri和selection就可獲取真實路徑,如下
/*** 4.4版本以前,直接獲取真實路徑 *@paramdata*/
private voidhandleImageBeforeKitKat(Intent data) { Uri uri=data.getData(); String imagePath= getImagePath(uri, null);//顯示圖片
displayImage(imagePath); }privateString getImagePath(Uri uri, String selection) { String path= null;//通過Uri和selection來獲取真實的圖片路徑
Cursor cursor = getContentResolver().query(uri, null, selection, null, null);if (cursor != null) {if(cursor.moveToFirst()) { path=cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); } cursor.close(); }returnpath; }
Android 4.4之后,需要解析封裝過的Uri,如果Uri是document類型,則通過document id處理,如果是content類型的Uri,則使用普通方式處理,如果是file類型的Uri,直接獲取圖片路徑即可。獲取到路徑后即可顯示,如下
private voidhandleImageOnKitKat(Intent data) { String imagePath= null; Uri uri=data.getData();if (DocumentsContract.isDocumentUri(this, uri)) {//如果是document類型的Uri,則通過document id處理
String docId =DocumentsContract.getDocumentId(uri);if ("com.android.providers.media.documents".equals(uri.getAuthority())) { String id= docId.split(":")[1]; //解析出數字格式的id
String selection = MediaStore.Images.Media._ID + "=" +id; imagePath=getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection); }else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) { Uri contentUri= ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId)); imagePath= getImagePath(contentUri, null); } }else if ("content".equalsIgnoreCase(uri.getScheme())) {//如果是content類型的Uri,則使用普通方式處理
imagePath = getImagePath(uri, null); }else if ("file".equalsIgnoreCase(uri.getScheme())) {//如果是file類型的Uri,直接獲取圖片路徑即可
imagePath =uri.getPath(); } displayImage(imagePath);//根據圖片路徑顯示圖片
}
顯示圖片
/*** 顯示圖片 *@paramimagePath 圖片路徑*/
private voiddisplayImage(String imagePath) {if (imagePath != null) { logoBitmap=BitmapFactory.decodeFile(imagePath);//顯示圖片
picture_logo.setImageBitmap(logoBitmap); }else{ Toast.makeText(this, "獲取圖片失敗", Toast.LENGTH_SHORT).show(); } }
動態權限申請
由於涉及了敏感權限 WRITE_EXTERNAL_STORAGE ,所以需要進行權限的動態申請,如下
//動態權限申請
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) !=PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1); }else{//打開相冊
openAlbum(); }
@Overridepublic void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {switch(requestCode) {case 1:if (grantResults.length > 0 && grantResults[0] ==PackageManager.PERMISSION_GRANTED) {//打開相冊
openAlbum(); }else{ Toast.makeText(this, "你拒絕了權限申請,可能無法打開相冊喲", Toast.LENGTH_SHORT).show(); }break;default: } }
上面的代碼就是動態申請權限的流程,首先判斷用戶是不是已經給我們權限授權了,使用ContextCompat.checkSelfPermission()方法,第一個參數是Context,第二個參數是具體的權限名稱,如果等於PackageManager.PERMISSION_GRANTED表明已授權,不等於就是沒有授權。
如果已授權就直接做后面的操作,如果沒有授權,需要調用ActivityCompat.requestPermissions()方法申請授權,第一個參數是當前Activity實例,第二個參數是權限數組,第三個是請求碼。
用戶的選擇將會回調到onRequestPermissionsResult()方法中,授權結果封裝在grantResults參數中,如果被授權,則打開相冊,否則提示用戶未打開權限無法使用。
android 拍照无法生成图片,Android生成二維碼--拍照或從相冊選取圖片相关推荐
- Android二維碼掃描
总是站在牛人的肩膀上在~~ 直接上代码了 添加Gradle依赖:(其实都是人家的...) compile 'com.google.zxing:core:3.1.0' compile 'cn.bingo ...
- android高仿微信拍照、多选、预览、删除(去除相片)相冊功能
先声明授人与鱼不如授人与渔,仅仅能提供一个思路,当然须要源代码的同学能够私下有偿问我要源代码:QQ:508181017 工作了将近三年时间了,一直没正儿八经的研究系统自带的相冊和拍照,这回来个高仿微信 ...
- c#生成图片、生成二维码、读取excel、自动匹配路径
以下是个园林树牌信息生成程序,是使用c#语言编写的控制台程序,包含了生成图片.生成二维码.读取excel.自动匹配路径等功能,可作为以上功能的demo.注意只有系统中已有的字体才可以使用,如果使用系统 ...
- Android生成二维码--拍照或从相册选取图片
拍照或从相册选择图片是我们日常开发中经常使用到的,可以说是必须掌握的东西.上一篇我介绍了如何生成自定义二维码<Android生成自定义二维码>,其中logo和代替黑色色块的图片都是写死的, ...
- Android扫一扫和生成二维码(使用华为ScanKit)
本文主要讲如何使用华为统一扫码scan Kit进行扫一扫以及生成二维码, 有兴趣的可以看一下华为扫描和Zxing扫描的区别 使用步骤 1.在全局的build.gradle文件里添加华为maven仓库 ...
- Android开发规范,flutter生成二维码
变量命名要做到足够长有一定意义,同时又足够短以避免冗长. 关于携带Android控件的变量,个人建议规则:[控件逻辑名称]+[控件缩写] 如mLoginBtn, mBottomLayout, mTit ...
- android zxing 集成过程,android 集成Zxing教程
關於Zxing集成教程,網上有很多很多,我想說你妹的很多都是"copy,copy,copy",問題是尼瑪到最后還出不來...前幾天看了android Bus網站,看到了一個集成Zx ...
- android 解析、生成二维码
android 解析.生成二维码 (1)ZXing是一个开源Java类库用于解析多种格式的1D/2D条形码.目标是能够对QR编码.Data Matrix.UPC的1D条形码进行解码. 其提供了多种平台 ...
- PHP基于phpqrcode类生成二维码
使用ThinkPHP框架引入phpqrcode类生成二维码后,发现每次必须通过TP框架生成,略显繁琐,打算写一个简单的方法,然后运行php后直接批量生成二维码.方法也简单,直接写个PHP脚本,然后引入 ...
最新文章
- SQLserver安全设置攻略
- mysql 分库分表,真的能支持服务无限扩容么?
- 英国EE:启动TechCity 2.0 首期将部署LTE-Advanced Pro
- 二叉树 跳表_漫谈 LevelDB 数据结构(一):跳表(Skip List)
- [数据结构]顺序单链表插入
- 突破边界局限,阿里云神龙负责人张献涛分享15年虚拟化之路
- Qt安装事件过滤器、过滤子控件事件、截获控件按键、鼠标事件
- 将vim打造成python开发工具
- QGIS 3.0 使用教程
- matlab dll 通达信,通达信DLL插件实战篇,怎样制作我们想要的函数
- java正态分布随机数产生方法
- [日语]学习“五十音”(读音篇)
- visual studio进入时许可证已过期解决方案
- HDU 4602 Partition 规律题
- 【远程连接】SSH链接远程主机
- HTML CSS 学习总结
- 【sdx62】WCN6856加载wlan.ko系统崩溃问题解决方案
- 夜来风雨声,对象知多少。
- 相机显示无法访问内存卡?看完你就明白了
- vue使用windows自带能力播放音频