8

I have a problem with my camera app.Camera activity is in portrait mode.So i gave

camera.setDisplayOrientation(90);

As per different posts in SO, this will work fine in portrait mode.

but it never works fine with different devices.The issue is, preview rotated 90 degree left or right.In Htc it's ok. But with galaxy series it's not working.

Can anyone help me ?

4 Answers 4

3

Set orientation and preview in following different ways, use as requirement :

First Ways :

  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

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

Second ways :

  private Camera mCamera;
  private OrientationEventListener mOrientationEventListener;
  private int mOrientation =  -1;

 private static final int ORIENTATION_PORTRAIT_NORMAL =  1;
 private static final int ORIENTATION_PORTRAIT_INVERTED =  2;
 private static final int ORIENTATION_LANDSCAPE_NORMAL =  3;
 private static final int ORIENTATION_LANDSCAPE_INVERTED =  4;

 @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
         // force Landscape layout
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR |           ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
   /*
      Your other initialization code here
   */
   }

 @Override 
  protected void onResume() {
       super.onResume();

        if (mOrientationEventListener == null) {            
              mOrientationEventListener = new OrientationEventListener(this,  SensorManager.SENSOR_DELAY_NORMAL) {

        @Override
        public void onOrientationChanged(int orientation) {

            // determine our orientation based on sensor response
            int lastOrientation = mOrientation;

            if (orientation >= 315 || orientation < 45) {
                if (mOrientation != ORIENTATION_PORTRAIT_NORMAL) {                          
                    mOrientation = ORIENTATION_PORTRAIT_NORMAL;
                }
            }
            else if (orientation < 315 && orientation >= 225) {
                if (mOrientation != ORIENTATION_LANDSCAPE_NORMAL) {
                    mOrientation = ORIENTATION_LANDSCAPE_NORMAL;
                }                       
            }
            else if (orientation < 225 && orientation >= 135) {
                if (mOrientation != ORIENTATION_PORTRAIT_INVERTED) {
                    mOrientation = ORIENTATION_PORTRAIT_INVERTED;
                }                       
            }
            else { // orientation <135 && orientation > 45
                if (mOrientation != ORIENTATION_LANDSCAPE_INVERTED) {
                    mOrientation = ORIENTATION_LANDSCAPE_INVERTED;
                }                       
            }   

            if (lastOrientation != mOrientation) {
                changeRotation(mOrientation, lastOrientation);
            }
        }
    };
}
if (mOrientationEventListener.canDetectOrientation()) {
    mOrientationEventListener.enable();
    }
 }

  @Override protected void onPause() {
       super.onPause();
       mOrientationEventListener.disable();
  }

    /**
     * Performs required action to accommodate new orientation
     * @param orientation
     * @param lastOrientation
    */
   private void changeRotation(int orientation, int lastOrientation) {
   switch (orientation) {
    case ORIENTATION_PORTRAIT_NORMAL:
        mSnapButton.setImageDrawable(getRotatedImage(android.R.drawable.ic_menu_camera, 270));
        mBackButton.setImageDrawable(getRotatedImage(android.R.drawable.ic_menu_revert, 270));
        Log.v("CameraActivity", "Orientation = 90");
        break;
    case ORIENTATION_LANDSCAPE_NORMAL:
        mSnapButton.setImageResource(android.R.drawable.ic_menu_camera);
        mBackButton.setImageResource(android.R.drawable.ic_menu_revert);
        Log.v("CameraActivity", "Orientation = 0");
        break;
    case ORIENTATION_PORTRAIT_INVERTED:
        mSnapButton.setImageDrawable(getRotatedImage(android.R.drawable.ic_menu_camera, 90));
        mBackButton.setImageDrawable(getRotatedImage(android.R.drawable.ic_menu_revert, 90));
        Log.v("CameraActivity", "Orientation = 270");
        break;
    case ORIENTATION_LANDSCAPE_INVERTED:
        mSnapButton.setImageDrawable(getRotatedImage(android.R.drawable.ic_menu_camera, 180));
        mBackButton.setImageDrawable(getRotatedImage(android.R.drawable.ic_menu_revert, 180));      
        Log.v("CameraActivity", "Orientation = 180");
        break;
     }
  } 

    /**
   * Rotates given Drawable
   * @param drawableId    Drawable Id to rotate
   * @param degrees       Rotate drawable by Degrees
   * @return              Rotated Drawable
   */
 private Drawable getRotatedImage(int drawableId, int degrees) {
    Bitmap original = BitmapFactory.decodeResource(getResources(), drawableId);
    Matrix matrix = new Matrix();
    matrix.postRotate(degrees);

   Bitmap rotated = Bitmap.createBitmap(original, 0, 0, original.getWidth(),  original.getHeight(),  matrix, true);
  return new BitmapDrawable(rotated);
}

