2014-12-03 159 views
0

我正在開發一個Android應用程序,使用Android相機API打開預覽並從中拍攝照片。該應用程序只能在肖像模式下工作,並且必須可以同時使用設備的前置攝像頭和後置攝像頭(如果設備具有兩個攝像頭)。使用Android相機拍攝的照片的奇怪尺寸

我已經在我的應用程序中打開預覽,我已經正確設置了顯示方向(使用方法旋轉90度的方向:mCamera.setDisplayOrientation(90)),以便可以在縱向模式下查看應用程序預覽,並且我添加了按鈕,可以在前後攝像頭之間切換。所有這些東西在應用程序中正常工作。

問題是當我拍照時:爲了以正確的方式(以肖像)旋轉拍攝的照片,我將設備的方向設爲對角,並將圖片旋轉爲所需的方向。但是,當照片保存到圖庫中時,照片尺寸很奇怪:如果使用前置相機拍攝,則照片尺寸爲全屏,而不是使用後置照相機拍攝。我的目標是始終全屏照相。

這兩個屏幕截圖顯示的問題:

---後相機的照片:

BACK-CAMERA PHOTO

---前置攝像頭PHOTO:

FRONT-CAMERA PHOTO

這裏,有我的CameraPreview代碼:

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 

    if (mHolder.getSurface() == null){ 
     return; 
    } 

    try { 
     mCamera.stopPreview(); 
    } catch (Exception e){ 
    } 

    try { 
     // Start preview in portrait mode 
     mCamera.setDisplayOrientation(90); 

     // Set the list of supported preview size in the related variable 
     if(mCamera != null){ 
      if(mCamera.getParameters().getSupportedPreviewSizes() != null){ 
       mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes(); 
      } 
     } 

     // Get the parameters of camera 
     Camera.Parameters parameters = mCamera.getParameters(); 

     // Set output format to NV21 (which is guranteed to be supported on all devices) 
     parameters.setPreviewFormat(ImageFormat.NV21); 

     // Set the correct preview size (after applying the getOptimalPreviewSize) 
     if(mPreviewSize != null) { 
      parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); 
      Log.d(TAG,"Preview size is ("+mPreviewSize.width+";"+mPreviewSize.height+")"); 
      // initializing bitmap and pixels 
      bitmap = Bitmap.createBitmap(mPreviewSize.width, mPreviewSize.height, Bitmap.Config.ARGB_8888); 
      pixels = new int[mPreviewSize.width * mPreviewSize.height]; 
     } 

     // Correct the size - orientation of picture taken 
     if(isTablet(getContext()) == Boolean.FALSE){ 
      onOrientationChanged(getScreenRotationOnPhone(),parameters); 
     }else{ 
      onOrientationChanged(getScreenRotationOnTablet(),parameters); 
     } 

     mCamera.setPreviewDisplay(mHolder); 
     // Set to turn the Flash ON 
     // parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); 

     mCamera.setParameters(parameters); 
     mCamera.setPreviewDisplay(mHolder); 
     mCamera.startPreview(); 

     // Call the setPreviewCallback and onPreviewFrame to get the incoming frame 
     mCamera.setPreviewCallback(new Camera.PreviewCallback() { 
      @Override 
      public void onPreviewFrame (byte[] data, Camera camera){ 
       Log.i(TAG, "Ma entro nella onPreviewFrame?"); 
       Camera.Parameters parameters = mCamera.getParameters(); 
       int format = parameters.getPreviewFormat(); 
       Log.i(TAG, "Il formato del frame e': " + format); 
       //YUV formats require more conversion 
       if (format == ImageFormat.NV21 || format == ImageFormat.YUY2 || format == ImageFormat.NV16) { 
        int w = parameters.getPreviewSize().width; 
        int h = parameters.getPreviewSize().height;       
       } 
      } 
     }); 

    } catch (Exception e){ 
     Log.d(TAG, "Error starting camera preview: " + e.getMessage()); 
    } 
} 

