Using BitmapFactory in B4A or a better way to get image width/height

Roger Garstang

Well-Known Member
Licensed User
Longtime User
I found this sample code below. The decodeResource might be used for internal images, but I'd probably use this for files more since I'd know internal resources sizes to hardcode the ratios and max values...so whichever correct function for that to load from file would be needed. I just want to process a file and get the width and height without loading it into memory since the images may be large. I don't want to add a library just for this though (VBBitmap I think uses this method, but has other functions I don't need). Is there anything that does this in B4A or an alternative way either using another way like in the next paragraph or converting this code to use in B4A with Reflection?

Bitmap.InitializeSample and LoadBitmapSample seem to do some of this and allow for specifying a max size for each and appears to keep aspect ratio. Without using Gravity.Fill though the image is actually still bigger than the ImageView, so wastes resources. On the device I'm on now the Density is 1.5 and that is about how much bigger the picture is. On other devices the image may be even bigger than needed with higher density. I tried dividing the width and height of the ImageView that I pass to the sample methods by the Density which gets very close, but chops off the edges a bit like it is still a little too large.

So, how do I go about getting the image to be within the exact bounds I give for max width/height? I did figure out that specifying -1 for either value just uses the other value and keeps the ratio...which is nice, but still doesn't get it exact. There doesn't appear to be a padding issue either because the image goes right to the edges of the ImageView.

B4X:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
 

Roger Garstang

Well-Known Member
Licensed User
Longtime User
Bitmap createScaledBitmap and the Sample methods in B4A both pass Max values. The VBBitmap library uses the inSampleSize stuff which appears to only allow for fractions like 1/2, 1/3, 1/4, 1/5, etc. So, are you saying B4A doesn't use the createScaledBitmap method and uses something that takes inSampleSize as a parameter? So, does it calculate an inSampleSize that makes it closest to the size requested and use it? If that is the case it needs to pick the one that makes it <= the size requested as it is making it too big. Since VBBitmap uses the inSampleSize stuff wouldn't it have the same issues?

It would be nice to have some functions to get the size of the image without loading it too so we can calculate the needed sizes. Maybe a Bitmap.InitializeInfoOnly(Dir as String, Filename as String) that populates the Width and Height only (And maybe a value called Bitmap.OrigMimeType). It would use the options.inJustDecodeBounds value above. Using it as a bitmap for anything could either be as if null was passed or would call the regular Initialize with the passed file to initialize it properly to prevent issues.
 
Last edited:
Upvote 0

Roger Garstang

Well-Known Member
Licensed User
Longtime User
Looks like another group is trying to figure out the same thing:

http://www.basic4ppc.com/forum/basic4android-updates-questions/20643-resizing-image.html

Someone posted this code which works and gives the proper size, but wouldn't work for large images a user passes since you have to create a bitmap first:

B4X:
Sub CreateScaledBitmap(Original As Bitmap, NewWidth As Int, NewHeight As Int) As Bitmap
    Dim r As Reflector
    Dim b As Bitmap
    b = r.RunStaticMethod("android.graphics.Bitmap", "createScaledBitmap", Array As Object(Original, NewWidth, NewHeight, True), Array As String("android.graphics.Bitmap", "java.lang.int", "java.lang.int", "java.lang.boolean"))
    Return b
End Sub

It doesn't make very smooth results in small images most likely either because the B4A sample functions use the fraction increments or they use some type of Bicubic filter or something to smooth them out.
 
Last edited:
Upvote 0

Informatix

Expert
Licensed User
Longtime User
From the API documentation:

public boolean inJustDecodeBounds
If set to true, the decoder will return null (no bitmap), but the out... fields will still be set, allowing the caller to query the bitmap without having to allocate the memory for its pixels.


If I read it well, you can know the width and height without loading the whole picture in memory.

BitmapPlus is also a small library providing GetImageDimensions and CreateScaledBitmap.
 
Upvote 0

Informatix

Expert
Licensed User
Longtime User
Does GetImageDimensions use the inJustDecodeBounds option?

Of course.

B4X:
public Map GetImageDimensions(String Location)
{
       Map m = new Map();
       m.Initialize();
    
       BitmapFactory.Options options = new BitmapFactory.Options();
       options.inJustDecodeBounds = true;
       BitmapFactory.decodeFile(Location, options);
       if (options.outHeight > 0 || options.outWidth > 0)
       {
          m.Put("Height", options.outHeight);
          m.Put("Width", options.outWidth);
       }
       return m;
}
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
Of course.

B4X:
public Map GetImageDimensions(String Location)
{
       Map m = new Map();
       m.Initialize();
   
       BitmapFactory.Options options = new BitmapFactory.Options();
       options.inJustDecodeBounds = true;
       BitmapFactory.decodeFile(Location, options);
       if (options.outHeight > 0 || options.outWidth > 0)
       {
          m.Put("Height", options.outHeight);
          m.Put("Width", options.outWidth);
       }
       return m;
}


A nice B4A snippet? ;)
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
The source code is in post #7 of this thread, the one you quoted.

I have a sneaking suspicion that it is in Java :).

Also, now I'm confused. Klaus has simply used a Bitmap:

Private bmpDrawing As Bitmap
bmpDrawing.Initialize(...)
If bmpDrawing.Width / bmpDrawing.Height ...
 
Upvote 0
Top