2014-11-20 65 views
2

我試圖在我的應用程序中設置圖片預覽爲正方形,並使得生成的圖片與預覽完全匹配。但是,圖片和預覽正如下面的屏幕截圖所示。CWAC相機預覽和圖片不匹配

Preview 預覽屏幕截圖

Picture 圖片截圖

屏幕截圖來自一個的Nexus 5運行Android 5.0。我也在三星S3上運行4.4.2進行了測試,看起來,雖然Nexus的圖片捕捉比預覽更多,但在S3上,它似乎只是偏移了(到左上角)預覽。如果需要,我可以從S3發佈圖片。

這裏是我的代碼:

public class MainActivity extends Activity { 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
    if (savedInstanceState == null) { 
     getFragmentManager().beginTransaction() 
       .add(R.id.container, new PlaceholderFragment()) 
       .commit(); 
    } 
} 


@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
    // Inflate the menu; this adds items to the action bar if it is present. 
    getMenuInflater().inflate(R.menu.menu_main, menu); 
    return true; 
} 

@Override 
public boolean onOptionsItemSelected(MenuItem item) { 
    // Handle action bar item clicks here. The action bar will 
    // automatically handle clicks on the Home/Up button, so long 
    // as you specify a parent activity in AndroidManifest.xml. 
    int id = item.getItemId(); 

    //noinspection SimplifiableIfStatement 
    if (id == R.id.action_settings) { 
     return true; 
    } 

    return super.onOptionsItemSelected(item); 
} 

/** 
* A placeholder fragment containing a simple view. 
*/ 
public static class PlaceholderFragment extends CameraFragment { 

    private FrameLayout cameraPreviewLayout; 
    private Camera camera; 

    @Override 
    public void onCreate(Bundle state) { 
     super.onCreate(state); 

     SimpleCameraHost.Builder builder= 
       new SimpleCameraHost.Builder(new TestCameraHost(getActivity())); 

     setHost(builder.useFullBleedPreview(true).build()); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
          Bundle savedInstanceState) { 
     View cameraView= 
       super.onCreateView(inflater, container, savedInstanceState); 
     View rootView = inflater.inflate(R.layout.fragment_main, container, false); 

     cameraPreviewLayout = ((FrameLayout)rootView.findViewById(R.id.camera_layout)); 
     cameraPreviewLayout.addView(cameraView); 

     ImageButton changeLayout = (ImageButton) rootView.findViewById(R.id.pick_existing); 
     changeLayout.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 

      } 
     }); 

     Button takePicture = (Button) rootView.findViewById(R.id.shutter_button); 
     takePicture.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       PictureTransaction xact = new PictureTransaction(getHost()); 
       takePicture(xact); 
      } 
     }); 

     return(rootView); 
    } 

    @Override 
    public void onResume() { 
     // Get the window width to make the camera preview window square 
     DisplayMetrics metrics = new DisplayMetrics(); 
     getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics); 
     final int windowWidth = metrics.widthPixels; 
     cameraPreviewLayout.post(new Runnable() { 
      @Override 
      public void run() { 
       ViewGroup.LayoutParams params = cameraPreviewLayout.getLayoutParams(); 
       params.height = windowWidth; 
       cameraPreviewLayout.setLayoutParams(params); 
      } 
     }); 

     super.onResume(); 
    } 

    @Override 
    public void onPause() { 
     if (camera != null) { 
      camera.release(); 
     } 
     super.onPause(); 
    } 

    private class TestCameraHost extends SimpleCameraHost { 
     public TestCameraHost(Context context) { 
      super(context); 
     } 

     @Override 
     public void saveImage(PictureTransaction xact, byte[] image) { 

      DisplayActivity.imageToShow = image; 
      DisplayActivity.x = (int) cameraPreviewLayout.getX(); 
      DisplayActivity.y = (int) cameraPreviewLayout.getY(); 
      DisplayActivity.height = (int) cameraPreviewLayout.getHeight(); 
      DisplayActivity.width = (int) cameraPreviewLayout.getWidth(); 
      startActivity(new Intent(getActivity(), DisplayActivity.class)); 

     } 
    } 
} 

}

public class DisplayActivity extends Activity { 
static byte[] imageToShow=null; 
static int x = 0; 
static int y = 0; 
static int width = 0; 
static int height = 0; 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    if (imageToShow == null) { 
     Toast.makeText(this, "no image!", Toast.LENGTH_LONG).show(); 
     finish(); 
    } 
    else { 
     ImageView iv=new ImageView(this); 
     BitmapFactory.Options opts=new BitmapFactory.Options(); 

     opts.inPurgeable=true; 
     opts.inInputShareable=true; 
     opts.inMutable=false; 
     opts.inSampleSize=2; 

     Bitmap bitmap = BitmapFactory.decodeByteArray(imageToShow, 
       0, imageToShow.length, opts); 
     Bitmap croppedBitmap = Bitmap.createBitmap(bitmap, x, y, width, height); 

     iv.setImageBitmap(croppedBitmap); 
     imageToShow=null; 

     iv.setScaleType(ImageView.ScaleType.CENTER_INSIDE); 
     setContentView(iv); 
    } 
} 

}

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:tools="http://schemas.android.com/tools" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
tools:context=".MainActivity$PlaceholderFragment"> 

<FrameLayout 
    android:id="@+id/camera_layout" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"/> 

