首页 > 代码库 > 从相机相册获取图片裁剪后用于评论晒图或更换背景图
从相机相册获取图片裁剪后用于评论晒图或更换背景图
这是我人生中写的第一篇博客,是否要纪念一下这一刻(2016.09.01 16:52)。其实关于写博客,老早就有这种写法,首先觉得他能够帮我总结我学到的和用过的技术,其次还能帮助那些和我有一样需求的人,我也是很开心啊,但是至于为什么现在才写第一篇,首先没有想好写什么,然后前段时间也确实比较忙。是不是那些来观技术的人已经想骂人了啊。。。啊哦!原谅我第一次写博客的激动心情吧!
废话不多说,开始我们的问题吧,首先因为我做了两次关于调用相机和相册获取图片的功能,觉得很有必要总结一下,下面我将从这两个功能出发完成这篇泊车
一、功能描述:
类似于淘宝评论中上传图片的功能先上图
1.实现步骤:
①点击打开底部Dialog去选择拍照或者相册
/**
* 1)打开底部弹窗
*
* @author 陈静
* @version 2016-9-1 下午5:21:21
*/
private void openDialog() {
mtakephoteDialog = new Dialog(this, R.style.my_dialog);
LinearLayout view = (LinearLayout) LayoutInflater.from(
MainActivity.this).inflate(R.layout.my_takephoto_dialog, null);
TextView tp_dialog_tv = (TextView) view.findViewById(R.id.tp_dialog_tv);
view.findViewById(R.id.tp_dialog_takebtn).setOnClickListener(
MainActivity.this);
view.findViewById(R.id.tp_dialog_picturebtn).setOnClickListener(
MainActivity.this);
view.findViewById(R.id.tp_dialog_canclebtn).setOnClickListener(
MainActivity.this);
tp_dialog_tv.setText("亲,你还可上传" + (2 - PHOTO_SUM) + "张照片");
showBottomDialog(MainActivity.this, view, mtakephoteDialog);
}
/**
* 2)显示底部弹窗
*/
public final void showBottomDialog(Context context, View layout,
Dialog myDialog) {
// Dialog mCameraDialog = new Dialog(context, R.style.my_dialog);
myDialog.setContentView(layout);
Window dialogWindow = myDialog.getWindow();
dialogWindow.setGravity(Gravity.BOTTOM);
dialogWindow.setWindowAnimations(R.style.dialogstyle);// 添加动画
WindowManager.LayoutParams lp = dialogWindow.getAttributes();// 获取对话框当前的参数值
lp.x = 0;// 新位置X坐标
lp.y = -20;// 新位置Y坐标
lp.width = (int) getResources().getDisplayMetrics().widthPixels;// 宽度//
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;// 高度
lp.alpha = 9f;// 透明度
layout.measure(0, 0);
lp.height = layout.getMeasuredHeight();
lp.alpha = 9f; // 透明度
dialogWindow.setAttributes(lp);
myDialog.show();
}
/**
* 3)在styles.xml中配置弹窗样式
* */
<style name="my_dialog" parent="@android:style/Theme.Dialog">
<item name="android:windowFrame">@null</item>
<!-- 边框 -->
<item name="android:windowIsFloating">true</item>
<!-- 是否浮现在activity之上 -->
<item name="android:windowIsTranslucent">false</item>
<!-- 半透明 -->
<item name="android:windowNoTitle">true</item>
<!-- 无标题 -->
<item name="android:windowBackground">@android:color/transparent</item>
<!-- 背景透明 -->
<item name="android:backgroundDimEnabled">true</item>
<!-- 模糊 -->
</style>
<style name="dialogstyle" parent="android:Animation">
<item name="@android:windowEnterAnimation">@anim/dialog_enter</item>
<item name="@android:windowExitAnimation">@anim/dialog_exit</item>
</style>
/**
* 4)在res下创建anim 文件夹,添加用到的两个动画
* */
--- dialog_enter.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<translate
android:duration="400"
android:fromYDelta="100%p" />
</set>
--- dialog_exit.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<translate
android:duration="400"
android:toYDelta="100%p" />
</set>
②点击打开相册或相机
1)点击打开相册
/*
* 从相册获取
*/
public void gallery() {
// 激活系统图库,选择一张图片
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
// 开启一个带有返回值的Activity,请求码为PHOTO_REQUEST_GALLERY
startActivityForResult(intent, PHOTO_REQUEST_GALLERY);
}
2)点击打开相机
// 相机拍照方法
private void takeCamera() {
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, PHOTO_REQUEST_CAREMA);
③获取到图片时接受相册或相机的返回图片,重写onActivityResult方法
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// 拍照返回
String imagePath = new String();
if (resultCode != Activity.RESULT_OK) {// result is not correct
return;
} else {
if (requestCode == PHOTO_REQUEST_GALLERY) {
// 从相册返回的数据
if (data != null) {
// 得到图片的全路径
Uri uri = data.getData();
// 展示图片
if (PHOTO_SUM == 0) {
takephoto1.setVisibility(View.VISIBLE);
// 加载本地图片(路径以/开头, 绝对路径)
bitmapUtils.display(takephoto1,
getAbsoluteImagePath(uri));
} else if (PHOTO_SUM == 1) {
takephoto2.setVisibility(View.VISIBLE);
evalute_takephoto_ib.setVisibility(View.GONE);
bitmapUtils.display(takephoto2,
getAbsoluteImagePath(uri));
}
PHOTO_SUM += 1;
// 图片地址添加到集合中
imagePath = getAbsoluteImagePath(uri);
mFile.add(new File(imagePath));
}
} else if (requestCode == PHOTO_REQUEST_CAREMA) {
// 根据有没有SD卡给出相关路径
String picName = "evalute" + System.currentTimeMillis()
+ ".png";
String picPath = new String();
if (hasSdcard()) {
picPath = Environment.getExternalStorageDirectory()
.toString();
imagePath = picPath + "/" + picName;
} else {
picPath = this.getFilesDir().toString();
imagePath = picPath + "/" + picName;
}
// 得到图片的全路径
Bitmap bitmap = data.getParcelableExtra("data");
saveBitmap(picPath, picName, bitmap);// 图片保存到本地
mFile.add(new File(imagePath));// 保存路径添加到集合中
// 在界面上展示对应图片
if (PHOTO_SUM == 0) {
takephoto1.setVisibility(View.VISIBLE);
this.takephoto1.setImageBitmap(bitmap);
} else if (PHOTO_SUM == 1) {
takephoto2.setVisibility(View.VISIBLE);
evalute_takephoto_ib.setVisibility(View.GONE);
this.takephoto2.setImageBitmap(bitmap);
}
PHOTO_SUM += 1;
}
}
// 关闭底部弹窗
if (mtakephoteDialog != null) {
mtakephoteDialog.dismiss();
}
super.onActivityResult(requestCode, resultCode, data);
}
④提供这其中用到的几个方法
/**
* 将Uri转换为绝对路径
*
* @author 陈静
* @version 2016-7-29 下午2:50:18
*/
protected String getAbsoluteImagePath(Uri uri) {
// can post image
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, proj, null, null, null);
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
/**
* 将拍摄的图片保存到本地
*
* @author 陈静
* @version 2016-7-29 下午2:50:53
*/
public void saveBitmap(String picPath, String picName, Bitmap bm) {
File f = new File(picPath, picName);
if (f.exists()) {
f.delete();
}
try {
FileOutputStream out = new FileOutputStream(f);
bm.compress(Bitmap.CompressFormat.PNG, 90, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* 判断sdcard是否被挂载
*/
private boolean hasSdcard() {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
return true;
} else {
return false;
}
}
2.温馨提示
①此界面显示图片用到了Xutils的bitmaputils
②在此功能中添加private List<File> mFile = new ArrayList<File>();// 把图片保存到file数组中用于循环上传到服务器
二、功能描述:
类似于微信朋友圈点击更换背景图片的功能,即:点击图片后弹窗提示更换背景图片,点击后跳转页面,去选择拍照还是从相册获取,并进行裁剪后返回到上一个页面,这里也上张图吧
1.实现步骤:
①点击弹出popuwindow提示更换背景图片
// 弹出更换背景图片的popuwindow
private void changBGPopuwindow() {
// 1.加载布局
View mView = View.inflate(MainActivity.this,
R.layout.change_userinfo_bg, null);
pm = new PopupWindow(mView, LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT, true);
// 如果不添加这行代码,点击pw区域之外的地方不能关闭pw
pm.setBackgroundDrawable(new ColorDrawable());
// pm.showAsDropDown(cic_part1_0_rl,0,-cic_part1_0_rl.getHeight());
pm.showAtLocation(rl, Gravity.CENTER, 0, 150);
}
②点击更换背景图片的跳转选择相机或拍照的页面
// 点击更换背景图片的Poupuwindow
public void changUsesBg(View v) {
pm.dismiss();
Intent intent = new Intent();
intent.setClass(MainActivity.this, ChangeBGActivity.class);
startActivityForResult(intent, 777);
}
③ 点击相机或拍照
// 相机拍照方法
private void takeCamera() {
// Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// startActivityForResult(cameraIntent, PHOTO_REQUEST_CAREMA);
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
boolean sdCardExist = Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA_MOUNTED); // 判断sd卡是否存在
if (sdCardExist == true) {
imageUri = Uri.fromFile(new File(Environment
.getExternalStorageDirectory(), picName));
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(cameraIntent, PHOTO_REQUEST_CAREMA);
} else {
imageUri = Uri.fromFile(new File(ChangeBGActivity.this
.getFilesDir(), picName));
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(cameraIntent, PHOTO_REQUEST_CAREMA);
}
}
/*
* 从相册获取
*/
public void gallery() {
// 激活系统图库,选择一张图片
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
// 开启一个带有返回值的Activity,请求码为PHOTO_REQUEST_GALLERY
startActivityForResult(intent, PHOTO_REQUEST_GALLERY);
}
④重写onActivityResult方法接收相机或相册传回来的图片,然后调用裁剪的方法得到最终图片后传递到上一个界面
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
String imagePath = new String();
if (resultCode != Activity.RESULT_OK) {// result is not correct
return;
} else {
if (requestCode == PHOTO_REQUEST_GALLERY) {
// 从相册返回的数据
if (data != null) {
// 得到图片的全路径
Uri uri = data.getData();
// 裁剪图片
crop(uri);
// 图片地址添加到集合中
imagePath = getAbsoluteImagePath(uri);
mFile.add(new File(imagePath));
}
} else if (requestCode == PHOTO_REQUEST_CAREMA) {
// 根据有没有SD卡给出相关路径
String picPath = new String();
if (hasSdcard()) {
picPath = Environment.getExternalStorageDirectory()
.toString();
imagePath = picPath + "/" + picName;
} else {
picPath = this.getFilesDir().toString();
imagePath = picPath + "/" + picName;
}
// 裁剪图片
crop(Uri.fromFile(new File(imagePath)));
// 得到图片的全路径
// Bitmap bitmap = data.getParcelableExtra("data");
// saveBitmap(picPath, picName, bitmap);// 图片保存到本地
// mFile.add(new File(imagePath));// 保存路径添加到集合中
// 在界面上展示对应图片
} else if (requestCode == PHOTO_REQUEST_CUT) {
// 从剪切图片返回的数据
if (data != null) {
Bitmap bitmap = data.getParcelableExtra("data");
Intent intent = getIntent();
intent.putExtra("bitmap", bitmap);
setResult(666, intent);
finish();
}
try {
// 将临时文件删除
// tempFile.delete();
} catch (Exception e) {
e.printStackTrace();
}
}
}
super.onActivityResult(requestCode, resultCode, data);
}
⑤调用裁剪的方法
// 剪切图片
private void crop(Uri uri) {
// 裁剪图片意图
// Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/*");
intent.putExtra("crop", "true");// 裁剪框的比例,1:1
intent.putExtra("scale", true);// 去黑边
intent.putExtra("aspectX", 11);
intent.putExtra("aspectY", 8); // 裁剪后输出图片的尺寸大小
intent.putExtra("outputX", 220);
intent.putExtra("outputY", 160);
intent.putExtra("outputFormat", "PNG");// 图片格式
intent.putExtra("noFaceDetection", true);// 取消人脸识别
intent.putExtra("return-data", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
intent.putExtra("outputFormat", Bitmap.CompressFormat.PNG.toString());
// 设置剪切的图片保存位置
Uri cropUri = null;
if (hasSdcard()) {
cropUri = Uri.fromFile(new File(Environment
.getExternalStorageDirectory(), "bg_crop.png"));
} else {
cropUri = Uri.fromFile(new File(ChangeBGActivity.this
.getFilesDir(), "bg_crop.png"));
}
intent.putExtra(MediaStore.EXTRA_OUTPUT, cropUri);
// 开启一个带有返回值的Activity,请求码为PHOTO_REQUEST_CUT
startActivityForResult(intent, PHOTO_REQUEST_CUT);
}
⑥在上一个界面接受传递过来的图片并显示
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// changBgActivity返回的数据
if (resultCode == 666) {
Bitmap bitmap = data.getParcelableExtra("bitmap");
BitmapDrawable bd = new BitmapDrawable(bitmap);
rl.setBackgroundDrawable(bd);
}
super.onActivityResult(requestCode, resultCode, data);
}
⑦在界面下一次打开时,回显该图片
// 判断有没有背景图片
Uri cropUri = null;
if (hasSdcard()) {
cropUri = Uri.fromFile(new File(Environment
.getExternalStorageDirectory(), "bg_crop.png"));
} else {
cropUri = Uri.fromFile(new File(MainActivity.this.getFilesDir(),
"bg_crop.png"));
}
rl.setBackgroundDrawable(Drawable.createFromPath(cropUri.getPath()));
}
2.温馨提示:
①此功能中用到的一些方法已在功能已中提供,不在细列
②输出的图片有2种情况:
1)如果你没有指定Intent里面的Extra参数,它就返回一个序列化(putExtra(“data”, bitmap))的Bitmap(参照1. 获得拍照的预览图)。
2)如果你指定了Intent里面的Extra参数MediaStore.EXTRA_OUTPUT,拍照后它就直接把bitmap写到了Uri里面了,返回是空
结语:
至此,我的第一篇博客结束了,可能表达的不是很清楚,但希望能够对需要的人有所帮助,为了能让大家更方便我单独整理除了一个Demo(eclipse),供大家参考,喜欢的话,就鼓励我吧,以后我就会更愿意分享更多的东西了
下载源码:http://download.csdn.net/detail/qq_25283953/9619905
从相机相册获取图片裁剪后用于评论晒图或更换背景图