Don't stretch Camera preview inside SurfaceView in portrait mode - android

What my code do is take image from camera and show it inside surfaceview in fullscreen, but preview is stretched upward (so an object like a bottle appear higher and thinner than reality). This is my code:
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Camera.Parameters params = mCamera.getParameters();
Camera.Size result = getBestPreviewSize(params, width, height);
params.setPreviewSize(result.width, result.height);
params.setPictureFormat(ImageFormat.JPEG);
params.setJpegQuality(100);
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
params.setPictureSize(dpWidth, dpWidth);
params.setRotation(90);
mCamera.setParameters(params);
mCamera.startPreview();
}
public Camera.Size getBestPreviewSize(Camera.Parameters params, int width,
int height) {
Camera.Size result = null;
for (Camera.Size size : params.getSupportedPreviewSizes()) {
Log.d("size: ", size.width + ":" + size.height);
if (size.width <= width && size.height <= height) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea > resultArea) {
result = size;
}
}
}
}
return result;
}
what's wrong?

Related

Multiscreen Support in android : Camera preview is stretched in Samsung Galaxy s4 mini issue android

This is my Preview class to take a picture : it's working perfectly with many devices but Android Samsung Galaxy S4 shows me bad result => the problem that the image is stretched when preview.
You can see the image below :
Here is my code :
class Preview extends ViewGroup implements SurfaceHolder.Callback {
private final String TAG = "Preview";
SurfaceView mSurfaceView;
SurfaceHolder mHolder;
Camera.Size mPreviewSize;
List<Camera.Size> mSupportedPreviewSizes;
Camera mCamera;
Preview(Context context, SurfaceView sv) {
super(context);
mSurfaceView = sv;
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
requestLayout();
// get Camera parameters
Camera.Parameters params = mCamera.getParameters();
List<String> focusModes = params.getSupportedFocusModes();
try {
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
} else if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
}
else if (focusModes.contains(Camera.Parameters.FOCUS_MODE_INFINITY)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY);
}
mCamera.setParameters(params);
}
catch (Exception e) {
}
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// We purposely disregard child measurements because act as a
// wrapper to a SurfaceView that centers the camera preview instead
// of stretching it.
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed && getChildCount() > 0) {
final View child = getChildAt(0);
final int width = r - l;
final int height = b - t;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null) {
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
}
// Center the child SurfaceView within the parent.
if (width * previewHeight > height * previewWidth) {
final int scaledChildWidth = previewWidth * height / previewHeight;
child.layout((width - scaledChildWidth) / 2, 0,
(width + scaledChildWidth) / 2, height);
} else {
final int scaledChildHeight = previewHeight * width / previewWidth;
child.layout(0, (height - scaledChildHeight) / 2,
width, (height + scaledChildHeight) / 2);
}
}
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, acquire the camera and tell it where
// to draw.
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(holder);
}
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
if (mCamera != null) {
mCamera.stopPreview();
}
}
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;
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;
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if(mCamera != null) {
if (mPreviewSize!=null){
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
mCamera.setParameters(parameters);
mCamera.startPreview();
}
}
}
}
I want to keep image support Multiscreen in android after preview.
To not have a stretched image or preview , you should choose a previewSize that keep the same ratio as the screen of the phone. Then , you should set it before launching and starting the camera. Try this code :
public void setCamera(Camera camera, int screenW, int screenH) {
//screenW ==> screen width of the phone in Pixels
//screenH ==> screen height of the phone in Pixels
mCamera = camera;
if (mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, screenW
, screenH);
}
requestLayout();
// get Camera parameters
Camera.Parameters params = mCamera.getParameters();
if (mPreviewSize != null)
params.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
List<String> focusModes = params.getSupportedFocusModes();
try {
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
} else if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
} else if (focusModes.contains(Camera.Parameters.FOCUS_MODE_INFINITY)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY);
}
mCamera.setParameters(params);
Log.i(TAG, " getPreviewSize " + mCamera.getParameters().getPreviewSize().width + " X "
+ mCamera.getParameters().getPreviewSize().height);
Log.i(TAG, " getPictureSize " + mCamera.getParameters().getPictureSize().width + " X "
+ mCamera.getParameters().getPictureSize().height);
} catch (Exception e) {
}
}
}

