Question

I have a long array of bytes which represents abgr32 pixel data (0xAABBGGRR) of a big picture. Is there an efficient way to change the endiness of this long byte array in java?

For example:

Source byte array is [FF,11,22,33,FF,12,34,11,..........]

Is it possible to convert it to something like this [33,22,11,FF,11,34,12,FF,....] ? Efficiency is important.

I have tryed to use ByteBuffer.order(ByteOrder.LITTLE_ENDIAN) and ByteBuffer.order(ByteOrder.BIG_ENDIAN) conversion but it didn't help.

Thank you for your help.

Was it helpful?

Solution 3

You can try doing it manually by swapping the bytes in each group of adjacent 4 bytes. This code assumes that the length of the array is a multiple of 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;
}

Though this is technically a solution to the problem, it may be wiser to find a solution which is not endian-ness sensitive (like some of the comments above).

OTHER TIPS

First of all: Are you sure you need to change it? The native Java BufferedImage.TYPE_4BYTE_ABGR should work fine for this pixel layout...

Now, if you really need to change the byte order, wrapping the array in a byte buffer, using ByteBuffer.order(ByteOrder.LITTLE_ENDIAN) should work. Just remember you have to read/get integers from the byte buffer, for the byte order to have significance in this case. Changing the byte order does not change the internal order of the bytes, just how multi-byte types (short, int, long) are interpreted.

Both of these version does no array reordering, and thus likely to be faster than anything that does reordering. If you really want to reorder, see the other answers in the thread.

There are some tricks you can do with Unsafe which are faster, but the simplest thing you can do is make sure the code is warmed up.

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

prints

[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

I would just go for a simple iteration:

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];
}

It might work faster than "conventional swapping", if you know how to tell the compiler to apply some sort of loop-unrolling optimization.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top