private int getScreenRotationOnPhone() { 
    final Display display = ((WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); 

    if(display.getRotation() == Surface.ROTATION_0){ 
     System.out.println("SCREEN_ORIENTATION_PORTRAIT"); 
     return Surface.ROTATION_0; 
    }else if(display.getRotation() == Surface.ROTATION_90){ 
     System.out.println("SCREEN_ORIENTATION_LANDSCAPE"); 
     return Surface.ROTATION_90; 
    }else if(display.getRotation() == Surface.ROTATION_180){ 
     System.out.println("SCREEN_ORIENTATION_REVERSE_PORTRAIT"); 
     return Surface.ROTATION_180; 
    }else if(display.getRotation() == Surface.ROTATION_270){ 
     System.out.println("SCREEN_ORIENTATION_REVERSE_LANDSCAPE"); 
     return Surface.ROTATION_270; 
    }else{ 
     System.out.println("SCREEN_ORIENTATION_NOT_ADMISSIBLE"); 
     return -1; 
    } 
} 

private int getScreenRotationOnTablet() { 
    final Display display = ((WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); 

    if(display.getRotation() == Surface.ROTATION_0){ 
     System.out.println("SCREEN_ORIENTATION_LANDSCAPE"); 
     return Surface.ROTATION_0; 
    }else if(display.getRotation() == Surface.ROTATION_90){ 
     System.out.println("SCREEN_ORIENTATION_REVERSE_PORTRAIT"); 
     return Surface.ROTATION_90; 
    }else if(display.getRotation() == Surface.ROTATION_180){ 
     System.out.println("SCREEN_ORIENTATION_REVERSE_LANDSCAPE"); 
     return Surface.ROTATION_180; 
    }else if(display.getRotation() == Surface.ROTATION_270){ 
     System.out.println("SCREEN_ORIENTATION_PORTRAIT"); 
     return Surface.ROTATION_270; 
    }else{ 
     System.out.println("SCREEN_ORIENTATION_NOT_ADMISSIBLE"); 
     return -1; 
    } 
} 

public boolean isTablet(Context context) { 
    boolean xlarge = ((context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == 4); 
    boolean large = ((context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_LARGE); 
    return (xlarge || large); 
} 

public void onOrientationChanged(int orientation, Camera.Parameters mParameters) { 
    android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); 
    android.hardware.Camera.getCameraInfo(CameraActivity.getOpenedCamera(), info); 
    Log.i(TAG, "onOrientationChanged -> Camera opened actually is: "+CameraActivity.getOpenedCamera()); 
    orientation = (orientation + 45)/90 * 90; 
    int rotation = 0; 
    if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { 
     rotation = (info.orientation - orientation + 360) % 360; 
    } else { // back-facing camera 
     rotation = (info.orientation + orientation) % 360; 
    } 
    Log.i(TAG, "onOrientationChanged -> Orientation of pictures setted to: "+rotation); 
    mParameters.setRotation(rotation); 
} 

在這裏,有CameraActivity的onPictureTaken代碼,切換攝像頭的方法:使用工具的這種方法

@Override 
public void onPictureTaken(byte[] data, Camera camera) { 
    // TODO Auto-generated method stub 
    File pictureFile = Utility.getOutputMediaFile(); 
    if (pictureFile == null){ 
     Toast.makeText(this, "Couldn't create file", Toast.LENGTH_SHORT).show(); 
     Log.d(TAG,"Couldn't create file"); 
     return;//? 
    }else{ 
     try{ 
      FileOutputStream fos = new FileOutputStream(pictureFile); 
      fos.write(data); 
      fos.flush(); 
      fos.close(); 
     } 
     catch (FileNotFoundException e){ 
      Toast.makeText(this, "File not found exception", Toast.LENGTH_SHORT).show(); 
      Log.d(TAG,"File not found: "+e.getMessage()); 
     } 
     catch (IOException e){ 
      Toast.makeText(this, "IO Exception", Toast.LENGTH_SHORT).show(); 
      Log.d(TAG, "Error accessing file: "+e.getMessage()); 
     } 
     //Per farle comparire subito nella cartella le foto: 
     this.mPictureFile = pictureFile; 
     MediaScannerConnection.scanFile(getApplicationContext(), 
       new String[]{this.mPictureFile.toString()}, null, 
       new MediaScannerConnection.OnScanCompletedListener() { 
        public void onScanCompleted(String path, Uri uri) { 
         Log.i(TAG, "ExternalStorage Scanned " + path + ":"); 
         Log.i(TAG, "ExternalStorage -> uri=" + uri); 
        } 
       }); 
     camera.startPreview(); 
     imageSaved.sendEmptyMessage(0); 
    } 
} 

public void switchCam(){ 
    if (hasFrontCam == Boolean.TRUE && hasBackCam == Boolean.TRUE) { 
     // The phone has front camera and back camera 
     if(openedCam==Camera.CameraInfo.CAMERA_FACING_BACK){ 
      //Chiudi la preview 
      if (mCamera!=null){ 
       mCamera.setPreviewCallback(null); 
       mCamera.stopPreview(); 
       mCamera.release(); 
       mCamera = null; 
      } 
      //Apri la nuova camera 
      mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT); 
      init(); 
      openedCam=Camera.CameraInfo.CAMERA_FACING_FRONT; 
     }else{ 
      //openedCam==Camera.CameraInfo.CAMERA_FACING_FRONT 
      //Chiudi la preview 
      if (mCamera!=null){ 
       mCamera.setPreviewCallback(null); 
       mCamera.stopPreview(); 
       mCamera.release(); 
       mCamera = null; 
      } 
      //Apri la nuova camera 
      mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK); 
      //riprendi la preview 
      init(); 
      openedCam=Camera.CameraInfo.CAMERA_FACING_BACK; 
     } 
    } 
} 

/** Create a File for saving an image */ 
public static File getOutputMediaFile(){ 
    String state = Environment.getExternalStorageState(); 
    if(state.equals(Environment.MEDIA_MOUNTED)){ 
     File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyApp"); 
     if (!mediaStorageDir.exists()){ 
      if (!mediaStorageDir.mkdirs()){ 
       Log.d(TAG,"Failed to create directory"); 
       return null; 
      } 
     } 
     // Create a media file name 
     String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); 
     File mediaFile; 
     mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg"); 
     return mediaFile; 
    }else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { 
     Log.d(TAG,"External storage not writable but only readable"); 
     return null; 
    }else{ 
     Log.d(TAG,"External storage not writable"); 
     return null; 
    } 
} 

