hardware.Camera 및 SurfaceView

11911 단어

SufaceView


주로 Surface, SurfaceView 및 SurfaceHolder 세 가지 클래스가 있습니다.Surface 객체는 원본 픽셀 데이터의 버퍼를 나타냅니다.SurfaceHolder는 Surface와 연결하는 연결고리이며, SurfaceView 내부에는 그리기 전용 Surface 객체가 봉인되어 있습니다.(Provides a dedicated drawing surface embedded inside of a view hierarchy). 서피스 객체도 라이프 사이클이 있으므로 서피스 뷰가 화면에 나타나면 서피스가 생성되고 서피스 뷰가 화면에서 사라지면 서피스가 제거됩니다.Surface의 라이프 사이클을 정확하게 파악하기 위해SurfaceHolder를 통해Callback 인터페이스가 구현되었습니다.
SurfaceView는 뷰 계층 구조에서 드로잉을 위한 Surface를 제공하는 뷰의 특수 하위 클래스로, 이 드로잉 Surface를 UI 스레드가 아닌 다른 스레드(스레드)에 제공하므로 시스템이 뷰 계층 구조가 제대로 그려질 때까지 기다릴 필요가 없습니다.반대로 또 다른 스레드는 서피스의 참조를 가지고 있으며, 자신의 걸음걸이에 따라 자신의 canvas로 그릴 수 있다.
응용 프로그램에 추가한 UI 구성 요소나 사용자 정의 컨트롤은 보기 계층 구조에 추가되며 전체 보기 트리는 UI 스레드에서 그려집니다.SurfaceView는 UI 스레드를 사용하지 않고 자체 스레드에서 그려집니다.
SurfaceView는 다른 View와 다른 점은 컨텐츠를 자체 그리지 않는다는 점입니다.컨텐트를 Surface 버퍼에 그리려는 클라이언트(Surface)

SurfaceHolder.Callback


다음과 같은 세 가지 방법이 있습니다.
surfaceCreated(SurfaceHolder): SurfaceView가 화면에 배치될 때 이 방법을 호출합니다. 여기도 Surface가 클라이언트와 연결된 곳입니다.
surfaceChanged (Surface Holder, int, int): Surface의 형식과 크기가 바뀌면 즉시 이 방법을 호출합니다. 적어도 한 번은 호출될 것입니다. (surfaceCreated () 호출된 후에.여기에는 일반적으로 Surface를 알리는 데 사용되는 클라이언트의 영역이 얼마나 큰지 알 수 있습니다.
surfaceDestroyed(SurfaceHolder): 화면에서 SurfaceView가 이동하고 Surface가 제거될 때이 메서드에서는 클라이언트에게 Surface 사용을 중지하라고 알릴 수 있습니다.

Camera


시스템 카메라 부팅

    /**
     *  , 
     */
    public static void openCamera(Activity activity, int requestCode, File file) {
        if (file == null) {
            return;
        }
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));
        if (requestCode != 0) {
            activity.startActivityForResult(intent, requestCode);
        } else {
            activity.startActivity(intent);
        }
    }
위의 은닉intent의 action을 MediaStore로 설정하면ACTION_VID
E
O_CAPTURE가 녹화 기능을 시작합니다.
시스템 카메라를 사용하면 촬영한 사진이 갤러리에 바로 나타나지 않기 때문에 시스템이 리셋을 해야 한다고 통지해야 한다.다음과 같습니다.
                        // 
                        MediaScannerConnection.scanFile(this, new String[]{AppUtils.getCaptureImageFile(this).getAbsolutePath()}, null, null);
                        sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(captureImageFile)));
그중captureImageFile는 사진 촬영을 저장하는 데 사용되는 그림이고 AppUtils.getCaptureImageFile () 은 그림이 있는 폴더를 되돌려줍니다.즉, 이 방법은 폴더를 새로 고치는 것이 아니라 지정한 파일만 새로 고칠 수 있다.

개술


Camera는 장치 카메라 하드웨어 레벨을 호출합니다.카메라는 일종의 독점적인 자원으로 한 번에 하나의activity가 카메라를 호출할 수 있기 때문에 카메라를 사용하는 것이 매우 관건적인 점은 필요할 때 사용하고 사용이 끝난 후에 바로 방출하는 것이다.장치를 다시 켜지 않으면 다른 응용 프로그램에서 카메라를 사용할 수 없습니다.

사용 권한


카메라를 사용하려면 목록 파일에 해당하는 권한과 를 추가해야 합니다. 은 장치의 특정한 특색 기능을 사용하도록 지정하는 데 사용되며, 이 기능을 갖춘 장치만 이 기능을 사용할 수 있도록 보장합니다.구체적으로 다음과 같다.
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-feature android:name="android.hardware.camera" android:required="true" />

열기 및 해제


