Android的抓图表面视图显示黑屏 [英] Android Take Screenshot of Surface View Shows Black Screen

查看:1513
本文介绍了Android的抓图表面视图显示黑屏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图把我的游戏截图通过code,并通过一个Intent共享。我能够做的那些事情,但是截图总是显得黑。这里是code相关的共享截图:

I am attempting to Take a Screenshot of my Game through code and Share it through an Intent. I able to do of those things, however the screenshot always appears black. Here is the Code Related to Sharing the Screenshot:

View view = MainActivity.getView();
view.setDrawingCacheEnabled(true);
Bitmap screen = Bitmap.createBitmap(view.getDrawingCache(true));
.. save Bitmap

这是在MainActivity:

This is in the MainActivity:

view = new GameView(this);
view.setLayoutParams(new RelativeLayout.LayoutParams(
            RelativeLayout.LayoutParams.FILL_PARENT,
            RelativeLayout.LayoutParams.FILL_PARENT));

public static SurfaceView getView() {
    return view;
}

和视图本身:

public class GameView extends SurfaceView implements SurfaceHolder.Callback {
private static SurfaceHolder surfaceHolder;
...etc

这是我如何绘制一切:

And this is how I am Drawing everything:

Canvas canvas = surfaceHolder.lockCanvas(null);
        if (canvas != null) {
                Game.draw(canvas);
...

确定,基于一些答案,我已经构建了这一点:

Ok, based on some answers, i have constructed this:

public static void share() {
    Bitmap screen = GameView.SavePixels(0, 0, Screen.width, Screen.height);
    Calendar c = Calendar.getInstance();
    Date d = c.getTime();
    String path = Images.Media.insertImage(
            Game.context.getContentResolver(), screen, "screenShotBJ" + d
                    + ".png", null);
    System.out.println(path + " PATH");
    Uri screenshotUri = Uri.parse(path);
    final Intent emailIntent = new Intent(
            android.content.Intent.ACTION_SEND);
    emailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    emailIntent.putExtra(Intent.EXTRA_STREAM, screenshotUri);
    emailIntent.setType("image/png");
    Game.context.startActivity(Intent.createChooser(emailIntent,
            "Share High Score:"));
}

该Gameview包含下面的方法:

The Gameview contains the Following Method:

public static Bitmap SavePixels(int x, int y, int w, int h) {
    EGL10 egl = (EGL10) EGLContext.getEGL();
    GL10 gl = (GL10) egl.eglGetCurrentContext().getGL();
    int b[] = new int[w * (y + h)];
    int bt[] = new int[w * h];
    IntBuffer ib = IntBuffer.wrap(b);
    ib.position(0);
    gl.glReadPixels(x, 0, w, y + h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, ib);
    for (int i = 0, k = 0; i < h; i++, k++) {
        for (int j = 0; j < w; j++) {
            int pix = b[i * w + j];
            int pb = (pix >> 16) & 0xff;
            int pr = (pix << 16) & 0x00ff0000;
            int pix1 = (pix & 0xff00ff00) | pr | pb;
            bt[(h - k - 1) * w + j] = pix1;
        }
    }

    Bitmap sb = Bitmap.createBitmap(bt, w, h, Bitmap.Config.ARGB_8888);
    return sb;
}

的截图还没有亮。是不是有什么毛病我保存它也许是这样?

The Screenshot is still Black. Is there something wrong with the way I am saving it perhaps?

我已经尝试几种不同的方法采取截图,但他们没有工作: 在上面的code所示的是最常见的建议之一。但它似乎并没有工作。 这是一个问题,使用SurfaceView?如果是这样,为什么view.getDrawingCache(真),即使存在,如果我不能使用它,我该如何解决这个问题?

I have attempted several different methods to take the Screenshot, but none of them worked: The one shown in the code above was the most commonly suggested one. But it does not seem to work. Is this an Issue with using SurfaceView? And if so, why does view.getDrawingCache(true) even exist if I cant use it and how do I fix this?

工作code:

public static void share() {
    // GIVES BLACK SCREENSHOT:
    Calendar c = Calendar.getInstance();
    Date d = c.getTime();

    Game.update();
    Bitmap.Config conf = Bitmap.Config.RGB_565;
    Bitmap image = Bitmap.createBitmap(Screen.width, Screen.height, conf);
    Canvas canvas = GameThread.surfaceHolder.lockCanvas(null);
    canvas.setBitmap(image);
    Paint backgroundPaint = new Paint();
    backgroundPaint.setARGB(255, 40, 40, 40);
    canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(),
            backgroundPaint);
    Game.draw(canvas);
    Bitmap screen = Bitmap.createBitmap(image, 0, 0, Screen.width,
            Screen.height);
    canvas.setBitmap(null);
    GameThread.surfaceHolder.unlockCanvasAndPost(canvas);

    String path = Images.Media.insertImage(
            Game.context.getContentResolver(), screen, "screenShotBJ" + d
                    + ".png", null);
    System.out.println(path + " PATH");
    Uri screenshotUri = Uri.parse(path);
    final Intent emailIntent = new Intent(
            android.content.Intent.ACTION_SEND);
    emailIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    emailIntent.putExtra(Intent.EXTRA_STREAM, screenshotUri);
    emailIntent.setType("image/png");
    Game.context.startActivity(Intent.createChooser(emailIntent,
            "Share High Score:"));
}

感谢你。

推荐答案

有一个很大的困惑,这一点,和几个<一个href="http://stackoverflow.com/questions/27486164/how-to-take-snapshot-of-surfaceview/27488970#27488970">correct <一href="http://stackoverflow.com/questions/25086263/take-screenshot-of-surfaceview/25086739#25086739">answers.

There is a great deal of confusion about this, and a few correct answers.

这里的交易:

