Android截屏方案

Android截屏

已整理為Android library,請大家移步--->ScreenShotTools
Android截屏的原理:獲取具體需要截屏的區域的Bitmap,然后繪制在畫布上,保存為圖片后進行分享或者其它用途

在截屏功能中,有時需要截取全屏的內容,有時需要截取超過一屏的內容(比如:Listview,Scrollview,RecyclerView)。下面介紹各種場景獲取Bitmap的方法

普通截屏的實現

獲取當前Window的DrawingCache的方式,即decorView的DrawingCache

/**
   * shot the current screen ,with the status but the status is trans *
   *
   * @param ctx current activity
   */
  public static Bitmap shotActivity(Activity ctx) {

    View view = ctx.getWindow().getDecorView();
    view.setDrawingCacheEnabled(true);
    view.buildDrawingCache();

    Bitmap bp = Bitmap.createBitmap(view.getDrawingCache(), 0, 0, view.getMeasuredWidth(),
        view.getMeasuredHeight());

    view.setDrawingCacheEnabled(false);
    view.destroyDrawingCache();

    return bp;
  }

獲取當前View的DrawingCache

public static Bitmap getViewBp(View v) {
        if (null == v) {
            return null;
        }
        v.setDrawingCacheEnabled(true);
        v.buildDrawingCache();
        if (Build.VERSION.SDK_INT >= 11) {
            v.measure(MeasureSpec.makeMeasureSpec(v.getWidth(),
                    MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
                    v.getHeight(), MeasureSpec.EXACTLY));
            v.layout((int) v.getX(), (int) v.getY(),
                    (int) v.getX() + v.getMeasuredWidth(),
                    (int) v.getY() + v.getMeasuredHeight());
        } else {
            v.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
            v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
        }
        Bitmap b = Bitmap.createBitmap(v.getDrawingCache(), 0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());

        v.setDrawingCacheEnabled(false);
        v.destroyDrawingCache();
        return b;
    }

開源方案

在滾動視圖中,如果當前View并沒有在視圖中全部繪制出來,我們可以利用View的ScrollTo()和ScrollBy()方法來移動畫布,同時獲取當前View的可視部分的DrawingCache,最后進行拼接得到其Bitmap,參考:PGSSoft/scrollscreenshot@[Github]

Scrollview截屏

三個截屏中,ScrollView最簡單,因為ScrollView只有一個childView,雖然沒有全部顯示在界面上,但是已經全部渲染繪制,因此可以直接 調用scrollView.draw(canvas)來完成截圖


  public static Bitmap shotScrollView(ScrollView scrollView) {
    int h = 0;
    Bitmap bitmap = null;
    for (int i = 0; i < scrollView.getChildCount(); i++) {
      h += scrollView.getChildAt(i).getHeight();
      scrollView.getChildAt(i).setBackgroundColor(Color.parseColor("#ffffff"));
    }
    bitmap = Bitmap.createBitmap(scrollView.getWidth(), h, Bitmap.Config.RGB_565);
    final Canvas canvas = new Canvas(bitmap);
    scrollView.draw(canvas);
    return bitmap;
  }

listview截屏

而ListView就是會回收與重用Item,并且只會繪制在屏幕上顯示的ItemView,根據stackoverflow上大神的建議,采用一個List來存儲Item的視圖,這種方案依然不夠好,當Item足夠多的時候,可能會發生oom。

  public static Bitmap shotListView(ListView listview) {

    ListAdapter adapter = listview.getAdapter();
    int itemscount = adapter.getCount();
    int allitemsheight = 0;
    List<Bitmap> bmps = new ArrayList<Bitmap>();

    for (int i = 0; i < itemscount; i++) {

      View childView = adapter.getView(i, null, listview);
      childView.measure(
          View.MeasureSpec.makeMeasureSpec(listview.getWidth(), View.MeasureSpec.EXACTLY),
          View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));

      childView.layout(0, 0, childView.getMeasuredWidth(), childView.getMeasuredHeight());
      childView.setDrawingCacheEnabled(true);
      childView.buildDrawingCache();
      bmps.add(childView.getDrawingCache());
      allitemsheight += childView.getMeasuredHeight();
    }

    Bitmap bigbitmap =
        Bitmap.createBitmap(listview.getMeasuredWidth(), allitemsheight, Bitmap.Config.ARGB_8888);
    Canvas bigcanvas = new Canvas(bigbitmap);

    Paint paint = new Paint();
    int iHeight = 0;

    for (int i = 0; i < bmps.size(); i++) {
      Bitmap bmp = bmps.get(i);
      bigcanvas.drawBitmap(bmp, 0, iHeight, paint);
      iHeight += bmp.getHeight();

      bmp.recycle();
      bmp = null;
    }

    return bigbitmap;
  }

