3

In my android application I am working on canvas bitmaps (actually it is SCanvas from Samsung SPen SDK, but it does not matter), as a rule 90-95% of area of such bitmaps is transparent, so I expected to have not too large bitmap size in KB. But seems like bitmap size (in KB) does not depend on whether it is a simple background or complex picture, so for example if I have two images (sorry, I am a new user and I can't post any images):

1) empty frame (1000x700 px, background is transparent, color border)

2) full frame (1000x700 px, background is transparent, color border, a lot of text inside)

the size of both bitmaps are about 1.3MB.

But if I convert these bitmaps in byte arrays, the size of the first array is about 11 times less than the size of the second array.

I have to store a lot of such images as BLOBs in DB and display them as ImageView bitmaps.

Question 1: if I need to display 20 ImageView objects with such 95% transparent images, is there any way to not use 20 * 1.3MB at the same time? To me it seems like it should be only 1 alpha layer + 20 "data" layers.

Question 2: is there any way to reduce size (in KB) of an image with transparency without losing too much quality? The only way I saw is to decode the image byte array with inSampleSize = 2 and then create a scaled bitmap to keep the original image dimensions, something like:

originalBitmap.compress(Bitmap.CompressFormat.PNG, 0, stream);
byte[] bitmapBytes = stream.toByteArray();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.length, options);
int bWidth = options.outWidth;
int bHeight = options.outHeight;
options.inSampleSize = 2;
options.inPreferredConfig = Bitmap.Config.ARGB_4444;
options.inJustDecodeBounds = false;
Bitmap scaledBitmap = BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.length, options);
Bitmap finalBitmap = Bitmap.createScaledBitmap(scaledBitmap, bWidth, bHeight, true);

But the finalBitmap quality is unacceptable, no matter what options I used (inPreferredConfig, inDither).

Any other thoughts about the optimal way to handle the images with about 90% of simple transparent background and 10% of one-color "data"?

  • if you are using ImageView you must use Drawable instead of Bitmap. – Mohammad Ersan Nov 09 '12 at 13:56
  • 1
    I would say it is more convenient way if you are working with resources. In case of byte array what is the benefit? http://stackoverflow.com/a/7045044/1811746 – zmiter.freeman Nov 09 '12 at 14:18
  • use this code to convert from Bitmap to Drawables. `BitmapDrawable bitmapDrawable=new BitmapDrawable(orginalBitmap); imageView.setImageDrawable(bitmapDrawable);` – Mohammad Ersan Nov 09 '12 at 14:30
  • Consider opening them one by one, and drawing onto a main bitmap. So there are only ever 2 image loaded in memory at the same time. p.s. always insample size where possible. – IAmGroot Nov 09 '12 at 14:50

1 Answers1

1

No matter what format you use, it will always end up as raw uncompressed (decoded) data before displaying, if it weren't decoded, you couldn't see it on the display. If you're worried about memory, try not to have all the images decoded all the time, just decode the one you have to show, and always release the others (don't keep a reference to them).

Zoltán
  • 21,321
  • 14
  • 93
  • 134
  • I do use png conversion. Let's say you have 1000x700 canvas with transparent background and only one color pixel - "data". Then you do the following (rough example): 'code' canvas.getBitmap().compress(Bitmap.CompressFormat.PNG, 0, stream);byte[] item = stream.toByteArray();Bitmap finalBitmap = BitmapFactory.decodeByteArray(item, 0, item.length); 'code' and the finalBitmap has size 1.3MB. – zmiter.freeman Nov 09 '12 at 13:18
  • 1
    Is your problem storing the bitmap or displaying it? Compressing to PNG and decompressing won't help you. And there is nothing you can do if you need to use bitmaps in the end. All bitmaps have the same size for a given resolution and colour depth. If it's just for displaying, why do you care about the size? If you want to store them, store them as PNG, don't decompress them before storing. – Zoltán Nov 09 '12 at 13:35
  • The scenario is simple: get e.g. 20 BLOBs from DB, decode them to anything you can display in 20 ImageViews which in turn in ScrollView. This way I have about 20*1.3MB memory usage - this means that I need to somehow reduce the image size (not dimensions) before storing the BLOB in DB. Do you have any idea how to do it without losing alpha layer (which is 90-95% of an image) and too much quality? – zmiter.freeman Nov 09 '12 at 13:49
  • OK. Keep the images as PNG in your DB, i.e. BLOB = PNG. Then when you need to display it, decode it to bitmap. Does that work for you? – Zoltán Nov 09 '12 at 14:20
  • No. I don't really care how many bytes are in my DB, it is not the biggest problem. The problem will potentially occur when you decode 20 BLOBs into bitmaps and get 20*1.3MB. Maybe I should not use bitmaps at all, but I don't see any real difference between decoding byte arrays to Bitmaps or Drawable, my feeling is that I need to compress a canvas bitmap using some different mechanism than standard originalBitmap.compress(Bitmap.CompressFormat.PNG, 0, stream); – zmiter.freeman Nov 09 '12 at 14:36
  • No matter what format you use, it will always end up as raw uncompressed (decoded) data before displaying, if it weren't decoded, you couldn't see it on the display. If you're worried about memory, try not to have all the images decoded all the time, just decode the one you have to show, and always release the others (don't keep a reference to them). But on the other hand, using 26 MB of RAM is really not that big a deal. – Zoltán Nov 09 '12 at 14:41
  • 1
    Using 26MB is a huge deal. Maybe not on a PC but on an android device, you will exhaust ALL the avalaible app memory in one go (on some devices - and not much better off on All devices.). – IAmGroot Nov 09 '12 at 14:48
  • 1
    @zmiter.freeman this is the truth. Every pixel in a ARGB_4444 bitmap will take 2 bytes, so your 1000x700 becomes 1.37MB. The only way around it is to not keep it as a bitmap until you absolutely need to display it. – Mark Ransom Nov 09 '12 at 16:00
  • So there is no way to get data from 1000x700px canvas, process it somehow without losing its quality too much and display it in 1000x700px ImageView using less than 1.3MB - is that correct? – zmiter.freeman Nov 09 '12 at 16:34