2011-05-14 10 views
2

Camera APIを使用して画像をキャプチャするアプリケーションがあります。この実装はCameraActivityクラスに含まれています。このクラスは、このサイトで見た多くの例の後にモデル化されています。アプリケーションは現在、何千もの電話機で正しく動作しています。しかし、今日、HTC Desire Zユ​​ーザーから、自分の画像が一連の縦線としてキャプチャされているという報告がありました(残念ながら、画像を投稿するのに十分なポイントがありませんが、 1つを見るのが好きです)。私のアプリケーション内の画像プレビューと私が保存した画像は歪んでいます。ユーザーは自分のアプリケーションの外で電話カメラを問題なく使用できることも確認しました。私はレビューのためにソースを添付しました。HTC Desire Zで撮影した画像は、一連の縦線を表示します。

ご協力いただければ幸いです。

public class CameraActivity extends Activity { 
public static final int FOTO_MODE = 0; 
private SurfaceView preview = null; 
private SurfaceHolder previewHolder = null; 
private Camera camera = null; 
private boolean inPreview = false; 
private String receiptFileName = null; 

SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() { 
    public void surfaceCreated(SurfaceHolder holder) { 
     try { 
      camera.setPreviewDisplay(previewHolder); 
     } catch (Throwable t) { 
      Log.e("PreviewDemo-surfaceCallback", "Exception in setPreviewDisplay()", t); 
      Toast.makeText(CameraActivity.this, t.getMessage(), Toast.LENGTH_LONG).show(); 
     } 
    } 

    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 
     Camera.Parameters parameters = camera.getParameters(); 
     Camera.Size size = getBestPreviewSize(width, height, parameters); 

     if (size != null) { 
      parameters.setPreviewSize(size.width, size.height); 
      parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO); 
      camera.setParameters(parameters); 
      camera.startPreview(); 
      inPreview = true; 
     } 
    } 

    public void surfaceDestroyed(SurfaceHolder holder) { 
     // no-op 
    } 
}; 

Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() { 
    public void onPictureTaken(byte[] imageData, Camera c) { 
     if (imageData != null) { 
      StoreByteImage(CameraActivity.this, imageData, 50, "ImageName"); 
      camera.startPreview(); 
      Intent resultIntent = new Intent(); 
      resultIntent.putExtra(getString(R.string.receiptFileName), receiptFileName); 
      setResult(FOTO_MODE, resultIntent); 
      finish(); 
     } 
    } 
}; 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    requestWindowFeature(Window.FEATURE_NO_TITLE); 
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 
    setContentView(R.layout.camera_preview); 
    receiptFileName = getIntent().getStringExtra(getString(R.string.receiptFileName)); 
    ImageView shutterButton = (ImageView) findViewById(R.id.shutterButton); 
    shutterButton.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      takePicture(); 
     } 
    }); 
    shutterButton.setOnLongClickListener(new View.OnLongClickListener() { 
     @Override 
     public boolean onLongClick(View v) { 
      focusOnly(); 
      return false; 
     } 
    }); 
    preview = (SurfaceView) findViewById(R.id.surface_camera); 
    previewHolder = preview.getHolder(); 
    previewHolder.addCallback(surfaceCallback); 
    previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 
} 

@Override 
public void onResume() { 
    super.onResume(); 
    camera = Camera.open(); 
} 

@Override 
public void onPause() { 
    if (inPreview) { 
     camera.stopPreview(); 
    } 

    camera.release(); 
    camera = null; 
    inPreview = false; 

    super.onPause(); 
} 

private Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters) { 
    Camera.Size result = null; 

    for (Camera.Size size : parameters.getSupportedPreviewSizes()) { 
     if (size.width <= width && size.height <= height) { 
      if (result == null) { 
       result = size; 
      } else { 
       int resultArea = result.width * result.height; 
       int newArea = size.width * size.height; 

       if (newArea > resultArea) { 
        result = size; 
       } 
      } 
     } 
    } 

    return result; 
} 

private void focusOnly() { 
    String focusMode = camera.getParameters().getFocusMode(); 
    if (focusMode != null 
      && (focusMode.equals(Camera.Parameters.FOCUS_MODE_AUTO) || focusMode 
        .equals(Camera.Parameters.FOCUS_MODE_MACRO))) { 
     Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() { 
      public void onAutoFocus(boolean success, Camera camera) { 
      } 
     }; 
     camera.autoFocus(autoFocusCallback); 
    } 
} 

private void takePicture() { 
    camera.takePicture(null, mPictureCallback, mPictureCallback); 
} 

private boolean StoreByteImage(Context mContext, byte[] imageData, int quality, String expName) { 
    String state = Environment.getExternalStorageState(); 
    if (Environment.MEDIA_MOUNTED.equals(state)) { 
     FileOutputStream fileOutputStream = null; 
     try { 
      BitmapFactory.Options options = new BitmapFactory.Options(); 
      options.inSampleSize = 2; 
      Bitmap bMap = BitmapFactory.decodeByteArray(imageData, 0, imageData.length, options); 
      Matrix mat = new Matrix(); 
      mat.postRotate(90); 
      Bitmap myImage = Bitmap.createBitmap(bMap, 0, 0, bMap.getWidth(), bMap.getHeight(), mat, true); 

      File path = new File(Environment.getExternalStorageDirectory() + ExpenseIt.SD_CARD_PATH_EXTENSION); 
      path.mkdirs(); 
      fileOutputStream = new FileOutputStream(path + "/" + determineReceiptName()); 
      BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream); 
      myImage.compress(CompressFormat.JPEG, quality, bos); 
      bos.flush(); 
      bos.close(); 
     } catch (Exception e) { 
      FailureDialogFactory.getInstance().handleFailure(this, "Failure storing camera image.", e); 
     } 
    } else { 
     FailureDialogFactory.getInstance().handleFailure(this, 
       "Unable capture receipts while SD card is not available or phone is connected to computer.", null); 
    } 
    return true; 
} 

