Image quality is poor using custom camera - android

I am using custom camera and working fine but the issue is image is saving with very low (poor) quality. To overcome with it , i have tried all suggestions and implementations. Like ,
parameters.setJpegQuality(100);
parameters.setPictureFormat(ImageFormat.JPEG);
this is not working. After that i have used
List<Size> sizes = cameraParams.getSupportedPictureSizes();
Camera.Size size = sizes.get(0);
for(int i=0;i<sizes.size();i++)
{
if(sizes.get(i).width > size.width)
size = sizes.get(i);
}
cameraParams.setPictureSize(mPictureSize.width, mPictureSize.height);
This is also not working. Its saving with poor quality still.
Note : Camera preview is showing proper with good quality but the issue is when saving captured image to sdcard folder.
Advanced help would be appreciated!!

Finally my issue solved.
Here I was setting parameters for camera preview before i was capturing the image
public void takePicture() {
mCamera.takePicture(new ShutterCallback() {
#Override
public void onShutter() {
}
}, new PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
}
}, new PictureCallback() {
#Override
public void onPictureTaken(final byte[] data, Camera camera) {
data1 = data;
if (mCamera != null) {
mCamera.stopPreview();
}
}
});
}
So before i called this function in my fragment i have set parameters before this method.
mPreview.setParams(params);// This was the mistake what i have done !
mPreview.takePicture();
finally solved after removing mPreview.setParams(params);

I can show you methods for resetting preview size:
You should change your parameters of preview at Camera.
private void setImageSize() {
Camera.Size size = CameraUtil.findClosetImageSize(mRxCamera.getNativeCamera(), PREFER_SIZE);
mCamera.getNativeCamera().getParameters().setPictureSize(size.width, size.height);
WIDTH = size.width;
HEIGHT = size.height;
}
and after You need to change layout sizes
private void resetPreviewSize() {
final boolean widthIsMax = mWidth > mHeight;
final Camera.Size size = mCamera.getNativeCamera().getParameters().getPreviewSize();
final RectF rectDisplay = new RectF();
final RectF rectPreview = new RectF();
rectDisplay.set(0, 0, mWidth, mHeight);
final int width = widthIsMax ? size.width : size.height;
final int height = widthIsMax ? size.height : size.width;
rectPreview.set(0, 0, width, height);
final Matrix matrix = new Matrix();
matrix.setRectToRect(rectDisplay, rectPreview, Matrix.ScaleToFit.START);
matrix.invert(matrix);
matrix.mapRect(rectPreview);
mCameraView.getLayoutParams().height = (int) (rectPreview.bottom);
mCameraView.getLayoutParams().width = (int) (rectPreview.right);
mCameraView.requestLayout();
}
and if you need
public static Camera.Size findClosetImageSize(Camera camera, Point preferSize) {
int preferX = preferSize.x;
int preferY = preferSize.y;
Camera.Parameters parameters = camera.getParameters();
List<Camera.Size> allSupportSizes = parameters.getSupportedPictureSizes();
Log.d(TAG, "all support Image size: " + dumpPreviewSizeList(allSupportSizes));
int minDiff = Integer.MAX_VALUE;
int index = 0;
for (int i = 0; i < allSupportSizes.size(); i++) {
Camera.Size size = allSupportSizes.get(i);
int x = size.width;
int y = size.height;
int diff = Math.abs(x - preferX) + Math.abs(y - preferY);
if (diff < minDiff) {
minDiff = diff;
index = i;
}
}
return allSupportSizes.get(index);
}

Related

Camera Size and 4:3 aspect ratio is not matching

