Search code examples
javaandroidbitmapsurfaceview

surfaceview to bitmap return black or Null


Im struggling to capture a surfaceview and save it to bitmap so I can convert it later to pdf, I tested many approaches but none of them seems to work all what I get is an empty bitmap or black one, I have tried : surfaceView.getDrawingCache(); and surfaceView.getBackground(); and even replace it with textureview and do textureview.getbitmap() but no different result,

//************************************

private void initPaint(){
    paint.setAntiAlias(true);
    paint.setStyle(Paint.Style.STROKE);
    paint.setColor(Color.BLACK);
    paint.setStrokeWidth(5);
}

private void initSurfaceView() {
    touchHelper = TouchHelper.create(surfaceView, callback);

    surfaceView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
        @Override
        public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int
                oldRight, int oldBottom) {
            if (cleanSurfaceView()){
                surfaceView.removeOnLayoutChangeListener(this);
            }
            List<Rect> exclude = new ArrayList<>();
            exclude.add(getRelativeRect(surfaceView, buttonEraser));
            exclude.add(getRelativeRect(surfaceView, buttonPen));
            exclude.add(getRelativeRect(surfaceView, cbRender));

            Rect limit = new Rect();
            surfaceView.getLocalVisibleRect(limit);
            touchHelper.setStrokeWidth(3.0f)
                    .setLimitRect(limit, exclude)
                    .openRawDrawing();
        }
    });

}

//************************

public Rect getRelativeRect(final View parentView, final View childView) {
    int [] parent = new int[2];
    int [] child = new int[2];
    parentView.getLocationOnScreen(parent);
    childView.getLocationOnScreen(child);
    Rect rect = new Rect();
    childView.getLocalVisibleRect(rect);
    rect.offset(child[0] - parent[0], child[1] - parent[1]);
    return rect;
}

private boolean cleanSurfaceView() {
    if (surfaceView.getHolder() == null) {
        return false;
    }
    Canvas canvas = surfaceView.getHolder().lockCanvas();
    if (canvas == null) {
        return false;
    }
    canvas.drawColor(Color.WHITE);
    surfaceView.getHolder().unlockCanvasAndPost(canvas);
    return true;
}

//*****************************

private void drawRect(TouchPoint endPoint){

    Canvas canvas = surfaceView.getHolder().lockCanvas();
    if (canvas == null ) {
        return;
    }

    if (startPoint == null || endPoint == null) {
        surfaceView.getHolder().unlockCanvasAndPost(canvas);
        return;
    }

    canvas.drawColor(Color.WHITE);
    canvas.drawRect(startPoint.getX(), startPoint.getY(), endPoint.getX(), endPoint.getY(), paint);

    Log.d(TAG,"drawRect ");
    surfaceView.getHolder().unlockCanvasAndPost(canvas);
}

private RawInputCallback callback = new RawInputCallback() {

    @Override
    public void onBeginRawDrawing(boolean b, TouchPoint touchPoint) {
        Log.d(TAG, "onBeginRawDrawing");
        startPoint = touchPoint;
        Log.d(TAG,touchPoint.getX() +", " +touchPoint.getY());
        countRec = 0;

    }

    @Override
    public void onEndRawDrawing(boolean b, TouchPoint touchPoint) {
        Log.d(TAG, "onEndRawDrawing");
        if (!cbRender.isChecked()){
            drawRect(touchPoint);
        }
        Log.d(TAG,touchPoint.getX() +", " +touchPoint.getY());
        build();
    }

    @Override
    public void onRawDrawingTouchPointMoveReceived(TouchPoint touchPoint) {
        Log.d(TAG, "onRawDrawingTouchPointMoveReceived");
        Log.d(TAG,touchPoint.getX() +", " +touchPoint.getY());
        countRec++;
        countRec = countRec % INTERVAL;
        if (!cbRender.isChecked() && countRec == INTERVAL - 1 ){
            drawRect(touchPoint);
        }
        Log.d(TAG,"countRec = " + countRec);

    }

I guess the display data for the SurfaceView isn't even accessible to the app processor, it may be the output of a hardware video pipeline that is composited with the display output of the app processor through a dedicated overlay.


Solution

  • Solve It, i added a another canvas and from the touchHelper i get the raw data then draw the strokes in the new canvas

     @Override
        public void onBeginRawDrawing(boolean b, TouchPoint touchPoint) {
            Log.d(TAG, "onBeginRawDrawing");
            startPoint = touchPoint;
            Log.d(TAG,touchPoint.getX() +", " +touchPoint.getY());
            countRec = 0; 
            if (baseBitmap == null) {
                baseBitmap = Bitmap.createBitmap(iv_canvas.getWidth(),
                        iv_canvas.getHeight(), Bitmap.Config.ARGB_8888);
                canva = new Canvas(baseBitmap);
                canva.drawColor(Color.WHITE);
                iv_canvas.setImageBitmap(baseBitmap);
    
            }
        }
    

    //***********************

     @Override
        public void onRawDrawingTouchPointMoveReceived(TouchPoint touchPoint) {
            Log.d(TAG, "onRawDrawingTouchPointMoveReceived");
            Log.d(TAG,touchPoint.getX() +", " +touchPoint.getY());
            countRec++;
            countRec = countRec % INTERVAL;
            if (!cbRender.isChecked() && countRec == INTERVAL - 1 ){
                drawRect(touchPoint);
            }
            Log.d(TAG,"countRec = " + countRec);
    
            canva.drawLine(startPoint.x, startPoint.y, touchPoint.x, touchPoint.y, paint);
            startPoint=touchPoint;
        }