记录:拍照需要实现前后置摄头双拍,然后合成一张图片,上传到服务器
注注注注意的点:因为安卓手机机型比较多,每个手机拍出来获取图片资源方向都会不一样,因此需要先修正图片然后再合成图片,不然合成图片的方向就会不可控制,如下图一。由于每个手机拍出来的图片显示方向都会不一样。修正后就正常显示,如下图二。拍照完成后小图片可在大图片范围内任意拖拽,拖拽超出大图则回弹到大图边缘,如下图三。
/**
* 缩放前摄像头的图片 小图 屏幕宽高的0.32倍
*
* @return
*/
private Bitmap zoomBitmapImg(Bitmap bitmapWH) {
double imgWidth = Double.valueOf(DensityUtil.getScreenWidth(this)) * 0.32; //image 宽
double imgHeight = Double.valueOf(DensityUtil.getScreenHeight4_3(this)) * 0.32; //image 高
int width = bitmapWH.getWidth(); //bitmap 宽
int height = bitmapWH.getHeight(); //bitmap 高
//得到想要的大小
float scaleWidth = (float) (imgWidth / width); //宽的缩放比 scaleW = 想要得到的宽 / bitmap宽
float scaleHeight = (float) (imgHeight / height); //高的缩放比 scaleH = 想要得到的高 / bitmap高
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
Bitmap newBm = Bitmap.createBitmap(bitmapWH, 0, 0, width, height, matrix, true);
if (bitmapWH != null && !bitmapWH.isRecycled()) {
bitmapWH.recycle();
}
return newBm;
}
/**
* 把大图变成4:3 为背景图
*
* @return
*/
private Bitmap zoBitmapImg(Bitmap bitmapWH) {
double imgWidth = Double.valueOf(DensityUtil.getScreenWidth(this)); //image 宽
double imgHeight = Double.valueOf(DensityUtil.getScreenHeight4_3(this)); //image 高
int width = bitmapWH.getWidth(); //bitmap 宽
int height = bitmapWH.getHeight(); //bitmap 高
//得到想要的大小
float scaleWidth = (float) (imgWidth / width); //宽的缩放比
float scaleHeight = (float) (imgHeight / height); //高的缩放比
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
Bitmap newBm = Bitmap.createBitmap(bitmapWH, 0, 0, width, height, matrix, true);
if (bitmapWH != null && !bitmapWH.isRecycled()) {
bitmapWH.recycle();
}
return newBm;
}
/**
* 为 Bitmap 设置切割圆角
*
* @param source 原图
* @return
*/
private Bitmap getRoundBitmap(Bitmap source, float radius) {
Bitmap bitmap_bg = getBitmapByColor(source.getWidth() + DensityUtil.dip2px(this, 2) * 2,
source.getHeight() + DensityUtil.dip2px(this, 2) * 2);
Bitmap result = composeBitmap(getRoundCornerBitmap(bitmap_bg, DensityUtil.dip2px(this, 22)), getRoundCornerBitmap(source, radius));
return result;
}
/**
* 裁剪圆角
*
* @param source
* @param radius
* @return
*/
private Bitmap getRoundCornerBitmap(Bitmap source, float radius) {
Bitmap dstBitmap = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
final Paint paint = new Paint();
paint.setAntiAlias(true);
final Rect dst = new Rect(0, 0, source.getWidth(), source.getHeight());
final RectF rectF = new RectF(dst);
Canvas canvas = new Canvas(dstBitmap);
canvas.drawARGB(0, 0, 0, 0);
canvas.drawRoundRect(rectF, radius, radius, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(source, null, dst, paint);
if (source != null && !source.isRecycled()) {
source.recycle();
}
return dstBitmap;
}
/**
* 构建背景,用于设置圆角,本质是一大一小两个圆角bitmap 合并
*
* @param width
* @param height
* @return
*/
private Bitmap getBitmapByColor(int width, int height) {
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
int[] pixels = new int[width * height];
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
pixels[i * width + j] = Color.BLACK;
}
}
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
return bitmap;
}
/**
* 合并图片
*
* @param bitmap1
* @param bitmap2
* @return
*/
private Bitmap composeBitmap(Bitmap bitmap1, Bitmap bitmap2) {
int bgWidth = bitmap1.getWidth();
int bgHeight = bitmap1.getHeight();
Bitmap newBitmap = Bitmap.createBitmap(bgWidth, bgHeight, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(newBitmap);
canvas.drawBitmap(bitmap1, 0, 0, null);
canvas.drawBitmap(bitmap2, (bgWidth - bitmap2.getWidth()) >> 1, (bgHeight - bitmap2.getHeight()) >> 1, null);
canvas.save();
canvas.restore();
return newBitmap;
}
注:没有修正图片之前
/**
* 读取照片旋转角度
*
* @param path 照片路径
* @return 角度
*/
public Bitmap readPictureDegree(String path) {
Bitmap bitmap = BitmapUtil.fileToBitmap(path);
try {
Matrix matrix = new Matrix();
ExifInterface exifInterface = new ExifInterface(path);
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
//ok
matrix.postScale(-1f, 1f);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
matrix.setRotate(180f);
break;
case ExifInterface.ORIENTATION_FLIP_VERTICAL:
matrix.postScale(1f, -1f);
break;
case ExifInterface.ORIENTATION_TRANSPOSE:
matrix.setRotate(90f);
matrix.postScale(-1f, 1f);
break;
case ExifInterface.ORIENTATION_ROTATE_90:
//ok
matrix.setRotate(90f);
break;
case ExifInterface.ORIENTATION_TRANSVERSE:
//ok
matrix.setRotate(270);
matrix.postScale(-1f, 1f);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
matrix.setRotate(-90f);
break;
}
Bitmap bm = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
if (bitmap != bm) {
bitmap.recycle();
bitmap = bm;
}
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
/**
* 两张图片合成一张图片 前后摄像头两张图片 旋转图片
*
* @param backImgUrl //后摄像头图片
* @param frontImgUrl //前摄像头图片
* @return
*/
private Bitmap newCombineBitMap(String backImgUrl, String frontImgUrl, float centrePointX, float centrePointY) {
try {
Bitmap backImg = zoBitmapImg(readPictureDegree(backImgUrl)); //大图
Bitmap frontImg = getRoundBitmap(zoomBitmapImg(readPictureDegree(frontImgUrl)), DensityUtil.dip2px(this, 20)); //小图
Bitmap bitmap = Bitmap.createBitmap(backImg.getWidth(), backImg.getHeight(), backImg.getConfig());
Canvas canvas = new Canvas(bitmap);
canvas.drawBitmap(backImg, new Matrix(), null);
// 通过中心点比例显示 X,Y 轴
float mPointX = backImg.getWidth() * centrePointX - (frontImg.getWidth() / 2);
float mPointY = backImg.getHeight() * centrePointY - (frontImg.getHeight() / 2);
// LogUtils.d("中心点是什么==============:", mPointX, mPointY);
canvas.drawBitmap(frontImg, mPointX, mPointY, null);
return bitmap;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
注:修正图片之后
添加点击拖拽事件:
//滑动事件
mCoverPreviewFront.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
float x = motionEvent.getX();
float y = motionEvent.getY();
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { //按下
isMove = false;
mDownX = x;
mDownY = y;
// 记录第一次在屏幕上坐标,用于计算初始位置
mFirstX = (int) motionEvent.getRawX();
mFirstY = (int) motionEvent.getRawY();
} else if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) {//移动
mDragY = motionEvent.getY(); //拖拽时记录Y轴变化
mDragX = motionEvent.getX(); //拖拽时记录X轴变化
view.offsetTopAndBottom((int) (y - mDownY));
view.offsetLeftAndRight((int) (x - mDownX));
//记录移动位置大于一定程度才算滑动事件
int offs = 3;
if (mDragX > mDownX + offs || mDragX < mDownX - offs || mDragY > mDownY + offs || mDragY < mDownY - offs) {
isMove = true;
}
} else if (motionEvent.getAction() == MotionEvent.ACTION_UP) { //抬起
if (isMove) {
adsorptionBorder(view, mImagePreview);
} else {
switchImage();
}
}
return view.onTouchEvent(motionEvent);
}
});
}
边框吸顶:
/**
* 拖动超出父控件,吸边
*
* @param view
* @param parentView
*/
private void adsorptionBorder(View view, View parentView) {
// int padding = 32;
int padding = 40;
int endX = parentView.getWidth() - padding;
int endY = parentView.getHeight() - padding;
int x = 0;
int y = 0;
if ((view.getX()) < padding) {
x = padding;
// view.animate().setInterpolator(new DecelerateInterpolator()).setDuration(300).x(x).start();
} else if ((view.getX() + view.getWidth()) > endX) {
x = parentView.getWidth() - (view.getWidth() + padding);
// view.animate().setInterpolator(new DecelerateInterpolator()).setDuration(300).x(x).start();
} else {
x = (int) view.getX();
}
if (view.getY() < padding) {
y = padding;
// view.animate().setInterpolator(new DecelerateInterpolator()).setDuration(300).y(padding).start();
} else if (view.getY() + view.getHeight() > endY) {
y = endY - view.getHeight();
// view.animate().setInterpolator(new DecelerateInterpolator()).setDuration(300).y(y).start();
} else {
y = (int) view.getY();
}
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) view.getLayoutParams();
layoutParams.leftMargin = x;
layoutParams.topMargin = y;
view.setLayoutParams(layoutParams);
}
/**
* 切换图片显示
*/
private void switchImage() {
mIsSwitch = !mIsSwitch;
Glide.with(getContext()).load(mIsSwitch ? mFrontBackImgUrl : mRearImgUrl).into(mImagePreview);
Glide.with(getContext()).load(mIsSwitch ? mRearImgUrl : mFrontBackImgUrl).into(mCoverPreviewFront);
}
中心点计算:(用于计算小图在大图上滑动的中心点,用于摆放位置记录)
// 通过 X,Y 轴 获取中心点比例
float mPointX = (mCoverPreviewFront.getX() + mCoverPreviewFront.getWidth() / 2) / mImagePreview.getWidth();
float mPointY = (mCoverPreviewFront.getY() + mCoverPreviewFront.getHeight() / 2) / mImagePreview.getHeight();
//中心点取前两位值
BigDecimal mBigPointX = BigDecimal.valueOf(centrePointX).setScale(2, BigDecimal.ROUND_HALF_UP);
BigDecimal mBigPointY = BigDecimal.valueOf(centrePointY).setScale(2, BigDecimal.ROUND_HALF_UP);