I am using the Surface View of Camera to show camera and take a photo
i need the camera preview to be of specific ration 4:3, instagram is a square and mine is a rectangle.
If you look at the instagram app the camera preview is not stretching or compressed, but in mine its compressed.
This is my Camera Preview Class :
class CustomCam extends SurfaceView implements SurfaceHolder.Callback {
private final String TAG = "PIC-FRAME";
private static final double ASPECT_RATIO = 4.0 / 3.0;
private static final int PICTURE_SIZE_MAX_WIDTH = 1280;
private static final int PREVIEW_SIZE_MAX_WIDTH = 640;
private SurfaceHolder mHolder;
private Camera mCamera;
private Display display;
public List<Camera.Size> mSupportedPreviewSizes;
private Camera.Size mPreviewSize;
public CustomCam(Activity context, Camera camera) {
super(context);
mCamera = camera;
display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
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);
setKeepScreenOn(true);
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
this.getHolder().removeCallback(this);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
}
private Camera.Size getBestPreviewSize(int width, int height) {
Camera.Size result = null;
Camera.Parameters p = mCamera.getParameters();
for (Camera.Size size : p.getSupportedPreviewSizes()) {
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;
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
//This line helped me set the preview Display Orientation to Portrait
//Only works API Level 8 and higher unfortunately.
try {
Camera.Parameters parameters = mCamera.getParameters();
// Camera.Size size = getBestPreviewSize(width, height);
// Camera.Size size = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
// parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
// initialCameraPictureSize(parameters);
// parameters.setPreviewSize(size.width, size.height);
Camera.Size bestPreviewSize = determineBestPreviewSize(parameters);
Camera.Size bestPictureSize = determineBestPictureSize(parameters);
parameters.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height);
parameters.setPictureSize(bestPictureSize.width, bestPictureSize.height);
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
mCamera.setDisplayOrientation(90);
mCamera.getParameters().setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
mCamera.setPreviewDisplay(mHolder);
mCamera.setParameters(parameters);
mCamera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void initialCameraPictureSize(Camera.Parameters parameters) {
List list = parameters.getSupportedPictureSizes();
if (list != null) {
Camera.Size size = null;
Iterator iterator = list.iterator();
do {
if (!iterator.hasNext())
break;
Camera.Size size1 = (Camera.Size) iterator.next();
if (Math.abs(3F * ((float) size1.width / 4F) - (float) size1.height) < 0.1F * (float) size1.width && (size == null || size1.height > size.height && size1.width < 3000))
size = size1;
} while (true);
if (size != null)
parameters.setPictureSize(size.width, size.height);
else
Log.e("CameraSettings", "No supported picture size found");
}
}
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
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.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
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;
}
/**
* Measure the view and its content to determine the measured width and the
* measured height.
*/
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = MeasureSpec.getSize(heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
if (width > height * ASPECT_RATIO) {
width = (int) (height * ASPECT_RATIO + 0.5);
} else {
height = (int) (width / ASPECT_RATIO + 0.5);
}
setMeasuredDimension(width, height);
}
protected Camera.Size determineBestSize(List<Camera.Size> sizes, int widthThreshold) {
Camera.Size bestSize = null;
for (Camera.Size currentSize : sizes) {
boolean isDesiredRatio = (currentSize.width / 4) == (currentSize.height / 3);
boolean isBetterSize = (bestSize == null || currentSize.width > bestSize.width);
boolean isInBounds = currentSize.width <= PICTURE_SIZE_MAX_WIDTH;
if (isDesiredRatio && isInBounds && isBetterSize) {
bestSize = currentSize;
}
}
if (bestSize == null) {
return sizes.get(0);
}
return bestSize;
}
private Camera.Size determineBestPreviewSize(Camera.Parameters parameters) {
List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();
return determineBestSize(sizes, PREVIEW_SIZE_MAX_WIDTH);
}
private Camera.Size determineBestPictureSize(Camera.Parameters parameters) {
List<Camera.Size> sizes = parameters.getSupportedPictureSizes();
return determineBestSize(sizes, PICTURE_SIZE_MAX_WIDTH);
}
}
My Custom Frame layout :
CustomFrameLayout extends FrameLayout {
private static final float RATIO = 4f / 3f;
public CustomFrameLayout(Context context) {
super(context);
}
public CustomFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public CustomFrameLayout(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
int height = getMeasuredHeight();
int widthWithoutPadding = width - getPaddingLeft() - getPaddingRight();
int heigthWithoutPadding = height - getPaddingTop() - getPaddingBottom();
int maxWidth = (int) (heigthWithoutPadding * RATIO);
int maxHeight = (int) (widthWithoutPadding / RATIO);
if (widthWithoutPadding > maxWidth) {
width = maxWidth + getPaddingLeft() + getPaddingRight();
} else {
height = maxHeight + getPaddingTop() + getPaddingBottom();
}
setMeasuredDimension(width, height);
}
But the cam preview is compressed inside the frame layout how can i solve this ?issue ?
Update
Ok after some research got to know that its because of onMeasure
ASPECT_RATIO = 4:3
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = MeasureSpec.getSize(heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
if (width > height * ASPECT_RATIO) {
width = (int) (height * ASPECT_RATIO + 0.5);
} else {
height = (int) (width / ASPECT_RATIO + 0.5);
}
setMeasuredDimension(width, height);
}
Solution
So i was thinking of a solution, might be (just like Instagram does) to make your camera at full size and then hide some areas of the layout just to make it look like its 4:3 ratio.Then by using some crop mechanism have to cut the image to make the image look like 4:3.
Say i always show preview from top with 4:3 ratio and rest of the below part is hidden, so now as soon as i take photo i want to crop the image from top to 4:3 ratio and save it.
How can i achieve this, is this a feasible solution ?
As far as I understand, your current problem is how to crop the image you receive and show it. Here is a small example:
#OnClick(R.id.btn_record_start)
public void takePhoto() {
if (null != actions) {
EasyCamera.PictureCallback callback = new EasyCamera.PictureCallback() {
public void onPictureTaken(byte[] data, EasyCamera.CameraActions actions) {
// store picture
Bitmap bitmap = ImageUtils.getExifOrientedBitmap(data);
if ((portrait && bitmap.getHeight() < bitmap.getWidth()) ||
(!portrait && bitmap.getHeight() > bitmap.getWidth())) {
Matrix matrix = new Matrix();
matrix.postRotate(90);
bitmap =
Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
matrix, true);
}
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
if (Camera.CameraInfo.CAMERA_FACING_FRONT == info.facing) {
Matrix matrix = new Matrix();
matrix.postRotate(180);
bitmap =
Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
matrix, true);
}
showPhoto(bitmap);
}
};
actions.takePicture(EasyCamera.Callbacks.create()
.withJpegCallback(callback));
}
}
This is a method I'm using to handle image orientation after the photo is taken.
It can easily be modified to handle cropping too. To achieve this, you have to specify the target width and height of the image (currently I'm sending the whole bitmap's size). A possible solution is to take the image's height and delete the excessive width - so the params you send to the createBitmap method would be bitmap.getHeight() * 4.0 / 3.0 and bitmap.getHeight(). Here is the modified example:
#OnClick(R.id.btn_record_start)
public void takePhoto() {
if (null != actions) {
EasyCamera.PictureCallback callback = new EasyCamera.PictureCallback() {
public void onPictureTaken(byte[] data, EasyCamera.CameraActions actions) {
// store picture
Bitmap bitmap = ImageUtils.getExifOrientedBitmap(data);
if ((portrait && bitmap.getHeight() < bitmap.getWidth()) ||
(!portrait && bitmap.getHeight() > bitmap.getWidth())) {
Matrix matrix = new Matrix();
matrix.postRotate(90);
bitmap =
Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
matrix, true);
}
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
if (Camera.CameraInfo.CAMERA_FACING_FRONT == info.facing) {
Matrix matrix = new Matrix();
matrix.postRotate(180);
bitmap =
Bitmap.createBitmap(bitmap, 0, 0, (int) (bitmap.getHeight() * 4.0 / 3.0), bitmap.getHeight(),
matrix, true);
}
showPhoto(bitmap);
}
};
actions.takePicture(EasyCamera.Callbacks.create()
.withJpegCallback(callback));
}
}
A few things to note:
you can substitute the 4.0 / 3.0 part with the ASPECT_RATIO variable
my example is doing image rotation so it looks as it was during the preview, in your case the required UI might be different.
I'm using the EasyCamera library to simplify the camera management
Here are the other ImageUtils methods I'm using:
getExifOrientedBitmap
public static Bitmap getExifOrientedBitmap(byte[] data) {
File newPhotoFile = writeToFile(data);
if (newPhotoFile == null) {
return null;
}
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
bitmap = fixOrientationIfNeeded(newPhotoFile, bitmap);
newPhotoFile.delete();
return bitmap;
}
writeToFile
#Nullable
public static File writeToFile(byte[] data) {
File dir = PhotoMessageComposer.getPhotoDir();
if (!dir.exists()) {
dir.mkdir();
}
File newPhotoFile = new File(dir, ImageUtils.getRandomFilename());
FileOutputStream fos = null;
try
{
fos = new FileOutputStream(newPhotoFile);
fos.write(data);
fos.close();
} catch (Exception error) {
return null;
} finally {
try {
if (fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return newPhotoFile;
}
getPhotoDir
#NonNull
public static File getPhotoDir() {
return new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) +
PICTURES_DIR);
}
getRandomFileName
public static String getRandomFilename() {
return UUID.randomUUID().toString() + IMAGE_EXTENSION;
}
fixOrientationIfNeeded
public static Bitmap fixOrientationIfNeeded(File sourceFile, Bitmap source) {
ExifInterface exif;
try {
exif = new ExifInterface(sourceFile.getAbsolutePath());
int exifOrientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
if (exifOrientation != ExifInterface.ORIENTATION_NORMAL) {
Matrix matrix = new Matrix();
int angle = findRotationAngle(exifOrientation);
matrix.postRotate(angle);
source = Bitmap.createBitmap(source, 0, 0, source.getWidth(),
source.getHeight(), matrix, true);
return source;
}
} catch (IOException e) {
e.printStackTrace();
}
return source;
}
findRotationAngle
protected static int findRotationAngle(int exifOrientation) {
switch (exifOrientation) {
case ExifInterface.ORIENTATION_ROTATE_270:
return 270;
case ExifInterface.ORIENTATION_ROTATE_180:
return 180;
case ExifInterface.ORIENTATION_ROTATE_90:
return 90;
default:
return 0;
}
}
P.S. It has been a few years since this ImageUtils class was implemented, so probably there are better ways to handle some of these operations. They should be good enough for a starting point though.

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);

