Android调用相册或相机拍照选取照片并裁剪


★ 参考代码

package com.zlf.jarzip;

import java.io.ByteArrayOutputStream;
import java.io.File;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;

/**
 * 获取图片
 * 
 */
public class SelectPhotoActivity extends Activity {

	public static final int REQUEST_CODE_PHOTOGRAPH = 1;	// 系统拍照
	public static final int REQUEST_CODE_ALBUM = 2; 		// 本地相册
	public static final int REQUEST_CODE_CUT = 3;			// 缩放裁剪

	public static final String IMAGE_UNSPECIFIED = "image/*";

	private ImageView imageView = null;
	private Button button0 = null;
	private Button button1 = null;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		// 选择相册:返回Uri对象
		((Button)(findViewById(R.id.graph_btn))).setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Intent intent = new Intent(Intent.ACTION_PICK, null);
				intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 
						IMAGE_UNSPECIFIED);
				startActivityForResult(intent, REQUEST_CODE_ALBUM);
			}
		});

		// 选择拍照:获取Uri对象 或者 Bitmap对象
		((Button)(findViewById(R.id.album_btn))).setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
				/*
				 * 1.如果为Intent添加以下Extra,则拍照完成后,系统自动保存图片文件到指定文件夹下的文件中,intent中包含Uri数据,
				 * 		此时onActivityResult方法中返回的intent data为null:data.getData() == null;
				 * 
				 * 2.如果不添加,则intent中返回的是Bitmap对象(注意:返回的 Bitmap 对象是缩略图尺寸!)
				 * 		Bitmap bmp = data.getParcelableExtra("data");
				 * 
				 */
				intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(
						Environment.getExternalStorageDirectory(), "ketwangwai_temp.jpg")));
				startActivityForResult(intent, REQUEST_CODE_PHOTOGRAPH);
			}
		});
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		//必须针对resultCode进行判断,防止在调用系统程序时非正常返回导致的错误
		if (resultCode == RESULT_OK){
			return;
		}
		switch (requestCode) {
		//系统拍照
		case REQUEST_CODE_PHOTOGRAPH:
			File picture = new File(Environment.getExternalStorageDirectory()
					+ "/ketwangwai_temp.jpg");
			startPhotoZoom(Uri.fromFile(picture));
			break;
		//本地相册
		case REQUEST_CODE_ALBUM:
			Uri uri = data.getData();
			if (uri != null) {
				startPhotoZoom(data.getData());
			}
			break;
		//缩放裁剪
		case REQUEST_CODE_CUT:
			Bundle extras = data.getExtras();
			if (extras != null) {
				Bitmap photo = extras.getParcelable("data");
				ByteArrayOutputStream stream = new ByteArrayOutputStream();
				photo.compress(Bitmap.CompressFormat.JPEG, 75, stream);
				imageView.setImageBitmap(photo);
			}
			break;
		}
		super.onActivityResult(requestCode, resultCode, data);
	}

	/**
	 * 调用系统裁剪图片的方法,可以选择参数为Uri对象 或者 Bitmap对象
	 * 
	 * @param uri
	 */
	public void startPhotoZoom(Uri uri) {
		Intent intent = new Intent("com.android.camera.action.CROP");
		intent.setDataAndType(uri, IMAGE_UNSPECIFIED);
		// 发送裁剪信号
		intent.putExtra("crop", "true");
		// aspectX aspectY 是宽高比例
		intent.putExtra("aspectX", 1);
		intent.putExtra("aspectY", 1);
		// outputX outputY 是裁剪输出图片宽高
		intent.putExtra("outputX", 64);
		intent.putExtra("outputY", 64);
		// intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);//直接输出文件
		// intent.putExtra("noFaceDetection", true); //关闭人脸检测
		intent.putExtra("return-data", true); // 是否返回数据
		startActivityForResult(intent, REQUEST_CODE_CUT);
	}
}


★ 注意问题

1.outputX与outputY如果设置参数太大,会出现卡屏问题,可能是参数大,处理图片比较慢造成的,也许应该使用辅助线程吧...


2.使用魅族手机,调用系统裁剪完成后,在onActivityResult中获取不到data数据,其他机器不存在这样的问题,解决办法如下:

                mPhoto = extras.getParcelable("data");
                if (mPhoto == null) {
                    String filePath = extras.getString("filePath");
                    if (!StringUtils.isEmpty(filePath))
                        mPhoto = ImageUtils.decodeSampledBitmapFromFile(filePath, 400, 600);
                }


出现上述问题,主要存在于部分手机硬件设置,如跳转值拍照界面时,发生横竖屏切换,导致的Activity生命周期的变化(onDestroy --> onCreate),参考如下:

AndroidManifest.xml中的Activity标签中android:configChanges属性:

通过设置这个属性可以使Activity捕捉设备状态变化,以下是可以被识别的内容:  
设置方法:将下列字段用“|”符号分隔开,例如:“locale|navigation|orientation

