首先找到screencap类在Android源码中的位置,/442/frameworks/base/cmds/screencap/screencap.cpp。

源码如下:

[cpp] view plaincopy
  1. /*
  2. * Copyright (C) 2010 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. *      http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <errno.h>
  17. #include <unistd.h>
  18. #include <stdio.h>
  19. #include <fcntl.h>
  20. #include <linux/fb.h>
  21. #include <sys/ioctl.h>
  22. #include <sys/mman.h>
  23. #include <binder/ProcessState.h>
  24. #include <gui/SurfaceComposerClient.h>
  25. #include <gui/ISurfaceComposer.h>
  26. #include <ui/PixelFormat.h>
  27. #include <SkImageEncoder.h>
  28. #include <SkBitmap.h>
  29. #include <SkData.h>
  30. #include <SkStream.h>
  31. using namespace android;
  32. static uint32_t DEFAULT_DISPLAY_ID = ISurfaceComposer::eDisplayIdMain;
  33. static void usage(const char* pname)
  34. {
  35. fprintf(stderr,
  36. "usage: %s [-hp] [-d display-id] [FILENAME]\n"
  37. "   -h: this message\n"
  38. "   -p: save the file as a png.\n"
  39. "   -d: specify the display id to capture, default %d.\n"
  40. "If FILENAME ends with .png it will be saved as a png.\n"
  41. "If FILENAME is not given, the results will be printed to stdout.\n",
  42. pname, DEFAULT_DISPLAY_ID
  43. );
  44. }
  45. static SkBitmap::Config flinger2skia(PixelFormat f)
  46. {
  47. switch (f) {
  48. case PIXEL_FORMAT_RGB_565:
  49. return SkBitmap::kRGB_565_Config;
  50. default:
  51. return SkBitmap::kARGB_8888_Config;
  52. }
  53. }
  54. static status_t vinfoToPixelFormat(const fb_var_screeninfo& vinfo,
  55. uint32_t* bytespp, uint32_t* f)
  56. {
  57. switch (vinfo.bits_per_pixel) {
  58. case 16:
  59. *f = PIXEL_FORMAT_RGB_565;
  60. *bytespp = 2;
  61. break;
  62. case 24:
  63. *f = PIXEL_FORMAT_RGB_888;
  64. *bytespp = 3;
  65. break;
  66. case 32:
  67. // TODO: do better decoding of vinfo here
  68. *f = PIXEL_FORMAT_RGBX_8888;
  69. *bytespp = 4;
  70. break;
  71. default:
  72. return BAD_VALUE;
  73. }
  74. return NO_ERROR;
  75. }
  76. int main(int argc, char** argv)
  77. {
  78. ProcessState::self()->startThreadPool();
  79. const char* pname = argv[0];
  80. bool png = false;
  81. int32_t displayId = DEFAULT_DISPLAY_ID;
  82. int c;
  83. while ((c = getopt(argc, argv, "phd:")) != -1) {
  84. switch (c) {
  85. case 'p':
  86. png = true;
  87. break;
  88. case 'd':
  89. displayId = atoi(optarg);
  90. break;
  91. case '?':
  92. case 'h':
  93. usage(pname);
  94. return 1;
  95. }
  96. }
  97. argc -= optind;
  98. argv += optind;
  99. int fd = -1;
  100. if (argc == 0) {
  101. fd = dup(STDOUT_FILENO);
  102. } else if (argc == 1) {
  103. const char* fn = argv[0];
  104. fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664);
  105. if (fd == -1) {
  106. fprintf(stderr, "Error opening file: %s (%s)\n", fn, strerror(errno));
  107. return 1;
  108. }
  109. const int len = strlen(fn);
  110. if (len >= 4 && 0 == strcmp(fn+len-4, ".png")) {
  111. png = true;
  112. }
  113. }
  114. if (fd == -1) {
  115. usage(pname);
  116. return 1;
  117. }
  118. void const* mapbase = MAP_FAILED;
  119. ssize_t mapsize = -1;
  120. void const* base = 0;
  121. uint32_t w, s, h, f;
  122. size_t size = 0;
  123. ScreenshotClient screenshot;
  124. sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(displayId);
  125. if (display != NULL && screenshot.update(display) == NO_ERROR) {
  126. base = screenshot.getPixels();
  127. w = screenshot.getWidth();
  128. h = screenshot.getHeight();
  129. s = screenshot.getStride();
  130. f = screenshot.getFormat();
  131. size = screenshot.getSize();
  132. } else {
  133. const char* fbpath = "/dev/graphics/fb0";
  134. int fb = open(fbpath, O_RDONLY);
  135. if (fb >= 0) {
  136. struct fb_var_screeninfo vinfo;
  137. if (ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) == 0) {
  138. uint32_t bytespp;
  139. if (vinfoToPixelFormat(vinfo, &bytespp, &f) == NO_ERROR) {
  140. size_t offset = (vinfo.xoffset + vinfo.yoffset*vinfo.xres) * bytespp;
  141. w = vinfo.xres;
  142. h = vinfo.yres;
  143. s = vinfo.xres;
  144. size = w*h*bytespp;
  145. mapsize = offset + size;
  146. mapbase = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, fb, 0);
  147. if (mapbase != MAP_FAILED) {
  148. base = (void const *)((char const *)mapbase + offset);
  149. }
  150. }
  151. }
  152. close(fb);
  153. }
  154. }
  155. if (base) {
  156. if (png) {
  157. SkBitmap b;
  158. b.setConfig(flinger2skia(f), w, h, s*bytesPerPixel(f));
  159. b.setPixels((void*)base);
  160. SkDynamicMemoryWStream stream;
  161. SkImageEncoder::EncodeStream(&stream, b,
  162. SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality);
  163. SkData* streamData = stream.copyToData();
  164. write(fd, streamData->data(), streamData->size());
  165. streamData->unref();
  166. } else {
  167. write(fd, &w, 4);
  168. write(fd, &h, 4);
  169. write(fd, &f, 4);
  170. size_t Bpp = bytesPerPixel(f);
  171. for (size_t y=0 ; y<h ; y++) {
  172. write(fd, base, w*Bpp);
  173. base = (void *)((char *)base + s*Bpp);
  174. }
  175. }
  176. }
  177. close(fd);
  178. if (mapbase != MAP_FAILED) {
  179. munmap((void *)mapbase, mapsize);
  180. }
  181. return 0;
  182. }

由源码可以看出,screencap的入口main方法是从命令行获取参数,通过分析后执行相应的操作。我们要想在java层调用这个类,就要把它的入口改成native方法的接口,修改后的代码如下:

[cpp] view plaincopy
  1. #include <jni.h>
  2. #include "com_android_servicescreencap_ScreenCap.h"
  3. #include <errno.h>
  4. #include <unistd.h>
  5. #include <stdio.h>
  6. #include <fcntl.h>
  7. #include <linux/fb.h>
  8. #include <sys/ioctl.h>
  9. #include <sys/mman.h>
  10. #include <binder/ProcessState.h>
  11. #include <gui/SurfaceComposerClient.h>
  12. #include <gui/ISurfaceComposer.h>
  13. #include <ui/PixelFormat.h>
  14. #include <SkImageEncoder.h>
  15. #include <SkBitmap.h>
  16. #include <SkData.h>
  17. #include <SkStream.h>
  18. #include <android/log.h>
  19. #define LOG_TAG "ServiceScreenCap"
  20. #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
  21. #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
  22. #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
  23. using namespace android;
  24. static uint32_t DEFAULT_DISPLAY_ID = ISurfaceComposer::eDisplayIdMain;
  25. static status_t vinfoToPixelFormat(const fb_var_screeninfo& vinfo,
  26. uint32_t* bytespp, uint32_t* f)
  27. {
  28. switch (vinfo.bits_per_pixel) {
  29. case 16:
  30. *f = PIXEL_FORMAT_RGB_565;
  31. *bytespp = 2;
  32. break;
  33. case 24:
  34. *f = PIXEL_FORMAT_RGB_888;
  35. *bytespp = 3;
  36. break;
  37. case 32:
  38. // TODO: do better decoding of vinfo here
  39. *f = PIXEL_FORMAT_RGBX_8888;
  40. *bytespp = 4;
  41. break;
  42. default:
  43. return BAD_VALUE;
  44. }
  45. return NO_ERROR;
  46. }
  47. static SkBitmap::Config flinger2skia(PixelFormat f)
  48. {
  49. switch (f) {
  50. case PIXEL_FORMAT_RGB_565:
  51. return SkBitmap::kRGB_565_Config;
  52. default:
  53. return SkBitmap::kARGB_8888_Config;
  54. }
  55. }
  56. /*
  57. * Class:     com_android_servicescreencap_ScreenCap
  58. * Method:    currentscreen
  59. * Signature: (Ljava/lang/String;)I
  60. */
  61. JNIEXPORT jint
  62. JNICALL ScreenCap_currentscreen(JNIEnv *env,
  63. jclass clazz, jstring jpath) {
  64. ProcessState::self()->startThreadPool();
  65. int32_t displayId = DEFAULT_DISPLAY_ID;
  66. const char* fn = env->GetStringUTFChars(jpath,NULL);
  67. LOGI("=====jpath:%s \n", fn);
  68. if (fn == NULL) {
  69. LOGE("=====path = %s \n =====err: %s \n",fn, strerror(errno));
  70. return 1;
  71. }
  72. int fd = -1;
  73. fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664);
  74. LOGI("=====after open ,fd:%d \n",fd);
  75. if (fd == -1) {
  76. LOGE("=====err: %s \n", strerror(errno));
  77. return 2;
  78. }
  79. void const* mapbase = MAP_FAILED;
  80. ssize_t mapsize = -1;
  81. void const* base = 0;
  82. uint32_t w, s, h, f;
  83. size_t size = 0;
  84. ScreenshotClient screenshot;
  85. sp < IBinder > display = SurfaceComposerClient::getBuiltInDisplay(displayId);
  86. if (display != NULL && screenshot.update(display) == NO_ERROR) {
  87. base = screenshot.getPixels();
  88. w = screenshot.getWidth();
  89. h = screenshot.getHeight();
  90. s = screenshot.getStride();
  91. f = screenshot.getFormat();
  92. size = screenshot.getSize();
  93. } else {
  94. const char* fbpath = "/dev/graphics/fb0";
  95. int fb = open(fbpath, O_RDONLY);
  96. LOGI("=====read framebuffer, fb:%d \n", fb);
  97. if (fb >= 0) {
  98. struct fb_var_screeninfo vinfo;
  99. if (ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) == 0) {
  100. uint32_t bytespp;
  101. if (vinfoToPixelFormat(vinfo, &bytespp, &f) == NO_ERROR) {
  102. size_t offset = (vinfo.xoffset + vinfo.yoffset * vinfo.xres)
  103. * bytespp;
  104. w = vinfo.xres;
  105. h = vinfo.yres;
  106. s = vinfo.xres;
  107. size = w * h * bytespp;
  108. mapsize = offset + size;
  109. mapbase = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, fb, 0);
  110. if (mapbase != MAP_FAILED) {
  111. base = (void const *) ((char const *) mapbase + offset);
  112. }
  113. }
  114. }
  115. close(fb);
  116. }else{
  117. LOGE("=====fb = %d , err: %s \n",fb, strerror(errno));
  118. return 3;
  119. }
  120. }
  121. if (base) {
  122. SkBitmap b;
  123. b.setConfig(flinger2skia(f), w, h, s * bytesPerPixel(f));
  124. b.setPixels((void*) base);
  125. SkDynamicMemoryWStream stream;
  126. SkImageEncoder::EncodeStream(&stream, b, SkImageEncoder::kPNG_Type,
  127. SkImageEncoder::kDefaultQuality);
  128. SkData* streamData = stream.copyToData();
  129. write(fd, streamData->data(), streamData->size());
  130. streamData->unref();
  131. }
  132. close (fd);
  133. if (mapbase != MAP_FAILED) {
  134. munmap((void *) mapbase, mapsize);
  135. }
  136. return 0;
  137. }
  138. static JNINativeMethod methods[] = {
  139. {"currentscreen","(Ljava/lang/String;)I",(void*)ScreenCap_currentscreen},
  140. };
  141. static int registerNativeMethods(JNIEnv* env,const char* classname,JNINativeMethod* gMethods,int numMethods ){
  142. jclass clazz;
  143. clazz = env->FindClass(classname);
  144. if(clazz == NULL){
  145. return JNI_FALSE;
  146. }
  147. if(env->RegisterNatives(clazz,gMethods,numMethods) <0 ){
  148. return JNI_FALSE;
  149. }
  150. return JNI_TRUE;
  151. }
  152. static int registerNatives(JNIEnv* env)
  153. {
  154. if (!registerNativeMethods(env, "com/android/servicescreencap/ScreenCap",
  155. methods, sizeof(methods) / sizeof(methods[0]))) {
  156. return JNI_FALSE;
  157. }
  158. return JNI_TRUE;
  159. }
  160. typedef union {
  161. JNIEnv* env;
  162. void* venv;
  163. } UnionJNIEnvToVoid;
  164. jint JNI_OnLoad(JavaVM* vm, void* reserved)
  165. {
  166. UnionJNIEnvToVoid uenv;
  167. uenv.venv = NULL;
  168. jint result = -1;
  169. JNIEnv* env = NULL;
  170. if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_6) != JNI_OK) {
  171. return result;
  172. }
  173. env = uenv.env;
  174. if (registerNatives(env) != JNI_TRUE) {
  175. return result;
  176. }
  177. result = JNI_VERSION_1_6;
  178. return result;
  179. }

