Pantalla de captura de GLSurfaceView en bitmap

Necesito poder capturar una imagen de GLSurfaceView en cierto momento. Tengo el siguiente código:

 relative.setDrawingCacheEnabled(true); screenshot = Bitmap.createBitmap(relative.getDrawingCache()); relative.setDrawingCacheEnabled(false); Log.v(TAG, "Screenshot height: " + screenshot.getHeight()); image.setImageBitmap(screenshot); 

GLSurfaceView está dentro de RelativeLayout , pero también lo GLSurfaceView intentado directamente usando GLSurfaceView para intentar capturar la imagen. Con esto, creo que la pantalla captura una imagen transparente, es decir, nada allí. Cualquier ayuda será apreciada.

SurfaceView y GLSurfaceView perforan agujeros en sus ventanas para permitir que se muestren sus superficies. En otras palabras, tienen áreas transparentes.

Por lo tanto, no puede capturar una imagen llamando a GLSurfaceView.getDrawingCache() .

Si desea obtener una imagen de GLSurfaceView , debe invocar gl.glReadPixels() en GLSurfaceView.onDrawFrame() .

createBitmapFromGLSurface método createBitmapFromGLSurface y lo llamo onDrawFrame() .

(El código original puede ser del código de skuld ).

 private Bitmap createBitmapFromGLSurface(int x, int y, int w, int h, GL10 gl) throws OutOfMemoryError { int bitmapBuffer[] = new int[w * h]; int bitmapSource[] = new int[w * h]; IntBuffer intBuffer = IntBuffer.wrap(bitmapBuffer); intBuffer.position(0); try { gl.glReadPixels(x, y, w, h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, intBuffer); int offset1, offset2; for (int i = 0; i < h; i++) { offset1 = i * w; offset2 = (h - i - 1) * w; for (int j = 0; j < w; j++) { int texturePixel = bitmapBuffer[offset1 + j]; int blue = (texturePixel >> 16) & 0xff; int red = (texturePixel << 16) & 0x00ff0000; int pixel = (texturePixel & 0xff00ff00) | red | blue; bitmapSource[offset2 + j] = pixel; } } } catch (GLException e) { return null; } return Bitmap.createBitmap(bitmapSource, w, h, Bitmap.Config.ARGB_8888); } 

Aquí está una solución completa si está utilizando una biblioteca de terceros que simplemente ‘transfiere’ un GLSurfaceView definido en su diseño. No tendrá un control sobre onDrawFrame () del renderizador, esto puede ser un problema …

Para hacer esto, necesita ponerlo en cola para que GLSurfaceView lo maneje.

 private GLSurfaceView glSurfaceView; // findById() in onCreate private Bitmap snapshotBitmap; private interface BitmapReadyCallbacks { void onBitmapReady(Bitmap bitmap); } /* Usage code captureBitmap(new BitmapReadyCallbacks() { @Override public void onBitmapReady(Bitmap bitmap) { someImageView.setImageBitmap(bitmap); } }); */ // supporting methods private void captureBitmap(final BitmapReadyCallbacks bitmapReadyCallbacks) { glSurfaceView.queueEvent(new Runnable() { @Override public void run() { EGL10 egl = (EGL10) EGLContext.getEGL(); GL10 gl = (GL10)egl.eglGetCurrentContext().getGL(); snapshotBitmap = createBitmapFromGLSurface(0, 0, glSurfaceView.getWidth(), glSurfaceView.getHeight(), gl); runOnUiThread(new Runnable() { @Override public void run() { bitmapReadyCallbacks.onBitmapReady(snapshotBitmap); } }); } }); } // from other answer in this question private Bitmap createBitmapFromGLSurface(int x, int y, int w, int h, GL10 gl) { int bitmapBuffer[] = new int[w * h]; int bitmapSource[] = new int[w * h]; IntBuffer intBuffer = IntBuffer.wrap(bitmapBuffer); intBuffer.position(0); try { gl.glReadPixels(x, y, w, h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, intBuffer); int offset1, offset2; for (int i = 0; i < h; i++) { offset1 = i * w; offset2 = (h - i - 1) * w; for (int j = 0; j < w; j++) { int texturePixel = bitmapBuffer[offset1 + j]; int blue = (texturePixel >> 16) & 0xff; int red = (texturePixel << 16) & 0x00ff0000; int pixel = (texturePixel & 0xff00ff00) | red | blue; bitmapSource[offset2 + j] = pixel; } } } catch (GLException e) { Log.e(TAG, "createBitmapFromGLSurface: " + e.getMessage(), e); return null; } return Bitmap.createBitmap(bitmapSource, w, h, Config.ARGB_8888); } 

