Android手机多媒体——拍照和相册

一 拍照功能

1.布局文件:在线性布局中设置一个按钮,用来启动拍照功能,设置一个ImageView用来展示图像

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     android:layout_width="match_parent"
 3     android:layout_height="match_parent"
 4     android:orientation="vertical">
 5
 6     <Button
 7         android:id="@+id/take_photo"
 8         android:layout_width="match_parent"
 9         android:layout_height="wrap_content"
10         android:text="take photo" />
11
12     <ImageView
13         android:id="@+id/picture"
14         android:layout_width="wrap_content"
15         android:layout_height="wrap_content"
16         android:layout_gravity="center_horizontal" />
17 </LinearLayout>

2.主函数:

 1 public class MainActivity extends AppCompatActivity {
 2
 3     private Button takePhoto;
 4     private ImageView picture;
 5     public static final int TAKE_PHOTO = 1;
 6     private Uri imageUri;
 7
 8     @Override
 9     protected void onCreate(Bundle savedInstanceState) {
10         super.onCreate(savedInstanceState);
11         setContentView(R.layout.activity_main);
12
13         takePhoto = (Button) findViewById(R.id.take_photo);
14         picture = (ImageView) findViewById(R.id.picture);
15         takePhoto.setOnClickListener(new View.OnClickListener() {
16             @Override
17             public void onClick(View view) {
18                 /*创建FIle对象用于存储拍照后的图片,
19                 * getExternalCacheDir()用来获得应用关联目录地址,用于存储图片*/
20                 File outputImage = new File(getExternalCacheDir(), "output_image.jpg");
21                 try {
22                     if (outputImage.exists()) {  //如果outputImage存在,则删除原有outputImage
23                         outputImage.delete();
24                     }
25                     outputImage.createNewFile();  //创建新的文件
26                 } catch (IOException e) {
27                     e.printStackTrace();
28                 }
29
30                 /*在Android7.0以后 就不将uri代表的真实存储路径暴露出来了,
31                 * 取而代之的是getURIForFile对其进行封装的uri,三个参数是context,唯一的字符串,File对象*/
32                 if (Build.VERSION.SDK_INT >= 24){
33                     imageUri = FileProvider.getUriForFile(MainActivity.this,
34                             "com.example.cameraalbumtest.fileprovider",outputImage);
35                 }else {
36                     imageUri = Uri.fromFile(outputImage);
37                 }
38
39                 /*隐式intent,只有能够相应intent活动的activity会被调用
40                 * 然后使用putExtra方法传输一个指定位置imageUri,使拍照后的图像存储到该位置*/
41                 Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
42                 intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri);
43                 startActivityForResult(intent,TAKE_PHOTO);
44             }
45         });
46     }
47
48     /*startActivityForResult之后回调到这个方法中,传入相关参数
49     * 如果是拍照请求码,先判断是否拍照成功,成功的话通过BitmapFactory.decodeStream将其转化为bitmap格式
50     * 在picture中显示出来*/
51     @Override
52     protected void onActivityResult(int requestCode,int resultCode,Intent data){
53         switch (requestCode){
54             case TAKE_PHOTO:
55                 if(resultCode == RESULT_OK){
56                     try{
57                         //拍照成功,将图片显示出来
58                         Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
59                         picture.setImageBitmap(bitmap);
60                     } catch (FileNotFoundException e) {
61                         e.printStackTrace();
62                     }
63                 }
64                 break;
65             default:
66                 break;
67         }
68     }
69 }

函数主要可以分为三部分。首先对按键,图像,uri进行声明,并定义一个常量Take_Photo为1。

  1.第一部分为创建file部分

创建一个outputImage,是file(文件)类型,存放的是应用关联目录的地址,这个目录是应用的临时文件目录,所有也不需要申请sd卡存放权限,

然后进行判断,如果outputImage中存在文件,即有拍照过的照片储存,则删除原有的outputImage。然后创建一个新的文件。

  2.第二部分为Intent部分