android camera preview wrong aspect ratio

i created a camera app based on tutorial. the preview class i use is from api-Demos "CameraPreview". I added a modification from here (preview was always rotated by 90°). So this is how i set preview size:
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// Now that the size is known, set up the camera parameters and begin
// the preview.
Camera.Parameters parameters = mCamera.getParameters();
Display display = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
if (display.getRotation() == Surface.ROTATION_0) {
parameters.setPreviewSize(mPreviewSize.height, mPreviewSize.width);
mCamera.setDisplayOrientation(90);
}
if (display.getRotation() == Surface.ROTATION_90) {
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
}
if (display.getRotation() == Surface.ROTATION_180) {
parameters.setPreviewSize(mPreviewSize.height, mPreviewSize.width);
}
if (display.getRotation() == Surface.ROTATION_270) {
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setDisplayOrientation(180);
}
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
mCamera.setParameters(parameters);
mCamera.startPreview();
}
But the Preview is displayed with wrong aspect ratio. Is it because of the code above or probably because of the layout i use?:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="#+id/button_capture"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="#string/capture" />
<FrameLayout
android:id="#+id/camera_preview"
android:layout_width="100dp"
android:layout_height="match_parent"/>
So how to get the correct aspect ratio? Thanks in advance.
P.S. i read the answer from: Android camera preview look strange
But this isn't working for me.
Try changing the preview sizes with adding this function:
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.05;
double targetRatio = (double) w/h;
if (sizes==null) return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
// Find 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);
}
}
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;
}
And the setting the sizes from these optimized values:
List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();
Camera.Size optimalSize = getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
parameters.setPreviewSize(optimalSize.width, optimalSize.height);
The following code modifies the width/height of the camera preview container to match the aspect ratio of the camera preview.
Camera.Size size = camera.getParameters().getPreviewSize();
//landscape
float ratio = (float)size.width/size.height;
//portrait
//float ratio = (float)size.height/size.width;
preview = (FrameLayout) findViewById(R.id.camera_preview);
int new_width=0, new_height=0;
if(preview.getWidth()/preview.getHeight()<ratio){
new_width = Math.round(preview.getHeight()*ratio);
new_height = cameraPreview.getHeight();
}else{
new_width = preview.getWidth();
new_height = Math.round(preview.getWidth()/ratio);
}
preview.setLayoutParams(new FrameLayout.LayoutParams(new_width, new_height));
Using the above solution, using the method private Size getOptimalPreviewSize(List sizes, int w, int h).
Worked fine! I was having problems with the aspect ratio on portrait orientation: Here it´s my solution using. Mixing it with android's documentation:
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.
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
Camera.Parameters params = mCamera.getParameters();
params.set("orientation", "portrait");
Size optimalSize=getOptimalPreviewSize(params.getSupportedPreviewSizes(), getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
params.setPreviewSize(optimalSize.width, optimalSize.height);
mCamera.setParameters(params);
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
problem is really in way you layout things.
there is overriden onLayout in Preview class. idea of its work is to set child SurfaceView size according to found optimal Size. but it doesn't take rotation into account, so you need to do it by yourself:
if (mPreviewSize != null) {
previewWidth = mPreviewSize.height;
previewHeight = mPreviewSize.width;
}
instead of
if (mPreviewSize != null) {
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
}
Trick is to swap width and height which is done because of 90 degree rotation achieved by
mCamera.setDisplayOrientation(90);
You might also consider forking child preview size setting depending on orientation that you set in
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
//...
}
(in provided by me code it is always for 90 degree rotation, for 180 you don't have to do anyhing and when you don't set any rotation, there is no need to swap width and height)
Another thing worth mentioning - when calculating getOptimalPreviewSize for case when you have rotation and you swap child width and height you also should pass parent(Preview) width and height swapped in onMeasure:
if (mSupportedPreviewSizes != null) {
//noinspection SuspiciousNameCombination
final int previewWidth = height;
//noinspection SuspiciousNameCombination
final int previewHeight = width;
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, previewWidth, previewHeight);
}
Henric's answer didn't work for me, so I've created another method which determines the optimal preview size for any camera given the target view current width and height and also the activity orientation:
public static Size getOptimalPreviewSize(List<Camera.Size> cameraPreviewSizes, int targetWidth, int targetHeight, boolean isActivityPortrait) {
if (CommonUtils.isEmpty(cameraPreviewSizes)) {
return null;
}
int optimalHeight = Integer.MIN_VALUE;
int optimalWidth = Integer.MIN_VALUE;
for (Camera.Size cameraPreviewSize : cameraPreviewSizes) {
boolean isCameraPreviewHeightBigger = cameraPreviewSize.height > cameraPreviewSize.width;
int actualCameraWidth = cameraPreviewSize.width;
int actualCameraHeight = cameraPreviewSize.height;
if (isActivityPortrait) {
if (!isCameraPreviewHeightBigger) {
int temp = cameraPreviewSize.width;
actualCameraWidth = cameraPreviewSize.height;
actualCameraHeight = temp;
}
} else {
if (isCameraPreviewHeightBigger) {
int temp = cameraPreviewSize.width;
actualCameraWidth = cameraPreviewSize.height;
actualCameraHeight = temp;
}
}
if (actualCameraWidth > targetWidth || actualCameraHeight > targetHeight) {
// finds only smaller preview sizes than target size
continue;
}
if (actualCameraWidth > optimalWidth && actualCameraHeight > optimalHeight) {
// finds only better sizes
optimalWidth = actualCameraWidth;
optimalHeight = actualCameraHeight;
}
}
Size optimalSize = null;
if (optimalHeight != Integer.MIN_VALUE && optimalWidth != Integer.MIN_VALUE) {
optimalSize = new Size(optimalWidth, optimalHeight);
}
return optimalSize;
}
This uses a custom Size object, because Android's Size is available after API 21.
public class Size {
private int width;
private int height;
public Size(int width, int height) {
this.width = width;
this.height = height;
}
public int getHeight() {
return height;
}
public int getWidth() {
return width;
}
}
You can determine the width and height of a view by listening for its global layout changes and then you can set the new dimensions. This also shows how to programmatically determine activity orientation:
cameraPreviewLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// gets called after layout has been done but before display.
cameraPreviewLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
boolean isActivityPortrait = getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
Size optimalCameraPreviewSize = CustomUtils.getOptimalPreviewSize(cameraPreview.getCameraSizes(), cameraPreviewLayout.getWidth(), cameraPreviewLayout.getHeight(), isActivityPortrait);
if (optimalCameraPreviewSize != null) {
LinearLayout.LayoutParams cameraPreviewLayoutParams = new LinearLayout.LayoutParams(optimalCameraPreviewSize.getWidth(), optimalCameraPreviewSize.getHeight());
cameraPreviewLayout.setLayoutParams(cameraPreviewLayoutParams);
}
}
});