修改后的代码入口是ScreenCap_currentscreen,该方法接收一个地址,将当前屏幕截取到该地址下。代码中加入了日志,可以打印native层的错误信息。


此处需采用动态方式注册本地方法,静态方式好像会有问题。

参考链接:

Android: How to Capture Screen in Gingerbread(2.3中实现截屏)

Android: How to Capture Screen in Gingerbread(2.3中实现截屏)(续)

Android系统截屏的实现(附代码)

原文地址: http://blog.csdn.net/lingfengxu/article/details/43487793

android后台截屏实现(2)--screencap源码修改相关推荐

  1. 快捷键自动截屏保存图片工具附源码0积分共享

    快捷键自动截图保存在工具所在目录,目前快捷键复用的原来的截屏软件,不影响原来截屏键功能.源码公开可免费下载需要者自取,可以根据需要自行修改.用对话框实现的,但是做成了系统托盘图标,没有界面显示,方便后 ...

  2. Windows CE/Moblie截屏工具及实现源码

    Windows CE/Moblie截屏工具及实现源码 [img]http://dl2.iteye.com/upload/attachment/0084/6997/c72941f2-b86e-3683- ...

  3. Android后台截屏功能

    前言 最近公司领导要求我做一个截屏的功能,说是为了方便监控小屏.本来以为没什么难度,然后就答应了下来.谁知道全都是坑. 这里要说明一点,我这里做的Android程序是 安装在 Android小屏上和机 ...

  4. android 后台截屏代码,Android实现截图和分享功能的代码

    先给大家展示下效果图吧 直接上代码: xml的布局: android:id="@+id/btn_jp" android:layout_marginTop="10dip&q ...

  5. android后台截屏实现(3)--编译screencap

    修改好之后就要编译了,screencap的编译是要在源码环境中进行的. 将修改后的screencap.cpp文件替换源码中的原始文件,然后修改screencap的Android.mk文件,修改后的文件 ...

  6. 一键锁屏源代码c语言,Android一键锁屏开发全过程【源码】【附图】

    一.项目简介: 项目:<Android 一键锁屏> 开发周期:4天 代码量:100行 ------------------------ 二.项目流程: 三.项目代码 1.主程序代码: Ja ...

  7. Android开发WebView之加载HTML源码修改HTML字体大小以及缩放HTML的方法

    老套路上图: 再看下缩放功能: 先说下设置HTML网页字体大小的方法: //设置网页字体大小webview.getSettings().setTextSize(WebSettings.TextSize ...

  8. 【源码解读】Screencap源码分析-基础篇

    本文期望达到的目的: 了解screencap使用 了解screencap实现基础原理 为后续screencap源码修改和其他应用做准备 源码位置: android4.0之后内置了截图工具screenc ...

  9. android截屏功能实现方式汇总【包括后台截屏】

    前言 对于android实现截屏功能,简单讲述一下可行的方法和之间的利弊 使用canvas View v = getWindow().getDecorView(); Bitmap bitmap = B ...