有人可以幫助我解決這個問題?

+0

我注意到圖片翻轉了。是對的嗎? – hasan83 2014-12-03 10:04:29

+0

在前後凸輪之間切換的代碼在哪裏。 – hasan83 2014-12-03 10:08:49

+0

是的,圖片被翻轉以糾正其保存到Gallery中的方向。改變的作品,實際上照片的方向是正確的。我還添加了切換攝像頭的方法。 – user140888 2014-12-03 10:24:48

回答

0

我已經解決了這個問題。

我在支持的背面和前置攝像頭的圖片尺寸列表中找到了解決方案。

就我而言,我使用的是三星S4的開發,並支持圖片尺寸列表中,爲後相機,是:

0) (4128*3096) aspect_ratio=1.333 ---> Choosen automatically 
1) (4128*2322) aspect_ratio=1.777 
2) (3264*2448) aspect_ratio=1.333 
3) (3264*1836) aspect_ratio=1.777 
4) (2048*1536) aspect_ratio=1.333 
5) (2048*1152) aspect_ratio=1.777 
6) (1280*720) aspect_ratio=1.777 
7) (640*480) aspect_ratio=1.777 

對於前置攝像頭:

0) (1920*1080) aspect_ratio=1.777 ---> Choosen automatically 
1) (1440*1080) aspect_ratio=1.333 
2) (1280*720) aspect_ratio=1.777 
3) (960*720) aspect_ratio=1.333 
4) (720*480) aspect_ratio=1.5 
5) (640*480) aspect_ratio=1.333 
6) (320*240) aspect_ratio=1.333 

假設尺寸是(寬度;高度),寬高比計算如下:寬度/高度。

Android自動選擇前後相機的最佳圖片尺寸;它不檢查前後相機選擇的尺寸是否具有相同的寬高比。但縱橫比必須相同,才能在相同尺寸的圖庫照片中顯示。

相關問題