  1. 一个SurfaceView有两部分,表面和视图。表面上是从所有视图UI元素的完全独立的层。该 getDrawingCache()办法适用于View层而已,所以它并没有反映出对地面任何东西。

  1. A SurfaceView has two parts, the Surface and the View. The Surface is on a completely separate layer from all of the View UI elements. The getDrawingCache() approach works on the View layer only, so it doesn't capture anything on the Surface.

缓冲队列具有一个生产者 - 消费者的API,它只能有一个生产商。 Canvas是一个生产者,GLES是另一回事。你不能用帆布画和读取像素GLES。 (从技术上讲,你的可以的如果画布用GLES和正确的EGL背景是当前的,当你去读取像素,但是这不能保证。画布渲染到表面没有任何发布的版本加速Android系统,所以现在有没有希望它的工作的。)

The buffer queue has a producer-consumer API, and it can have only one producer. Canvas is one producer, GLES is another. You can't draw with Canvas and read pixels with GLES. (Technically, you could if the Canvas were using GLES and the correct EGL context was current when you went to read the pixels, but that's not guaranteed. Canvas rendering to a Surface is not accelerated in any released version of Android, so right now there's no hope of it working.)

(不相关的情况,但我会提到它的完整性:)一个表面不是一个帧缓存,它的缓冲区队列。当您提交一个缓冲区GLES,它跑了,你不能再从中读取。所以,如果你是渲染与GLES和GLES采集,则需要前回调用eglSwapBuffers()来读取像素。

(Not relevant for your case, but I'll mention it for completeness:) A Surface is not a frame buffer, it is a queue of buffers. When you submit a buffer with GLES, it is gone, and you can no longer read from it. So if you were rendering with GLES and capturing with GLES, you would need to read the pixels back before calling eglSwapBuffers().

通过画布渲染,最简单的方法来捕获表面内容是简单地画了两遍。创建一个屏幕大小的位图,创建位图一个画布,并将它传递给你的平局()的功能。

With Canvas rendering, the easiest way to "capture" the Surface contents is to simply draw it twice. Create a screen-sized Bitmap, create a Canvas from the Bitmap, and pass it to your draw() function.

通过GLES渲染,你可以使用glReadPixels()的缓冲交换之前抢像素。有一个(较便宜比code在这里)实施抢code在 Grafika 的;看到 saveFrame()的<一个href="https://github.com/google/grafika/blob/master/src/com/android/grafika/gles/EglSurfaceBase.java">EglSurfaceBase.

With GLES rendering, you can use glReadPixels() before the buffer swap to grab the pixels. There's a (less-expensive than the code here) implementation of the grab code in Grafika; see saveFrame() in EglSurfaceBase.

如果你希望得到一个复合屏幕快照同时含有表面内容和查看用户界面的内容,则需要两个手动捕获的画布上面,捕捉观与通常的绘图缓存伎俩,再复合。请注意这不会拿起系统部件(状态栏,导航栏)。

If you were hoping to get a composite screen shot containing both the Surface contents and the View UI contents, you will need to capture the Canvas as above, capture the View with the usual drawing cache trick, and then composite the two manually. Note this won't pick up the system parts (status bar, nav bar).

如果您想了解这一切的东西的作品,看到Android 系统级图形架构文档。

If you want to understand how all this stuff works, see the Android System-Level Graphics Architecture doc.

这篇关于Android的抓图表面视图显示黑屏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