Android 사용자 정의 카메라 상세 설명

거의 모든 앱 이 사용 하 는 카메라 기능 입 니 다.아래 의 작은 편집 자 는 내용 을 정리 하여 우리 플랫폼 에 공유 하여 여러분 이 참고 하고 관심 이 있 는 친구 들 이 함께 공부 하도록 하 겠 습 니 다!
카 메 라 를 시작 하 는 두 가지 방식
1.시스템 카메라 직접 시작

<code class="hljs avrasm"> Intent intent = new Intent(); 
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); 
startActivity(intent);</code>
그림 을 되 돌려 주 는 이름 을 지정 합 니 다.

<code class="hljs avrasm"> 
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(mCurrentPhotoFile));
startActivityForResult(intent, CAMERA_WITH_DATA);</code>
2.사용자 정의 시작 카메라
오늘 은 두 번 째 로 예 를 들 면효과 도 는 다음 과 같다
demo
사용자 정의 카메라 의 일반적인 절차
카메라 화면 을 표시 하 는 레이아웃 을 만 듭 니 다.Android 는 Surface View 를 선택 하여 Surface View\#getHolder()를 통 해 Camera 와 Surface View 를 연결 하 는 Surface Holder Camame.open()카 메 라 를 열 어 Surface Holder 를 통 해 Camera 와 Surface View 를 연결 합 니 다.
일반 단계 의 코드 데모