Nota: En este código, cuando hago clic en el Botón, toma la captura de pantalla como Imagen y la guarda en la ubicación de la tarjeta SD. onDraw condición booleana y una instrucción if en el método onDraw , porque la clase del procesador puede llamar al método onDraw cualquier momento y de todos modos, y sin el if este código puede guardar muchas imágenes en la tarjeta de memoria.

Clase de actividad principal:

 protected boolean printOptionEnable = false; saveImageButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Log.v("hari", "pan button clicked"); isSaveClick = true; myRenderer.printOptionEnable = isSaveClick; } }); 

Clase MyRenderer:

 int width_surface , height_surface ; @Override public void onSurfaceChanged(GL10 gl, int width, int height) { Log.i("JO", "onSurfaceChanged"); // Adjust the viewport based on geometry changes, // such as screen rotation GLES20.glViewport(0, 0, width, height); float ratio = (float) width / height; width_surface = width ; height_surface = height ; } @Override public void onDrawFrame(GL10 gl) { try { if (printOptionEnable) { printOptionEnable = false ; Log.i("hari", "printOptionEnable if condition:" + printOptionEnable); int w = width_surface ; int h = height_surface ; Log.i("hari", "w:"+w+"-----h:"+h); int b[]=new int[(int) (w*h)]; int bt[]=new int[(int) (w*h)]; IntBuffer buffer=IntBuffer.wrap(b); buffer.position(0); GLES20.glReadPixels(0, 0, w, h,GLES20.GL_RGBA,GLES20.GL_UNSIGNED_BYTE, buffer); for(int i=0; i>16)&0xff; int pr=(pix<<16)&0x00ff0000; int pix1=(pix&0xff00ff00) | pr | pb; bt[(hi-1)*w+j]=pix1; } } Bitmap inBitmap = null ; if (inBitmap == null || !inBitmap.isMutable() || inBitmap.getWidth() != w || inBitmap.getHeight() != h) { inBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); } //Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); inBitmap.copyPixelsFromBuffer(buffer); //return inBitmap ; // return Bitmap.createBitmap(bt, w, h, Bitmap.Config.ARGB_8888); inBitmap = Bitmap.createBitmap(bt, w, h, Bitmap.Config.ARGB_8888); ByteArrayOutputStream bos = new ByteArrayOutputStream(); inBitmap.compress(CompressFormat.JPEG, 90, bos); byte[] bitmapdata = bos.toByteArray(); ByteArrayInputStream fis = new ByteArrayInputStream(bitmapdata); final Calendar c=Calendar.getInstance(); long mytimestamp=c.getTimeInMillis(); String timeStamp=String.valueOf(mytimestamp); String myfile="hari"+timeStamp+".jpeg"; dir_image = new File(Environment.getExternalStorageDirectory()+File.separator+ "printerscreenshots"+File.separator+"image"); dir_image.mkdirs(); try { File tmpFile = new File(dir_image,myfile); FileOutputStream fos = new FileOutputStream(tmpFile); byte[] buf = new byte[1024]; int len; while ((len = fis.read(buf)) > 0) { fos.write(buf, 0, len); } fis.close(); fos.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } Log.v("hari", "screenshots:"+dir_image.toString()); } } catch(Exception e) { e.printStackTrace(); } } 

Puede usar un GLTextureView que extienda TextureView en lugar de GlsurfaceView para mostrarle los datos de OpenGL.

Ver: http://stackoverflow.com/questions/12061419/converting-from-glsurfaceview-to-textureview-via-gltextureview

Como GLTextureView se extiende desde TextureView, tiene una función getBitmap que debería funcionar.

 myGlTextureView.getBitmap(int width, int height)