I am working on an Android app that uses the phone's camera and I'm using a custom code.
The problem is that the image is showing in the preview is not correct (the image aspect ratio is not OK).
If I use the following code:
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Camera.Parameters params = mCamera.getParameters();
List<Camera.Size> sizes = params.getSupportedPreviewSizes();
Camera.Size selected = sizes.get(0);
params.setPreviewSize(selected.width,selected.height);
mCamera.setParameters(params);
mCamera.startPreview();
the preview image is OK (I think little part of the image top and bottom is not showed).
The problem then is that the captured image showed after takePicture method is called is not showed correctly (the image aspect ratio is not OK, the image appears to be compressed into the view), even so if I save the picture to a file image appears to be OK.
I wonder if it is possible to show the image correctly in both cases. Suggestions?
The solution was easy, but I didn't know I must set correct aspect ratio MANUALLY (it is not an automatic process, I supposed it was and this step it is not explained in most how to's). Finally, I solved it this way:
Getting supported sizes using params.getSupportedPreviewSizes() and params.getSuppertedPictureSize().
Computing the best aspect ratio (width/height) according to the measures width and height passed in surfaceChanged(SurfaceHolder holder, int format, int width, int height).
Setting the best preview size and picture size using setPreviewSizeand setPictureSize, respectively, before startPreview() method is called.
If you saved the image and it appears correctly, the problem isn't the image being taken, it's how you're displaying it back to the user. If you're using an ImageView, make sure you're using src (not background), as src will keep the aspect ratio, but background will stretch and distort the image to fill the background. Likewise, you can set android:adjustViewBounds="true" to have the ImageView adjust its boundaries to preserve the aspect ratio.
Related
On my Moto E, I want my preview to be full screen hence i have set the texture view's dimension to be full screen i.e. 540*960by overriding onMeasure, but using camera2 api the closest match of preview size that i am getting is 768*432 which is of the same aspect ratio. Google sample suggests that "Initially, output stream images from the Camera2 API will be rotated to the native device orientation from the sensor's orientation, and the TextureView will default to scaling these buffers to fill it's view bounds. If the aspect ratios and relative orientations are correct, this is fine." But even when in native orientation I am getting stretched previews. Even if I setTransform to Identity matrix, I don't know how the preview is still scaled automatically to fill the whole screen.
I also encountered this problem and solved it like this:
re-set surfaceview params (width and heigth).
ViewTreeObserver observer = mSurfaceView.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener()
{
#Override
public void onGlobalLayout()
{
FrameLayout.LayoutParams surfaceParams = (FrameLayout.LayoutParams) mSurfaceView.getLayoutParams();
surfaceParams.height = screenHeight;
surfaceParams.width = screenWidth;
mSurfaceView.setLayoutParams(surfaceParams);
mSurfaceView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});
I am using the Intel Inde library for media (specifically this example: https://github.com/INDExOS/media-for-mobile/blob/master/Android/samples/apps/src/com/intel/inde/mp/samples/CameraCapturerActivity.java)
My goal is to set up a full screen preview in portrait mode and record videos in portrait mode. Everything works great in landscape mode(full screen preview and recording). However in portrait mode I can't stretch the preview to fill the screen vertically (even though I set the surface view to max size). The largest size I get is a square image preview. I have tried making the surface view larger then the screen, but still stuck with a square preview and recording.
This is what my preview screen currently looks like:
http://imgur.com/XUznvF1
Here is my code:
public void createCamera()
{
Camera camera = Camera.open();
Camera.Parameters parameters = camera.getParameters();
List<Camera.Size> supportedResolutions = camera.getParameters().getSupportedPreviewSizes();
parameters.setPreviewSize(supportedResolutions.get(0).width,
supportedResolutions.get(0).height);
camera.setDisplayOrientation(90);
camera.setParameters(parameters);
}
public void createPreview()
{
GLSurfaceView surfaceView = new GLSurfaceView(getActivity().getApplicationContext());
//This code is used to get display size to set surface view size
Display display = getActivity().getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
surfaceView.setLayoutParams(new FrameLayout.LayoutParams(width, height));
//Used to test that the surfaceview does cover the whole screen
//surfaceView.setBackgroundColor(Color.RED);
((RelativeLayout)view.findViewById(R.id.myview)).addView(surfaceView, 0);
preview = capture.createPreview(surfaceView, camera);
preview.start();
}
There is a thread on the Intel Developer site, appears to be the same issue. They have a solution, but you have to request the library update via email:
https://software.intel.com/en-us/forums/topic/542633
I think your problem is that you are setting the preview size of your camera to the first size in the list of supported sizes.
List<Camera.Size> supportedResolutions = camera.getParameters().getSupportedPreviewSizes();
parameters.setPreviewSize(supportedResolutions.get(0).width, supportedResolutions.get(0).height);
What you should do is loop through the list of supported sizes and find a size that closely matches the screen's size/resolution.
You can check this SO answer for sample code snippets
Update
The next step would be to debug it and find out why it didn't work for you. What I would do in your case would be to print out the contents of the supportedResolutions list. Since you already the have the display size, I would compare the display size to the different sizes in the supportedResolutions list and also to the size returned from the getOptimalSize method. It's possible that the getOptimalSize method didn't find an optimal size and the method may need to be tweaked to your need. I tweaked mine to get it to work.
Let me know if you need more help.
In my app each of the screens has a background image. I want to use the same image for portrait and landscape, but to make it look decent I need to rotate the image 90 degrees when in landscape so that it does not get stretched to fill the screen.
My solution was to just create two copies of the image one for portrait that I put in drawable-port and one for landscape that I put in drawable-land. Now that I have many different backgrounds my solution of just embedding a second copy of the image in my apk is causing the apk size to be much larger then needed.
How can I support rotated images, preferably in pure XML. In code I suppose you could just rotate the image before onStart and it would work, but I would really rather keep it in the XML if possible.
Thanks for the help!
I can't think of a way to do this in XML. But if you created a custom class that inherited from whichever view you're applying the background to (say, RelativeLayout), then you could do something like
#Override
protected void onSizeChanged(int newWidth, int newHeight, int oldWidth, int oldHeight) {
if (newWidth > newHeight) { // landscape
// rotate the background
}
}
This way, you only have to implement the rotation once and all of your views would auto-rotate their backgrounds.
At the moment I have a FrameLayout which will hold a preview of a picture taken. The size of this is determined in the layout xml file I created for it, at the moment its just set to fill_parent. However the image taken is at 4:3 aspect ratio, but this isn't always going to be the right aspect ratio for the users screen.
For example with my Xperia X10 which is 480 X 854, the 4:3 image taken by the camera always stretches to fit the FrameLayout.
What I want to do is change the size of the FrameLayout outside of the XML file so that it is 4:3 and a size appropriate for the users screen size. Any ideas?
I guess you are using an ImageView inside your FrameLayout to display the actual picture? In this case, use scaleType to define how the picture should be stretched.
You can set that in your XML, just use android:scaleType=".." inside your ImageView tag.
Framelayout.LayoutParams lp = new LinearLayout.LayoutParams(width, height);
lv.setLayoutParams(lp);
Try using the above code...
My Android app (a text-based game) uses background images a lot in order to provide a better visual ambiance. For example, if the action in the game takes you into a tavern, then you get a background image of a tavern in the game. This is a vast improvement, graphically, over the boring black background that you would otherwise get.
It is also a problem, however, since android:background always stretches to the dimensions of the screen. The result is that the background images look very bad if the player switches between portrait and landscape mode. And to make matters worse, many devices have very different aspect ratios (e.g., 320x480 mdpi, 480x800 hdpi, and 480x852 hdpi) and even more variations are coming.
How do others solve this problem? Having individual images for the main resolutions/orientations is not an option for me, as this would result in the apk growing too large.
The first step is to get the screen height and width of the device itself, then stretch/shrink or pad your bitmap as needed. This SO answer has source that should help, copied below. Props to Josef for original answer.
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
Here's generic source on getting the orientation.
int orientation = display.getOrientation();
or some more involved source from here (a little messy but looks correct).
public int getscrOrientation()
{
Display getOrient = getWindowManager().getDefaultDisplay();
int orientation = getOrient.getOrientation();
// Sometimes you may get undefined orientation Value is 0
// simple logic solves the problem compare the screen
// X,Y Co-ordinates and determine the Orientation in such cases
if(orientation==Configuration.ORIENTATION_UNDEFINED){
Configuration config = getResources().getConfiguration();
orientation = config.orientation;
if(orientation==Configuration.ORIENTATION_UNDEFINED){
//if height and widht of screen are equal then
// it is square orientation
if(getOrient.getWidth()==getOrient.getHeight()){
orientation = Configuration.ORIENTATION_SQUARE;
}else{ //if widht is less than height than it is portrait
if(getOrient.getWidth() < getOrient.getHeight()){
orientation = Configuration.ORIENTATION_PORTRAIT;
}else{ // if it is not any of the above it will defineitly be landscape
orientation = Configuration.ORIENTATION_LANDSCAPE;
}
}
}
}
return orientation; // return value 1 is portrait and 2 is Landscape Mode
}
I would suggest you get the width and height of your current view. Right now I am not sure what functions will give you these values but I am sure it is possible. With that you can then calculate an aspect ratio. I'd make the images something like 1000x1000 and just show a certain part of the image, so that the aspect ratio will not be wrong.
I have the same problem with the camera. So my solution was to pick one of the two values, width or height, as fixed, and calculate the correct other value according to the aspect ratio. I'm not sure if there are functions already to just show a part of the image, but I am sure you could write something to copy just a part of the image and show that part.
The drawback is of course that you will be showing just a part of the background. Since the general aspect ratio of the phones is however somewhere between 1:1.3 and 1:1.8 I guess it wouldn't be a too big problem. I for one would rather see the part of an image in the correct way, than looking at an ugly stretched image.
Maybe you could create your background images as NinePatch images so that you are in better control of how it stretches?
Otherwise, you can just prevent your images from stretching (or at least keep the correct aspect ratio) by setting the scaleType attribute e.g. android:scaleType="center".