Android高效旋转图片的方式

文章目录

  • 背景
  • renderscript方式的优缺点
  • 代码
  • 结束

背景

在项目开发中涉及到比较多的图片处理,如摄像头预览图片的旋转,送入人脸识别sdk的图片数据,上传到后台识别记录的抓拍图片等等,以前常用的方式都是直接使用matrix来处理或者重复创建多个bitmap,这样会造成大量的资源浪费,并且效率低下,通过查找一些资料,发现了可以使用renderscript来处理,这样的方式会更快,因此在此记录下。

不知道renderscript是什么的同学可以看下这篇文章:Android高效计算——RenderScript

renderscript方式的优缺点

优点:

1、速度更快(对比matrix的方式速度2-5倍);

2、cpu和内存降低(使用同一份缓存);

缺点:

1、可能存在适配问题。
2、实现复杂。

代码

  • ScriptUtils
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.support.v8.renderscript.*;
import android.util.Log;
public class ScriptUtils {
	private static final String TAG = "ScriptUtil";
	private static RenderScript mRs;
	private static Allocation mInAllocation;
	private static Allocation mOutAllocation;
	private static ScriptC_rotatemirror mRotateRotateMirrorScript;
	private static ScriptC_rotate mRotateRotateScript;
	
	public static void getRotateBitmap(Context context, Bitmap bitmap,Bitmap outBitmap,
			boolean isFrontCamera) {
		if(isFrontCamera){
			getRotateAndMirrorBitmap(context, bitmap,outBitmap);
			return;
		}
		getRotateBitmap(context, bitmap,outBitmap);
	} 
	public static void getRotateBitmap(Context context, Bitmap bitmap,Bitmap outBitmap){
		if(bitmap == null || bitmap.isRecycled() || outBitmap == null || outBitmap.isRecycled()){
			Log.w(TAG, "getRotateBitmap bitmap is empty!");
		}
		initRsIfNeed(context,bitmap,outBitmap);	
		mInAllocation.copyFrom(bitmap);

		mRotateRotateScript.bind_gPixels(mInAllocation);
		mRotateRotateScript.set_gIn(mOutAllocation);
		mRotateRotateScript.set_gOut(mOutAllocation);
		mRotateRotateScript.set_gScript(mRotateRotateScript);
		mRotateRotateScript.invoke_filter();
		mOutAllocation.copyTo(outBitmap);
	}
	
	public static void getRotateAndMirrorBitmap(Context context, Bitmap bitmap,Bitmap outBitmap){
		if(bitmap == null || bitmap.isRecycled() || outBitmap == null || outBitmap.isRecycled()){
			Log.w(TAG, "getRotateAndMirrorBitmap bitmap is empty!");
		}
		initRsIfNeed(context,bitmap,outBitmap);		
		mInAllocation.copyFrom(bitmap);
		mRotateRotateMirrorScript.bind_gPixels(mInAllocation);
		mRotateRotateMirrorScript.set_gIn(mOutAllocation);
		mRotateRotateMirrorScript.set_gOut(mOutAllocation);
		mRotateRotateMirrorScript.set_gScript(mRotateRotateMirrorScript);
		mRotateRotateMirrorScript.invoke_filter();
		mOutAllocation.copyTo(outBitmap);
	}
	