private String determineReceiptName() { 
    if (receiptFileName == null) { 
     receiptFileName = Calendar.getInstance().getTimeInMillis() + ".jpg"; 
    } 
    return receiptFileName; 
} 

答えて

2
私はgetSupportedPictureSizes方法がサポートされるサイズの巨大なリストを返されていますが、私のHTCの欲望Sに自分のカメラのプロジェクトで同じ問題で苦労

、私が発見した私はせずにキャプチャすることができた写真「垂直バー」の問題は、デバイスの画面のアスペクト比に最も近いアスペクト比を持つものでした。 例:

私のHTC欲望SはgetSupportedPictureSizesメソッドが呼び出され、次のリストを返します:

2592x1952,2592x1456,2592x1520,2592x1936,2592x1728,2592x1552,2048x1536,2048x1360,2048x1216,2048x1152,2048x1200,1600x1200,1584x1056,1280x960,1280x848,1280x768,1280x720,1280x752,1024x768,640x480,640x416,640x384,640x368,512x384,400x400,272x272 

電話の画面解像度は、次のとおりです。

800x480 
Aspect Ratio: 1.67 

だから私は最大のサイズを使用している場合イメージをキャプチャするgetSupportedPictureSizesメソッドによって返される

2592x1952 
Aspect Ratio: 1.32 

結果:キャプチャされた画像は一連の垂直バーです。 。:(

だから私はCameraPreview exampleにここに与えられたとして、それを行うには、最も効率的な方法handetの画面解像度に最も近い解像度のリストを返すためにgetOptimalPreviewSize方法を変更したが私の作品:

private List getOptimalPictureSizes(List<Size> sizes, int w, int h) { 
    final double ASPECT_TOLERANCE = 0.1; 
    double targetRatio = (double) w/h; 

    Size optimalSize = null; 
    double minDiff = Double.MAX_VALUE; 

    int targetHeight = h; 
    List<Size> finalSizes = new ArrayList(); 
    // First filter out all sizes that have an aspect 
    // tolerance > 0.1 

    for (Size size : sizes) { 
     double ratio = (double) size.width/size.height; 
     if (Math.abs(ratio - targetRatio) < ASPECT_TOLERANCE){ 
      finalSizes.add(size); 
     } 
    } 

    // Remove sizes with same width but more deviation from the 
    // handset's aspect ratio (1.67 in my HTC Desire S) 

    List<Size> absoulteSizes = new ArrayList<Size>(); 
    for(int i=0; i<finalSizes.size()-1; i++){ 
     for(int j=i+1; j<finalSizes.size(); j++){ 
      Size iSize = finalSizes.get(i); 
      Size jSize = finalSizes.get(j); 
      if(iSize.width != jSize.width) 
       continue; 
      double iRatio = (double)iSize.width/iSize.height; 
      double jRatio = (double)jSize.width/jSize.height; 
      if(Math.abs(targetRatio - iRatio) < Math.abs(targetRatio - jRatio)){ 
       absoulteSizes.add(iSize); 
      }else if(Math.abs(targetRatio - iRatio) > Math.abs(targetRatio - jRatio)){ 
       absoulteSizes.add(jSize); 
      } 
      else{ 
       absoulteSizes.add(iSize); 
       absoulteSizes.add(jSize); 
      } 
     } 
    } 
    for(Size s:absoulteSizes){ 
     Log.e("Preview", "COMPUTED::: "+s.width+"x"+s.height); 
    } 
    return absoulteSizes; 
} 

上記の方法は、私に、次のフィルタリングされたリストを与える:

2592x1552 Aspect Ratio: 1.67 
2048x1216 Aspect Ratio: 1.684 
1280x768 Aspect Ratio: 1.67 
640x384 Aspect Ratio: 1.67 

は、すべての4つのサイズが縦棒の問題もなく私のカメラのために正常に動作それは同じ4つのサイズがSで提案されていることに注意することも価値があります。電話機のカメラアプリもトックする。

これが役に立ちます。

+0

アイデアをありがとうが、これは機能しませんでした。あなたのアイデアをgetBestPreviewSize()メソッドに組み込みましたが、結果はまだ垂直線です。 –

+0

@ user657719明確にするために、上記の4つの解像度サイズはsetPreviewSize()メソッドではなく* setPictureSize()メソッドに渡されます。問題を回避する別の方法が見つかりましたか? – Siddharth

+0

メイト、許容誤差を0.1に設定すると、サポートされている画像サイズがすべて1.3のギャラクシーエースのようなデバイスでは機能しなくなります。 – dumbfingers

関連する問題