android相机surfaceview方向

标签 android orientation smartphone android-sdk-2.1 android-camera

好的,所以我有一个扩展 SurfaceView 并覆盖的类

surfaceChanged - 只需调用 startPreview
surfaceCreated - 打开相机,编辑参数*,设置surfaceHolder
surfaceDestroyed - 调用 stopPreview,释放相机

这一切都很好,因为当方向是纵向时:

从表面创建 *

m_camera = Camera.open();
Camera.Parameters p = m_camera.getParameters();

if (getResources().getConfiguration().orientation != 
    Configuration.ORIENTATION_LANDSCAPE)
{
    p.set("orientation", "portrait");

    // CameraApi is a wrapper to check for backwards compatibility  
    if (CameraApi.isSetRotationSupported())
    {
         CameraApi.setRotation(p, 90);
    }
}

但是,每次方向改变时,它都会调用 Camera.open()... 您可能知道这是一项相当昂贵的操作,导致转换不那么平滑。

当我将方向强制为横向时,预览效果很好。创建只被调用一次,因为预览是横向的,相机总是用户看到的。但是,我需要一种方法来设置纵向拍摄的实际照片的方向。但是,当我强制横向时,永远不会重新创建表面,并且当相机保持纵向时永远不会设置参数。

那么,我该如何(仅)执行以下操作之一?

  1. 在方向改变时在 onDestroy 和 onCreate 之间按住 m_camera,以便平滑过渡

  2. 强制横向并以另一种方式检测方向变化...旋转最终拍摄的照片(如果保持纵向)。

另外,如果我不在基地,有人可以为我指出更好的方向吗?谢谢。

最佳答案

我实现它的方式:

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

然后在您的 PictureCallback 中设置元数据以指示旋转级别:

    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
                }

            } catch (Exception e) {
                e.printStackTrace();
                // handle exceptions
            }

            mResultIntent = new Intent();
            mResultIntent.setData(uri);
        } catch (Exception e) {
            e.printStackTrace();
        }

        finish();
    }
};

希望对你有帮助。

更新现在,当基于横向的设备出现时,需要在 OrientationEventListener 中对其进行额外检查。

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

完整代码(LC有点浪费,但很容易演示该方法)

@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_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);
    }
}

关于android相机surfaceview方向,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5157984/

相关文章:

ios - 使用 Storyboard 中的自动布局更改横向 View 框架

android - 方向改变崩溃应用程序

html - 通过 html 调用 GPS 应用程序

css - Bootstrap - Android 显示太小

android - Glide ,回收 View : Glide returns the same picture over and over again even with different data inputs

java.lang.IllegalStateException : does not have a NavController set on xxxxx(location address) error 错误

android - Android上的DGPS校正

objective-c - 更改手势识别器位置?

android - 使用摩托罗拉 Moto G(或 Moto X)录制立体声音频

android - 拥有付费和免费版 Android 应用的最佳方式