Android Question Write large files (multiple photos)

Hello,

In the app we need to save and upload a large (xml) file. It works as long as the file (created with XMLBuilder) stays within certain limits. However when saving the xml with 10+ large photos (base64) then the error below occurs.
Largeheap is already activated in the manifest.

B4X:
File.WriteString(Map_Wachtrij, sFilename, x.asString) 'x =XMLBuilder and writestring triggers an error below

B4X:
java.lang.OutOfMemoryError: Failed to allocate a 226207176 byte allocation with 25165824 free bytes and 70MB until OOM, max allowed footprint 488170160, growth limit 536870912

Any thoughts?
 
used to write:
B4X:
Dim x As XMLBuilder

'fill x with photo's and other tags

File.WriteString(Map_JDS, File_PDA,x.asString)

error:
B4X:
java.lang.OutOfMemoryError: Failed to allocate a 123122680 byte allocation with 25165824 free bytes and 106MB until OOM, max allowed footprint 449855920, growth limit 536870912
 
Upvote 0
Sorry, I thought you might had enough at just the first line. See below.

We are taking pictures of (damaged) goods at max resolution (customer wishes). Converting these pictures to base64 string and then adding them to the XMLBuilder.


B4X:
'code to add an photo to the xml.
x = x.element("sf")
                    x = x.element("sf1").text(tFoto.sFile).up 'base64 string of the picture, already converted.
                    x = x.element("sf2").text(fBehandel.ZendingID&"_"&(i+1)&"_"&getTimeNoLimiterUnique&".JPEG").up 'give an name to the picture

                        x = x.element("sf3").text( 0).up 'identifier

                    x = x.up

Full error. Added just 7 pictures.

B4X:
java.lang.OutOfMemoryError: Failed to allocate a 197210232 byte allocation with 25165824 free bytes and 78MB until OOM, max allowed footprint 479584288, growth limit 536870912
    at java.util.Arrays.copyOf(Arrays.java:3260)
    at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:125)
    at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:660)
    at java.lang.StringBuilder.append(StringBuilder.java:203)
    at java.util.AbstractMap.toString(AbstractMap.java:561)
    at anywheresoftware.b4a.objects.collections.Map$MyMap.toString(Map.java:296)
    at java.lang.String.valueOf(String.java:2896)
    at java.lang.StringBuilder.append(StringBuilder.java:132)
    at java.util.AbstractMap.toString(AbstractMap.java:559)
    at anywheresoftware.b4a.objects.collections.Map$MyMap.toString(Map.java:296)
    at java.lang.String.valueOf(String.java:2896)
    at java.lang.StringBuilder.append(StringBuilder.java:132)
    at java.util.AbstractMap.toString(AbstractMap.java:559)
    at anywheresoftware.b4a.objects.collections.Map$MyMap.toString(Map.java:296)
    at anywheresoftware.b4a.AbsObjectWrapper.toString(AbsObjectWrapper.java:141)
    at java.lang.String.valueOf(String.java:2896)
    at anywheresoftware.b4a.BA.ObjectToString(BA.java:771)
    at lmmobile.jds.android.globaal._checkxml_valid(globaal.java:3676)
    at lmmobile.jds.android.globaal._savestatusfile(globaal.java:14612)
    at lmmobile.jds.android.starter$ResumableSub_ZendingOpslaan.resume(starter.java:26902)
    at lmmobile.jds.android.starter._zendingopslaan(starter.java:25809)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:221)
    at anywheresoftware.b4a.keywords.Common.CallSub4(Common.java:1114)
    at anywheresoftware.b4a.keywords.Common.CallSubNew(Common.java:1061)
    at lmmobile.jds.android.lm_wachttijd._overzend_click(lm_wachttijd.java:887)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:221)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:205)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:201)
    at anywheresoftware.b4a.objects.ViewWrapper$1.onClick(ViewWrapper.java:80)
    at android.view.View.performClick(View.java:7339)
    at android.widget.TextView.performClick(TextView.java:14275)
    at android.view.View.performClickInternal(View.java:7305)
    at android.view.View.access$3200(View.java:846)
    at android.view.View$PerformClick.run(View.java:27787)
    at android.os.Handler.handleCallback(Handler.java:873)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:214)
    at android.app.ActivityThread.main(ActivityThread.java:7078)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:964)
 
