Android选择图片并裁剪。

写在前面:个人有个习惯,在非必要的情况下,我不喜欢用第三方包,因为有些东西太复杂了,不好改,在只需要特定某功能的时候也增加了apk包大小。当然,这里的图片裁剪也是。啥都不懂,网上胡乱搜索,很多都没完整的,然后自己研究了好久搞出来了!所以决定分享给大家。当然,理还是那个理,网上多的是,但区别就是:必须满足伸手党,拿来即用!


原理:调用系统打开图像方法,返回一个uri,然后根据版本(4.4以上或以下)然后处理uri(因为4.4以上和4.4以下返回uri不同,复杂点的地方就在这里),再调用裁剪图片的方法,裁剪图片成功后将裁剪的结果图片存放到一个自己指定的文件夹下,最后显示到ImageView上。本来还想加上上传代码的,后来想了一下,反正没上传地址,也测试不了。需要上传代码的大家其余地方去找找。

其实代码很简单。难点的地方有注释!

下面直接上源码,不是代码块啊,整个文件的贴!

下载地址:http://download.csdn.net/detail/parcool/8223483

图:





MainActivity:

package com.parcool.mycroppicandupload;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.Calendar;

import com.parcool.mycroppicandupload.utils.AppConstant;
import com.parcool.mycroppicandupload.utils.Utils;

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.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivity extends Activity implements OnClickListener {

	private Button btnSelect;
	private ImageView ivResult;

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

	// 初始化控件
	private void init() {
		// TODO Auto-generated method stub
		btnSelect = (Button) findViewById(R.id.btn_select);
		btnSelect.setOnClickListener(this);
		ivResult = (ImageView) findViewById(R.id.iv_result);
	}

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		switch (v.getId()) {
		case R.id.btn_select:
			Utils.getInstance().selectPicture(this);
			break;

		case R.id.iv_result:
			break;
		}
	}

	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		// TODO Auto-generated method stub
		super.onActivityResult(requestCode, resultCode, data);
		if (resultCode != Activity.RESULT_OK) {
			return;
		}
		if (null == data) {
			return;
		}
		Uri uri = null;
		if (requestCode == AppConstant.KITKAT_LESS) {
			uri = data.getData();
			Log.d("tag", "uri=" + uri);
			// 调用裁剪方法
			Utils.getInstance().cropPicture(this, uri);
		} else if (requestCode == AppConstant.KITKAT_ABOVE) {
			uri = data.getData();
			Log.d("tag", "uri=" + uri);
			// 先将这个uri转换为path,然后再转换为uri
			String thePath = Utils.getInstance().getPath(this, uri);
			Utils.getInstance().cropPicture(this,
					Uri.fromFile(new File(thePath)));
		} else if (requestCode == AppConstant.INTENT_CROP) {
			Bitmap bitmap = data.getParcelableExtra("data");
			ivResult.setImageBitmap(bitmap);
			File temp = new File(Environment.getExternalStorageDirectory()
					.getPath() + "/yourAppCacheFolder/");// 自已缓存文件夹
			if (!temp.exists()) {
				temp.mkdir();
			}
			File tempFile = new File(temp.getAbsolutePath()+"/"
					+ Calendar.getInstance().getTimeInMillis() + ".jpg"); // 以时间秒为文件名
			// 图像保存到文件中
			FileOutputStream foutput = null;
			try {
				foutput = new FileOutputStream(tempFile);
				if (bitmap.compress(Bitmap.CompressFormat.JPEG, 100, foutput)) {
					Toast.makeText(MainActivity.this,
							"已生成缓存文件,等待上传!文件位置:" + tempFile.getAbsolutePath(),
							Toast.LENGTH_LONG).show();
				}
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

}


Utils:

package com.parcool.mycroppicandupload.utils;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;


public class Utils {
	private static Utils utils;

	public static Utils getInstance() {
		if (utils == null) {
			utils = new Utils();
		}
		return utils;
	}
	
	
	/***
	 * 选择一张图片
	 * 图片类型,这里是image/*,当然也可以设置限制
	 * 如:image/jpeg等
	 * @param activity Activity
	 */
	@SuppressLint("InlinedApi")
	public void selectPicture(Activity activity) {
		if (Build.VERSION.SDK_INT < 19) {
			Intent intent = new Intent();
			intent.setType("image/*");
			intent.setAction(Intent.ACTION_GET_CONTENT);
			//由于startActivityForResult()的第二个参数"requestCode"为常量,
			//个人喜好把常量用一个类全部装起来,不知道各位大神对这种做法有异议没?
			activity.startActivityForResult(intent, AppConstant.KITKAT_LESS);
		} else {
			Intent intent = new Intent();
			intent.setType("image/*");
			//由于Intent.ACTION_OPEN_DOCUMENT的版本是4.4以上的内容
			//所以注意这个方法的最上面添加了@SuppressLint("InlinedApi")
			//如果客户使用的不是4.4以上的版本,因为前面有判断,所以根本不会走else,
			//也就不会出现任何因为这句代码引发的错误
			intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
			activity.startActivityForResult(intent, AppConstant.KITKAT_ABOVE);
		}
	}
	
	
	/***
	 * 裁剪图片
	 * @param activity Activity
	 * @param uri 图片的Uri
	 */
	public void cropPicture(Activity activity, Uri uri) {
		Intent innerIntent = new Intent("com.android.camera.action.CROP");
		innerIntent.setDataAndType(uri, "image/*");
		innerIntent.putExtra("crop", "true");// 才能出剪辑的小方框,不然没有剪辑功能,只能选取图片
		innerIntent.putExtra("aspectX", 1); // 放大缩小比例的X
		innerIntent.putExtra("aspectY", 1);// 放大缩小比例的X   这里的比例为:   1:1
		innerIntent.putExtra("outputX", 320);  //这个是限制输出图片大小
		innerIntent.putExtra("outputY", 320); 
		innerIntent.putExtra("return-data", true);
		innerIntent.putExtra("scale", true);
		activity.startActivityForResult(innerIntent, AppConstant.INTENT_CROP);
	}
	
	
	/**
	 * 下面几个方法来自于stackoverflow,虽然来自大神,但大神的代码也不是就那样?
	 * 看不懂的地方挨个百度。
	 * -----------------------割-------------------------
	 * Get a file path from a Uri. This will get the the path for Storage Access
	 * Framework Documents, as well as the _data field for the MediaStore and
	 * other file-based ContentProviders.
	 * 
	 * @param context
	 *            The context.
	 * @param uri
	 *            The Uri to query.
	 * @author paulburke
	 */
	@SuppressLint("NewApi")
	public String getPath(final Context context, final Uri uri) {

		final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;

		// DocumentProvider
		if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
			// ExternalStorageProvider
			if (isExternalStorageDocument(uri)) {
				final String docId = DocumentsContract.getDocumentId(uri);
				final String[] split = docId.split(":");
				final String type = split[0];

				if ("primary".equalsIgnoreCase(type)) {
					return Environment.getExternalStorageDirectory() + "/"
							+ split[1];
				}

				// TODO handle non-primary volumes
			}
			// DownloadsProvider
			else if (isDownloadsDocument(uri)) {
				final String id = DocumentsContract.getDocumentId(uri);
				final Uri contentUri = ContentUris.withAppendedId(
						Uri.parse("content://downloads/public_downloads"),
						Long.valueOf(id));

				return getDataColumn(context, contentUri, null, null);
			}
			// MediaProvider
			else if (isMediaDocument(uri)) {
				final String docId = DocumentsContract.getDocumentId(uri);
				final String[] split = docId.split(":");
				final String type = split[0];

				Uri contentUri = null;
				if ("image".equals(type)) {
					contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
				} else if ("video".equals(type)) {
					contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
				} else if ("audio".equals(type)) {
					contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
				}

				final String selection = "_id=?";
				final String[] selectionArgs = new String[] { split[1] };

				return getDataColumn(context, contentUri, selection,
						selectionArgs);
			}
		}
		// MediaStore (and general)
		else if ("content".equalsIgnoreCase(uri.getScheme())) {

			// Return the remote address
			if (isGooglePhotosUri(uri))
				return uri.getLastPathSegment();

			return getDataColumn(context, uri, null, null);
		}
		// File
		else if ("file".equalsIgnoreCase(uri.getScheme())) {
			return uri.getPath();
		}

		return null;
	}
	
	
	/**
	 * Get the value of the data column for this Uri. This is useful for
	 * MediaStore Uris, and other file-based ContentProviders.
	 * 
	 * @param context
	 *            The context.
	 * @param uri
	 *            The Uri to query.
	 * @param selection
	 *            (Optional) Filter used in the query.
	 * @param selectionArgs
	 *            (Optional) Selection arguments used in the query.
	 * @return The value of the _data column, which is typically a file path.
	 */
	public String getDataColumn(Context context, Uri uri, String selection,
			String[] selectionArgs) {

		Cursor cursor = null;
		final String column = "_data";
		final String[] projection = { column };

		try {
			cursor = context.getContentResolver().query(uri, projection,
					selection, selectionArgs, null);
			if (cursor != null && cursor.moveToFirst()) {
				final int index = cursor.getColumnIndexOrThrow(column);
				return cursor.getString(index);
			}
		} finally {
			if (cursor != null)
				cursor.close();
		}
		return null;
	}

	/**
	 * @param uri
	 *            The Uri to check.
	 * @return Whether the Uri authority is ExternalStorageProvider.
	 */
	public static boolean isExternalStorageDocument(Uri uri) {
		return "com.android.externalstorage.documents".equals(uri
				.getAuthority());
	}

	/**
	 * @param uri
	 *            The Uri to check.
	 * @return Whether the Uri authority is DownloadsProvider.
	 */
	public static boolean isDownloadsDocument(Uri uri) {
		return "com.android.providers.downloads.documents".equals(uri
				.getAuthority());
	}

	/**
	 * @param uri
	 *            The Uri to check.
	 * @return Whether the Uri authority is MediaProvider.
	 */
	public static boolean isMediaDocument(Uri uri) {
		return "com.android.providers.media.documents".equals(uri
				.getAuthority());
	}

	/**
	 * @param uri
	 *            The Uri to check.
	 * @return Whether the Uri authority is Google Photos.
	 */
	public static boolean isGooglePhotosUri(Uri uri) {
		return "com.google.android.apps.photos.content".equals(uri
				.getAuthority());
	}
}


AppConstant:

package com.parcool.mycroppicandupload.utils;

public class AppConstant {
	/***
	 * 4.4以下(也就是kitkat以下)的版本
	 */
	public static final int KITKAT_LESS = 0;
	/***
	 * 4.4以上(也就是kitkat以上)的版本,当然也包括最新出的5.0棒棒糖
	 */
	public static final int KITKAT_ABOVE = 1;
	
	/***
	 * 裁剪图片成功后返回
	 */
	public static final int INTENT_CROP = 2;
}

资源文件(activity_main.xml):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <TextView
        android:id="@+id/tv_tips"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/tips_plz_select_pic_to_upload" />

    <Button
        android:id="@+id/btn_select"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/tv_tips"
        android:text="@string/btn_select" />

    <ImageView
        android:id="@+id/iv_result"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/btn_select"
        android:contentDescription="@string/app_name" />

</RelativeLayout>


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值