I am working on a project where image is capturing from Android camera. Everything works fine.
But now one issue is facing that when preview is showing that is fine but after capturing the image both are not 100% same. After capturing image sometimes image is stretch or squeezed.
CameraPreview class:
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
private Context mContext;
float mDist = 0;
public CameraPreview(Context context, Camera camera) {
super(context);
mContext = context;
mCamera = camera;
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
try {
// create the surface and start camera preview
if (mCamera == null) {
Camera.Parameters params = mCamera.getParameters();
if (params.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
}
mCamera.setParameters(params);
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
}
} catch (IOException e) {
Log.d(VIEW_LOG_TAG, "Error setting camera preview: " + e.getMessage());
}
}
public void refreshCamera(Camera camera) {
if (mHolder.getSurface() == null) {
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
// start preview with new settings
setCamera(camera);
// TODO: don't hardcode cameraId '0' here... figure this out later.
//setCameraDisplayOrientation(mContext, Camera.CameraInfo.CAMERA_FACING_FRONT, mCamera);
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.setDisplayOrientation(90);
mCamera.startPreview();
} catch (Exception e) {
Log.d(VIEW_LOG_TAG, "Error starting camera preview: " + e.getMessage());
}
}
public static void setCameraDisplayOrientation(Context context, int cameraId, Camera camera) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
int rotation = wm.getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
// Compensate for the mirror image.
result = (360 - result) % 360;
} else {
// Back-facing camera.
result = (info.orientation - degrees + 360) % 360;
}
camera.setDisplayOrientation(result);
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
refreshCamera(mCamera);
}
public void setCamera(Camera camera) {
//method to set a camera instance
mCamera = camera;
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
// mCamera.release();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// Get the pointer ID
Camera.Parameters params = mCamera.getParameters();
int action = event.getAction();
if (event.getPointerCount() > 1) {
// handle multi-touch events
if (action == MotionEvent.ACTION_POINTER_DOWN) {
mDist = getFingerSpacing(event);
} else if (action == MotionEvent.ACTION_MOVE
&& params.isZoomSupported()) {
mCamera.cancelAutoFocus();
handleZoom(event, params);
}
} else {
// handle single touch events
if (action == MotionEvent.ACTION_UP) {
handleFocus(event, params);
}
}
return true;
}
private void handleZoom(MotionEvent event, Camera.Parameters params) {
int maxZoom = params.getMaxZoom();
int zoom = params.getZoom();
float newDist = getFingerSpacing(event);
if (newDist > mDist) {
// zoom in
if (zoom < maxZoom)
zoom++;
} else if (newDist < mDist) {
// zoom out
if (zoom > 0)
zoom--;
}
mDist = newDist;
params.setZoom(zoom);
mCamera.setParameters(params);
}
public void handleFocus(MotionEvent event, Camera.Parameters params) {
int pointerId = event.getPointerId(0);
int pointerIndex = event.findPointerIndex(pointerId);
// Get the pointer's current position
float x = event.getX(pointerIndex);
float y = event.getY(pointerIndex);
List<String> supportedFocusModes = params.getSupportedFocusModes();
if (supportedFocusModes != null
&& supportedFocusModes
.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
mCamera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean b, Camera camera) {
// currently set to auto-focus on single touch
}
});
}
}
/** Determine the space between the first two fingers */
private float getFingerSpacing(MotionEvent event) {
// ...
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float)Math.sqrt(x * x + y * y);
}
}
Below is the xml layout where inside FrameLayout, camera preview under LinearLayout(@+id/cameraFrame) is used.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false"
tools:context=".view.activity.PhotoCaptureActivity">
<RelativeLayout
android:id="@+id/mainLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="0dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"
android:layout_marginTop="0dp"
android:orientation="horizontal"
android:weightSum="3">
<FrameLayout
android:id="@+id/cameraFrame_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/cameraFrame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" />
<ImageView
android:id="@+id/captured_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:scaleType="fitXY"
android:scaleX="-1"
/>
<ImageView
android:id="@+id/captured_image_back"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:scaleType="fitXY"
android:scaleX="-1"
android:scaleY="-1"
android:visibility="gone"/>
<ImageButton
android:id="@+id/button_capture"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_gravity="center_horizontal|bottom"
android:layout_marginBottom="5dp"
android:background="@drawable/ic_camera_capture_image" />
<ImageButton
android:id="@+id/swicth_camera"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_gravity="right|bottom"
android:layout_marginBottom="10dp"
android:layout_marginEnd="20dp"
android:background="@drawable/ic_camera_switch" />
<ImageButton
android:id="@+id/flash_on"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_gravity="left|bottom"
android:layout_marginBottom="10dp"
android:layout_marginStart="20dp"
android:background="@drawable/ic_gallery"
android:visibility="gone"/>
<ImageButton
android:id="@+id/fab_send_photo"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="right|bottom"
android:layout_marginBottom="10dp"
android:layout_marginEnd="20dp"
app:srcCompat="@drawable/ic_send_blue"
android:visibility="gone" />
</FrameLayout>
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
I have shared my Activity class, Camera Preview class and xml file in google drive. https://drive.google.com/drive/folders/1WETYNhUZiTZOOChzEynRC-cEB6RsYrN5?usp=sharing
Before capturing image:
After capturing image:
You can see in the left hand side letter'F' is now visible after capturing the image. But letter 'F' was not in the preview. And top bar "hp" logo vanishes after capturing image but "hp" logo was in the preview.
I tried few solutions from stack overflow but it did not suit in my case. When I tried Android Camera Preview Stretched solution, then camera preview was not showing so it was not possible for me to identify whether it was solved or not.
Please let me know what can done to get a optimal solution for this issue?