For my application I am using android native camera and previewing the image using surface view. in my case everything is working except the camera orientation. When I open the camera by setting screenOrientation="landscape on manifest file I am getting the preview without any problem in landscape mode. But I need to take image in portrait mode, for this I changed my manifest like android:screenOrientation="portrait" and change my code like mCamera.setDisplayOrientation(90), params.set("orientation", "landscape"),params.set("rotation", 90), but still I am getting 90 degree rotated image.
And my code is
public void setupCamera(int width, int height) {
Log.i(TAG, "setupCamera");
synchronized (this) {
if (mCamera != null) {
Camera.Parameters params = mCamera.getParameters();
List<Camera.Size> sizes = params.getSupportedPreviewSizes();
List<Camera.Size> imgsize=params.getSupportedPictureSizes();
mFrameWidth = width;
mFrameHeight = height;
// mCamera.setDisplayOrientation(90);
params.set("orientation", "landscape");
params.set("rotation", 90);
// selecting optimal camera preview size
{
int minDiff = Integer.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - height) < minDiff) {
mFrameWidth = size.width;
mFrameHeight = size.height;
minDiff = Math.abs(size.height - height);
}
}
}
params.setPreviewSize(getFrameWidth(), getFrameHeight());
List<String> FocusModes = params.getSupportedFocusModes();
if (FocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO))
{
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
}
mCamera.setParameters(params);
mCamera.startPreview();
}
}
}
I am using Micromax A 52 model...
Any one please help.....
If your application runs on v2.2 or above you can rotate camera orientation to portrait using camera.setDisplayOrientation(90).
For others:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO)
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
//After opening camera - call via reflection
Method rotateMethod = android.hardware.Camera.class.getMethod("setDisplayOrientation", int.class);
rotateMethod.invoke(mCamera, 90);
for more details please refer this link and this Hope this will be helpful
Related
I have searched about fitting camera preview and surface view but I couldn't find about not stretching image while saving it in android studio.
The camera works well on showing on the surface view of the devices. The ratios of the supported screen sizes and surface view are ok.
The problem is that after capturing the image it takes more from all sides of the surface view of the screen. It just does not take the view that is shown on the surface view but more in all sides of the devices while saving the image.
The problem is only solved when height of the surface view and supported screen sizes are equal. Such as:
Supported size is:
1280/720
Surface view is:
405/720
But this leads to a problem which limits the height and width of the surface view. I want height of surface view to be longer and width to be match parent.
So, the problem is not solved without having the heights equal. I want height of the surface view to be longer and width to be match parent.
Can anyone help me with this,
Thanks everyone,
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "CameraPreview";
private Context mContext;
private SurfaceHolder mHolder;
private Camera mCamera;
private List<Camera.Size> mSupportedPreviewSizes;
private Camera.Size mPreviewSize;
public int measurewidth, measureheigh;
public CameraPreview(Context context, Camera camera) {
super(context);
mContext = context;
mCamera = camera;
// supported preview sizes
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
for(Camera.Size str: mSupportedPreviewSizes)
Log.e(TAG, str.width + "/" + str.height);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
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) {
// empty. surfaceChanged will take care of stuff
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Log.e(TAG, "surfaceChanged => w=" + w + ", h=" + 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.
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
try {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width ,mPreviewSize.height); //B
// parameters.setPreviewSize(1280,720 );
mCamera.setParameters(parameters);
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
Log.e(TAG, "REAL SCREEN SIZE => w=" + width + ", h=" + height);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
Log.e(TAG, "MPREVIEW SIZE OPTIMAL => w=" + mPreviewSize.width + ", h=" + mPreviewSize.height);
float ratio;
if(mPreviewSize.height >= mPreviewSize.width)
ratio = (float) mPreviewSize.height / (float) mPreviewSize.width;
else
ratio = (float) mPreviewSize.width / (float) mPreviewSize.height;
Log.e(TAG, "Ration => R=" + ratio);
// One of these methods should be used, second method squishes preview slightly
//setMeasuredDimension(1080, 1200);
//setMeasuredDimension(mPreviewSize.height, mPreviewSize.width); //B
setMeasuredDimension(width, (int)(width*ratio)); //B
// setMeasuredDimension(720, 1280);
// setMeasuredDimension((int) (width ), height);
measurewidth = width ; // this is for bitmap width
measureheigh = (int)(width*ratio); // this is for bitmap height
}
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) { // long screen
final double ASPECT_TOLERANCE = 0.1;
double targetRatio=(double)h / w;
if (sizes == null) return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Camera.Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.width - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.width - targetHeight);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.width - targetHeight) < minDiff) {// size.height was changed with size.width
optimalSize = size;
minDiff = Math.abs(size.width - targetHeight); // size.height was changed with size.width
}
}
}
return optimalSize;
}
}
After checking through your code (and the problem you are facing), I have decided to not focus on the coding part. Instead, I will give you an overview of what's happening between a preview and a snap (take picture).
Overview
In legacy camera API, there are 2 very important Camera.Size that you would need to take care - preview size and picture size.
From Camera.Parameters API, you are able to get 2 separate list of supported sizes by calling Parameters.getSupportedPreviewSizes() and Parameters.getSupportedPicturSizes().
As the names imply, each size list is dedicated for different purpose - preview and take picture.
Sample case
Imagine you have the list like this:
Preview size: 1920x1080 (16:9), 1280x960 (4:3)
Picture size: 3840x2160 (16:9), 1920x1440 (4:3)
Say, you want to take a picture in 3840x2160 (16:9), you call Parameters.setPictureSize(3840, 2160) to tell the camera you want to take a picture in this resolution when you call takePicture(...).
Solve equation
Now, how are you going to show a preview with the same resolution on the screen (or viewfinder)?
Yes, you guessed it - a preview size with the same aspect ratio (AR).
We need to find out the AR of the (target) picture size and find a matching preview size with the same AR and call Parameters.setPreviewSize(width, height) when we are ready.
In our case, we will select the preview size 1920x1080 as it has the same AR (16:9) as the picture size.
Different AR?
What happened if you want to take a picture of 16:9 but is setting the preview size to 4:3?
The answer is obvious, user will not be able to snap a picture in WYSIWYG style.
Points to note
Selecting a picture size and deciding on the preview size is not really difficult. Still, there are more you need to take care of to use the camera properly.
The orientation of the camera (CameraInfo.orientation) as opposed to the device natural orientation. Remember to call `Parameters.setRotation(rotation) when necessary.
In cases where the camera supports the same resolution in different orientation (eg. 1920x1080 and 1080x1920), call `Parameters.setPreviewSize(width, height) with the orientation you wish to take the picture in.
Hope this helps.
I'm trying to use camera features as part of my application and I'm stuck on camera preview step.
I want to understand why the preview image remains dark if there are no bright light.
Here is what params I set before start previewing:
mParameters = mCamera.getParameters();
List<Camera.Size> mSupportedPreviewSizes = mParameters.getSupportedPreviewSizes();
Camera.Size optimalSize = CameraHelper.getOptimalPreviewSize(mSupportedPreviewSizes, DEFAULT_PREVIEW_WIDTH, DEFAULT_PREVIEW_HEIGHT);
// Use the same size for recording profile.
mProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
mProfile.videoFrameWidth = optimalSize.width;
mProfile.videoFrameHeight = optimalSize.height;
// likewise for the camera object itself.
mParameters.setPreviewSize(mProfile.videoFrameWidth, mProfile.videoFrameHeight);
// Set correct video width and height according to screen rotation
transformMatrixHelper.setVideoDimensions(optimalSize.width, optimalSize.height);
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
transformMatrixHelper.setVideoDimensions(optimalSize.height, optimalSize.width);
}
transformMatrixHelper.clearInitTextureDimension();
mParameters.setPreviewFpsRange(MAX_FPS, MAX_FPS);
mParameters.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
// Auto-focus
if (mParameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
}
// Auto-exposure
if (mParameters.isAutoExposureLockSupported()) {
mParameters.setAutoExposureLock(false);
}
mCamera.setParameters(mParameters);
I'm not calling any camera.autoFocus(callback) method after preview stared.
I will be very grateful if someone help me, thanks.
I have the following code in my app:
camera = Camera.open(CameraInfo.CAMERA_FACING_FRONT);
Camera.Parameters setting_param = camera.getParameters();
setting_param.setPreviewSize(128,128);
camera.setParameters(setting_param);
Camera.Parameters read_param = camera.getParameters();
Camera.Size sz = read_param.getPreviewSize();
The code works exactly as expected on my galaxy tab 10.1 running Android 3.1. but on My Galaxy S II phone running 4.1.2, the width and height of the preview, i.e. sz.width and sz.height are 640 and 480! Is this a bug in 4.1.2, or a consequence of an error of mine I am getting away with in 3.1 and not getting away with in 4.1.2?
Before setting a preview size you should check if that preview size is supported.
You have a method on Camera called getSupportedPreviewSizes which will return you a list of supported preview sizes.
Mick, you should check if a preview size is supported by camera before setting it. Change your onSurfaceChanged method a bit like following.
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Camera.Parameters mParameters = mCamera.getParameters();
Camera.Size bestSize = null;
List<Camera.Size> sizeList = mCamera.getParameters().getSupportedPreviewSizes();
bestSize = sizeList.get(0);
for(int i = 1; i < sizeList.size(); i++){
if((sizeList.get(i).width * sizeList.get(i).height) >
(bestSize.width * bestSize.height)){
bestSize = sizeList.get(i);
}
}
mParameters.setPreviewSize(bestSize.width, bestSize.height);
mCamera.setParameters(mParameters);
mCamera.startPreview();
//any other code ....
}
In portrait mode, the images look vertically stretched and in landscape mode it looks horizontally stretched.
Although after capturing the image appears in proper size.
How to resolve this issue?
You need to choose a preview size that matches your display size. I would suggest changing the preview size setting to match your SurfaceView rather than the other way around. While the preview data is just fine, it's not distorted, it will look distorted when flung onto a surface with different aspect ratio.
If you have a full-screen view, then you should find the camera has a preview size matching that size -- at the least there will be one with the same aspect ratio. For example if your screen is 640x480 then a 320x240 preview size will not appear stretched on a full-screen SurfaceView.
You have to constrain your preview size based on (1) available preview sizes (2) your view. Here is my solution if you still need it:
private class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
private void startPreview() {
try {
/**
* Orientation should be adjusted, see http://stackoverflow.com/questions/20064793/how-to-fix-camera-orientation/26979987#26979987
*/
Camera.Parameters parameters = mCamera.getParameters();
List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
Camera.Size previewSize = null;
float closestRatio = Float.MAX_VALUE;
int targetPreviewWidth = isLandscape() ? getWidth() : getHeight();
int targetPreviewHeight = isLandscape() ? getHeight() : getWidth();
float targetRatio = targetPreviewWidth / (float) targetPreviewHeight;
Log.v(TAG, "target size: " + targetPreviewWidth + " / " + targetPreviewHeight + " ratio:" + targetRatio);
for (Camera.Size candidateSize : previewSizes) {
float whRatio = candidateSize.width / (float) candidateSize.height;
if (previewSize == null || Math.abs(targetRatio - whRatio) < Math.abs(targetRatio - closestRatio)) {
closestRatio = whRatio;
previewSize = candidateSize;
}
}
Log.v(TAG, "preview size: " + previewSize.width + " / " + previewSize.height);
parameters.setPreviewSize(previewSize.width, previewSize.height);
mCamera.setParameters(parameters);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
}
I fixed this by adding this before calling camera.startPreview():
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(yourSurfaceView.getWidth(), yourSurfaceView.getHeight());
camera.setParameters(parameters);
It might help someone.
just add the following function to set the aspect ratio and preview size
private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio=(double)h / w;
if (sizes == null) return null;
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Size size : sizes) {
double ratio = (double) size.getWidth() / size.getHeight();
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.getHeight() - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.getHeight() - targetHeight);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Size size : sizes) {
if (Math.abs(size.getHeight() - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.getHeight() - targetHeight);
}
}
}
return optimalSize;
}
use like this
final CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
try {
final CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
final StreamConfigurationMap map =
characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
// For still image captures, we use the largest available size.
final Size largest =
Collections.max(
Arrays.asList(map.getOutputSizes(ImageFormat.YUV_420_888)),
new CompareSizesByArea());
sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
// Danger, W.R.! Attempting to use too large a preview size could exceed the camera
// bus' bandwidth limitation, resulting in gorgeous previews but the storage of
// garbage capture data.
/* previewSize =
chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
inputSize.getWidth(),
inputSize.getHeight());*/
previewSize = getOptimalPreviewSize(Arrays.asList(map.getOutputSizes(SurfaceTexture.class)),textureView.getWidth(),textureView.getHeight());
} catch (final CameraAccessException e) {
Log.e(TAG, "Exception!" + e);
} catch (final NullPointerException e) {
// Currently an NPE is thrown when the Camera2API is used but not supported on the
// device this code runs.
// TODO(andrewharp): abstract ErrorDialog/RuntimeException handling out into new method and
// reuse throughout app.
ErrorDialog.newInstance(getString(R.string.camera_error))
.show(getChildFragmentManager(), FRAGMENT_DIALOG);
throw new RuntimeException(getString(R.string.camera_error));
}
The solution is simple! If you use surfaceview under actionbar this maybe the problem. I use this line and i can fix, but i not test using action bar.
use this:
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
If you are talking about preview, try setting the SurfaceView's size same as Camera's preview size. That way the preview shouldn't be scaled.
I face a problem a problem trying to have a camera preview in portrait mode. I have read various articles about it and I had solved it having the following code:
Display display = ((CaptureActivity)context).getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
if (Integer.parseInt(Build.VERSION.SDK) >= 8) {
setDisplayOrientation(camera, 90);
}else{
Camera.Parameters parameters = camera.getParameters();
parameters.set("orientation", "portrait");
camera.setParameters(parameters);
}
where setDisplayOrientation() is defined as:
protected void setDisplayOrientation(Camera camera, int angle) {
Method downPolymorphic;
try {
downPolymorphic = camera.getClass().getMethod(
"setDisplayOrientation", new Class[] { int.class });
if (downPolymorphic != null)
downPolymorphic.invoke(camera, new Object[] { angle });
} catch (Exception e1) {
}
}
Now I tried this code to a Galaxy Tab and it failed. I solved it (trying and error approach) using the following code:
if (height == 1024 && width == 600) {
Camera.Parameters parameters = camera.getParameters();
parameters.set("orientation", "portrait");
parameters.setRotation(90);
camera.setParameters(parameters);
}
Now my two questions are:
1) Why there is such problem while Galaxy tab has the 2.2 version, and
2) Is there any better solution to this problem?
Thanks a lot for your time!
for setting the display orientation check out the official docs, dont just hardcode 90 degrees there.