28

Tamam ben SurfaceView uzanır veandroid kamera SurfaceView yönelim

surfaceChanged geçersiz kılan bir sınıf var bu yüzden - düzenlemeleri surfaceHolder
surfaceDestroyed setleri, * params, kamerayı açar - - sadece startPreview
surfaceCreated çağırır stopPreview, salma kamera

çağırır surfaceCreated dan

*

: yönelimi Dikey olduğunda çünkü

bu tüm büyük çalışır

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

Ancak, yönlendirme her değiştiğinde Camera.open() ... diyebileceğimiz gibi, oldukça pahalı bir işlemdir ve geçişlerin bu kadar pürüzsüz olmamasına neden olur.

Yönlendirmeyi yatayya zorladığımda önizleme harika. Yalnızca önizleme manzarada olduğu için çalışan bir kere çağrılır, kamera her zaman kullanıcının gördüğü şeydir. Bununla birlikte, portre sırasında çekilen gerçek resmin yönünü belirlemenin bir yoluna ihtiyacım var. Manzarayı zorladığımda, yüzey yeniden oluşturulmaz ve kamera portre çekildiğinde hiçbir zaman parametreler ayarlanmaz.

Aşağıdakilerden birini (münhasıran) nasıl yapabilirim? OnDestroy ve onCreate arasındaki m_camera üzerine

  1. Tut yönünü değiştirip geçiş pürüzsüz

  2. Kuvvet manzara ve yönünü tespit olduğunu başka bir yol ... son snaped resmini dönen değişmesini sağlayın düzenlenen eğer portre

Ayrıca, eğer üs durumundaysam, birisi bana daha iyi bir yönde işaret edebilir mi? Teşekkür ederim.

+2

+1 Ayrıca bununla ilgileniyorum. Varsayılan google kamera uygulaması bunu güzel bir şekilde gerçekleştirir: etkinliği yeniden oluşturmaz, ancak düğmeler ve son resim önizlemesi, manzara/portre yönlendirmesine uyacak şekilde güzel bir şekilde döndürülür. Btw, _p.set ("yönlendirme", "portre") _, benim anlayışımda, gizli bir API kullanımı ve resmi olarak desteklenmiyor, değil mi? – Audrius

+0

Acctuallyually bir şey yapmaz sanmıyorum, lol. Tercih ettiğim yöntem manzarayı zorlamaktı. Sorun, bir şekilde yönelimi başka bir şekilde tespit etmem gerektiğidir, çünkü kameraActivite yeniden yaratılmayacaktır. –

+0

Ah, aklında ne olduğunu görüyorum. Böylece kamera aktivitesini bir manzaraya zorlar ve ardından * gerçek * yönelimine bağlı olarak bir resmi döndürürsünüz, değil mi? [Bu] (http://android-er.blogspot.com/2010/08/orientationeventlistener-detect.html) size yardımcı olabilir. Bu kötü bir fikir değil, gidip kendim uygulayabilirim (-. – Audrius

cevap

57

bunu uygulamaya yol:

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

Ve sonra rotasyon seviyesini belirtmek için PictureCallback seti metaverilerde: Ben yardımcı olur umarım

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

.

UPDATE Şimdi, peyzaj tabanlı aygıtlar için bir ek denetim göründüğünde, OrientationEventListener'da gereklidir.

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

Tam kod surfaceChanged arayabilirler

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

Varsayılan kamera aktivitesini kullanarak bitirdim, ancak bu iyi görünüyor, başka bir zamanda buna geri dönebilirim. Teşekkür ederim. –

+2

dürüst, farklı android telefonlardaki varsayılan kamera etkinliği ile ilgili tüm tutarsızlıklar nedeniyle kendi kamera aktivitesini uygulamıştım ve etrafta dolaşmak için her türlü hack yapmayı düşünmüyordum. – Audrius

+0

@Audrius düğmelerle basit bir özel kamera oluşturdum ama kameranın 4 tarafında kamerayı döndürmem gerekiyor ... bunu nasıl yapmalıyım? –

17

API doc sağlanan thats, standart yöntem kullanılarak düşündünüz mü, (kolayca biraz LC tarafından savurgan, ancak bir yaklaşım göstermektedir)? Resmi kaydederken daha sonra kullanmak için dereceleri global değişkende saklayabilirsiniz. Ayrıca, kamera değişkeni üzerinde basit bir boş denetleyici de yapabilir, böylece yüzeyi yeniden oluşturmayacaksınız.

public void setCameraDisplayOrientation() 
{   
    if (mCamera == null) 
    { 
     Log.d(TAG,"setCameraDisplayOrientation - camera null"); 
     return;    
    } 

    Camera.CameraInfo info = new Camera.CameraInfo(); 
    Camera.getCameraInfo(CAM_ID, info); 

    WindowManager winManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); 
    int rotation = winManager.getDefaultDisplay().getRotation(); 

    int degrees = 0; 

    switch (rotation) 
    { 
     case Surface.ROTATION_0: degrees = 0; break; 
     case Surface.ROTATION_90: degrees = 90; break; 
     case Surface.ROTATION_180: degrees = 180; break; 
     case Surface.ROTATION_270: degrees = 270; break; 
    } 

    int result; 
    if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) 
    { 
     result = (info.orientation + degrees) % 360; 
     result = (360 - result) % 360; // compensate the mirror 
    } else { // back-facing 
     result = (info.orientation - degrees + 360) % 360; 
    } 
    mCamera.setDisplayOrientation(result); 
} 
+0

Eğer uygulamaya devam ederseniz, lütfen CAM_ID'nin başka bir yere koyduğum global bir değişken olduğunu not edin: – OriginalCliche

+2

Yukarıdaki kod benim için çalışmıyor .. ** Samsung S2 ** 'de test edildi. – swiftBoy

+0

SetCameraDisplayOrientation() öğesini SurfaceCreaeted/surfaceChanged veya onResume – Nepster

2

Diğer yanıtlardan da görüldüğü gibi, bu kod çok karmaşık hale gelir. , CWAC-Kamera OS 2.3 destekler ve yukarı Sen (umarım 2.2 desteği şimdi OS 2.1 ve OS bırakabilirsiniz) Örneğin, bu özelliği sağlamaya yardımcı olacak bir kitaplığı kullanarak araştırmak isteyebilirsiniz:
https://github.com/commonsguy/cwac-camera

CWAC-Kamera kamera önizlemesini yatay olarak kilitlemeyi destekler ve görüntüleri sizin için düzeltme yönüne otomatik olarak döndürür. Çözülmesi gereken tüm aygıt sorunlarına bir göz atmak isterseniz, bu kodun tamamını korumak ve kendinizi sınamak yerine bir kitaplığı kullanmaya çalışmak için daha fazla neden olan IMO'nun nedenleri project issues'a göz atın.

İlgili konular