<code class="hljs java">public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Camera.AutoFocusCallback {
private static final String TAG = "CameraSurfaceView";
private Context mContext;
private SurfaceHolder holder;
private Camera mCamera;
private int mScreenWidth;
private int mScreenHeight;
public CameraSurfaceView(Context context) {
this(context, null);
}
public CameraSurfaceView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CameraSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
getScreenMetrix(context);
initView();
}
private void getScreenMetrix(Context context) {
WindowManager WM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
WM.getDefaultDisplay().getMetrics(outMetrics);
mScreenWidth = outMetrics.widthPixels;
mScreenHeight = outMetrics.heightPixels;
}
private void initView() {
holder = getHolder();//  surfaceHolder  
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//    
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.i(TAG, "surfaceCreated");
if (mCamera == null) {
mCamera = Camera.open();//    
try {
mCamera.setPreviewDisplay(holder);//        Surface 
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.i(TAG, "surfaceChanged");
mCamera.startPreview();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.i(TAG, "surfaceDestroyed");
mCamera.stopPreview();//    
mCamera.release();//      
mCamera = null;
holder = null;
}
@Override
public void onAutoFocus(boolean success, Camera Camera) {
if (success) {
Log.i(TAG, "onAutoFocus success="+success);
}
}
}</code>
카메라 와 자동 초점 제한 권 추가

<code class="hljs xml"><uses-permission android:name="android.permission.CAMERA">
<uses-feature android:name="android.hardware.camera.autofocus"></uses-feature></uses-permission></code>
Camera Surface View 를 레이아웃 파일 에 두 고 가장 바깥쪽 을 FrameLayout 로 권장 합 니 다.나중에 사용 할 것 입 니 다.이렇게 해서 우 리 는 사진 기능 이 없 는 카 메 라 를 가지 게 되 었 다.처음 외 에 카메라 가 화면 을 표시 하 는 것 을 자세히 살 펴 보면 그림 이 심하게 변형 되 지 않 습 니까?그것 은 우리 가 아직 카 메 라 를 위해 각종 인 자 를 설정 하지 않 았 기 때문이다.미리 보기 전에 카메라 의 해상도,미리 보기 해상도 와 이미지 해상도 의 너비 와 높이 를 일치 시 켜 야 합 니 다.이렇게 해야만 그림 이 변형 되 지 않 는 다.이것 은 비교적 이해 하기 어 려 운 부분 이 므 로 깊이 이해 하려 면 독자 스스로 실천 해 야 한다.

<code class="hljs java"> private void setCameraParams(Camera camera, int width, int height) {
Log.i(TAG,"setCameraParams width="+width+" height="+height);
Camera.Parameters parameters = mCamera.getParameters();
//         PictureSize  
List<camera.size> pictureSizeList = parameters.getSupportedPictureSizes();
for (Camera.Size size : pictureSizeList) {
Log.i(TAG, "pictureSizeList size.width=" + size.width + " size.height=" + size.height);
}
/**            */
Camera.Size picSize = getProperSize(pictureSizeList, ((float) height / width));
if (null == picSize) {
Log.i(TAG, "null == picSize");
picSize = parameters.getPictureSize();
}
Log.i(TAG, "picSize.width=" + picSize.width + " picSize.height=" + picSize.height);
//      PictureSize    SurfaceView  
float w = picSize.width;
float h = picSize.height;
parameters.setPictureSize(picSize.width,picSize.height);
this.setLayoutParams(new FrameLayout.LayoutParams((int) (height*(h/w)), height));
//         PreviewSize  
List<camera.size> previewSizeList = parameters.getSupportedPreviewSizes();
for (Camera.Size size : previewSizeList) {
Log.i(TAG, "previewSizeList size.width=" + size.width + " size.height=" + size.height);
}
Camera.Size preSize = getProperSize(previewSizeList, ((float) height) / width);
if (null != preSize) {
Log.i(TAG, "preSize.width=" + preSize.width + " preSize.height=" + preSize.height);
parameters.setPreviewSize(preSize.width, preSize.height);
}
parameters.setJpegQuality(100); //       
if (parameters.getSupportedFocusModes().contains(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
parameters.setFocusMode(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);//       
}
mCamera.cancelAutoFocus();//    。
mCamera.setDisplayOrientation(90);//   PreviewDisplay   ,                 
mCamera.setParameters(parameters);
}
/**
*             
*   w:h = 4:3
*<p>  :   w     height
* h     width</p></camera.size></camera.size></code>
*/ private Camera.Size getProperSize(List pictureSizeList, float screenRatio) { Log.i(TAG, "screenRatio=" + screenRatio); Camera.Size result = null; for (Camera.Size size : pictureSizeList) { float currentRatio = ((float) size.width) / size.height; if (currentRatio - screenRatio == 0) { result = size; break; } } if (null == result) { for (Camera.Size size : pictureSizeList) { float curRatio = ((float) size.width) / size.height; if (curRatio == 4f / 3) {//   w:h = 4:3 result = size; break; } } } return result; }
화면 너비 가 높 고 조 정 된 인자 가 나 왔 습 니 다.surfaceChanged 방법 에서 mCamera.start Preview()를 실행 합 니 다.setCameraParams(mCamera,mScreenWidth,mScreenHeight)를 호출 합 니 다.됐 습 니 다.마지막 으로 AndroidManifest.xml 에 activity 의 방향 을 설정 해 야 합 니 다.android:screenOrientation="portrait"코드 에 주석 이 많 습 니 다.그 중에서 제 가 디 버 깅 할 때의 Log 도 있 습 니 다.여러분 이 직접 디 버 깅 해서 서로 다른 매개 변수의 효 과 를 볼 수 있 습 니 다.어제 매개 변 수 를 조금 더 만들어 서 모두 이 함 수 를 괴 롭 혔 다.아이고,쓰 라 린 눈물.
카메라 인 데 사진 을 못 찍 어?정말 창피해!다음은 우리 카메라 에 사진 을 찍 는 기능 을 추가 합 니 다.사진 핵심 코드 는 다음 과 같 습 니 다.mCamera.takePicture(null,null,jpeg);
takePicture 방법 은 ShutterCallback,PictureCallback,PictureCallback 세 가지 인 자 를 볼 수 있 습 니 다.여 기 는 저희 가 PictureCallback 만 썼어 요.

<code class="hljs java"> //       
private Camera.ShutterCallback shutter = new Camera.ShutterCallback() {
@Override
public void onShutter() {
Log.i(TAG,"shutter");
}
};
//             
private Camera.PictureCallback raw = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera Camera) {
Log.i(TAG, "raw");
}
};
//  jpeg        
private Camera.PictureCallback jpeg = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera Camera) {
BufferedOutputStream bos = null;
Bitmap bm = null;
try {
//     
bm = BitmapFactory.decodeByteArray(data, 0, data.length);
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
Log.i(TAG, "Environment.getExternalStorageDirectory()="+Environment.getExternalStorageDirectory());
String filePath = "/sdcard/dyk"+System.currentTimeMillis()+".jpg";//      
File file = new File(filePath);
if (!file.exists()){
file.createNewFile();
}
bos = new BufferedOutputStream(new FileOutputStream(file));
bm.compress(Bitmap.CompressFormat.JPEG, 100, bos);//        
}else{
Toast.makeText(mContext,"        ", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bos.flush();//  
bos.close();//  
bm.recycle();//   bitmap  
mCamera.stopPreview();//     
mCamera.startPreview();//     
} catch (IOException e) {
e.printStackTrace();
}
}
}
};</code>
jpeg 의 onPicture Taken 에서사진 정 보 를 저장 하 는 byte[]data 를 bitmap 으로 해석 한 후 JPG 형식의 그림 으로 변환 하여 SD 카드 에 저장 합 니 다.finally 의 마지막 두 마디 mCamera.stopPreview();/미리 보기 mCamera.startPreview()를 닫 습 니 다./미리 보 기 를 엽 니 다.camera.takePiture 방법 을 호출 한 후 camera 가 미리 보 기 를 닫 았 습 니 다.이 때 start Preview()를 사용 하여 미리 보 기 를 다시 시작 해 야 합 니 다.미리 보 기 를 다시 열지 않 으 면 사진 화면 에 머 물 러 있 습 니 다.외부 호출 사진 편 의 를 위해 서여기 서 나 는 외부 에서 사진 을 찍 을 수 있 는 방법 을 폭로 했다.

<code class="hljs cs"> public void takePicture(){
//    ,   
setCameraParams(mCamera, mScreenWidth, mScreenHeight);
//    camera.takePiture   ,camera     ,      startPreview()       
mCamera.takePicture(null, null, jpeg);
}</code>
레이아웃 파일 에 Button 을 추가 하고 Button 을 누 르 면 takePicture()방법 을 실행 합 니 다.SD 카드 제한 권 추가 잊 지 마 세 요.

<code class="hljs xml"><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission></code>
이로써 사진 을 찍 고 사진 을 저장 하 는 기능 을 가 진 카메라 가 만 들 어 졌 다.But,우 리 는 이것으로 만족 합 니까?이런 간단 한 기능 을 위해 서 라면 나 도 이 블 로 그 를 쓰 지 않 을 것 이다.이것 은 시작 일 뿐이다.
진정한 시작
어제 다른 앱 이 사진 을 찍 고 있 는 것 을 보 았 을 때 화면 에 효과 도 같은 틀,보조 점,사진 bulabulabula 가 나 타 났 다.인터넷 에서 실현 방식 을 검색 하고 자신의 이 해 를 더 해 이 블 로 그 를 구성 했다.
위의 레이아웃 파일 이 계속 붙 어 있 지 않 습 니 다.지금 붙 여 놓 으 면 여러분 이 먼저 훑 어보 세 요.어떤 컨트롤 들 은 다음 에 보 여 드릴 것 입 니 다.

<code class="hljs xml"><!--?xml version="1.0" encoding="utf-8"?-->
<framelayout android:layout_height="match_parent" android:layout_width="match_parent" xmlns:android="http://schemas.android.com/apk/res/android">
<com.dyk.cameratest.view.camerasurfaceview android:id="@+id/cameraSurfaceView" android:layout_height="match_parent" android:layout_width="match_parent">
<com.dyk.cameratest.view.rectoncamera android:layout_height="match_parent" android:layout_width="match_parent">
<relativelayout android:layout_height="match_parent" android:layout_width="match_parent">
</relativelayout></com.dyk.cameratest.view.rectoncamera></com.dyk.cameratest.view.camerasurfaceview></framelayout></code><button android:background="#88427ac7" android:id="@+id/takePic" android:layout_alignparentbottom="true" android:layout_centerhorizontal="true" android:layout_height="50dp" android:layout_marginbottom="20dp" android:layout_width="80dp" android:text="  " android:textcolor="#aaa"><code class="hljs xml">
</code></button>
레이아웃 파일 의 가장 바깥쪽 은 FrameLayout 입 니 다.FrameLayout 는 자체 적 으로 덮어 쓰기 효 과 를 가 진 다 는 것 을 알 고 있 습 니 다.유래 라 는 생각 은 이어서 매우 간단 하 다.프로 그래 밍 의 중요 한 것 은 사상,사상 이 있 고 나머지 는 구체 적 인 실현 세부 사항 만 남 았 다.
사용자 정의 테두리
Camera Surface View 와 구분 하기 위해 RectOnCamera 를 사용 하여 테두리 테 두 리 를 그립 니 다.이렇게 하면 또 하나의 장점 은 유지 하기 편리 하고 모든 것 을 하나의 View 에 두 지 않 는 다 는 것 이다.
RectOnCamera

<code class="hljs java">package com.dyk.cameratest.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
/**
* Created by dyk on 2016/4/7.
*/
public class RectOnCamera extends View {
private static final String TAG = "CameraSurfaceView";
private int mScreenWidth;
private int mScreenHeight;
private Paint mPaint;
private RectF mRectF;
//  
private Point centerPoint;
private int radio;
public RectOnCamera(Context context) {
this(context, null);
}
public RectOnCamera(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RectOnCamera(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
getScreenMetrix(context);
initView(context);
}
private void getScreenMetrix(Context context) {
WindowManager WM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
WM.getDefaultDisplay().getMetrics(outMetrics);
mScreenWidth = outMetrics.widthPixels;
mScreenHeight = outMetrics.heightPixels;
}
private void initView(Context context) {
mPaint = new Paint();
mPaint.setAntiAlias(true);//    
mPaint.setDither(true);//    
mPaint.setColor(Color.RED);
mPaint.setStrokeWidth(5);
mPaint.setStyle(Paint.Style.STROKE);//   
int marginLeft = (int) (mScreenWidth*0.15);
int marginTop = (int) (mScreenHeight * 0.25);
mRectF = new RectF(marginLeft, marginTop, mScreenWidth - marginLeft, mScreenHeight - marginTop);
centerPoint = new Point(mScreenWidth/2, mScreenHeight/2);
radio = (int) (mScreenWidth*0.1);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.RED);
canvas.drawRect(mRectF, mPaint);
mPaint.setColor(Color.WHITE);
Log.i(TAG, "onDraw");
canvas.drawCircle(centerPoint.x,centerPoint.y, radio,mPaint);//   
canvas.drawCircle(centerPoint.x,centerPoint.y, radio - 20,mPaint); //   
}
}
</code>
QR 코드 스 캔 과 비슷 한 틀 을 간단하게 그 렸 고 초점 을 맞 추 는 내외 원 도 있 었 다.그렇다면 초점 을 맞 춘 내외 원 은 손가락 이 미 끄 러 워 지면 서 위 치 를 바 꾸 고 초점 을 맞 추 는 효과 가 있어 야 한다.포커 싱 기능 을 가 진 카메라 서 페 이 스 뷰 와 는 같은 종류 가 아니 라 내외 원 에 초점 을 맞 출 뿐만 아니 라 카메라 서 페 이 스 뷰 도 완전히 덮 었 다.이런 문 제 를 처리 하려 면 인터페이스 리 셋 이 필요 하 다.이것 이 바로 사상 아래 의 세부 사항 이다.현재 인터페이스 리 셋 이 확인 되 었 지만 문제 가 하나 더 있 습 니 다.Camera Surface View 류 와 RectOnCamera 류 에는 상대방 의 대상 이나 인용 이 없습니다.맞습니다.RectOnCamera 와 CameraSurface View 를 공동으로 보유 한 Activity 를 통 해 이 기능 을 수행 할 수 있 습 니 다.다음은 구체 적 인 실현 방법 이다.
움직이다
우선 손가락 이 미 끄 러 짐 에 따라 RectOnCamera 의 위 치 를 바 꾸 려 면 onTouch Event()방법 을 복사 해 야 합 니 다.

<code class="hljs cs"> @Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
int x = (int) event.getX();
int y = (int) event.getY();
centerPoint = new Point(x, y);
invalidate();
return true;
}
return true;
}</code>
그 다음으로 리 셋 인터페이스 정의

