Search code examples
androidbitmapscale

Android: How to get bitmap's scaled width in onDraw()


Simple question where the simple answer isn't working. I have a bitmap and I want to get its dimensions as scaled to the display by the system for different DPI screens within the onDraw() method. bitmap.width() returns its unscaled width successfully. However, bitmap.getScaledWidth() returns zero. I have tried getScaledWidth(canvas) and getScaledWidth(canvas.getDensity()), but both return 0. Indeed, canvas.getDensity() returns zero so I can't even calculate it manually.

What am I doing wrong?

Bit more detail. I'm using a custom view. The bitmap is declared in the class and loaded in the constructor.

Edit:

I've found that using:

        DisplayMetrics metrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(metrics);

bitmap.getScaledHeight(metrics) returns the same value as bitmap.getHeight().

It would appear that bitmap.getWidth() returns the dimension of the resident bitmap after it has been scaled, meaning there's no apparent way to get the bitmap's original width.


Solution

  • The Canvas class has a lots of overloads for the drawBitmap() function. One of them allows you to scale/cut a Bitmap through a pretty comfortable interface.

    public void drawBitmap (Bitmap bitmap, Rect src, RectF dst, Paint paint)

    Where

    • Bitmap bitmap - is your bitmap you want to draw
    • Rect src - the source rect from your bitmap. If its not null, it will cut out a piece from your bitmap (in the size and position of src)
    • RectF dst - This Rect will represent the Rectangle, your Bitmap will fit in.
    • Paint paint - optional paint

    And now an example! Lets say, you want to shrink your Bitmaps width to 1/2 and increase its height to 2 times of the original:

    float startX = 0; //the left
    float startY = 0; //and top corner (place it wherever you want)
    float endX = startX + bitmap.getWidth() * 0.5f; //right
    float endY = startY + bitmap.getHeight() * 2.0f; //and bottom corner
    
    canvas.drawBitmap(bitmap, null, new RectF(startX, startY, endX, endY), null);
    

    UPDATE

    I don't really understand, what you are trying to acomplish, after reading your comment, but here is some extra info to get started:

    Get the original size of a Bitmap without loading it into the memory:

    BitmapFactory.Options options = new BitmapFactory.Options();
    bitmapOptions.inJustDecodeBounds = true; // bitmap wont be loaded into the memory
    
    //won't load the Bitmap, but the options will contain the required information.
    BitmapFactory.decodeStream(inputStream, null, options);
    /*or*/ BitmapFactory.decodeFile(pathName, options);
    
    int originalWidth = bitmapOptions.outWidth;
    int originalHeight = bitmapOptions.outHeight;
    

    Now if you have another your actual (scaled) Bitmap, or an ImageView, what you want to compare to the original, then you can use this (to get the width and height use getWidth() and getHeight()):

    /*Get these values*/
    int originalWidth, originalHeight, scaledWidth, scaledHeight; 
    
    float scaleWidthRatio = (float)scaledWidth / originalWidth;
    float scaleHeightRatio = (float)scaledHeight / originalHeight;