Android: Make tiles 32-bit color instead of 16-bit by Sublimis · Pull Request #1654 · mapsforge/mapsforge

@Sublimis

Make non-transparent bitmaps (i.e. tile bitmaps) use Config.ARGB_8888 instead of Config.RGB_565 on Android.
Nobody expects to see 16-bit color on their smartphone nowadays.

A/B animation

(A-PNG, hopefully the colors didn't get skewed in the process)
2025-ARGB8888-anim

Exaggerated difference

2025-ARGB8888-diff

@Sublimis

…ARGB_8888 instead of Config.RGB_565

@devemux86

@Sublimis Can you post 2 screenshots with the same area to see the difference?

As this may affect memory, we better make it optional via the Parameters class.

@Sublimis

As this may affect memory, we better make it optional via the Parameters class.

Even on xxxhdpi devices this amounts to just several MBs difference per entire screen. If optional, this should at least be the default. Also, keep in mind that the heap size is closely related to the screen resolution on a particular Android device.

@devemux86

@Sublimis Some quick tests do not reveal any significant difference?
Unless hill shading is used, where we have to try hard to see it (at least here).

If we need this, we should add a boolean switch in Parameters with default false and use it like:

public static final Config NON_TRANSPARENT_BITMAP = Parameters.ANDROID_ARGB_BITMAP ? Config.ARGB_8888 : Config.RGB_565;

devemux86

// on memory use) and allows transparencies. Use ARGB_8888 whenever
// Determines size of bitmaps used, RGB_565 is 2 bytes per pixel
// while ARGB_8888 uses 4 bytes per pixel and allows transparencies.
// Use ARGB_8888 whenever

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Sublimis Let's keep the old comments, are they are useful.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original comment is still there, just the misleading claim of "severe impact on memory use" was removed, as there's nothing severe about it. Also, there's probably no programmer in the world who doesn't know that 4x8=32 bits is 2x more than 5+6+5=16 bits.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Sublimis Is the comment or the calculation wrong?
If it uses more memory, it is better to be mentioned.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Sublimis If you do not like the "severe" we can remove it.
But we should still mention the difference memory use.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Sublimis Is the comment or the calculation wrong?

The comment is wrong (or rather misleading or manipulative). Doubling memory usage may sound like a lot ("severe"), and it certainly can be, when comparing say 500 GB to 1 TB, but here we're talking about ~4 vs. 8 MB for an entire screen (not per tile bitmap) of a high-end device. In 2025.

If it uses more memory, it is better to be mentioned.

But to whom? That comment is only consumed by library contributors. This RGB vs. ARGB story is so old that if the contributor does not know about it or can't understand the javadoc words "Each pixel is stored on 4 bytes." and "Each pixel is stored on 2 bytes", they'd better not touch anything... :)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In short, the memory usage comment should be placed on Parameters.ANDROID_ARGB_BITMAP field, if it is to be implemented this way, and should definitely not use the word "severe" as it sounds like there will be some serious consequences if ARGB_8888 is used.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the memory usage comment should be placed on Parameters.ANDROID_ARGB_BITMAP field, if it is to be implemented this way, and should definitely not use the word "severe" as it sounds like there will be some serious consequences if ARGB_8888 is used.

@Sublimis No problem with this. But let's have the same comment here too for easy reference.

@devemux86

@Sublimis Android heap size is unfortunately not the whole device memory, but much more limited, like desktop Java.

Also we do not know how users and apps fill the memory.
Mapsforge is just the map engine, there many more things happening in the apps that can fill the heap.
That's why we better not change such core default.

@Sublimis

@Sublimis Some quick tests do not reveal any significant difference? Unless hill shading is used, where we have to try hard to see it (at least here).

Perhaps one thing needs to be clarified, which may not have been emphasized enough in the first post:

  • AndroidGraphicFactory.NON_TRANSPARENT_BITMAP is only used to draw tiles on the screen, and basically nowhere else.

That's why screen dpi was mentioned, as well as heap size.

@Sublimis

It might also be worth noting that we have been using this in our app for some months now without any problems? 😄

