編輯:關於Android編程
最近在做Android的項目,其中部分涉及到圖像處理的內容.這裡先講述如何調用Camera應用程序進行拍照,並截圖和保存顯示在ImageView控件中以及遇到的困難和解決方法.
PS:作者購買了本《Android第一行代碼 著:郭霖》,參照裡面的內容完成(推薦該書,前面的布局及應用非常不錯).網上這類資料非常多,作者僅僅分享給初學者同時在線記錄些內容,希望對大家有所幫助.
首先,設置activity_main.xml為LinearLayout布局且 android:orientation=vertical
然後,在MainActivity.java文件中public class MainActivity extends Activity修改源代碼.添加自定義變量:
//自定義變量 public static final int TAKE_PHOTO = 1; public static final int CROP_PHOTO = 2; private Button takePhotoBn; private ImageView showImage; private Uri imageUri; //圖片路徑 private String filename; //圖片名稱添加函數實現點擊拍照功能:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); takePhotoBn = (Button) findViewById(R.id.button1); showImage = (ImageView) findViewById(R.id.imageView1); //點擊Photo Button按鈕照相 takePhotoBn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //圖片名稱 時間命名 SimpleDateFormat format = new SimpleDateFormat(yyyyMMddHHmmss); Date date = new Date(System.currentTimeMillis()); filename = format.format(date); //創建File對象用於存儲拍照的圖片 SD卡根目錄 //File outputImage = new File(Environment.getExternalStorageDirectory(),test.jpg); //存儲至DCIM文件夾 File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM); File outputImage = new File(path,filename+.jpg); try { if(outputImage.exists()) { outputImage.delete(); } outputImage.createNewFile(); } catch(IOException e) { e.printStackTrace(); } //將File對象轉換為Uri並啟動照相程序 imageUri = Uri.fromFile(outputImage); Intent intent = new Intent(android.media.action.IMAGE_CAPTURE); //照相 intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); //指定圖片輸出地址 startActivityForResult(intent,TAKE_PHOTO); //啟動照相 //拍完照startActivityForResult() 結果返回onActivityResult()函數 } }); if (savedInstanceState == null) { getFragmentManager().beginTransaction() .add(R.id.container, new PlaceholderFragment()) .commit(); } }通過startActivityForResult和onActivityResult方法實現拍照截圖和保存功能:
protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode != RESULT_OK) { Toast.makeText(MainActivity.this, ActivityResult resultCode error, Toast.LENGTH_SHORT).show(); return; } switch(requestCode) { case TAKE_PHOTO: Intent intent = new Intent(com.android.camera.action.CROP); //剪裁 intent.setDataAndType(imageUri, image/*); intent.putExtra(scale, true); //設置寬高比例 intent.putExtra(aspectX, 1); intent.putExtra(aspectY, 1); //設置裁剪圖片寬高 intent.putExtra(outputX, 340); intent.putExtra(outputY, 340); intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); Toast.makeText(MainActivity.this, 剪裁圖片, Toast.LENGTH_SHORT).show(); //廣播刷新相冊 Intent intentBc = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); intentBc.setData(imageUri); this.sendBroadcast(intentBc); startActivityForResult(intent, CROP_PHOTO); //設置裁剪參數顯示圖片至ImageView break; case CROP_PHOTO: try { //圖片解析成Bitmap對象 Bitmap bitmap = BitmapFactory.decodeStream( getContentResolver().openInputStream(imageUri)); Toast.makeText(MainActivity.this, imageUri.toString(), Toast.LENGTH_SHORT).show(); showImage.setImageBitmap(bitmap); //將剪裁後照片顯示出來 } catch(FileNotFoundException e) { e.printStackTrace(); } break; default: break; } }
由於涉及到SD卡中寫數據操作和Camera操作,需要在AndroidMainfest.xml文件中聲明權限:
運行結果如下圖所示:
需要注意以下幾個問題:
1.拍照和截圖都涉及到startActivityForResult和onActivityResult的交互操作.
startActivityForResult( Intent intent, //Intent對象 int requestCode //>=0 當Activity結束時requestCode將歸還在onActivityResult()中 ) onActivityResult( int requestCode, //提供給onActivityResult,以確認返回的數據是從哪個Activity返回的 int resultCode, //由子Activity通過其setResult()方法返回 通常為RESULT_CANCELED或RESULT_OK Intent data //一個Intent對象,帶有返回的數據 )
其中onActivityResult的requestCode和startActivityForResult中的requestCode相對應.同時結合Intent意圖實現拍照和截圖,核心代碼如下:(intent的參數設置省略)
Intent intent = new Intent(android.media.action.IMAGE_CAPTURE);
startActivityForResult(intent,TAKE_PHOTO);
Intent intent = new Intent(com.android.camera.action.CROP);
startActivityForResult(intent, CROP_PHOTO);
2.使用Android拍照保存在系統相冊,圖庫不能立刻顯示最新照片.解決方法是發送系統內置的廣播去刷新相冊實現顯示.代碼如下:
Intent intentBc = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); intentBc.setData(imageUri); this.sendBroadcast(intentBc);
可能你會使用下面這條廣播掃描整個SD卡,但4.4已禁止這樣的操作:
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse(...)))
參考資料 http://blog.csdn.net/xiaanming/article/details/8990627
3.當運行程序是可能會發現結果圖像顯示很小,當通過一個Intent意圖觸發時,Camera程序不會將全尺寸圖像返回給主調活動,這樣需要大量的內存,而移動設備內存會有一定限制.通常Camera將在返回的意圖中返回一幅很小的縮略圖,大圖可能會導致OOM問題.參考:《Android多媒體開發高級編程 著:Shawn Van Every》
針對大圖像Android提供BitmapFactory類,允許通過各種資源加載Bitmap圖像.調用BitmapFactory.Options類可以定義如何將Bitmap讀入內存,當加載圖像時,可設置BitmapFactory采樣大小.並指定inSampleSize參數表明加載時結果Bitmap圖像所占的比例.如inSampleSize=8表明產生一副大小為原始圖像1/8的圖像.參考下面代碼:
if(resultCode==RESULT_OK) { DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); int width = dm.widthPixels; //寬度 int height = dm.heightPixels ; //高度 //加載圖像尺寸而不是圖像本身 BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options(); bmpFactoryOptions.inJustDecodeBounds = true; //bitmap為null 只是把圖片的寬高放在Options裡 int heightRatio = (int)Math.ceil(bmpFactoryOptions.outHeight/(float)height); int widthRatio = (int)Math.ceil(bmpFactoryOptions.outWidth/(float)width); //設置圖片壓縮比例 如果兩個比例大於1 圖像一邊將大於屏幕 if(heightRatio>1&&widthRatio>1) { if(heightRatio>widthRatio) { bmpFactoryOptions.inSampleSize = heightRatio; } else { bmpFactoryOptions.inSampleSize = widthRatio; } } //圖像真正解碼 bmpFactoryOptions.inJustDecodeBounds = false; Bitmap bitmap = BitmapFactory.decodeFile(imageUri.toString(), bmpFactoryOptions); showImage.setImageBitmap(bitmap); //將剪裁後照片顯示出來 }
4.使用nexus 4 剪裁圖片後不能setImageBitmap顯示在ImageView控件中,其中只有保存按鈕,沒有剪裁按鈕.測試發現沒有返回RESULT_OK.這個問題不能解決.Why?
參考:Unable to Save Photo Edits
最後希望文章對大家有所幫助,這是我學習Android圖像處理部分的基礎性文章與解決過程.
參考資料和推薦博文:(都是非常不錯的資料-.-)
《Android第一行代碼》著郭霖 參考8.3 調用攝像頭和相冊
android拍照圖片選取與圖片剪裁 By:Lee_Allen
Android_照相機Camera_調用系統照相機返回data為空 By:strawberry2013
Android圖片剪裁功能實心詳解 By:小馬
Android開發 拍照、圖片集保存照片技巧
Android 拍照並顯示在ImageView中(進階) By:leesa
android調動系統的照相機並把照片顯示在ImageView上
cameraintent data null in onActivityResult(int requestCode, int resultCode, Intentdata)
Android高效加載大圖、多圖解決方案,有效避免程序OOM By:guolin
Android相機、相冊獲取圖片顯示並保存到SD卡 By:唐韌_Ryan
android、獲取本地圖片|直接獲取照相圖片 By:zcljy0318
1. 設置 2.定義變量 3.生成Setter/Getter 4.生成 5.結果
本文實例講述了Android實現給TableLayou繪制邊框的方法。分享給大家供大家參考,具體如下:效果如下:思路:使用share作為背景顯示邊框步驟:1.在res/d
線程的運行機制 1. 開啟線程過多,會消耗cpu2. 單核cpu,同一時刻只能處理一個線程,多核cpu同一時刻可以處理多個線程3. 操作系統為每個運行線程安排一
在android開發中會經常遇到滑動沖突(比如ScrollView或是SliddingMenu與ListView的嵌套)的問題,需要我們深入的了解android事件響應