Skip to content

Commit ec6cae9

Browse files
committed
Update
1 parent a45a877 commit ec6cae9

2 files changed

Lines changed: 75 additions & 102 deletions

File tree

-8.06 KB
Binary file not shown.

app/src/main/java/com/omarea/common/ui/FastBlurUtility.java

Lines changed: 75 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -7,54 +7,81 @@
77
import android.graphics.ColorMatrixColorFilter;
88
import android.graphics.Paint;
99
import android.graphics.Rect;
10+
import android.os.Handler;
11+
import android.os.Looper;
1012
import android.view.View;
1113

14+
import java.util.concurrent.ExecutorService;
15+
import java.util.concurrent.Executors;
16+
1217
public class FastBlurUtility {
1318

14-
// Tỉ lệ thu nhỏ ảnh để xử lý nhanh (1/10 giúp giảm 100 lần số pixel cần tính toán)
1519
private static final float SCALE_FACTOR = 0.10f;
1620
private static final int BLUR_RADIUS = 8;
21+
22+
// Executor để xử lý các tác vụ nặng ngoài UI Thread
23+
private static final ExecutorService executor = Executors.newSingleThreadExecutor();
24+
private static final Handler mainHandler = new Handler(Looper.getMainLooper());
1725

18-
/**
19-
* Chụp màn hình và làm mờ (Dùng làm phương án dự phòng khi không lấy được Wallpaper)
20-
*/
21-
public static Bitmap getBlurBackgroundDrawer(Activity activity) {
22-
Bitmap bmp = takeScreenShot(activity);
23-
return startBlurBackground(bmp);
26+
public interface BlurCallback {
27+
void onBlurCompleted(Bitmap bitmap);
2428
}
2529

2630
/**
27-
* Quy trình xử lý: Thu nhỏ -> Làm mờ -> Phóng to & Nhuộm tối (Dim)
28-
* Đảm bảo mượt mà từ SDK 23 trở lên.
31+
* Phương thức chính: Chụp và làm mờ không gây lag UI
2932
*/
30-
public static Bitmap startBlurBackground(Bitmap bkg) {
33+
public static void getBlurBackgroundAsync(Activity activity, BlurCallback callback) {
34+
// 1. Chụp màn hình phải thực hiện trên UI Thread
35+
Bitmap screenshot = takeScreenShot(activity);
36+
37+
if (screenshot == null) {
38+
callback.onBlurCompleted(null);
39+
return;
40+
}
41+
42+
// 2. Đẩy việc xử lý làm mờ vào Background Thread
43+
executor.execute(() -> {
44+
Bitmap blurred = startBlurProcess(screenshot);
45+
46+
// 3. Trả kết quả về Main Thread qua Callback
47+
mainHandler.post(() -> callback.onBlurCompleted(blurred));
48+
});
49+
}
50+
51+
private static Bitmap startBlurProcess(Bitmap bkg) {
3152
if (bkg == null || bkg.isRecycled()) return null;
3253

33-
// 1. Tính toán kích thước thu nhỏ
34-
int width = Math.round(bkg.getWidth() * SCALE_FACTOR);
35-
int height = Math.round(bkg.getHeight() * SCALE_FACTOR);
54+
int originWidth = bkg.getWidth();
55+
int originHeight = bkg.getHeight();
56+
57+
// Tính toán kích thước thu nhỏ
58+
int width = Math.round(originWidth * SCALE_FACTOR);
59+
int height = Math.round(originHeight * SCALE_FACTOR);
3660

3761
if (width <= 0 || height <= 0) return bkg;
3862

39-
// 2. Thu nhỏ ảnh (Sử dụng bộ lọc Bilinear để ảnh mượt hơn)
63+
// Thu nhỏ ảnh
4064
Bitmap smallBitmap = Bitmap.createScaledBitmap(bkg, width, height, true);
65+
66+
// Giải phóng ảnh gốc ngay để tiết kiệm RAM
67+
if (bkg != smallBitmap) {
68+
bkg.recycle();
69+
}
4170

42-
// 3. Làm mờ bằng thuật toán StackBlur (CPU-based, cực kỳ ổn định)
71+
// Làm mờ bằng thuật toán StackBlur
4372
Bitmap blurred = fastBlur(smallBitmap, BLUR_RADIUS);
4473

45-
// 4. Phóng to về kích thước gốc áp dụng bộ lọc màu tối
46-
return scaleAndDim(blurred, bkg.getWidth(), bkg.getHeight());
74+
// Phóng to và làm tối
75+
return scaleAndDim(blurred, originWidth, originHeight);
4776
}
4877

49-
/**
50-
* Chụp ảnh màn hình an toàn trên SDK 23+
51-
*/
5278
private static Bitmap takeScreenShot(Activity activity) {
5379
try {
5480
View view = activity.getWindow().getDecorView();
5581
if (view.getWidth() <= 0 || view.getHeight() <= 0) return null;
5682

57-
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
83+
// Dùng RGB_565 để tiết kiệm 50% bộ nhớ so với ARGB_8888 (phù hợp SDK 23+)
84+
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.RGB_565);
5885
Canvas canvas = new Canvas(bitmap);
5986
view.draw(canvas);
6087
return bitmap;
@@ -63,46 +90,34 @@ private static Bitmap takeScreenShot(Activity activity) {
6390
}
6491
}
6592

66-
/**
67-
* Phóng to ảnh và áp dụng ColorMatrix để làm tối nền (Dim)
68-
*/
6993
private static Bitmap scaleAndDim(Bitmap bitmap, int targetW, int targetH) {
70-
Bitmap output = Bitmap.createBitmap(targetW, targetH, Bitmap.Config.ARGB_8888);
94+
Bitmap output = Bitmap.createBitmap(targetW, targetH, Bitmap.Config.RGB_565);
7195
Canvas canvas = new Canvas(output);
7296

73-
// Paint với bộ lọc chống răng cưa và lọc bitmap khi scale
7497
Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG);
7598

76-
// Tạo bộ lọc màu để giảm độ sáng (contrast 0.85f ~ giảm 15% độ sáng)
99+
// Giảm độ sáng 20%
77100
ColorMatrix cm = new ColorMatrix();
78101
float contrast = 0.8f;
79-
cm.set(new float[]{
80-
contrast, 0, 0, 0, 0,
81-
0, contrast, 0, 0, 0,
82-
0, 0, contrast, 0, 0,
83-
0, 0, 0, 1, 0});
102+
cm.setScale(contrast, contrast, contrast, 1.0f);
84103
paint.setColorFilter(new ColorMatrixColorFilter(cm));
85104

86-
// Vẽ ảnh từ vùng nguồn (nhỏ) ra vùng đích (toàn màn hình)
87105
Rect src = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
88106
Rect dst = new Rect(0, 0, targetW, targetH);
89107
canvas.drawBitmap(bitmap, src, dst, paint);
90108

91-
// Giải phóng bitmap tạm sau khi đã vẽ xong
92-
if (bitmap != null && !bitmap.isRecycled()) {
109+
if (!bitmap.isRecycled()) {
93110
bitmap.recycle();
94111
}
95112

96113
return output;
97114
}
98115

99116
/**
100-
* Thuật toán StackBlur (Multi-pass box blur) - Tối ưu cho hiệu năng CPU
101-
* Hỗ trợ hoàn hảo cho các thiết bị từ cũ đến mới.
117+
* Thuật toán StackBlur tối ưu hóa
102118
*/
103119
private static Bitmap fastBlur(Bitmap sentBitmap, int radius) {
104120
Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
105-
106121
if (radius < 1) return null;
107122

108123
int w = bitmap.getWidth();
@@ -151,48 +166,27 @@ private static Bitmap fastBlur(Bitmap sentBitmap, int radius) {
151166
gsum += sir[1] * rbs;
152167
bsum += sir[2] * rbs;
153168
if (i > 0) {
154-
rinsum += sir[0];
155-
ginsum += sir[1];
156-
binsum += sir[2];
169+
rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2];
157170
} else {
158-
routsum += sir[0];
159-
goutsum += sir[1];
160-
boutsum += sir[2];
171+
routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2];
161172
}
162173
}
163174
stackpointer = radius;
164-
165175
for (x = 0; x < w; x++) {
166-
r[yi] = dv[rsum];
167-
g[yi] = dv[gsum];
168-
b[yi] = dv[bsum];
169-
rsum -= routsum;
170-
gsum -= goutsum;
171-
bsum -= boutsum;
176+
r[yi] = dv[rsum]; g[yi] = dv[gsum]; b[yi] = dv[bsum];
177+
rsum -= routsum; gsum -= goutsum; bsum -= boutsum;
172178
stackstart = stackpointer - radius + div;
173179
sir = stack[stackstart % div];
174-
routsum -= sir[0];
175-
goutsum -= sir[1];
176-
boutsum -= sir[2];
180+
routsum -= sir[0]; goutsum -= sir[1]; boutsum -= sir[2];
177181
if (y == 0) vmin[x] = Math.min(x + radius + 1, wm);
178182
p = pix[yw + vmin[x]];
179-
sir[0] = (p & 0xff0000) >> 16;
180-
sir[1] = (p & 0x00ff00) >> 8;
181-
sir[2] = (p & 0x0000ff);
182-
rinsum += sir[0];
183-
ginsum += sir[1];
184-
binsum += sir[2];
185-
rsum += rinsum;
186-
gsum += ginsum;
187-
bsum += binsum;
183+
sir[0] = (p & 0xff0000) >> 16; sir[1] = (p & 0x00ff00) >> 8; sir[2] = (p & 0x0000ff);
184+
rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2];
185+
rsum += rinsum; gsum += ginsum; bsum += binsum;
188186
stackpointer = (stackpointer + 1) % div;
189187
sir = stack[(stackpointer) % div];
190-
routsum += sir[0];
191-
goutsum += sir[1];
192-
boutsum += sir[2];
193-
rinsum -= sir[0];
194-
ginsum -= sir[1];
195-
binsum -= sir[2];
188+
routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2];
189+
rinsum -= sir[0]; ginsum -= sir[1]; binsum -= sir[2];
196190
yi++;
197191
}
198192
yw += w;
@@ -203,59 +197,38 @@ private static Bitmap fastBlur(Bitmap sentBitmap, int radius) {
203197
for (i = -radius; i <= radius; i++) {
204198
yi = Math.max(0, yp) + x;
205199
sir = stack[i + radius];
206-
sir[0] = r[yi];
207-
sir[1] = g[yi];
208-
sir[2] = b[yi];
200+
sir[0] = r[yi]; sir[1] = g[yi]; sir[2] = b[yi];
209201
rbs = r1 - Math.abs(i);
210-
rsum += r[yi] * rbs;
211-
gsum += g[yi] * rbs;
212-
bsum += b[yi] * rbs;
202+
rsum += r[yi] * rbs; gsum += g[yi] * rbs; bsum += b[yi] * rbs;
213203
if (i > 0) {
214-
rinsum += sir[0];
215-
ginsum += sir[1];
216-
binsum += sir[2];
204+
rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2];
217205
} else {
218-
routsum += sir[0];
219-
goutsum += sir[1];
220-
boutsum += sir[2];
206+
routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2];
221207
}
222208
if (i < hm) yp += w;
223209
}
224210
yi = x;
225211
stackpointer = radius;
226212
for (y = 0; y < h; y++) {
227213
pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum];
228-
rsum -= routsum;
229-
gsum -= goutsum;
230-
bsum -= boutsum;
214+
rsum -= routsum; gsum -= goutsum; bsum -= boutsum;
231215
stackstart = stackpointer - radius + div;
232216
sir = stack[stackstart % div];
233-
routsum -= sir[0];
234-
goutsum -= sir[1];
235-
boutsum -= sir[2];
217+
routsum -= sir[0]; goutsum -= sir[1]; boutsum -= sir[2];
236218
if (x == 0) vmin[y] = Math.min(y + r1, hm) * w;
237219
p = x + vmin[y];
238-
sir[0] = r[p];
239-
sir[1] = g[p];
240-
sir[2] = b[p];
241-
rinsum += sir[0];
242-
ginsum += sir[1];
243-
binsum += sir[2];
244-
rsum += rinsum;
245-
gsum += ginsum;
246-
bsum += binsum;
220+
sir[0] = r[p]; sir[1] = g[p]; sir[2] = b[p];
221+
rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2];
222+
rsum += rinsum; gsum += ginsum; bsum += binsum;
247223
stackpointer = (stackpointer + 1) % div;
248224
sir = stack[stackpointer];
249-
routsum += sir[0];
250-
goutsum += sir[1];
251-
boutsum += sir[2];
252-
rinsum -= sir[0];
253-
ginsum -= sir[1];
254-
binsum -= sir[2];
225+
routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2];
226+
rinsum -= sir[0]; ginsum -= sir[1]; binsum -= sir[2];
255227
yi += w;
256228
}
257229
}
258230
bitmap.setPixels(pix, 0, w, 0, 0, w, h);
231+
sentBitmap.recycle(); // Giải phóng bitmap cũ sau khi copy
259232
return bitmap;
260233
}
261234
}

0 commit comments

Comments
 (0)