And then in your PictureCallback set metadata to indicate rotation level:

private Camera.PictureCallback mJpegCallback = new Camera.PictureCallback() {

@Override
public void onPictureTaken(byte[] data, Camera camera) {
    try {
        // Populate image metadata

        ContentValues image = new ContentValues();
        // additional picture metadata
        image.put(Media.DISPLAY_NAME, [picture name]);
        image.put(Media.MIME_TYPE, "image/jpg");
        image.put(Media.TITLE, [picture title]);
        image.put(Media.DESCRIPTION, [picture description]);
        image.put(Media.DATE_ADDED, [some time]);
        image.put(Media.DATE_TAKEN, [some time]);
        image.put(Media.DATE_MODIFIED, [some time]);

        // do not rotate image, just put rotation info in
        switch (mOrientation) {
            case ORIENTATION_PORTRAIT_NORMAL:
                image.put(Media.ORIENTATION, 90);
                break;
            case ORIENTATION_LANDSCAPE_NORMAL:
                image.put(Media.ORIENTATION, 0);
                break;
            case ORIENTATION_PORTRAIT_INVERTED:
                image.put(Media.ORIENTATION, 270);
                break;
            case ORIENTATION_LANDSCAPE_INVERTED:
                image.put(Media.ORIENTATION, 180);
                break;
        }

        // store the picture
        Uri uri = getContentResolver().insert(
                Media.EXTERNAL_CONTENT_URI, image);

        try {
            Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0,
                    data.length);
            OutputStream out = getContentResolver().openOutputStream(
                    uri);
            boolean success = bitmap.compress(
                    Bitmap.CompressFormat.JPEG, 75, out);
            out.close();
            if (!success) {
                finish(); // image output failed without any error,
                            // silently finish
            }

Now when landscape based devices are appearing an additional check for it is required in OrientationEventListener.

  Display display = ((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay();                                        
 if (display.getOrientation() == Surface.ROTATION_0) { 
    // landscape oriented devices
 } else { 
     // portrait oriented device
 }

Full code (a bit wasteful by LC, but easily demonstrates the approach)

 @Override
 public void onOrientationChanged(int orientation) {

// determine our orientation based on sensor response
int lastOrientation = mOrientation;

Display display = ((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay();                                        

if (display.getOrientation() == Surface.ROTATION_0) {   // landscape oriented devices
    if (orientation >= 315 || orientation < 45) {
        if (mOrientation != ORIENTATION_LANDSCAPE_NORMAL) {                         
            mOrientation = ORIENTATION_LANDSCAPE_NORMAL;
        }
    } else if (orientation < 315 && orientation >= 225) {
        if (mOrientation != ORIENTATION_PORTRAIT_INVERTED) {
            mOrientation = ORIENTATION_PORTRAIT_INVERTED;
        }                       
    } else if (orientation < 225 && orientation >= 135) {
        if (mOrientation != ORIENTATION_LANDSCAPE_INVERTED) {
            mOrientation = ORIENTATION_LANDSCAPE_INVERTED;
        }                       
    } else if (orientation <135 && orientation > 45) { 
        if (mOrientation != ORIENTATION_PORTRAIT_NORMAL) {
            mOrientation = ORIENTATION_PORTRAIT_NORMAL;
        }                       
    }                       
} else {  // portrait oriented devices
    if (orientation >= 315 || orientation < 45) {
        if (mOrientation != ORIENTATION_PORTRAIT_NORMAL) {                          
            mOrientation = ORIENTATION_PORTRAIT_NORMAL;
        }
    } else if (orientation < 315 && orientation >= 225) {
        if (mOrientation != ORIENTATION_LANDSCAPE_NORMAL) {
            mOrientation = ORIENTATION_LANDSCAPE_NORMAL;
 }                       
    } else if (orientation < 225 && orientation >= 135) {
        if (mOrientation != ORIENTATION_LANDSCAPE_INVERTED) {
            mOrientation = ORIENTATION_LANDSCAPE_INVERTED;
        }                       
    } else if (orientation <135 && orientation > 45) { 
        if (mOrientation != ORIENTATION_PORTRAIT_NORMAL) {
            mOrientation = ORIENTATION_PORTRAIT_NORMAL;
        }                       
    }                       
} else {  // portrait oriented devices
    if (orientation >= 315 || orientation < 45) {
        if (mOrientation != ORIENTATION_PORTRAIT_NORMAL) {                          
            mOrientation = ORIENTATION_PORTRAIT_NORMAL;
        }
    } else if (orientation < 315 && orientation >= 225) {
        if (mOrientation != ORIENTATION_LANDSCAPE_NORMAL) {
            mOrientation = ORIENTATION_LANDSCAPE_NORMAL;
        }                       
    } else if (orientation < 225 && orientation >= 135) {
        if (mOrientation != ORIENTATION_PORTRAIT_INVERTED) {
            mOrientation = ORIENTATION_PORTRAIT_INVERTED;
        }                       
    } else if (orientation <135 && orientation > 45) { 
        if (mOrientation != ORIENTATION_LANDSCAPE_INVERTED) {
            mOrientation = ORIENTATION_LANDSCAPE_INVERTED;
        }                       
    }
 }

  if (lastOrientation != mOrientation) {
    changeRotation(mOrientation, lastOrientation);
  }
 }

Third ways :

 private Bitmap adjustImageOrientation(Bitmap image) {
    ExifInterface exif;
    try {
        exif = new ExifInterface(picturePath);
        int exifOrientation = exif.getAttributeInt(
                ExifInterface.TAG_ORIENTATION,
                ExifInterface.ORIENTATION_NORMAL);

        int rotate = 0;
        switch (exifOrientation) {
        case ExifInterface.ORIENTATION_ROTATE_90:
            rotate = 90;
            break;

        case ExifInterface.ORIENTATION_ROTATE_180:
            rotate = 180;
            break;

        case ExifInterface.ORIENTATION_ROTATE_270:
            rotate = 270;
            break;
        }

        if (rotate != 0) {
            int w = image.getWidth();
            int h = image.getHeight();

            // Setting pre rotate
            Matrix mtx = new Matrix();
            mtx.preRotate(rotate);

            // Rotating Bitmap & convert to ARGB_8888, required by tess
            image = Bitmap.createBitmap(image, 0, 0, w, h, mtx, false);

        }
    } catch (IOException e) {
             return null;
    }
    return image.copy(Bitmap.Config.ARGB_8888, true);
}
1

I gave this answer to a similar question, but as you say it was on an HTC device. I would recommend that you add breakpoints to the rotation code and examine the variables while physically rotating the device - this may help identify whats different with the Galaxy models.

1

Check if the "Auto-rotate Screen" option is checked in the phone Settings (Settings > Dislay or Screen - depends on the android version).

0
1

Just posting a new solution that worked for me.

Basically you can get the orientation value from the Camera.CameraInfo. This will tell the degrees you need to use on setDisplayOrientation so the image is properly displayed. When using the back facing camera you can simply use setDisplayOrientation with the value retrieved, But when using the front facing camera you need to tweak it a bit as the Android system will flip the image so it appears like a mirror.

Below code worked for me and tested on 4 different devices including a Nexus6 and Galaxy.

Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
int cameraCount = Camera.getNumberOfCameras();
int camIdx = 0; // DO your logic to get front or back camera...or loop through all avaialable.
Camera.getCameraInfo(camIdx, cameraInfo);

try {
    mCamera = Camera.open(camIdx);
    // If using back camera then simply rotate what CameraInfo tells you.
    if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK)
        mCamera.setDisplayOrientation(cameraInfo.orientation);
    else
        // If using front camera note that image might be flipped to give users the impresion the are looking at a mirror.
        mCamera.setDisplayOrientation( (360 - cameraInfo.orientation) % 360);
} catch (Exception e) {
    e.printStackTrace();
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.