Upvote 0
1. I've fixed an bug (didn't check if the file exists) in the CheckXML_Valid function. However an new error occurs (see below)
2. Resizing isn't an option. The customer wants most detailed pictures.

B4X:
globaal_savestatusfile (java line: 14613)
java.lang.OutOfMemoryError: Failed to allocate a 51770376 byte allocation with 25165824 free bytes and 34MB until OOM, max allowed footprint 525484520, growth limit 536870912
    at java.lang.StringFactory.newStringFromChars(StringFactory.java:267)
    at java.lang.StringBuffer.toString(StringBuffer.java:671)
    at java.io.StringWriter.toString(StringWriter.java:210)
    at com.jamesmurty.utils.XMLBuilder.asString2(XMLBuilder.java:1014)
    at com.jamesmurty.utils.XMLBuilder.asString(XMLBuilder.java:1053)
    at lmmobile.jds.android.globaal._savestatusfile(globaal.java:14613)
    at lmmobile.jds.android.starter$ResumableSub_ZendingOpslaan.resume(starter.java:26902)
    at lmmobile.jds.android.starter._zendingopslaan(starter.java:25809)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:221)
    at anywheresoftware.b4a.keywords.Common.CallSub4(Common.java:1114)
    at anywheresoftware.b4a.keywords.Common.CallSubNew(Common.java:1061)
    at lmmobile.jds.android.lm_wachttijd._overzend_click(lm_wachttijd.java:887)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:221)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:205)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:201)
    at anywheresoftware.b4a.objects.ViewWrapper$1.onClick(ViewWrapper.java:80)
    at android.view.View.performClick(View.java:7339)
    at android.widget.TextView.performClick(TextView.java:14275)
    at android.view.View.performClickInternal(View.java:7305)
    at android.view.View.access$3200(View.java:846)
    at android.view.View$PerformClick.run(View.java:27787)
    at android.os.Handler.handleCallback(Handler.java:873)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:214)
    at android.app.ActivityThread.main(ActivityThread.java:7078)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:964)
 
Upvote 0

ernschd

Active Member
Licensed User
Longtime User
Would it be an option to compress the photos? In other words, to use the highest resolution, but zipped, for example.
 
Upvote 0

emexes

Expert
Licensed User
Longtime User
Both JPEG and PNG formats are compressed.

But not to the same degree. PNG is lossless and I've found usually compresses a 24-bit photo to 1/2th original size. JPEG has an adjustable quality setting, and typically compresses a 24-bit photo between from 1/10th original size at quality=90 to 1/30th original size at quality =50.

Zipping them will not change their size much

👍
 
Upvote 0

emexes

Expert
Licensed User
Longtime User
Added just 7 pictures.

B4X:
java.lang.OutOfMemoryError: Failed to allocate a 197210232 byte allocation

197 million bytes for 7 pictures = about 28 MB per picture, which suggests the pictures have not (yet) been compressed using JPEG.

Doing that should reduce the sizes by about 90% (or more, if you decrease the quality factor). Things are much more managable at those sizes. Perhaps see if you can get the images after they've been saved to storage by the camera app - however large those picture files are, they are at about the best resolution etc that you're going to get, and any image data larger than that isn't going to contain more actual non-hallucinatory detail.

TBH most consumer digital camera photos can be reduced to half their original dimensions ie reduce number of pixels (image file size) by 75%, without noticeable loss of quality or detail, because the image sensors are returning separate 8-bit red, green or blue pixels, not composite 24-bit red, green and blue pixels. Although that reasoning might be hard to sell to your customers, and it could be better (simpler) to live with needlessly-larger image files than have your customers thinking you're trying to bilk them.
 
Last edited:
Upvote 0

MrKim

Well-Known Member
Licensed User
Longtime User
You might try compressing a few images, show your customer the compressed and uncompressed and ask them to tell them which is which 🤣
 
Upvote 0

TILogistic

Expert
Licensed User
Longtime User
Better WEBP compression:

You can convert from PNG or JPG to WebP format, or from WebP to PNG or JPG.

Use the native Android method (API 18+).

Example: PNG to WebP

1751882633409.png

1751882906678.png

Ref:
Note:
This is related to this other post.
 
Last edited:
Upvote 0
Top