RecyclerView截屏

我們都知道,在新的Android版本中,已經可以用RecyclerView來代替使用ListView的場景,相比較ListView,RecyclerView對Item View的緩存支持的更好。可以采用和ListView相同的方案,這里也是在stackoverflow上看到的方案。


  public static Bitmap shotRecyclerView(RecyclerView view) {
    RecyclerView.Adapter adapter = view.getAdapter();
    Bitmap bigBitmap = null;
    if (adapter != null) {
      int size = adapter.getItemCount();
      int height = 0;
      Paint paint = new Paint();
      int iHeight = 0;
      final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

      // Use 1/8th of the available memory for this memory cache.
      final int cacheSize = maxMemory / 8;
      LruCache<String, Bitmap> bitmaCache = new LruCache<>(cacheSize);
      for (int i = 0; i < size; i++) {
        RecyclerView.ViewHolder holder = adapter.createViewHolder(view, adapter.getItemViewType(i));
        adapter.onBindViewHolder(holder, i);
        holder.itemView.measure(
            View.MeasureSpec.makeMeasureSpec(view.getWidth(), View.MeasureSpec.EXACTLY),
            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
        holder.itemView.layout(0, 0, holder.itemView.getMeasuredWidth(),
            holder.itemView.getMeasuredHeight());
        holder.itemView.setDrawingCacheEnabled(true);
        holder.itemView.buildDrawingCache();
        Bitmap drawingCache = holder.itemView.getDrawingCache();
        if (drawingCache != null) {

          bitmaCache.put(String.valueOf(i), drawingCache);
        }
        height += holder.itemView.getMeasuredHeight();
      }

      bigBitmap = Bitmap.createBitmap(view.getMeasuredWidth(), height, Bitmap.Config.ARGB_8888);
      Canvas bigCanvas = new Canvas(bigBitmap);
      Drawable lBackground = view.getBackground();
      if (lBackground instanceof ColorDrawable) {
        ColorDrawable lColorDrawable = (ColorDrawable) lBackground;
        int lColor = lColorDrawable.getColor();
        bigCanvas.drawColor(lColor);
      }

      for (int i = 0; i < size; i++) {
        Bitmap bitmap = bitmaCache.get(String.valueOf(i));
        bigCanvas.drawBitmap(bitmap, 0f, iHeight, paint);
        iHeight += bitmap.getHeight();
        bitmap.recycle();
      }
    }
    return bigBitmap;
  }

上面的方法在截取存在異步加載圖片的RecyclerView時候會出現加載不出圖片的情況,這里再補充一種滾動式截屏的方法

  public static void screenShotRecycleView(final RecyclerView mRecyclerView, final 
 RecycleViewRecCallback callBack) {
        if (mRecyclerView == null) {
            return;
        }
        BaseListFragment.MyAdapter adapter = (BaseListFragment.MyAdapter) mRecyclerView.getAdapter();
        final Paint paint = new Paint();
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
        // Use 1/8th of the available memory for this memory cache.
        final int cacheSize = maxMemory / 8;
        LruCache<String, Bitmap> bitmaCache = new LruCache<>(cacheSize);
        final int oneScreenHeight = mRecyclerView.getMeasuredHeight();
        int shotHeight = 0;
        if (adapter != null && adapter.getData().size() > 0) {
            int headerSize = adapter.getHeaderLayoutCount();
            int dataSize = adapter.getData().size();
            for (int i = 0; i < headerSize + dataSize; i++) {
                BaseViewHolder holder = (BaseViewHolder) adapter.createViewHolder(mRecyclerView, adapter.getItemViewType(i));
                if (i >= headerSize)
                    adapter.startConvert(holder, adapter.getData().get(i - headerSize));
                holder.itemView.measure(
                        View.MeasureSpec.makeMeasureSpec(mRecyclerView.getWidth(), View.MeasureSpec.EXACTLY),
                        View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
                holder.itemView.layout(0, 0, holder.itemView.getMeasuredWidth(), holder.itemView.getMeasuredHeight());
                holder.itemView.setDrawingCacheEnabled(true);
                holder.itemView.buildDrawingCache();
                Bitmap drawingCache = holder.itemView.getDrawingCache();
                //holder.itemView.destroyDrawingCache();//釋放緩存占用的資源
                if (drawingCache != null) {
                    bitmaCache.put(String.valueOf(i), drawingCache);
                }
                shotHeight += holder.itemView.getHeight();
                if (shotHeight > 12000) {
                    //設置截圖最大值
                    if (callBack != null)
                        callBack.onRecFinished(null);
                    return;
                }
            }
            //添加底部高度(加載更多或loading布局高度,此處為固定值:)
            final int footHight = Util.dip2px(mRecyclerView.getContext(), 42);
            shotHeight += footHight;

            //返回到頂部
            while (mRecyclerView.canScrollVertically(-1)) {
                mRecyclerView.scrollBy(0, -oneScreenHeight);
            }

            //繪制截圖的背景
            final Bitmap bigBitmap = Bitmap.createBitmap(mRecyclerView.getMeasuredWidth(), shotHeight, Bitmap.Config.ARGB_8888);
            final Canvas bigCanvas = new Canvas(bigBitmap);
            Drawable lBackground = mRecyclerView.getBackground();
            if (lBackground instanceof ColorDrawable) {
                ColorDrawable lColorDrawable = (ColorDrawable) lBackground;
                int lColor = lColorDrawable.getColor();
                bigCanvas.drawColor(lColor);
            }


            final int[] drawOffset = {0};
            final Canvas canvas = new Canvas();
            if (shotHeight <= oneScreenHeight) {
                //僅有一頁
                Bitmap bitmap = Bitmap.createBitmap(mRecyclerView.getWidth(), mRecyclerView.getHeight(), Bitmap.Config.ARGB_8888);
                canvas.setBitmap(bitmap);
                mRecyclerView.draw(canvas);
                if (callBack != null)
                    callBack.onRecFinished(bitmap);
            } else {
                //超過一頁
                final int finalShotHeight = shotHeight;
                mRecyclerView.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        if ((drawOffset[0] + oneScreenHeight < finalShotHeight)) {
                            //超過一屏
                            Bitmap bitmap = Bitmap.createBitmap(mRecyclerView.getWidth(), mRecyclerView.getHeight(), Bitmap.Config.ARGB_8888);
                            canvas.setBitmap(bitmap);
                            mRecyclerView.draw(canvas);
                            bigCanvas.drawBitmap(bitmap, 0, drawOffset[0], paint);
                            drawOffset[0] += oneScreenHeight;
                            mRecyclerView.scrollBy(0, oneScreenHeight);
                            try {
                                bitmap.recycle();
                            } catch (Exception ex) {
                                ex.printStackTrace();
                            }
                            mRecyclerView.postDelayed(this, 10);
                        } else {
                            //不足一屏時的處理
                            int leftHeight = finalShotHeight - drawOffset[0] - footHight;
                            mRecyclerView.scrollBy(0, leftHeight);
                            int top = oneScreenHeight - (finalShotHeight - drawOffset[0]);
                            if (top > 0 && leftHeight > 0) {
                                Bitmap bitmap = Bitmap.createBitmap(mRecyclerView.getWidth(), mRecyclerView.getHeight(), Bitmap.Config.ARGB_8888);
                                canvas.setBitmap(bitmap);
                                mRecyclerView.draw(canvas);
                                //截圖,只要補足的那塊圖
                                bitmap = Bitmap.createBitmap(bitmap, 0, top, bitmap.getWidth(), leftHeight, null, false);
                                bigCanvas.drawBitmap(bitmap, 0, drawOffset[0], paint);
                                try {
                                    bitmap.recycle();
                                } catch (Exception ex) {
                                    ex.printStackTrace();
                                }
                            }
                            if (callBack != null)
                                callBack.onRecFinished(bigBitmap);
                        }
                    }
                }, 10);
            }
        }
    }


    public interface RecycleViewRecCallback {
        void onRecFinished(Bitmap bitmap);
    }

