124

I am using a Preview to display what the camera see's on the screen.

I can get everything working fine, surface created, surface set and the surface is displayed.

However it always displays the picture at an incorrect 90 degree angle in portrait mode.

Such as in the picture:

alt text

I am aware that using the following code will set the picture straight:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

However I have the Preview within an Activity that has other elements in it and it does not make sense for my Activity to be displayed in landscape mode. (Its disabled by default)

So I was wondering is there anyway to just change the orientation of the Preview? And leave the rest of my Activity correctly displayed in Portrait mode?

Or anyway to rotate the preview so that it is displayed correctly?

Donal Rafferty
  • 19,239
  • 37
  • 110
  • 186
  • Have a look - http://stackoverflow.com/questions/10259299/force-a-camera-to-always-open-in-portrait-mode-in-android/10259572#10259572 – Suvam Roy Apr 22 '12 at 06:31

8 Answers8

146

This issue appeared to start out as a bug with certain hardware see here but can be overcome by using the call to mCamera.setDisplayOrientation(degrees) available in API 8. So this is how I implement it:

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {            
    if (isPreviewRunning) {
        mCamera.stopPreview();
    }

    Parameters parameters = mCamera.getParameters();
    Display display = ((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay();

    if(display.getRotation() == Surface.ROTATION_0) {
        parameters.setPreviewSize(height, width);                           
        mCamera.setDisplayOrientation(90);
    }

    if(display.getRotation() == Surface.ROTATION_90) {
        parameters.setPreviewSize(width, height);                           
    }

    if(display.getRotation() == Surface.ROTATION_180) {
        parameters.setPreviewSize(height, width);               
    }

    if(display.getRotation() == Surface.ROTATION_270) {
        parameters.setPreviewSize(width, height);
        mCamera.setDisplayOrientation(180);
    }

    mCamera.setParameters(parameters);
    previewCamera();                      
}

And the previewCamera method :

public void previewCamera() {        
    try {           
        mCamera.setPreviewDisplay(mSurfaceHolder);          
        mCamera.startPreview();
        isPreviewRunning = true;
    } catch(Exception e) {
        Log.d(APP_CLASS, "Cannot start preview", e);    
    }
}

This was on an HTC Desire and I had to initially put in logging statements in each of the rotation checks to say what the rotation was and then debugged on the device and watched the logCat output while I rotated the device. For the HTC Desire, 0 was the phone as you would have expected (portrait), 90 degrees was turning the phone 90 degrees COUNTER-CLOCKWISE (I had assumed it would have been clockwise). In the code you'll see I didn't need to do any display rotation when the phone was at 90 or 180 degrees - the device seemed to handle this itself. Only one point not working properly: The 270 degree rotation is when you turn the device 90 degrees clockwise and the display rotation counters that ok but if you rotate the device 270 degrees counter-clockwise, it doesn't appear to compensate it properly.

P.S. Note the swapover of width and height in the appropriate rotations.

John J Smith
  • 9,654
  • 9
  • 49
  • 69
  • 7
    but setDisplayOrientation(degree); method supports form 2.2, what about lower version?? parameters.setRotation(90); parameters.set("orientation", "portrait"); are not working. If you have any solution for lower versions please help me. – Vikram Nov 01 '11 at 15:11
  • 1
    I implemented a preview on my app which will always show in portrait mode. I was always rotating the screen by 90 degrees and this seemed to work on every device until we tested it on the HTC Desire C. As I do not count on the device now to test this, I would like you to clarify if this fix you suggest finally worked well on the HTC desire. Thanks! – argenkiwi Dec 19 '12 at 14:10
  • 13
    The `mCamera.setParameters(parameters);` statement crash my app, because the surface dimensions are not a valid preview size for my phone (maybe because I keep the status bar visible?). However, I found that using `mCamera.setDisplayOrientation(90)` then `mCamera.setPreviewDisplay(mSurfaceHolder);` without setting the parameters worked too! – nicopico Feb 16 '13 at 13:18
  • @JohnJSmith If the device `Auto Rotation is disabled`, onSurfaceChanged will not be called, no matter which way you rotate. So, no work around for that? – Archie.bpgc May 21 '13 at 19:01
  • Thank you for efforts it worked for all except **Samsung Galaxy ACE with 2.3.6 Android version**. The method **setDisplayOrientation(90)** is not working. – swiftBoy Oct 03 '13 at 11:54
  • best answer. Thanks John. – Eliasz Kubala Oct 01 '14 at 10:54
  • Hello I have implemented above solution but it's still display picture in landscape only. I have tested it with samsung galaxy s3. – Gaurav Darji Dec 04 '14 at 06:49
  • 3
    would be cleaner with a switch statement – Siavash Dec 22 '15 at 19:45
  • 2
    Doesn't this assume that the preview is sideways on ALL devices? for it's sideways on some devices and up-right on others.... is there a way to check to see if a devices default camera orientation inline with the portrait side of the phone or not? – Siavash Jan 07 '16 at 22:55
  • when i swith width and height like in your code it streches my preview, but when i doesn't it works. saved me a day! – kilian eller Sep 07 '17 at 13:18
  • Hello if you set orientation at -> 90 and as your logic height and width are swapped so it wont allow to set the parameters as the size wont be supported if you try with 640X480 – Hardy Apr 05 '18 at 07:10
16

try to set the display orientation. It solves my problem.

 mCamera.setDisplayOrientation(90);
ksu
  • 812
  • 1
  • 11
  • 17
13
 public void surfaceCreated(SurfaceHolder holder) {
     mCamera = Camera.open();
     mCamera.setDisplayOrientation(90);
     try {
         mCamera.setPreviewDisplay(holder);
         mCamera.setPreviewCallback(new PreviewCallback() {

             @Override
             public void onPreviewFrame(byte[] data, Camera camera) {
             }
         });

     } catch (Exception e) {
         e.printStackTrace();
     }
}

try this code

Yaroslav Mytkalyk
  • 16,503
  • 10
  • 70
  • 96
jitendra G2
  • 131
  • 1
  • 4
4

I did it taking advice of mCamera.setDisplayOrientation(90); but also rotated the bitmap because for some reason the others approaches doesnt work for me in version 2.3.3.

For rotate the bitmap i did this:

Matrix matrix = new Matrix();
matrix.postRotate(90);
imageView1 = new ImageView(this);
Bitmap bitmap = BitmapFactory.decodeFile(files[i].getAbsolutePath());
Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap , 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
Bitmap scaledBitmap = Bitmap.createScaledBitmap(rotatedBitmap, 80, 80, true);
imageView1.setImageBitmap(scaledBitmap);
Community
  • 1
  • 1
yngrdyn
  • 266
  • 3
  • 12
4

I was having a problem with front Camera(Upside down issue). Then I used the following method documented in Android Docs -

public void setCameraDisplayOrientation(Activity activity , int icameraId , Camera camera1s)
    {
        CameraInfo cameraInfo = new CameraInfo();

        Camera.getCameraInfo(icameraId, cameraInfo);

        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();

        int degrees = 0; // k

        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 (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT)
        {
            // cameraType=CAMERATYPE.FRONT;

            result = (cameraInfo.orientation + degrees) % 360;
            result = (360 - result) % 360; // compensate the mirror

        }
        else
        { // back-facing

            result = (cameraInfo.orientation - degrees + 360) % 360;

        }
        // displayRotate=result;
        camera.setDisplayOrientation(result);


    }
Hrishikesh Kadam
  • 29,211
  • 3
  • 19
  • 29
AndroidGeek
  • 30,803
  • 14
  • 212
  • 262
0

I have compared my code to the tutorial one and what finally fixed it was putting the following code into my AndroidManifext.xml: In the <activity> tag:

android:screenOrientation="landscape"
android:configChanges="keyboardHidden|orientation">
sbaechler
  • 1,069
  • 12
  • 18
0
public void surfaceChanged(SurfaceHolder holder, int format, int w, int 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;
    }

    try {
        mCamera.stopPreview();
    } catch (Exception e) {
        e.printStackTrace();
    }

    Camera.Parameters parameters = mCamera.getParameters();
    Display display = ((WindowManager) getContext().getSystemService(WINDOW_SERVICE)).getDefaultDisplay();

    if (display.getRotation() == Surface.ROTATION_0) {
        parameters.setPreviewSize(h, w);
        mCamera.setDisplayOrientation(90);
    }

    if (display.getRotation() == Surface.ROTATION_90) {
        parameters.setPreviewSize(w, h);
        mCamera.setDisplayOrientation(0);
    }

    if (display.getRotation() == Surface.ROTATION_180) {
        parameters.setPreviewSize(h, w);
        mCamera.setDisplayOrientation(270);
    }

    if (display.getRotation() == Surface.ROTATION_270) {
        parameters.setPreviewSize(w, h);
        mCamera.setDisplayOrientation(180);
    }

    previewCamera();
}

public void previewCamera() {
    try {
        mCamera.setPreviewDisplay(mHolder);
        mCamera.startPreview();
    } catch (Exception e) {
        //Log.d(APP_CLASS, "Cannot start preview", e);
        e.printStackTrace();
    }
}
sofi37
  • 323
  • 1
  • 3
  • 15
0

I think the SENSOR_ORIENTATION value will explain what value to be used for the rotation instead of hardcoding to 90 degrees

CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
        if (manager == null) {
            Log.i(TAG, "camera manager is null");
            return;
        }
        for (String id: manager.getCameraIdList()) {
            CameraCharacteristics characteristics = manager.getCameraCharacteristics(id);
            Integer orientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
            Log.i(TAG, "camera sensor orientation is " + orientation);
        }
psykid
  • 378
  • 3
  • 15