2011-04-01 9 views
29

특정 시점에 GLSurfaceView의 이미지를 캡처 할 수 있어야합니다. 나는 다음과 같은 코드가 있습니다비트 맵에 GLSurfaceView 화면 캡처

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

GLSurfaceViewRelativeLayout 내에 포함되어, 그러나 나는 또한이 똑바로 시도하고 이미지를 캡처 GLSurfaceView를 사용하려고합니다. 이걸로 나는 스크린이 투명한 이미지, 즉 아무것도 볼 수 없다고 생각한다. 어떤 도움을 주시면 감사하겠습니다.

+1

안녕하세요 저는 동일한 문제가 발생했기 때문에 해결책을 찾았습니까? 공유해 주셔서 감사합니다. – DroidBot

+0

이 질문에 대한 답변을 찾지 못했습니다. – SamRowley

+0

계속 렌더링 하시겠습니까 ?? – srinivasan

답변

42

SurfaceViewGLSurfaceView 창에 펀치 구멍이있어 표면을 표시 할 수 있습니다. 다시 말해 투명 영역이 있습니다.

GLSurfaceView.getDrawingCache()을 호출하여 이미지를 캡처 할 수 없습니다.

GLSurfaceView에서 이미지를 가져 오려면 gl.glReadPixels()GLSurfaceView.onDrawFrame()에 불러야합니다.

createBitmapFromGLSurface 방법을 패치하고 onDrawFrame()으로 전화하십시오.

(원래 코드는 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); 
} 
+0

안녕하세요 Dalinaum, 위의 방법을 사용해보세요. 이 메소드를 어디에 두는가. – harikrishnan

+1

GLSurfaceView의 서브 클래스에'createBitmapFromGLSurface'를 넣을 수 있습니다. onDraw()에서 호출하는 것이 중요합니다. – Dalinaum

+1

그러나 onDraw에는 gl 인스턴스가 없습니다. 어떻게 검색 할 수 있습니까? – Nativ

2

참고 :이 코드에서, 내가 버튼을 클릭하면, 그것은 이미지로 스크린 샷을 소요하고 SDCARD 위치에 저장 . 렌더러 클래스가 onDraw 메서드를 언제든지 호출 할 수 있기 때문에 부울 조건과 if 문을 메서드에 사용 했으므로 if 코드가 없으면 메모리 카드에 많은 이미지가 저장 될 수 있습니다.

MainActivity 클래스 :

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; 
    } 
}); 

MyRenderer 클래스 : 당신은 당신이 당신의 레이아웃에 정의 된 GLSurfaceView '전달'타사 라이브러리를 사용하는 경우

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<h; i++) 
      { 
       //remember, that OpenGL bitmap is incompatible with Android bitmap 
       //and so, some correction need.   
       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-i-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(); 
    } 
} 
11

여기에 완벽한 솔루션입니다 . 당신은 렌더러의 onDrawFrame() 핸들을 가지지 않을 것입니다, 이것은 문제가 될 수 있습니다 ...

이렇게하려면 처리 할 GLSurfaceView를 큐에 넣어야합니다.

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); 
}