Android camera preview look strange

I am implementing a camera app and when I look at the preview (especially with front camera), the image is very fat. It looks like the image get stretched horizontally. I follow the sdk sample with the optimzed camera size but it doesn't help. How can I adjust my camera setting so that it will preview like the other camera app?
Thanks.
My code is below.
public class CameraActivity extends Activity implements SurfaceHolder.Callback, Camera.ShutterCallback, Camera.PictureCallback {
Camera m_camera;
SurfaceView m_surfaceView;
int m_numOfCamera;
int m_defaultCameraId;
int m_currentCamera;
int m_surfaceWidth;
int m_surfaceHeight;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
getActionBar().setDisplayHomeAsUpEnabled(true);
m_surfaceView = (SurfaceView)findViewById(R.id.cameraPreview);
m_surfaceView.getHolder().addCallback(this);
m_camera = Camera.open();
m_numOfCamera = Camera.getNumberOfCameras();
CameraInfo cameraInfo = new CameraInfo();
for (int i = 0; i < m_numOfCamera; ++i) {
Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
m_defaultCameraId = i;
m_currentCamera = m_defaultCameraId;
}
}
if (m_numOfCamera < 1) {
MenuItem switchCam = (MenuItem)findViewById(R.id.menu_switch_camera);
switchCam.setVisible(false);
}
}
#Override
public void onPause() {
super.onPause();
m_camera.stopPreview();
}
#Override
public void onDestroy() {
super.onDestroy();
m_camera.release();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_camera, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(final MenuItem item)
{
if (item.getItemId() == android.R.id.home)
{
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
return true;
}
else if (item.getItemId() == R.id.menu_switch_camera)
{
if (m_camera != null) {
m_camera.stopPreview();
m_camera.release();
m_camera = null;
}
m_camera = Camera.open((m_currentCamera + 1) % m_numOfCamera);
m_currentCamera = (m_currentCamera + 1) % m_numOfCamera;
Camera.Parameters params = m_camera.getParameters();
List<Camera.Size> sizes = params.getSupportedPreviewSizes();
Camera.Size size = getOptimalPreviewSize(sizes, m_surfaceWidth, m_surfaceHeight);
params.setPreviewSize(size.width, size.height);
m_camera.setParameters(params);
setCameraDisplayOrientation(this, m_currentCamera, m_camera);
m_camera.startPreview();
try {
m_camera.setPreviewDisplay(m_surfaceView.getHolder());
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
return true;
}
public void onPictureTaken(byte[] arg0, Camera arg1) {
// TODO Auto-generated method stub
}
public void onShutter() {
// TODO Auto-generated method stub
}
public void surfaceChanged(SurfaceHolder arg0, int format, int w, int h) {
m_surfaceWidth = w;
m_surfaceHeight = h;
Camera.Parameters params = m_camera.getParameters();
List<Camera.Size> sizes = params.getSupportedPreviewSizes();
Camera.Size selected = getOptimalPreviewSize(sizes, w, h);
params.setPreviewSize(selected.width, selected.height);
m_camera.setParameters(params);
setCameraDisplayOrientation(this, m_currentCamera, m_camera);
m_camera.startPreview();
}
private static void setCameraDisplayOrientation(Activity activity,
int cameraId, android.hardware.Camera camera) {
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int rotation = activity.getWindowManager().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;
}
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;
}
camera.setDisplayOrientation(result);
}
public void surfaceCreated(SurfaceHolder arg0) {
try {
m_camera.setPreviewDisplay(m_surfaceView.getHolder());
} catch (Exception e) {
e.printStackTrace();
}
}
public void surfaceDestroyed(SurfaceHolder arg0) {
// TODO Auto-generated method stub
}
private Size getOptimalPreviewSize(List<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;
}
}
The camera preview always fills up the SurfaceView showing it. If the aspect ratio of m_surfaceView doesn't match with the camera's aspect ratio, the preview will be stretched.
You'll need to create m_surfaceView matching the aspect ratio. That means, you'll need to create it from code, not from layout XML file.
There is a sample project APIDemos that you'll find in android sample projects. In the project there is a thing named CameraPreview. This one has a good demonstration for setting up camera preview in a SurfaceView. It has a class that extends ViewGroup, and adds the SurfaceView as its child from the code. The onMeasure() method has been overridden to determine the height and width of the SurfaceView, so the aspect ratio is preserved. Take a look on the project, and I hope it will be clear.
[Sorry I couldn't post the link here - this is supposed to be the link, but I found it broken. But if you have installed the sample projects with the Android SDK, you can find the project in the samples. Open a new Android Sample Project, select APIDemos, then look for a class named CameraPreview. It should be in the package com.example.android.apis.graphics, as far as I remember.]
I changed onLayout method and not camera preview is not stretched. Rest of the thing are same like APiDemo which find here sdk/sample/adroid-18.The idea is we have only some supported size of preview but our view size may not always match with preview size. so i took larger preview size then my imageview size. it works for me. May help someone..
#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;
left = (width - scaledChildWidth) / 2;
top = 0;
right = (width + scaledChildWidth) / 2;
bottom = height;
child.layout(left, top, right, bottom);
} else {
final int scaledChildHeight = previewHeight * width
/ previewWidth;
left = 0;
top = (height - scaledChildHeight) / 2;
right = width;
bottom = (height + scaledChildHeight) / 2;
child.layout(left, top, right, bottom);
}
}
}
I have problem with too stretching camera preview.
It is too stretching at vertical and landscape mode.
So at manifest i added screenOrentation="Portrait",
but it did not help,still preview is rescaled at
any position (vertical - preview is to wide or
landscape is too long) you can
see this at screens.
I would like to add at Samsung ace III everything is fine but at LG Nexus 4 is stretching
package pl.probs.camera.component;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Point;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import pl.probs.lib.debug.L;
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "CameraPreview";
private static boolean showLogs = true;
private SurfaceHolder mHolder;
private Camera mCamera;
private Context context;
private Parameters resolution;
private List<Size> lSuportedPreviewSize;
private static int cOrientation = 0; // aktualny kat orientacji
private static boolean cOrientationChanged = false; // Stan orientacji
// zostal zmieniony
// wzgledem poprzedniego
private Display display; // Rozmiar ekranu
private Point displaySize; // Zmienna przechowuje Rozmiar Ekranu
private Point optimalPreviewSize;
public CameraPreview(Context context, Camera camera, int resolution) {
super(context);
this.optimalPreviewSize = new Point();
this.context = context;
this.mCamera = camera;
setDisplaySize(this.display);
setFocusable(true);
setFocusableInTouchMode(true);
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
this.resolution = getMinResolution(resolution);
this.optimalPreviewSize = getOptimalPreviewResolution(this.display);
Size s = mCamera.getParameters().getPreviewSize(); // Sprawdzenie jaki
// prewiev ustawiony
}
public Point getOptimalPreviewSize() {
return optimalPreviewSize;
}
public void surfaceCreated(SurfaceHolder holder) {
try {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.setPreviewDisplay(holder);
Size s = mCamera.getParameters().getPreviewSize();
mCamera.startPreview();
}
} catch (IOException e) {
L.d("Błąd ustawiania podglÄ…du: " + e.getMessage());
}
}
protected void onPause() {
// Because the Camera object is a shared resource, it's very
// important to release it when the activity is paused.
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
if (mCamera != null) {
mCamera.stopPreview();
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Camera.Parameters setPrevOrientation = mCamera.getParameters();
if (mHolder.getSurface() == null)
return;
try {
mCamera.stopPreview();
Size sizeBefore = mCamera.getParameters().getPreviewSize();
setPrevOrientation.setRotation(setCameraDisplayOrientation((Activity) context, getCameraId(), mCamera));
// Orientacja Portrait np 640x480 Landscape 480x640
this.resolution.setPreviewSize(this.optimalPreviewSize.x, this.optimalPreviewSize.y);
mCamera.setParameters(this.resolution);
Size sizeAfter = mCamera.getParameters().getPreviewSize();
} catch (RuntimeException e) {
L.d("Podgląd nie istnieje");
}
try {
mCamera.stopPreview();
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
L.d("błąd podgladu: " + e.getMessage());
}
}
#SuppressLint("ClickableViewAccessibility")
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mCamera.autoFocus(new AutoFocusCallback() {
#Override
public void onAutoFocus(boolean success, Camera camera) {
// do something
}
});
}
return true;
}
private static int setCameraDisplayOrientation(Activity activity, int cameraId, android.hardware.Camera camera) {
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int rotation = activity.getWindowManager().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;
}
cOrientation = degrees;
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;
}
camera.setDisplayOrientation(result);
return result;
}
private int getCameraId() {
int cameraId = -1;
int numberOfCameras = Camera.getNumberOfCameras();
for (int i = 0; i < numberOfCameras; i++) {
CameraInfo info = new CameraInfo();
Camera.getCameraInfo(i, info);
if (info.facing == CameraInfo.CAMERA_FACING_BACK) {
cameraId = i;
break;
}
}
return cameraId;
}
private Parameters getMinResolution(int desireResolutionInMpx) {
int height[], width[], size;
float megapixels;
Camera.Parameters p = mCamera.getParameters();
size = p.getSupportedPictureSizes().size();
height = new int[size];
width = new int[size];
for (int i = 0; i < size; i++) {
height[i] = p.getSupportedPictureSizes().get(i).height;
width[i] = p.getSupportedPictureSizes().get(i).width;
megapixels = (float) (((float) height[i] * (float) width[i]) / 1024000);
if (megapixels <= desireResolutionInMpx) {
p.setPictureSize(width[i], height[i]);
break;
}
}
return p;
}
private Point getOptimalPreviewResolution(Display displaySize) {
lSuportedPreviewSize = mCamera.getParameters().getSupportedPreviewSizes();
Point optimalPreviewSize = new Point();
int displayWidth = displaySize.getWidth(); // szerokosc ekranu
int displayHeight = displaySize.getHeight(); // wysokosc ekranu
int cameraHeight; // wspierana wysokosc kamery
int cameraWidth; // wspierana szerokosc kamery
// Lista przechowywujace SupportedPreviewSize kamery, wszyskie
// rozdzielczosci mniejsze od szerokosc i wysokosci ekranu
List<Point> lOptimalPoint = new ArrayList<Point>();
// Pomocniczo do listowania zawartosci listy
// TODO manta displayHeight cameraHeight brak oraz width brak zgodnosci
// (
System.out.println(lOptimalPoint.toString());
for (int i = 0; i < lSuportedPreviewSize.size(); i++) {
Log.i(TAG, "w " + lSuportedPreviewSize.get(i).width + " h " + lSuportedPreviewSize.get(i).height + " \n");
}
// Wyszukanie wszystkich wysokosci kamery mniejszej od wysokosci ekranu
for (int i = 0; i < lSuportedPreviewSize.size(); i++) {
// TODO Uwazaj kamera zapisuje swoj rozmiar dla pozycji landscape
// gdzie height = 480 a width = 800
cameraHeight = lSuportedPreviewSize.get(i).width;
cameraWidth = lSuportedPreviewSize.get(i).height;
// Porownaj wysokosc ekranu urzadzenia z wysokosci supportedPreview
// dodaj do listy
if (displayHeight > cameraHeight) {
lOptimalPoint.add(new Point(cameraHeight, cameraWidth));
}
}
// Sortowanie rosnaco
Collections.sort(lOptimalPoint, new ComapreSupportedPreviewByWidth());
// Ostatni element listy optymalny
optimalPreviewSize = lOptimalPoint.get(lOptimalPoint.size()-1);
// Zwracana rozdzielczosc landscape aparatu np (800x600)
return optimalPreviewSize;
}
private void setDisplaySize(Display display) {
Activity activity = (Activity) this.context; // Pobierz aktywnosc aby
// znać rozmiar ekranu
this.display = activity.getWindowManager().getDefaultDisplay();
}
class ComapreSupportedPreviewByWidth implements Comparator<Point> {
#Override
public int compare(Point lhs, Point rhs) {
return lhs.x - rhs.x;
}
}
}
Link to screens and project doing at eclipse
I already solved problem. What could cause problem with strange camera preview.
Status bar takes spaces - you can hide it Hiding the Status Bar
Some spaces also take TitleBar - you can turn off this at manifest
android:theme="#android:style/Theme.NoTitleBar">
Changed activity orientation to landscape "beacuse camera preview support that orientation" - you can check this at API demo Graphics->CameraPreview
algorithm that compares the size of Display.getWidth () Camera.getParameters size (). getSupportedPreviewSizes (); if they are the same is a function of surfaceChanged change Parametrs.setPreviewSize (x, y) you received when searching the list
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Camera.Parameters setPrevOrientation = mCamera.getParameters();
if (mHolder.getSurface() == null)
return;
try {
mCamera.stopPreview();
Size sizeBefore = mCamera.getParameters().getPreviewSize();
setPrevOrientation.setRotation(setCameraDisplayOrientation(
(Activity) context, getCameraId(), mCamera));
// Orientacja Portrait np 640x480 Landscape 480x640
this.resolution.setPreviewSize(this.optimalPreviewSize.x,
this.optimalPreviewSize.y);
mCamera.setParameters(this.resolution);
Size sizeAfter = mCamera.getParameters().getPreviewSize();
} catch (RuntimeException e) {
L.d("Podgląd nie istnieje");
}
try {
mCamera.stopPreview();
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
L.d("błąd podgladu: " + e.getMessage());
}
}
private Point getOptimalPreviewResolution(Display displaySize) {
lSuportedPreviewSize = mCamera.getParameters()
.getSupportedPreviewSizes();
Point optimalPreviewSize = new Point();
int displayWidth = displaySize.getWidth();
int displayHeight = displaySize.getHeight();
int cameraHeight;
int cameraWidth;
List<Point> lOptimalPoint = new ArrayList<Point>();
for (int i = 0; i < lSuportedPreviewSize.size(); i++) {
cameraHeight = lSuportedPreviewSize.get(i).width;
cameraWidth = lSuportedPreviewSize.get(i).height;
if (displayHeight >= cameraHeight) {
lOptimalPoint.add(new Point(cameraHeight, cameraWidth));
}
}
// Sort ascending
Collections.sort(lOptimalPoint,
new ComapreSupportedPreviewByWidth());
// Last element is optimal
optimalPreviewSize = lOptimalPoint.get(lOptimalPoint.size() - 1);
// Return resolution - camera at landscape mode (800x600)
return optimalPreviewSize;
}
class ComapreSupportedPreviewByWidth implements Comparator<Point> {
#Override
public int compare(Point lhs, Point rhs) {
return lhs.x - rhs.x;
}

How do you take high resolution images using Camera.takePicture()?

I'm implementing an in-app camera and every time I take a picture my image is 320x240, though my phone's camera is capable of much higher resolutions (Galaxy Nexus). I couldn't find a parameter for setting the resolution, so how do I up the resolution of images I am taking? Here's the relevant code:
#Override
public void surfaceCreated( SurfaceHolder holder ) {
setSurfaceHolder( holder );
}
#Override
public void surfaceDestroyed( SurfaceHolder holder ) {
setSurfaceHolder( null );
}
private void attachCameraToSurface( Camera camera, SurfaceHolder holder ) {
try {
camera.setPreviewDisplay( holder );
setInPreview( true );
}
catch (IOException e) {
Log.e( "CameraFragment", "Exception in attachCameraToSurface()", e );
}
}
#Override
public void surfaceChanged( SurfaceHolder holder, int format, int width, int height ) {
Camera camera = getCamera();
if ( camera == null ) {
return;
}
Camera.Size size = getCameraPreviewSize( camera );
Camera.Parameters params = camera.getParameters();
params.setPreviewSize( size.width, size.height );
camera.setParameters( params );
attachCameraToSurface( camera, holder );
startPreview();
}
private Camera.Size getCameraPreviewSize( Camera camera ) {
Camera.Parameters params = camera.getParameters();
List<Camera.Size> supportedSizes = params.getSupportedPreviewSizes();
Rect frame = getSurfaceHolder().getSurfaceFrame();
int width = frame.width();
int height = frame.height();
for (Camera.Size size : supportedSizes) {
if ( size.width >= width || size.height >= height ) {
return size;
}
}
return supportedSizes.get( 0 );
}
#Override
public void onClick( View v ) {
switch (v.getId()) {
case R.id.camera_action_ImageView:
getCamera().takePicture( getShutterCallback(), null, new JpegPictureCallback() );
break;
}
}
private class JpegPictureCallback implements PictureCallback {
#Override
public void onPictureTaken( byte[] data, Camera camera ) {
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeByteArray( data, 0, data.length );
}
catch (OutOfMemoryError e) {
Log.e( "CameraFragment", "Out of memory decoding image from camera.", e );
return;
}
data = null;
if ( bitmap != null ) {
new SavePictureWorker( getActivity() ).execute( bitmap );
}
startPreview();
}
}
Use params.setPictureSize(). See Camera.Parameters for more information.
Ensure that you call params.getSupportedPictureSizes() first to get an array of supported picture sizes. Then choose a size from the list and use the setPictureSize() method to set the desired size.
Camera.Parameters params = camera.getParameters();
List<Camera.Size> supportedSizes = params.getSupportedPictureSizes();
.
.
Camera.Size sizePicture = (one of the sizes from supportedSizes list);
.
params.setPictureSize(sizePicture.width, sizePicture.height);
Camera.Parameters param;
param = camera.getParameters();
Camera.Size bestSize = null;
List<Camera.Size> sizeList = camera.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);
}
}
List<Integer> supportedPreviewFormats = param.getSupportedPreviewFormats();
Iterator<Integer> supportedPreviewFormatsIterator = supportedPreviewFormats.iterator();
while(supportedPreviewFormatsIterator.hasNext()){
Integer previewFormat =supportedPreviewFormatsIterator.next();
if (previewFormat == ImageFormat.YV12) {
param.setPreviewFormat(previewFormat);
}
}
param.setPreviewSize(bestSize.width, bestSize.height);
param.setPictureSize(bestSize.width, bestSize.height);
camera.setParameters(param);
camera.takePicture(shutterCallback, rawCallback, jpegCallback);
Ensure that you call camera.getSupportedPictureSizes() first to get an array of supported picture sizes.
Actually it's params.getSupportedPictureSizes();
I think,
You can use setPictureSize (int width, int height). It is used to set the image dimensions in pixels.
Camera.Parameters parameters = camera.getParameters();
List<Camera.Size> sizes = parameters.getSupportedPictureSizes();
int w = 0, h = 0;
for (Camera.Size size : sizes) {
if (size.width > w || size.height > h) {
w = size.width;
h = size.height;
}
}
parameters.setPictureSize(w, h);

Categories

Resources