1. 程式人生 > >android呼叫照相機拿到原圖

android呼叫照相機拿到原圖

轉自:原地址
本文主要講解的是儲存拍照後的圖片到系統預設資料夾下,並在日後使用系統自帶 相簿 應用時可以方便的看到。
本文主要內容:
1、呼叫系統相機拍照並存儲;
2、處理大圖片防止記憶體溢位(OOM);
3、獲取系統預設照片路徑並儲存;
4、刷新系統相簿,解決相簿不能立刻顯示最新照片的問題;
5、圖片裁剪;
6、圖片大小及尺寸調整。

隨著《證件照片助手》http://www.eoemarket.com/soft/165173.html 這一工具類應用的開發和上線,個人的程式碼能力又得到了一些提高,積累了一些經驗。現將用到的難點和一些小技巧分享給大家,望各位前輩批評指正!
呼叫系統相機,不用多說,網上已經有很多的例子了。當然,為了完整性,做再次說明:
首先,在要呼叫相機的程式碼位置,寫上以下內容:

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(new File(AppConf.BUFFER_FILE)));
startActivityForResult(intent, requestCode_camera);

這裡有幾點需要注意:
1、MediaStore.ACTION_IMAGE_CAPTURE和MediaStore.EXTRA_OUTPUT是MediaStore類的常量,這個類是安卓系統提供的多媒體相關的類;
2、AppConf.BUFFER_FILE是呼叫系統相機拍照成功並經過使用者確認後生成的照片的儲存路徑。當然,你也可以直接把這個路徑定義到系統預設相簿路徑上。這裡是為了應用需要,使用了臨時的目錄來存放照片。有關係統預設相簿路徑和後續處理,請直接往後看;
3、requestCode_camera是為了標識從系統相簿返回的。
然後,在回撥方法onActivityResult()中,處理系統相機返回的資料。

    if (requestCode == requestCode_camera) {
        try {
           BitmapFactory.Options options = new BitmapFactory.Options();
            options.inTempStorage = new byte[1024 * 1024 * 2];
            options.inSampleSize = 2;
            Bitmap bitmap = BitmapFactory.decodeFile(AppConf.BUFFER_FILE,
                    options);
            if (bitmap != null) {
                ResizeActivity.bitmap = bitmap;
                startActivity(new Intent(MenuActivity.this,
                        ResizeActivity.class));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

這裡,紫色文字部分是防止圖片過大溢位的處理,使用了2MB的大小操作,這樣避免了因圖片過大造成OOM。灰色文字部分是本應用需要,可以忽略。
至此,我們就可以拿到使用者剛剛拍照的照片的Bitmap物件了。
說到系統相簿的預設路徑,估計大家想到的應該是那個叫做“DCIM”的資料夾。這個一點都沒錯,我們可以直接用”/mnt/sdcard/DCIM”。可是,還有很多手機的路徑是“/storage/sdcard0/DCIM”,特別是在4.1及以上的系統中。為了統一,可以用下面的方法來獲取路徑:

Environment.getExternalStorageDirectory() + File.separator + Environment.DIRECTORY_DCIM

這樣就能獲取系統的照片檔案夾了。
下面我們就將剛剛生成好的Bitmap物件儲存到這個目錄下:

public static void save(Bitmap bitmap, Context context, Activity activity) {
     // 調整到100*130
    Matrix matrix = new Matrix();
    matrix.postScale(100f / bitmap.getWidth(), 130f / bitmap.getHeight());
    bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
            bitmap.getHeight(), matrix, true);
   int option = 100;
    FileOutputStream photo = null;
    File file = new File(AppConf.PHOTO_WRITE_PATH);
    file.mkdir();
    String str = null;
    Date date = null;
    SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
    date = new Date(System.currentTimeMillis());
    str = format.format(date);
    fileName = AppConf.PHOTO_WRITE_PATH + File.separator
            + "ht_choosephoto_" + str + ".jpg";
    try {
        photo = new FileOutputStream(fileName);
        bitmap.compress(Bitmap.CompressFormat.JPEG, option, photo);
        photo.flush();
        MediaStore.Images.Media.insertImage(context.getContentResolver(),
                fileName, new File(fileName).getName(),
                new File(fileName).getName());
        Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        Uri uri = Uri.fromFile(new File(fileName));
        intent.setData(uri);
        activity.sendBroadcast(intent);
        while (new File(fileName).length() / 1024 >= 19) {
            option -= 10;
            photo = new FileOutputStream(fileName);
            bitmap.compress(Bitmap.CompressFormat.JPEG, option, photo);
            photo.flush();
        }
        ResizeActivity.mhandler.sendEmptyMessage(0);
        bitmap.recycle();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

這個方法的功能有三個:
1、調整照片尺寸以符合2寸電子照片標準;
2、限制圖片大小20KB以內;
3、儲存圖片;
4、刷新系統相簿。
如果在程式中不去刷新系統相簿的話,剛剛儲存的圖片是無法及時在相簿應用中顯示的。可使用快圖這樣的軟體卻能看得到,可是,我們不能指望每個使用者都去安裝第三方的圖片瀏覽器。為了使程式更加好用,新增重新整理的操作還是很有必要的。
這裡我們做一個延伸思考:可以發現,刷新系統相簿的操作實際上就是傳送了系統內建的廣播。也就是說,我們可以虛假髮送系統的廣播(尚未驗證可用性)。所以在我們以後每次要傳送這樣的廣播的時候,務必不要發錯了,以免造成一些很奇怪的狀況。
關於圖片裁剪,首先看一下效果圖:

Android開發 拍照、圖片及儲存照片技巧

效果是這樣的:中間的調整部分實際上是一個ImageView,這個ImageView上面放置了一個只有白色邊框的透明度圖片,ImageView四周是由4個帶有灰色背景的ImageView包裹的。這樣一來,使用者就可以清楚的分辨出白框內的影象就是裁剪後要儲存的圖片了。
思路是這樣的:首先對整個螢幕進行截圖,然後獲取中間ImageView的座標及控制元件大小,最後只要儲存這個ImageView的截圖就OK了。
具體實現是這樣的:

int width = cutWindow.getRight() - cutWindow.getLeft();
int height = cutWindow.getBottom() - cutWindow.getTop();
// 截圖
View view = getWindow().getDecorView();
Display display = ResizeActivity.this.getWindowManager().getDefaultDisplay();
view.layout(0, 0, display.getWidth(), display.getHeight());
view.setDrawingCacheEnabled(true);
Bitmap tempbmp = Bitmap.createBitmap(view.getDrawingCache());
// 裁剪
Bitmap bmp = Bitmap.createBitmap(tempbmp, display.getWidth()/ 2 - width / 2 + 2,display.getHeight() / 2 - height/ 2 + 2, width - 4, height - 4);

對於Bitmap物件bmp的處理還需注意:由於裁剪後得到的是ImageView的截圖,因此四周的白框仍然是有的。我們需要減去1-2個畫素來去掉四周的白框。