如何简单的在Android设备截去截屏远程显示界面图像

1、在布局xml文件中设置根布局对象id。

<?xml version="1.0" encoding="utf-8"?>

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=“http://schemas.android.com/apk/res/android”
xmlns:app=“http://schemas.android.com/apk/res-auto”
xmlns:tools=“http://schemas.android.com/tools”
android:id="@+id/layoutRoot"
android:layout_width=“match_parent”
android:layout_height=“match_parent”
android:background="@drawable/bg_home"
tools:context=".ui.MainActivity">

2、在Activity加载对象
private var isStopRemote = false // 控制是否退出远程截屏
private var isRemoteRunning = false //

private lateinit var layoutRoot: ConstraintLayout

layoutRoot = this.findViewById(R.id.layoutRoot) as ConstraintLayout

3、在Acitivity中调用接口获取改对象的显示图像
private fun startRemoteScreen() {
if(isRemoteRunning) {
return
}
isStopRemote = false
isRemoteRunning = true
//layoutRoot.background.setDither(true)
GlobalScope.launch(Dispatchers.Main) {
while(!isStopRemote)
try {
if(layoutRoot != null) {
layoutRoot.setDrawingCacheEnabled(true)
layoutRoot.buildDrawingCache()
delay(100)
layoutRoot.getDrawingCache()
}
} catch (ex: Exception) {

            } finally {
                try {
                    if(layoutRoot != null) {
                        layoutRoot.destroyDrawingCache()
                        layoutRoot.setDrawingCacheEnabled(false)
                    }
                } catch (ex: java.lang.Exception) {
                    ex.printStackTrace()
                }
                delay(100)
            }
    }
    isRemoteRunning = false
}

4、在model方法中处理合成图像并传输

private val screenWidth = GwApplication.SCREEN_WIDTH
private val screenHeight = GwApplication.SCREEN_HEIGHT
private var remoteImg: Bitmap? = Bitmap.createBitmap(screenWidth / 2, screenHeight / 2, Bitmap.Config.ARGB_8888)
private var remoteCanvas = Canvas(remoteImg!!)
private var output = ByteArrayOutputStream()

private var imgPath: String? = null

public fun remoteScreenRecord(bmp: Bitmap?) {
    if (bmp == null || bmp.isRecycled || remoteImg == null) {
        return
    }
    remoteCanvas.drawColor(Color.WHITE)
    val count = remoteCanvas.save()
    try {
        remoteCanvas.drawBitmap(bmp, Rect(0, 0, screenWidth, screenHeight), Rect(0, 0, screenWidth / 2, screenHeight / 2), Paint())
        remoteCanvas.save()
        output.reset()
        remoteImg!!.compress(Bitmap.CompressFormat.JPEG, 80, output)
        output.flush()
        sendRemoteScreenHidMsg(remoteImg!!.width, remoteImg!!.height, output.toByteArray())
    } catch (ex: Exception) {
        ex.printStackTrace()
    } finally {
        remoteCanvas.restoreToCount(count)
    }
}

5、Android端显示效果:
在这里插入图片描述

6、PC端显示效果(压缩图像50%)
在这里插入图片描述

7、摄像头视频图像合成
public fun remoteScreenRecord(bmp: Bitmap?, imgData: ImageDoubleData) {
if(bmp == null || bmp.isRecycled || remoteImg == null) {
return
}
remoteCanvas.drawColor(Color.WHITE)
val count = remoteCanvas.save()
var tmp: Bitmap? = null
try {
remoteCanvas.drawBitmap(bmp, Rect(0, 0, screenWidth, screenHeight), Rect(0, 0, screenWidth / 2, screenHeight / 2), Paint())
tmp = fastYUVtoRGB.convertYUVtoRGB(imgData.getTemp(), imgData.width, imgData.height)
log("====fastYUVtoRGB.convertYUVtoRGB() temp is null?${tmp != null}")
if (tmp != null) {
log("====remoteCanvas.drawBitmap(tmp)")
// 画入视频图像,注意划入的视频大小和定位
remoteCanvas.drawBitmap(tmp, Rect(0, 0, imgData.width, imgData.height), Rect(15, 62, 372 + 22, 279 + 63), Paint())
}
remoteCanvas.save()
output.reset()
remoteImg!!.compress(Bitmap.CompressFormat.JPEG, 80, output)
output.flush()
sendRemoteScreenHidMsg(remoteImg!!.width, remoteImg!!.height, output.toByteArray())
} catch (ex: Exception) {
ex.printStackTrace()
} finally {
remoteCanvas.restoreToCount(count)
if(tmp != null && !tmp.isRecycled) {
tmp.recycle()
tmp = null
}
}
}

