2014-12-03 120 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自动选择前后相机的最佳图片尺寸;它不检查前后相机选择的尺寸是否具有相同的宽高比。但纵横比必须相同,才能在相同尺寸的图库照片中显示。

相关问题