您的位置:首页 > 移动开发 > Android开发

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

2014-08-23 18:00 519 查看
http://blog.csdn.net/zx19899891/article/details/7072291

在这里首先很感谢博主zmyde2010发表的这篇http://blog.csdn.net/zmyde2010/article/details/6925498#reply文章,我最开始也是看了他的文章才弄懂截屏的,而且博主基本上把全部的过程都讲出来,后来还附了代码,对于他这样无私的奉献我表示很感谢。我这篇文章也是在他的基础上修改,所以称做他的一个续集吧。有什么问题请大家及时在评论中提出来,我会尽快修复的。

在zmyde2010那篇文章中,他是直接在c层截出图并保存在指定位置,而我这篇讲的是在c层将图输出为流的形式传到java层,然后再由java层处理,这样可以在java 层将其转化成图片或者做其他相应的操作。下面首先给出cpp代码,我采用的是动态注册本地函数的形式.

com_android_screencapture_ScreenCaptureNative.cpp

[cpp] view
plaincopy

#define LOG_TAG "Screen_Capture"

#include "jni.h"

#include <utils/Log.h>

#include <binder/IPCThreadState.h>

#include <binder/ProcessState.h>

#include <binder/IServiceManager.h>

#include <binder/IMemory.h>

#include <surfaceflinger/ISurfaceComposer.h>

#include <SkImageEncoder.h>

#include <SkBitmap.h>

#include "CreateJavaOutputStreamAdaptor.h"

using namespace android;

const int kJPEG = 0;

const int kPNG = 1;

//format表示图片格式,目前是jpeg或者png;quality为图片质量,一般为90;outputStream表示截图对应的流输出,buffer为缓冲区,我是定为4096个byte

jboolean nativeCaptureScreen(JNIEnv *env, jobject object, jint format, jint quality, jobject outputStream, jbyteArray buffer)

{

const String16 name("SurfaceFlinger");

sp<ISurfaceComposer> composer;

getService(name, &composer);

sp<IMemoryHeap> heap;

uint32_t w, h;

PixelFormat f;

status_t err = composer->captureScreen(0, &heap, &w, &h, &f, 0, 0);

if (err != NO_ERROR) {

LOGE("Screen shot failed");

return JNI_FALSE;

}

LOGD("screen capture success: w=%u, h=%u, pixels=%p\n",w, h, heap->getBase());

SkBitmap b;

b.setConfig(SkBitmap::kARGB_8888_Config, w, h);

b.setPixels(heap->getBase());

SkImageEncoder::Type fm;

switch (format) {

case kJPEG:

fm = SkImageEncoder::kJPEG_Type;

break;

case kPNG:

fm = SkImageEncoder::kPNG_Type;

break;

default:

LOGE("FORMAT ERROR");

return JNI_FALSE;

}

SkWStream* strm = CreateJavaOutputStreamAdaptor(env, outputStream, buffer);

if (NULL != strm) {

SkImageEncoder* encoder = SkImageEncoder::Create(fm);

if (NULL != encoder) {

encoder->encodeStream(strm, b, quality);

delete encoder;

}

delete strm;

}

return JNI_TRUE;

}

static const char *classPathName = "com/android/screencapture/ScreenCaptureNative";

static JNINativeMethod methods[] = {

{"nativeCaptureScreen", "(IILjava/io/OutputStream;[B)Z", (void*)nativeCaptureScreen},

};

/*

* Register several native methods for one class.

*/

static int registerNativeMethods(JNIEnv* env, const char* className,

JNINativeMethod* gMethods, int numMethods)

{

jclass clazz;

clazz = env->FindClass(className);

if (clazz == NULL) {

LOGE("Native registration unable to find class '%s'", className);

return JNI_FALSE;

}

if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {

LOGE("RegisterNatives failed for '%s'", className);

return JNI_FALSE;

}

return JNI_TRUE;

}

/*

* Register native methods for all classes we know about.

*

* returns JNI_TRUE on success.

*/

static int registerNatives(JNIEnv* env)

{

if (!registerNativeMethods(env, classPathName,

methods, sizeof(methods) / sizeof(methods[0]))) {

return JNI_FALSE;

}

return JNI_TRUE;

}

/*

* This is called by the VM when the shared library is first loaded.

*/

typedef union {

JNIEnv* env;

void* venv;

} UnionJNIEnvToVoid;

jint JNI_OnLoad(JavaVM* vm, void* reserved)