相信有不少小伙伴用BRVH第三方庫來做recycleview的適配器的。使用這個庫的話再用上面的方法會報角標越界的錯誤,看了BRVH的源碼

 public void onBindViewHolder(ViewHolder holder, int positions) {
        int viewType = holder.getItemViewType();
        switch(viewType) {
        case 0:
            this.convert((BaseViewHolder)holder, this.mData.get(holder.getLayoutPosition() - this.getHeaderLayoutCount()));
        case 273:
        case 819:
        case 1365:
            break;
        case 546:
            this.addLoadMore(holder);
            break;
        default:
            this.convert((BaseViewHolder)holder, this.mData.get(holder.getLayoutPosition() - this.getHeaderLayoutCount()));
            this.onBindDefViewHolder((BaseViewHolder)holder, this.mData.get(holder.getLayoutPosition() - this.getHeaderLayoutCount()));
        }

    }

在調用adapter.onBindViewHolder時,因為里面的position參數未使用,里面用的計算holder.getLayoutPosition() - this.getHeaderLayoutCount()的值一直是-1導致角標越界報錯。

本人理解,RecyclerView的截屏原理是,首先構造每個item的ViewHolder,然后調用具體設置數據到每個item的方法,此時cache中就存有item的內容,此時繪制就能獲取到完整的內容。采用v7包中的onBindViewHolder方法即可,或者是BRVH的convert方法,可以看到BRVH中沒有暴露出這個方法,而且唯一暴露出的onBindViewHolder還會報角標越界錯誤,此時我們就需要在BRVH的基礎上暴露出convert即可,代碼如下

 public class MyAdapter extends BaseQuickAdapter<T> {

        public MyAdapter() {
            super(getItemLayoutResId(), datas);
        }

        /**
         * 用于對外暴露convert方法,構造緩存視圖(截屏用)
         * @param viewHolder
         * @param t
         */
        public void startConvert(BaseViewHolder viewHolder, T t){
            convert(viewHolder,t);
        }

        @Override
        protected void convert(BaseViewHolder viewHolder, T t) {
            bindView(viewHolder, t);
        }
    }

