【问题标题】:Bitmap Compression and Speed Optimization In AndroidAndroid中的位图压缩和速度优化
【发布时间】:2014-03-24 21:03:55
【问题描述】:

我正在处理 Android 中的一个利用相机输出的 AR 应用程序。我正在处理部分代码以保存三个图像文件:原始图片、屏幕叠加层和带有叠加层的合成图片(可能是多余的,考虑到另外两个)。我的相机的原始图像尺寸是 2592x1944。

现在我的保存操作花费的时间比我希望的要长。我正在使用 AsyncTask 进行图片保存,但实际保存部分归结为以下内容:

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();
}

将 Bitmap 转换为 byte[] 正在通过以下方式完成:

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

请注意,所有文件对象(例如 ImageFile)都是自定义的,但所需的相关信息是它们使用 FileOutputStream 处理字节 [] 的写入。这是此运行的最近时间转储。

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

变化很大,每次保存大约 5-15 秒。叠加层(基本上是在屏幕上绘制的线条)当前被保存为透明度的 PNG,并且由于 JPEG 压缩导致的锐线边缘处的伪影。按照this question 的逻辑,我看到如果我将叠加层切换为JPEG,我将这一步的时间缩短了一半。如您所见,我确实为合成图片实现了该更改(锐边已经被图像本身模糊),在压缩步骤上节省了大约 20 秒。

所以我的问题是这样的。我可以做些什么来节省压缩叠加层的时间,但保留 PNG 输出?或者,或者,我在这里做的其他事情是否会浪费大量时间来加快整体保存操作?那么我就不需要担心 PNG 与 JPEG 的关系了。

【问题讨论】:

    标签: android performance bitmap


    【解决方案1】:
    1. PNG 压缩比 JPEG 压缩慢得多,尤其是当您的位图尺寸较大时。
    2. 如果您不关心透明度,请使用 RGB_565 而不是 ARGB_8888

    更多信息在这里:https://stackoverflow.com/a/33299613/4747587

    【讨论】:

    • bitmap.compress(Bitmap.CompressFormat.JPEG, quality, stream) 对于1472x736 分辨率非常慢,80 毫秒
    • 我不会认为 80ms 很慢,因为这是一个 IO 操作。而且无论多快,这个操作都不应该在 UI 线程中完成。
    【解决方案2】:

    戏剧性的加速机制:

    尽可能使用 RGB_565 而不是 ARGB_8888(例如,没有透明像素)

    此外,“复制”操作比在画布上绘制该位图需要更多时间。您可以简单地创建一个空位图并绘制原始图像。

    【讨论】:

    • RGB_565 在这一步确实为我创造了大约 30% 的改进。但是,由于某种原因,在空白画布上绘图并不能同时保留图像和叠加层。
    • 当您导出叠加层时,也使用 JPEG 作为压缩格式。因为JPEG的压缩可以通过硬件辅助,而PNG压缩完全是软件操作。
    猜你喜欢
    • 2014-01-03
    • 1970-01-01
    • 1970-01-01
    • 2013-11-15
    • 1970-01-01
    • 1970-01-01
    • 2017-04-15
    • 2011-12-14
    • 1970-01-01
    相关资源
    最近更新 更多