2013-08-17 10 views
13

Mam aplikację, którą chcę móc przechwycić zrzut ekranu. Tło układu to surfaceView, który pokazuje wideo z tylnego aparatu. Poniższy kod jest w stanie wykonać zrzut ekranu, ale zawartość surfaceView jest zapisana jako czarna. Oto kod:Wykonywanie zrzutów ekranu programowo nie powoduje przechwycenia zawartości surfaceVIew

btn.setOnClickListener(new OnClickListener() 
{ 

public void onClick(View v) 
{ 
    Random num = new Random(); 
    int nu=num.nextInt(1000); 
    Bitmap bmp; 
    CamView.setDrawingCacheEnabled(true); 
    CamView.buildDrawingCache(true); 
    Bitmap bmp2 = Bitmap.createBitmap(CamView.getDrawingCache()); //Screenshot of the layout 
    CamView.setDrawingCacheEnabled(false); 

    SurView.setDrawingCacheEnabled(true); 
    SurView.buildDrawingCache(true); 
    Bitmap bmp1 = Bitmap.createBitmap(SurView.getDrawingCache()); //Screenshot of the surfaceView 
    SurView.setDrawingCacheEnabled(false); 

    Bitmap bmOverlay = Bitmap.createBitmap(bmp1.getWidth(), bmp1.getHeight(),bmp1.getConfig()); 
    Canvas canvas = new Canvas(bmOverlay); //Overlaying the 2 bitmaps 
    canvas.drawBitmap(bmp1, 0,0, null); 
    canvas.drawBitmap(bmp2, 0,0, null); 
    bmp=bmOverlay; 

    //saving the file 
    ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
    bmp.compress(CompressFormat.JPEG, 100, bos); 
    byte[] bitmapdata = bos.toByteArray(); 
    ByteArrayInputStream fis = new ByteArrayInputStream(bitmapdata); 

    String picId=String.valueOf(nu); 
    String myfile="Ghost"+picId+".jpeg"; 

    File dir_image = new File(Environment.getExternalStorageDirectory()+ 
      File.separator+"Ultimate Entity Detector"); 
    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(); 
    } 
} 
}); 

Zaktualizowałem kod. Teraz tworzę 2 mapy bitowe, 1 dla układu xml i 1 dla surfaceView, a następnie nakładam je na jedną bitmapę. Ale bitmapy surfaceView jest nadal czarny

+0

Prawdopodobnie taka sama jak w przypadku powierzchni OpenGL i przechwytywania ekranu GDI opartego na Win32. Dobre pytanie dla Androida. –

+0

@ David-SkyMesh Zobacz moją odpowiedź, jeśli jesteś zainteresowany – mremremre1

Odpowiedz

9

W końcu to rozwiązałem. Poniżej podaję kod dla każdego, kto chce wiedzieć, jak robić zrzuty ekranu układu, zdjęcia z kamery bez intencji, zrzuty ekranu (rodzaj) zawartości powierzchniowej i wyświetlać zrzut ekranu w folderze:

public class Cam_View extends Activity implements SurfaceHolder.Callback { 

    protected static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 0; 
    private SurfaceView SurView; 
    private SurfaceHolder camHolder; 
    private boolean previewRunning; 
    final Context context = this; 
    public static Camera camera = null; 
    private RelativeLayout CamView; 
    private Bitmap inputBMP = null, bmp, bmp1; 
    private ImageView mImage; 

