Android開發——深度毛玻璃效果

ImageView
在開發中使用毛玻璃效果時,通常是以Dialog的形式彈出的,若是跳轉到另外一個Activity顯示的話,在速度上明顯不如Dialog.我遇到的狀況是須要先把原先的界面進行截屏,而後將截屏的界面進行毛玻璃深度處理。

流程以下:android

1.截取原先的界面生成Bitmap算法

 
  1. View view = activity.getWindow().getDecorView();
  2. view.setDrawingCacheEnabled(true);
  3. view.buildDrawingCache();
  4. Bitmap screenshotBitmap = view.getDrawingCache();

2.將圖片進行質量壓縮ui

 
  1. screenshotBitmap = compressImage(screenshotBitmap);// 將圖片進行壓縮
 
  1. /**
  2. * 將圖片的進行質量壓縮
  3. */
  4. private static Bitmap compressImage(Bitmap image) {
  5.  
  6. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  7. image.compress(Bitmap.CompressFormat.JPEG, 30, baos);// 質量壓縮方法,30是壓縮率表示壓縮70%,把壓縮後的數據存放到baos中
  8. int options = 100;
  9. while (baos.toByteArray().length / 1024 > 200) { // 循環判斷若是壓縮後圖片是否大於200kb,大於繼續壓縮
  10. baos.reset();// 重置baos即清空baos
  11. options -= 10;// 每次都減小10
  12. image.compress(Bitmap.CompressFormat.JPEG, options, baos);// 這裏壓縮options%,把壓縮後的數據存放到baos中
  13.  
  14. }
  15. ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());// 把壓縮後的數據baos存放到ByteArrayInputStream中
  16. return BitmapFactory.decodeStream(isBm, null, null);// 把ByteArrayInputStream數據生成圖片
  17. }

3.去掉狀態欄,code

 
  1. // 獲取狀態欄高度
  2. Rect frame = new Rect();
  3. activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
  4. int statusBarHeight = frame.top;
  5. // 獲取屏幕長和高
  6. int width = activity.getWindowManager().getDefaultDisplay().getWidth();
  7. int height = activity.getWindowManager().getDefaultDisplay()
  8. .getHeight();
  9. try {
  10. // 去掉標題欄
  11. screenshotBitmap = Bitmap.createBitmap(screenshotBitmap, 0,
  12. statusBarHeight, width, height - statusBarHeight);
  13. } catch (OutOfMemoryError e) {
  14. e.printStackTrace();
  15. }