onResume () 및 onPause () 리셋 방법에서 카메라 자원을 가져오고 방출합니다.이 두 가지 방법은 사용자가 보기와 상호작용할 수 있는 시간 경계이기 때문에 사용자가 보기와 상호작용할 수 있을 때만 카메라를 사용할 수 있다.카메라를 가져오고 해제하는 코드는 다음과 같습니다.
	@Override
	protected void onResume() {// 
		super.onResume();
		mCamera = Camera.open();
	}

	@Override
	protected void onPause() {// 
		if (mCamera != null) {
			mCamera.release();
			mCamera = null;
		}
		super.onPause();
	}

카메라를 사용할 때는 반드시 비공식 판단을 해야 한다. 이것은 필수적이다.카메라 자원을 요청해도 얻지 못할 수도 있기 때문이다.

상용 방법


open(): 후면 카메라를 엽니다.다시 불러오는 방법인 오픈 (int) 은api9에 추가되며, 시스템은 전송된 값에 따라 대응하는 카메라를 열 것입니다.일반적으로 다음과 같은 (open() 소스를 사용합니다.
    public static Camera open() {
        int numberOfCameras = getNumberOfCameras();
        CameraInfo cameraInfo = new CameraInfo();
        for (int i = 0; i < numberOfCameras; i++) {
            getCameraInfo(i, cameraInfo);
            if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
                return new Camera(i);
            }
        }
        return null;
    }

카메라 하나하나를 훑어보고 앞뒤 위치에 따라 어느 것을 열어야 할지 판단한다.
setDisplayOrientation(): 미리보기 방향을 설정합니다.기본적으로 가로 화면으로 미리 보기되며 setDisplayOrientation(90)을 호출해야 세로 화면이 됩니다.
getParameters(): 카메라의 매개 변수를 가져옵니다.
setParameters(): 이 카메라는 매개변수를 설정합니다.
autoFocus(): 자동 초점 맞추기.매개 변수는 자동으로 초점을 맞춘 후의 리셋이다.
setPreviewCallback(): 미리 보기 콜백을 설정합니다.이 고등학교에서는 미리 보기된 데이터를 저장할 수 있다.

카메라가 있는지 없는지를 판단하다


구체적인 코드는 다음과 같습니다.
	/**
	 * @return true ,false 
	 */
	private boolean hasCamera() {
		PackageManager pm = getPackageManager();
		return pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)
				|| pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)
				|| Camera.getNumberOfCameras() > 0;
	}

미리 보기


Camera를 사용하여 사진을 찍을 때는 미리보기 인터페이스가 필요하며 SurfaceView를 미리보기 인터페이스로 사용합니다.구체적인 코드는 다음과 같습니다.
		SurfaceView sv = (SurfaceView) findViewById(R.id.btn1);
		SurfaceHolder holder = sv.getHolder();
		holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		holder.addCallback(new Callback() {
			public void surfaceCreated(SurfaceHolder holder) {
				try {
					if (mCamera != null)// 
						mCamera.setPreviewDisplay(holder);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			public void surfaceChanged(SurfaceHolder holder, int format,
					int width, int height) {
				if (mCamera == null)
					return;
				// 
				Parameters parameters = mCamera.getParameters();
				List<Size> sizes = parameters.getSupportedPreviewSizes();
				Size s = sizes.get(0);
				int ar = s.width * s.height;
				for (Size ts : sizes) {
					int ta = ts.width * ts.height;
					if (ta > ar) {
						s = ts;
						ar = ta;
					}
				}
				parameters.setPreviewSize(s.width, s.height);
				mCamera.setParameters(parameters);
				// 。 , 
				try {
					mCamera.startPreview();
				} catch (Exception e) {
					mCamera.release();
					mCamera = null;
				}
			}
			public void surfaceDestroyed(SurfaceHolder holder) {
				if (mCamera != null)
					mCamera.stopPreview();
			}
		});

미리 보기를 설정하기 전에 SurfaceHolder가 호출되었습니다.setType(SurfaceHolder.SURFACE TYPE PUSH BUFFERS)는 저버전에서 실행하려면 반드시 필요합니다.
위 코드에서surfaceCreated()에서 Camera를 호출합니다.setPreviewDisplay(),surfaceChanged()에서 Camera를 호출합니다.startPreview(),surfaceDestroyed()에서 Camera를 호출합니다.stopPreview().

미리 보기 데이터 가져오기


주로 setPreCallback()에서 콜백을 통해 수행됩니다.다음과 같습니다.
                    camera.startPreview();
                    camera.setPreviewCallback(new Camera.PreviewCallback() {
                        @Override
                        public void onPreviewFrame(byte[] data, Camera camera) {
                            takePicture(data);
                        }
                    });
takePicture는 매개변수를bitmap으로 변환하는 방법입니다.
private void takePicture(byte[] data) {
        Camera.Size size = camera.getParameters().getPreviewSize();
        try {
            YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            image.compressToJpeg(new Rect(0, 0, size.width, size.height), 80, stream);
            Bitmap bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());// bitmap
            //do sth
            stream.close();
        } catch (Exception ex) {
            Log.e("Sys", "Error:" + ex.getMessage());
        }
    }
이 방법은 주로 시스템이 자체로 가지고 있는 YuvImage류를 이용하여 진행한다.두 번째 매개변수는 ImageFormat일 수 있습니다.NV21 또는 ImageFormat.YUY2.

적절한 미리보기 크기 가져오기


코드는 apidemo에서 유래했다
    private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
        final double ASPECT_TOLERANCE = 0.1;
        double targetRatio = (double) w / h;
        if (sizes == null)
            return null;
        Camera.Size optimalSize = null;
        double minDiff = Double.MAX_VALUE;
        // Try to find an size match aspect ratio and size
        for (Camera.Size size : sizes) {
            double ratio = (double) size.width / size.height;
            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
                continue;
            if (Math.abs(size.height - h) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - h);
            }
        }

        // Cannot find the one match the aspect ratio, ignore the requirement
        if (optimalSize == null) {
            minDiff = Double.MAX_VALUE;
            for (Camera.Size size : sizes) {
                if (Math.abs(size.height - h) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - h);
                }
            }
        }
        return optimalSize;
    }