    @SuppressWarnings("deprecation") 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.camera); 

     CamView = (RelativeLayout) findViewById(R.id.camview);//RELATIVELAYOUT OR 
                   //ANY LAYOUT OF YOUR XML 

     SurView = (SurfaceView)findViewById(R.id.sview);//SURFACEVIEW FOR THE PREVIEW 
                 //OF THE CAMERA FEED 
     camHolder = SurView.getHolder();       //NEEDED FOR THE PREVIEW 
     camHolder.addCallback(this);        //NEEDED FOR THE PREVIEW 
     camHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//NEEDED FOR THE PREVIEW 
     camera_image = (ImageView) findViewById(R.id.camera_image);//NEEDED FOR THE PREVIEW 

     Button btn = (Button) findViewById(R.id.button1); //THE BUTTON FOR TAKING PICTURE 

     btn.setOnClickListener(new OnClickListener() { //THE BUTTON CODE 
      public void onClick(View v) { 
        camera.takePicture(null, null, mPicture);//TAKING THE PICTURE 
                 //THE mPicture IS CALLED 
                 //WHICH IS THE LAST METHOD(SEE BELOW) 
      } 
     }); 
    } 

    @Override 
    public void surfaceChanged(SurfaceHolder holder, int format, int width,//NEEDED FOR THE PREVIEW 
     int height) { 
     if(previewRunning) { 
      camera.stopPreview(); 
     } 
     Camera.Parameters camParams = camera.getParameters(); 
     Camera.Size size = camParams.getSupportedPreviewSizes().get(0); 
     camParams.setPreviewSize(size.width, size.height); 
     camera.setParameters(camParams); 
     try { 
      camera.setPreviewDisplay(holder); 
      camera.startPreview(); 
      previewRunning=true; 
     } catch(IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    public void surfaceCreated(SurfaceHolder holder) {     //NEEDED FOR THE PREVIEW 
     try { 
      camera=Camera.open(); 
     } catch(Exception e) { 
      e.printStackTrace(); 
      Toast.makeText(getApplicationContext(),"Error",Toast.LENGTH_LONG).show(); 
      finish(); 
     } 
    } 

    @Override 
    public void surfaceDestroyed(SurfaceHolder holder) {    //NEEDED FOR THE PREVIEW 
     camera.stopPreview(); 
     camera.release(); 
     camera=null; 
    } 

    public void TakeScreenshot(){ //THIS METHOD TAKES A SCREENSHOT AND SAVES IT AS .jpg 
     Random num = new Random(); 
     int nu=num.nextInt(1000); //PRODUCING A RANDOM NUMBER FOR FILE NAME 
     CamView.setDrawingCacheEnabled(true); //CamView OR THE NAME OF YOUR LAYOUR 
     CamView.buildDrawingCache(true); 
     Bitmap bmp = Bitmap.createBitmap(CamView.getDrawingCache()); 
     CamView.setDrawingCacheEnabled(false); // clear drawing cache 
     ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
     bmp.compress(CompressFormat.JPEG, 100, bos); 
     byte[] bitmapdata = bos.toByteArray(); 
     ByteArrayInputStream fis = new ByteArrayInputStream(bitmapdata); 

     String picId=String.valueOf(nu); 
     String myfile="Ghost"+picId+".jpeg"; 

     File dir_image = new File(Environment.getExternalStorageDirectory()+//<--- 
         File.separator+"Ultimate Entity Detector");   //<--- 
     dir_image.mkdirs();             //<--- 
     //^IN THESE 3 LINES YOU SET THE FOLDER PATH/NAME . HERE I CHOOSE TO SAVE 
     //THE FILE IN THE SD CARD IN THE FOLDER "Ultimate Entity Detector" 

     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(); 
      Toast.makeText(getApplicationContext(), 
          "The file is saved at :SD/Ultimate Entity Detector",Toast.LENGTH_LONG).show(); 
      bmp1 = null; 
      camera_image.setImageBitmap(bmp1); //RESETING THE PREVIEW 
      camera.startPreview();    //RESETING THE PREVIEW 
     } catch (FileNotFoundException e) { 
      e.printStackTrace(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    private PictureCallback mPicture = new PictureCallback() { //THIS METHOD AND THE METHOD BELOW 
           //CONVERT THE CAPTURED IMAGE IN A JPG FILE AND SAVE IT 

     @Override 
     public void onPictureTaken(byte[] data, Camera camera) { 

      File dir_image2 = new File(Environment.getExternalStorageDirectory()+ 
          File.separator+"Ultimate Entity Detector"); 
      dir_image2.mkdirs(); //AGAIN CHOOSING FOLDER FOR THE PICTURE(WHICH IS LIKE A SURFACEVIEW 
            //SCREENSHOT) 

      File tmpFile = new File(dir_image2,"TempGhost.jpg"); //MAKING A FILE IN THE PATH 
          //dir_image2(SEE RIGHT ABOVE) AND NAMING IT "TempGhost.jpg" OR ANYTHING ELSE 
      try { //SAVING 
       FileOutputStream fos = new FileOutputStream(tmpFile); 
       fos.write(data); 
       fos.close(); 
       //grabImage(); 
      } catch (FileNotFoundException e) { 
       Toast.makeText(getApplicationContext(),"Error",Toast.LENGTH_LONG).show(); 
      } catch (IOException e) { 
       Toast.makeText(getApplicationContext(),"Error",Toast.LENGTH_LONG).show(); 
      } 

      String path = (Environment.getExternalStorageDirectory()+ 
          File.separator+"Ultimate EntityDetector"+ 
               File.separator+"TempGhost.jpg");//<--- 

      BitmapFactory.Options options = new BitmapFactory.Options();//<--- 
       options.inPreferredConfig = Bitmap.Config.ARGB_8888;//<--- 
      bmp1 = BitmapFactory.decodeFile(path, options);//<---  *********(SEE BELOW) 
      //THE LINES ABOVE READ THE FILE WE SAVED BEFORE AND CONVERT IT INTO A BitMap 
      camera_image.setImageBitmap(bmp1); //SETTING THE BitMap AS IMAGE IN AN IMAGEVIEW(SOMETHING 
             //LIKE A BACKGROUNG FOR THE LAYOUT) 

      tmpFile.delete(); 
      TakeScreenshot();//CALLING THIS METHOD TO TAKE A SCREENSHOT 
      //********* THAT LINE MIGHT CAUSE A CRASH ON SOME PHONES (LIKE XPERIA T)<----(SEE HERE) 
      //IF THAT HAPPENDS USE THE LINE "bmp1 =decodeFile(tmpFile);" WITH THE METHOD BELOW 

     } 
    }; 

    public Bitmap decodeFile(File f) { //FUNCTION BY Arshad Parwez 
     Bitmap b = null; 
     try { 
      // Decode image size 
      BitmapFactory.Options o = new BitmapFactory.Options(); 
      o.inJustDecodeBounds = true; 

      FileInputStream fis = new FileInputStream(f); 
      BitmapFactory.decodeStream(fis, null, o); 
      fis.close(); 
      int IMAGE_MAX_SIZE = 1000; 
      int scale = 1; 
      if (o.outHeight > IMAGE_MAX_SIZE || o.outWidth > IMAGE_MAX_SIZE) { 
       scale = (int) Math.pow(
         2, 
         (int) Math.round(Math.log(IMAGE_MAX_SIZE 
           /(double) Math.max(o.outHeight, o.outWidth)) 
           /Math.log(0.5))); 
      } 

      // Decode with inSampleSize 
      BitmapFactory.Options o2 = new BitmapFactory.Options(); 
      o2.inSampleSize = scale; 
      fis = new FileInputStream(f); 
      b = BitmapFactory.decodeStream(fis, null, o2); 
      fis.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     return b; 
    } 
} 

Jeśli chcesz zrobić prosty zrzut ekranu (nie trzeba używać aparatu fotograficznego), możesz użyć tylko metody TakeScreenshot.

Jeśli chcesz zrobić zrzut ekranu z surfaceView with, nie można zrobić bezpośrednio z widoku powierzchni, użyj mPicture, ustaw zdjęcie zrobione jako tło, a następnie zadzwoń do TakeScreenshot, aby zrobić zrzut ekranu. (Jak pokazano powyżej)

Jeśli chcesz zrobić zdjęcie aparatem bez wywoływania innej aplikacji z zamiarem użycia, użyj funkcji takePicture z mPicture i surfaceView stuff z powyższego kodu.

To, co robi poprzedni kod, jeśli jest używane "tak jak jest", polega na wykonaniu zrzutu ekranu na zawartość układu (przyciski, obrazy, itp.) I ustawieniu jako obraz z kamery.

Poniżej ja także zapewnić podstawowe xml układ dla poprzedniego kodu:

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
android:id="@+id/camview"> 

<SurfaceView 
    android:id="@+id/sview" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:layout_alignParentLeft="true" 
    android:layout_alignParentTop="true" /> 

<ImageView 
    android:id="@+id/camera_image" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:contentDescription="@string/app_name" /> 



<Button 
    android:id="@+id/button1" 
    style="?android:attr/buttonStyleSmall" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:layout_alignParentLeft="true" 
    android:layout_alignParentTop="true" /> 


</RelativeLayout> 

nie zapomnij importować, co musi być importowane

+0

Uważam, że robienie zdjęć jest tu przesadzone. Masz już otwartą kamerę i powierzchnię podglądu. Wystarczy poprosić o wywołanie zwrotne podglądu (w twoim przypadku może to być [setOneShotPreviewCallback()] (http://developer.android.com/reference/android/hardware/Camera.html#setOneShotPreviewCallback (android.hardware.Camera.PreviewCallback))) i przekonwertuj wynikowy YUV na bitmapę. To powinno być znacznie szybsze (mniejsze opóźnienie) niż Capture. –

+0

Witaj @ mremremre1, Twój kod działa, ale obraz jest obrócony, dlaczego tak się stało? –

+0

@SagarZala spróbuj zablokować aktywność w pejzażu.Dodaj to do swojego manifestu w Androidzie: android: screenOrientation = "landscape" – mremremre1

3

Według komentarza (https://groups.google.com/forum/#!topic/android-developers/jYjvm7ItpXQ) przez inżyniera ramowego Android, SurfaceView nie jest traktowany jak normalny widok:

Widok powierzchnia jest faktycznie za twoim oknem, i dziurkowany w oknie, żebyś go zobaczył. W ten sposób możesz umieścić go w swoim oknie, ale nic w twoim oknie nie może się pojawić za nim.

Ponieważ jest to "ZASTĘPUJ" okno aplikacji, w związku z tym rysunek dla widoku okna go nie zawiera. Przypuszczam, że jedynym sposobem jest dostarczenie metody w twojej klasie SurfaceView do narysowania własnej zawartości do dostarczonego płótna/bitmapy.

Powiązane problemy