我有一长串字节,表示大图片的abgr32
像素数据(0xAABBGGRR
)。
有没有一种有效的方法来改变java中这个长字节数组的持久性?
例如:
源字节数组是[FF,11,22,33,FF,12,34,11,..........
]
是否可以将其转换为此类[33,22,11,FF,11,34,12,FF,....
]?
效率很重要。
我尝试使用ByteBuffer.order(ByteOrder.LITTLE_ENDIAN
)和ByteBuffer.order(ByteOrder.BIG_ENDIAN)
转换,但它没有帮助。
感谢您的帮助。
答案 0 :(得分:4)
首先:您确定需要更改它吗?本机Java BufferedImage.TYPE_4BYTE_ABGR
应该适用于此像素布局......
现在,如果你真的需要更改字节顺序,将数组包装在字节缓冲区中,使用ByteBuffer.order(ByteOrder.LITTLE_ENDIAN)
应该可行。只记得你必须从字节缓冲区读取/获取整数,因为在这种情况下字节顺序具有重要性。更改字节顺序不会更改字节的内部顺序,只是多字节类型(short, int, long
)解释的方式。
这两个版本都不进行数组重新排序,因此可能比重新排序的任何版本更快。如果您真的想重新排序,请参阅主题中的其他答案。
答案 1 :(得分:3)
您可以尝试通过交换相邻4个字节的每组中的字节来手动执行此操作。 此代码假定数组的长度是4的倍数。
for (int i = 0; i < arr.length; i += 4) {
int tmp;
// swap 0 and 3
tmp = arr[i];
arr[i] = arr[i + 3];
arr[i + 3] = tmp;
// swap 1 and 2
tmp = arr[i + 1];
arr[i + 1] = arr[i + 2];
arr[i + 2] = tmp;
}
虽然这在技术上是解决问题的方法,但找到一个不具有字符串敏感性的解决方案可能更明智(如上面的一些评论)。
答案 2 :(得分:2)
使用Unsafe可以做一些技巧更快,但最简单的方法是确保代码预热。
public static void swapIntBytes(byte[] bytes) {
assert bytes.length % 4 == 0;
for (int i = 0; i < bytes.length; i += 4) {
// swap 0 and 3
byte tmp = bytes[i];
bytes[i] = bytes[i + 3];
bytes[i + 3] = tmp;
// swap 1 and 2
byte tmp2 = bytes[i + 1];
bytes[i + 1] = bytes[i + 2];
bytes[i + 2] = tmp2;
}
}
public static void swapIntBytes2(byte[] bytes) {
assert bytes.length % 4 == 0;
IntBuffer bb1 = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).asIntBuffer();
IntBuffer bb2 = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer();
bb1.put(bb2);
}
public static void swapIntBytes3(byte[] bytes) {
assert bytes.length % 4 == 0;
for (int i = 0; i < bytes.length; i += 4)
UNSAFE.putInt(bytes, BYTES_OFFSET + i, Integer.reverseBytes(UNSAFE.getInt(bytes, BYTES_OFFSET + i)));
}
public static void main(String... ignored) {
byte[] bytes = {1, 2, 3, 4, 5, 6, 7, 8};
swapIntBytes3(bytes);
System.out.println(Arrays.toString(bytes));
byte[] bytes4k = new byte[16384];
for (int i = 0; i < 20; i++) {
long start = System.nanoTime();
swapIntBytes(bytes4k);
long mid1 = System.nanoTime();
swapIntBytes2(bytes4k);
long mid2 = System.nanoTime();
swapIntBytes3(bytes4k);
long end = System.nanoTime();
System.out.printf("Swap byte[] %.1f us, Swap IntBuffer %.1f us, Swap UNSAFE %.1f%n",
(mid1 - start) / 1e3, (mid2 - mid1) / 1e3, (end - mid2) / 1e3);
}
}
static final Unsafe UNSAFE;
static final int BYTES_OFFSET;
static {
try {
@SuppressWarnings("ALL")
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
UNSAFE = (Unsafe) theUnsafe.get(null);
BYTES_OFFSET = UNSAFE.arrayBaseOffset(byte[].class);
} catch (Exception e) {
throw new AssertionError(e);
}
}
打印
[4, 3, 2, 1, 8, 7, 6, 5]
Swap byte[] 433.8 us, Swap IntBuffer 8577.8 us, Swap UNSAFE 1711.8
Swap byte[] 244.6 us, Swap IntBuffer 5773.1 us, Swap UNSAFE 1764.0
Swap byte[] 247.5 us, Swap IntBuffer 5059.7 us, Swap UNSAFE 1756.3
Swap byte[] 255.7 us, Swap IntBuffer 416.9 us, Swap UNSAFE 563.6
Swap byte[] 441.7 us, Swap IntBuffer 437.6 us, Swap UNSAFE 597.4
Swap byte[] 12.1 us, Swap IntBuffer 466.9 us, Swap UNSAFE 632.7
Swap byte[] 11.6 us, Swap IntBuffer 448.4 us, Swap UNSAFE 7.8
Swap byte[] 10.7 us, Swap IntBuffer 415.4 us, Swap UNSAFE 7.0
Swap byte[] 10.2 us, Swap IntBuffer 426.1 us, Swap UNSAFE 6.6
Swap byte[] 9.1 us, Swap IntBuffer 49.0 us, Swap UNSAFE 3.4
Swap byte[] 5.9 us, Swap IntBuffer 24.4 us, Swap UNSAFE 3.1
Swap byte[] 6.0 us, Swap IntBuffer 24.3 us, Swap UNSAFE 3.2
Swap byte[] 5.9 us, Swap IntBuffer 24.2 us, Swap UNSAFE 3.1
Swap byte[] 5.9 us, Swap IntBuffer 24.2 us, Swap UNSAFE 3.1
Swap byte[] 5.9 us, Swap IntBuffer 24.1 us, Swap UNSAFE 3.1
Swap byte[] 5.9 us, Swap IntBuffer 24.2 us, Swap UNSAFE 3.1
Swap byte[] 5.9 us, Swap IntBuffer 24.2 us, Swap UNSAFE 3.1
Swap byte[] 6.6 us, Swap IntBuffer 27.1 us, Swap UNSAFE 3.5
Swap byte[] 5.9 us, Swap IntBuffer 24.2 us, Swap UNSAFE 3.1
Swap byte[] 6.7 us, Swap IntBuffer 27.1 us, Swap UNSAFE 3.5
答案 3 :(得分:0)
我只想进行一次简单的迭代:
for (int i=0; i<array.length; i+=4)
{
int sum03 = array[i+0]+array[i+3];
int sum12 = array[i+1]+array[i+2];
array[i+0] = sum03 - array[i+0];
array[i+1] = sum12 - array[i+1];
array[i+2] = sum12 - array[i+2];
array[i+3] = sum03 - array[i+3];
}
如果您知道如何告诉编译器应用某种循环展开优化,它可能比“传统交换”更快。