<code class="hljs java"> private IAutoFocus mIAutoFocus;
/**         */
public interface IAutoFocus{
void autoFocus();
}
public void setIAutoFocus(IAutoFocus mIAutoFocus) {
this.mIAutoFocus = mIAutoFocus;
}</code>
onTouchEvent()에 return 전에 가입

<code class="hljs cs"> if (mIAutoFocus != null){
mIAutoFocus.autoFocus();
}</code>
이로써 우리 의 리 셋 인 터 페 이 스 는 이미 정의 되 었 습 니 다.이때 Camera Surface View 가 Activity 호출 을 위해 초점 을 맞 추 는 방법 을 노출 해 야 합 니 다.

<code class="hljs cs"> public void setAutoFocus(){
mCamera.autoFocus(this);
}</code>
준비 작업 이 모두 끝 났 습 니 다.다음은 Activity 의 구체 적 인 실현 을 보십시오.

<code class="hljs java">public class MainActivity extends Activity implements View.OnClickListener,RectOnCamera.IAutoFocus{
private CameraSurfaceView mCameraSurfaceView;
private RectOnCamera mRectOnCamera;
private Button takePicBtn;
private boolean isClicked;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
//     
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
mCameraSurfaceView = (CameraSurfaceView) findViewById(R.id.cameraSurfaceView);
mRectOnCamera = (RectOnCamera) findViewById(R.id.rectOnCamera);
takePicBtn= (Button) findViewById(R.id.takePic);
mRectOnCamera.setIAutoFocus(this);
takePicBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.takePic:
mCameraSurfaceView.takePicture();
break;
default:
break;
}
}
@Override
public void autoFocus() {
mCameraSurfaceView.setAutoFocus();
}
}
</code>
이 를 통 해 알 수 있 듯 이 MainActivity 는 IAuto Focus 인 터 페 이 스 를 실현 하고 복 사 된 IAuto Focus\#autoFocus()방법 에서 Camera Surface View 가 노출 되 는 방법 setAutoFocus()를 호출 했다.이로써 RectOnCamera 는 미 끄 러 질 때마다 포커 스 내외 원 의 위치 가 바 뀌 고 포커 스 기능 도 추가 된다.한마음 한 뜻,심지 어 는 한마음 한 뜻 으로 많이 쓰 는 것 이 더 좋 지 않 겠 습 니까?
자,안 드 로 이 드 사용자 정의 카메라 튜 토리 얼 은 여기 서 마 치 겠 습 니 다.도움 이 되 셨 으 면 좋 겠 습 니 다!
우 리 는 읽 기 를 추천 합 니 다.
Android 개발 카메라 나 앨범 에서 이미지 재단 가 져 오기
안 드 로 이 드 사용자 정의 카메라 카운트다운 사진

좋은 웹페이지 즐겨찾기