8、合成后的显示效果
在这里插入图片描述

相关代码:
Activity界面
private lateinit var cameraView: CameraDoubleView

cameraView = findViewById(R.id.cameraView) as CameraDoubleView

private fun initCameraView(width: Int, height: Int) {
cameraView.initCameraView(GwApplication.DEFAULT_CR_CAMERA, 0, width, height)
}

// 显示摄像头
initCameraView(mWidth, mHeight);

ImageDoubleData .java文件

/**

  • author zoufeng

  • date:2021/11/18

  • desc:
    */
    public class ImageDoubleData {
    private int width;
    private int height;
    private int size;
    private byte[] data;
    private byte[] temp;
    private Boolean isNewData;
    private Boolean isNewTemp;

    public ImageDoubleData(int width, int height) {
    this.width = width;
    this.height = height;
    size = width * height * 3 / 2;
    data = new byte[size];
    temp = new byte[size];
    isNewData = true;
    isNewTemp = true;
    }

    public int getWidth() {
    return width;
    }

    public int getHeight() {
    return height;
    }

    public byte[] getData() {
    return data;
    }

    public void setData(byte[] pData) {
    synchronized (isNewData) {
    if (!isNewData) {
    System.arraycopy(pData, 0, data, 0, pData.length);
    setNewData(true);
    }
    }
    }

    public void setTemp(byte[] pData) {
    synchronized (isNewTemp) {
    if (!isNewTemp) {
    System.arraycopy(pData, 0, temp, 0, pData.length);
    setNewTemp(true);
    }
    }
    }

    public byte[] getTemp() {
    return temp;
    }

    public boolean isNewData() {
    return isNewData;
    }

    public boolean isNewTemp() {
    return isNewTemp;
    }

    public synchronized void setNewData(boolean isNew) {
    isNewData = isNew;
    }

    public synchronized void setNewTemp(boolean isNew) {
    isNewTemp = isNew;
    }
    }

CameraDoubleView.java文件

