android 自定義照相機

做了一個dome,內容和功能都很簡單,當練練手

部分代碼參考了一個博客任何自己添加了一些項目的功能,具體那個博客忘記了,不好意思。

具體就是調用系統的攝相機拍照保存到手機,以後返回相片的文件地址

效果圖:





照相界面的佈局文件:

 <SurfaceView   
        android:id="@+id/surfaceView"  
        android:layout_width="match_parent"  
        android:layout_height="match_parent"  
        />  
    <!-- 相對佈局,放置兩個按鈕 -->

        <RelativeLayout
            android:id="@+id/buttonLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:visibility="visible" >
            <FrameLayout
	            android:id="@+id/fra_shade_top"
	            android:layout_width="match_parent"
	            android:layout_height="150dp"
	            android:layout_alignParentTop="true"
	            android:background="#000000" />

      	 	<FrameLayout
	            android:id="@+id/fra_shade_bottom"
	            android:layout_width="match_parent"
	            android:layout_height="150dp"
	            android:layout_alignParentBottom="true"
	            android:background="#000000" />
			
			<TableLayout
	            android:id="@+id/table1"
	            android:layout_width="fill_parent"
	            android:layout_height="wrap_content"
	            android:layout_alignParentBottom="true"
	            android:padding="4dip"
	            android:stretchColumns="*" >

            <TableRow>

                <Button
                    android:id="@+id/bnt_enter"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="確認" />

                <Button
                    android:id="@+id/bnt_takepicture"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="拍照" />

                <Button
                    android:id="@+id/bnt_cancel"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="5dp"
                    android:text="取消" />
            </TableRow>
       		</TableLayout>

        </RelativeLayout>
其中SurfaceView是用於顯示照相機的圖像的。

RelativeLayout是相機的遮罩(設定視圖的大小,我這裏是1:1正方形)

下面是照相機調用和圖片保存類:


/**
 * 
 * 自定義相機控件
 * 
 * @author Nickey
 * @date 2014.11.29
 *
 */
