最近要做手机截取当前屏幕的开发,发了大半天时间在网上找了很多资料,终于有了一个大概的头绪和思路,若有问题望指点,谢谢!
目前而言个人了解android有三种截屏方法:
1、android
SDK提供的截屏View.getDrawingCache()方法,当这个方法只能截取当前activity的界面,对自己的项目要求有点有同,既然可以实现就拿出来学习学习。
测试代码:
public class MainActivity
extends Activity implements OnClickListener {
private Button button;
private ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initListener();
}
private void initView() {
button = (Button) findViewById(R.id.button);
imageView = (ImageView) findViewById(R.id.IamagerView);
}
private void initListener() {
button.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button:
imageView.setImageBitmap(getSreenBitmap(v));
break;
default:
break;
}
}
private Bitmap getSreenBitmap(View v) {
View view = v.getRootView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap bitmap = view.getDrawingCache();
if (bitmap == null) {
Log.d("tag", "null");
return null;
}
Log.d("tag", "return");
return bitmap;
}
}
2 基于android
ddmlib.jar这个包进行截屏,这个jar包位于/tools/lib目录下,网上找了很多资料讲的都不是很清楚,下了几个小Demo远行不了;貌似DDMS里面的截屏就是通过这个包来实现的。
3
基于android本地编程,读取framebuffer;
这是我现在使用的方法。它的优点是整个屏幕都可以截下来,同时不需要写JNI,也不需要Java层的实现。而且如果是emulator的话,也可以直接用adb来操作,十分方便(其实,有一个库android-screenshot-lib应该实现了类似的功能,但是我尝试了一下没有截图成功,图片大小不正确,且是黑屏。就没有进一步尝试了)。
Android的framebuffer介绍
framebuffer是linux内核对显示的最底层驱动。在一般的linux文件系统中,通过/dev/fb0设备文件来提供给应用程序对framebuffer进行读写的访问。这里,如果有多个显示设备,就将依次出现fb1,fb2,…等文件。而在我们所说的android系统中,这个设备文件被放在了/dev/graphics/fb0,而且往往只有这一个。
对android framebuffer的基本操作
1.读取framebuffer
2.Framebuffer转换为bitmap
3.bitmap生成图像文件
读取framebuffer
在android上使用这种方法第一个难题是获取framebuffer,因为默认的配置中framebuffer的读取权限是“root”,而Apk的权限最高只能提升到“system”,framework工作的权限也是“system”,也因此网上提供的截屏软件都只能在root过的手机上使用。对拥有源码的人来说,最简单的方法是直接改变framebuffer的权限,普通用户也有权限读取framebuffer。
然后就可以通过读文件的方式直接读取framebuffer,利用如下代码打开一个指向framebuffer的输入流就可以读取了。
publicstaticInputStream getInputStream()throwsException
{
FileInputStream
buf =newFileInputStream(
newFile("/dev/graphics/fb0"));
returnbuf;
}//get
the InputStream from framebuffer
framebuffer到bitmap的转换
framebuffer的数据是直接送入显示设备的,这些数据没有文件头,而且由于framebuffer读到数据跟显示方式关系很大,在不同设备上framebuffer的大小和数据格式不一样,读取前确定framebuffer的数据格式。
获取屏幕大小:
DisplayMetrics
metrics =newDisplayMetrics();
WindowManager
WM = (WindowManager)mContext
.getSystemService(Context.WINDOW_SERVICE);
Display
display = WM.getDefaultDisplay();
display.getMetrics(metrics);
intheight
= metrics.heightPixels;
//屏幕高
intwith
= metrics.widthPixels; //屏幕的宽
获取显示方式
intpixelformat
= display.getPixelFormat();
PixelFormat
localPixelFormat1
=newPixelFormat();
PixelFormat.getPixelFormatInfo(pixelformat,
localPixelFormat1);
intdeepth
= localPixelFormat1.bytesPerPixel;//位深
pixelformat代表的意义是在PixelFormat.java定义的:
public
static final int
RGBA_8888 =
1;
public
static final int
RGBX_8888 =
2;
public
static final int
RGB_888 =
3;
public
static final int
RGB_565 =
4;
public
static final int
RGBA_5551 =
6;
public
static final int
RGBA_4444 =
7;
public
static final int
A_8 =
8;
public
static final int
L_8 =
9;
public
static final int
LA_88 =
0xA;
public
static final int
RGB_332 =
0xB;
pixelformat是下面进行判断处理的依据,根据pixelformat计算出实际的深度。
一般
Framebuffer大小=(height*
with* deepth)*2;
之所以“*2”,是因为Framebuffer包含两帧画面,我们使用任何一帧都可以。
piex
=newbyte[height
* with * deepth];
InputStream
stream
= getInputStream(
newFile("/dev/graphics/fb0"));
DataInputStream
dStream =newDataInputStream(stream);
dStream.readFully(piex);
这样framebuffer的数据就被写进了piex。
piex生成bitmap
bitmap=
Bitmap.createBitmap(data,mwidth,mheight, config);
data:像素数据,data的一个元素表示一个像素,所以这里不能直接使用piex,必须经过转换。
mwidth,mheight:图像大小
config:图像格式,可以取以下数值
Bitmap.Config.ALPHA_8 (2),
Bitmap.Config.RGB_565 (4),
Bitmap.Config.ARGB_4444 (5),
Bitmap.Config.ARGB_8888 (6)
bitmap保存为png格式:
这是跟上面一样的
FileOutputStream out =newFileOutputStream(file_name);
bitmap.compress(Bitmap.CompressFormat.PNG,
100, out);