您好,登錄后才能下訂單哦!
做過類似需求的同學(xué)都知道,在Activity中通過如下代碼可以啟動相機(jī),然后在重寫的onActivityResult方法中可以獲取到返回的照片數(shù)據(jù):
Intent openCameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(openCameraIntent, TAKE_PICTURE);
在onActivityResult方法里通過Intent的getData方法獲取的數(shù)據(jù)轉(zhuǎn)換成bitmap并顯示在界面上,有時候會有取不到數(shù)據(jù),或者顯示的bitmap會非常小,如果將bitmap保存到sd卡后會發(fā)現(xiàn),圖片的分辨率很低,并且圖片大小也是經(jīng)過壓縮的,不管將相機(jī)的像素設(shè)置多高,最后通過這種方式返回的bitmap總是經(jīng)過壓縮了的。如果想獲得理想的照片大小和分辨率改如何處理呢?
大家都知道,現(xiàn)在手機(jī)像素少則500W或800W,多則4KW(某亞),就拿常見的800W像素的相機(jī)拍出來的照片來說,分辨率大概在3200*2400左右,照片大小在2M左右。試想一下,在Android系統(tǒng)中bitmap占用4個字節(jié),3200*2400*4=?,結(jié)果大家自己算算,如果為了一張圖片,耗用這么大的內(nèi)存,肯定是不合理的,并且,官方文檔中有說明,Android系統(tǒng)分配給每個應(yīng)用的最大內(nèi)存是16M,所以,系統(tǒng)為了防止應(yīng)用內(nèi)存占用過大,對于在應(yīng)用內(nèi)通過相機(jī)拍攝的圖片最終返回來的結(jié)果進(jìn)行了壓縮,壓縮后的圖片變得很小,通過之前說的getData的方式只能滿足比如顯示個頭像這樣的需求。
如果要顯示大圖,就會出現(xiàn)模糊的情況。那如何獲取清晰的大圖呢?我的解決思路如下:
1.拍照時,將拍得的照片先保存在本地,通過修改之前的代碼如下:
Uri p_w_picpathUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(),"p_w_picpath.jpg"));
//指定照片保存路徑(SD卡),p_w_picpath.jpg為一個臨時文件,每次拍照后這個圖片都會被替換
openCameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, p_w_picpathUri);
如何調(diào)取相機(jī)拍照,代碼如下:
/**拍照獲取相片**/ private void doTakePhoto() { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); //調(diào)用系統(tǒng)相機(jī) Uri p_w_picpathUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(),"p_w_picpath.jpg")); //指定照片保存路徑(SD卡),p_w_picpath.jpg為一個臨時文件,每次拍照后這個圖片都會被替換 intent.putExtra(MediaStore.EXTRA_OUTPUT, p_w_picpathUri); //直接使用,沒有縮小 startActivityForResult(intent, PHOTO_WITH_CAMERA); //用戶點(diǎn)擊了從相機(jī)獲取 }
2.在onActivityResult方法中再將圖片取出,并經(jīng)過縮小處理再顯示在界面上或上傳給服務(wù)器(壓縮比例自定義)
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { switch (requestCode) { case TAKE_PICTURE: //將保存在本地的圖片取出并縮小后顯示在界面上 Bitmap bitmap = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory()+"/p_w_picpath.jpg"); Bitmap newBitmap = zoomBitmap(bitmap, bitmap.getWidth() / SCALE, bitmap.getHeight() / SCALE); //由于Bitmap內(nèi)存占用較大,這里需要回收內(nèi)存,否則會報out of memory異常 bitmap.recycle(); //將處理過的圖片顯示在界面上,并保存到本地 iv_p_w_picpath.setImageBitmap(newBitmap); savePhotoToSDCard(newBitmap, Environment.getExternalStorageDirectory().getAbsolutePath(), String.valueOf(System.currentTimeMillis())); break; default: break; } } }
由于Android給bitmap分配的內(nèi)存最大不超過8M,所以對使用完的較大的Bitmap要釋放內(nèi)存,調(diào)用其recycle()方法即可。然后將縮小后的bitmap顯示在界面上或保存到SD卡,至于之前保存的原圖,可以刪掉,也可以放在那,下次拍照時,這張原圖就會被下一張照片覆蓋,所以SD卡上使用只有一張臨時圖片,占用也不是很大。
以上講的是拍照獲取圖片,如果是從相冊中獲取圖片又如何處理呢,我的方法如下:
1.打開相冊選取圖片:
Intent openAlbumIntent = new Intent(Intent.ACTION_GET_CONTENT); openAlbumIntent.setType("p_w_picpath/*"); startActivityForResult(openAlbumIntent, CHOOSE_PICTURE);
2.在onActivity方法中處理獲取到的圖片,思路和之前類似
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { switch (requestCode) { case CHOOSE_PICTURE: ContentResolver resolver = getContentResolver(); //照片的原始資源地址 Uri originalUri = data.getData(); try { //使用ContentProvider通過URI獲取原始圖片 Bitmap photo = MediaStore.Images.Media.getBitmap(resolver, originalUri); if (photo != null) { //為防止原始圖片過大導(dǎo)致內(nèi)存溢出,這里先縮小原圖顯示,然后釋放原始Bitmap占用的內(nèi)存 Bitmap smallBitmap = zoomBitmap(photo, photo.getWidth() / SCALE, photo.getHeight() / SCALE); //釋放原始圖片占用的內(nèi)存,防止out of memory異常發(fā)生 photo.recycle(); iv_p_w_picpath.setImageBitmap(smallBitmap); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } break; default: break; } } }
還有一個方法 zoomBitmap(),代碼如下:
/** 縮放Bitmap圖片 **/ public Bitmap zoomBitmap(Bitmap bitmap, int width, int height) { int w = bitmap.getWidth(); int h = bitmap.getHeight(); Matrix matrix = new Matrix(); float scaleWidth = ((float) width / w); float scaleHeight = ((float) height / h); matrix.postScale(scaleWidth, scaleHeight);// 利用矩陣進(jìn)行縮放不會造成內(nèi)存溢出 Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true); return newbmp; }
至此,功能已實(shí)現(xiàn)。
下面是本人項目中所實(shí)現(xiàn)的功能在這里總結(jié)一下:
1.要想對從圖庫選擇的照片進(jìn)行裁剪:
/**從相冊獲取圖片**/ private Intent doPickPhotoFromGallery() { Intent intent = new Intent(); intent.setType("p_w_picpath/*"); // 開啟Pictures畫面Type設(shè)定為p_w_picpath intent.setAction(Intent.ACTION_GET_CONTENT); //使用Intent.ACTION_GET_CONTENT這個Action //實(shí)現(xiàn)對圖片的裁剪,必須要設(shè)置圖片的屬性和大小 intent.setType("p_w_picpath/*"); //獲取任意圖片類型 intent.putExtra("crop", "true"); //滑動選中圖片區(qū)域 intent.putExtra("aspectX", 1); //裁剪框比例1:1 intent.putExtra("aspectY", 1); intent.putExtra("outputX", 300); //輸出圖片大小 intent.putExtra("outputY", 300); intent.putExtra("return-data", true); //有返回值 return intent; }
調(diào)用此方法處:
Intent intent2 = doPickPhotoFromGallery(); startActivityForResult(intent2, PHOTO_WITH_DATA);
ActivityForResult中和上面一樣
2.項目中要拍多少張 就保存多少張,顯示圖片列表:
A.將拍照的照片或者圖庫選擇的圖片,保存到本地
創(chuàng)建圖片名,不能重復(fù)哦!
/** 為圖片創(chuàng)建不同的名稱用于保存,避免覆蓋 **/ public static String createFileName() { String fileName = ""; Date date = new Date(System.currentTimeMillis()); // 系統(tǒng)當(dāng)前時間 SimpleDateFormat dateFormat = new SimpleDateFormat( "'IMG'_yyyyMMdd_HHmmss"); fileName = dateFormat.format(date) + ".jpg"; return fileName; }
保存圖片到SD卡
/**Save p_w_picpath to the SD card**/ public static void savePhotoToSDCard(String path, String photoName, Bitmap photoBitmap) { if (android.os.Environment.getExternalStorageState().equals( android.os.Environment.MEDIA_MOUNTED)) { File dir = new File(path); if (!dir.exists()) { dir.mkdirs(); } File photoFile = new File(path, photoName); //在指定路徑下創(chuàng)建文件 FileOutputStream fileOutputStream = null; try { fileOutputStream = new FileOutputStream(photoFile); if (photoBitmap != null) { if (photoBitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream)) { fileOutputStream.flush(); } } } catch (FileNotFoundException e) { photoFile.delete(); e.printStackTrace(); } catch (IOException e) { photoFile.delete(); e.printStackTrace(); } finally { try { fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }
B.最后就是顯示圖片列表,因為我們要用到listView,自然少不了Adapter了,我們將保存到SD卡上的圖片名獲取到集合中,在自定義的適配器中根據(jù)名字加載圖片嘍!
自定義圖片列表適配器代碼:
/** * 插入圖片列表適配器 * @author ZHF * */ public class ImagesListAdapter extends BaseAdapter { private Context context; private List<String> p_w_picpathsList; //各個圖片的路徑 public ImagesListAdapter(Context context, List<String> p_w_picpathsList) { this.context = context; this.p_w_picpathsList = p_w_picpathsList; } /**得到總的數(shù)量**/ @Override public int getCount() { // TODO Auto-generated method stub return p_w_picpathsList.size(); } /**根據(jù)ListView位置返回View**/ @Override public Object getItem(int position) { return p_w_picpathsList.get(position); //返回當(dāng)前選中的item圖片的路徑 } /**根據(jù)ListView位置得到List中的ID**/ @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; //返回當(dāng)前選中項的Id } /**根據(jù)位置得到View對象**/ @Override public View getView(int position, View convertView, ViewGroup parent) { if(convertView == null) { convertView = LayoutInflater.from(context).inflate(R.layout.newwrite_p_w_picpath_item, null); } ImageView img = (ImageView) convertView.findViewById(R.id.newwrite_et_content_p_w_picpath); //圖片列表項 if(!p_w_picpathsList.get(position).equals("")) {//沒有圖片 Bitmap tempBitmap = BitmapFactory.decodeFile(p_w_picpathsList.get(position));//根據(jù)路徑顯示對應(yīng)的圖片 Bitmap newBitmap = new ImageManager(context).zoomBitmap(tempBitmap, tempBitmap.getWidth(), tempBitmap.getHeight() / 3); img.setImageBitmap(newBitmap);//對應(yīng)的行上顯示對應(yīng)的圖片 } return convertView; } }
ok!完了,在顯示圖片的時候大家可能會碰到OOM(OutOfMemory)異常,在下一篇博客中我會具體解決了一下~
Demo已上傳!下載附件即可!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。