Необъяснимое вращение камеры Android при захвате для некоторых устройств (не в EXIF) - PullRequest
28 голосов
/ 04 октября 2010

То, что я делаю, кажется, должно быть простым, но я все еще потерялся после того, как прочитал все возможные ответы Stackoverflow, которые я могу найти, и прогуглил каждую статью, которую я могу найти.

Яс помощью предварительного просмотра SurfaceView и захвата изображения из действия, которое установлено для screenOrientation = "landscape" в моем AndroidManifest.xml.

Я следовал примеру кода приложения Camera и думал, что все работает, пока не попробовал мое приложение нанесколько устройств Motorola, работающих под управлением 1.5.

У меня OrientationEventListener работает нормально, и я использую отражение, чтобы увидеть, если установить вращение следующим образом:

final int latchedOrientation = roundOrientation(mLastOrientation + 90);

Parameters parameters = preview.camera.getParameters();

JPLog.d("Setting camera rotation = %d", latchedOrientation);
try {
    // if >= 2.0
    Method method = Camera.Parameters.class.getMethod("setRotation",
        int.class);

    if(method != null) {
        method.invoke(parameters, latchedOrientation);
    }

} catch(Throwable t) {
    // if < 2.0
    parameters.set("rotation", latchedOrientation);
}

preview.camera.setParameters(parameters);

NexusOne (OS 2.2) - Отлично работает.latchedOrientation = 0, изображение в норме без поворота в заголовке EXIF.

T-Mobile G1 (OS 1.6) - также отлично работает.latchedOrientation = 0, изображение в порядке.

Motorola Backflip (OS 1.5) - изображение повернуто.latchedOrientation = 0, в изображении нет поворота EXIF.

Motorola CLIQ (OS 1.5) - изображение повернуто.latchedOrientation = 0, изображение не имеет поворота EXIF.

Что происходит с этими устройствами Motorola?Я думал, что моя проблема в том, что драйвер камеры Motorola не поворачивает изображения, поэтому нашел классы чтения Sanselan EXIF ​​для Android и готовился повернуть их сам.Забавно то, что есть заголовки EXIF, но нет элемента поворота.

Если я установлю поворот вручную на 90 градусов, изображения получатся идеальными для устройств Motorola, но теперь G1 и NexusOne имеют изображения, которые поворачиваются90 градусов (не то, что я хочу).Должно быть что-то, чего я здесь не получаю.

Я сомневаюсь, что это проблема 1.5, иначе кто-то опубликовал бы информацию об этом?

Ответы [ 4 ]

46 голосов
/ 15 июня 2012

У меня была эта проблема, и я использовал этот метод для захвата изображения. (Без создания пользовательской камеры)

final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(image));
startActivityForResult(intent, 0);

и сделал все остальное в onActivityResult (int requestCode, int resultCode, Intent data) {}

Но исходное изображение (фактическое изображение с SD-карты) было правильным, и растровое изображение поворачивалось, когда я получал вот так. Bitmap bmp = BitmapFactory.decodeStream (..

Решение:

    try {
        File f = new File(SD_CARD_IMAGE_PATH);
        ExifInterface exif = new ExifInterface(f.getPath());
        int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);

        int angle = 0;

        if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
            angle = 90;
        } 
        else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
            angle = 180;
        } 
        else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
            angle = 270;
        }

        Matrix mat = new Matrix();
        mat.postRotate(angle);

        Bitmap bmp = BitmapFactory.decodeStream(new FileInputStream(f), null, null);
        Bitmap correctBmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), mat, true);                 
    }
    catch (IOException e) {
        Log.w("TAG", "-- Error in setting image");
    }   
    catch(OutOfMemoryError oom) {
        Log.w("TAG", "-- OOM Error in setting image");
    }
10 голосов
/ 09 февраля 2011

На самом деле это проблема конкретного устройства, которая в основном затрагивает устройства Motorola. Разработчики Google включили вызов setDisplayOrientation в API 8, чтобы обойти эту проблему. Основная ошибка подана здесь .

Для тех, кто не может перейти на API 8, есть два общих решения:

Переопределить onDraw
Переопределите onDraw в ViewGroup верхнего уровня и поверните холст на 90 градусов, чтобы компенсировать поворот. Обратите внимание, что здесь есть предостережение, поскольку ваши сенсорные события также нужно будет поворачивать.

Использовать ландшафтный режим
Заблокируйте активность в ландшафтном режиме, но рисуйте активы, как если бы они были в портретной ориентации Это означает, что вы делаете макет и поворачиваете ресурсы изображения, чтобы выглядеть так, как будто вы находитесь в портретном режиме, чтобы изображение выглядело нормально. К сожалению, это затрудняет использование меню, поскольку оно открывается горизонтально.

Я также видел, как люди используют контроллер анимации для поворота вида. Недостаток, который я не смог преодолеть, заключается в том, что повернутое изображение не растягивается, чтобы заполнить экран. См. ответ Georg для примера реализации.

4 голосов
/ 03 августа 2011

Вот код, который я использовал onActivityResult () в своей деятельности.Возвращаемое намерение было для выбора изображения типа image / *.Хорошо работает для меня!

Uri imageUri = intent.getData();
                String[] orientationColumn = {MediaStore.Images.Media.ORIENTATION};
                Cursor cur = managedQuery(imageUri, orientationColumn, null, null, null);
                int orientation = -1;
                if (cur != null && cur.moveToFirst()) {
                    orientation = cur.getInt(cur.getColumnIndex(orientationColumn[0]));
                }  
                Matrix matrix = new Matrix();
                matrix.postRotate(orientation);
0 голосов
/ 04 июня 2011

Похоже, что предложение «использовать ландшафтный режим» - единственное, что действительно работает. Похоже, что это нормально для манифеста или для вызова через setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) в действии onCreate.

...