	private static void initRsIfNeed(Context context,Bitmap inBitmap,Bitmap outBitmap){
		if(mRs == null){
			mRs = RenderScript.create(context);
		}
		int width = inBitmap.getWidth();
		int height = inBitmap.getHeight();
		if(mInAllocation == null ||  (mInAllocation.getType().getX() != width || mInAllocation.getType().getY() != height) ){
			if(mInAllocation != null){
				mInAllocation.destroy();
			}
			mInAllocation = Allocation.createFromBitmap(mRs, inBitmap,
					Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
		}
		width = outBitmap.getWidth();
		height = outBitmap.getHeight();
		if(mOutAllocation == null ||  (mOutAllocation.getType().getX() != width || mOutAllocation.getType().getY() != height) ){
			if(mOutAllocation != null){
				mOutAllocation.destroy();
			}
			mOutAllocation = Allocation.createFromBitmap(mRs, outBitmap,
					Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
		}
		if(mRotateRotateMirrorScript == null){
			mRotateRotateMirrorScript = new ScriptC_rotatemirror(mRs,context.getResources(),R.raw.rotatemirror);
		}
		if(mRotateRotateScript == null){
			mRotateRotateScript = new ScriptC_rotate(mRs,context.getResources(),R.raw.rotate);
		}
		
	}
}
  • rotate.rs
#pragma version(1)
#pragma rs java_package_name(com.jwz.bitmap.utils)

rs_allocation gIn;
rs_allocation gOut;
rs_script gScript;

static int mImageWidth;
static int mImageHeight;
const uchar4 *gPixels;

void init() {
}

void root(const uchar4 *v_in, uchar4 *v_out, const void *usrData, uint32_t x, uint32_t y) {
	
	*v_out = gPixels[y + (mImageWidth-1-x)*mImageHeight];
	
	return;
}


void filter() {
    mImageWidth = rsAllocationGetDimX(gOut);
    mImageHeight = rsAllocationGetDimY(gOut);
    /*
    rsDebug("In image size is ", rsAllocationGetDimX(gIn), rsAllocationGetDimY(gIn));
    rsDebug("Out image size is ", rsAllocationGetDimX(gOut), rsAllocationGetDimY(gOut));
    */
    rsForEach(gScript, gIn, gOut);
}
  • rotatemirror.rs
#pragma version(1)
#pragma rs java_package_name(com.jwz.bitmap.utils)

rs_allocation gIn;
rs_allocation gOut;
rs_script gScript;

static int mImageWidth;
static int mImageHeight;
const uchar4 *gPixels;

void init() {
}

void root(const uchar4 *v_in, uchar4 *v_out, const void *usrData, uint32_t x, uint32_t y) {
	*v_out = gPixels[(mImageHeight-y -1) + (mImageWidth-1-x)*mImageHeight];
	return;
}

void filter() {
    mImageWidth = rsAllocationGetDimX(gOut);
    mImageHeight = rsAllocationGetDimY(gOut);
    
    //rsDebug("In image size is ", rsAllocationGetDimX(gIn), rsAllocationGetDimY(gIn));
    //rsDebug("Out image size is ", rsAllocationGetDimX(gOut), rsAllocationGetDimY(gOut));
    
    rsForEach(gScript, gIn, gOut);
}
  • horizontalmirror.rs
#pragma version(1)
#pragma rs java_package_name(com.jwz.bitmap.utils)

rs_allocation gIn;
rs_allocation gOut;
rs_script gScript;

static int mImageWidth;
static int mImageHeight;
const uchar4 *gPixels;

void init() {
}

void root(const uchar4 *v_in, uchar4 *v_out, const void *usrData, uint32_t x, uint32_t y) {
	*v_out = gPixels[(mImageWidth - x - 1) + (y-1)*mImageWidth];
	return;
}

void filter() {
    mImageWidth = rsAllocationGetDimX(gOut);
    mImageHeight = rsAllocationGetDimY(gOut);
    
    //rsDebug("In image size is ", rsAllocationGetDimX(gIn), rsAllocationGetDimY(gIn));
    //rsDebug("Out image size is ", rsAllocationGetDimX(gOut), rsAllocationGetDimY(gOut));
    
    rsForEach(gScript, gIn, gOut);
}

结束

这些方法在实际的开发过程中还是很好用的,在人脸识别的应用中,往往几毫秒、十几毫秒的时间都是非常珍贵的,所以在开发过程中,我们尽可能多去使用这些性能较高的方式来完成我们的应用程序。

你可能感兴趣的:(Android)