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);
Related
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);
}
Hi I am working in custom camera. I used CameraPreview class from git. Everything works fine but problem is when i open camera from Activity A, it takes 4 seconds to open the camera. I am not getting any error. But getCameraInstance method calling takes long time to open the camera. How to reduce 4 seconds delay when opening the camera? I have clueless how to reduce the delay to go to TakePhotoFragment. Please help me to solve the issue
Here is CameraPreview:
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private Context mContext;
private Camera camera;
private SurfaceHolder surfaceHolder;
public List<Camera.Size> mSupportedPreviewSizes;
public Camera.Size mPreviewSize;
private static final String TAG = "CameraPreview";
public CameraPreview(Context context, Camera camera) {
super(context);
mContext = context;
this.camera = camera;
mSupportedPreviewSizes = camera.getParameters().getSupportedPreviewSizes();
for (Camera.Size str : mSupportedPreviewSizes)
Log.e(TAG, str.width + "/" + str.height);
surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try {
this.camera.setPreviewDisplay(surfaceHolder);
Camera.Parameters params = this.camera.getParameters();
List<Camera.Size> sizes = params.getSupportedPictureSizes();
Camera.Size mSize = null;
List<Camera.Size> psizes = params.getSupportedPreviewSizes();
Camera.Size pSize = null;
Collections.sort(sizes, new Comparator<Camera.Size>() {
#Override
public int compare(Camera.Size t1, Camera.Size t2) {
return t1.width >= t2.width ? -1 : 1;
}
});
Collections.sort(psizes, new Comparator<Camera.Size>() {
#Override
public int compare(Camera.Size t1, Camera.Size t2) {
return t1.width >= t2.width ? -1 : 1;
}
});
for (Camera.Size size :
sizes) {
if (size.width <= 1920) {
mSize = size;
break;
}
}
// for (Camera.Size size :
// psizes) {
// if (size.width == mSize.width) {
// pSize = size;
// break;
// }
// }
// if (pSize==null){
for (Camera.Size size :
psizes) {
if (size.width <= 1920) {
pSize = size;
break;
}
}
// }
Log.i("CAMERA", "Available resolution: " + mSize.width + " " + mSize.height);
Log.i("CAMERA", "Available resolution2: " + pSize.width + " " + pSize.height);
params.setPictureSize(mSize.width, mSize.height);
params.setPreviewSize(pSize.width, pSize.height);
this.camera.setParameters(params);
this.camera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, 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 (surfaceHolder.getSurface() == null) {
// preview surface does not exist
return;
}
// stop preview before making changes
try {
camera.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 = camera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
camera.setParameters(parameters);
camera.setDisplayOrientation(90);
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
} catch (Exception e) {
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
this.camera.stopPreview();
this.camera.release();
getHolder().removeCallback(this);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
float ratio;
if (mPreviewSize.height >= mPreviewSize.width)
ratio = (float) mPreviewSize.height / (float) mPreviewSize.width;
else
ratio = (float) mPreviewSize.width / (float) mPreviewSize.height;
// One of these methods should be used, second method squishes preview slightly
setMeasuredDimension(width, (int) (width * ratio));
// setMeasuredDimension((int) (width * ratio), height);
}
public 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.height / size.width;
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;
}
}
In CameraFragment:
public class TakePhotoFragment extends Fragment {
private Button camera;
private Button gallery;
private Camera mCamera;
private CameraPreview mCameraPreview;
private FrameLayout preview;
public static TakePhotoFragment newInstance() {
return new TakePhotoFragment();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.rr_take_photo, container, false);
camera = (Button) view.findViewById(R.id.button_capture);
gallery = (Button) view.findViewById(R.id.gallery);
mCamera = getCameraInstance();
mCameraPreview = new CameraPreview(getActivity(), mCamera);
preview = (FrameLayout) view.findViewById(R.id.camera_preview);
preview.addView(mCameraPreview);
camera.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
/* Intent intent = new Intent(getActivity(), PhotoActivity.class);
startActivity(intent);
getActivity().finish();*/
mCamera.takePicture(null, null, mPicture);
}
});
//this takes long time to open
private Camera getCameraInstance() {
Camera camera = null;
try {
camera = Camera.open();
} catch (Exception e) {
// cannot get camera or does not exist
}
return camera;
}
Camera.PictureCallback mPicture = new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = getOutputMediaFile();
Log.e("pictureFile",pictureFile.getAbsolutePath());
if (pictureFile == null) {
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
SharedPreferencesHelper.setStringItem("gallery_item", pictureFile.getAbsolutePath());
Intent intent = new Intent(getActivity(), PhotoActivity.class);
startActivity(intent);
getActivity().finish();
} catch (FileNotFoundException e) {
} catch (IOException e) {
}
}
};
private static File getOutputMediaFile() {
File mediaStorageDir = new File(
Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
"MyCameraApp");
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.d("MyCameraApp", "failed to create directory");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
.format(new Date());
File mediaFile;
mediaFile = new File(mediaStorageDir.getPath() + File.separator
+ "IMG_" + timeStamp + ".jpg");
Log.e("mediaFile",mediaStorageDir.getPath());
return mediaFile;
}
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>
I'm using a custom camera preview on my app, it works fine in almost all devices, for HTC-One I'm getting a bad cut, the original photo doesn't match what the preview shows on the top.
It only happens on this device, this is the code of my preview camera and the picture about what's going on.
Thanks in advance for any help someone can give me.
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private final String TAG = "CameraPreview";
private SurfaceHolder mHolder;
private Camera mCamera;
private Context context;
private Camera.Size mPreviewSize;
private List<Camera.Size> mSupportedPreviewSizes;
public CameraPreview(Context context) {
super(context);
this.context = context;
mHolder = getHolder();
mHolder.addCallback(this);
}
public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
for (Camera.Size str : mSupportedPreviewSizes) {
Log.e(TAG, str.width + "/" + str.height);
}
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
float ratio;
if (mPreviewSize.height >= mPreviewSize.width) {
ratio = (float) mPreviewSize.height / (float) mPreviewSize.width;
} else {
ratio = (float) mPreviewSize.width / (float) mPreviewSize.height;
}
setMeasuredDimension(width, (int) (width * ratio));
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
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);
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
mCamera.setParameters(parameters);
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
public void setFlash(String flashMode) {
Camera.Parameters params = mCamera.getParameters();
params.setFlashMode(flashMode);
mCamera.setParameters(params);
}
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;
for (Camera.Size size : sizes) {
double ratio = (double) size.height / size.width;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
continue;
if (Math.abs(size.height - h) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - h);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - h) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - h);
}
}
}
return optimalSize;
}
public void switchCamera(Camera camera) {
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
if (display.getRotation() == Surface.ROTATION_0) {
camera.setDisplayOrientation(90);
} else if (display.getRotation() == Surface.ROTATION_270) {
camera.setDisplayOrientation(180);
}
setCamera(camera);
try {
camera.setPreviewDisplay(mHolder);
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
}
}
Camera preview size and picture size are two different parameters, which you can update through setPictureSize() and setPreviewSize() APIs. But if user doesn't change these sizes, it will use default values.
In this case you are updating the preview size by calculating optimum preview size based on some aspect ratio. But you are not updating picture size, so it will be using default picture size.
If picture size and preview size aspect ratios are different, definitely the captured image looks different from preview. So update the picture size also by calculating optimum picture size with same aspect ratio as preview size.
I'm creating a camera app that implements it's own camera preview for taking pictures.
The app is currently forced into portrait mode.
My problem is that the preview from the camera is slightly stretched (the aspect ratio is a bit off).
The funny thing is that I'm setting my SurfaceView size to always match the preview size. This ensures that the aspect ratio should always be perserved... but it isn't...
Here is the layout i use to show my camera preview:
public class Cp extends ViewGroup implements SurfaceHolder.Callback {
private final String TAG = "CameraPreview";
private boolean mPreviewRunning = false;
private SurfaceView mSurfaceView;
private SurfaceHolder mHolder;
private Size mPreviewSize;
private List<Size> mSupportedPreviewSizes;
private Camera mCamera;
public boolean IsPreviewRunning() {
return mPreviewRunning;
}
public Cp(Context context) {
this(context, null, 0);
}
public Cp(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public Cp(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mSurfaceView = new SurfaceView(context);
addView(mSurfaceView);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
requestLayout();
}
}
public void switchCamera(Camera camera) {
setCamera(camera);
try {
camera.setPreviewDisplay(mHolder);
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
camera.setParameters(parameters);
}
#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 && 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.height;
previewHeight = mPreviewSize.width;
}
if (previewWidth == 0) {
previewWidth = 1;
}
if (previewHeight == 0) {
previewHeight = 1;
}
// 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);
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, acquire the camera and tell it where to
// draw.
try {
if (mCamera != null) {
Parameters params = mCamera.getParameters();
mSupportedPreviewSizes = params.getSupportedPreviewSizes();
mCamera.setPreviewDisplay(holder);
}
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
stop();
}
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;
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if (mCamera != null) {
// Now that the size is known, set up the camera parameters and
// begin the preview.
Camera.Parameters parameters = mCamera.getParameters();
if (mPreviewSize != null) {
parameters.setPreviewSize(mPreviewSize.width,
mPreviewSize.height);
}
requestLayout();
mCamera.setParameters(parameters);
mCamera.startPreview();
mPreviewRunning = true;
}
}
public void stop() {
if (mCamera != null) {
mCamera.stopPreview();
mPreviewRunning = false;
mCamera = null;
}
}
}
Please note that in onLayout width and height are swapped because the app is always running in portrait.
I'm including some pictures to show you what the problem looks like:
I've debugged the code. The preview size is being set to 1280x720 and the size of the layout is also being correctly adjusted to match that size.
I've also tried different layouts but the result was always the same...
I was having the same problem, after some days in this puzzle, my Java class end up on this code:
So, The problem was happening because the camera display had a size (hight x width) 576x720, and my display was 1184x720. So, the camera preview (my surface view class) stretched to fill in the parent.
So, the approach that worked is to make this view bigger than my screen, and that just display the area of my screen. So, I had to use this weird frame combination (a relative layout inside a linearlayout), so that the size of the relative will be as big as I want - the surface view will fill in it -, and the linear will take just the part that I wanna display.
package com.example.frame.camera;
import android.content.Context;
import android.hardware.Camera;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup.LayoutParams;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Toast;
import com.example.frame.MainActivity;
public class NativeCamera extends SurfaceView implements SurfaceHolder.Callback {
static private NativeCamera instance;
private LinearLayout frame = null;
private RelativeLayout innerFrame = null;
private Camera camera;
private final SurfaceHolder previewHolder;
private static final String TAG = "NativeCamera.java";
private boolean inPreview = false;
private boolean cameraConfigured = false;
private boolean frontCamera = false;
private Camera.Size size;
static public NativeCamera getInstance() {
if (NativeCamera.instance == null) {
if (MainActivity.debug) {
Log.d(TAG, "Creating Camera Singleton");
}
NativeCamera.instance = new NativeCamera(MainActivity.instance);
}
return NativeCamera.instance;
}
public void onResume() {
if (MainActivity.debug) {
Log.d(TAG, "onResume");
}
camera = Camera.open();
if (size != null) {
initPreview(size.width, size.height);
}
startPreview();
}
public void onPause() {
if (MainActivity.debug) {
Log.d(TAG, "onPause");
}
if (inPreview) {
camera.stopPreview();
}
camera.release();
camera = null;
inPreview = false;
}
public void onDestroy() {
if (MainActivity.debug) {
Log.d(TAG, "onDestroy");
}
NativeCamera.instance = null;
}
public void onSwitch() {
frontCamera = !frontCamera;
if (inPreview) {
camera.stopPreview();
}
camera.release();
int cam = frontCamera ? 1 : 0;
camera = Camera.open(cam);
if (size != null) {
initPreview(size.width, size.height);
}
startPreview();
}
private NativeCamera(Context context) {
super(context);
// TODO Auto-generated constructor stub
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
previewHolder = getHolder();
previewHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
// previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
innerFrame = new RelativeLayout(MainActivity.instance);
innerFrame.addView(this);
frame = new LinearLayout(MainActivity.instance);
frame.addView(innerFrame);
}
public LinearLayout getFrame() {
return frame;
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
if (MainActivity.debug) {
Log.d(TAG, "surfaceChanged");
}
initPreview(width, height);
startPreview();
}
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
// no-op -- wait until surfaceChanged()
}
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
// no-op
}
private Camera.Size getBestPreviewSize(int width, int height,
Camera.Parameters parameters) {
Camera.Size result = null;
for (Camera.Size size : parameters.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;
}
}
}
}
this.size = result;
return (result);
}
private void initPreview(int width, int height) {
if (camera != null && previewHolder.getSurface() != null) {
if (!cameraConfigured) {
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = getBestPreviewSize(width, height, parameters);
if (size != null) {
parameters.setPreviewSize(size.width, size.height);
camera.setParameters(parameters);
cameraConfigured = true;
// Setting up correctly the view
double ratio = size.height / (double) size.width;
LayoutParams params = innerFrame.getLayoutParams();
params.height = MainActivity.size.y;
params.width = (int) (MainActivity.size.y * ratio);
innerFrame.setLayoutParams(params);
int deslocationX = (int) (params.width / 2.0 - MainActivity.size.x / 2.0);
innerFrame.animate().translationX(-deslocationX);
}
}
try {
camera.setPreviewDisplay(previewHolder);
camera.setDisplayOrientation(90);
} catch (Throwable t) {
Log.e(TAG, "Exception in setPreviewDisplay()", t);
Toast.makeText(MainActivity.instance, t.getMessage(), Toast.LENGTH_LONG).show();
}
}
}
private void startPreview() {
if (MainActivity.debug) {
Log.d(TAG, "startPreview");
}
if (cameraConfigured && camera != null) {
camera.startPreview();
inPreview = true;
}
}
}
I have been trying to solve the same issue... Below code worked for me:
private void setMyPreviewSize(int width, int height) {
// Get the set dimensions
float newProportion = (float) width / (float) height;
// Get the width of the screen
int screenWidth = getWindowManager().getDefaultDisplay().getWidth();
int screenHeight = getWindowManager().getDefaultDisplay().getHeight();
float screenProportion = (float) screenWidth / (float) screenHeight;
// Get the SurfaceView layout parameters
android.view.ViewGroup.LayoutParams lp = surfaceView.getLayoutParams();
if (newProportion > screenProportion) {
lp.width = screenWidth;
lp.height = (int) ((float) screenWidth / newProportion );
} else {
lp.width = (int) (newProportion * (float) screenHeight);
lp.height = screenHeight;
}
// Commit the layout parameters
surfaceView.setLayoutParams(lp);
}
You can see the thread: Resizing surface view for aspect ratio change in video display in android
Here's a solution
surfaceChanged is just to get the best preview size
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.e("MYTAG", "surfaceChanged " );
Camera.Parameters myParameters = camera.getParameters();
Camera.Size myBestSize = getBestPreviewSize(width, height, myParameters);
if(myBestSize != null){
myParameters.setPreviewSize(myBestSize.width, myBestSize.height);
camera.setParameters(myParameters);
camera.startPreview();
}
}
#Override
public void onPictureTaken(byte[] data, Camera camera) {
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
imageReview.setImageBitmap(bitmap);
}
This will set the captured image on imageReview, but you need a method to get the rotation of the bitmap
you need to set imageView scaleType attribute for stretched image issue
<ImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
/>