2015年11月29日 星期日

Camera 與 Gallery 使用

--------------------------------------------
1. Camera
--------------------------------------------

Android中應用相機功能,一般有兩種:

 - Method 1:調用系統相機,使用Intent跳轉到系統相機,action
    在 manifests xml 中 加入 Camera 權限 和 外部存取權限 來抓取相機拍照後所回傳的結果相片。

       <uses-permission android:name="android.permission.CAMERA" />
       <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

     - 在 Main.java 中所使用的 function 方法:
    private final static int CAMERA = 66 ;

    // get Display Height and Widht pixel
    private DisplayMetrics metrics; 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // 抓取 display 變數 
        metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);
    }

    private void goCamera() {
        // Start an intent for Camera Capture with ResultActivity
        Intent cameraIntent = new Intent(
                android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
        try {
            cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, getImageUri());
            if (cameraIntent.resolveActivity(getPackageManager()) != null) {
                startActivityForResult(cameraIntent, CAMERA);  //設定回傳 resultCode
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

            // Put and Draw Selected Photo in SurfaceView
            Uri imageUri = null;
            InputStream inputStream = null;
            if ( requestCode == CAMERA ){
                // 將拍照完的圖片儲存再 m_imagePath 路徑內,以便讀圖編輯
                try {
                    if (data!=null){
                        // 其他相機程式回傳的 uri
                        imageUri = data.getData();
                    } else {
                        // 內建相機程式回傳的 uri
                        File file = new File(m_imagePath);
                        imageUri = Uri.fromFile(file);
                    }
                    inputStream = getContentResolver().openInputStream(imageUri);
                    try {
                        Bitmap getbp =  ScaleLoadBitmapByOption(getBytesFromInputStream(inputStream), 
                                                                                               metrics.widthPixels,
                                                                                               metrics.heightPixels);

                    }catch (OutOfMemoryError e) {
//                    Toast.makeText(Phone2.this, "Out Of Memory", Toast.LENGTH_SHORT).show();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            }
    }

- Method 2. 自己寫的相機
    1. SurfaceView顯示照相機中的預覽效果,        - Camera類提供:
            a. 一個 setPreviewDisplay( SurfaceHolder ) 的方法來連接 surfaceHolder, 並通過他來控制 surfaceView。
            b. startPreview() 和 stopPreview() 來開启和關閉預覽.
    2. 開启相機.Camera.open() 這是個靜態方法,如果相機沒有別人用着,則會返回一個 相機引用,如果被人用着,則會拋出異常。
    3. 不能放在構造方法或者 onCreate() 方法中,會照成沒有預覽效果.
    4. 當開始拍照時,會依次調用:
            a. shutter的onShutter()方法,  shutter--拍照瞬間調用
            b. raw的onPictureTaken方法 ,  raw--獲得沒有壓縮過的圖片數據
            c. jpeg的onPictureTaken方法 . jpeg---返回jpeg的圖片數據

    5. 透過控制裝置相機,來拍好圖片。
            a. 其設置相關的参數:
                Camera.Parameters parames = myCamera.getParameters();        //獲得参數對象
                parames.setPictureFormat(PixelFormat.JPEG);                             //設置圖片格式
                parames.setPreviewSize(640,480);                                                 //這裏面的参數只能是幾個特定的参數,否則會報錯.                                                                                                                                                                                    //(176*144,320*240,352*288,480*360,640*480)
                myCamera.setParameters(parames);
            b. 自動對焦方法:
                myCamera.autoFocus();                                                                   //這個方法必須在startPreview()和stopPreview()中間。(有些手機沒有此功能)
                AutoFocusCallback是自動對焦的接口,實現它必須實現public void onAutoFocus(boolean success, Camera camera)這個方法

- 在 manifests xml 中 加入 Camera 權限 和 外部存取權限 來抓取相機拍照後所回傳的結果相片。
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera.autofocus" />

 - CameraTest_4.java - 
import android.app.Activity;  
....
import android.view.View.OnClickListener;  

public class CameraTest_3 extends Activity implements Callback, OnClickListener, AutoFocusCallback {  

     SurfaceView mySurfaceView;         //surfaceView聲明  
     SurfaceHolder holder;                     //surfaceHolder聲明  
     Camera myCamera;                      //相機聲明  
     String filePath="/sdcard/wjh.jpg";    //照片保存路徑  
     boolean isClicked = false;               //是否點擊標識  

     //創建jpeg圖片回調數據對象 
     PictureCallback jpeg = new PictureCallback() {   
          
        @Override  
        public void onPictureTaken(byte[] data, Camera camera) {   
            // TODO Auto-generated method stub  
             try  {// 獲得圖片  
                    Bitmap bm = BitmapFactory.decodeByteArray(data, 0, data.length);   
                    File file = new File(filePath);   
                    BufferedOutputStream bos =  new BufferedOutputStream(new FileOutputStream(file));  
                    bm.compress(Bitmap.CompressFormat.JPEG, 100, bos);//將圖片壓縮到流中  
                     bos.flush();//輸出   
                    bos.close();//關閉   
            }catch(Exception e)   {   
                e.printStackTrace();  
            } 
        }   
    };  

    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState); 
        requestWindowFeature(Window.FEATURE_NO_TITLE);                                              //無標題  
        this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);   //設置拍攝方向  
        setContentView(R.layout.main);  

        mySurfaceView = (SurfaceView)findViewById(R.id.surfaceView1);                                //獲得控件  
        holder = mySurfaceView.getHolder();                                                                              //獲得句柄 

        holder.addCallback(this);                                                                                                 //添加回調
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);                          //設置類型 
        mySurface.setOnClickListener(this);                                                                               //設置監聽 
    }

    @Override  
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {   
        // TODO Auto-generated method stub   
        //設置参數並開始預覽  
        Camera.Parameters params = myCamera.getParameters();  
        params.setPictureFormat(PixelFormat.JPEG);   
        params.setPreviewSize(640,480);   
        myCamera.setParameters(params);   
        myCamera.startPreview();  
    }  

    @Override   
    public void surfaceCreated(SurfaceHolder holder) {  
        // TODO Auto-generated method stub  
        //開启相機  
        if(myCamera == null)  {   
            myCamera = Camera.open();  
            try {  
                myCamera.setPreviewDisplay(holder);  
            } catch (IOException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
             }  
        }           
    }  

    @Override   
    public void surfaceDestroyed(SurfaceHolder holder) {  
        // TODO Auto-generated method stub   
        //關閉預覽並釋放資源  
        myCamera.stopPreview();  
        myCamera.release();   
        myCamera = null;           
    }  

    @Override  
    public void onClick(View v) {  
        // TODO Auto-generated method stub  
        if(!isClicked)  {   
            myCamera.autoFocus(this);//自動對焦   
            isClicked = true;   
        }else  {  
             myCamera.startPreview();//開启預覽  
             isClicked = false;  
        }          
    }

    @Override  
    public void onAutoFocus(boolean success, Camera camera) {  
        // TODO Auto-generated method stub  
        if(success)  {  
            //設置参數,並拍照  
             Camera.Parameters params = myCamera.getParameters();   
             params.setPictureFormat(PixelFormat.JPEG);  
             params.setPreviewSize(640,480);  
             myCamera.setParameters(params);   
             myCamera.takePicture(null, null, jpeg);  
        }  
    }  
}


參考資料:







--------------------------------------------
2. Gallery
--------------------------------------------

讀取 Android gallery 中 相簿相片:

    在 manifests xml 中 加入 外部存取權限 來抓取相簿後所回傳的結果相片。
       <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

     - 在 Main.java 中所使用的 function 方法:
    private final static int PHOTO= 66 ;

    // get Display Height and Widht pixel
    private DisplayMetrics metrics; 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // 抓取 display 變數 
        metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);
    }

    private void goAlbums() {
        // Start an intent for user Albums with ResultActivity
        Intent intent = new Intent();
        intent.setType("image/*");
        intent.setAction(Intent.ACTION_GET_CONTENT);
        startActivityForResult(intent, PHOTO);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

            Uri imageUri = null;
            InputStream inputStream = null;
            if (requestCode == PHOTO && data != null)
            {
                try{
                    imageUri = data.getData();
                    inputStream = getContentResolver().openInputStream(imageUri);
                    try {
                         Bitmap getbp = ScaleLoadBitmapByOption(getBytesFromInputStream(inputStream), // bytes[]
                                                                                               metrics.widthPixels,
                                                                                               metrics.heightPixels));
                    }catch (OutOfMemoryError e) {
//                    Toast.makeText(Phone2.this, "Out Of Memory", Toast.LENGTH_SHORT).show();
                    }
                } catch (IOException e) {
//                Toast.makeText(Phone2.this, "File Error", Toast.LENGTH_SHORT).show();
                    e.printStackTrace();
                }
            }
    }





