拍照/选择图库头像/裁剪

阅读: 评论:0

拍照/选择图库头像/裁剪

拍照/选择图库头像/裁剪

当前项目用到了拍照/从相册选取照片并裁剪展示到ImageView上的功能,在网上找到很多资料,却发现大同小异,知道我看到Ryan Hoo大神的文章 茅塞顿开,在此记录一下原理以及实现步骤.
一.点击相应Button弹出拍照/从相册选取/取消布局(如图)


拍照/照片图库.jpg

实现方式很多 可以用Dialogfragment 我的做法是PopWindow,代码贴上:

t.Context;
aphics.drawable.ColorDrawable;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.PopupWindow;
import android.widget.TextView;
/** * PopWindow */
public class SelectPicturePopupWindow extends PopupWindow implements View.OnClickListener, PopupWindow.OnDismissListener {    private View mContentView;    private Context mContext;    private PictureCallBack mPictureCallBack;    public SelectPicturePopupWindow(Context context, PictureCallBack pictureCallBack) {super(context);this.mContext = context;this.mPictureCallBack = pictureCallBack;init(context);    
}private void init(Context context) {mContentView = LayoutInflater.from(context).inflate(R.layout.popup_select_picture,null);mContentView.setOnClickListener(this);        // 设置SelectPicPopupWindow的Viewthis.setContentView(mContentView);        // 设置SelectPicPopupWindow弹出窗体的宽this.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);        // 设置SelectPicPopupWindow弹出窗体的高this.setHeight(ViewGroup.LayoutParams.MATCH_PARENT);        // 刷新状态this.update();        // 实例化一个ColorDrawable颜色为半透明ColorDrawable dw = new ColorDrawable(0000000000);        // 点back键和其他地方使其消失,设置了这个才能触发OnDismisslistener ,设置其他控件变化等操作this.setBackgroundDrawable(dw);TextView cancel = (TextView) mContentView.findViewById(R.id.popup_cancel);TextView gallery = (TextView) mContentView.findViewById(R.id.popup_select_from_gallery);TextView takePicture = (TextView) mContentView.findViewById(R.id.popup_take_picture); cancel.setOnClickListener(this);gallery.setOnClickListener(this);takePicture.setOnClickListener(this);setOnDismissListener(this);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.popup_cancel:                //取消break;case R.id.popup_select_from_gallery:                //图片图库if (mPictureCallBack != null) {SelectFromGallery();}break;case R.id.popup_take_picture:       //拍照if (mPictureCallBack != null) {TakePicture();}break;}dismiss();}@Overridepublic void onDismiss() {dismiss();}public interface PictureCallBack{void onTakePicture();void onSelectFromGallery();}   /** * 显示popupWindow* @param parent*/public void show(View parent) {if (!this.isShowing()) { // 以下拉方式显示popupwindow showAtLocation(parent, Gravity.NO_GRAVITY,0,0);} else {this.dismiss();}}
}

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android=""              android:layout_width="match_parent"              android:layout_height="match_parent"              android:background="#88000000"android:gravity="bottom"android:orientation="vertical"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:layout_marginBottom="10dp"android:background="@drawable/popup_white_bg"android:orientation="vertical"><TextViewandroid:id="@+id/popup_take_picture"android:layout_width="match_parent"android:layout_height="45dp" android:gravity="center"android:paddingLeft="20dp"android:text="拍照"android:textColor="#666666"/><Viewandroid:layout_width="match_parent"android:layout_height="1px"            android:background="#dfdfdf"/><TextViewandroid:id="@+id/popup_select_from_gallery"android:layout_width="match_parent"android:layout_height="45dp"android:gravity="center"android:paddingLeft="20dp"android:text="照片图库"android:textColor="#666666"/></LinearLayout><TextViewandroid:id="@+id/popup_cancel"android:layout_width="match_parent"android:layout_height="45dp"android:background="@drawable/popup_white_bg"android:gravity="center"android:paddingLeft="20dp"android:text="取消"android:textColor="#666666"/>
</LinearLayout>

注释也很清晰 在此不做过多赘述,接下来进入重点,首先是拍照截图:
(一).在Button点击事件中弹出刚自定义的Popwindow:

@Override
public void onClick(View view) {if (Id() == R.id.btn_hey) {//弹出PopWindowif (mSelectPicturePopup == null) {mSelectPicturePopup = new SelectPicturePopupWindow(this, this);}mSelectPicturePopup.show(view);}
}

(二).准备好使用到的Uri:

private static final String IMAGE_FILE_LOCATION = "file:///sdcard/test.jpg";
Uri imageUri = Uri.parse(IMAGE_FILE_LOCATION);

(三).在回调中调用Camera程序进行拍照:

//拍照 调用相机
@Override
public void onTakePicture() {Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);startActivityForResult(intent, CODE_TAKE_PICTURE);
}

(四). onActivityResult中拿到返回的数据,并传递给截图的程序:

case CODE_TAKE_PICTURE:if(resultCode == RESULT_OK){cutPhoto(2,1,280,140,imageUri,TAKE_CUT);}break;

使用系统自带的裁剪程序的方法我封装好了一个方法:
Tip:


Paste_Image.png


intent.putExtra("return-data", false);
false代表不返回数据,返回url
true代表返回数据,bitmap

private void cutPhoto(int aspectX,int aspectY,int outputX,int outputY,Uri uri,int requestCode) {// 裁剪图片意图Intent in = new Intent("com.android.camera.action.CROP");in.setDataAndType(uri, "image/*");in.putExtra("crop", "true");// 裁剪框的比例,2:1in.putExtra("aspectX", aspectX);in.putExtra("aspectY", aspectY);// 裁剪后输出图片的尺寸大小in.putExtra("outputX", outputX);in.putExtra("outputY", outputY);in.putExtra("scale", true);in.putExtra(MediaStore.EXTRA_OUTPUT, uri);in.putExtra("return-data", true);in.putExtra("outputFormat", "PNG");// 图片格式in.putExtra("noFaceDetection", true);// 取消人脸识别startActivityForResult(in, requestCode);// 开启一个带有返回值的Activity
}

(五).最后一步,处理返回的Bitmap:

case TAKE_CUT://拍照 拿到剪切数据Bitmap bmap2 = ParcelableExtra("data");iv_photo.setImageBitmap(bmap2);

如果你在裁剪意图中返回的是url,那么只需这样转换就好:

if(imageUri != null){Bitmap bitmap = decodeUriAsBitmap(imageUri);iv_photo.setImageBitmap(bitmap);
 }
private Bitmap decodeUriAsBitmap(Uri uri){Bitmap bitmap = null;try {bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));
 } catch (FileNotFoundException e) {e.printStackTrace();return null; 
}return bitmap;
 }