import android.content.Context;
import android.hardware.Camera;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import com.face.obj.ImageData;
import com.face.obj.ImageDoubleData;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**

  • author zoufeng

  • date:2021/11/18

  • desc:
    */
    public class CameraDoubleView extends SurfaceView implements SurfaceHolder.Callback, Camera.PreviewCallback {
    private final static String TAG = “CameraView”;
    private SurfaceHolder surfaceHolder;
    private int mCameraIndex = 0;
    private Camera mCamera;
    private int mRotate = 0;
    private int mWidth = 0;
    private int mHeight = 0;
    private int mSize = 0;
    private ArrayList<Camera.Size> listSupportSize = new ArrayList<>();

    private CameraView.onPreviewChangedListener mOnPreviewChangedListener = null;

    private ImageDoubleData imgData = null;
    private byte[] mBuffer = null;
    private boolean isPreview = false;

    public CameraDoubleView(Context context, AttributeSet attrs) {
    super(context, attrs);
    }

    /**

    • @param cameraIndex 摄像头序号
    • @param rotate 旋转角度
    • @param width 图像preview宽度
    • @param height 图像preview高度
      */
      public void initCameraView(int cameraIndex, int rotate, int width, int height){
      log(String.format(“CameraView initCameraView() cameraIndex:%d rotate:%d width:%d height:%d”, cameraIndex, rotate, width, height));
      surfaceHolder = this.getHolder();
      surfaceHolder.addCallback(this);
      mCameraIndex = cameraIndex;
      mRotate = rotate;
      mWidth = width;
      mHeight = height;
      mSize = mWidth * mHeight * 3 / 2;
      mBuffer = new byte[mSize];
      imgData = new ImageDoubleData(mWidth, mHeight);
      isPreview = false;
      }

    /**

    • 初始化SurfaceView时调用一次,另外更改surface或者onpause->onresume时调用
      */
      @Override
      public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
      log(“CameraView surfaceChanged()”);
      if (null == mCamera) {
      //Camera.open()方法说明:2.3以后支持多摄像头,所以开启前可以通过getNumberOfCameras先获取摄像头数目,
      // 再通过 getCameraInfo得到需要开启的摄像头id,然后传入Open函数开启摄像头,
      // 假如摄像头开启成功则返回一个Camera对象
      try {
      mCamera = Camera.open(mCameraIndex);
      } catch (Exception e) {
      }
      }
      if (mCamera != null) {
      int num = Camera.getNumberOfCameras();
      log(“Camera.getNumberOfCameras() num:” + num);
      Camera.Parameters parameters = mCamera.getParameters();
      List<Camera.Size> sizeList = parameters.getSupportedPictureSizes();
      log(“getSupportedPictureSizes() sizeList.size:” + sizeList.size());
      listSupportSize.clear();
      listSupportSize.addAll(sizeList);

       //设置照片的大小
       log("setPictureSize mWidth:" + mWidth + " mHeight:" + mHeight);
       parameters.setPreviewSize(mWidth , mHeight);
       parameters.setPictureSize(mWidth , mHeight);
       //预览画面默认是横屏的,需要旋转90度
       if(mRotate != 0) {
           mCamera.setDisplayOrientation(mRotate);
       }
       try {
           mCamera.setParameters(parameters);
       } catch(RuntimeException ex) {
           ex.printStackTrace();
       }
       try {
           mCamera.setPreviewDisplay(holder);
           mCamera.addCallbackBuffer(mBuffer);
           mCamera.setPreviewCallbackWithBuffer(this);
       } catch (IOException e) {
           e.printStackTrace();
       }
       //调用相机预览功能
       mCamera.startPreview();
      

      }
      }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    log(“CameraView surfaceCreated()”);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    log(“CameraView surfaceDestroyed()”);
    isPreview = false;
    if (null != mCamera) {
    try {
    mCamera.setPreviewDisplay(null);
    mCamera.setPreviewCallbackWithBuffer(null);
    } catch (IOException e) {
    e.printStackTrace();
    }
    //停止预览
    mCamera.stopPreview();
    //释放相机资源
    mCamera.release();
    mCamera = null;
    }
    }

    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
    //log("====onPreviewFrame()");
    imgData.setData(data);
    imgData.setTemp(data);
    mCamera.addCallbackBuffer(mBuffer);

    }

    public void setOnPreviewChangedListener(CameraView.onPreviewChangedListener mPreviewChangedListener) {
    log(“CameraView setOnPreviewChangedListener()”);
    this.mOnPreviewChangedListener = mPreviewChangedListener;
    }

    public interface onPreviewChangedListener {
    public void onPreviewChanged(int cameraIndex, boolean isPreview);
    }

    public ImageDoubleData getImageData() {
    return imgData;
    }

    public int getPreviewWidth() {
    return mWidth;
    }

    public int getPreviewHeight() {
    return mHeight;
    }

    public boolean isPreview() {
    return isPreview;
    }

    public List<Camera.Size> getListSupportSize() {
    return listSupportSize;
    }

    private void log(String msg) {
    Log.d(TAG, msg);
    }
    }

猜你喜欢

转载自blog.csdn.net/bluefire1126/article/details/121618613