--------------------------------------------
3. Sub-Function 
--------------------------------------------

    //--------------------------------------------
    // LoadFileToBitmap and TransFileToBytes
    //--------------------------------------------
    private Bitmap ScaleLoadBitmapByOption(byte[] data, int dspW, int dspH){
//        //Only decode image size. Not whole image
//        BitmapFactory.Options options = new BitmapFactory.Options();
//        options.inJustDecodeBounds = true;
//        BitmapFactory.decodeByteArray(data, 0, data.length, options);
//        //The new size to decode to dspW and dspH
//        //Now we have image width and height. We should find the correct scale value. (power of 2)
//        int width=options.outWidth;   //
//        int height=options.outHeight;
//        float scale = 0;
//        if (width > dspW || height > dspH){
//            if (height > width){
//                scale = height/dspH;
//            }else if (width > height){
//                scale = width/dspW;
//            }
//        }else{
//            scale = 1;
//        }
        //Decode again with inSampleSize
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inPurgeable = true;
        options.inInputShareable = true;
//        options.inSampleSize=(int)scale;
        return BitmapFactory.decodeByteArray(data, 0, data.length, options);
    }
    private static byte[] getBytesFromInputStream(InputStream is) throws IOException {
        ByteArrayOutputStream outstream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024]; //
        int len = -1;
        while ((len = is.read(buffer)) != -1) {
            outstream.write(buffer, 0, len);
        }
        outstream.close();
        return outstream.toByteArray();
    }


參考資料:

沒有留言:

張貼留言