这几天有个需求是需要在拍照的时候,截图选定框内的照片,如下,截取绿色框内的照片
通常我们拍照 的话,都是直接调用系统的相机, 这样的话只能拍出整个屏幕的照片,不能达到我现在想要的效果,所以这时候我们需要重新来自定义个相机拍照
首先这是主界面的布局,也就是拍照的界面
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<SurfaceView
android:id="@+id/previewSV"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<com.example.partialphoto.DrawViewFrame
android:id="@+id/drawIV"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</FrameLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageButton
android:id="@+id/takephoto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:background="#01000000"
android:src="@drawable/btn_takepic"/>
</RelativeLayout>
</FrameLayout>
其次这是我程序的入口布局,为的就是拍照结束后,在ImageView上显示出来
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="@+id/iv_take"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="拍照" />
<ImageView
android:layout_gravity="center"
android:id="@+id/iv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/ic_launcher" />
</LinearLayout>
这是程序入口的代码,这里对图片做了些处理
package com.example.partialphoto;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
public class IntentTakePhoto extends Activity {
private ImageView iv;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_take);
Button btn = (Button) findViewById(R.id.iv_take);
iv = (ImageView) findViewById(R.id.iv);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(IntentTakePhoto.this,MainActivity.class);
// Uri uriPath = Uri.fromFile(new File(Environment.getExternalStorageDirectory(),"image.jpg"));
// intent.putExtra("take", uriPath);
startActivityForResult(intent, 1);
}
});
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
Uri uri = null;
Bitmap bitmap;
if(resultCode == 0&&requestCode == 1){
// newUri = data.getData();
if(null != data){
String path = data.getStringExtra("path");
uri = Uri.fromFile(new File(path));
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Config.RGB_565;
try {
bitmap = BitmapFactory.decodeStream(getContentResolver()
.openInputStream(uri), null, options);
float width = bitmap.getWidth();
float height = bitmap.getHeight();
// 创建操作图片用的matrix对象
Matrix matrix = new Matrix();
// 计算宽高缩放率
if (width > 600) {
float sacleFactor = 0;
if (width < height) {
matrix.postRotate(90);
sacleFactor = 600 / height;
} else {
sacleFactor = 600 / width;
}
matrix.postScale(sacleFactor, sacleFactor);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, (int) width,
(int) height, matrix, true);
float newwidth = bitmap.getWidth();
float newheight = bitmap.getHeight();
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
int opt = 100;
while ( baos.toByteArray().length / 1024>50) { //循环判断如果压缩后图片是否大于100kb,大于继续压缩
baos.reset();//重置baos即清空baos
bitmap.compress(Bitmap.CompressFormat.JPEG, opt, baos);//这里压缩options%,把压缩后的数据存放到baos中
opt -= 10;//每次都减少10
}
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中
bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream数据生成图片 ,然后再赋值给bitmap
System.out.println("------回来了");
iv.setImageBitmap(bitmap);
Toast.makeText(IntentTakePhoto.this, "-------"+bitmap.getWidth(), 0).show();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
然后这是拍照界面上的代码
package com.example.partialphoto;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.Toast;
public class MainActivity extends Activity implements Callback {
private static final String tag="PartialPhoto";
public static int frame = 0;
private boolean isPreview = false;
private SurfaceView mPreviewSV = null;
private DrawViewFrame mDrawIV = null;
private SurfaceHolder mySurfaceHolder = null;
private ImageButton mPhotoImgBtn = null;
private ImageButton btnAdd = null;
private ImageButton btnMinus = null;
private Camera myCamera = null;
private Bitmap mBitmap = null;
private AutoFocusCallback myAutoFocusCallback = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
Window myWindow = this.getWindow();
myWindow.setFlags(flag, flag);
setContentView(R.layout.activity_rect_photo);
mPreviewSV = (SurfaceView)findViewById(R.id.previewSV);
mPreviewSV.setZOrderOnTop(false);
mySurfaceHolder = mPreviewSV.getHolder();
mySurfaceHolder.setFormat(PixelFormat.TRANSPARENT);
mySurfaceHolder.addCallback(this);
mDrawIV = (DrawViewFrame)findViewById(R.id.drawIV);
mDrawIV.onDraw(new Canvas());
myAutoFocusCallback = new AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
// TODO Auto-generated method stub
if(success) //focus successfully
Log.i(tag, "myAutoFocusCallback: success...");
else
Log.i(tag, "myAutoFocusCallback: failure");
}
};
mPhotoImgBtn = (ImageButton)findViewById(R.id.takephoto);
mPhotoImgBtn.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
// TODO Auto-generated method stub
if(isPreview && myCamera!=null){
// myCamera.takePicture(null, null, myJpegCallback); //without shutter sound
myCamera.takePicture(new ShutterCallback() {
@Override
public void onShutter() {
Toast.makeText(MainActivity.this,"myShutterCallback:onShutter..." , MODE_PRIVATE).show();
}
}, null, myJpegCallback); //with shutter sound
}
}
});
}
//three important callback functions of SurfaceHolder.Callback as follows:
//surfaceChanged, surfaceCreated, surfaceDestroyed
//This is called immediately after any structural changes have been made to the surface.
public void surfaceChanged(SurfaceHolder holder, int format, int prevWidth,int prevHeight) {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, "surface改变了 了... ... ", 0).show();
if(isPreview){
myCamera.stopPreview();
}
if(null != myCamera){
Camera.Parameters myParam = myCamera.getParameters();
myParam.setPictureFormat(ImageFormat.JPEG); //set the stored picture format
int width = mDrawIV.getWidth();
int height = mDrawIV.getHeight();
myParam.setPictureSize(width, height);
//NOTE:
//set the size of preview interface
if (getWindowManager().getDefaultDisplay().getRotation() == 0){
myCamera.setDisplayOrientation(90);
myParam.setPreviewSize(prevHeight, prevWidth);
}
else
myParam.setPreviewSize(prevWidth, prevHeight);
try
{
myCamera.setParameters(myParam);
}
catch(Exception e)
{
e.printStackTrace();
}
myCamera.startPreview();
myCamera.autoFocus(myAutoFocusCallback);
isPreview = true;
}
}
//This is called immediately after the surface is first created.
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
myCamera = Camera.open();
try {
myCamera.setPreviewDisplay(mySurfaceHolder);
}
catch (IOException e) {
// TODO Auto-generated catch block
if(null != myCamera){
myCamera.release();
myCamera = null;
//Writes a printable representation of this Throwable's stack trace
e.printStackTrace();
}
}
}
//This is called immediately before a surface is being destroyed.
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
if(null != myCamera)
{
myCamera.setPreviewCallback(null);
myCamera.stopPreview();
isPreview = false;
myCamera.release();
myCamera = null;
}
}
//supply original image data from a photo capture
PictureCallback myJpegCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
// TODO Auto-generated method stub
if(null != data){
mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
myCamera.stopPreview();
isPreview = false;
}
int width = mDrawIV.getWidth();
int height = mDrawIV.getHeight();
int point_dw = (int)(width/10);
int point_dh = (int)(5*height/12-height*10/30);
int rect_dw = width-2*point_dw;
int rect_dh = height-2*point_dh;
// Bitmap sizeBitmap = Bitmap.createScaledBitmap(mBitmap, width, height, true);
mBitmap = Bitmap.createScaledBitmap(mBitmap, width, height, true);
//NOTE:
//set the format of the picture of the interception
// Bitmap rectBitmap = Bitmap.createBitmap(sizeBitmap, (int)width/30, (int)width/45,width-20*width/30, height-20*width/45);
mBitmap = Bitmap.createBitmap(mBitmap, point_dw,point_dh, rect_dw,rect_dh);
myCamera.startPreview();
isPreview = true;
if(null != mBitmap) {
String CurrentPhotoFile = "";
CurrentPhotoFile = saveJpeg(mBitmap); //save bitmap as a picture in sdcard
Intent intent = new Intent();
intent.putExtra("path", CurrentPhotoFile);
setResult(0, intent);
finish();
}
}
};
//save the picture
public String saveJpeg(Bitmap bm){
String jpegName = "";
String savePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/pp/"; //save directory
File folder = new File(savePath);
if(!folder.exists())
folder.mkdir();
long dataTake = System.currentTimeMillis();
jpegName = savePath + dataTake +".jpg";
try {
FileOutputStream fout = new FileOutputStream(jpegName);
BufferedOutputStream bos = new BufferedOutputStream(fout);
bm.compress(Bitmap.CompressFormat.JPEG, 100, bos);
bos.flush();
bos.close();
Log.i(tag, "saveJpeg锛歴torage completed!");
} catch (IOException e) {
// TODO Auto-generated catch block
Log.i(tag, "saveJpeg: storage failed!");
e.printStackTrace();
}
return jpegName;
}
}
最后这是自定义指定框的类
package com.example.partialphoto;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.widget.ImageView;
public class DrawViewFrame extends ImageView{
public DrawViewFrame(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
Paint paint1 = new Paint();
{
paint1.setAntiAlias(true);
paint1.setColor(Color.GREEN);
paint1.setStyle(Style.STROKE);
paint1.setStrokeWidth(8f);
paint1.setAlpha(100);
};
Paint paint2 = new Paint();
{
paint2.setAntiAlias(true);
paint2.setColor(Color.BLACK);
paint2.setStyle(Style.FILL);
paint2.setAlpha(150);
};
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
DisplayMetrics dm = new DisplayMetrics();
((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(dm);
int width = dm.widthPixels;
int height = dm.heightPixels;
int point_dw1 = (int)(width/10);
int point_dh1 = (int)(5*height/12-height*10/30);
//int point_dh1 = (int)(height/3);
int point_dw2 = width-point_dw1;
int point_dh2 = height-point_dh1;
//draw a rectangle around viewing frame
canvas.drawRect(new Rect(point_dw1, point_dh1, point_dw2, point_dh2), paint1);
// canvas.drawRect(new Rect((int)width/30,(int)width/45,(int)11*height/7,(int)19*height/20), paint1);
//这里是框外 阴影部分
canvas.drawRect(new Rect(0, 0, point_dw1, height), paint2);
canvas.drawRect(new Rect(point_dw2, 0, width, height), paint2);
canvas.drawRect(new Rect(point_dw1, 0, point_dw2, point_dh1), paint2);
canvas.drawRect(new Rect(point_dw1, point_dh2, point_dw2, height), paint2);
}
}
值得说一下:起初我用的是Intent直接传递的Bimap对象,但是试了几次,有时候成功,有时候不成功(onActivityResult方法执行不到),后来百度半天才知道,原来用Intent传递Bitmap对象很吃力,因为他只能传递小于40k的Bitmap,超过的就不行了,所以最后选择传递Bitmap的保存路径,然后再根据传递的String路径,通过Uri.fronFile()转化成Uri,然后通过BitmapFactory.decodeStream(getContentResolver.openInputStream(uri),null,options)来转化成bitmap
补充一下,有时候拍照的话,会很模糊, 原因是聚焦可能失败,所以可以添加下面的方法,调用surfaceview的touch事件
mPreviewSV.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
myCamera.autoFocus(myAutoFocusCallback);
System.out.println("点击聚焦");
return false;
}
});
来源:oschina
链接:https://my.oschina.net/u/2633885/blog/644809