ValueDescription
mccThe IMSI mobile country code (MCC) has changed — that is, a SIM hasbeen detected and updated the MCC.移动国家号码,由三位数字组成,每个国家都有自己独立的MCC,可以识别手机用户所属国家。
mncThe IMSI mobile network code (MNC) has changed — that is, a SIM hasbeen detected and updated the MNC.移动网号,在一个国家或者地区中,用于区分手机用户的服务商。
localeThe locale has changed — for example, the user has selected a new language that text should be displayed in.用户所在地区发生变化。
touchscreenThe touchscreen has changed. (This should never normally happen.)
keyboardThe keyboard type has changed — for example, the user has plugged in an external keyboard.键盘模式发生变化,例如:用户接入外部键盘输入
keyboardHiddenThe keyboard accessibility has changed — for example, the user has slid the keyboard out to expose it.用户打开手机硬件键盘
navigationThe navigation type has changed. (This should never normally happen.)
orientationThe screen orientation has changed — that is, the user has rotated the device.设备旋转,横向显示和竖向显示模式切换。
fontScaleThe font scaling factor has changed — that is, the user has selected a new global font size.全局字体大小缩放发生改变

在Activity中添加了 android:configChanges属性,目的是当所指定属性(Configuration Changes)发生改变时,通知程序调用 onConfigurationChanged()函数。

横竖屏切换时候activity的生命周期 android:configChanges

01、不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次

02、设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次

03、设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法

3. ImageView setImageURI图片不变化的问题

问题描述:多次拍照或裁剪图片保存本地的时候,如果使用相同的文件名,即URI对应的文件路径相同的情况下,调用setImageURI方法无法更新显示的图片,ImageView始终显示初始的第一张图片。

问题分析:setImageURI方法对uri进行了缓存,导致即使图片内容发生改变,但uri没有变化,所以ImageView显示的还是之前的图片内容,这一点从源码中可以看出:

public void setImageURI(Uri uri) {
        if (mResource != 0 ||
                (mUri != uri &&
                 (uri == null || mUri == null || !uri.equals(mUri)))) {
            updateDrawable(null);
            mResource = 0;
            mUri = uri;

            final int oldWidth = mDrawableWidth;
            final int oldHeight = mDrawableHeight;

            resolveUri();

            if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
                requestLayout();
            }
            invalidate();
        }
    }
解决方案:

01. 使用不同的文件名(即不同的uri),可以利用时间戳等方式实现;

02. 使用setImageBitmap方法替换setImageURI方法显示图片内容。


★ 相关拓展:


	/**
	 * 依据Uri获取文件地址
	 * @param uri
	 * return 
	 */
	private String getFilePathFromUri(Uri uri) {
        String[] filePathColumn = { MediaStore.Images.Media.DATA };
        Cursor cursor = getContentResolver().query(uri, filePathColumn, null, null, null);
        cursor.moveToFirst();
        int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
        String picturePath = cursor.getString(columnIndex);
        cursor.close();
        return picturePath;
	}
	
	/**
	 * 使用Base64对文件编码,并返回字符串
	 * @param filePath
	 * @return
	 */
	public static String fileToBase64String(String filePath) {
		File photoFile = new File(filePath);
		try {
			FileInputStream fis = new FileInputStream(photoFile);
			ByteArrayOutputStream baos = new ByteArrayOutputStream(10000);
			byte[] buffer = new byte[1000];
			while (fis.read(buffer)!=-1) {
				baos.write(buffer);
			}
			baos.close();
			fis.close();
			return Base64.encode(baos.toByteArray(), Base64.DEFAULT).toString();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * zip压缩
	 * @param filePath
	 * @return 返回zip文件地址
	 */
	public String zipCompass(String filePath){
		File zipFile = new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis() + ".zip");
		try{
			//指定了两个待压缩的文件,都在assets目录中
			String[] filenames = new String[]{ "activity_main.xml", "strings.xml" };
			FileOutputStream fos = new FileOutputStream(zipFile);
			ZipOutputStream zos = new ZipOutputStream(fos);
			int i = 1;
			//枚举filenames中的所有待压缩文件
			while (i <= filenames.length){
				//从filenames数组中取出当前待压缩的文件名,作为压缩后的名称,以保证压缩前后文件名一致
				ZipEntry zipEntry = new ZipEntry(filenames[i - 1]);
				//打开当前的zipEntry对象
				zos.putNextEntry(zipEntry);

				FileInputStream is = new FileInputStream(filePath);
				byte[] buffer = new byte[8192];
				int count = 0;
				//写入数据
				while ((count = is.read(buffer)) >= 0){
					zos.write(buffer, 0, count);
				}
				zos.flush();
				zos.closeEntry();
				is.close();
				i++;

			}
			zos.finish();
			zos.close();
			return zipFile.getAbsolutePath();
		}
		catch (Exception e){
			Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
			return null;
		}
	}



Android Zip压缩和解压缩参考博文: http://blog.csdn.net/zlfxy/article/details/8625297


参考博客http://blog.csdn.net/leechee_1986/article/details/25049243

参考官网:https://developer.android.com/training/camera/photobasics.html



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值