12

Path drawn on scaled GLES20RecordingCanvas has quality as if it was drawn unscaled in bitmap and then up-scaled.

In contrast, if I create Canvas with backing bitmap and then apply the same scaling transformations to Canvas object I get much superior bitmap.

Here both circles are drawn with Path.addCircle and using Canvas.scale. Upper circle is drawn with scaled GLES20RecordingCanvas and lower is drawn with scaled simple Canvas with backing bitmap.

Some code:

public class TestPathRenderer extends View {

    ...

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        int measuredWidth = getMeasuredWidth();
        int measuredHeight = getMeasuredHeight();
        float distortedWidth = getDistortedWidth();
        float distortedHeight = getDistortedHeight();

        path.reset();
        path.addCircle(distortedWidth/2f, distortedHeight/2f, Math.min(distortedWidth/2f, distortedHeight/2f), Path.Direction.CW);

        bitmap = assembleNewBitmap(measuredWidth, measuredHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        switch (renderMode) {
            case RENDER_MODE_WO_BITMAP:
                drawOnCanvas(canvas);
                break;
            case RENDER_MODE_WITH_BITMAP:
                canvas.drawBitmap(bitmap, 0f, 0f, paint);
                break;
            default:
                throw new UnsupportedOperationException("Undefined render mode: " + renderMode);
        }
    }

    private Bitmap assembleNewBitmap(int w, int h) {
        Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawOnCanvas(canvas);
        return bitmap;
    }

    private void drawOnCanvas(@NonNull Canvas canvas) {
        canvas.save();
        canvas.scale(DISTORTION_FACTOR, DISTORTION_FACTOR);
        canvas.drawPath(path, paint);
        canvas.restore();
    }
}

Full example

I can't understand the quality difference with these two cases. For me it seems that they have to be interchangeable.

Vsevolod Ganin
  • 623
  • 8
  • 22

2 Answers2

3

Poor quality during scaling is a limitation of Hardware Acceleration according to Android docs.

Bracadabra
  • 3,609
  • 3
  • 26
  • 46
1

After seeing your question, I decided to check out the source code of the GLES20RecordingCanvas class. And here's what I found out:

GLES20RecordingCanvas extends from GLES20Canvas which extends from HardwareCanvas. This HardwareCanvas class extends from Canvas. But the main difference I noticed is that it overrides the isHardwareAcceleratedMethod() returning true.

So my assumption is that the GLES20RecordingCanvas renders the bitmap with Hardware Acceleration while Canvas doesn't. And this is probably why you get less quality with the GLES20RecorgingCanvas.