首先进行判断,在Android7.0以后 就不将uri代表的真实存储路径暴露出来了,取而代之的是fileProvider提供器中getURIForFile()方法对其进行封装的uri,该方法的三个参数是context,唯一的字符串,File对象,如果是7.0之前的话,则可以直接通过Uri.fromFile()对file直接进行解析。

然后创建Intent,隐式intent,只有能够响应intent活动的activity会被调用。然后intent中传输的是一个uri标识,即:使用putExtra方法传输一个指定位置imageUri,使拍照后的图像存储到该位置。

然后使用 startActivityForResult()方法启动intent。

  3.第三部分为intent的回调部分

startActivityForResult之后回调到这个方法中,传入相关参数。

如果是拍照请求码,先判断是否拍照成功,成功的话通过BitmapFactory.decodeStream将其转化为bitmap格式,在picture中显示出来。

3.权限声明

因为在第二部分对uri进行封装的时候使用到了FileProvider提供器,所以需要对其在AndroidManifest.xml中进行相关注册。

1         <provider
2             android:name="android.support.v4.content.FileProvider"
3             android:authorities="com.example.cameraalbumtest.fileprovider"
4             android:exported="false"
5             android:grantUriPermissions="true">
6             <meta-data
7                 android:name="android.support.FILE_PROVIDER_PATHS"
8                 android:resource="@xml/file_paths" />
9         </provider>

其中Android:name是固定的,authorities值与之前对uri封装是的唯一标识符(标黄)是相同的,使用<meta-data>来指定uri的共享路径。引用了一个 @xml/file_paths 资源。

在res中新建xml文件夹,新建一个file类型的file_paths.xml文件:用来指定uri共享,path中为空即整个SD卡都共享。

1 <?xml version="1.0" encoding="utf-8"?>
2 <!--suppress ALL -->
3 <paths xmlns:android="http://schemas.android.com/apk/res/android">
4     <external-path
5         name="my_images"
6         path=""/>
7 </paths>

二 相册功能

在布局文件中新增了一个按钮,表示相册中选择照片

    <Button
        android:id="@+id/choose_from_album"
        android:text="Choose album"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

