Android – Bitmap Compression and Speed Optimization In Android

android, bitmap, performance

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 2592×1944.

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: beginStart Saving:      4 ms, Start Pic SaveStart Saving:      86 ms, Start Overlay SaveStart Saving:      3576 ms, Start Overlay Onto Pic SaveStart Saving:      2066 ms, Start Metadata SaveStart Saving:      15 ms, DoneStart 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.

Best Solution

  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