Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bitmap Compression and Speed Optimization In Android

I'm dealing with an AR application in Android that draws on the camera output. I'm working on a portion of the code to save three image files: the raw picture, the screen overlay and the composite picture with overlay drawn on (possibly superfluous, given the other two). The native image size for my camera is 2592x1944.

Right now my save operation is taking longer than I'd like. I'm doing the picture saving using an AsyncTask, but the actual save part boils down to the following:

public void onPictureTaken(byte[] data, Camera camera){
  Size sz = camera.getParameters().getPictureSize();

  TimingLogger tl = new TimingLogger("CodeTiming", "Start Saving");
  String fileName = getNameFromTime();

  tl.addSplit("Start Pic Save");
  // The Picture itself 
  ImageFile photo = new ImageFile(fileName+"_image.jpg");
  photo.write(data);

  tl.addSplit("Start Overlay Save");
  // The overlay with blank background
  Bitmap bmp = Bitmap.createBitmap(sz.width,sz.height,Bitmap.Config.ARGB_8888);
  Canvas canvas = new Canvas(bmp);
  DrawStuffOnCanvas(canvas);
  ImageFile overlay = new ImageFile(fileName+"_overlay.png");
  overlay.write(bitmapToByteArray(bmp,Bitmap.CompressFormat.PNG));

  tl.addSplit("Start Overlay Onto Pic Save");
  // The picture with the overlay drawn on
  Options options = new Options();
  options.inDither = false;
  options.inPreferredConfig = Bitmap.Config.ARGB_8888;
  Bitmap picture = BitmapFactory.decodeByteArray(data, 0, data.length, options);
  picture = picture.copy(Bitmap.Config.ARGB_8888, true);
  Canvas canvas2 = new Canvas(picture);
  DrawStuffOnCanvas(canvas2);
  ImageFile overlay2 = new ImageFile(fileName+"_combo.jpg");
  overlay2.write(bitmapToByteArray(picture,Bitmap.CompressFormat.JPEG));

  tl.addSplit("Start Metadata Save");
  //Save picture metadata, not relevant to question

  tl.addSplit("Done");
  tl.dumpToLog();
}

Converting the Bitmap to the byte[] is being done by:

byte[] bitmapToByteArray(Bitmap b,Bitmap.CompressFormat fmt){
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  b.compress(fmt, 100, baos);
  return baos.toByteArray();
}

Note that all of the file objects (e.g. ImageFile) are custom, but the relevant information needed is that they handle the writing of a byte[] using a FileOutputStream. Here's a recent timing dump for this run.

Start Saving: begin
Start Saving:      4 ms, Start Pic Save
Start Saving:      86 ms, Start Overlay Save
Start Saving:      3576 ms, Start Overlay Onto Pic Save
Start Saving:      2066 ms, Start Metadata Save
Start Saving:      15 ms, Done
Start Saving: end, 5747 ms

There's quite a bit of variability, anywhere from about 5-15 seconds per save. The overlay (essentially lines drawn on the screen) is currently being saved as a PNG for the transparency, and because of artifacts at the sharp line edges caused by the JPEG compression. Following the logic of this question, I saw that if I switch the overlay to a JPEG, I cut my time for that step in half. As you can see, I did implement that change for the composite picture (sharp edges are already blurred by the image itself), which saved about 20 seconds on that compression step.

So my question is this. Is there anything I can do to save time on my compression of the overlay, but keep the PNG output? Or, alternatively, is there something else I'm doing here that's wasting a lot of time that could speed up the overall save operation? Then I wouldn't need to worry about PNG vs. JPEG quite as much.

like image 801
jranalli Avatar asked Mar 24 '14 21:03

jranalli


People also ask

Why bitmap is used in Android?

Android provides Bitmap class to handle images.

How do you handle bitmaps in Android?

For most cases, we recommend that you use the Glide library to fetch, decode, and display bitmaps in your app. Glide abstracts out most of the complexity in handling these and other tasks related to working with bitmaps and other images on Android.

How does BMP compression work?

Compression reduces the disk and memory storage required for the bitmap. When the Compression member of the bitmap information header structure is BI_RLE8, a run-length encoding (RLE) format is used to compress an 8-bit bitmap. This format can be compressed in encoded or absolute modes.

What type of compression does bitmap use?

BMP images are generally uncompressed or compressed with a lossless compression method. The files can store two-dimensional digital images with both monochrome and color. Various Color Depths, alpha channels, color profiles and optional data compression are supported in this format.


2 Answers

  1. PNG compression is much slower than JPEG compression, especially when your bitmap size is high.
  2. Use RGB_565 instead of ARGB_8888 if you don't care of transparency.

More info here: https://stackoverflow.com/a/33299613/4747587

like image 60
Henry Avatar answered Sep 22 '22 13:09

Henry


Dramatic speed up mechanism:

Use RGB_565 instead of ARGB_8888 whereas possible (e.g. no transparent pixel)

Also, the "copy" operation takes more time than drawing that Bitmap on the Canvas. You can simply create an empty bitmap and draw the original image.

like image 36
Patrick Chan Avatar answered Sep 22 '22 13:09

Patrick Chan