1. 程式人生 > >Android圖片壓縮(包含拍照或從相簿選取圖片,PopupWindow的使用)

Android圖片壓縮(包含拍照或從相簿選取圖片,PopupWindow的使用)

目前大部分智慧手機拍照效果好,圖片畫素很高.但是在儲存或傳輸圖片的時候不太方便,需要首先將其進行壓縮.
先看看效果圖.
首介面 彈出PopupWindow選擇拍照或從相簿選取 壓縮前後效果圖對比
注意,最後一張圖片顯示的壓縮前後兩張圖似乎沒有太大區別,但事實上壓縮前圖片為1.6MB,壓縮後只有141KB.(如有需要可以根據原始碼自己對壓縮後圖片大小進行調整,我這裡設定的是壓縮後圖片大小不超過200KB.壓縮後的圖片會儲存在SD卡的PicCompress資料夾下)
完整的原始碼以及下載連結我會在後面給出下載連結,下面我對程式用到的幾個重要的函式進行簡單說明.
首先是圖片壓縮函式.這裡給出了兩個壓縮函式(兩種方式的輸入不一樣,大家可以根據自己的需要進行選擇),第一個函式是compressImage(String path, int size)

   /**
     * 壓縮圖片。
     * @param path  圖片路徑
     * @param size  壓縮後圖片最大尺寸(單位:KB)
     * @return 壓縮後的圖片
     * @throws IOException
     */
    public static Bitmap compressImage(String path, int size)
            throws IOException {
        Bitmap bitmap = null;
        // 取得圖片
        InputStream is = new
FileInputStream(path); BitmapFactory.Options options = new BitmapFactory.Options(); // 這個引數代表,不為bitmap分配記憶體空間,只記錄一些該圖片的資訊(例如圖片大小),說白了就是為了記憶體優化 options.inJustDecodeBounds = true; // 通過建立圖片的方式,取得options的內容(這裡就是利用了java的地址傳遞來賦值) BitmapFactory.decodeStream(is, null, options); // 關閉流
is.close(); // // 生成壓縮的圖片 int i = 0; while (true) { // 這一步是根據要設定的大小,使寬和高都能滿足 if ((options.outWidth >> i <= size) && (options.outHeight >> i <= size)) { // 重新取得流,注意:這裡一定要再次載入,不能二次使用之前的流! is = new FileInputStream(path); // 這個引數表示 新生成的圖片為原始圖片的幾分之一。 options.inSampleSize = (int) Math.pow(2.0D, i); // 這裡之前設定為了true,所以要改為false,否則就建立不出圖片 options.inJustDecodeBounds = false; options.inPreferredConfig = Config.ARGB_8888; // 同時設定才會有效 options.inPurgeable = true; // 當系統記憶體不夠時候圖片自動被回收 options.inInputShareable = true; // 建立Bitmap bitmap = BitmapFactory.decodeStream(is, null, options); break; } i += 1; } return bitmap; }
第二個函式是imageZoom(Bitmap bm, double maxSize)(最後選用的是這種方法)
  /**
     * 縮放圖片到固定檔案大小
     * @param bm  需要縮放的圖片
     * @param maxSize   目標檔案大小,單位:KB
     * @return
     */
    public static Bitmap imageZoom(Bitmap bm, double maxSize) {
        // 圖片允許最大空間 單位:KB
        // 將bitmap放至陣列中,意在bitmap的大小(與實際讀取的原檔案要大)
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bm.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        byte[] b = baos.toByteArray();
        // 將位元組換成KB
        double mid = b.length / 1024;
        // 判斷bitmap佔用空間是否大於允許最大空間 如果大於則壓縮 小於則不壓縮
        if (mid > maxSize) {
            // 獲取bitmap大小 是允許最大大小的多少倍
            double i = mid / maxSize;
            // 開始壓縮 此處用到平方根 將寬頻和高度壓縮掉對應的平方根倍
            // 保持刻度和高度和原bitmap比率一致,壓縮後也達到了最大大小佔用空間的大小
            bm = zoomImage(bm, bm.getWidth() / Math.sqrt(i), bm.getHeight()
                    / Math.sqrt(i));
        }
        return bm;
    }
    /***
     * 圖片的縮放方法
     * 
     * @param bgimage
     *            :源圖片資源
     * @param newWidth
     *            :縮放後寬度
     * @param newHeight
     *            :縮放後高度
     * @return
     */
    public static Bitmap zoomImage(Bitmap bgimage, double newWidth,
            double newHeight) {
        // 獲取這個圖片的寬和高
        float width = bgimage.getWidth();
        float height = bgimage.getHeight();
        // 建立操作圖片用的matrix物件
        Matrix matrix = new Matrix();
        // 計算寬高縮放率
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;
        // 縮放圖片動作
        matrix.postScale(scaleWidth, scaleHeight);
        Bitmap bitmap = Bitmap.createBitmap(bgimage, 0, 0, (int) width,
                (int) height, matrix, true);
        return bitmap;
    }

還有一個重要的函式就是將Bitmap儲存成圖片的函式.本應用將系統時間設為圖片名.最後要注意儲存後通過廣播對相簿進行通知.

public static void saveImageToGallery(Context context, Bitmap bmp) {
        // 首先儲存圖片
        File appDir = new File(Environment.getExternalStorageDirectory(), "PicCompress");
        if (!appDir.exists()) {
            appDir.mkdir();
        }
        Log.d("PICCOMPRESS","資料夾建立成功!");
        String fileName = System.currentTimeMillis() + ".jpg";
        File file = new File(appDir, fileName);
        try {
            FileOutputStream fos = new FileOutputStream(file);
            bmp.compress(CompressFormat.JPEG, 100, fos);
            fos.flush();
            fos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }      
        // 其次把檔案插入到系統圖庫
        try {
            MediaStore.Images.Media.insertImage(context.getContentResolver(),
                    file.getAbsolutePath(), fileName, null);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        // 最後通知相簿更新
        context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" +file.getAbsolutePath())));
        Log.d("PICCOMPRESS","廣播通知相簿成功!");
    }

除此之外PopupWindow的使用也比較重要.PopupWindow整體比較美觀,這裡使用它就是讓使用者選擇拍照獲取圖片還是直接從相簿選取圖片.初始化PopupWindow的方法如下:

private  void initPopWIndow(){
        popupWindow=new PopupWindow(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        View view= LayoutInflater.from(context).inflate(R.layout.popwindow_select_photo,null);

        TextView selectPhoto=(TextView)view.findViewById(R.id.selectPhoto);
        selectPhoto.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                intent.setType("image/*");
                startActivityForResult(Intent.createChooser(intent, "Pick any photo"), RESUEST_SELECT_PHOTO);
            }
        });
        TextView takePhoto=(TextView)view.findViewById(R.id.takePhoto);
        takePhoto.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
                photoFile = bitMapIO.getFullFile();
                //polygonBean.setFileName(photoFile.toString());
                intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
                imageUri = Uri.fromFile(photoFile);
                startActivityForResult(intent, RESUEST_PHOTO);
            }
        });
        TextView cancel=(TextView)view.findViewById(R.id.cancel);
        cancel.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                popupWindow.dismiss();
            }
        });

        popupWindow.setContentView(view);
        popupWindow.setFocusable(true);
        popupWindow.setOutsideTouchable(true);
        ColorDrawable colorDrawable = new ColorDrawable(Color.BLUE);
        popupWindow.setBackgroundDrawable(colorDrawable);
    }   

其他部分,比如佈局檔案什麼的大家直接看原始碼就好.注意要新增幾項許可權:

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

下面是原始碼的下載連結:點選這裡