I am developping an android application that combine a camera review in order to take picture and at the same time i want show OCR blocktext over the preview , the application first waorked fine with only taking picture from the preview , but when i added the OCR i don't get the preview anymore (just white scrren) but the OCR is working and showing up detected caracters. i think there is a problem with the camera opened by the preview and the OCR , kind of a conflict , but i can't find it.
here is a sample of my code :
Camera camera;
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
boolean previewing = false;
Context context;
@BindView(R.id.preview_layout)
LinearLayout previewLayout;
@BindView(R.id.border_camera)
View borderCamera;
@BindView(R.id.res_border_size)
TextView resBorderSizeTV;
private OnFragmentInteractionListener mListener;
private TextRecognizer textRecognizer;
private CameraSource cameraSource;
private TextView textBlockContent;
Camera.Size previewSizeOptimal;
public interface OnFragmentInteractionListener {
void onFragmentInteraction(Bitmap bitmap);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setRetainInstance(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_photo, container, false);
ButterKnife.bind(this, view);
context = getContext();
surfaceView = (SurfaceView) view.findViewById(R.id.camera_preview_surface);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
//--------------------------------------------------------------------- OCR elements -----------------------------------------------------
textBlockContent = view.findViewById(R.id.textBlockContent);
textRecognizer = new TextRecognizer.Builder(getActivity().getApplicationContext()).build();
return view;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString() + " must implement OnFragmentInteractionListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
camera = Camera.open();
//--------------------------------------------------------------------- OCR Process-----------------------------------------------------
try {
//noinspection MissingPermission
int rc = ActivityCompat.checkSelfPermission(getActivity().getApplicationContext(), Manifest.permission.CAMERA);
if (rc == PackageManager.PERMISSION_GRANTED) {
if (!textRecognizer.isOperational()) {
Log.w("MainActivity", "Detector dependencies are not yet available.");
}
cameraSource = new CameraSource.Builder(getActivity().getApplicationContext(), textRecognizer)
.setFacing(CameraSource.CAMERA_FACING_BACK)
.setRequestedPreviewSize(1280, 1024)
.setRequestedFps(2.0f)
.setAutoFocusEnabled(true)
.build();
cameraSource.start(surfaceHolder);
} else {
//requestCameraPermission();
}
} catch (IOException ex) {
ex.printStackTrace();
}
textRecognizer.setProcessor(new Detector.Processor<TextBlock>() {
@Override
public void release() {
}
@Override
public void receiveDetections(Detector.Detections<TextBlock> detections) {
Log.d("Main", "receiveDetections");
final SparseArray<TextBlock> items = detections.getDetectedItems();
if (items.size() != 0) {
Log.d("Main", "receiveDetections : " + items.toString());
textBlockContent.post(new Runnable() {
@Override
public void run() {
StringBuilder value = new StringBuilder();
for (int i = 0; i < items.size(); ++i) {
TextBlock item = items.valueAt(i);
value.append(item.getValue());
value.append("\n");
}
//update text block content to TextView
textBlockContent.setText(value.toString());
}
});
}
}
});
//--------------------------------------------------------------------- End OCR -----------------------------------------------------
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (previewing) {
camera.stopPreview();
previewing = false;
}
if (camera != null) {
try {
Camera.Parameters parameters = camera.getParameters();
//get preview sizes
List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
//find optimal - it very important
previewSizeOptimal = getOptimalPreviewSize(previewSizes, parameters.getPictureSize().width, parameters.getPictureSize().height);
//TODO TESSSSSSST
//set parameters
if (previewSizeOptimal != null) {
parameters.setPreviewSize(previewSizeOptimal.width, previewSizeOptimal.height);
}
if (camera.getParameters().getFocusMode().contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
}
if (camera.getParameters().getFlashMode() != null && camera.getParameters().getFlashMode().contains(Camera.Parameters.FLASH_MODE_AUTO)) {
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
}
camera.setParameters(parameters);
//rotate screen, because camera sensor usually in landscape mode
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
if (display.getRotation() == Surface.ROTATION_0) {
camera.setDisplayOrientation(90);
} else if (display.getRotation() == Surface.ROTATION_270) {
camera.setDisplayOrientation(180);
}
//write some info
int x1 = previewLayout.getWidth();
int y1 = previewLayout.getHeight();
int x2 = borderCamera.getWidth();
int y2 = borderCamera.getHeight();
String info =
"Preview width:" + String.valueOf(x1) + "\n" + "Preview height:" + String.valueOf(y1) + "\n" + "Border width:" + String.valueOf(x2) + "\n" + "Border height:" + String.valueOf(y2);
resBorderSizeTV.setText(info);
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
previewing = true;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public 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;
int targetHeight = h;
// 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 - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
// 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 - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
camera.stopPreview();
camera.release();
camera = null;
previewing = false;
cameraSource.stop();
}
@OnClick(R.id.make_photo_button)
void makePhoto() {
if (camera != null) {
camera.takePicture(myShutterCallback, myPictureCallback_RAW, myPictureCallback_JPG);
}
}
Camera.ShutterCallback myShutterCallback = new Camera.ShutterCallback() {
@Override
public void onShutter() {
}
};
Camera.PictureCallback myPictureCallback_RAW = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
}
};
Camera.PictureCallback myPictureCallback_JPG = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
Bitmap bitmapPicture = BitmapFactory.decodeByteArray(data, 0, data.length);
Bitmap croppedBitmap = null;
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
if (display.getRotation() == Surface.ROTATION_0) {
//rotate bitmap, because camera sensor usually in landscape mode
Matrix matrix = new Matrix();
matrix.postRotate(90);
Bitmap rotatedBitmap = Bitmap.createBitmap(bitmapPicture, 0, 0, bitmapPicture.getWidth(), bitmapPicture.getHeight(), matrix, true);
Log.i("onPictureTaken", "rotatedBitmap width" + rotatedBitmap.getWidth());
Log.i("onPictureTaken", "rotatedBitmap height " + rotatedBitmap.getHeight());
Log.i("onPictureTaken", "previewLayout.getWidth() " + previewLayout.getWidth());
Log.i("onPictureTaken", "previewLayout.getHeight() " + previewLayout.getHeight());
//save file
createImageFile(rotatedBitmap);
//calculate aspect ratio
float koefX = (float) rotatedBitmap.getWidth() / (float) previewLayout.getWidth();
float koefY = (float) rotatedBitmap.getHeight() / (float) previewLayout.getHeight();
Log.i("onPictureTaken", "koefx " + koefX);
Log.i("onPictureTaken", "koefy " + koefY);
//get viewfinder border size and position on the screen
int x1 = borderCamera.getLeft();
int y1 = borderCamera.getTop();
int x2 = borderCamera.getWidth();
int y2 = borderCamera.getHeight();
Log.i("onPictureTaken", "borderCamera.getWidth() " + borderCamera.getWidth());
Log.i("onPictureTaken", "borderCamera.getHeight() " + borderCamera.getHeight());
//TODO size 1028 * 1251
//calculate position and size for cropping
int cropStartX = Math.round(x1 * koefX);
int cropStartY = Math.round(y1 * koefY);
int cropWidthX = Math.round(x2 * koefX);
int cropHeightY = Math.round(y2 * koefY);
//check limits and make crop
if (cropStartX + cropWidthX <= rotatedBitmap.getWidth() && cropStartY + cropHeightY <= rotatedBitmap.getHeight()) {
croppedBitmap = Bitmap.createBitmap(rotatedBitmap, cropStartX, cropStartY, cropWidthX, cropHeightY);
} else {
croppedBitmap = null;
}
//save result
if (croppedBitmap != null) {
// Scale down to the output size
//Bitmap scaledBitmap = Bitmap.createScaledBitmap(croppedBitmap, 1028, 1251, true);
createImageFile(croppedBitmap);
}
} else if (display.getRotation() == Surface.ROTATION_270) {
// for Landscape mode
}
//pass to another fragment
if (mListener != null) {
if (croppedBitmap != null) mListener.onFragmentInteraction(croppedBitmap);
}
if (camera != null) {
camera.startPreview();
}
}
};
public void createImageFile(final Bitmap bitmap) {
File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
String timeStamp = new SimpleDateFormat("MMdd_HHmmssSSS").format(new Date());
String imageFileName = "pic_" + timeStamp + ".jpg";
final File file = new File(path, imageFileName);
try {
// Make sure the Pictures directory exists.
if (path.mkdirs()) {
Toast.makeText(context, "Not exist :" + path.getName(), Toast.LENGTH_SHORT).show();
}
OutputStream os = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
os.flush();
os.close();
Log.i("ExternalStorage", "Writed " + path + file.getName());
// Tell the media scanner about the new file so that it is
// immediately available to the user.
MediaScannerConnection.scanFile(context, new String[]{file.toString()}, null, new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("ExternalStorage", "Scanned " + path + ":");
Log.i("ExternalStorage", "-> uri=" + uri);
}
});
Toast.makeText(context, file.getName(), Toast.LENGTH_SHORT).show();
} catch (Exception e) {
// Unable to create file, likely because external storage is
// not currently mounted.
Log.w("ExternalStorage", "Error writing " + file, e);
}
}