贴上效果图:


显示.png


从相册图库选取只有意图和url不一样:

//从相册选取 调用android的图库
@Override
public void onSelectFromGallery() {Intent i = new Intent(Intent.ACTION_PICK,MediaStore.Images.Media.EXTERNAL_CONTENT_URI);startActivityForResult(i, CODE_FROM_GALLERY);}

在onActivityResult中

case CODE_FROM_GALLERY:if (data != null) {Uri uri = Data();if (uri != null) {cutPhoto(3,2,280,140,uri,PHOTO_REQUEST_CUT);}}

至此功能已经完成 拿到bitmap之后,我们要上传到服务器,我这边要求是Base64,那么也很简单:

public String bitmaptoString(Bitmap bitmap) {String s = null;// 将Bitmap转换成Base64字符串
    ByteArrayOutputStream bStream = new ByteArrayOutputStream();
    bitmappress(Bitmap.CompressFormat.PNG, 100, bStream);
    byte[] bytes = ByteArray();
    s = deToString(bytes, Base64.DEFAULT);
    return s;
}

bug以及我不理解的地方:
1.点击裁剪界面的取消按钮程序会直接退出,不知道怎么控制.
2(已解决,方法:将裁剪图片方法中返回数据改为false,使用url进行操作,因为直接返回bitmap,一张相片3M多,会造成OOM)
如果我将裁剪的尺寸设置为宽800 高400,那么裁剪界面的确定取消按钮都会无反应
如果我将裁剪的尺寸设置为宽560 高280那么程序会蹦,报这个错:

System: stat file error, path is /data/app/com.lxd.photocut-2/lib/arm64, exception is android.system.ErrnoException: stat failed: ENOENT (No such file or directory)

3.拍照后并没有保存到我们的手机相册中,我看了下qq微信,拍照后相册中也会有,我在查阅第一行代码(第二版)之后,按照郭霖大神的思路去写 发现无效.代码如下:

        private Uri imageUri;//创建File对象 用于存储拍照后的图片File outputImage = new File(getExternalCacheDir(),"test111.jpg");//如果文件存在 先删除try {ists()){outputImage.delete();}ateNewFile();} catch (IOException e) {e.printStackTrace();}if(Build.VERSION.SDK_INT >= 24){imageUri = UriForFile(MainActivity.this,"com.lxd.photocut.fileprovider",outputImage);}else {imageUri = Uri.fromFile(outputImage);}//调用相机Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);startActivityForResult(intent, CODE_TAKE_PICTURE);

思路是这样的:首先创建File对象,放到了SD卡的应用关联缓存目录下(因为6.0系统开始读写SD卡也被列为危险权限),接着将File对象转换成uri对象.我觉得是因为我手机没有装SD卡 那么相片存储的位置该怎么获取到呢?
以上.希望大神交流指点~

另外我做了一个拍照选择图库压缩图片后并上传到服务器的Demo,完美适配6.0权限问题,里面有权限工具类还有,上传文件工具类有需要的朋友可以下载看一看点击Demo下载

本文发布于:2024-01-31 05:03:44,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170664862425744.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:头像   图库
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23