主函数中整体处理逻辑流程:

  1. 在主函数中,为选择相册按钮添加点击事件,
  2. 先是一个申请授权访问SD卡的操作,(先判断是否有权限,没有权限进行询问,有权限下一步。  询问时,同意进行下一步,不同意则弹出反馈信息)
  3. 获得授权之后会执行openAlbum方法,构造一个Intent对象,设置相应的动作。调用startActivityForResult()方法就可以访问相册选择照片了,该方法第二个参数为Choose photo是一个常量2。
  4. 选择完图片后,进入回调函数onActivityForResult(),进入到Choose Photo的case来进行处理,这是进行一个判断,判断手机的版本。4.4和4.4以上的版本调用 handleImageOnKitKat()方法处理,以下的调用 handleImageBeforeKitKat()方法处理。
  5. handleImageOnKitKat()方法逻辑主要是如何解析封装过的Uri,分为三种大情况。如果是document类型的话,使用document id进行处理;如果不是就用普通方法来处理。然后用解析后的uri和条件语句调用getImagePath()方法来获取真实路径。最后调用displayImage()方法进行展示
  6. handleImageBeforeKitKat()方法不需要解析,直接将uri传入getImagePath()方法获取真实路径。然后调用displayImage()进行展示。
  7. getImagePath()方法通过uri和条件语句来获取真实路径。
  8. displayImage()方法,如果路径不为空,则将其转化为bitmap格式,然后在imageView中进行展示,否则弹出反馈信息。
  1 package com.example.cameraalbumtest;
  2
  3 import android.Manifest;
  4 import android.annotation.TargetApi;
  5 import android.content.ContentUris;
  6 import android.content.Intent;
  7 import android.content.pm.PackageManager;
  8 import android.database.Cursor;
  9 import android.graphics.Bitmap;
 10 import android.graphics.BitmapFactory;
 11 import android.net.Uri;
 12 import android.os.Build;
 13 import android.provider.DocumentsContract;
 14 import android.provider.MediaStore;
 15 import android.support.v4.app.ActivityCompat;
 16 import android.support.v4.content.ContextCompat;
 17 import android.support.v4.content.FileProvider;
 18 import android.support.v7.app.AppCompatActivity;
 19 import android.os.Bundle;
 20 import android.view.View;
 21 import android.widget.Button;
 22 import android.widget.ImageView;
 23 import android.widget.Toast;
 24
 25 import java.io.File;
 26 import java.io.FileNotFoundException;
 27 import java.io.IOException;
 28
 29 public class MainActivity extends AppCompatActivity {
 30
 31     private Button takePhoto;
 32     private Button choosePhoto;
 33     private ImageView picture;
 34     public static final int TAKE_PHOTO = 1;
 35     public static final int CHOOSE_PHOTO = 2;
 36     private Uri imageUri;
 37
 38     @Override
 39     protected void onCreate(Bundle savedInstanceState) {
 40         super.onCreate(savedInstanceState);
 41         setContentView(R.layout.activity_main);
 42
 43         takePhoto = (Button) findViewById(R.id.take_photo);
 44         picture = (ImageView) findViewById(R.id.picture);
 45         takePhoto.setOnClickListener(new View.OnClickListener() {
 46             @Override
 47             public void onClick(View view) {
 48                 /*创建FIle对象用于存储拍照后的图片,
 49                 * getExternalCacheDir()用来获得应用关联目录地址,用于存储图片*/
 50                 File outputImage = new File(getExternalCacheDir(), "output_image.jpg");
 51                 try {
 52                     if (outputImage.exists()) {  //如果outputImage存在,则删除原有outputImage
 53                         outputImage.delete();
 54                     }
 55                     outputImage.createNewFile();  //创建新的文件
 56                 } catch (IOException e) {
 57                     e.printStackTrace();
 58                 }
 59
 60                 /*在Android7.0以后 就不将uri代表的真实存储路径暴露出来了,
 61                 * 取而代之的是getURIForFile对其进行封装的uri,三个参数是context,唯一的字符串,File对象*/
 62                 if (Build.VERSION.SDK_INT >= 24) {
 63                     imageUri = FileProvider.getUriForFile(MainActivity.this,
 64                             "com.example.cameraalbumtest.fileprovider", outputImage);
 65                 } else {
 66                     imageUri = Uri.fromFile(outputImage);
 67                 }
 68
 69                 /*隐式intent,只有能够响应intent活动的activity会被调用
 70                 * 然后使用putExtra方法传输一个指定位置imageUri,使拍照后的图像存储到该位置*/
 71                 Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
 72                 intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
 73                 startActivityForResult(intent, TAKE_PHOTO);
 74             }
 75         });
 76
 77         choosePhoto = (Button) findViewById(R.id.choose_from_album);
 78         choosePhoto.setOnClickListener(new View.OnClickListener() {
 79             @Override
 80             public void onClick(View view) {
 81                 if (ContextCompat.checkSelfPermission(MainActivity.this,
 82                         Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
 83                     ActivityCompat.requestPermissions(MainActivity.this,
 84                             new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
 85                 } else {
 86                     openAlbum();
 87                 }
 88             }
 89         });
 90     }
 91
 92     private void openAlbum() {
 93         Intent intent = new Intent("android.intent.action.GET_CONTENT");
 94         intent.setType("image/*"); //读取的文件类型:照片
 95         startActivityForResult(intent, CHOOSE_PHOTO);
 96     }
 97
 98     @Override
 99     public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
100         switch (requestCode) {
101             case 1:
102                 if (grantResults.length >= 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
103                     openAlbum();
104                 } else {
105                     Toast.makeText(this, "未获得相册授权", Toast.LENGTH_LONG).show();
106                 }
107                 break;
108             default:
109                 break;
110         }
111     }
112
113     /*startActivityForResult之后回调到这个方法中,传入相关参数
114     * 如果是拍照请求码,先判断是否拍照成功,成功的话通过BitmapFactory.decodeStream将其转化为bitmap格式
115     * 在picture中显示出来*/
116     @Override
117     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
118         switch (requestCode) {
119             case TAKE_PHOTO:
120                 if (resultCode == RESULT_OK) {
121                     try {
122                         //拍照成功,将图片显示出来
123                         Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
124                         picture.setImageBitmap(bitmap);
125                     } catch (FileNotFoundException e) {
126                         e.printStackTrace();
127                     }
128                 }
129                 break;
130             case CHOOSE_PHOTO:
131                 if (resultCode == RESULT_OK) {
132                     //判断手机版本
133                     if (Build.VERSION.SDK_INT >= 19) {
134                         //4.4和以上的系统使用这个方法处理照片
135                         handleImageOnKitKat(data);
136                     } else {
137                         //4.4以下的系统使用这个方法
138                         handleImageBeforeKitKat(data);
139                     }
140                 }
141             default:
142                 break;
143         }
144     }
145
146     @TargetApi(19)
147     private void handleImageOnKitKat(Intent data) {
148         /*因为intent传输来的uri进行了封装,要对其uri进行解析,
149         * 分三种大情况进行解析,解析出图片的文件路径。*/
150         String imagePath = null;
151         Uri uri = data.getData();
152         if (DocumentsContract.isDocumentUri(this, uri)) {
153             //如果是document(文件)类型的Uri,则通过document id来处理
154             String docId = DocumentsContract.getDocumentId(uri);
155             if ("com.android.providers.media.documents".equals(uri.getAuthority())) {
156                 String id = docId.split(":")[1];  //解析出数字格式的id
157                 String selection = MediaStore.Images.Media._ID + "=" + id;
158                 imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
159             } else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
160                 Uri contentUri = ContentUris.withAppendedId
161                         (Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId));
162                 imagePath = getImagePath(contentUri, null);
163             }
164         } else if ("content".equalsIgnoreCase(uri.getScheme())) {
165             //如果是content类型的uri,则使用普通方法处理
166             imagePath = getImagePath(uri, null);
167         } else if ("file".equalsIgnoreCase(uri.getScheme())) {
168             //如果是file类型的uri,直接获取图片路径就可以
169             imagePath = uri.getPath();
170         }
171         /*解析完uri,直接根据图片路径展示图片*/
172         displayImage(imagePath);
173     }
174
175     private void handleImageBeforeKitKat(Intent data) {
176         Toast.makeText(this, "你的Android版本太低", Toast.LENGTH_LONG).show();
177         Uri uri = data.getData();
178         String imagePath = getImagePath(uri, null);
179         displayImage(imagePath);
180     }
181
182     private String getImagePath(Uri uri, String selection) {
183         //通过Uri和seletion来获取真实图片地址
184         String path = null;
185         Cursor cursor = getContentResolver().query(uri, null, selection, null, null);
186         if (cursor != null) {
187             if (cursor.moveToFirst()) {
188                 path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
189             }
190             cursor.close();
191         }
192         return path;
193     }
194
195     /*将图片转化为Bitmap格式,在下面展现出来*/
196     private void displayImage(String imagePath) {
197         if (imagePath!=null) {
198             Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
199             picture.setImageBitmap(bitmap);
200         }else{
201             Toast.makeText(this,"无法获得图片",Toast.LENGTH_LONG).show();
202         }
203     }
204 }

