Подтвердить что ты не робот

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

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

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

Я следил за образцом кода камеры и думал, что все работает до тех пор, пока я не попробовал свое приложение на нескольких устройствах 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) - отлично работает. lathedOrientation = 0, изображение ОК без какого-либо вращения в заголовке EXIF.

T-Mobile G1 (OS 1.6) - также отлично работает. lathedOrientation = 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, иначе кто-то разместил бы информацию об этом?

4b9b3361

Ответ 1

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

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

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

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

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

Ответ 2

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

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");
    }

Ответ 3

Вот код, который я использовал 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);

Ответ 4

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