Android開發 Bitmap圖像處理詳解


前言

  Bitmap開發涉及到方方面面,比如裁剪圖片,壓縮圖片,鏡像圖片,旋轉圖片,各種轉存圖片等等,是必需掌握Android開發技巧,Android開發提供了2個類來實現這些需求,Bitmap類與BitmapFactory類。此博客會持續更新各種實際需求。

將Res位圖資源轉成Bitmap

請注意,使用這個方法會出現Bitmap為null的問題。這個問題可能是因為資源id異常引起的。特別是你使用了分module形式構建的app

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);

將指定文件轉成Bitmap

Bitmap bitmap = BitmapFactory.decodeFile(getContext().getExternalCacheDir() + File.separator + "demo1.png");

將Drawable矢量圖資源轉成Bitmap

    public static Bitmap getBitmapFromDrawable(Context context, @DrawableRes int drawableId) {
        Drawable drawable = ContextCompat.getDrawable(context, drawableId);
        if (drawable instanceof BitmapDrawable) {
            return ((BitmapDrawable) drawable).getBitmap();
        } else if (drawable instanceof VectorDrawable || drawable instanceof VectorDrawableCompat) {
            Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(bitmap);
            drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
            drawable.draw(canvas);
            return bitmap;
        } else {
            throw new IllegalArgumentException("unsupported drawable type");
        }
    }

將Uri轉成Bitmap

    @Override
    public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        //相冊選擇圖片
        if (requestCode == GALLERY_RESULT_CODE && resultCode == RESULT_OK) {
            final Uri uri = data.getData();
            try (InputStream inputStream = getActivity().getApplicationContext().getContentResolver().openInputStream(uri)) {
                Bitmap bitmap = BitmapFactory.decodeStream(inputStream);//得到bitmap
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return;
        }
    }

將Bitmap輸出成文件 

           Bitmap bitmap = BitmapFactory.decodeFile(getContext().getExternalCacheDir() + File.separator + "demo1.png");
                File file = new File(getContext().getExternalCacheDir(), "demo.jpg");
                try (FileOutputStream fileOutputStream = new FileOutputStream(file)) {
                    //參數1:輸出的圖片格式 參數2:輸出圖片的壓縮質量(范圍值為0-100) 參數3:輸出流
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fileOutputStream);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }

鏡像垂直翻轉

        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
        Matrix matrix = new Matrix();
        matrix.postScale(1, -1);   //鏡像垂直翻轉
        Bitmap changBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);

鏡像水平翻轉

        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
        Matrix matrix = new Matrix();
        matrix.postScale(-1, 1);   //鏡像水平翻轉
        Bitmap changBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
        mBinding.weatherIcon.setImageBitmap(changBitmap);

旋轉圖片

        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
        Matrix matrix = new Matrix();
        matrix.postRotate(-90);  //旋轉-90度
        Bitmap changBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
        mBinding.weatherIcon.setImageBitmap(changBitmap);

壓縮圖片質量,降低圖片存儲大小

原理其實很簡單就是利用compress方法,一點一點的降低圖片質量,最后壓縮到需要的目標存儲大小

    /**
     * 壓縮圖片
     * @param bitmap bitmap圖片 壓縮
     * @param targetKB 目標壓縮大小
     * @return
     */
    private Bitmap compressImage(Bitmap bitmap, int targetKB){
        Bitmap outBitmap = null;
        ByteArrayInputStream bais = null;
        ByteArrayOutputStream baos = null;
        try {
            baos = new ByteArrayOutputStream();
            int quality = 80;
            bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
            while ((baos.toByteArray().length/1024) > targetKB){
                quality = quality-10;
                baos.reset();
                bitmap.compress(Bitmap.CompressFormat.JPEG,quality,baos);
            }
            bais = new ByteArrayInputStream(baos.toByteArray());
            outBitmap = BitmapFactory.decodeStream(bais);
            bais.close();
            baos.close();
        } catch (Exception e) {
            e.printStackTrace();
            onError(e);
        } finally {
            try {
                bais.close();
                baos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        return outBitmap;

    }

壓縮圖片尺寸

原理是利用BitmapFactory.decodeStream方法,傳入options,以降冪的方式等比例的壓縮到目標尺寸,關鍵是options.inSampleSize = be;這個屬性的配置

 

/**
     * 尺寸壓縮
     * @param bitmap
     */
    private Bitmap sizeCompres(Bitmap bitmap,float targetWidth,float targetHeight){
        Bitmap handleBitmap = null;
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.JPEG,100,baos);
            // 判斷如果圖片大於1M,進行壓縮避免在生成圖片(BitmapFactory.decodeStream)時溢出
            if (baos.toByteArray().length / 1024 > 1024) {
                baos.reset();// 重置baos即清空baos
                bitmap.compress(Bitmap.CompressFormat.JPEG, 50, baos);// 這里壓縮50%,把壓縮后的數據存放到baos中
            }
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(bais,null,options);
            options.inJustDecodeBounds = false;
            int imageWidth = options.outWidth;
            int imageHeight = options.outHeight;
            int be = 1;
            if (imageWidth>imageHeight && imageWidth>targetWidth){
                be = Math.round(imageWidth/targetWidth);

            }else if (imageHeight>imageWidth && imageHeight>targetHeight){
                be = Math.round(imageHeight/targetHeight);
            }
            if (be <= 1){
                be =1;//如果小於1等於1就不需要壓縮直接返回
            }
            options.inSampleSize = be;
            bais = new ByteArrayInputStream(baos.toByteArray());//bais運行到這里可能已經清空了,所以需要再次添加
            handleBitmap = BitmapFactory.decodeStream(bais,null,options);
            bais.close();
            baos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return handleBitmap;

    }

獲取圖片的角度屬性與將圖片角度屬性設置回去

獲取圖片的角度屬性很重要,這里說明下,因為我們在壓縮或者讀取圖片成Bitmap后在保存到文件里會丟失圖片的角度,這樣下次在查看這張圖片的時候極有可能是倒的圖片

try {
            ExifInterface exifInterface = new ExifInterface(inpPath);//獲取圖片角度
            mDegrees = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1);
            int angle = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1);
            switch (angle){
                case ExifInterface.ORIENTATION_ROTATE_270:
                    mDegrees = 270;

                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    mDegrees = 180;

                    break;
                case ExifInterface.ORIENTATION_ROTATE_90:
                    mDegrees = 90;

                    break;
                default:
                    mDegrees = 0;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

 將圖片角度設置回去

         Matrix matrix = new Matrix();
            matrix.setRotate(mDegrees, bitmap.getWidth(), bitmap.getHeight());
            Bitmap finishBitmap = Bitmap.createBitmap(finishBitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix,true);

 

 

End


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM