本文总结了安卓实现截图的几种方式。
View.getDrawingCache()
可以实现所有View的截图及全屏幕的截图,但是WebView无法截图。
@Deprecated
public static Bitmap createBitmapFromView(View view) {
Bitmap bitmap;
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap src = view.getDrawingCache();
bitmap = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight());
view.destroyDrawingCache();
view.setDrawingCacheEnabled(false);
src.recycle();
src = null;
return bitmap;
}
View绘制
创建画布传给View进行绘制。
public static Bitmap createBitmapFromView(View view) {
if (view == null) {
return null;
}
Bitmap screenshot;
screenshot = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(screenshot);
canvas.translate(-view.getScrollX(), -view.getScrollY());
view.draw(canvas);
return screenshot;
}
WebView.capturePicture
针对WebView截图的实现方式
public static Bitmap captureFromWebView(WebView webView) {
Picture snapShot = webView.capturePicture();
Bitmap bmp = Bitmap.createBitmap(snapShot.getWidth(),
snapShot.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmp);
snapShot.draw(canvas);
return bmp;
}
SurfaceControl.screenshot
SurfaceControl.screenshot()的低版本是Surface.screenshot()方法,这两种方法都是系统内部提供的截屏函数,但是这个函数是@hide的,所以无法直接调用,需要反射调用。
public static Bitmap screenshot(Context context) {
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
DisplayMetrics displayMetrics = new DisplayMetrics();
display.getRealMetrics(displayMetrics);
String surfaceClassName;
if (Build.VERSION.SDK_INT <= 17) {
surfaceClassName = "android.view.Surface";
} else {
surfaceClassName = "android.view.SurfaceControl";
}
Class<?> classname;
Bitmap bm = null;
try {
classname = Class.forName(surfaceClassName);
Method method = classname.getDeclaredMethod("screenshot",
new Class[]{int.class, int.class});
bm = (Bitmap) method.invoke(
null,
new Object[]{Integer.valueOf(displayMetrics.widthPixels),//分辨率
Integer.valueOf(displayMetrics.heightPixels)});
} catch (Exception e) {
e.printStackTrace();
}
return bm;
}
MediaProjection + ImageReader
Android5.0以上提供了MediaProjection,方便截屏录屏等功能。局限是必须进行申请会话授权。
public void screenshot(int resultCode, Intent data) {
final MediaProjection mediaProjection = mManager.getMediaProjection(resultCode, data);
if (mediaProjection == null) {
return;
}
mVirtualDisplay = mediaProjection.createVirtualDisplay("snap",
screenWidth, screenHeight, densityDpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,
mSurface, null, null);
Handler handler = new Handler(getMainLooper());
handler.postDelayed(new Runnable() {
public void run() {
//capture the screen
mImage = mImageReader.acquireLatestImage();
if (mImage == null) {
return;
}
int width = mImage.getWidth();
int height = mImage.getHeight();
final Image.Plane[] planes = mImage.getPlanes();
final ByteBuffer buffer = planes[0].getBuffer();
int pixelStride = planes[0].getPixelStride();
int rowStride = planes[0].getRowStride();
int rowPadding = rowStride - pixelStride * width;
Bitmap bitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888);
bitmap.copyPixelsFromBuffer(buffer);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height);
mImage.close();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy_MM_dd_hh_mm_ss");
String strDate = dateFormat.format(new java.util.Date());
String pathImage = Environment.getExternalStorageDirectory().getPath() + "/DCIM/";
String nameImage = pathImage + strDate + ".png";
if (bitmap != null) {
try {
File dir = new File(pathImage);
if (!dir.exists() && !dir.mkdirs()) {
dir.mkdirs();
}
File fileImage = new File(nameImage);
if (!fileImage.exists() && !fileImage.createNewFile()) {
fileImage.createNewFile();
}
FileOutputStream out = new FileOutputStream(fileImage);
if (out != null) {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
Intent media = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri contentUri = Uri.fromFile(fileImage);
media.setData(contentUri);
sendBroadcast(media);
mediaProjection.stop();
finish();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
finish();
}
}
}
}, 50);
}
PixelCopy.request
提供发出PixelCopy请求的机制,允许将Surface中的内容复制到Bitmap中。需要API 24(Android 7.0以上)支持。
@RequiresApi(api = Build.VERSION_CODES.N)
public static void getBitmapFormView(View view, Activity activity, Callback callback) {
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
int[] locations = new int[2];
view.getLocationInWindow(locations);
Rect rect = new Rect(locations[0], locations[1], locations[0] + view.getWidth(), locations[1] + view.getHeight());
PixelCopy.request(activity.getWindow(), rect, bitmap, copyResult -> {
if (copyResult == PixelCopy.SUCCESS) {
callback.onResult(bitmap);
}
}, new Handler(Looper.getMainLooper()));
}
感谢大家的支持,如有错误请指正,如需转载请标明原文出处!