溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

【移動開發(fā)】Android相機(jī)、相冊獲取圖片顯示并保存到SD卡

發(fā)布時間:2020-06-30 19:18:38 來源:網(wǎng)絡(luò) 閱讀:22006 作者:zhf651555765 欄目:開發(fā)技術(shù)

   做過類似需求的同學(xué)都知道,Activity中通過如下代碼可以啟動相機(jī),然后在重寫的onActivityResult方法中可以獲取到返回的照片數(shù)據(jù):

Intent openCameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(openCameraIntent, TAKE_PICTURE);

    在onActivityResult方法里通過IntentgetData方法獲取的數(shù)據(jù)轉(zhuǎn)換成bitmap并顯示在界面上,有時候會有取不到數(shù)據(jù),或者顯示的bitmap會非常小,如果將bitmap保存到sd卡后會發(fā)現(xiàn),圖片的分辨率很低,并且圖片大小也是經(jīng)過壓縮的,不管將相機(jī)的像素設(shè)置多高,最后通過這種方式返回的bitmap總是經(jīng)過壓縮了的。如果想獲得理想的照片大小和分辨率改如何處理呢?

    大家都知道,現(xiàn)在手機(jī)像素少則500W800W,多則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;
            }
        }
    }

由于Androidbitmap分配的內(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已上傳!下載附件即可!










向AI問一下細(xì)節(jié)

免責(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)容。

AI