原文地址:https://www.cnblogs.com/Mask-D/p/9535909.html

时间: 2024-07-30 09:07:44

Android手机多媒体——拍照和相册的相关文章

实现调用Android手机的拍照功能

很简单,直接上示例吧 1 xml 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_paren

Android手机多媒体——通知

一 创建手机通知 1.创建一个NotificationManager 创建一个NotificationManager来对通知就行管理.一般调用context的getSystemService()方法得到这个对象,这个方法传入要获取的服务,返回的是一个该类型的值.如下: /*获取到一个NotificationManager来对通知进行管理, * 使用的是getSystemService方法,传入一个服务,返回一个manager*/ NotificationManager manager = (No

Android拍照、相册选取、裁剪图片

来自:http://blog.csdn.net/ryantang03/article/details/8656278 package com.example.listactivity; import java.io.ByteArrayOutputStream; import java.io.File; import com.example.model.ImageTools; import android.app.Activity; import android.app.AlertDialog;

部分Android手机拍照后照片被旋转的解决方案

在部分Android手机(如MT788.Note2)上,使用Camera拍照以后,得到的照片会被自动旋转(90°.180°.270°),这个情况很不符合预期.仔细分析了一下,因为照片属性中是存储了旋转信息的,所以要解决这个问题,可以在onActivityResult方法中,获取到照片数据后,读取它的旋转信息,如果不是0,说明这个照片已经被旋转过了,那么再使用android.graphics.Matrix将照片旋转回去即可. 1.读取图片的旋转属性 /**  * 读取图片的旋转的角度  *  *

Android拍照,相册选择图片以及Android6.0权限管理

概述 在android开发过程中,拍照或者从相册中选择图片是很常见的功能.下面要说得这个案例比较简单,用户点击按钮选择拍照或者打开相册选择图片,然后将选中的图片显示在手机上.android6.0后,推出了动态权限管理.以往我们将涉及到的权限全部写在清单文件中,只要用户安装了该程序,程序在运行过程中都会获得相应权限.android6.0后,对于一些特别敏感的权限,开发者必须在程序中进行声明.拍照和从相册选择图片都是涉及到用户隐私的敏感权限,必须在程序中进行声明. 大概的流程 创建布局文件,这里不多

android——拍照,相册图片剪切其实就这么简单

接触android这么久了.还没有真正的浩浩看看android拍照,相册图片剪切到底是怎么回事,每次都是从别人的代码一扣,就过来了.其实,谷歌提供的API已经很强大.只需要用的好,就那么几句就可以搞定神秘的拍照和剪切图片.废话不多少,直接看源码 package com.example.testcamera; import java.io.FileNotFoundException; import android.app.Activity; import android.content.Inten

Android拍照与相册选取图片

做过几次拍照,相册选取图片,但都记不住,这次发表个简单的保存下 private static final int PHOTO_GRAPH = 1;// 拍照 private static final int PHOTO_ALBUM = 2; // 相册获取 private static final String IMAGE_TYPE = "image/*"; 1 public void takePhoto(){ 2 3 String SDState = Environment.getE

HTML5 Plus 拍照或者相册选择图片上传

利用HTML Plus的Camera.GalleryIO.Storage和Uploader来实现手机APP拍照或者从相册选择图片上传.Camera模块管理设备的摄像头,可用于拍照.摄像操作,通过plus.camera获取摄像头管理对象.Gallery模块管理系统相册,支持从相册中选择图片或视频文件.保存图片或视频文件到相册等功能.通过plus.gallery获取相册管理对象.IO模块管理本地文件系统,用于对文件系统的目录浏览.文件的读取.文件的写入等操作.通过plus.io可获取文件系统管理对象

拍照/从相册读取图片后进行裁剪的方法

本范例实现的是用户可以通过拍照.相册获取图片,然后进行裁剪,最后将结果保存在IamgeView中.当然你可以选择将结果同时存放在sd卡中,作为以后的缓存. 思路: 1.通过拍照获取图片 进入系统自带的相机界面——>拍照——>保存在sd卡中——>读取sd卡的文件进行裁减.PS:裁剪前先判断是否获取到图片了 2.通过系统相册获取图片 进入系统相册——>找到图片——>进行裁减.PS:裁剪前线判断是否获取到系统的图片了 接下来贴上实现方法: 1.进入拍照界面或者相册的方法,获取信息后