I am using this camera preview application for my Android app.
I want the camera preview over the full screen.Hence I used the example from Android APIs to try setting the preview to full screen. This is how I am trying to do it:
if (!cameraConfigured) {
Camera.Parameters parameters=camera.getParameters();
Camera.Size size = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
if (size != null) {
parameters.setPreviewSize(size.width, size.height);
camera.setParameters(parameters);
cameraConfigured=true;
}
I am using relative layout as my layout. My layout settings are follows:
<android.view.SurfaceView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/preview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
I am still not able to preview my camera over the entire screen. I would like to know how to preview over the entire screen.
I found the problem. I added the following setting to Android Manifest file
<supports-screens android:largeScreens="true"
android:normalScreens="true"
android:smallScreens="true" android:xlargeScreens="true"/>
I am able to view the camera over full screen.
Im assuming your code is within a class that extends SurfaceView and that you will place the surfaceView inside a FrameLayout that is as large as the display.
What you are not doing in your code is setting your SurfaceView to be the same size as the display which in the following code block is done by getting the layout, and setting the width and height.
I use the following code to stretch to the dimensions of the screen:
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
...
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
...
final DisplayMetrics dm = this.getResources().getDisplayMetrics();
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(cameraSize.width, cameraSize.height);
mCamera.setParameters(parameters);
//Here you get the SurfaceView layout and subsequently set its width and height
FrameLayout.LayoutParams frameParams = (FrameLayout.LayoutParams) this.getLayoutParams();
frameParams.width = LayoutParams.MATCH_PARENT;// dm.widthPixels should also work
frameParams.height = LayoutParams.MATCH_PARENT;//dm.heightPixels should also work
this.setLayoutParams(frameParams);
//And we should have things set now...
....
}
...
}
I hope this helps. The key parts to integrate are between those inner comments
Get dimensions of the screen
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int height = displayMetrics.heightPixels;
int width = displayMetrics.widthPixels;
use this width and height to get preview size.
First, get the display width and height:
int dw = currentDisplay.getWidth(); // dw == display width
int dh = currentDisplay.getHeight(); // dh == display height
Then loop through the supported preview sizes, and pick the largest one where, if
(size.width <= dw && size.height <= dh). When you hit one where this if statement
fails, use the previous values (you could set something like prevWidth and prevHeight
as a quick/easy way to step back one ... just remember to set each of those AFTER
you test them; after you hit a preview size that's larger than screen size, just
break out of the loop.
Later,
--jim
Related
Following are the screenshots when using texture view in camera2 apis.In full screen the preview stretches,but it works when using lower resolution(second image).
How to use this preview in full screen without stretching it.
Below answer assumes you are in portrait mode only.
Your question is
How to use the preview in full-screen without stretching it
Let's break it down to 2 things:
You want the preview to fill the screen
The preview cannot be distorted
First you need to know that this is logically impossible without crop, if your device's viewport has a different aspect ratio with any available resolution the camera provides.
So I would assume you accept cropping the preview.
Step 1: Get a list of available resolutions
StreamConfigurationMap map = mCameraCharacteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (map == null) {
throw new IllegalStateException("Failed to get configuration map: " + mCameraId);
}
Size[] sizes = map.getOutputSizes(SurfaceTexture.class);
Now you get a list of available resolutions (Sizes) of your device's camera.
Step 2: Find the best aspect ratio
The idea is to loop the sizes and see which one best fits. You probably need to write your own implementation of "best fits".
I am not going to provide any code here since what I have is quite different from your use case. But ideally, it should be something like this:
Size findBestSize (Size[] sizes) {
//Logic goes here
}
Step 3: Tell the Camera API that you want to use this size
//...
textureView.setBufferSize(bestSize.getWidth(), bestSize.getHeight());
Surface surface = textureView.getSurface();
try {
mPreviewRequestBuilder = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mPreviewRequestBuilder.addTarget(surface);
mCamera.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
mSessionCallback, null);
} catch (final Exception e) {
//...
}
Step 4: Make your preview extends beyond your viewport
This is then nothing related to the Camera2 API. We "crop" the preview by letting the SurfaceView / TextureView extends beyond device's viewport.
First place your SurfaceView or TextureView in a RelativeLayout.
Use the below to extend it beyond the screen, after you get the aspect ratio from step 2.
Note that in this case you probably need to know this aspect ratio before you even start the camera.
//Suppose this value is obtained from Step 2.
//I simply test here by hardcoding a 3:4 aspect ratio, where my phone has a thinner aspect ratio.
float cameraAspectRatio = (float) 0.75;
//Preparation
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int screenWidth = metrics.widthPixels;
int screenHeight = metrics.heightPixels;
int finalWidth = screenWidth;
int finalHeight = screenHeight;
int widthDifference = 0;
int heightDifference = 0;
float screenAspectRatio = (float) screenWidth / screenHeight;
//Determines whether we crop width or crop height
if (screenAspectRatio > cameraAspectRatio) { //Keep width crop height
finalHeight = (int) (screenWidth / cameraAspectRatio);
heightDifference = finalHeight - screenHeight;
} else { //Keep height crop width
finalWidth = (int) (screenHeight * cameraAspectRatio);
widthDifference = finalWidth - screenWidth;
}
//Apply the result to the Preview
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) cameraView.getLayoutParams();
lp.width = finalWidth;
lp.height = finalHeight;
//Below 2 lines are to center the preview, since cropping default occurs at the right and bottom
lp.leftMargin = - (widthDifference / 2);
lp.topMargin = - (heightDifference / 2);
cameraView.setLayoutParams(lp);
If you don't care about the result of Step 2, you can actually ignore Step 1 to Step 3 and simply use a library out there, as long as you can configure its aspect ratio. (It looks like this one is the best, but I haven't tried yet)
I have tested using my forked library. Without modifying any code of my library, I managed to make the preview fullscreen just by using Step 4:
Before using Step 4:
After using Step 4:
And the preview just after taking a photo will not distort as well, because the preview is also extending beyond your screen.
But the output image will include area that you cannot see in the preview, which makes perfect sense.
The code of Step 1 to Step 3 are generally referenced from Google's CameraView.
That's a common problem on some devices. I've noticed it mostly on samsung. You may use a trick with setting transformation on your TextureView to make it centerCrop like ImageView behaviour
I also faced similar situation, but this one line solved my problem
view_finder.preferredImplementationMode = PreviewView.ImplementationMode.TEXTURE_VIEW
in your xml:
<androidx.camera.view.PreviewView
android:id="#+id/view_finder"
android:layout_width="match_parent"
android:layout_height="match_parent" />
For camera implementation using cameraX you can refer
https://github.com/android/camera-samples/tree/master/CameraXBasic
I figured out what was your poroblem. You were probably trying something like this:
textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int j) {
cam.startPreview(surfaceTexture, i, j);
cam.takePicture();
}
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) { }
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { return false; }
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { }
});
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'm building an app for Android but The device do have a square screen. The screen is 320x320 and the camera app use the SurfaceView to show the preview as below :
mCameraView = (SurfaceView) findViewById(R.id.surface);
LayoutParams params = mCameraView.getLayoutParams();
int camera_dimension = getResources().getInteger(R.integer.camera_dimension);
params.height = camera_dimension; //320px
params.width = camera_dimension;
mCameraView.setLayoutParams(params);
mCameraViewHolder = mCameraView.getHolder();
mCameraViewHolder.addCallback(this);
mCameraViewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
On Surface changed, I'm doing this and it works but the supporter preview is w480 x h320
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
int mWidth = w;
int mHeight = h;
int mFormat = format;
try {
mCameraAccess.mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
Camera.Parameters param = mCameraAccess.mCamera.getParameters();
List<Camera.Size> SupportedPreview = param.getSupportedPreviewSizes();
int ScreenSize = getResources().getInteger(R.integer.camera_dimension);
for (int i = 0; i < SupportedPreview.size(); i++) {
if (SupportedPreview.get(i).height == ScreenSize) {
param.setPreviewSize(SupportedPreview.get(i).width, SupportedPreview.get(i).height);
break;
}
}
mCameraAccess.mCamera.setParameters(param);
mCameraAccess.mCamera.startPreview();
}
How can make sure that my preview inside the viewholder is not compressed but a kind of centercrop. As the preview is a rectangle, I just need the square centered on the image. Usually I'm using scaleType but it's not supported in Surface view
Any idea ?
The solution which i have figured out is:
1)-Keep surface view full screen,so that is doesn't stretch.
2)-Put a view over surfaceview with full opacity.So that is looks like camera is already squared.
3)-After capturing image or video,you will have to crop them.
For video you have to use some video processing library like javacv.Using this library you can extract video frames,convert them to bitmap,crop bitmap in square and then re-encode into video.
To get accurate results you will need to play around with different techniques like zooming camera during capture etc. according to your needs.
Original Image:
Squared Image:
I want to set scrollable wallpaper on homescreen but my wallpaper gets center crop automatically.
The images i am using are in ratio "3:2/ 16:9" so i want them to get spread uniformly on multiple pages of homescreen.
I am currently using:
wallpaperManager.suggestDesiredDimensions(width, height);
wallPaperBitmap = BitmapFactory.
decodeStream(url);
wallpaperManager.setBitmap(wallPaperBitmap);
`
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21"/>
Got the help from androidhive.com
//get screen height
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
screenHeight = size.y;
wallPaperBitmap= ... //your bitmap resource
//adjust the aspect ratio of the Image
//this is the main part
int width = wallPaperBitmap.getWidth();
width = (width * screenHeight) / wallPaperBitmap.getHeight();
//set the wallpaper
//this may not be the most efficent way but it works
wallpaperManager.setBitmap(Bitmap.createScaledBitmap(wallPaperBitmap, width, height, true));
Hi i want to fit my app to all screen sizes and to do so i need to get the screen width and height.
but if i use this code for example
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int height = displaymetrics.heightPixels;
int width = displaymetrics.widthPixels
It gives me the pixels so there can happen a situation that it gives me the same dimentions for tablet and a smaller phone.
how can i get the actual screen size?
and another thing, i have a game i made with bitmaps and on my phone it is working fine but on tablet the bitmaps are too small how can i resize them according to screen size?
You need screen density and pixel size. (Number of pixels) / (dots per inch) gives screen size in inches.
See: getting the screen density programmatically in android?
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int height = displaymetrics.heightPixels;
int width = displaymetrics.widthPixels
int realWidth = (int)((float)width/metrics.density);
int realHeight = (int((float)height/metrics.density);
Answer to the second question depends on how are you loading your bitmaps. You should provide multiple sizes for different devices. Then you can use built-in scaling mechanism - simply place bitmaps in their matching drawable-(dpi)-(screen size) folders. Other way you would have to load images from assets folder and scale them if necessary.
For your 2nd problem of bitmap appearing too small on tablet, try to nine patch your image and then place those images in their respective folders (hdpi, mdpi, xhdpi, xxhdpi)
Make sure you use the high quality resolution image for nine patching otherwise your image will get stretch (poor quality).
You can nine patch your image from here also nine patching image
try this:
Display display = activity.getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
You can get screen dimensions with this code:
public int getScreenHeight() {
return getDisplay().getHeight();
}
private Display getDisplay() {
return ((WindowManager) getContext().getSystemService(
Context.WINDOW_SERVICE)).getDefaultDisplay();
}
public int getScreenWidth() {
return getDisplay().getWidth();
}
Try this.
Add this to onCreate() Method. Declare point!
WindowManager wm = ((WindowManager) getSystemService(WINDOW_SERVICE));
Display display = wm.getDefaultDisplay();
point = getDisplaySize(display);
//here is the method to get device size.
#Deprecated
#SuppressLint("NewApi")
private static Point getDisplaySize(final Display display) {
final Point point = new Point();
try {
display.getSize(point);
} catch (java.lang.NoSuchMethodError ignore) { // Older device
point.x = display.getWidth();
point.y = display.getHeight();
}
return point;
}