最新文章

  1. linux pps 包 网卡,linux下安装PPS
  2. tfs连不上团队资源管理器问题
  3. css实现横向进度条和竖向进度条
  4. 二叉树链表结构表示法
  5. python文件操作模式是什么,python --文件操作模式详解
  6. sap模块介绍_小迈说|SAP究竟有多少模块?
  7. 设计模式之 - 代理模式(Proxy Pattern)
  8. 常用而又不为大多数人所知的三种网页特效
  9. python opencv用法中文教程
  10. C# —— IEnumerator和foreach
  11. Chrome , Firfox 对应IE fireEvent 的方法
  12. ubuntu 一张网卡绑定多个ip
  13. 微信配置JS接口安全域名-Nginx配置 文件的配置
  14. Java 設計模式 - 適配器模式
  15. 微信小程序开发时,下载node.js安装后出错误怎么办
  16. 克鲁格曼《微观经济学》第2版课后习题答案
  17. input:-webkit-autofill
  18. C语言写一个函数,可以逆序一个字符串的内容。
  19. Java实现编辑图片并添加文字
  20. 疫情错峰云计算冲锋,给Zoom带来了多少溢价?

热门文章

  1. 《第1集:机器学习的动机与应用》
  2. 【转】RMAN 高级恢复
  3. MySql数据库操作遇到的蛋疼二三事
  4. 深入Atlas系列:探究Application Services(2) - 自定义服务器端Profile Service支持
  5. 机器学习导论(张志华):核定义(2)
  6. 统计学:回归分析(2)
  7. GPU(CUDA)学习日记(九)------ CUDA存储器模型
  8. git切换路径报错:bash: cd: too many arguments
  9. 【Paper】研究论文不会写?先来学学怎么做西红柿炒鹌鹑蛋吧!
  10. 云炬随笔20210714(1)