Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

android camera setDisplayOrientation(90) fails in different devices

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 ?

like image 806
hacker Avatar asked Aug 18 '12 08:08

hacker


3 Answers

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);
}
like image 85
Nirav Mehta Avatar answered Nov 15 '22 01:11

Nirav Mehta


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.

like image 39
John J Smith Avatar answered Nov 14 '22 23:11

John J Smith


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

like image 27
Bruno Siqueira Avatar answered Nov 14 '22 23:11

Bruno Siqueira