@devemux86

@Sublimis What is the status here? Will you add a parameter as we discussed above?

@Sublimis

Not sure this will ever be needed, maybe you could reconsider this? Have you done the math, and read the comment above? The reasons against 16-bit color pile up, including the constant 32<->16-bit conversions (all icons are 32-bit, as are all phone screens), to name just one. Can't think of a single additional benefit to 16-bit color, other than the (rather marginal) memory savings. Are there other benefits?

If you think the quality degradation of 16-bit is too small to justify 32-bit always, remember that it depends entirely on the render theme - the more colors it uses, the greater the degradation; the situation will not always be like in the screenshots above. Even the Glide library, a standard image loading library for Android, made ARGB_8888 a default back in 2017.

@Sublimis Sublimis changed the title Android: Make tiles use 24/32-bit color istead of 16-bit Android: Make tiles 32-bit color instead of 16-bit

Feb 17, 2025

@devemux86

@Sublimis It's better such core changes to be optional until more tests can be made and we do not force them to all apps.

@Sublimis

We're constantly testing, that's the point. Also, since the memory savings are marginal (the only advantage of 16-bit), where do you think the problem could even arise? There are better places in the code for memory optimizations.

It may be overambitious to call this a "core change". It's better to think of it as fixing an old workaround that’s no longer needed (a code maturity issue, if you will): If the library had been created in 2020. instead of 2010., we probably wouldn't be talking about 16-bit color now.

Once this becomes a parameter, it will be much harder to remove later. Maybe you could create a poll to see if anyone needs this parameter (almost guaranteed not)?

@Sublimis

Also note that since Android 8.0 (API level 26), the bitmap pixel data is stored in the native heap rather than the "regular" java heap.

@devemux86

@Sublimis Everything can be changed later. The public API was changed recently.

Anyway let's not over analyze this so much. 🙂
Options exist so everyone can test with their apps and not force anything until we are all happy with the results.

@Sublimis

Anyway let's not over analyze this so much. 🙂

Well you started it, our solution was a dead-simple old workaround removal 😃

That said, can you implement this the way you want? Just keep 32-bit as default please. As for nomenclature, it's better to use terms like "16-BIT_COLOR" or "32-BIT_COLOR" instead of "RGB" or "ARGB" in field names, which also makes any comments about memory usage redundant.

@devemux86

can you implement this the way you want?

Sure, I can prepare a pull request with default the existing library code.

@devemux86

@Sublimis

Something like #1655

Looks good, but the default should be true, or if you want false as default than revert the condition and call the field ANDROID_16BIT_COLOR maybe. Also the comment on that field is highly unnecessary and only adds noise. There's really no need to explain ARGB_4444 for example, it's better to remove the comment altogether.

Besides, 16-bit color can be used only in tile bitmaps, so it's unnatural for this field or the new AndroidGraphicFactory.getNonTransparentBitmapConfig() method to try to act as general solutions for bitmaps, i.e. their names and/or comments suggest that the 16/32-bit color will be used everywhere, which is simply not true. Maybe their names should contain the word "tile"?

@devemux86

It is also used in the publc createBitmap.
I will update the comments.

@Sublimis

It is also used in the publc createBitmap. I will update the comments.

Yes, but that public method is used only from the FrameBufferBitmapHA3.... ?? Android app using this library will certainly not use AndroidGraphicFactory.createBitmap() to create its bitmaps. That method is public/interface simply because it's being used from other package(s), not because it's expected that users of the library should use it...

@devemux86

It's a method that returns a bitmap config. The constants with the other configs also correctly have generic names.

Apps may use Mapsforge GraphicFactory to create easily various Mapsforge classes for Bitmap, Canvas, Paint, etc.
So how it can be used externally, we do not know, it depends on the apps.

@Sublimis

Oh well...
The only important thing here is that 32bit should be the default.

@Sublimis

Oh well... The only important thing here is that 32bit should be the default.

And if giving an option, use naming and wording that discourages the use of 16-bit, not the other way around.

@devemux86