拍照存檔

      在〈拍照存檔〉中尚無留言

ImageReader

拍照前, 需先設定ImageReader, 在參數中設定拍照解析度. 並設定setOnImageAvailableListener.

imageReader=ImageReader.newInstance(maxWidth, maxHeight, ImageFormat.JPEG, 1);
imageReader.setOnImageAvailableListener(imageReaderReady, cameraHandler);
captureRequest = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureRequest.addTarget(imageReader.getSurface());

當照片完成後, 會先調用onImageAvailable方法. 請注意, 在開始讀取照片資料時, 需先停止一段時間, 不然會閃退. 這是一個坑, 原因不明.

private ImageReader.OnImageAvailableListener imageReaderReady=new ImageReader.OnImageAvailableListener() {
    @Override
    public void onImageAvailable(ImageReader imageReader) {
        //此處有坑, 不停頓的話會當機, 網路上說要停1秒, 原因不明
        SystemClock.sleep(300);
        Image image=imageReader.acquireNextImage();
        if(image!=null) {
            ByteBuffer buffer = image.getPlanes()[0].getBuffer();
            byte[] bytes = new byte[buffer.remaining()];
            buffer.get(bytes);
            image.close();
            Bundle bundle = new Bundle();
            bundle.putByteArray("bitmapByteArray", bytes);
            Message msg = new Message();
            msg.what = MahalCamera2.CAMERA_BITMAP_READY;
            msg.setData(bundle);
            customHandler.sendMessage(msg);
        }
    }
};

啟動拍照

啟動拍照, 需使用cameraCaptureSession.capture方法, 但在啟動前, 需將session停止, 分別是使用cameraCaptureSession.stopRepeating及cameraCaptureSession.abortCaptures, 若沒有停止, 會造成意外閃退.

拍完照後, 並不是直接調用callback, 而是先執行setOnImageAvailable, 等執行完畢, 才會調用callback的onCaptureCompleted方法.

拍完照片後, 再進入preview模式

try {
    cameraCaptureSession.stopRepeating();
    cameraCaptureSession.abortCaptures();
    if (cameraFlash) {
        captureRequest.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
    } 
    else {
        captureRequest.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
    }
    captureRequest.set(CaptureRequest.JPEG_QUALITY, (byte)100);
    cameraCaptureSession.capture(captureRequest.build(), new CameraCaptureSession.CaptureCallback() {
        @Override
        public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
            Camera2Engine.this.captureResult=result;
            stillAvailable = true;
            startPreview();
       }
    }, cameraHandler);
} 
catch (CameraAccessException e) {}

拍照品質

在執行capture前, 需先設定照片品質

captureRequest.set(CaptureRequest.JPEG_QUALITY, (byte)100);

存檔

ImageReader讀取照片後, 是以Image格式存放. 網路上都是說明由Image取得byte[] array後, 放入Bitmap中, 再由Bitmap.compress將圖片存放在sd卡中.  但這種方法需花費大量時間, 以一張5M左右的照片, 約需使用3~4秒中.

為了解決這個issue, 建議把byte[] array傳出給主執行緒. 而後在主執行緒中直接使用FileOutputStream將byte[] 資料儲存即可, 如下

byte[] bytes=bundle.getByteArray("bitmapByteArray");
File file=new File(G.appPath+"/"+System.currentTimeMillis()+".jpg");
OutputStream os=new FileOutputStream(file);
os.write(bytes);
os.close();

Thumbnail

經由上面的方式儲存後, 並沒有縮圖. 若要顯示縮圖, 需再調用MediaScannerConnection.scanFile

MediaScannerConnection.scanFile(MainActivity.this, new String[] { file.getAbsolutePath() }, null,
        new MediaScannerConnection.OnScanCompletedListener() {
            public void onScanCompleted(String path, Uri uri) {
                MainActivity.this.sendBroadcast(new Intent("android.hardware.action.NEW_PICTURE" , uri));
                MainActivity.this.sendBroadcast(new Intent("com.android.camera.NEW_PICTURE", uri));
            }
        }
);

請注意, 若未調用MediaScannerConnection, 除了沒有縮圖外, 照片品質還會相當的差, 原因不明.尤其用不是很高級的相機所拍出的照片, 在圖片放大後的差異會更大.

下圖是有進行縮圖的處理

camera_good

下圖為沒有處理過的

camera2_bad

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *