B4A Library BETA: VBBitmap (extended safer LoadBitmapSample)

Releasing VBBitmap 1.3 beta

  • SmartBitmap
    Permissions:
    • android.permission.WRITE_EXTERNAL_STORAGE
    Properties:
    • GlobalAllocSize As Long
      returns getGlobalAllocSize;
    • GlobalFreedSize As Long
      returns getGlobalFreedSize;
    Methods:
    • FreeMem As Double
      returns free memory available from heap
      double memoryAvailable = Runtime.getRuntime().maxMemory() - (heapSize - heapRemaining) - nativeUsage;
    • FreeMem2 As Long
      returns freeMemory
      long freeMemory = (Runtime.getRuntime().maxMemory()) - (Debug.getNativeHeapAllocatedSize());
    • Garbage
      Runs the Garbage Collector to free memory
      Make sure your code is good first you are not initializing bitmaps aggressively
      No amount of System.gc() calls will help a memory leak
      You should split up the work and cache your data to file(s) and remove objects accordingly.
      If you really need more memory you should run your java app with larger heap memory set
    • HowBig (Directory As String, Filename As String) As String
      HowBig(String Directory, String Filename)
      returns height/width as one combined string variable
    • MaxMem As Double
      returns MaxMemory
      Runtime.getRuntime().maxMemory()
    • heapRemaining As Double
      returns heapRemaining
      Runtime.getRuntime().freeMemory();
    • heapSize As Double
      returns totalMemory
      Runtime.getRuntime().totalMemory();
    • loadbitmap (Directory As String, Filename As String, reqWidth As Integer, reqHeight As Integer) As Bitmap
      returns a simple bitmap
      dont use file.dirassets ever, copy image over to another place from project
      example: Activity.loadbitmap(mm.GetSafeBitmap(File.DirInternal,"/moon.jpg",Activity.height,Activity.width))
      If this runs into memory problems, it's going to load a really low res image which will look bad
      but it might not crash the app
    • loadbitmap2 (Directory As String, Filename As String, SampleSize As Integer, RGB565 As Boolean) As Bitmap
      loadbitmap2(String Directory, String Filename, Integer SampleSize, Boolean RGB565)
      returns a safe sized bitmap
      dont use file.dirassets ever, copy image over to another place from project
      example: Activity.SetBackgroundImage(mm.loadbitmap2(File.DirInternal,"/moon.jpg",8))
      SampleSize, can be 2, 4, ,6, 8,....16, 32...etc
      RGB565=True will set options.inPreferredConfig = Config.RGB_565;
    • nativeUsage As Double
      returns free memory available from heap
      Debug.getNativeHeapAllocatedSize();

BitmapLib.HowBig - returns the height/width of an image
Msgbox(BitmapLib.HowBig(File.DirInternal,"/moon3.jpg"),"SIZE")



BitmapLib.loadbitmap2 This allows you to pass a SampleSize
Also lets you choose loading the bitmap as 16bit RGB565 which also could save some memory

you can do the math yourself to find the best SampleSize and read up here: Loading Large Bitmaps Efficiently | Android Developers

loadbitmap2(String Directory, String Filename, Integer SampleSize, Boolean RGB565)

*Setting this Boolean RGB565 flag to true, acts like a converter to convert the 24bit image file into a 16bit


BitmapLib.loadbitmap Will act like LoadBitmapSample, but if it runs into an out of memory it will automatically load a really low res image so your app won't crash and you get the bad app review on Google Play Market from one of the 1500+ devices out there. ( You never know what a device has running and how much memory is available when your app is loaded. )

loadbitmap(String Directory, String Filename, Integer Width, Integer Height)


BitmapLib.Garbage - Runs the Garbage Collection



Information about Memory


BitmapLib.FreeMem - returns free memory available from heap double memoryAvailable = Runtime.getRuntime().maxMemory() - (heapSize - heapRemaining) - nativeUsage

BitmapLib.FreeMem2 - returns freeMemory long freeMemory = (Runtime.getRuntime().maxMemory()) - (Debug.getNativeHeapAllocatedSize());

BitmapLib.heapRemaining - returns heapRemaining Runtime.getRuntime().freeMemory();

BitmapLib.heapSize - returns totalMemory Runtime.getRuntime().totalMemory();

BitmapLib.MaxMem - returns MaxMemory Runtime.getRuntime().maxMemory()

BitmapLib.nativeUsage - returns free memory available from heap Debug.getNativeHeapAllocatedSize();


BitmapLib.GlobalAllocSize
BitmapLib.GlobalFreedSize







Example usage:
B4X:
Dim BitmapLib As SmartBitmap
File.Copy(File.DirAssets,"moon3.jpg",File.DirInternal,"moon3.jpg")
        Activity.SetBackgroundImage(BitmapLib.loadbitmap2(File.DirInternal,"/moon3.jpg",1,True))
      'Activity.SetBackgroundImage(BitmapLib.loadbitmap(File.DirInternal,"/moon3.jpg",Activity.Width,Activity.Height))
Msgbox(BitmapLib.HowBig(File.DirInternal,"/moon3.jpg"),"SIZE")
Msgbox(BitmapLib.heapRemaining,"HeapRemaining")

Please test with some big images/bitmaps.


Thanks in Advance

Vb1992

Library Revision History:

Old...... Library is version 1.0 - June 29th, 2012
Old...... Library is version 1.1 - June 29th, 2012
Old...... Library is version 1.2 - July 2nd, 2012
New...... Library is version 1.3 - July 2nd, 2012
improved algorithmic values for loadbitmap
added Log( GlobalAllocSize)
added Log( GlobalFreedSize)
 

Attachments

  • VBBitmap1.3.zip
    5.4 KB · Views: 905
Last edited:

Informatix

Expert
Licensed User
Longtime User
I tried your demo with my own images (very big JPEG), my own sizes and I got a black (or yellow or red, it depends on the dominant color) image when there's not enough memory. Your algorithm is maybe a bit too aggressive.
Set width and height to 80 in your demo and you should see what I mean (or you can look at the screenshot).

I often get negative values with FreeMem. Is it normal ?
 

Attachments

  • screenshot.jpg
    screenshot.jpg
    21.1 KB · Views: 415

vb1992

Well-Known Member
Licensed User
Longtime User
I would agree the algorithm is very aggressive to avoid an OOM
but that part of the algorithm only gets used when you are actually
low on memory and trying to load a huge bitmap that exceeds the memory available.

Let's say a user chooses to load a really big image that would
crash the app, this would most likely prevent it.

What would you like it to do better?
I am open to suggestions and making this better.
 

Informatix

Expert
Licensed User
Longtime User
Let's say a user chooses to load a really big image that would
crash the app, this would most likely prevent it.

What would you like it to do better?
I am open to suggestions and making this better.

After hundreds of tries (in a loop), I didn't see any crash with LoadBitmapSample under Froyo and Gingerbread. LoadBitmapSample raises an exception ("Loading error") when there's not enough memory. And that's exactly the same thing with your function, except it tries to load a small image (size/32) when memory becomes critical. But in most cases, this small image is not very useful (a colored square) as I stated in my previous post or the function fails to load anything if the source image is very big.
The images I used are pictures taken with the device camera and I tried to create thumbnails from them. It's a common usage I think.

I don't want to say that your function is useless or not working, I simply say I can't see any avantage to use it. Maybe on other devices or with some particular apps, that's essential.
 

vb1992

Well-Known Member
Licensed User
Longtime User
Thanks Informatix

Here is another test

This demo has 2 buttons, one that loads with LoadBitmapSample
and the other button with vbLoadbitmap

I find my device crashes after pressing the LoadBitmapSample button a few times
where I can press vbLoadbitmap about 30 times

Use with Library 1.3 in first post

Zippyshare.com - Anothertest.zip
 
Last edited:

vb1992

Well-Known Member
Licensed User
Longtime User


the trade off is always risking decoding a large image to blow up the heap, vs sampling down the size to a safe enough size to keep the app from Force Closing

 

Informatix

Expert
Licensed User
Longtime User
I find my device crashes after pressing the LoadBitmapSample button a few times
where I can press vbLoadbitmap about 30 times

Use with Library 1.3 in first post

I tried your 1.3 with a Huawei Honor under A 2.3.6:
vbLB : I clicked 4 times, at the 5th -> Alert "Problems"
LBS : I clicked 4 times, at the 5th -> Alert "Problems"
No difference and no crash.

I changed the imageview size to 150x150. Exactly the same results.

Then I changed the max size of the image to 500x500.
I can click 16 times before the MsgBox pops up. No difference between the two functions.

But if your device needs it, I have nothing to object.
 

Informatix

Expert
Licensed User
Longtime User
is your device rooted?

No. And I have no utility app to manage memory.

What does say the emulator ? I wanted to try yesterday but I gave up because of loading times.

I'm not very surprised to see differences. Many Android versions, many software overlays (almost one by manufacturer), many devices = many reasons to see differences. That's why a lot of developers prefer to work with iOS.
 

Silentsea

Member
Licensed User
Longtime User
Hi vb1992,

one little question in combination with your lib. How will HowBig works internally? I would like to use Howbig to check sizes before I maybe have to manually scale a picture by a CreateScaledBitmap method. I need to know if HowBig loads the file to an bitmap object reading the dimensions, because the I rather would do it by myself to have more control in my calculations. I would like the idea reading the sozes out of metadata or something, don't know if this is possible. But it would save memory.


Greetings.

P.S. Nice lib for checking memory.
 
Last edited:

Silentsea

Member
Licensed User
Longtime User
Yes, ok. But how is it read? Will it store the file shortly in mem to read? I maybe have found a workarround for my problem, but if you thought of big pictures taken by the cam 3 mp or higher, that would be 3264x2448x4 = 32 MB in Memory. This could result in a mem exception. Also if is is only read? Or am I wrong?

Greetings.
 

Informatix

Expert
Licensed User
Longtime User
Will it store the file shortly in mem to read? I maybe have found a workarround for my problem, but if you thought of big pictures taken by the cam 3 mp or higher, that would be 3264x2448x4 = 32 MB in Memory. This could result in a mem exception. Also if is is only read?

As I said, using HowBig does not consume memory. The function does not store anything. It just reads the file chunk of data after chunk of data. I didn't read the source code of the Android API to know precisely the size of the read buffer but that should be something between 1024 and 4096 bytes.
 

gadgetmonster

Active Member
Licensed User
Longtime User
Problem with images on web services

Hi

I am using contentchooser to allow users to pick an image using the following code:

B4X:
imageChooser.Initialize("imageChooser")
imageChooser.Show("image/*", "Choose image")

In my case I can choose images from Google Drive / Dropbox as well as the gallery.

Once the user picks an image I load this into an image view using:

B4X:
Sub imageChooser_Result (Success As Boolean, Dir As String, FileName As String)
imgView.Bitmap =  LoadBitmapSample(Dir, FileName, imagePhoto.Width, imagePhoto.Height )
End Sub

This all works fine even for images from Google Drive and Dropbox.

I store a reference to the Dir and FileName for use later on.

When the user comes to save I rescale the image, to do this I need to know the size so I do this:

B4X:
bitmapSize = Regex.Split("/", BitmapLib.HowBig(Dir, Filename))

Now with files from my device (i.e. the gallery etc) it works fine. BUT with files from services like GoogleDrive I get the error:


java.io.FileNotFoundException: /ContentDir/content:/com.google.android.apps.docs.files ....... Open Failed. ENOENT (No such file or directory).


Please help. I though this would work as I can pass the same dir and filename into loadbitmap and that works.
 
Top