Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why path drawn on scaled GLES20RecordingCanvas and simple Canvas has different qualities?

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.

like image 734
Vsevolod Ganin Avatar asked Nov 23 '16 14:11

Vsevolod Ganin


2 Answers

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

like image 109
Bracadabra Avatar answered Oct 03 '22 02:10

Bracadabra


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.

like image 27
Rosário Pereira Fernandes Avatar answered Oct 03 '22 00:10

Rosário Pereira Fernandes