Android截屏方案实现原理解析

2020-10-30 00:12:06 浏览数 (1)

Android截屏的原理:获取具体需要截屏的区域的Bitmap,然后绘制在画布上,保存为图片后进行分享或者其它用途

在截屏功能中,有时需要截取全屏的内容,有时需要截取超过一屏的内容(比如:Listview,Scrollview,RecyclerView)。下面介绍各种场景获取Bitmap的方法

普通截屏的实现

获取当前Window的DrawingCache的方式,即decorView的DrawingCache

代码语言:javascript复制
/**
  * 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

代码语言:javascript复制
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) 来完成截图

代码语言:javascript复制
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;
 }

Scrollview截屏

而ListView就是会回收与重用Item,并且只会绘制在屏幕上显示的ItemView,根据stackoverflow上大神的建议,采用一个List来存储Item的视图,这种方案依然不够好,当Item足够多的时候,可能会发生oom。

代码语言:javascript复制
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上看到的方案。

代码语言:javascript复制
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时候会出现加载不出图片的情况,这里再补充一种滚动式截屏的方法

代码语言:javascript复制
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的源码

代码语言:javascript复制
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 即可,代码如下

代码语言:javascript复制
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方法修改一下

代码语言:javascript复制
/**
* 截取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

比如四张合成一张

代码语言:javascript复制
/**
* 将四张图拼成一张
*
* @param pic1 图一
* @param pic2 图二
* @param pic3 图三
* @param pic4 图四
* @return only_bitmap
* 详情见说明:{@link com.bertadata.qxb.util.ScreenShotUtils}
*/
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;
}

图片后期处理

代码语言:javascript复制
/**
* 将传入的Bitmap合理压缩后输出到系统截屏目录下
* 命名格式为:Screenshot 时间戳 启信宝报名.jpg
* 同时通知系统重新扫描系统文件
*
* @param pic1  图一 标题栏截图
* @param pic2  图二 scrollview截图
* @param context 用于通知重新扫描文件系统,为提升性能可去掉
*        详情见说明:{@link com.bertadata.qxb.util.ScreenShotUtils}
*/
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);
}

总结

以上所述是小编给大家介绍的Android截屏方案实现原理解析,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对ZaLou.Cn网站的支持!

0 人点赞