public class MainActivity extends Activity implements OnClickListener{
	  private Button bntTakePic;
	  private Button bntEnter;
	  private Button bntCancel;
	  private SurfaceView surfaceView ;
	  private FrameLayout fraShadeTop;
	  private FrameLayout fraShadeBottom;
	  private Camera camera;  
	  private Camera.Parameters parameters = null;  
	  private WindowManager mWindowManager;
	  private int windowWidth ;//獲取手機屏幕寬度
	  private int windowHight ;//獲取手機屏幕高度
	  private String savePath = "/finger/";
	  private Bundle bundle = null;// 聲明一個Bundle對象,用來存儲數據    
	  private int IS_TOOK = 0;//是否已經拍照 ,0爲否
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		init();
		getActionBar().hide();
		
		
	}
	
	@SuppressWarnings("deprecation")
	private void init(){
		mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
		windowWidth = mWindowManager.getDefaultDisplay().getWidth();
		windowHight = mWindowManager.getDefaultDisplay().getHeight();
		fraShadeTop = (FrameLayout)findViewById(R.id.fra_shade_top);
		fraShadeBottom = (FrameLayout)findViewById(R.id.fra_shade_bottom);
		RelativeLayout.LayoutParams topParams =(RelativeLayout.LayoutParams) fraShadeTop.getLayoutParams();
		topParams.width = windowWidth;
		topParams.height =(windowHight - windowWidth) / 2;
		fraShadeTop.setLayoutParams(topParams);
		fraShadeTop.getBackground().setAlpha(200);
		
		RelativeLayout.LayoutParams bottomParams =(RelativeLayout.LayoutParams) fraShadeBottom.getLayoutParams();
		bottomParams.width = windowWidth;
		bottomParams.height =(windowHight - windowWidth) / 2;
		fraShadeBottom.setLayoutParams(bottomParams);
		fraShadeBottom.getBackground().setAlpha(200);
		
		//按鈕
		bntTakePic = (Button)findViewById(R.id.bnt_takepicture);
		bntEnter = (Button)findViewById(R.id.bnt_enter);
		bntCancel = (Button)findViewById(R.id.bnt_cancel);
		
		bntTakePic.setVisibility(View.VISIBLE);
		bntEnter.setVisibility(View.INVISIBLE);
		bntCancel.setVisibility(View.INVISIBLE);
		bntTakePic.setOnClickListener(this);
		bntEnter.setOnClickListener(this);
		bntCancel.setOnClickListener(this);
		
		//照相機預覽的空間
		surfaceView = (SurfaceView) this
				.findViewById(R.id.surfaceView);
		surfaceView.getHolder()
				.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		surfaceView.getHolder().setFixedSize(150, 150); // 設置Surface分辨率
		surfaceView.getHolder().setKeepScreenOn(true);// 屏幕常亮
		surfaceView.getHolder().addCallback(new SurfaceCallback());// 爲SurfaceView的句柄添加一個回調函數
	}
	
	/**
	 * 三個按鈕點擊事件
	 */
	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		switch (v.getId()) {  
	        case R.id.bnt_takepicture:  
	            // 拍照  
	        	 if (camera != null) {
	        		 camera.takePicture(null, null, new MyPictureCallback());  
	        	 }
	            break;  
	        
			case R.id.bnt_enter:
				 if (bundle == null) {  
	                 Toast.makeText(getApplicationContext(), "bundle null",  
	                         Toast.LENGTH_SHORT).show();  
	             } else {  
	                 try {
	                	if (isHaveSDCard())
	                		saveToSDCard(bundle.getByteArray("bytes"));
	                	else
	                		saveToRoot(bundle.getByteArray("bytes"));
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
	                    	
						finish();
	             }  
	             break; 
			case R.id.bnt_cancel:
				 bntTakePic.setVisibility(View.VISIBLE);
	             bntCancel.setVisibility(View.INVISIBLE);
	             bntEnter.setVisibility(View.INVISIBLE);
				 if (camera != null) {
					 IS_TOOK = 0;
					 camera.startPreview();
				 }
			 break;
		}   
	}

	/**
	 * 檢驗是否有SD卡
	 * @true or false
	 */
	public static boolean isHaveSDCard() {
		return Environment.MEDIA_MOUNTED.equals(Environment
				.getExternalStorageState());
	}
    
	/**
	 * 重構照相類
	 * @author 
	 *
	 */
    private final class MyPictureCallback implements PictureCallback {  
    	
        @Override  
        public void onPictureTaken(byte[] data, Camera camera) {  
            try {  
                bundle = new Bundle();  
                bundle.putByteArray("bytes", data); //將圖片字節數據保存在bundle當中,實現數據交換  
                
           //     saveToSDCard(data); // 保存圖片到sd卡中  
                Toast.makeText(getApplicationContext(), "success",  
                        Toast.LENGTH_SHORT).show();  
                bntTakePic.setVisibility(View.INVISIBLE);
                bntCancel.setVisibility(View.VISIBLE);
                bntEnter.setVisibility(View.VISIBLE);
              //  camera.startPreview(); // 拍完照後,重新開始預覽  
                IS_TOOK = 1;
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
        }  
    }  
	
    /** 
     * 將拍下來的照片存放在SD卡中 
     * @param data   
     * @throws IOException 
     */  
    public void saveToSDCard(byte[] data) throws IOException {  
    	//剪切爲正方形
    	Bitmap b = byteToBitmap(data);
    	Bitmap bitmap = Bitmap.createBitmap(b, 0, 0, windowWidth, windowWidth ); 
    	//生成文件
        Date date = new Date();  
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); // 格式化時間  
        String filename = format.format(date) + ".jpg";  
        File fileFolder = new File(Environment.getExternalStorageDirectory()  
                + savePath);  
        if (!fileFolder.exists()) { // 如果目錄不存在,則創建一個名爲"finger"的目錄  
            fileFolder.mkdir();  
        }  
        File jpgFile = new File(fileFolder, filename);  
        FileOutputStream outputStream = new FileOutputStream(jpgFile); // 文件輸出流  
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
        outputStream.flush();

        
     //   out.close();
      //  outputStream.write(data); // 寫入sd卡中  
        outputStream.close(); // 關閉輸出流  
        Intent intent = new Intent();
        intent.putExtra("path",Environment.getExternalStorageDirectory() + savePath + filename);
		setResult(1, intent);
    }  
    
    /**
     * 
     */
    public void saveToRoot(byte[] data) throws IOException {  
    	//剪切爲正方形
    	Bitmap b = byteToBitmap(data);
    	Bitmap bitmap = Bitmap.createBitmap(b, 0, 0, windowWidth, windowWidth ); 
    	//生成文件
        Date date = new Date();  
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); // 格式化時間  
        String filename = format.format(date) + ".jpg";  
        File fileFolder = new File(Environment.getRootDirectory()  
                + savePath);  
        if (!fileFolder.exists()) { // 如果目錄不存在,則創建一個名爲"finger"的目錄  
            fileFolder.mkdir();  
        }  
        File jpgFile = new File(fileFolder, filename);  
        FileOutputStream outputStream = new FileOutputStream(jpgFile); // 文件輸出流  
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
        outputStream.flush();

        
     //   out.close();
      //  outputStream.write(data); // 寫入sd卡中  
        outputStream.close(); // 關閉輸出流  
        Intent intent = new Intent();
        intent.putExtra("path",Environment.getExternalStorageDirectory() + savePath + filename);
		setResult(1, intent);
    }  
    
    
    
    /**
     * 把圖片byte流編程bitmap
     * @param data
     * @return
     */
	private Bitmap byteToBitmap(byte[] data){
    	Options options = new BitmapFactory.Options();
    	options.inJustDecodeBounds = true;
    	Bitmap b = BitmapFactory.decodeByteArray(data, 0, data.length,options);
		int i = 0;
		while (true) {
			if ((options.outWidth >> i <= 1000)
					&& (options.outHeight >> i <= 1000)) {
				options.inSampleSize = (int) Math.pow(2.0D, i);
				options.inJustDecodeBounds = false;
				b = BitmapFactory.decodeByteArray(data, 0, data.length,options);
				break;
			}
			i += 1;
		}
		return b;

    }
    
	/**
	 * 重構相機照相回調類
	 * @author pc
	 *
	 */
    private final class SurfaceCallback implements Callback {

		@SuppressWarnings("deprecation")
		@Override
		public void surfaceChanged(SurfaceHolder holder, int format, int width,
				int height) {
			// TODO Auto-generated method stub
			parameters = camera.getParameters(); // 獲取各項參數  
            parameters.setPictureFormat(PixelFormat.JPEG); // 設置圖片格式  
            parameters.setPreviewSize(width, height); // 設置預覽大小  
            parameters.setPreviewFrameRate(5);  //設置每秒顯示4幀  
            parameters.setPictureSize(width, height); // 設置保存的圖片尺寸  
            parameters.setJpegQuality(80); // 設置照片質量  
          //  camera.setParameters(parameters);
		}

		@Override
		public void surfaceCreated(SurfaceHolder holder) {
			// TODO Auto-generated method stub
			try {  
                camera = Camera.open(); // 打開攝像頭  
                camera.setPreviewDisplay(holder); // 設置用於顯示拍照影像的SurfaceHolder對象  
                camera.setDisplayOrientation(getPreviewDegree(MainActivity.this));  
                camera.startPreview(); // 開始預覽  
            } catch (Exception e) {  
                e.printStackTrace();  
            }  
		}

		@Override
		public void surfaceDestroyed(SurfaceHolder holder) {
			// TODO Auto-generated method stub
			if (camera != null) {  
                camera.release(); // 釋放照相機  
                camera = null;  
            }  
		} 
    	
    	
    	
    }
    

  /**
   * 物理按鍵事件
   */
      
    @Override  
    public boolean onKeyDown(int keyCode, KeyEvent event) {  
        switch (keyCode) {  
        case KeyEvent.KEYCODE_CAMERA: // 按下拍照按鈕  
            if (camera != null && event.getRepeatCount() == 0) {  
                // 拍照  
                //注:調用takePicture()方法進行拍照是傳入了一個PictureCallback對象——當程序獲取了拍照所得的圖片數據之後  
                //,PictureCallback對象將會被回調,該對象可以負責對相片進行保存或傳入網絡  
                camera.takePicture(null, null, new MyPictureCallback());  
            } 
        case KeyEvent.KEYCODE_BACK:
        	if (IS_TOOK == 0)
        		finish();
        	else{
        	//	camera.startPreview();
        		bntCancel.performClick();
        		return false;
        	}
        	
        	break;
        	
        }  
        
        return super.onKeyDown(keyCode, event);  
    }  
    
    // 提供一個靜態方法,用於根據手機方向獲得相機預覽畫面旋轉的角度  
    public static int getPreviewDegree(Activity activity) {  
        // 獲得手機的方向  
        int rotation = activity.getWindowManager().getDefaultDisplay()  
                .getRotation();  
        int degree = 0;  
        // 根據手機的方向計算相機預覽畫面應該選擇的角度  
        switch (rotation) {  
        case Surface.ROTATION_0:  
            degree = 90;  
            break;  
        case Surface.ROTATION_90:  
            degree = 0;  
            break;  
        case Surface.ROTATION_180:  
            degree = 270;  
            break;  
        case Surface.ROTATION_270:  
            degree = 180;  
            break;  
        }  
        return degree;  
    }  
    
    


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

	/**
	 * 通過文件地址獲取文件的bitmap
	 * @param path
	 * @return
	 * @throws IOException
	 */
	
	public static Bitmap getBitmapByPath(String path) throws IOException {
		BufferedInputStream in = new BufferedInputStream(new FileInputStream(
				new File(path)));
		BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		BitmapFactory.decodeStream(in, null, options);
		in.close();
		int i = 0;
		Bitmap bitmap = null;
		while (true) {
			if ((options.outWidth >> i <= 1000)
					&& (options.outHeight >> i <= 1000)) {
				in = new BufferedInputStream(
						new FileInputStream(new File(path)));
				options.inSampleSize = (int) Math.pow(2.0D, i);
				options.inJustDecodeBounds = false;
				bitmap = BitmapFactory.decodeStream(in, null, options);
				break;
			}
			i += 1;
		}
		return bitmap;
	}


}



具體的使用很簡單,就是普通的activity間的調用和回調(startActivityForResult);



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章