사진을 찍다


Camera 호출takePicture()에서 사진을 찍으면 된다.그것의 첫 번째 파라미터는 카메라가 이미지를 포획할 때 호출되며, 이때 이미지 데이터는 아직 처리되지 않았다.두 번째 파라미터는 원시 이미지 데이터가 사용할 수 있을 때 호출된다. 이때 원시 이미지 데이터 처리가 끝났지만 아직 저장되지 않았다.세 번째 매개변수는 JPEG 버전의 이미지가 사용 가능한 경우를 나타냅니다.상응하는 리셋이 필요하지 않으면null로 직접 전송할 수 있습니다.구체적으로 다음과 같다.
				if (mCamera != null) {
					mCamera.takePicture(new ShutterCallback() {
						public void onShutter() {
							System.out.println(" ");
						}
					}, null, new PictureCallback() {// JPG 
						public void onPictureTaken(byte[] data, Camera camera) {
							File directory = Environment
									.getExternalStorageDirectory();
							File f = new File(directory, "me.jpg");
							FileOutputStream fo = null;
							try {
								fo = new FileOutputStream(f);
								fo.write(data);
							} catch (Exception e) {
								e.printStackTrace();
							} finally {
								if (fo != null) {
									try {
										fo.close();
									} catch (IOException e1) {
										e1.printStackTrace();
									}
								}
							}
							finish();
						}
					});
				}

Camera.Parameters


카메라의 매개변수 클래스를 설정하려면 Camera#getParameters()를 사용합니다.

상용 방법


setPictureFormat(): 사후 사진의 형식을 설정합니다.예: ImageFormat.JPEG 등.
setFocusMode(): 초점 모드를 설정합니다.예: Camera.Parameters.FOCUS_MODE_AUTO-자동 초점 맞추기.

FAQ


지정된 위치의 이미지를 촬영합니다.


현상.


Camera를 사용하여 사진을 찍는데 미리보기 그림에 테두리가 있고 찍은 그림은 테두리 중의 부분이다.

의 원리


Camera에서 사진을 찍으려면 미리 보기 그림을 표시하기 위해 SurfaceView를 화면으로 사용해야 합니다.프레임은 프레임 레이아웃을 사용하는 다른 Surfaceview를 사용할 수 있습니다.아래쪽의 SurfaceView를 경계선 표시를 위해 Camera의 미리보기 영역으로 설정합니다.
여기서 MySurfaceView를 사용자 정의하고 다음과 같은 테두리를 그려야 합니다.
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback{
	
	private SurfaceHolder holder;
	public MySurfaceView(Context context, AttributeSet attrs) {
		super(context, attrs);
		holder = getHolder();
		holder.addCallback(this);
		holder.setFormat(PixelFormat.TRANSPARENT);
		setZOrderOnTop(true);
	}
	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		
	}
	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
	}
	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		
	}
	public void draw(){
		Canvas canvas = holder.lockCanvas();
		canvas.drawColor(Color.TRANSPARENT);
		Paint p = new Paint();
		p.setStrokeWidth(4);
		p.setColor(Color.RED);
		p.setStyle(Paint.Style.STROKE);
		p.setAntiAlias(true);
		canvas.drawRect(100, 300, 400, 600, p);// , surfaceview 
		holder.unlockCanvasAndPost(canvas);
	}
}

마지막으로 액티비티에서 사진을 찍어서 얻은 그림을 캡처하면 됩니다.

좋은 웹페이지 즐겨찾기