如何在Xamarin Android中裁剪屏幕并进行屏幕截图?

时间:2018-11-05 15:33:49

标签: android xamarin xamarin.forms xamarin.android screenshot

我正在使用以下代码在Xamarin Android中截屏,如何裁剪屏幕并进行截屏?

    private async void btnCapture_Clicked(object sender, EventArgs e)
    {    
        Bitmap imageByte = await CaptureScreenAsync();
        imageView2.SetImageBitmap(imageByte);
    }

    public async Task<Bitmap> CaptureScreenAsync()
    {
        var activity = this;
        if (activity == null)
        {
            return null;
        }

        var view = activity.Window.DecorView;
        view.DrawingCacheEnabled = true;
        Bitmap bitmap = view.GetDrawingCache(true);
        return bitmap;
    }

1 个答案:

答案 0 :(得分:0)

ScreenCapture 类是处理作物和屏幕截图的关键代码。

public class ScreenCapture {
private static final String TAG = "ScreenCaptureActivity";
public static final String MESSAGE = "message";
public static final String FILE_NAME = "temp_file";
private SimpleDateFormat dateFormat = null;
private String strDate = null;
private String pathImage = null;
private String nameImage = null;

private MediaProjection mMediaProjection = null;
private VirtualDisplay mVirtualDisplay = null;

public static int mResultCode = 0;
public static Intent mResultData = null;
public static MediaProjectionManager mMediaProjectionManager1 = null;

private WindowManager mWindowManager1 = null;
private int windowWidth = 0;
private int windowHeight = 0;
private ImageReader mImageReader = null;
private DisplayMetrics metrics = null;
private int mScreenDensity = 0;
private int mScreenWidth = 0;

Handler handler = new Handler(Looper.getMainLooper());
private Rect mRect;
private MarkSizeView.GraphicPath mGraphicPath;
private ScreenCaptureActivity activity;


@TargetApi(Build.VERSION_CODES.KITKAT)
public ScreenCapture(ScreenCaptureActivity activity, Intent intent, int resultCode
    , Rect mRect, MarkSizeView.GraphicPath mGraphicPath){
    this.activity=activity;
    mResultData=intent;
    mResultCode=resultCode;
    this.mRect = mRect;
    this.mGraphicPath = mGraphicPath;
    this.mScreenWidth = ViewUtil.getScreenWidth(activity);
    try {
        createVirtualEnvironment();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

@TargetApi(Build.VERSION_CODES.KITKAT)
public void toCapture() {
    try {

        handler.postDelayed(new Runnable() {
            public void run() {
                LogUtil.d(TAG, "before startVirtual");
                startVirtual();
                LogUtil.d(TAG, "after startVirtual");
            }
        }, 10);

        handler.postDelayed(new Runnable() {
            public void run() {
                //capture the screen
                try {
                    LogUtil.d(TAG, "before startCapture");
                    startCapture();
                    LogUtil.d(TAG, "after startCapture");
                } catch (Exception e) {
                    e.printStackTrace();
                    sendBroadcastCaptureFail();
                }
            }
        }, 100);
    } catch (Exception e) {
        e.printStackTrace();
    } catch (Error e) {
        e.printStackTrace();
    }
}

private void sendBroadcastCaptureFail() {
    ToastUtil.show(R.string.screen_capture_fail);
    activity.finish();
}

@RequiresApi(api = Build.VERSION_CODES.KITKAT)
private void createVirtualEnvironment() {
    dateFormat = new SimpleDateFormat("yyyy_MM_dd_hh_mm_ss");
    strDate = dateFormat.format(new java.util.Date());
    pathImage = Environment.getExternalStorageDirectory().getPath() + "/Pictures/";
    nameImage = pathImage + strDate + ".png";
    mMediaProjectionManager1 = (MediaProjectionManager) activity.getApplication().getSystemService(Context.MEDIA_PROJECTION_SERVICE);
    mWindowManager1 = (WindowManager) activity.getApplication().getSystemService(Context.WINDOW_SERVICE);
    windowWidth = ViewUtil.getScreenWidth(activity);
    windowHeight = ViewUtil.getSceenHeight(activity);
    metrics = new DisplayMetrics();
    mWindowManager1.getDefaultDisplay().getMetrics(metrics);
    mScreenDensity = metrics.densityDpi;
    mImageReader = ImageReader.newInstance(windowWidth, windowHeight, 0x1, 2); //ImageFormat.RGB_565

    LogUtil.d(TAG, "prepared the virtual environment");
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void startVirtual() {
    if (mMediaProjection != null) {
        LogUtil.d(TAG, "want to display virtual");
        virtualDisplay();
    } else {
        LogUtil.d(TAG, "want to build mediaprojection and display virtual");
        setUpMediaProjection();

        virtualDisplay();
    }
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void setUpMediaProjection() {
    try {
        mMediaProjection = mMediaProjectionManager1.getMediaProjection(mResultCode, mResultData);
    } catch (Exception e) {
        e.printStackTrace();
        LogUtil.d(TAG, "mMediaProjection defined");
    }

}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void virtualDisplay() {
    try {
        mVirtualDisplay = mMediaProjection.createVirtualDisplay("screen-mirror",
                windowWidth, windowHeight, mScreenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                mImageReader.getSurface(), null, null);
        LogUtil.d(TAG, "virtual displayed");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void startCapture() throws Exception {
    strDate = dateFormat.format(new java.util.Date());
    nameImage = pathImage + strDate + ".png";

    Image image = mImageReader.acquireLatestImage();

    if (image==null){
        LogUtil.d(TAG, "image==null,restart");
        handler.post(new Runnable() {
            @Override
            public void run() {
                toCapture();
            }
        });
        return;
    }
    int width = image.getWidth();
    int height = image.getHeight();
    final Image.Plane[] planes = image.getPlanes();
    final ByteBuffer buffer = planes[0].getBuffer();
    int pixelStride = planes[0].getPixelStride();
    int rowStride = planes[0].getRowStride();
    int rowPadding = rowStride - pixelStride * width;
    Bitmap bitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888);
    bitmap.copyPixelsFromBuffer(buffer);
    image.close();
    LogUtil.d(TAG, "image data captured");

    if (width!=mScreenWidth ||rowPadding !=0){
        int[] pixel=new int[width + rowPadding / pixelStride];
        bitmap.getPixels(pixel,0,width + rowPadding / pixelStride,0,0,width + rowPadding / pixelStride,1);
        int leftPadding=0;
        int rightPadding=width + rowPadding / pixelStride;
        for (int i=0;i<pixel.length;i++){
            if (pixel[i]!=0){
                leftPadding=i;
                break;
            }
        }
        for (int i=pixel.length-1;i>=0;i--){
            if (pixel[i]!=0){
                rightPadding=i;
                break;
            }
        }
        width=Math.min(width,mScreenWidth);
        if (rightPadding-leftPadding>width){
            rightPadding= width;
        }
        bitmap=Bitmap.createBitmap(bitmap,leftPadding, 0, rightPadding-leftPadding, height);
    }

    LogUtil.d(TAG, "bitmap cuted first");
    if (mGraphicPath!=null){
        mRect=new Rect(mGraphicPath.getLeft(),mGraphicPath.getTop(),mGraphicPath.getRight(),mGraphicPath.getBottom());
    }
    if (mRect != null) {

        if (mRect.left < 0)
            mRect.left = 0;
        if (mRect.right < 0)
            mRect.right = 0;
        if (mRect.top < 0)
            mRect.top = 0;
        if (mRect.bottom < 0)
            mRect.bottom = 0;
        int cut_width = Math.abs(mRect.left - mRect.right);
        int cut_height = Math.abs(mRect.top - mRect.bottom);
        if (cut_width > 0 && cut_height > 0) {
            Bitmap cutBitmap = Bitmap.createBitmap(bitmap, mRect.left, mRect.top, cut_width, cut_height);
            LogUtil.d(TAG, "bitmap cuted second");
            if (mGraphicPath!=null){
                // prepare paint
                Paint paint = new Paint();
                paint.setAntiAlias(true);
                paint.setStyle(Paint.Style.FILL_AND_STROKE);
                paint.setColor(Color.WHITE);
                Bitmap temp = Bitmap.createBitmap(cut_width, cut_height, Bitmap.Config.ARGB_8888);
                Canvas canvas = new Canvas(temp);

                Path path = new Path();
                if (mGraphicPath.size() > 1) {
                    path.moveTo((float) ((mGraphicPath.pathX.get(0)-mRect.left)), (float) ((mGraphicPath.pathY.get(0)- mRect.top)));
                    for (int i = 1; i < mGraphicPath.size(); i++) {
                        path.lineTo((float) ((mGraphicPath.pathX.get(i)-mRect.left)), (float) ((mGraphicPath.pathY.get(i)- mRect.top)));
                    }
                } else {
                    return;
                }
                canvas.drawPath(path, paint);
                paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

                // The key code
                canvas.drawBitmap(cutBitmap, 0 , 0, paint);
                LogUtil.d(TAG, "bitmap cuted third");

                saveCutBitmap(temp);

            }else {
                saveCutBitmap(cutBitmap);
            }
        }
    } else {
        saveCutBitmap(bitmap);
    }
    bitmap.recycle();//free choose whether to recycle
}

private void saveCutBitmap(Bitmap cutBitmap) {
    File localFile = new File(activity.getFilesDir(), "temp.png");
    String fileName=localFile.getAbsolutePath();
    try {
        if (!localFile.exists()) {
            localFile.createNewFile();
            LogUtil.d(TAG,"image file created");
        }
        FileOutputStream fileOutputStream = new FileOutputStream(localFile);
        if (fileOutputStream != null) {
            cutBitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
            fileOutputStream.flush();
            fileOutputStream.close();
        }
    } catch (IOException e) {
        sendBroadcastCaptureFail();
        return;
    }
    Intent newIntent = new Intent(activity, CaptureResultActivity.class);
    newIntent.putExtra(ScreenCapture.MESSAGE, "save success");
    newIntent.putExtra(ScreenCapture.FILE_NAME,fileName );
    activity.startActivity(newIntent);
    activity.finish();
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void tearDownMediaProjection() {
    if (mMediaProjection != null) {
        mMediaProjection.stop();
        mMediaProjection = null;
    }
    LogUtil.d(TAG, "mMediaProjection undefined");
}

@TargetApi(Build.VERSION_CODES.KITKAT)
private void stopVirtual() {
    if (mVirtualDisplay == null) {
        return;
    }
    mVirtualDisplay.release();
    mVirtualDisplay = null;
    LogUtil.d(TAG, "virtual display stopped");
}

public void onDestroy() {
    stopVirtual();
    tearDownMediaProjection();
    LogUtil.d(TAG, "application destroy");
}

}

MarkSizeView 用于选择您要选择的区域并显示虚拟边缘。(这是部分代码),也许您可​​以使用此onTouchEvent方法来绘制选择的区域。 / p>

public class MarkSizeView extends View {


 @Override
public boolean onTouchEvent(MotionEvent event) {
    if (!isEnabled()){
        return false;
    }
    int x= (int) event.getX();
    int y= (int) event.getY();

    if (isMarkRect) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                isUp = false;
                isAdjustMode = false;
                isMoveMode = false;
                isButtonClicked = false;
                isValid = false;
                adjustNum = 0;
                downX = x;
                downY = y;
                if (mOnClickListener != null) {
                    mOnClickListener.onTouch();
                }
                if (isAreaContainPoint(confirmArea,x, y)) {
                    isButtonClicked = true;
                    isValid = true;
                    if (mOnClickListener != null) {
                        mOnClickListener.onConfirm(markedArea);
                    }
                } else if (isAreaContainPoint(cancelArea,x, y)) {
                    isButtonClicked = true;
                    isValid = true;
                    if (mOnClickListener != null) {
                        mOnClickListener.onCancel();
                        isValid = false;
                        startX = startY = endX = endY = 0;
                        adjustMark(0, 0);
                    }
                } else if (isAreaContainPoint(ltVer,x, y)) {
                    isAdjustMode = true;
                    adjustNum = 1;
                } else if (isAreaContainPoint(rtVer,x, y)) {
                    isAdjustMode = true;
                    adjustNum = 2;
                } else if (isAreaContainPoint(lbVer,x, y)) {
                    isAdjustMode = true;
                    adjustNum = 3;
                } else if (isAreaContainPoint(rbVer,x, y)) {
                    isAdjustMode = true;
                    adjustNum = 4;
                } else if (markedArea.contains(x, y)) {
                    isMoveMode = true;
                } else {
                    isMoveMode = false;
                    startX = (int) event.getX();
                    startY = (int) event.getY();
                    endX = startX;
                    endY = startY;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (isButtonClicked) {
                    break;
                }
                adjustMark(x, y);
                break;
            case MotionEvent.ACTION_UP:
                isUp = true;
                if (isButtonClicked) {
                    break;
                }
                adjustMark(x, y);
                startX = markedArea.left;
                startY = markedArea.top;
                endX = markedArea.right;
                endY = markedArea.bottom;

                if (markedArea.width() > confirmBitmap.getWidth() * 3 + mActionGap * 3 && markedArea.height() > confirmBitmap.getHeight() * 5) {
                    //Displayed in the inner bottom of the selection
                    confirmArea.set(endX - confirmBitmap.getWidth() - mActionGap, endY - confirmBitmap.getHeight() - mActionGap, endX - mActionGap, endY - mActionGap);
                    cancelArea.set(endX - 2 * confirmBitmap.getWidth() - mActionGap * 2, endY - confirmBitmap.getHeight() - mActionGap, endX - confirmBitmap.getWidth() - mActionGap * 2, endY - mActionGap);
                } else if (endY > getHeight() - confirmBitmap.getHeight() * 3) {
                    //Displayed on top of the selection
                    confirmArea.set(endX - confirmBitmap.getWidth() - mActionGap, startY - confirmBitmap.getHeight() - mActionGap, endX - mActionGap, startY - mActionGap);
                    cancelArea.set(endX - 2 * confirmBitmap.getWidth() - mActionGap * 2, startY - confirmBitmap.getHeight() - mActionGap, endX - confirmBitmap.getWidth() - mActionGap * 2, startY - mActionGap);
                } else {
                    //Displayed below the selection
                    confirmArea.set(endX - confirmBitmap.getWidth() - mActionGap, endY + mActionGap, endX - mActionGap, endY + confirmBitmap.getHeight() + mActionGap);
                    cancelArea.set(endX - 2 * confirmBitmap.getWidth() - mActionGap * 2, endY + mActionGap, endX - confirmBitmap.getWidth() - mActionGap * 2, endY + confirmBitmap.getHeight() + mActionGap);
                }

                if (cancelArea.left<0){
                    int cancelAreaLeftMargin=Math.abs(cancelArea.left)+mActionGap;
                    cancelArea.left = cancelArea.left+cancelAreaLeftMargin;
                    cancelArea.right = cancelArea.right+cancelAreaLeftMargin;
                    confirmArea.left = confirmArea.left+cancelAreaLeftMargin;
                    confirmArea.right = confirmArea.right+cancelAreaLeftMargin;
                }

                if (!isValid) {
                    if (mOnClickListener != null) {
                        mOnClickListener.onCancel();
                    }
                }

                break;
            case MotionEvent.ACTION_CANCEL:
                isUp = true;
                break;
        }
    }else {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                isUp = false;
                isAdjustMode = false;
                isMoveMode = false;
                isButtonClicked = false;
                isValid = false;
                adjustNum = 0;
                downX = x;
                downY = y;
                if (mOnClickListener != null) {
                    mOnClickListener.onTouch();
                }
                if (isAreaContainPoint(confirmArea,x, y)) {
                    isButtonClicked = true;
                    isValid = true;
                    if (mOnClickListener != null) {
                        mOnClickListener.onConfirm(mGraphicPath);
                    }
                } else if (isAreaContainPoint(cancelArea,x, y)) {
                    isButtonClicked = true;
                    isValid = true;
                    if (mOnClickListener != null) {
                        mOnClickListener.onCancel();
                        isValid = false;
                        startX = startY = endX = endY = 0;
                        adjustMark(0, 0);
                    }
                    mGraphicPath.clear();
                } else {
                    isMoveMode = false;
                    startX = (int) event.getX();
                    startY = (int) event.getY();
                    endX = startX;
                    endY = startY;
                    mGraphicPath.clear();
                    mGraphicPath.addPath(x,y);

                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (isButtonClicked) {
                    break;
                }
                mGraphicPath.addPath(x,y);
                break;
            case MotionEvent.ACTION_UP:
                isUp = true;
                if (isButtonClicked) {
                    break;
                }
                mGraphicPath.addPath(x,y);

                startX = mGraphicPath.getLeft();
                startY = mGraphicPath.getTop();
                endX = mGraphicPath.getRight();
                endY = mGraphicPath.getBottom();

                if ((endX-startX)*(endY-startY)>200){
                    isValid=true;
                }
                markedArea.set(startX,startY,endX,endY);
                if (endY < getHeight() - confirmBitmap.getHeight() * 3){
                    //Displayed below the selection
                    confirmArea.set(endX - confirmBitmap.getWidth() - mActionGap, endY + mActionGap, endX - mActionGap, endY + confirmBitmap.getHeight() + mActionGap);
                    cancelArea.set(endX - 2 * confirmBitmap.getWidth() - mActionGap * 2, endY + mActionGap, endX - confirmBitmap.getWidth() - mActionGap * 2, endY + confirmBitmap.getHeight() + mActionGap);
                } else
                if (startY > confirmBitmap.getHeight() * 3) {
                    //Displayed on top of the selection
                    confirmArea.set(endX - confirmBitmap.getWidth() - mActionGap, startY - confirmBitmap.getHeight() - mActionGap, endX - mActionGap, startY - mActionGap);
                    cancelArea.set(endX - 2 * confirmBitmap.getWidth() - mActionGap * 2, startY - confirmBitmap.getHeight() - mActionGap, endX - confirmBitmap.getWidth() - mActionGap * 2, startY - mActionGap);
                }else if (markedArea.width() > confirmBitmap.getWidth() * 3 + mActionGap * 3 && markedArea.height() > confirmBitmap.getHeight() * 5)
                {
                    //Displayed in the inner bottom of the selection
                    confirmArea.set(endX - confirmBitmap.getWidth() - mActionGap, endY - confirmBitmap.getHeight() - mActionGap, endX - mActionGap, endY - mActionGap);
                    cancelArea.set(endX - 2 * confirmBitmap.getWidth() - mActionGap * 2, endY - confirmBitmap.getHeight() - mActionGap, endX - confirmBitmap.getWidth() - mActionGap * 2, endY - mActionGap);
                  }

                if (cancelArea.left<0){
                    int cancelAreaLeftMargin=Math.abs(cancelArea.left)+mActionGap;
                    cancelArea.left = cancelArea.left+cancelAreaLeftMargin;
                    cancelArea.right = cancelArea.right+cancelAreaLeftMargin;
                    confirmArea.left = confirmArea.left+cancelAreaLeftMargin;
                    confirmArea.right = confirmArea.right+cancelAreaLeftMargin;
                }
                if (!isValid) {
                    if (mOnClickListener != null) {
                        mOnClickListener.onCancel();
                    }
                }

                break;
            case MotionEvent.ACTION_CANCEL:
                isUp = true;
                break;
        }
    }
    postInvalidate();
    return true;
 }
}

代码要多一些,如果要翻译为Xamarin,将需要很多时间。如果您希望变得更加用户友好,则需要很多工作。