Search code examples
androidmatrixrotationscaleandroid-custom-view

Scaling image inside custom view with rotation angle in Android


Well, this might be a bit hard to explain but here is the deal: I have a custom view which has a background image and some other smaller images drawn above it. The whole view, when the user selects the option to save it, will be scaled to a certain resolution, let's say 900x900px. So if the phone is 720p the image will be scaled up, while if the screen is 1080p will be scaled down.

How is scaling done:

  • I take the view's layout params and change the width to 900px.
  • The background stored image is exactly at 900px, so when the view is prepared to be saved, I simply reload the background image at full quality.
  • All the other small images, get scaled as well, both their size and their position on screen.

So, if initially if the screen size is 720px width, when the size is changed to 900px, I calculate a scale factor, within onMeasure

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        super.onMeasure(widthMeasureSpec, widthMeasureSpec);

        if (MeasureSpec.getSize(widthMeasureSpec) == 900) {
                scale = (900 - viewWidth) * 100.2f / viewWidth;
                prepareSaving();
        }
}

Then I use this scale number when drawing:

canvas.drawBitmap(myCachedImage, x + addScale(x), y + addScale(y), imagePaint);

where

private float addScale(float value) {
        if (scale == 0) {
            return 0;
        } else {
            return (value * scale / 100.2f);
        }
    }

This allows me to draw the bitmap at scaled coordinates, and this works as expected. The problem appears when the user rotates the image. On rotate I do:

public void rotateSticker(float degrees) {
     imageMatrix.setRotate(degrees, imageCenterX + addScale(imageCenterX), imageCenterY +imageCenterY ));
}

Within onDraw I do:

if (angle!=0{
   canvas.save(Canvas.MATRIX_SAVE_FLAG);
   canvas.setMatrix(imageMatrix);
   canvas.drawBitmap(myCachedImage, x + addScale(x), y + addScale(y), imagePaint);
   canvas.retore()
}else
{
   canvas.drawBitmap(myCachedImage, x + addScale(x), y + addScale(y), imagePaint);
}

Here is my problem: if the user does not rotate, all scaling is done correctly and the saved image looks good. If there is an angle, on scaling, the image is not drawn in the right coordinates, it is moved, just like in the image bellow https://i.sstatic.net/TmNyV.png


Solution

  • All the problems with scaling and rotating was caused by the image's Matrix. When I switched to using only the view's canvas.rotate(), everything is working as expected.