4.當系統sdk版本大於16時使用API提供的ScriptIntrinsicBlur方法進行模糊化,值是從1--25.小於16時採用算法進行.orm

 
  1. import android.annotation.SuppressLint;
  2. import android.content.Context;
  3. import android.graphics.Bitmap;
  4. import android.os.Build.VERSION;
  5. import android.renderscript.Allocation;
  6. import android.renderscript.Element;
  7. import android.renderscript.RenderScript;
  8. import android.renderscript.ScriptIntrinsicBlur;
  9. import android.util.Log;
  10.  
  11. public class Blur {
  12.  
  13. private static final String TAG = "Blur";
  14.  
  15. @SuppressLint("NewApi")
  16. public static Bitmap fastblur(Context context, Bitmap sentBitmap, int radius) {
  17.  
  18. if (VERSION.SDK_INT > 16) {
  19. Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
  20.  
  21. final RenderScript rs = RenderScript.create(context);
  22. final Allocation input = Allocation.createFromBitmap(rs, sentBitmap, Allocation.MipmapControl.MIPMAP_NONE,
  23. Allocation.USAGE_SCRIPT);
  24. final Allocation output = Allocation.createTyped(rs, input.getType());
  25. final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
  26. script.setRadius(radius /* e.g. 3.f */);
  27. script.setInput(input);
  28. script.forEach(output);
  29. output.copyTo(bitmap);
  30. return bitmap;
  31. }
  32.  
  33. Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
  34.  
  35. if (radius < 1) {
  36. return (null);
  37. }
  38.  
  39. int w = bitmap.getWidth();
  40. int h = bitmap.getHeight();
  41.  
  42. int[] pix = new int[w * h];
  43. Log.e("pix", w + " " + h + " " + pix.length);
  44. bitmap.getPixels(pix, 0, w, 0, 0, w, h);
  45.  
  46. int wm = w - 1;
  47. int hm = h - 1;
  48. int wh = w * h;
  49. int div = radius + radius + 1;
  50.  
  51. int r[] = new int[wh];
  52. int g[] = new int[wh];
  53. int b[] = new int[wh];
  54. int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
  55. int vmin[] = new int[Math.max(w, h)];
  56.  
  57. int divsum = (div + 1) >> 1;
  58. divsum *= divsum;
  59. int dv[] = new int[256 * divsum];
  60. for (i = 0; i < 256 * divsum; i++) {
  61. dv[i] = (i / divsum);
  62. }
  63.  
  64. yw = yi = 0;
  65.  
  66. int[][] stack = new int[div][3];
  67. int stackpointer;
  68. int stackstart;
  69. int[] sir;
  70. int rbs;
  71. int r1 = radius + 1;
  72. int routsum, goutsum, boutsum;
  73. int rinsum, ginsum, binsum;
  74.  
  75. for (y = 0; y < h; y++) {
  76. rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
  77. for (i = -radius; i <= radius; i++) {
  78. p = pix[yi + Math.min(wm, Math.max(i, 0))];
  79. sir = stack[i + radius];
  80. sir[0] = (p & 0xff0000) >> 16;
  81. sir[1] = (p & 0x00ff00) >> 8;
  82. sir[2] = (p & 0x0000ff);
  83. rbs = r1 - Math.abs(i);
  84. rsum += sir[0] * rbs;
  85. gsum += sir[1] * rbs;
  86. bsum += sir[2] * rbs;
  87. if (i > 0) {
  88. rinsum += sir[0];
  89. ginsum += sir[1];
  90. binsum += sir[2];
  91. } else {
  92. routsum += sir[0];
  93. goutsum += sir[1];
  94. boutsum += sir[2];
  95. }
  96. }
  97. stackpointer = radius;
  98.  
  99. for (x = 0; x < w; x++) {
  100.  
  101. r[yi] = dv[rsum];
  102. g[yi] = dv[gsum];
  103. b[yi] = dv[bsum];
  104.  
  105. rsum -= routsum;
  106. gsum -= goutsum;
  107. bsum -= boutsum;
  108.  
  109. stackstart = stackpointer - radius + div;
  110. sir = stack[stackstart % div];
  111.  
  112. routsum -= sir[0];
  113. goutsum -= sir[1];
  114. boutsum -= sir[2];
  115.  
  116. if (y == 0) {
  117. vmin[x] = Math.min(x + radius + 1, wm);
  118. }
  119. p = pix[yw + vmin[x]];
  120.  
  121. sir[0] = (p & 0xff0000) >> 16;
  122. sir[1] = (p & 0x00ff00) >> 8;
  123. sir[2] = (p & 0x0000ff);
  124.  
  125. rinsum += sir[0];
  126. ginsum += sir[1];
  127. binsum += sir[2];
  128.  
  129. rsum += rinsum;
  130. gsum += ginsum;
  131. bsum += binsum;
  132.  
  133. stackpointer = (stackpointer + 1) % div;
  134. sir = stack[(stackpointer) % div];
  135.  
  136. routsum += sir[0];
  137. goutsum += sir[1];
  138. boutsum += sir[2];
  139.  
  140. rinsum -= sir[0];
  141. ginsum -= sir[1];
  142. binsum -= sir[2];
  143.  
  144. yi++;
  145. }
  146. yw += w;
  147. }
  148. for (x = 0; x < w; x++) {
  149. rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
  150. yp = -radius * w;
  151. for (i = -radius; i <= radius; i++) {
  152. yi = Math.max(0, yp) + x;
  153.  
  154. sir = stack[i + radius];
  155.  
  156. sir[0] = r[yi];
  157. sir[1] = g[yi];
  158. sir[2] = b[yi];
  159.  
  160. rbs = r1 - Math.abs(i);
  161.  
  162. rsum += r[yi] * rbs;
  163. gsum += g[yi] * rbs;
  164. bsum += b[yi] * rbs;
  165.  
  166. if (i > 0) {
  167. rinsum += sir[0];
  168. ginsum += sir[1];
  169. binsum += sir[2];
  170. } else {
  171. routsum += sir[0];
  172. goutsum += sir[1];
  173. boutsum += sir[2];
  174. }
  175.  
  176. if (i < hm) {
  177. yp += w;
  178. }
  179. }
  180. yi = x;
  181. stackpointer = radius;
  182. for (y = 0; y < h; y++) {
  183. // Preserve alpha channel: ( 0xff000000 & pix[yi] )
  184. pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum];
  185.  
  186. rsum -= routsum;
  187. gsum -= goutsum;
  188. bsum -= boutsum;
  189.  
  190. stackstart = stackpointer - radius + div;
  191. sir = stack[stackstart % div];
  192.  
  193. routsum -= sir[0];
  194. goutsum -= sir[1];
  195. boutsum -= sir[2];
  196.  
  197. if (x == 0) {
  198. vmin[y] = Math.min(y + r1, hm) * w;
  199. }
  200. p = x + vmin[y];
  201.  
  202. sir[0] = r[p];
  203. sir[1] = g[p];
  204. sir[2] = b[p];
  205.  
  206. rinsum += sir[0];
  207. ginsum += sir[1];
  208. binsum += sir[2];
  209.  
  210. rsum += rinsum;
  211. gsum += ginsum;
  212. bsum += binsum;
  213.  
  214. stackpointer = (stackpointer + 1) % div;
  215. sir = stack[stackpointer];
  216.  
  217. routsum += sir[0];
  218. goutsum += sir[1];
  219. boutsum += sir[2];
  220.  
  221. rinsum -= sir[0];
  222. ginsum -= sir[1];
  223. binsum -= sir[2];
  224.  
  225. yi += w;
  226. }
  227. }
  228.  
  229. Log.e("pix", w + " " + h + " " + pix.length);
  230. bitmap.setPixels(pix, 0, w, 0, 0, w, h);
  231. return (bitmap);
  232. }
  233.  
  234. }

5.當使用前4步的時候,會發現並不能達到本身想要的特別深刻的模糊。那麼咱們就須要回到需求上,既然是深度模糊,那麼在截屏壓縮的時候就不須要在乎其獲得的圖片分辨率的大小了,那麼能夠先獲取長寬,而後將其變小,生成新的Bitmap。圖片

 
  1. // 將去掉標題欄的Bitmap再次失真,
  2. screenshotBitmap = Bitmap.createScaledBitmap(screenshotBitmap,
  3. screenshotBitmap.getWidth() / scaleRatio,
  4. screenshotBitmap.getHeight() / scaleRatio, false);

我在這裏把其處理放在去掉標題欄以後。scaleRatio值越大,模糊程度越高。ip

相關文章
相關標籤/搜索