2016-06-10 12 views
4

Ich verfolge dieses Beispiel:schwarze Ränder um das genommen Screenshot

package com.mtsahakis.mediaprojectiondemo; 

import android.app.Activity; 
import android.content.Context; 
import android.content.Intent; 
import android.graphics.Bitmap; 
import android.graphics.Bitmap.CompressFormat; 
import android.graphics.PixelFormat; 
import android.graphics.Point; 
import android.hardware.display.DisplayManager; 
import android.hardware.display.VirtualDisplay; 
import android.media.Image; 
import android.media.ImageReader; 
import android.media.projection.MediaProjection; 
import android.media.projection.MediaProjectionManager; 
import android.os.Bundle; 
import android.os.Handler; 
import android.os.Looper; 
import android.util.DisplayMetrics; 
import android.util.Log; 
import android.view.Display; 
import android.view.OrientationEventListener; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.Button; 

import java.io.File; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.nio.ByteBuffer; 


public class ScreenCaptureImageActivity extends Activity { 

    private static final String TAG = ScreenCaptureImageActivity.class.getName(); 
    private static final int REQUEST_CODE = 100; 
    private static String STORE_DIRECTORY; 
    private static int IMAGES_PRODUCED; 
    private static final String SCREENCAP_NAME = "screencap"; 
    private static final int VIRTUAL_DISPLAY_FLAGS = DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY | DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC; 
    private static MediaProjection sMediaProjection; 

    private MediaProjectionManager mProjectionManager; 
    private ImageReader mImageReader; 
    private Handler mHandler; 
    private Display mDisplay; 
    private VirtualDisplay mVirtualDisplay; 
    private int mDensity; 
    private int mWidth; 
    private int mHeight; 
    private int mRotation; 
    private OrientationChangeCallback mOrientationChangeCallback; 

    private class ImageAvailableListener implements ImageReader.OnImageAvailableListener { 
     @Override 
     public void onImageAvailable(ImageReader reader) { 
      Image image = null; 
      FileOutputStream fos = null; 
      Bitmap bitmap = null; 

      try { 
       image = mImageReader.acquireLatestImage(); 
       if (image != null) { 
        Image.Plane[] planes = image.getPlanes(); 
        ByteBuffer buffer = planes[0].getBuffer(); 
        int pixelStride = planes[0].getPixelStride(); 
        int rowStride = planes[0].getRowStride(); 
        int rowPadding = rowStride - pixelStride * mWidth; 

        // create bitmap 
        bitmap = Bitmap.createBitmap(mWidth + rowPadding/pixelStride, mHeight, Bitmap.Config.ARGB_8888); 
        bitmap.copyPixelsFromBuffer(buffer); 

        // write bitmap to a file 
        fos = new FileOutputStream(STORE_DIRECTORY + "/myscreen_" + IMAGES_PRODUCED + ".png"); 
        bitmap.compress(CompressFormat.JPEG, 100, fos); 

        IMAGES_PRODUCED++; 
        Log.e(TAG, "captured image: " + IMAGES_PRODUCED); 
       } 

      } catch (Exception e) { 
       e.printStackTrace(); 
      } finally { 
       if (fos!=null) { 
        try { 
         fos.close(); 
        } catch (IOException ioe) { 
         ioe.printStackTrace(); 
        } 
       } 

       if (bitmap!=null) { 
        bitmap.recycle(); 
       } 

       if (image!=null) { 
        image.close(); 
       } 
      } 
     } 
    } 

    private class OrientationChangeCallback extends OrientationEventListener { 
     public OrientationChangeCallback(Context context) { 
      super(context); 
     } 

     @Override 
     public void onOrientationChanged(int orientation) { 
      synchronized (this) { 
       final int rotation = mDisplay.getRotation(); 
       if (rotation != mRotation) { 
        mRotation = rotation; 
        try { 
         // clean up 
         if(mVirtualDisplay != null) mVirtualDisplay.release(); 
         if(mImageReader != null) mImageReader.setOnImageAvailableListener(null, null); 

         // re-create virtual display depending on device width/height 
         createVirtualDisplay(); 
        } catch (Exception e) { 
         e.printStackTrace(); 
        } 
       } 
      } 
     } 
    } 

    private class MediaProjectionStopCallback extends MediaProjection.Callback { 
     @Override 
     public void onStop() { 
      Log.e("ScreenCapture", "stopping projection."); 
      mHandler.post(new Runnable() { 
       @Override 
       public void run() { 
        if(mVirtualDisplay != null) mVirtualDisplay.release(); 
        if(mImageReader != null) mImageReader.setOnImageAvailableListener(null, null); 
        if(mOrientationChangeCallback != null) mOrientationChangeCallback.disable(); 
        sMediaProjection.unregisterCallback(MediaProjectionStopCallback.this); 
       } 
      }); 
     } 
    } 