{

UnionJNIEnvToVoid uenv;

uenv.venv = NULL;

jint result = -1;

JNIEnv* env = NULL;

LOGI("JNI_OnLoad");

if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) {

LOGE("ERROR: GetEnv failed");

goto bail;

}

env = uenv.env;

if (registerNatives(env) != JNI_TRUE) {

LOGE("ERROR: registerNatives failed");

goto bail;

}

result = JNI_VERSION_1_4;

bail:

return result;

}

下面是对应的Android.mk文件:

[plain] view
plaincopy

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES := com_android_screencapture_ScreenCaptureNative.cpp

LOCAL_SHARED_LIBRARIES := \

libnativehelper \

libcutils \

libutils \

libbinder \

libskia \

libui \

libsurfaceflinger_client \

libandroid_runtime

LOCAL_C_INCLUDES += \

$(JNI_H_INCLUDE) \

external/skia/include/core \

external/skia/include/effects \

external/skia/include/images \

external/skia/src/ports \

external/skia/include/utils \

frameworks/base/core/jni/android/graphics

LOCAL_MODULE := libscreencapjni

LOCAL_MODULE_TAGS := optional

LOCAL_PRELINK_MODULE := false

include $(BUILD_SHARED_LIBRARY)

下面是对应的java层代码:

ScreenCaptureNative.java

[cpp] view
plaincopy

<pre name="code" class="cpp"><pre name="code" class="cpp"><pre name="code" class="cpp" style="background-color:rgb(255,255,255)"><pre name="code" class="java"></pre><pre name="code" class="java">package com.android.screencapture;

import java.io.OutputStream;

import java.io.ByteArrayOutputStream;

import android.util.Log;

public class ScreenCaptureNative {

private final static int BUFFER_SIZE = 4096;

private byte[] mBuffer = null;

static {

System.loadLibrary("screencapjni");

};

private native boolean nativeCaptureScreen(int format, int quality, OutputStream stream, byte[] buffer);

public ScreenCaptureNative(){

mBuffer = new byte[BUFFER_SIZE];

}

public byte[] startCaptureScreen(int format, int quality) {

ByteArrayOutputStream srcPic = new ByteArrayOutputStream();

if (!nativeCaptureScreen(format, quality, srcPic, mBuffer))

{

Log.e("screencapture", "CAPTURE FAILED");

return null;

}

byte[] screenData = srcPic.toByteArray();

return screenData;

}

} </pre><p><span style="font-size:18px"><br></span></p><p><span style="font-size:18px">上述java程序对应的make文件如下:</span></p><p><span style="font-size:18px"><br></span></p><p><span style="font-size:18px"></span></p><pre name="code" class="plain">LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

LOCAL_SRC_FILES := $(call all-subdir-java-files)

LOCAL_PACKAGE_NAME := ScreenCapture

LOCAL_CERTIFICATE := platform

LOCAL_REQUIRED_MODULES := libscreencapjni

LOCAL_JNI_SHARED_LIBRARIES := libscreencapjni

include $(BUILD_PACKAGE)

include $(call all-makefiles-under,$(LOCAL_PATH))</pre><br><br><p></p><p><span style="font-size:18px"><br></span></p><p><span style="font-size:18px"></span></p><p><span style="font-size:18px"><span style="white-space:pre"></span> 在这里特别强调两点:第一,在你所编写的android截屏程序中记得在对应的AndroidManifest.xml添加权限<uses-permission android:name="android.permission.READ_FRAME_BUFFER" />,否则就会在调用c层代码时报错;第二,在编写android截屏程序对应的make文件中,记得添加LOCAL_CERTIFICATE := platform,这也是跟权限相关,然后再放到源码中编译该程序。<br><span style="white-space:pre"></span> 另外在zmyde2010的那篇文章中说到编译android自带的截屏demo,结果生成了 test-screencap,我按照博主的要求test-screencap /mnt/sdcard/scapxx.png那样没有弄出截屏,没大明白他说的终端具体指哪个。我这里说下我是怎么用的,首先将test-screencap push到手机中,最好不要放到sd卡所在位置,你可以push到/data下面,然后手机连着电脑,在电脑命令行中输入adb shell进入手机的linux文件系统中,之后cd到刚才存放test-screencap的目录下,先修改下该文件的权限,使其可以执行,然后再输入命令 ./test-screencap /mnt/sdcard/scapxx.png即可截图了,最终在你的sd卡中就可看到刚才截的图。<br><span style="white-space:pre"></span> 我也是个android初学者,有哪里错误了欢迎大家指正。。。</span><br></p><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre><pre></pre></pre></pre></pre>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: