I want to get supported camera resolution preview size and aspected ratio in list view like i have shown in the pictures. Currently i am doing this which only show me a list of resolution width and height but i also want to show aspect ration.
public void find_camera_resolution()
{
Camera mCamera = Camera.open();
Camera.Parameters params = mCamera.getParameters();
List<Camera.Size> sizes = params.getSupportedPreviewSizes();
int widths[] = new int[params.getSupportedPreviewSizes().size()];
int heights[] = new int[params.getSupportedPictureSizes().size()];
Camera.Size mSize;
for (Camera.Size size : sizes) {
Toast.makeText(this,"Available resolution: "+widths.length+" "+size.height,Toast.LENGTH_LONG).show();
mSize = size;
}
}
But i want to show like this in the picture
The aspect ratio is just the the ratio of the resolution. So you (just) need to find the Greatest Common Divisor of width and height, divide the both values by the divisior and then you got your ratio.
For example 1600x720 -> GCD: 80 -> 1600/80=20, 720/80=9 -> aspect ratio: 20:9
There are a lot of existing algorithms to solve the Createst Common Divisor Problem and there existist already some implementations which you can use.
Sample source code are here:
int gcd=find_greatest_common_divisor_of_two_number(widths[i], heights[i]);
String ratio =(widths[i]/gcd)+":"+(heights[i]/gcd);
private static int find_greatest_common_divisor_of_two_number(int number1, int number2) {
//base case
if(number2 == 0){
return number1;
}
return find_greatest_common_divisor_of_two_number(number2, number1%number2);
}
Related
I have searched about fitting camera preview and surface view but I couldn't find about not stretching image while saving it in android studio.
The camera works well on showing on the surface view of the devices. The ratios of the supported screen sizes and surface view are ok.
The problem is that after capturing the image it takes more from all sides of the surface view of the screen. It just does not take the view that is shown on the surface view but more in all sides of the devices while saving the image.
The problem is only solved when height of the surface view and supported screen sizes are equal. Such as:
Supported size is:
1280/720
Surface view is:
405/720
But this leads to a problem which limits the height and width of the surface view. I want height of surface view to be longer and width to be match parent.
So, the problem is not solved without having the heights equal. I want height of the surface view to be longer and width to be match parent.
Can anyone help me with this,
Thanks everyone,
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "CameraPreview";
private Context mContext;
private SurfaceHolder mHolder;
private Camera mCamera;
private List<Camera.Size> mSupportedPreviewSizes;
private Camera.Size mPreviewSize;
public int measurewidth, measureheigh;
public CameraPreview(Context context, Camera camera) {
super(context);
mContext = context;
mCamera = camera;
// supported preview sizes
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
for(Camera.Size str: mSupportedPreviewSizes)
Log.e(TAG, str.width + "/" + str.height);
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
// empty. surfaceChanged will take care of stuff
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Log.e(TAG, "surfaceChanged => w=" + w + ", h=" + h);
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or reformatting changes here
// start preview with new settings
try {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width ,mPreviewSize.height); //B
// parameters.setPreviewSize(1280,720 );
mCamera.setParameters(parameters);
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
Log.e(TAG, "REAL SCREEN SIZE => w=" + width + ", h=" + height);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
Log.e(TAG, "MPREVIEW SIZE OPTIMAL => w=" + mPreviewSize.width + ", h=" + mPreviewSize.height);
float ratio;
if(mPreviewSize.height >= mPreviewSize.width)
ratio = (float) mPreviewSize.height / (float) mPreviewSize.width;
else
ratio = (float) mPreviewSize.width / (float) mPreviewSize.height;
Log.e(TAG, "Ration => R=" + ratio);
// One of these methods should be used, second method squishes preview slightly
//setMeasuredDimension(1080, 1200);
//setMeasuredDimension(mPreviewSize.height, mPreviewSize.width); //B
setMeasuredDimension(width, (int)(width*ratio)); //B
// setMeasuredDimension(720, 1280);
// setMeasuredDimension((int) (width ), height);
measurewidth = width ; // this is for bitmap width
measureheigh = (int)(width*ratio); // this is for bitmap height
}
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) { // long screen
final double ASPECT_TOLERANCE = 0.1;
double targetRatio=(double)h / w;
if (sizes == null) return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Camera.Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.width - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.width - targetHeight);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.width - targetHeight) < minDiff) {// size.height was changed with size.width
optimalSize = size;
minDiff = Math.abs(size.width - targetHeight); // size.height was changed with size.width
}
}
}
return optimalSize;
}
}
After checking through your code (and the problem you are facing), I have decided to not focus on the coding part. Instead, I will give you an overview of what's happening between a preview and a snap (take picture).
Overview
In legacy camera API, there are 2 very important Camera.Size that you would need to take care - preview size and picture size.
From Camera.Parameters API, you are able to get 2 separate list of supported sizes by calling Parameters.getSupportedPreviewSizes() and Parameters.getSupportedPicturSizes().
As the names imply, each size list is dedicated for different purpose - preview and take picture.
Sample case
Imagine you have the list like this:
Preview size: 1920x1080 (16:9), 1280x960 (4:3)
Picture size: 3840x2160 (16:9), 1920x1440 (4:3)
Say, you want to take a picture in 3840x2160 (16:9), you call Parameters.setPictureSize(3840, 2160) to tell the camera you want to take a picture in this resolution when you call takePicture(...).
Solve equation
Now, how are you going to show a preview with the same resolution on the screen (or viewfinder)?
Yes, you guessed it - a preview size with the same aspect ratio (AR).
We need to find out the AR of the (target) picture size and find a matching preview size with the same AR and call Parameters.setPreviewSize(width, height) when we are ready.
In our case, we will select the preview size 1920x1080 as it has the same AR (16:9) as the picture size.
Different AR?
What happened if you want to take a picture of 16:9 but is setting the preview size to 4:3?
The answer is obvious, user will not be able to snap a picture in WYSIWYG style.
Points to note
Selecting a picture size and deciding on the preview size is not really difficult. Still, there are more you need to take care of to use the camera properly.
The orientation of the camera (CameraInfo.orientation) as opposed to the device natural orientation. Remember to call `Parameters.setRotation(rotation) when necessary.
In cases where the camera supports the same resolution in different orientation (eg. 1920x1080 and 1080x1920), call `Parameters.setPreviewSize(width, height) with the orientation you wish to take the picture in.
Hope this helps.
I cannot help myself anymore, I have read every thread about this on stackoverflow, but nothing would fix my problem.
I try to set up my camera preview in a FrameLayout, everything works fine. I determine the correct size for the preview with this code:
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;
}
}
}
}
return (result);
}
Afterwards I apply it to my camera:
Camera.Parameters params = mCamera.getParameters();
Camera.Size size = getBestPreviewSize(width, height, params);
params.setPreviewSize(size.width, size.height);
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
mCamera.setParameters(params);
The Preview is still distorted afterwards, and my FrameLayout, which I expected to have the same size as the Preview Size I calculated, remains Fullscreen.
Fullscreen means 1920x1200
Preview Size means 1920x1080
So what I did is I set my Size of the FrameLayout manually to the calculated Preview Size. Then, however, my Preview looks even more skewed.
I have no idea what I am doing wrong. I thought when I use a supported Preview Size, this should not happen.
UPDATE:
I ran my application on another device, there everything works fine. Can this be a hardware bug? The device that is not working for me is the Nexus 7 Tablet.
I have finally come to a solution, this is really related to the hardware. There is a bug with some devices:
Bug-Report
The workaround:
This is a known low-level issue with some devices; they require that the still picture size and the preview size have matching aspect ratios, to avoid stretching artifacts.
If possible for your application, match the aspect ratios for setPreviewSize and setPictureSize.
Hope this helps you as well!
I have found out that when using a textureview instead of a surfaceview as a camera preview (both hooked up to the camera via a mediarecorder) then the preview is much more fuzzy.
What I mean by fuzzy is that in a texture view you can see the pixels, especially when zooming. That is not the case when using a surfaceview. Why is that the case?
UPD:
Sorry,but after I re-write my shit code, the key is the preview size too small that caused "fuzziness", so you should set a reasonable preview Size,not the reason strikeout below, but auto-focus is suggested ...
Size size = getBestSupportSize(parameters.getSupportedPreviewSizes(), width, height);
parameters.setPreviewSize(size.width, size.height);
As to the method getBestSupportSize(), how to get the bestSize for your project needs, in this case, it is as large as the screen width andhe ratio is 4/3 your's may be some other, I calculate the ration dividing width/height.
private Size getBestSupportSize(List<Size> sizes, int width, int height) {
Size bestsize = sizes.get(0);
int screenWidth = getResources().getDisplayMetrics().widthPixels;
int dt = Integer.MAX_VALUE;
for (int i = sizes.size() - 1; i >= 0; i--) {
Log.d(TAG, "-index : " + i);
Size s = sizes.get(i);
if (s.width * 3.0f / 4 == s.height) {
int newDT = Math.abs(screenWidth - s.width);
if (newDT < dt && screenWidth < s.width) {
dt = newDT;
bestsize = s;
}
}
}
return bestsize;//note that if no "4/3" size supported,default return size[0]
}
So this "fuzziness" was caused by a small previewSize calcualate a best size for the camera using this getSupportedPreviewSizes() method
And I will keep the autoFocus snippet below, strikeout though, FYR if is needed.
Well i got the solution for this "fuzzy" problem,and my case is just using TextureView andsurfaceTexture to take a pic instead of old surfaceView withsurfaceHolderway.
The key is set this mCamera.autofocus(), why the pic is"fuzzy" is bacause we lack of this autoFocus setting.
like below :
mCamera.setPreviewTexture(surface);
//enable autoFocus if moving
mCamera.setAutoFocusMoveCallback(new AutoFocusMoveCallback() {
#Override
public void onAutoFocusMoving(boolean start, Camera camera) {
if (start) { //true means you are moving the camera
mCamera.autoFocus(myAutoFocus);
}
}
});
mCamera.startPreview();
The autoFocusCallback like this:
AutoFocusCallback myAutoFocus = new AutoFocusCallback() {
#Override
public void onAutoFocus(boolean success, Camera camera) {
}
};
I searched for past two days and i was not successful yet .
I my case , i want to check the camera pixel resolution/Megapixels . If the camera's Mp is more than 4 then i need to re-size and upload .
Here is my code :
//to check the resolution
Camera mcamera ;
mcamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
Camera.Parameters param = mcamera.getParameters();
Camera.Size size = param.getPictureSize();
cam_height = size.height ;
cam_width = size.width ;
mcamera.release();
// my functionality
BitmapFactory.Options resample = new BitmapFactory.Options();
if(cam_height > pict_height || cam_width > pict_width )
resample.inSampleSize = 2; // whatever number seems appropriate 2 means 1/2 of the original
else
resample.inSampleSize = 1;
capturedimg = BitmapFactory.decodeFile(fileUri.getPath() , resample);
resized_uri = bitmaptouri(capturedimg);
but this returns only the picture resolution which is the same as the Screen resolution of the mobile but i want the Mobile camera's resolution .
Any related answers are welcomed , Thanks in advance .
How about getSupportedPictureSizes()?
First find height and width like below:
android.hardware.Camera.Parameters parameters = camera.getParameters();
android.hardware.Camera.Size size = parameters.getPictureSize();
int height = size.height;
int width = size.width;
then get mega pixel using below equation:
int mg = height * width / 1024000;
where mg is your mega pixels.
First check the supported picture sizes available for the Camera using Camera.Parameters. There is a function called getSupportedPictureSizes() in Camera Parameters.
For e.g:
List<Camera.Size> mList = mParams.getSupportedPictureSizes();
Camera.Size mSize = mList.get(mList.size() - 1);
From the mList you get all the supported Picture Sizes. The final one in the list will be the largest possible resolution.
Try the code from here. It returns resolution in mp for back camera. You should use getSupportedPictureSize instead of getPictureSize
https://stackoverflow.com/a/27000029/1554031
I am working on custom camera application for android. The problem is that the camera capture and showing preview good in other devices (example Samsung Galaxy S3) , but It shows distorted
image on Galaxy s4, Can any one help me??
My code for Picturesize() method is as follows:
Camera.Size getBestPicturSize(int width, int height, Camera.Parameters parameters) {
Camera.Size result=null;
float dr = Float.MAX_VALUE;
float ratio = (float)width/(float)height;
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
float r = (float)size.width/(float)size.height;
if( Math.abs(r - ratio) < dr && size.width <= width && size.height <= height ) {
dr = Math.abs(r - ratio);
result = size;
}
}
return result;
}
I had the same problem, if you mean that photos were taken with aspect ratio 4:3 and saved with aspect ratio 16:9 (they were outstretched). My problem was, that since I chose one of supported PictureSizes, I didn't do the same with the PreviewSizes.
Supported PictureSizes for Samsung G S4 are only with aspect ratio 16:9, however default PreviewSize was set to 1440x1080, which is 4:3. When I set both sizes with the same aspect ratio, picture was taken with no distortion.
Hope it will help.