I am using this code:
https://github.com/commonsguy/cw-advandroid/blob/master/Camera/Picture/src/com/commonsware/android/picture/PictureDemo.java
where in Manifest, Activity Orientation is set to Landscape.
So, its like allowing user to take picture only in Landscape mode, and if the picture is taking by holding the device in portrait mode, the image saved is like this:
a 90 degree rotated image.
After searching for a solution, I found this:
Android - Camera preview is sideways
where the solution is:
in surfaceChanged() check for
Display display = ((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
display.getRotation();
and change the Camera's displayOrientation accordingly.
camera.setDisplayOrientation(90);
But no matter how many times I rotate the device, surfaceChanged() never gets called.
I even tried removing orientation="Landscape" in the Manifest.xml, but then the preview itself is shown sideways(may be because default android.view.SurfaceView is supposed to be in Landscape mode?).
Try this.
public void surfaceCreated(SurfaceHolder holder) {
try {
camera = Camera.open();
camParam = camera.getParameters();
Camera.Parameters params = camera.getParameters();
String currentversion = android.os.Build.VERSION.SDK;
Log.d("System out", "currentVersion " + currentversion);
int currentInt = android.os.Build.VERSION.SDK_INT;
Log.d("System out", "currentVersion " + currentInt);
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
if (currentInt != 7) {
camera.setDisplayOrientation(90);
} else {
Log.d("System out", "Portrait " + currentInt);
params.setRotation(90);
/*
* params.set("orientation", "portrait");
* params.set("rotation",90);
*/
camera.setParameters(params);
}
}
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
// camera.setDisplayOrientation(0);
if (currentInt != 7) {
camera.setDisplayOrientation(0);
} else {
Log.d("System out", "Landscape " + currentInt);
params.set("orientation", "landscape");
params.set("rotation", 90);
camera.setParameters(params);
}
}
camera.setPreviewDisplay(holder);
camera.startPreview();
} catch (IOException e) {
Log.d("CAMERA", e.getMessage());
}
}
Since you've forced your application to be landscape, your application's configuration won't change when you rotate the device, and as a result, your UI won't get redrawn. So you'll never see a surfaceCreated/Changed callback because of it.
In any case, your issue isn't with preview, it's with the captured pictures.
The camera API doesn't automatically know which way is down; it needs you to tell it how you want your images rotated by using the Camera.Parameters setRotation method. There are several coordinate systems in play here (the orientation of the camera sensor relative to your device; the orientation of your UI relative to the device; and the orientation of the device relative to the world) which have to be done correctly.
So I highly recommend you use the code provided in the setRotation documentation, and inherit from the OrientationEventListener, implementing the listener as follows:
public void onOrientationChanged(int orientation) {
if (orientation == ORIENTATION_UNKNOWN) return;
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
orientation = (orientation + 45) / 90 * 90;
int rotation = 0;
if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
rotation = (info.orientation - orientation + 360) % 360;
} else { // back-facing camera
rotation = (info.orientation + orientation) % 360;
}
mParameters.setRotation(rotation);
}
This will update your camera's still picture orientation correctly so that 'up' is always up, whether your app is landscape or portrait, or your device is a tablet or a phone.
Related
I am kind of newbie in Android development, so my apologies in advance if my question is trivial. In one part of my app I need a live preview of my rear camera, so I created a custom class which extends SurfaceView and implement SurfaceHolder.Callback (I followed basically the instructions in the android documentation).
Unfortunately, I am testing my app in a Nexus 5x, which I've just realized that it has installed the camera sensor in a reverse way. For that reason, the camera preview of my app when running on my Nexus 5x appears upside down, which is something I dont want.
It seems that the new android.hardware.camera2 API is able to handle this issue automatically. Eventually I'll need to update all my code using this new API, but for now what I need is a quick fix while using the old camera API.
So I was reading out there and I found a piece of code that I would need to introduce in the SurfaceChanged method to workaround this issue. Here it is:
Display display = ((WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
if(display.getRotation() == Surface.ROTATION_0)
{
parameters.setPreviewSize(capHeight, capWidth);
camera.setDisplayOrientation(90);
}
if(display.getRotation() == Surface.ROTATION_90)
{
parameters.setPreviewSize(capWidth, capHeight);
}
if(display.getRotation() == Surface.ROTATION_180)
{
parameters.setPreviewSize(capHeight, capWidth);
}
if(display.getRotation() == Surface.ROTATION_270)
{
parameters.setPreviewSize(capWidth, capHeight);
camera.setDisplayOrientation(180);
}
camera.setParameters(parameters);*/
camera.startPreview();
The problem is that I don't see that something has changed.
Any thoughts?
The 5X camera is not "reverse"; it does report the correct camera orientation in its parameters, so no special workarounds are needed, just make sure you're setting the display orientation correctly:
public static void setCameraDisplayOrientation(Activity activity,
int cameraId, android.hardware.Camera camera) {
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int rotation = activity.getWindowManager().getDefaultDisplay()
.getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0: degrees = 0; break;
case Surface.ROTATION_90: degrees = 90; break;
case Surface.ROTATION_180: degrees = 180; break;
case Surface.ROTATION_270: degrees = 270; break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
camera.setDisplayOrientation(result);
}
From http://developer.android.com/reference/android/hardware/Camera.html#setDisplayOrientation%28int%29
if (Build.MODEL.equals("Nexus 5X")){
// rotate camera 180°
mCamera.setDisplayOrientation(180);
}
Change 5x to 5X will be ok.
Same here.
Since camera2 doesn't support devices < API 21, and don't want to implement the two APIs, it would be nice do get a quick fix.
I'm trying somthing like :
if (Build.MODEL.equals("Nexus 5x")){
// rotate camera 180°
mCamera.setDisplayOrientation(180);
}
But can't rotate the display of the camera. Gonna check if there is something to do with the PreviewCallback
Is it a bad thing to use the 2 apis ?
As in this topic, it is not recommended :
How to use Android's camera or camera2 API to support old and new API versions without deprecation notes?
Im trying to rotate my camera when the device rotates, iv tried several methods, but none of them seem to work on all devices.
//This Works on my nexus 5 but not on my Samsung galaxy tab
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
if (mHolder.getSurface() == null)
{
return;
}
try
{
mCamera.stopPreview();
Camera.Parameters parameters = mCamera.getParameters();
parameters.set("orientation", "landscape");
int rotation = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
int orientation = getContext().getResources().getConfiguration().orientation;
if (rotation == Surface.ROTATION_0) {
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
mCamera.setDisplayOrientation(0);
} else {
mCamera.setDisplayOrientation(90);
}
}
else if (rotation == Surface.ROTATION_90) {
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
mCamera.setDisplayOrientation(270);
}
}
else if (rotation == Surface.ROTATION_180) {
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
mCamera.setDisplayOrientation(180);
}
}
else if (rotation == Surface.ROTATION_270) {
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
mCamera.setDisplayOrientation(90);
}
}
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
}
catch (Exception e) {
}
}
// and i tried this, which is part of the documentation and it doesnt work on my nexus 5:
public static void setCameraDisplayOrientation(Activity activity,
int cameraId, android.hardware.Camera camera) {
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int rotation = activity.getWindowManager().getDefaultDisplay()
.getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0: degrees = 0; break;
case Surface.ROTATION_90: degrees = 90; break;
case Surface.ROTATION_180: degrees = 180; break;
case Surface.ROTATION_270: degrees = 270; break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
camera.setDisplayOrientation(result);
}
Does someone have a working solution for all devices?
Although I'm not exactly sure what's your issue from the code you provided, here are few things one has to got right when using Camera API and image rotation on Android (the old one - on API <21)
1. You have to take in account the orientation of the image sensor.
The orientation of the sensor means its angle to the device native use-mode. (that's what actually does the google snippet you are using) For phones this is usually being set to portrait, on tablets to landscape.
Here is an excerpt from the documentation, it can make pain in head for a while, but that's just how things work.
For example, suppose a device has a naturally tall screen. The back-facing camera sensor is mounted in landscape. You are looking at the screen. If the top side of the camera sensor is aligned with the right edge of the screen in natural orientation, the value should be 90. If the top side of a front-facing camera sensor is aligned with the right of the screen, the value should be 270.
2. Frontfacing camera preview is being mirrored
If you use frontfacing camera, you have to take in account the implicit mirroring.
3. These rules are only meant for rotating the Camera preview
This is important. All this is only meant to allow you to display correctly rotated preview frames on the device screen. Once you take an actual picture, you have to rotate it once again to suit your needs. For front-facing images this might mean mirroring it yourself,...You can see the result of this "weirdness" among all apps on Android. Just take picture in hangouts and share it right away. On various phones you gotta get somewhat weirdly rotated image as the result.
4. OEMs does not adhere to specs all the time
All I can say, is that probably no solution will be hasslefree, we got some issues with some particular devices. (as usual on Android:)
5. Use the CWAC Camera library
We found this library to be a superior wrapper around the official Camera APIs. Solving practically all of the issues I did mention.
I'm trying to make a custom camera app. I'm taking pictures from the front facing camera without preview, but the resulting images are rotated according to the front camera orientation.
I searched through a lot of post here at stack, also the one described here in the android docs.
This is the solution that I came up with:
private void prepareCamera(Activity a){
//Rotation
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_FRONT,info);
int rotation = a.getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
Log.d("TEST","rotation: "+rotation);
switch(rotation){
case Surface.ROTATION_0: degrees = 0; break; //Natural orientation
case Surface.ROTATION_90: degrees = 90; break; //Landscape left
case Surface.ROTATION_180: degrees = 180; break; //Upside down
case Surface.ROTATION_270: degrees = 270; break; //Landscape right
}
Log.d("TEST","degrees: "+degrees);
int result = (info.orientation + degrees) % 360;
Log.d("TEST","result: "+result);
result = (360 - result) % 360; //Compensate the mirror
Log.d("TEST","result: "+result);
//camera.setDisplayOrientation(result);
//Parameters
Camera.Parameters params = camera.getParameters();
params.setRotation(result);
params.setJpegQuality(100);
camera.setParameters(params);
//Preview
SurfaceView view = new SurfaceView(context);
try{
camera.setPreviewDisplay(view.getHolder());
}catch(IOException e){
throw new RuntimeException(e);
}
camera.startPreview();
}
It works, but I have two problems
1) I have the line, wich I took from the android docs, that "compensates the mirror". If I don't delete that line the pictures are well rotated according to the camera orientation, but they are overpassed by 180º. If I delete it the pictures are fine. I want to understand the why, if someone can please explain me.
I think its because that example code that I took from the docs its made for the SurfaceView, and it calls setDisplayOrientation(result);, when I'm using the results in .setRotation(result);. Maybe it has something to do with it?
2) When I'm testing I can rotate my phone to all directions but Upside down and get the pictures well rotated. But when I put the phone upside down, they are rotate 90, but upside down. As they were processed like Natural orientation. Maybe android wont track upside down rotation? If so, why would they with a case in the example provided by them.
Please look at setRotation() sample:
public void onOrientationChanged(int orientation) {
if (orientation == ORIENTATION_UNKNOWN) return;
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
orientation = (orientation + 45) / 90 * 90;
int rotation = 0;
if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
rotation = (info.orientation - orientation + 360) % 360;
} else { // back-facing camera
rotation = (info.orientation + orientation) % 360;
}
mParameters.setRotation(rotation);
}
Display.getRotation(), unlike orientation sensor, is limited to orientations that your current Activity supports. On some devices, the portrait upside-down orientation is not supported by system.
I have created a camera app and I want my app to be turned in all 4 possible orientations and the to update the camera preview accordingly. for that I have used the following method I have copied from:
Android - Camera preview is sideways
public void updateCameraDisplay(int w, int h) {
// set preview size and make any resize, rotate or
// reformatting changes here
Log.i("CameraPreviews", "Updating camera orientation with w=" + w
+ " and h=" + h);
Parameters parameters = camera.getParameters();
Display display = getActivity().getWindowManager()
.getDefaultDisplay();
int rotation = getActivity().getResources().getConfiguration().orientation;
Log.i("CameraPreviews", "rotation is " + display.getRotation());
if (display.getRotation() == Surface.ROTATION_0) {
parameters.setPreviewSize(h, w);
camera.setDisplayOrientation(0);
}
if (display.getRotation() == Surface.ROTATION_90) {
parameters.setPreviewSize(w, h);
camera.setDisplayOrientation(270);
}
if (display.getRotation() == Surface.ROTATION_180) {
parameters.setPreviewSize(h, w);
camera.setDisplayOrientation(180);
}
if (display.getRotation() == Surface.ROTATION_270) {
parameters.setPreviewSize(w, h);
camera.setDisplayOrientation(90);
}
try {
camera.setParameters(parameters);
} catch (Exception e) {
e.printStackTrace();
}
}
}
I have tweeked the values, testing them on the samsung galaxy tab2 to finally get the right orientations and it all works. When I tried it on htc one s phone it doesn't work at all!!!!! All e orientations are totally wrong! So I have arrived to the conclusion that thre must be 2 type of devices (or more... please no!) because the rotation represents how many degrees the screen has been rotated from its "default" position then some devices have one default position and others another. How could I find out about this default rotation and act accordingly in my code?
ej:
defaultOrientation=some code
if(defaultOrientation==0) ...
else ....
locking screen orientation is out of question.
target api>=11
thanks a lot
EDIT:
I have modified my code to:
public void updateCameraDisplay(int w, int h) {
// set preview size and make any resize, rotate or
// reformatting changes here
Log.i("CameraPreviews", "Updating camera orientation with w=" + w
+ " and h=" + h);
Parameters parameters = camera.getParameters();
Display display = getActivity().getWindowManager()
.getDefaultDisplay();
int rotation = getActivity().getResources().getConfiguration().orientation;
Log.i("CameraPreviews", "screen rotation is " + rotation);
Log.i("CameraPreviews", "display rotation is " + display.getRotation());
if (display.getRotation() == Surface.ROTATION_0) {
if (rotation == Configuration.ORIENTATION_LANDSCAPE) {
parameters.setPreviewSize(h, w);
camera.setDisplayOrientation(0);
} else {
parameters.setPreviewSize(h, w);
camera.setDisplayOrientation(90);
}
}
else if (display.getRotation() == Surface.ROTATION_90) {
if (rotation == Configuration.ORIENTATION_PORTRAIT) {
parameters.setPreviewSize(w, h);
camera.setDisplayOrientation(270);
} else {
parameters.setPreviewSize(w, h);
//camera.setDisplayOrientation(0);
}
}
else if (display.getRotation() == Surface.ROTATION_180) {
if (rotation == Configuration.ORIENTATION_LANDSCAPE) {
parameters.setPreviewSize(h, w);
camera.setDisplayOrientation(180);
}else {
parameters.setPreviewSize(h, w);
camera.setDisplayOrientation(270);
}
}
else if (display.getRotation() == Surface.ROTATION_270) {
if (rotation == Configuration.ORIENTATION_PORTRAIT) {
parameters.setPreviewSize(w, h);
camera.setDisplayOrientation(90);
} else {
parameters.setPreviewSize(w, h);
camera.setDisplayOrientation(180);
}
}
try {
camera.setParameters(parameters);
} catch (Exception e) {
e.printStackTrace();
}
}
works better on htc one s and samsung galaxy tab as long as we don't rotate the phone in the portrait mode upside down
the factors you need to think about are: the orientation of the device, the degree between the screen and the camera, assuming you are using the back camera, and whether you enable the activity to sense the orientation change.
And one important thing is whether the Camera HAL code implemented by the manufacturer is compliant with Google's protocol.
I face a problem a problem trying to have a camera preview in portrait mode. I have read various articles about it and I had solved it having the following code:
Display display = ((CaptureActivity)context).getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
if (Integer.parseInt(Build.VERSION.SDK) >= 8) {
setDisplayOrientation(camera, 90);
}else{
Camera.Parameters parameters = camera.getParameters();
parameters.set("orientation", "portrait");
camera.setParameters(parameters);
}
where setDisplayOrientation() is defined as:
protected void setDisplayOrientation(Camera camera, int angle) {
Method downPolymorphic;
try {
downPolymorphic = camera.getClass().getMethod(
"setDisplayOrientation", new Class[] { int.class });
if (downPolymorphic != null)
downPolymorphic.invoke(camera, new Object[] { angle });
} catch (Exception e1) {
}
}
Now I tried this code to a Galaxy Tab and it failed. I solved it (trying and error approach) using the following code:
if (height == 1024 && width == 600) {
Camera.Parameters parameters = camera.getParameters();
parameters.set("orientation", "portrait");
parameters.setRotation(90);
camera.setParameters(parameters);
}
Now my two questions are:
1) Why there is such problem while Galaxy tab has the 2.2 version, and
2) Is there any better solution to this problem?
Thanks a lot for your time!
for setting the display orientation check out the official docs, dont just hardcode 90 degrees there.