Camera is inverted in Nexus device

I am trying to create custom camera preview logic that actually works properly, for all scenarios:
any device: phone, tablet
any camera: front-facing, rear-facing
android.hardware.Camera
My android:minSdkVersion is 14 and android:targetSdkVersion is 21.
I have implemented custom camera preview class to set display orientation for camera preview and working very well for all devices without only Nexus devices. Nexus devices have I think default 180 orientation.
While I am starting my camera in Nexus devices it is showing inverted. To overcome with i have checked with Build.MANUFACTURER & Build.MODEL to identify the device and set orientation according to it.
if (Build.MODEL.equals("Nexus 6P") && Build.MANUFACTURER.equals("Huawei")) mCamera.setDisplayOrientation(90);
else mCamera.setDisplayOrientation(270);
But it is not working. So can anyone have idea to overcome with this and recommended way !! Advance help would be appreciated !!
As far as I know this problem doesn't occur on Nexus 5. I had to deal with it on a Nexus 5X and I lost some time trying(Click here to see why). As a big note, I can't guarantee that it's the best solution, but it fixed all the problems I had. To solve it I did something like this:
I created a class CameraPreview extends SurfaceView only to encapsulate all the preview initialisation in one place. Here is the constructor for that class:
public CameraPreview(Context context, int screenRotation, Camera camera) {
super(context);
mCamera = camera;
mScreenRotation = screenRotation;
mHolder = getHolder();
mHolder.addCallback(this);
setFocusable(true);
setFocusableInTouchMode(true);
}
To create the preview I used this: mPreview = new CameraPreview(getContext(), screenRotation, mCamera);, where screenRotation is int screenRotation = getActivity().getWindowManager().getDefaultDisplay().getRotation();
When the surfaceCreated callback is called:
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
setCameraDisplayOrientation(mScreenRotation, 0, mCamera);
Here,0 comes from the cameraId (it might be different if you're using the front facing camera). And here is all the magic:
public void setCameraDisplayOrientation(int screenRotation, int cameraId, Camera camera) {
int rotation = getRotationAngle(screenRotation, cameraId);
camera.setDisplayOrientation(rotation);
}
public static int getRotationAngle(int screenRotation, int cameraId) {
Camera.CameraInfo info = new Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int degrees = 0;
switch (screenRotation) {
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;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
return result;
}
I hope that this will fix the problem, but before starting to write it, make sure that you read the link I provided to see why the problem takes place. Hope this will fix it for you too.
To initiate in activity :
CameraPreviewNew mPreview = new ResizableCameraPreview(this, cameraId, CameraPreviewNew.LayoutMode.NoBlank, false, screenHeight, screenWidth); // cameraId for front or rear
LinearLayout.LayoutParams previewLayoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
frameCamera.addView(mPreview, 0, previewLayoutParams);
CameraPreviewNew.java
public class CameraPreviewNew extends SurfaceView implements SurfaceHolder.Callback {
private static boolean DEBUGGING = false;
private static final String LOG_TAG = "CameraPreviewSample";
private static final String CAMERA_PARAM_ORIENTATION = "orientation";
private static final String CAMERA_PARAM_LANDSCAPE = "landscape";
private static final String CAMERA_PARAM_PORTRAIT = "portrait";
protected Activity mActivity;
private SurfaceHolder mHolder;
protected Camera mCamera;
protected List<Camera.Size> mPreviewSizeList;
protected List<Camera.Size> mPictureSizeList;
protected Camera.Size mPreviewSize;
protected Camera.Size mPictureSize;
private int mSurfaceChangedCallDepth = 0;
private int mCameraId;
private LayoutMode mLayoutMode;
private int mCenterPosX = -1;
private int mCenterPosY;
private int screenHeight, screenWidth;
PreviewReadyCallback mPreviewReadyCallback = null;
public enum LayoutMode {
FitToParent, // Scale to the size that no side is larger than the parent
NoBlank // Scale to the size that no side is smaller than the parent
}
public interface PreviewReadyCallback {
void onPreviewReady();
}
/**
* State flag: true when surface's layout size is set and surfaceChanged()
* process has not been completed.
*/
protected boolean mSurfaceConfiguring = false;
public CameraPreviewNew(Activity activity, int cameraId, LayoutMode mode, int screenHeight, int screenWidth) {
super(activity); // Always necessary
mActivity = activity;
mLayoutMode = mode;
this.screenHeight = screenHeight;
this.screenWidth = screenWidth;
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
// mHolder.setFixedSize(fixWidth, fixHeight);
// FileLog.v("Camera ID ::::::::::: " + cameraId);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
if (Camera.getNumberOfCameras() > cameraId) {
mCameraId = cameraId;
} else {
mCameraId = 0;
}
} else {
mCameraId = 0;
}
// FileLog.d("Camera ID ::::::::::: " + cameraId);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
mCamera = Camera.open(mCameraId);
} else {
mCamera = Camera.open();
}
Camera.Parameters cameraParams = mCamera.getParameters();
mPreviewSizeList = cameraParams.getSupportedPreviewSizes();
mPictureSizeList = cameraParams.getSupportedPictureSizes();
// FileLog.d("Preview Size ID ::::::::::: " + mPreviewSizeList);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(mHolder);
} catch (IOException e) {
mCamera.release();
mCamera = null;
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
mSurfaceChangedCallDepth++;
doSurfaceChanged(width, height);
mSurfaceChangedCallDepth--;
}
public void doSurfaceChanged(int width, int height) {
mCamera.stopPreview();
Camera.Parameters cameraParams = mCamera.getParameters();
boolean portrait = isPortrait();
// The code in this if-statement is prevented from executed again when surfaceChanged is
// called again due to the change of the layout size in this if-statement.
if (!mSurfaceConfiguring) {
Camera.Size previewSize = determinePreviewSize(portrait, width, height);
Camera.Size pictureSize = determinePictureSize(previewSize);
if (DEBUGGING) { Log.v(LOG_TAG, "Desired Preview Size - w: " + width + ", h: " + height); }
mPreviewSize = previewSize;
mPictureSize = pictureSize;
mSurfaceConfiguring = adjustSurfaceLayoutSize(previewSize, portrait, width, height);
// Continue executing this method if this method is called recursively.
// Recursive call of surfaceChanged is very special case, which is a path from
// the catch clause at the end of this method.
// The later part of this method should be executed as well in the recursive
// invocation of this method, because the layout change made in this recursive
// call will not trigger another invocation of this method.
if (mSurfaceConfiguring && (mSurfaceChangedCallDepth <= 1)) {
return;
}
}
configureCameraParameters(cameraParams, portrait);
mSurfaceConfiguring = false;
try {
mCamera.startPreview();
} catch (Exception e) {
Log.w(LOG_TAG, "Failed to start preview: " + e.getMessage());
// Remove failed size
mPreviewSizeList.remove(mPreviewSize);
mPreviewSize = null;
// Reconfigure
if (mPreviewSizeList.size() > 0) { // prevent infinite loop
surfaceChanged(null, 0, width, height);
} else {
Log.w(LOG_TAG, "Gave up starting preview");
}
}
if (null != mPreviewReadyCallback) {
mPreviewReadyCallback.onPreviewReady();
}
}
/**
* #param portrait
* #param reqWidth must be the value of the parameter passed in surfaceChanged
* #param reqHeight must be the value of the parameter passed in surfaceChanged
* #return Camera.Size object that is an element of the list returned from Camera.Parameters.getSupportedPreviewSizes.
*/
protected Camera.Size determinePreviewSize(boolean portrait, int reqWidth, int reqHeight) {
// Meaning of width and height is switched for preview when portrait,
// while it is the same as user's view for surface and metrics.
// That is, width must always be larger than height for setPreviewSize.
int reqPreviewWidth; // requested width in terms of camera hardware
int reqPreviewHeight; // requested height in terms of camera hardware
if (portrait) {
reqPreviewWidth = reqHeight;
reqPreviewHeight = reqWidth;
} else {
reqPreviewWidth = reqWidth;
reqPreviewHeight = reqHeight;
}
if (DEBUGGING) {
Log.v(LOG_TAG, "Listing all supported preview sizes");
for (Camera.Size size : mPreviewSizeList) {
Log.v(LOG_TAG, " w: " + size.width + ", h: " + size.height);
}
Log.v(LOG_TAG, "Listing all supported picture sizes");
for (Camera.Size size : mPictureSizeList) {
Log.v(LOG_TAG, " w: " + size.width + ", h: " + size.height);
}
}
// Adjust surface size with the closest aspect-ratio
float reqRatio = ((float) reqPreviewWidth) / reqPreviewHeight;
float curRatio, deltaRatio;
float deltaRatioMin = Float.MAX_VALUE;
Camera.Size retSize = null;
for (Camera.Size size : mPreviewSizeList) {
curRatio = ((float) size.width) / size.height;
deltaRatio = Math.abs(reqRatio - curRatio);
if (deltaRatio < deltaRatioMin) {
deltaRatioMin = deltaRatio;
retSize = size;
}
}
retSize = mPreviewSizeList.get(0);
return retSize;
}
protected Camera.Size determinePictureSize(Camera.Size previewSize) {
Camera.Size retSize = null;
for (Camera.Size size : mPictureSizeList) {
if (size.equals(previewSize)) {
return size;
}
}
if (DEBUGGING) { Log.v(LOG_TAG, "Same picture size not found."); }
// if the preview size is not supported as a picture size
float reqRatio = ((float) previewSize.width) / previewSize.height;
float curRatio, deltaRatio;
float deltaRatioMin = Float.MAX_VALUE;
for (Camera.Size size : mPictureSizeList) {
curRatio = ((float) size.width) / size.height;
deltaRatio = Math.abs(reqRatio - curRatio);
if (deltaRatio < deltaRatioMin) {
deltaRatioMin = deltaRatio;
retSize = size;
}
}
retSize = mPictureSizeList.get(0);
return retSize;
}
protected boolean adjustSurfaceLayoutSize(Camera.Size previewSize, boolean portrait,
int availableWidth, int availableHeight) {
float tmpLayoutHeight, tmpLayoutWidth;
if (portrait) {
tmpLayoutHeight = previewSize.width;
tmpLayoutWidth = previewSize.height;
} else {
tmpLayoutHeight = previewSize.height;
tmpLayoutWidth = previewSize.width;
}
float factH, factW, fact;
factH = availableHeight / tmpLayoutHeight;
factW = availableWidth / tmpLayoutWidth;
if (mLayoutMode == LayoutMode.FitToParent) {
// Select smaller factor, because the surface cannot be set to the size larger than display metrics.
if (factH < factW) {
fact = factH;
} else {
fact = factW;
}
} else {
if (factH < factW) {
fact = factW;
} else {
fact = factH;
}
}
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)this.getLayoutParams();
int layoutHeight = (int) (tmpLayoutHeight * fact);
int layoutWidth = (int) (tmpLayoutWidth * fact);
if (DEBUGGING) {
Log.v(LOG_TAG, "Preview Layout Size - w: " + layoutWidth + ", h: " + layoutHeight);
Log.v(LOG_TAG, "Scale factor: " + fact);
}
boolean layoutChanged;
if ((layoutWidth != this.getWidth()) || (layoutHeight != this.getHeight())) {
int diffHeight = (screenHeight - layoutHeight) / 2;
layoutParams.height = layoutHeight + diffHeight;
int diffWidth = (screenWidth - layoutWidth) / 2;
layoutParams.width = layoutWidth + diffWidth;
if (mCenterPosX >= 0) {
layoutParams.topMargin = mCenterPosY - (layoutHeight / 2);
layoutParams.leftMargin = mCenterPosX - (layoutWidth / 2);
}
this.setLayoutParams(layoutParams); // this will trigger another surfaceChanged invocation.
layoutChanged = true;
} else {
layoutChanged = false;
}
return layoutChanged;
}
/**
* #param x X coordinate of center position on the screen. Set to negative value to unset.
* #param y Y coordinate of center position on the screen.
*/
public void setCenterPosition(int x, int y) {
mCenterPosX = x;
mCenterPosY = y;
}
protected void configureCameraParameters(Camera.Parameters cameraParams, boolean portrait) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) { // for 2.1 and before
if (portrait) {
cameraParams.set(CAMERA_PARAM_ORIENTATION, CAMERA_PARAM_PORTRAIT);
} else {
cameraParams.set(CAMERA_PARAM_ORIENTATION, CAMERA_PARAM_LANDSCAPE);
}
} else { // for 2.2 and later
int angle;
Display display = mActivity.getWindowManager().getDefaultDisplay();
switch (display.getRotation()) {
case Surface.ROTATION_0: // This is display orientation
angle = 90; // This is camera orientation
break;
case Surface.ROTATION_90:
angle = 0;
break;
case Surface.ROTATION_180:
angle = 270;
break;
case Surface.ROTATION_270:
angle = 180;
break;
default:
angle = 90;
break;
}
Log.v(LOG_TAG, "angle: " + angle);
mCamera.setDisplayOrientation(angle);
}
cameraParams.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
cameraParams.setPictureSize(mPictureSize.width, mPictureSize.height);
cameraParams.setZoom(0);
// if (cameraParams.isZoomSupported()) {
final int maxZoomLevel = cameraParams.getMaxZoom();
Log.e("max ZOOM ", "is " + maxZoomLevel);
// }
// cameraParams.setPreviewSize(fixWidth, fixHeight);
// cameraParams.setPictureSize(fixWidth, fixHeight);
if (DEBUGGING) {
Log.v(LOG_TAG, "Preview Actual Size - w: " + mPreviewSize.width + ", h: " + mPreviewSize.height);
Log.v(LOG_TAG, "Picture Actual Size - w: " + mPictureSize.width + ", h: " + mPictureSize.height);
}
mCamera.setParameters(cameraParams);
}
#SuppressWarnings("unused")
private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.2;
double targetRatio = (double) w / h;
if (sizes == null)
return null;
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
// Try to find an size match aspect ratio and size
for (Size size : sizes) {
Log.d("Camera", "Checking size " + size.width + "w " + size.height
+ "h");
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 (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) {
stop();
}
public void stop() {
try {
if (null == mCamera) {
return;
}
if(mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}catch (Exception e){
e.printStackTrace();
}
}
public boolean isPortrait() {
return (mActivity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT);
}
public void setOneShotPreviewCallback(PreviewCallback callback) {
if (null == mCamera) {
return;
}
mCamera.setOneShotPreviewCallback(callback);
}
public void setPreviewCallback(PreviewCallback callback) {
if (null == mCamera) {
return;
}
mCamera.setPreviewCallback(callback);
}
public Camera.Size getPreviewSize() {
return mPreviewSize;
}
public void setOnPreviewReady(PreviewReadyCallback cb) {
mPreviewReadyCallback = cb;
}
public Camera getPreviewCamera() {
return mCamera;
}
}
ResizableCameraPreview.java
public class ResizableCameraPreview extends CameraPreviewNew {
private static boolean DEBUGGING = false;
private static final String LOG_TAG = "ResizableCameraPreviewSample";
/**
* #param activity
* #param addReversedSizes is set to true to add reversed values of supported preview-sizes to the list.
*/
public ResizableCameraPreview(Activity activity, int cameraId, LayoutMode mode, boolean addReversedSizes, int screenHeight, int screenWidth) {
super(activity, cameraId, mode, screenHeight, screenWidth);
if (addReversedSizes) {
List<Camera.Size> sizes = mPreviewSizeList;
int length = sizes.size();
for (int i = 0; i < length; i++) {
Camera.Size size = sizes.get(i);
Camera.Size revSize = mCamera.new Size(size.height, size.width);
sizes.add(revSize);
}
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
mCamera.stopPreview();
Camera.Parameters cameraParams = mCamera.getParameters();
boolean portrait = isPortrait();
if (!mSurfaceConfiguring) {
Camera.Size previewSize = determinePreviewSize(portrait, width, height);
Camera.Size pictureSize = determinePictureSize(previewSize);
Log.v(LOG_TAG, "Desired Preview Size - w: " + width + ", h: " + height);
mPreviewSize = previewSize;
mPictureSize = pictureSize;
mSurfaceConfiguring = adjustSurfaceLayoutSize(previewSize, portrait, width, height);
if (mSurfaceConfiguring) {
return;
}
}
configureCameraParameters(cameraParams, portrait);
mSurfaceConfiguring = false;
try {
mCamera.startPreview();
} catch (Exception e) {
Log.w(LOG_TAG, "Failed to start preview: " + e.getMessage());
}
}
/**
*
* #param index selects preview size from the list returned by CameraPreview.getSupportedPreivewSizes().
* #param width is the width of the available area for this view
* #param height is the height of the available area for this view
*/
public void setPreviewSize(int index, int width, int height) {
mCamera.stopPreview();
Camera.Parameters cameraParams = mCamera.getParameters();
boolean portrait = isPortrait();
Camera.Size previewSize = mPreviewSizeList.get(index);
Camera.Size pictureSize = determinePictureSize(previewSize);
if (DEBUGGING) { Log.v(LOG_TAG, "Requested Preview Size - w: " + previewSize.width + ", h: " + previewSize.height); }
mPreviewSize = previewSize;
mPictureSize = pictureSize;
boolean layoutChanged = adjustSurfaceLayoutSize(previewSize, portrait, width, height);
if (layoutChanged) {
mSurfaceConfiguring = true;
return;
}
configureCameraParameters(cameraParams, portrait);
try {
mCamera.startPreview();
} catch (Exception e) {
}
mSurfaceConfiguring = false;
}
public List<Camera.Size> getSupportedPreivewSizes() {
return mPreviewSizeList;
}
}
Xml file :
<FrameLayout
android:id="#+id/frm"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:id="#+id/frameCamera"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
</LinearLayout>
</FrameLayout>

Custom camera preview is stretched and blur

I am using custom camera but the preview of custom camera is stretched and blur but after the click picture image shows right. Please help me how i can set the preview right on every device , thats my code
class Preview extends ViewGroup implements SurfaceHolder.Callback {
private final String TAG = "Preview";
SurfaceView mSurfaceView;
public static SurfaceHolder mHolder;
Size mPreviewSize;
List<Size> mSupportedPreviewSizes;
Camera mCamera;
Preview(Context context, SurfaceView sv) {
super(context);
mSurfaceView = sv;
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
requestLayout();
// get Camera parameters
Camera.Parameters params = mCamera.getParameters();
List<String> focusModes = params.getSupportedFocusModes();
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
// set the focus mode
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
// set Camera parameters
mCamera.setParameters(params);
}
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// We purposely disregard child measurements because act as a wrapper to a SurfaceView that
// centers the camera preview instead of stretching it.
int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
// we only allow landscape, if height > width - it means that we are in rotation animation. Swap width with height
if (height > width) {
width += height;
height = width - height;
width = width - height;
}
setMeasuredDimension(width, height);
Log.v("Camera", width + "x" + height);
if (mSupportedPreviewSizes == null && mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
}
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed && getChildCount() > 0) {
final View child = getChildAt(0);
final int width = r - l;
final int height = b - t;
int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null) {
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
}
// Center the child SurfaceView within the parent.
if (width * previewHeight > height * previewWidth) {
final int scaledChildWidth = previewWidth * height / previewHeight;
child.layout((width - scaledChildWidth) / 2, 0,
(width + scaledChildWidth) / 2, height);
} else {
final int scaledChildHeight = previewHeight * width / previewWidth;
child.layout(0, (height - scaledChildHeight) / 2,
width, (height + scaledChildHeight) / 2);
}
}
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, acquire the camera and tell it where
// to draw.
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(holder);
}
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
if (mCamera != null) {
mCamera.stopPreview();
}
}
private 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;
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
// Try to find an size match aspect ratio and size
for (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 (Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
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);
try {
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
Log.d(VIEW_LOG_TAG, "Error starting camera preview: " + e.getMessage());
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
try {
Camera.Parameters parameters = mCamera.getParameters();
// List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
//Camera.Size previewSize = previewSizes.get(4); //480h x 720w
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
e.printStackTrace();
}
}
}
after click image shows right

