数组副本排除每个 x 元素



我正在将RGBA图像转换为RGB。使用朴素数组复制:

for (int j=0, i=0; i<argbBytes.length; i++){
    if (i%4 < 3) {
        thumbRGB888[j++] = argbBytes[i];
    }
}

但是,正如预期的那样,它是超慢的(与System.arraycopy()方法相比),尤其是在Android设备上。有没有技巧可以做得更快?

使用两个索引并System.arraycopy(),每次复制 3 个元素:

for (int i = 0, j = 0; i < argbBytes.length; i += 4, j += 3)
{
    System.arraycopy(argbBytes, i, thumbRGB888, j, 3);
}

应该快得多。它不仅摆脱了模数和比较,System.arraycopy()使用本机代码实现,依赖于比单个赋值更快的memcpy

而不是

if (i%4 < 3)

for (int j=0, i=0; i<argbBytes.length; i++){
   thumbRGB888[j++] = argbBytes[i++];
   thumbRGB888[j++] = argbBytes[i++];
   thumbRGB888[j++] = argbBytes[i++];
}

这种解决方案要快得多,因为模运算和比较成本更高。

你应该避免使用 if 语句,它执行 2 个操作。
从 i=0 开始,i%4<3 表示:0,1,2,4,5,6,8,9,10。这是我的做法:

int div = 4;
int n = argbBytes.length - argbBytes.length%div;
int i=0;
int j=0;
for (; i<n; i+=div){
    // i = 0, 4, 8 ... then i, i+1,i+2 should pass (i%4<3)  
    thumbRGB888[j++] = argbBytes[i];
    thumbRGB888[j++] = argbBytes[i+1];
    thumbRGB888[j++] = argbBytes[i+2];
}
for(;i<argbBytes.length;i++){
    //i=n,n+1,n+2, since n%4==0 then (i%4<3) is passed
    thumbRGB888[j++] = argbBytes[i];
}

->i的增量相同
使用 [ 0,1,2,3,4,5,6,7,8,9,10] 返回 [0,1,2,4,5,6,8,9,10] 进行测试使用 10,000,000 个元素的数组进行测试,在 30
个元素的循环中运行原始代码:3191ms
修改后的代码:1653ms
我已经用 C# 测试过,所以结果可能会有所不同。顺便说一句,这可能没有太大的改进。

不是一个定义明确的答案,而是一个指针: 从未完成,也不能完全满足您的要求,但将转换留给位图工厂。完全不确定,但是:

使用 BitmapFactory 从字节中获取 ARGB 位图。如果不是可变的,那么可能没有进行新的分配。也可能是,您首先需要将字节包装到缓冲区中。

那么Bitmap.copy应该是可能的。

一些疯狂的想法:

BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inMutable = true; // Bitmap generated mutable.
opts.inPreferredConfig = Bitmap.Config.ARGB_8888; // I hope not BGRA.
Bitmap bmARGB = BitmapFactory.decodeByteArray(argbBytes, 0, argbBytes.length,
    opts);
bmARGB.setHasAlpha(false);
DisplayMetrics display = ...;
int[] colors = null; // Palette
Bitmap bmRGB = bmARBG.createBitmap(display, colors, width, height,
    Bitmap.Config.RGB_565); // 16 bit colors only!
bmARGB.recycle();

最新更新