我正在使用 JNI 和负责管理图形管道/渲染的第三方引擎(虚幻引擎 4)开发应用程序。
第三方引擎是用 C++ 编写的,因此需要使用 JNI 将其与 Android 桥接。
该应用程序需要将屏幕上显示的内容的屏幕截图保存在设备上(换句话说,是帧缓冲区的转储)。第三方引擎公开了一个调用自定义处理程序的 API,传入屏幕的宽度、高度和颜色数据。
colordata
是uint8
表示 RGBA 组件的自定义容器。
我成功地将其转换colorData
为 ajbyteArray
并将其作为参数传递给 JAVA 端的函数。在 java 方面,事情更简单:我从 byteArray 创建一个位图,翻转它并通过自定义将其保存为 jpg/png AsyncTask
。
问题:代码在三星 Galaxy S4/Note3(Android 5.0)上运行得非常好,而在 Nexus 10 Android 5.1.1 版本上,保存的 png 是空白的。 我担心这个问题比我可以访问的更严重,即显卡/驱动程序/操作系统版本,但我不是该领域的专家,所以我想知道是否有人已经遇到过类似的问题,或者可以阐明导致它的原因。
这是用于将引擎与 Java 连接起来的代码(我从这个项目开始使用 c++,所以这个片段中可能存在所有权/内存问题。非常欢迎您纠正我,以防万一 :))
void AndroidInterface::SaveBitmap(const TArray<FColor>& colorData, int32 width, int32 height) {
JNIEnv* env = FAndroidApplication::GetJavaEnv(true);
TArray<FColor> bitmap = colorData;
TArray<uint8> compressedBitmap;
FImageUtils::CompressImageArray(width, height, bitmap, compressedBitmap);
size_t len = width*height*compressedBitmap.GetTypeSize();
LOGD("===========Width: %i, height: %i - Len of bitmap element: %i==========", width, height, len);
jbyteArray bitmapData = env->NewByteArray(len);
LOGD("===========Called new byte array==========");
env->SetByteArrayRegion(bitmapData, 0, len, (const jbyte*)compressedBitmap.GetData() );
LOGD("===========Populated byte array==========");
check (bitmapData != NULL && "Couldn't create byte array");
jclass gameActivityClass = FAndroidApplication::FindJavaClass("com/epicgames/ue4/GameActivity");
check (gameActivityClass != nullptr && "GameActivityClassNotFound");
//get the method signature to take a game screenshot
jmethodID saveScreenshot = env->GetMethodID(gameActivityClass, "saveScreenshot", "([BII)V");
env->CallVoidMethod(AndroidInterface::sGameActivity, saveScreenshot, bitmapData, width, height);
env->DeleteLocalRef(bitmapData);
}
这是负责从转换为的javabyte[]
代码Bitmap
:
public void saveScreenshot(final byte[] colors, int width, int height) {
android.util.Log.d("GameActivity", "======saveScreenshot called. Width: " + width + " height: " + height + "=======");
android.util.Log.d("GameActivity", "Color content---->\n " + Arrays.toString(colors));
final BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
final Bitmap bitmap = BitmapFactory.decodeByteArray(colors, 0, colors.length, opts);
final FlipBitmap flipBitmapTask = new FlipBitmap();
flipBitmapTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, bitmap);
}
FlipBitmap 是负责将位图保存到文件的 AsyncTask:
private class FlipBitmap extends AsyncTask<Bitmap, Void, File> {
@Override
protected File doInBackground(Bitmap... params) {
final Bitmap src = params[0];
final File file = new File(MainActivity.SCREENSHOT_FOLDER + "screenshot" + System.currentTimeMillis() + ".png");
final Matrix matrix = new Matrix();
matrix.setScale(1, -1);
final Bitmap dst = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, false);
try {
final FileOutputStream out = new FileOutputStream(file);
dst.compress(Bitmap.CompressFormat.PNG, 90, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
return file;
}
@Override
protected void onPostExecute(File file) {
android.util.Log.d("GameActivity", "FlipBitmap onPostExecute");
if (file.exists()) {
final Intent i = new Intent(Intent.ACTION_SENDTO);
i.setData(Uri.parse("mailto:" + Globals.Network.MAIL_TO));
i.putExtra(Intent.EXTRA_SUBJECT, Globals.Network.MAIL_SUBJECT);
i.putExtra(Intent.EXTRA_TEXT, mBodyEmail);
i.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + file.getAbsolutePath()));
startActivity(Intent.createChooser(i, "Invia via email"));
}
}
}
提前致谢!