然后將上面所述的獲取Bitmap方法修改一下

 /**
     * 截取recycler view
     */
    public static Bitmap getRecyclerViewScreenshot(RecyclerView view) {
        BaseListFragment.MyAdapter adapter = (BaseListFragment.MyAdapter) view.getAdapter();
        Bitmap bigBitmap = null;
        if (adapter != null) {
            int size = adapter.getData().size();
            int height = 0;
            Paint paint = new Paint();
            int iHeight = 0;
            final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

            // Use 1/8th of the available memory for this memory cache.
            final int cacheSize = maxMemory / 8;
            LruCache<String, Bitmap> bitmaCache = new LruCache<>(cacheSize);
            for (int i = 0; i < size; i++) {
                BaseViewHolder holder = (BaseViewHolder) adapter.createViewHolder(view, adapter.getItemViewType(i));
                //此處需要調用convert方法,否則繪制出來的都是空的item
                adapter.startConvert(holder, adapter.getData().get(i));
                holder.itemView.measure(
                        View.MeasureSpec.makeMeasureSpec(view.getWidth(), View.MeasureSpec.EXACTLY),
                        View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
                holder.itemView.layout(0, 0, holder.itemView.getMeasuredWidth(),
                        holder.itemView.getMeasuredHeight());
                holder.itemView.setDrawingCacheEnabled(true);
                holder.itemView.buildDrawingCache();
                Bitmap drawingCache = holder.itemView.getDrawingCache();
                if (drawingCache != null) {

                    bitmaCache.put(String.valueOf(i), drawingCache);
                }
                height += holder.itemView.getMeasuredHeight();
            }

            bigBitmap = Bitmap.createBitmap(view.getMeasuredWidth(), height, Bitmap.Config.ARGB_8888);
            Canvas bigCanvas = new Canvas(bigBitmap);
            Drawable lBackground = view.getBackground();
            if (lBackground instanceof ColorDrawable) {
                ColorDrawable lColorDrawable = (ColorDrawable) lBackground;
                int lColor = lColorDrawable.getColor();
                bigCanvas.drawColor(lColor);
            }

            for (int i = 0; i < size; i++) {
                Bitmap bitmap = bitmaCache.get(String.valueOf(i));
                bigCanvas.drawBitmap(bitmap, 0f, iHeight, paint);
                iHeight += bitmap.getHeight();
                bitmap.recycle();
            }
        }
        return bigBitmap;
    }

合成Bitmap

比如四張合成一張


  /**
     * 將四張圖拼成一張
     *
     * @param pic1 圖一
     * @param pic2 圖二
     * @param pic3 圖三
     * @param pic4 圖四
     * @return only_bitmap
     */
    public static Bitmap combineBitmapsIntoOnlyOne(Bitmap pic1, Bitmap pic2, Bitmap pic3, Bitmap pic4, Activity context) {
        int w_total = pic2.getWidth();
        int h_total = pic1.getHeight() + pic2.getHeight() + pic3.getHeight() + pic4.getHeight();
        int h_pic1 = pic1.getHeight();
        int h_pic4 = pic4.getHeight();
        int h_pic12 = pic1.getHeight() + pic2.getHeight();
        //此處為防止OOM需要對高度做限制
        if (h_total > HEIGHTLIMIT) {
            return null;
        }

        Bitmap only_bitmap = Bitmap.createBitmap(w_total, h_total, Bitmap.Config.ARGB_4444);
        Canvas canvas = new Canvas(only_bitmap);
        canvas.drawColor(ContextCompat.getColor(context, R.color.color_content_bg));
        canvas.drawBitmap(pic1, 0, 0, null);
        canvas.drawBitmap(pic2, 0, h_pic1, null);
        canvas.drawBitmap(pic3, 0, h_pic12, null);
        canvas.drawBitmap(pic4, 0, h_total - h_pic4, null);
        return only_bitmap;
    }

圖片后期處理

 /**
     * 將傳入的Bitmap合理壓縮后輸出到系統截屏目錄下
     * 命名格式為:Screenshot+時間戳+啟信寶報名.jpg
     * 同時通知系統重新掃描系統文件
     *
     * @param pic1    圖一 標題欄截圖
     * @param pic2    圖二 scrollview截圖
     * @param context 用于通知重新掃描文件系統,為提升性能可去掉
     */
    public static void savingBitmapIntoFile(final Bitmap pic1, final Bitmap pic2, final Activity context, final BitmapAndFileCallBack callBack) {
        if (context == null || context.isFinishing()) {
            return;
        }
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                String fileReturnPath = "";
                int w = pic1.getWidth();
                Bitmap bottom = BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_picture_combine_bottom);
                Bitmap top_banner = BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_picture_combine_top);

                Bitmap bitmap_bottom = anyRatioCompressing(bottom, (float) w / bottom.getWidth(), (float) w / bottom.getWidth());
                Bitmap bitmap_top = anyRatioCompressing(top_banner, (float) w / bottom.getWidth(), (float) w / bottom.getWidth());
                final Bitmap only_bitmap = combineBitmapsIntoOnlyOne(bitmap_top, pic1, pic2, bitmap_bottom, context);

                // 獲取當前時間
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-ms", Locale.getDefault());
                String data = sdf.format(new Date());

                // 獲取內存路徑
                // 設置圖片路徑+命名規范
                // 聲明輸出文件
                String storagePath = Environment.getExternalStorageDirectory().getAbsolutePath();
                String fileTitle = "Screenshot_" + data + "_com.bertadata.qxb.biz_info.jpg";
                String filePath = storagePath + "/DCIM/";
                final String fileAbsolutePath = filePath + fileTitle;
                File file = new File(fileAbsolutePath);

                /**
                 * 質壓與比壓結合
                 * 分級壓縮
                 * 輸出文件
                 */
                if (only_bitmap != null) {
                    try {
                        // 首先,對原圖進行一步質量壓縮,形成初步文件
                        FileOutputStream fos = new FileOutputStream(file);
                        only_bitmap.compress(Bitmap.CompressFormat.JPEG, 50, fos);

                        // 另建一個文件other_file預備輸出
                        String other_fileTitle = "Screenshot_" + data + "_com.bertadata.qxb.jpg";
                        String other_fileAbsolutePath = filePath + other_fileTitle;
                        File other_file = new File(other_fileAbsolutePath);
                        FileOutputStream other_fos = new FileOutputStream(other_file);

                        // 其次,要判斷質壓之后的文件大小,按文件大小分級進行處理
                        long file_size = file.length() / 1024; // size of file(KB)
                        if (file_size < 0 || !(file.exists())) {
                            // 零級: 文件判空
                            throw new NullPointerException();
                        } else if (file_size > 0 && file_size <= 256) {
                            // 一級: 直接輸出
                            deleteFile(other_file);
                            // 通知刷新文件系統,顯示最新截取的圖文件
                            fileReturnPath = fileAbsolutePath;
                            context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + fileAbsolutePath)));
                        } else if (file_size > 256 && file_size <= 768) {
                            // 二級: 簡單壓縮:壓縮為原比例的3/4,質壓為50%
                            anyRatioCompressing(only_bitmap, (float) 3 / 4, (float) 3 / 4).compress(Bitmap.CompressFormat.JPEG, 40, other_fos);
                            deleteFile(file);
                            // 通知刷新文件系統,顯示最新截取的圖文件
                            fileReturnPath = other_fileAbsolutePath;
                            context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + other_fileAbsolutePath)));
                        } else if (file_size > 768 && file_size <= 1280) {
                            // 三級: 中度壓縮:壓縮為原比例的1/2,質壓為40%
                            anyRatioCompressing(only_bitmap, (float) 1 / 2, (float) 1 / 2).compress(Bitmap.CompressFormat.JPEG, 40, other_fos);
                            deleteFile(file);
                            // 通知刷新文件系統,顯示最新截取的圖文件
                            fileReturnPath = other_fileAbsolutePath;
                            context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + other_fileAbsolutePath)));
                        } else if (file_size > 1280 && file_size <= 2048) {
                            // 四級: 大幅壓縮:壓縮為原比例的1/3,質壓為40%
                            anyRatioCompressing(only_bitmap, (float) 1 / 3, (float) 1 / 3).compress(Bitmap.CompressFormat.JPEG, 40, other_fos);
                            deleteFile(file);
                            // 通知刷新文件系統,顯示最新截取的圖文件
                            fileReturnPath = other_fileAbsolutePath;
                            context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + other_fileAbsolutePath)));
                        } else if (file_size > 2048) {
                            // 五級: 中度壓縮:壓縮為原比例的1/2,質壓為40%
                            anyRatioCompressing(only_bitmap, (float) 1 / 2, (float) 1 / 2).compress(Bitmap.CompressFormat.JPEG, 40, other_fos);
                            deleteFile(file);
                            // 通知刷新文件系統,顯示最新截取的圖文件
                            fileReturnPath = other_fileAbsolutePath;
                            context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + other_fileAbsolutePath)));
                        }

                        // 注銷fos;
                        fos.flush();
                        other_fos.flush();
                        other_fos.close();
                        fos.close();
                        //callback用于回傳保存成功的路徑以及Bitmap
                        callBack.onSuccess(only_bitmap, fileReturnPath);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } else callBack.onSuccess(null, "");
            }
        });
        thread.start();
    }



    /**
     * 可實現任意寬高比例壓縮(寬高壓比可不同)的壓縮方法(主要用于微壓)
     *
     * @param bitmap       源圖
     * @param width_ratio  寬壓比(float)(0<&&<1)
     * @param height_ratio 高壓比(float)(0<&&<1)
     * @return 目標圖片
     * <p>
     */
    public static Bitmap anyRatioCompressing(Bitmap bitmap, float width_ratio, float height_ratio) {
        Matrix matrix = new Matrix();
        matrix.postScale(width_ratio, height_ratio);
        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
    }

本文參考http://www.cnblogs.com/BoBoMEe/p/4556917.html,并結合自己實際項目操作完成

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,818評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,185評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,656評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,647評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,446評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,951評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,041評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,189評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,718評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,800評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,419評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,420評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,755評論 2 371

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,604評論 25 707
  • Android截屏的原理:獲取具體需要截屏的區域的Bitmap,然后繪制在畫布上,保存為圖片后進行分享或者其它用途...
    皇小弟閱讀 1,213評論 1 3
  • 這是一個好問題, 大多數人都認為只要找到自己 真正喜歡的事情就能一生快樂了。 真的是這樣嗎? 每個人都在一直尋找自...
    為愛而活的芳芳閱讀 684評論 0 2
  • 棒棒魚圓圓的腦袋,細細的身體,活像一根在水里游來游去的的棒棒糖,它生活在山頂上的小溪里,它喜歡清清的溪水,岸邊的美...
    我是蘭爸爸閱讀 1,357評論 4 4
  • 不知道為什么總想寫些東西,每當我提起我那只買了不知多久的黑色圓珠筆,卻又不知道該寫些什么好,不知道如何下筆,從什...
    文宇楓閱讀 203評論 0 0