安卓开发|通过RenderScript 实现 NV21转Bitmap、两张Bitmap按照透明度混合的工具类

之前写的一篇文章中我通过提取bitmap的数组,然后通过位移运算提取两个数组的alpha值通过比例混合为一张新的图片,这样对于大图片来说会很卡。所以我在查阅资料后:
安卓开发手册 ScriptIntrinsicBlend
通过RenderScript使用GPU加速来获得非常好的转换效果,只要使用安卓自身提供的脚本工具类ScriptIntrinsicBlend,配置好参数和输入输出,还有混合模式,即可快速完成该任务。
4k×2k的两张Bitmap可以在我的手机上只要30ms就可以混合完成。下面贴出我写的工具类:

package com.meizu.argbinsertyuv; import android.content.Context; import android.graphics.Bitmap; import android.graphics.ImageFormat; import android.graphics.Rect; import android.graphics.YuvImage; import android.renderscript.Allocation; import android.renderscript.Element; import android.renderscript.RenderScript; import android.renderscript.ScriptIntrinsicBlend; import android.renderscript.ScriptIntrinsicYuvToRGB; import android.renderscript.Type; import android.util.Log; import java.io.OutputStream; /**@author 陈杰柱**/ public class YuvUtil { private Context mContext; private RenderScript rs; private ScriptIntrinsicYuvToRGB mYuvToRgbIntrinsic; private ScriptIntrinsicBlend mScriptIntrinsicBlend; private Type.Builder mYuvType, mRgbaType; private Type.Builder mRgbType1, mRgbType2; private Allocation mYuvin, mYuvOut; private Allocation mARGBPic1, mARGBPic2; private Bitmap mBmpout; public YuvUtil(Context context) { this.mContext = context; rs = RenderScript.create(context); mYuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs)); mScriptIntrinsicBlend = ScriptIntrinsicBlend.create(rs, Element.RGBA_8888(rs)); }/**nv21转bmp**/ public Bitmap nv21ToBitmap(byte[] nv21, int width, int height) { long start = System.currentTimeMillis(); if (mYuvType == null) { mYuvType = new Type.Builder(rs, Element.U8(rs)).setX(nv21.length); mYuvin = Allocation.createTyped(rs, mYuvType.create(), Allocation.USAGE_SCRIPT); mRgbaType = new Type.Builder(rs, Element.RGBA_8888(rs)).setX(width).setY(height); mYuvOut = Allocation.createTyped(rs, mRgbaType.create(), Allocation.USAGE_SCRIPT); } mYuvin.copyFrom(nv21); mYuvToRgbIntrinsic.setInput(mYuvin); mYuvToRgbIntrinsic.forEach(mYuvOut); if (mBmpout == null) { mBmpout = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); } else if (mBmpout.getWidth() != width || mBmpout.getHeight() != height) { mBmpout = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); } mYuvOut.copyTo(mBmpout); Log.i("cjztest", "nv21转bmp" + (System.currentTimeMillis() - start) + "ms"); return mBmpout; }/**两个bmp按照透明度混合**/ public Bitmap bitmapBlendBitmap(Bitmap bottom, Bitmap top) { long start = System.currentTimeMillis(); if (mRgbType1 == null || mRgbType2 == null) { mRgbType1 = new Type.Builder(rs, Element.RGBA_8888(rs)).setX(top.getWidth()).setY(top.getHeight()); mRgbType2 = new Type.Builder(rs, Element.RGBA_8888(rs)).setX(bottom.getWidth()).setY(bottom.getHeight()); mARGBPic1 = Allocation.createTyped(rs, mRgbType1.create(), Allocation.USAGE_SCRIPT); mARGBPic2 = Allocation.createTyped(rs, mRgbType2.create(), Allocation.USAGE_SCRIPT); } mARGBPic1.copyFrom(top); mARGBPic2.copyFrom(bottom); //mScriptIntrinsicBlend.forEachAdd(mARGBPic1, mYuvOut); //mScriptIntrinsicBlend.forEachDstAtop(mARGBPic1, mARGBPic2); //mScriptIntrinsicBlend.forEachDstIn(mARGBPic1, mARGBPic2); //mScriptIntrinsicBlend.forEachDstOut(mARGBPic2, mARGBPic1); mScriptIntrinsicBlend.forEachDstOver(mARGBPic2, mARGBPic1); if (mBmpout == null) { mBmpout = Bitmap.createBitmap(top.getWidth(), top.getHeight(), Bitmap.Config.ARGB_8888); } else if (mBmpout.getWidth() != top.getWidth() || mBmpout.getHeight() != top.getHeight()) { mBmpout = Bitmap.createBitmap(top.getWidth(), top.getHeight(), Bitmap.Config.ARGB_8888); } mARGBPic1.copyTo(mBmpout); Log.i("cjztest", "两个bmp按照透明度混合使用的时间" + (System.currentTimeMillis() - start) + "ms"); return mBmpout; }/**传统方法把YUV转jpg**/ public void nv21ToBitmapDirectSave(byte[] nv21, int width, int height, OutputStream os) { YuvImage im = new YuvImage(nv21, ImageFormat.NV21, width, height, new int[]{width, width, width}); im.compressToJpeg(new Rect(0, 0, width, height), 80, os); } }

另外可以符合使用,例如如果你希望实现在NV21上混合一个同样宽高的bmp,可以这么使用,也就是NV21先变成BMP再混合:
Bitmap resultBmp = mYuvUtil.bitmapBlendBitmap(mYuvUtil.nv21ToBitmap(photoBuffer, width, height), waterMarkBmp);

【安卓开发|通过RenderScript 实现 NV21转Bitmap、两张Bitmap按照透明度混合的工具类】

    推荐阅读