赞
踩
永远不要使用完整大小的位图。图像越大,需要模糊的越多,模糊半径也需要越高,通常,模糊半径越高,算法所需的时间就越长。
缩小位图的两种方式
1.位图options缩小
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inSampleSize = 8;
- Bitmap blurTemplate = BitmapFactory.decodeResource(getResources(), bitmap, options);
加载8 位图,因此只有原始图像的 1/64。inSampleSize可以根据需要修改
,但需要满足条件 2^n (2,4,8,...) ,以避免因缩放而降低质量。
2.位图Scale缩小
- Bitmap bitmap = ...;
- float BITMAP_SCALE = 0.4f;
- int width = Math.round(bitmap .getWidth() * BITMAP_SCALE);
- int height = Math.round(bitmap .getHeight() * BITMAP_SCALE);
- // 将缩小后的图片做为预渲染的图片
- Bitmap newBitmap = Bitmap.createScaledBitmap(bitmap , width, height, false);
Renderscript 提供
了一个高斯模糊滤镜ScriptIntrinsicBlur。它具有良好的视觉质量,使得位图在 Android上获得的更快速度。Google 声称“通常比多线程 C 实现快 2-3 倍,通常比 Java 实现快 10 倍以上”
。Renderscript 非常复杂(使用最快的处理设备(GPU、ISP 等)等),在理论上,通过测试和其他开发人员的报告,不可盲目地使用 Renderscript,因为硬件/驱动程序碎片似乎会导致某些设备出现问题。
- // 图片缩放比例(即模糊度)
- private static final float BITMAP_SCALE = 0.4f;
- /**
- * @param context 上下文对象
- * @param srcBitmap 需要模糊的图片
- * @return 模糊处理后的Bitmap
- */
- public static Bitmap blurBitmap(Context context, Bitmap srcBitmap, float blurRadius) {
- // 计算图片缩小后的长宽
- int width = Math.round(srcBitmap.getWidth() * BITMAP_SCALE);
- int height = Math.round(srcBitmap.getHeight() * BITMAP_SCALE);
- // 将缩小后的图片做为预渲染的图片
- Bitmap inputBitmap = Bitmap.createScaledBitmap(srcBitmap, width, height, false);
- // 创建一张渲染后的输出图片
- Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap);
- // 创建RenderScript内核对象
- RenderScript rs = RenderScript.create(context);
- // 创建一个模糊效果的RenderScript的工具对象
- ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
- // 由于RenderScript并没有使用VM来分配内存,所以需要使用Allocation类来创建和分配内存空间
- // 创建Allocation对象的时候其实内存是空的,需要使用copyTo()将数据填充进去
- Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);
- Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);
- // 设置渲染的模糊程度, 25f是最大模糊度
- blurScript.setRadius(blurRadius);
- // 设置blurScript对象的输入内存
- blurScript.setInput(tmpIn);
- // 将输出数据保存到输出内存中
- blurScript.forEach(tmpOut);
- // 将数据填充到Allocation中
- tmpOut.copyTo(outputBitmap);
- rs.destroy();
- return outputBitmap;
- }
- android {
- ...
- defaultConfig {
- ...
- renderscriptTargetApi 19
- renderscriptSupportModeEnabled true
- }
- }
如果需要多个模糊来进行实时模糊或类似操作,并且内存允许它不会多次从可绘制对象中加载位图,而是将其“缓存”在成员变量中。在这种情况下,请始终尝试使用相同的变量,以将垃圾收集降至最低。
- public static Bitmap fastBlur(Bitmap sentBitmap, float scale, int radius) {
- int width = Math.round(sentBitmap.getWidth() * scale);
- int height = Math.round(sentBitmap.getHeight() * scale);
- sentBitmap = Bitmap.createScaledBitmap(sentBitmap, width, height, false);
- Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
- if (radius < 1) {
- return null;
- }
- int w = bitmap.getWidth();
- int h = bitmap.getHeight();
- int[] pix = new int[w * h];
- bitmap.getPixels(pix, 0, w, 0, 0, w, h);
- int wm = w - 1;
- int hm = h - 1;
- int wh = w * h;
- int div = radius + radius + 1;
- int[] r = new int[wh];
- int[] g = new int[wh];
- int[] b = new int[wh];
- int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
- int[] vmin = new int[Math.max(w, h)];
- int divsum = (div + 1) >> 1;
- divsum *= divsum;
- int[] dv = new int[256 * divsum];
- for (i = 0; i < 256 * divsum; i++) {
- dv[i] = (i / divsum);
- }
- yw = yi = 0;
- int[][] stack = new int[div][3];
- int stackpointer;
- int stackstart;
- int[] sir;
- int rbs;
- int r1 = radius + 1;
- int routsum, goutsum, boutsum;
- int rinsum, ginsum, binsum;
- for (y = 0; y < h; y++) {
- rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
- for (i = -radius; i <= radius; i++) {
- p = pix[yi + Math.min(wm, Math.max(i, 0))];
- sir = stack[i + radius];
- sir[0] = (p & 0xff0000) >> 16;
- sir[1] = (p & 0x00ff00) >> 8;
- sir[2] = (p & 0x0000ff);
- rbs = r1 - Math.abs(i);
- rsum += sir[0] * rbs;
- gsum += sir[1] * rbs;
- bsum += sir[2] * rbs;
- if (i > 0) {
- rinsum += sir[0];
- ginsum += sir[1];
- binsum += sir[2];
- } else {
- routsum += sir[0];
- goutsum += sir[1];
- boutsum += sir[2];
- }
- }
- stackpointer = radius;
- for (x = 0; x < w; x++) {
- r[yi] = dv[rsum];
- g[yi] = dv[gsum];
- b[yi] = dv[bsum];
- rsum -= routsum;
- gsum -= goutsum;
- bsum -= boutsum;
- stackstart = stackpointer - radius + div;
- sir = stack[stackstart % div];
- routsum -= sir[0];
- goutsum -= sir[1];
- boutsum -= sir[2];
- if (y == 0) {
- vmin[x] = Math.min(x + radius + 1, wm);
- }
- p = pix[yw + vmin[x]];
- sir[0] = (p & 0xff0000) >> 16;
- sir[1] = (p & 0x00ff00) >> 8;
- sir[2] = (p & 0x0000ff);
- rinsum += sir[0];
- ginsum += sir[1];
- binsum += sir[2];
- rsum += rinsum;
- gsum += ginsum;
- bsum += binsum;
- stackpointer = (stackpointer + 1) % div;
- sir = stack[(stackpointer) % div];
- routsum += sir[0];
- goutsum += sir[1];
- boutsum += sir[2];
- rinsum -= sir[0];
- ginsum -= sir[1];
- binsum -= sir[2];
- yi++;
- }
- yw += w;
- }
- for (x = 0; x < w; x++) {
- rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
- yp = -radius * w;
- for (i = -radius; i <= radius; i++) {
- yi = Math.max(0, yp) + x;
- sir = stack[i + radius];
- sir[0] = r[yi];
- sir[1] = g[yi];
- sir[2] = b[yi];
- rbs = r1 - Math.abs(i);
- rsum += r[yi] * rbs;
- gsum += g[yi] * rbs;
- bsum += b[yi] * rbs;
- if (i > 0) {
- rinsum += sir[0];
- ginsum += sir[1];
- binsum += sir[2];
- } else {
- routsum += sir[0];
- goutsum += sir[1];
- boutsum += sir[2];
- }
- if (i < hm) {
- yp += w;
- }
- }
- yi = x;
- stackpointer = radius;
- for (y = 0; y < h; y++) {
- pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum];
- rsum -= routsum;
- gsum -= goutsum;
- bsum -= boutsum;
- stackstart = stackpointer - radius + div;
- sir = stack[stackstart % div];
- routsum -= sir[0];
- goutsum -= sir[1];
- boutsum -= sir[2];
- if (x == 0) {
- vmin[y] = Math.min(y + r1, hm) * w;
- }
- p = x + vmin[y];
- sir[0] = r[p];
- sir[1] = g[p];
- sir[2] = b[p];
- rinsum += sir[0];
- ginsum += sir[1];
- binsum += sir[2];
- rsum += rinsum;
- gsum += ginsum;
- bsum += binsum;
- stackpointer = (stackpointer + 1) % div;
- sir = stack[stackpointer];
- routsum += sir[0];
- goutsum += sir[1];
- boutsum += sir[2];
- rinsum -= sir[0];
- ginsum -= sir[1];
- binsum -= sir[2];
- yi += w;
- }
- }
- bitmap.setPixels(pix, 0, w, 0, 0, w, h);
- return bitmap;
- }
- #include <jni.h>
- #include <string.h>
- #include <math.h>
- #include <stdio.h>
- #include <android/log.h>
- #include <android/bitmap.h>
-
- #define LOG_TAG "libbitmaputils"
- #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
- #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
-
- typedef struct {
- uint8_t red;
- uint8_t green;
- uint8_t blue;
- uint8_t alpha;
- } rgba;
-
- JNIEXPORT void JNICALL Java_com_insert_your_package_ClassName_functionToBlur(JNIEnv* env, jobject obj, jobject bitmapIn, jobject bitmapOut, jint radius) {
- LOGI("Blurring bitmap...");
-
- // Properties
- AndroidBitmapInfo infoIn;
- void* pixelsIn;
- AndroidBitmapInfo infoOut;
- void* pixelsOut;
-
- int ret;
-
- // Get image info
- if ((ret = AndroidBitmap_getInfo(env, bitmapIn, &infoIn)) < 0 || (ret = AndroidBitmap_getInfo(env, bitmapOut, &infoOut)) < 0) {
- LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
- return;
- }
-
- // Check image
- if (infoIn.format != ANDROID_BITMAP_FORMAT_RGBA_8888 || infoOut.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
- LOGE("Bitmap format is not RGBA_8888!");
- LOGE("==> %d %d", infoIn.format, infoOut.format);
- return;
- }
-
- // Lock all images
- if ((ret = AndroidBitmap_lockPixels(env, bitmapIn, &pixelsIn)) < 0 || (ret = AndroidBitmap_lockPixels(env, bitmapOut, &pixelsOut)) < 0) {
- LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
- }
-
- int h = infoIn.height;
- int w = infoIn.width;
-
- LOGI("Image size is: %i %i", w, h);
-
- rgba* input = (rgba*) pixelsIn;
- rgba* output = (rgba*) pixelsOut;
-
- int wm = w - 1;
- int hm = h - 1;
- int wh = w * h;
- int whMax = max(w, h);
- int div = radius + radius + 1;
-
- int r[wh];
- int g[wh];
- int b[wh];
- int rsum, gsum, bsum, x, y, i, yp, yi, yw;
- rgba p;
- int vmin[whMax];
-
- int divsum = (div + 1) >> 1;
- divsum *= divsum;
- int dv[256 * divsum];
- for (i = 0; i < 256 * divsum; i++) {
- dv[i] = (i / divsum);
- }
-
- yw = yi = 0;
-
- int stack[div][3];
- int stackpointer;
- int stackstart;
- int rbs;
- int ir;
- int ip;
- int r1 = radius + 1;
- int routsum, goutsum, boutsum;
- int rinsum, ginsum, binsum;
-
- for (y = 0; y < h; y++) {
- rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
- for (i = -radius; i <= radius; i++) {
- p = input[yi + min(wm, max(i, 0))];
-
- ir = i + radius; // same as sir
-
- stack[ir][0] = p.red;
- stack[ir][1] = p.green;
- stack[ir][2] = p.blue;
- rbs = r1 - abs(i);
- rsum += stack[ir][0] * rbs;
- gsum += stack[ir][1] * rbs;
- bsum += stack[ir][2] * rbs;
- if (i > 0) {
- rinsum += stack[ir][0];
- ginsum += stack[ir][1];
- binsum += stack[ir][2];
- } else {
- routsum += stack[ir][0];
- goutsum += stack[ir][1];
- boutsum += stack[ir][2];
- }
- }
- stackpointer = radius;
-
- for (x = 0; x < w; x++) {
-
- r[yi] = dv[rsum];
- g[yi] = dv[gsum];
- b[yi] = dv[bsum];
-
- rsum -= routsum;
- gsum -= goutsum;
- bsum -= boutsum;
-
- stackstart = stackpointer - radius + div;
- ir = stackstart % div; // same as sir
-
- routsum -= stack[ir][0];
- goutsum -= stack[ir][1];
- boutsum -= stack[ir][2];
-
- if (y == 0) {
- vmin[x] = min(x + radius + 1, wm);
- }
- p = input[yw + vmin[x]];
-
- stack[ir][0] = p.red;
- stack[ir][1] = p.green;
- stack[ir][2] = p.blue;
-
- rinsum += stack[ir][0];
- ginsum += stack[ir][1];
- binsum += stack[ir][2];
-
- rsum += rinsum;
- gsum += ginsum;
- bsum += binsum;
-
- stackpointer = (stackpointer + 1) % div;
- ir = (stackpointer) % div; // same as sir
-
- routsum += stack[ir][0];
- goutsum += stack[ir][1];
- boutsum += stack[ir][2];
-
- rinsum -= stack[ir][0];
- ginsum -= stack[ir][1];
- binsum -= stack[ir][2];
-
- yi++;
- }
- yw += w;
- }
- for (x = 0; x < w; x++) {
- rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
- yp = -radius * w;
- for (i = -radius; i <= radius; i++) {
- yi = max(0, yp) + x;
-
- ir = i + radius; // same as sir
-
- stack[ir][0] = r[yi];
- stack[ir][1] = g[yi];
- stack[ir][2] = b[yi];
-
- rbs = r1 - abs(i);
-
- rsum += r[yi] * rbs;
- gsum += g[yi] * rbs;
- bsum += b[yi] * rbs;
-
- if (i > 0) {
- rinsum += stack[ir][0];
- ginsum += stack[ir][1];
- binsum += stack[ir][2];
- } else {
- routsum += stack[ir][0];
- goutsum += stack[ir][1];
- boutsum += stack[ir][2];
- }
-
- if (i < hm) {
- yp += w;
- }
- }
- yi = x;
- stackpointer = radius;
- for (y = 0; y < h; y++) {
- output[yi].red = dv[rsum];
- output[yi].green = dv[gsum];
- output[yi].blue = dv[bsum];
-
- rsum -= routsum;
- gsum -= goutsum;
- bsum -= boutsum;
-
- stackstart = stackpointer - radius + div;
- ir = stackstart % div; // same as sir
-
- routsum -= stack[ir][0];
- goutsum -= stack[ir][1];
- boutsum -= stack[ir][2];
-
- if (x == 0) vmin[y] = min(y + r1, hm) * w;
- ip = x + vmin[y];
-
- stack[ir][0] = r[ip];
- stack[ir][1] = g[ip];
- stack[ir][2] = b[ip];
-
- rinsum += stack[ir][0];
- ginsum += stack[ir][1];
- binsum += stack[ir][2];
-
- rsum += rinsum;
- gsum += ginsum;
- bsum += binsum;
-
- stackpointer = (stackpointer + 1) % div;
- ir = stackpointer; // same as sir
-
- routsum += stack[ir][0];
- goutsum += stack[ir][1];
- boutsum += stack[ir][2];
-
- rinsum -= stack[ir][0];
- ginsum -= stack[ir][1];
- binsum -= stack[ir][2];
-
- yi += w;
- }
- }
-
- // Unlocks everything
- AndroidBitmap_unlockPixels(env, bitmapIn);
- AndroidBitmap_unlockPixels(env, bitmapOut);
-
- LOGI ("Bitmap blurred.");
- }
-
- int min(int a, int b) {
- return a > b ? b : a;
- }
-
- int max(int a, int b) {
- return a > b ? a : b;
- }
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。