<RelativeLayout 
    android:id="@+id/footer" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:layout_alignParentBottom="true" 
    android:padding="16dp" 
    android:background="#ffffff"> 

    <ImageButton 
     android:id="@+id/pick_existing" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentLeft="true" 
     android:layout_centerVertical="true" 
     android:src="@drawable/ic_launcher"/> 

    <Button 
     android:id="@+id/shutter_button" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_centerInParent="true" 
     android:text="Take picture"/> 

    <ToggleButton 
     android:id="@+id/flash_toggle" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentRight="true" 
     android:padding="20dp" 
     android:layout_centerVertical="true" 
     android:textOff="" 
     android:textOn=""/> 

    </RelativeLayout> 
</RelativeLayout> 

我已經與adjustPreviewParameters嘗試,但似乎沒有要任何選擇,允許我把預覽設置爲方形。

我可以做我想做的事嗎?

+0

有關此問題的任何更新?我把我的頭髮拉出類似的問題! – Chris 2015-01-21 13:37:31

+0

@Chris我還沒有完全實現一個解決方案。下面的1個答案可能證明是有用的,儘管我沒有試圖完全實現它,並且我不確定我是否理解它。我已經提到了一個人,我認爲這些東西比我更擅長這方面的專家,他對它的可行性有一些擔憂。不過,您可能想直接聯繫答案海報。 – hBrent 2015-01-22 00:04:28

+0

非常感謝Brent的更新!我認爲我和你有同樣的問題 - 我不知道我理解解決方案哈哈。如果我找到解決方案,我會將其報告給您 – Chris 2015-01-22 07:14:20

回答

3
  1. in getPreviewSize()必須選擇一個提供的比例,而不是1:1。我會尋找一個4:3,這將提供最廣泛的相機視圖。

  2. in getPictureSize()必須選擇其中一個分辨率爲相同的預覽尺寸。否則,輸出結果可能會完全不同。

  3. 使用FrameLayout或RelativeLayout,以便您可以有兩層:底層是CameraView,上層將有一個正方形的透明視圖,並且保留是「阻塞」區域。如果將「塊視圖」設置爲半透明顏色,則會理解原因。

  4. 最佳比對使用爲4:3(不是16:9)

  5. 最後,最好的和最簡單的方法是使用/從圖像裁剪頂部正方形區域。使用中心區域似乎是合理的,但使用頂部廣場將爲您節省很多麻煩。

測試平臺:索尼的Xperia Z,安卓4.2.2

測試分辨率:1080×1920

預覽可用:1280×720960x720,720×480,704×576 ,640×480,分辨率480x320,320×240,176×144。

目標預覽尺寸:1080x1080,方形,當然:d

測試裏面我的自定義CameraHost的CameraHost.getPreviewSize()來完成。

  1. 如果我在這裏提供一個方形圖/尺寸超類函數,我得到704×576。它是11:9(或1.22222),最接近1:1或1.0。但是,當放大到1080寬度時,它看起來很模糊,並且也變形。

  2. 1280x720是16:9(1.777〜)。設備相機通過裁剪頂部和底部(請注意,相機正在以橫向模式交談)。

  3. 960x720是4:3(1.333〜)。這是設備相機的完整分辨率。這是我的目標分辨率,我只需要960x720內的720x720朝向頂部邊緣(人像)或左邊緣(橫向)。

  4. 在您的自定義CameraHost(延伸SimpleCameraHost),限制預覽大小:

    @Override 
    public Size getPreviewSize(int orientation, int w, int h, Parameters p) { 
        Size size = super.getPreviewSize(orientation, 720, 960, p); 
        ViewGroup.LayoutParams params = cameraView.getLayoutParams(); 
        params.width = 1080; 
        params.height = 960 * 1080/720; 
        cameraView.setLayoutParams(params); 
        return size; 
    } 
    
  5. layout.xml:

    <FrameLayout 
        android:layout_width="match_parent" 
        android:layout_height="match_parent"> 
        <com.commonsware.cwac.camera.CameraView 
         android:id="@+id/cameraView" 
         android:layout_width="match_parent" 
         android:layout_gravity="top|center_horizontal" 
         android:layout_height="match_parent"/> 
        <LinearLayout 
         android:layout_width="match_parent" 
         android:layout_height="match_parent" 
         android:orientation="vertical"> 
         <com.example.android.widget.SquareView 
          android:layout_width="match_parent" 
          android:layout_height="match_parent" 
          android:background="@android:color/transparent"/> 
         <LinearLayout 
          android:layout_width="match_parent" 
          android:layout_height="0dp" 
          android:layout_weight="1" 
          android:orientation="vertical" 
          android:background="#99e0e0e0"> 
          (your elements to cover up the extra area) 
         </LinearLayout> 
        </LinearLayout> 
    </FrameLayout> 
    

以下是結果,並與系統比較相機,使用4:3。

Screen using this codeDefault camera app with 4:3

注:

  1. 我想你知道如何創建自己的SquareView所以我不會在這裏發佈了它的代碼。你可以在這裏閱讀更多:Simple way to do dynamic but square layout
  2. #4中的代碼段只是測試代碼 - 你需要弄清楚它如何適應所有設備。
  3. 不要接受CameraView的點擊事件以進行對焦。改用SquareView。
+0

感謝您的詳細解答。這可能需要我花一些時間來吸收所有這些,但是我有必要在相機預覽上放置一個方形「窗口」來顯示方形區域作爲用戶可以實際看到的預覽。讓我試着實現這一點,並看到它在我對你的答案採取進一步行動之前完成了我所需要的。 – hBrent 2014-11-24 16:54:59

+0

@hBrent當然。慢慢來。如果遇到任何問題,請隨時告訴我。我正在開展一個類似要求的項目。所以,我願意與你分享任何經驗。 – 2014-11-27 21:27:36