For the 90-degrees rotations I really embrace RenderScript which is exactly designed to deal with bitmaps and is unexpectedly even faster than the default Bitmap.createBitmap()
. The in-process bitmap isn't stored on the Java heap, therefore not pushing you into OutOfMemoryError
.
After you set up the RenderScript support in your project with few lines, here is the RenderScript algorithm to use:
1) Create appsrcmain
s
otator.rs
RenderScript file with the following content.
#pragma version(1)
#pragma rs java_package_name(ua.kulku.rs)
rs_allocation inImage;
int inWidth;
int inHeight;
uchar4 __attribute__ ((kernel)) rotate_90_clockwise (uchar4 in, uint32_t x, uint32_t y) {
uint32_t inX = inWidth - 1 - y;
uint32_t inY = x;
const uchar4 *out = rsGetElementAt(inImage, inX, inY);
return *out;
}
uchar4 __attribute__ ((kernel)) rotate_270_clockwise (uchar4 in, uint32_t x, uint32_t y) {
uint32_t inX = y;
uint32_t inY = inHeight - 1 - x;
const uchar4 *out = rsGetElementAt(inImage, inX, inY);
return *out;
}
Pay attention to ua.kulku.rs
, that's some package name you choose for the auto-generate RS Java interface.
2) Reference it in your Java code:
import ua.kulku.rs.ScriptC_rotator;
public Bitmap rotate(Bitmap bitmap) {
RenderScript rs = RenderScript.create(mContext);
ScriptC_rotator script = new ScriptC_rotator(rs);
script.set_inWidth(bitmap.getWidth());
script.set_inHeight(bitmap.getHeight());
Allocation sourceAllocation = Allocation.createFromBitmap(rs, bitmap,
Allocation.MipmapControl.MIPMAP_NONE,
Allocation.USAGE_SCRIPT);
bitmap.recycle();
script.set_inImage(sourceAllocation);
int targetHeight = bitmap.getWidth();
int targetWidth = bitmap.getHeight();
Bitmap.Config config = bitmap.getConfig();
Bitmap target = Bitmap.createBitmap(targetWidth, targetHeight, config);
final Allocation targetAllocation = Allocation.createFromBitmap(rs, target,
Allocation.MipmapControl.MIPMAP_NONE,
Allocation.USAGE_SCRIPT);
script.forEach_rotate_90_clockwise(targetAllocation, targetAllocation);
targetAllocation.copyTo(target);
rs.destroy();
return target;
}
For 180-degrees rotations, NDK solution outperformed RenderScript, as for me, due to making use of the sequential array item access, as the 180-degree rotation is actually the reversion of the image's pixel array. The NDK algorithm I've used in these comparisons is from https://github.com/AndroidDeveloperLB/AndroidJniBitmapOperations . The in-process bitmap is also not stored on the Java heap, preventing OutOfMemoryError
.
The stats bars indicate what I got in milliseconds on my Samsung S4 (Android 5.0) for the 13 MP photo.