camera application issue camera preview

I am working in android custom camera app. I am facing a problem that is camera preview is stretched how can i resolve this ?
or when i click image with front camera then image shown in rotation form. is there any library for it?
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.
Camera.Parameters parameters = mCamera.getParameters();
List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();
Camera.Size selected = sizes.get(0);
parameters.setPreviewSize(selected.width,selected.height);
mCamera.setDisplayOrientation(Constant.CAMERA_ORIENTATION);
mCamera.setParameters(parameters);
mCamera.startPreview();
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();
}
public int getDisplayWidth() {
return displayWidth;
}
public int getDisplayHeight() {
return displayHeight;
}
public void setDisplayWidth(int displayWidth) {
this.displayWidth = displayWidth;
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
if (supportedPreviewSizes != null) {
previewSize = getOptimalPreviewSize(supportedPreviewSizes, width, height);
setCameraPictureSize();
Constant.CAMERA_PICTURE_WIDTH = pictureSize.width;
Constant.CAMERA_PICTURE_HEIGHT = pictureSize.height;
}
float ratio = 0f;
if(previewSize != null) {
if (previewSize.height >= previewSize.width) {
ratio = (float) previewSize.height / previewSize.width;
} else {
ratio = (float) previewSize.width / previewSize.height;
}
}
Constant.CAMERA_PREVIEW_WIDTH = previewSize.width;
Constant.CAMERA_PREVIEW_HEIGHT = previewSize.height;
int newWidth = width;
int newHeight = (int)(width * ratio);
setMeasuredDimension(newWidth, newHeight);
}
private void setCameraPictureSize() {
List<Camera.Size> pictureSizes = mCamera.getParameters().getSupportedPictureSizes();
float previewAspectRatio = (float) previewSize.width / previewSize.height;
for(Camera.Size size : pictureSizes){
float pictureAspectRatio = (float) size.width / size.height;
if(previewAspectRatio == pictureAspectRatio){
pictureSize = size;
break;
}
}
if(pictureSize == null) {
//get the largest picture size
pictureSize = pictureSizes.get(0);
}
}
Set this,
mSurfaceView.setAspectRatioMode(SurfaceView.ASPECT_RATIO_PREVIEW);

