2013-08-17 50 views
13

Tôi có một ứng dụng mà tôi muốn có thể chụp ảnh chụp màn hình. Nền của bố cục là một bề mặt cho thấy video từ camera phía sau. Đoạn mã sau có thể chụp ảnh màn hình nhưng nội dung của SurfaceView được lưu thành màu đen. Đây là mã:Chụp ảnh màn hình theo chương trình không nắm bắt được nội dung của 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(); 
    } 
} 
}); 

Tôi đã cập nhật mã. Bây giờ tôi tạo 2 bitmap, 1 cho xml bố trí và 1 cho SurfaceView và sau đó tôi phủ chúng vào một bitmap duy nhất. Nhưng bitmap surfaceView vẫn còn đen

+0

Có lẽ giống như với OpenGL bề mặt và chụp ảnh màn hình GDI-dựa trên Win32. Câu hỏi hay cho android. –

+0

@ David-SkyMesh Xem câu trả lời của tôi nếu bạn quan tâm – mremremre1

Trả lời

9

Cuối cùng tôi đã giải quyết vấn đề này. Dưới đây tôi cung cấp một số mã cho bất kỳ ai muốn biết cách chụp ảnh màn hình bố cục, hình ảnh từ máy ảnh mà không có ý định, ảnh chụp màn hình (loại) nội dung của chế độ xem bề mặt và lưu ảnh chụp màn hình vào một thư mục:

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

Nếu bạn muốn chụp ảnh màn hình đơn giản (không cần nguồn cấp dữ liệu máy ảnh), bạn có thể sử dụng phương pháp TakeScreenshot một mình.

Nếu bạn muốn chụp ảnh màn hình bề mặt không thể thực hiện trực tiếp từ surfaceview, hãy sử dụng mPicture, đặt ảnh bạn chụp thành backgroung và sau đó gọi TakeScreenshot để chụp ảnh màn hình của bạn.)

Nếu bạn muốn chụp ảnh bằng máy ảnh mà không cần gọi một ứng dụng máy ảnh khác với mục đích, hãy sử dụng takePicture với mPicture và nội dung SurfaceView từ mã bên trên.

Mã trước đó sẽ làm gì nếu sử dụng "nguyên trạng" là chụp ảnh màn hình của nội dung bố cục (nút, hình ảnh tưởng tượng, v.v ...) và đặt làm hình ảnh ngược từ máy ảnh.

Dưới đây tôi cũng cung cấp một xml bố trí cơ bản cho mã theo thời gian:

<?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> 

Dont quên để nhập khẩu những gì cần phải được nhập khẩu

+0

Tôi tin rằng chụp ảnh là một sự vượt qua ở đây. Bạn đã có một máy ảnh mở và một bề mặt xem trước. Đủ để yêu cầu gọi lại xem trước (trong trường hợp của bạn, có thể là [setOneShotPreviewCallback()] (http://developer.android.com/reference/android/hardware/Camera.html#setOneShotPreviewCallback (android.hardware.Camera.PreviewCallback)))), và chuyển đổi YUV thành bitmap. Điều này sẽ nhanh hơn nhiều (chậm trễ hơn) so với Capture. –

+0

Xin chào @ mremremre1, mã của bạn đang hoạt động, nhưng hình ảnh được xoay vòng, tại sao điều này lại xảy ra? –

+0

@SagarZala thử khóa hoạt động ở chế độ ngang.Thêm mục này vào tệp kê khai của bạn bên trong android: android: screenOrientation = "landscape" – mremremre1

3

Theo nhận xét (https://groups.google.com/forum/#!topic/android-developers/jYjvm7ItpXQ) bởi một kỹ sư Android Framework, SurfaceView không được điều trị như một cái nhìn bình thường:

Quan điểm bề mặt thực sự là BEHIND cửa sổ của bạn, và một lỗ được đục lỗ trong cửa sổ để bạn nhìn thấy nó. Do đó bạn có thể đặt mọi thứ lên trên nó trong cửa sổ của bạn, nhưng không có gì trong cửa sổ của bạn có thể xuất hiện phía sau nó.

Vì cửa sổ ứng dụng "BEHIND", do đó bản vẽ cho chế độ xem cửa sổ sẽ không chứa nó. Tôi cho rằng cách duy nhất sau đó là cung cấp một phương thức trong lớp SurfaceView của bạn để vẽ nội dung của riêng nó vào Canvas/Bitmap đã cung cấp.