    /****************************************** Activity Lifecycle methods ************************/ 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     // call for the projection manager 
     mProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE); 

     // start projection 
     Button startButton = (Button)findViewById(R.id.startButton); 
     startButton.setOnClickListener(new OnClickListener() { 

      @Override 
      public void onClick(View v) { 
       startProjection(); 
      } 
     }); 

     // stop projection 
     Button stopButton = (Button)findViewById(R.id.stopButton); 
     stopButton.setOnClickListener(new OnClickListener() { 

      @Override 
      public void onClick(View v) { 
       stopProjection(); 
      } 
     }); 

     // start capture handling thread 
     new Thread() { 
      @Override 
      public void run() { 
       Looper.prepare(); 
       mHandler = new Handler(); 
       Looper.loop(); 
      } 
     }.start(); 
    } 

    @Override 
    protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
     if (requestCode == REQUEST_CODE) { 
      sMediaProjection = mProjectionManager.getMediaProjection(resultCode, data); 

      if (sMediaProjection != null) { 
       File externalFilesDir = getExternalFilesDir(null); 
       if (externalFilesDir != null) { 
        STORE_DIRECTORY = externalFilesDir.getAbsolutePath() + "/screenshots/"; 
        File storeDirectory = new File(STORE_DIRECTORY); 
        if (!storeDirectory.exists()) { 
         boolean success = storeDirectory.mkdirs(); 
         if (!success) { 
          Log.e(TAG, "failed to create file storage directory."); 
          return; 
         } 
        } 
       } else { 
        Log.e(TAG, "failed to create file storage directory, getExternalFilesDir is null."); 
        return; 
       } 

       // display metrics 
       DisplayMetrics metrics = getResources().getDisplayMetrics(); 
       mDensity = metrics.densityDpi; 
       mDisplay = getWindowManager().getDefaultDisplay(); 

       // create virtual display depending on device width/height 
       createVirtualDisplay(); 

       // register orientation change callback 
       mOrientationChangeCallback = new OrientationChangeCallback(this); 
       if (mOrientationChangeCallback.canDetectOrientation()) { 
        mOrientationChangeCallback.enable(); 
       } 

       // register media projection stop callback 
       sMediaProjection.registerCallback(new MediaProjectionStopCallback(), mHandler); 
      } 
     } 
    } 

    /****************************************** UI Widget Callbacks *******************************/ 
    private void startProjection() { 
     startActivityForResult(mProjectionManager.createScreenCaptureIntent(), REQUEST_CODE); 
    } 

    private void stopProjection() { 
     mHandler.post(new Runnable() { 
      @Override 
      public void run() { 
       if (sMediaProjection != null) { 
        sMediaProjection.stop(); 
       } 
      } 
     }); 
    } 

    /****************************************** Factoring Virtual Display creation ****************/ 
    private void createVirtualDisplay() { 
     // get width and height 
     Point size = new Point(); 
     mDisplay.getSize(size); 
     mWidth = size.x; 
     mHeight = size.y; 

     // start capture reader 
     mImageReader = ImageReader.newInstance(mWidth, mHeight, PixelFormat.RGBA_8888, 2); 
     mVirtualDisplay = sMediaProjection.createVirtualDisplay(SCREENCAP_NAME, mWidth, mHeight, mDensity, VIRTUAL_DISPLAY_FLAGS, mImageReader.getSurface(), null, mHandler); 
     mImageReader.setOnImageAvailableListener(new ImageAvailableListener(), mHandler); 
    } 
} 

einen Screenshot auf Android ver >=21 zu nehmen.

Das Problem bei diesem Beispiel ist, dass wenn ich den Screenshot nehmen, gibt es schwarze Ränder auf dem top, right & bottom des Image.

Ich kann nicht sehen, wo ist das Problem, da die gegebene Width und Height sowohl die VirtualDisplay und die Bitmap sind richtig, was ich hier fehlt?

Antwort

6

Problem ist wahrscheinlich die Größe der virtuellen Anzeige.

mDisplay.getSize(size); 

kann etwas anderes als die tatsächliche Größe des Geräts zurück, wenn Ihr Gerät eine virtuelle Navigationsleiste (in der Regel von unten auf dem Bildschirm streichen, um sie anzuzeigen).

mDisplay.getRealSize(size); 

wird wahrscheinlich Ihr Problem mit schwarzen Rändern beheben.

+1

Absolut korrekt. Bestätigt experimentell. –

+0

Nexus 5X hat immer noch eine schwarze Kante, da sowohl getSize() als auch getRealSize() 1080 zurückgeben, aber nicht. Höhe kein solches Problem obwohl. –

1
Rect rect = image.getCropRect(); 
bitmap = Bitmap.createBitmap(bitmap, rect.left, rect.top, rect.width(), rect.height()); 
+0

Während dieses Code-Snippet die Frage lösen kann, [hilft eine Erklärung] (http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) wirklich, um die Qualität Ihres Beitrags zu verbessern. Denken Sie daran, dass Sie die Frage für Leser in der Zukunft beantworten, und diese Leute könnten die Gründe für Ihren Codevorschlag nicht kennen. – yennsarah

+0

Es ist selbst zu erklären. Die Frage ist "wo ist das Problem, da die angegebene Breite und Höhe korrekt sind", und dieser Codeausschnitt gibt an, wo die tatsächliche Breite/Höhe ist. – reker