SurfaceView camera preview squared: avoid image distortion

I have the sequent scenario: a surfaceview of square shape (on top of acvitity) and a green view below (that i will fill on future with other views). Now i would that preview of camera inside surfaceView it's squared, because i need to take squared picture, but preview is distorted (maybe because i gave preview dimension not squared). I show you code.
How i calculate dimension of square at runtime and assign dimension to green view
surfaceView = (SurfaceView) findViewById(R.id.surfaceview);
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
dpHeight = displayMetrics.heightPixels;
dpWidth = displayMetrics.widthPixels;
surfaceViewDimension = dpWidth;
int borderHeight = dpHeight - dpWidth;
View bottomBorder = findViewById(R.id.bottom_border);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
LayoutParams.MATCH_PARENT, borderHeight);
params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
bottomBorder.setLayoutParams(params);
bottomBorder.setBackgroundColor(Color.GREEN);
this is how i set camera options:
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Camera.Parameters params = mCamera.getParameters();
Camera.Size result = getBestPreviewSize(params, width, height);
params.setPreviewSize(result.width, result.height);
params.setPictureFormat(ImageFormat.JPEG);
params.setJpegQuality(100);
params.setPictureSize(dpWidth, dpWidth);
params.setRotation(90);
mCamera.setParameters(params);
mCamera.startPreview();
}
public Camera.Size getBestPreviewSize(Camera.Parameters params, int width,
int height) {
Camera.Size result = null;
for (Camera.Size size : params.getSupportedPreviewSizes()) {
Log.d("size: ", size.width + ":" + size.height);
if (size.width <= width && size.height <= height) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea > resultArea) {
result = size;
}
}
}
}
return result;
}
how could i change my code for obtain a squared preview without image distortion (saved picture is not distorced, only preview)?

Categories

Resources