Skip to content

Commit 32f2330

Browse files
committed
Update
1 parent fc19458 commit 32f2330

1 file changed

Lines changed: 37 additions & 158 deletions

File tree

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

Lines changed: 37 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,16 @@
88
import android.content.Context;
99

1010
public final class BlurEngine {
11-
// --- Các thành phần cũ để giữ tương thích hệ thống ---
1211
public static BlurController controller = new BlurController();
13-
public static volatile Bitmap blurBitmap;
12+
public static volatile Bitmap blurBitmap;
1413
public static boolean isPaused = false;
15-
public static float DEFAULT_CORNER_RADIUS = 30.0f;
1614

17-
// --- Cấu hình cho tính năng Blur thời gian thực (Lựa chọn 2) ---
18-
private static final float SCALE_FACTOR = 0.15f;
19-
private static final int BLUR_RADIUS = 8;
20-
15+
public static float DEFAULT_CORNER_RADIUS = 30.0f;
2116
public float cornerRadius = DEFAULT_CORNER_RADIUS;
2217

2318
private View targetView;
2419
private int[] location = new int[2];
20+
private int[] parentLocation = new int[2];
2521
private Rect srcRect = new Rect();
2622
private Bitmap cachedBitmap;
2723
private Canvas cachedCanvas;
@@ -42,59 +38,47 @@ public void setup() {
4238
targetView.getViewTreeObserver().addOnPreDrawListener(new BlurPreDrawListener(this, targetView));
4339
}
4440

45-
/**
46-
* Logic mới: Chụp nội dung phía sau trực tiếp để không bị mất blur khi cuộn dài
47-
*/
4841
public Bitmap getUpdatedBlurBitmap() {
49-
if (isPaused || targetView.getWidth() <= 0 || targetView.getHeight() <= 0) {
42+
if (isPaused || blurBitmap == null || blurBitmap.isRecycled() ||
43+
targetView.getWidth() <= 0 || targetView.getHeight() <= 0) {
5044
return null;
5145
}
5246

47+
// Lấy RootView thực sự (thường là DecorView của Window)
5348
View rootView = targetView.getRootView();
5449
if (rootView == null) return null;
55-
56-
// 1. Tính toán kích thước thu nhỏ để tối ưu hiệu suất
57-
int w = Math.round(targetView.getWidth() * SCALE_FACTOR);
58-
int h = Math.round(targetView.getHeight() * SCALE_FACTOR);
59-
60-
if (w <= 0 || h <= 0) return null;
61-
62-
try {
63-
// 2. Quản lý bộ nhớ đệm Bitmap
64-
if (cachedBitmap == null || cachedBitmap.getWidth() != w || cachedBitmap.getHeight() != h) {
65-
if (cachedBitmap != null) cachedBitmap.recycle();
66-
cachedBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
67-
cachedCanvas = new Canvas(cachedBitmap);
68-
}
69-
70-
// 3. Xác định tọa độ thực tế trên màn hình
71-
targetView.getLocationOnScreen(location);
72-
73-
// 4. CHỤP NỘI DUNG NỀN (Lựa chọn 2)
74-
cachedCanvas.save();
75-
cachedCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
76-
77-
// Di chuyển và scale canvas để "soi" đúng phần diện tích phía sau targetView
78-
cachedCanvas.scale(SCALE_FACTOR, SCALE_FACTOR);
79-
cachedCanvas.translate(-location[0], -location[1]);
50+
targetView.getLocationOnScreen(location);
51+
float scaleX = (float) blurBitmap.getWidth() / rootView.getWidth();
52+
float scaleY = (float) blurBitmap.getHeight() / rootView.getHeight();
53+
54+
int w = (int) (targetView.getWidth() * scaleX);
55+
int h = (int) (targetView.getHeight() * scaleY);
56+
int x = (int) (location[0] * scaleX);
57+
int y = (int) (location[1] * scaleY);
58+
59+
// Chống tràn biên Bitmap
60+
x = Math.max(0, Math.min(x, blurBitmap.getWidth() - w));
61+
y = Math.max(0, Math.min(y, blurBitmap.getHeight() - h));
62+
63+
if (w > 0 && h > 0) {
64+
try {
65+
if (cachedBitmap == null || cachedBitmap.getWidth() != w || cachedBitmap.getHeight() != h) {
66+
if (cachedBitmap != null) cachedBitmap.recycle();
67+
cachedBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
68+
cachedCanvas = new Canvas(cachedBitmap);
69+
}
8070

81-
// Tạm ẩn chính nó để tránh vòng lặp hiển thị (Recursive drawing)
82-
targetView.setVisibility(View.INVISIBLE);
83-
rootView.draw(cachedCanvas);
84-
targetView.setVisibility(View.VISIBLE);
85-
86-
cachedCanvas.restore();
87-
88-
// 5. Làm mờ trực tiếp trên ảnh đã thu nhỏ
89-
fastBlur(cachedBitmap, BLUR_RADIUS);
90-
91-
// 6. Phủ màu Tint theo theme (Dark/Light)
92-
cachedCanvas.drawColor(getBlurTintColor());
93-
94-
return cachedBitmap;
95-
} catch (Exception e) {
96-
return null;
71+
srcRect.set(x, y, x + w, y + h);
72+
cachedCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
73+
74+
cachedCanvas.drawBitmap(blurBitmap, srcRect, new Rect(0, 0, w, h), null);
75+
cachedCanvas.drawColor(getBlurTintColor());
76+
return cachedBitmap;
77+
} catch (Exception e) {
78+
return null;
79+
}
9780
}
81+
return null;
9882
}
9983

10084
private int getBlurTintColor() {
@@ -107,119 +91,14 @@ public static Paint getStrokePaint(Context context) {
10791
if (strokePaint == null) {
10892
strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
10993
strokePaint.setStyle(Paint.Style.STROKE);
110-
strokePaint.setStrokeWidth(3.0f);
94+
strokePaint.setStrokeWidth(3.0f);
11195
}
11296
int colorRes = ThemeModeState.isDarkMode() ? R.color.colorPirmLight : R.color.colorPirmDark;
11397
int color = ContextCompat.getColor(context, colorRes);
11498
if (strokePaint.getColor() != color) strokePaint.setColor(color);
11599
return strokePaint;
116100
}
117101

118-
/**
119-
* Thuật toán StackBlur tích hợp (Dùng xử lý ảnh nhỏ cực nhanh)
120-
*/
121-
private void fastBlur(Bitmap bitmap, int radius) {
122-
if (radius < 1) return;
123-
int w = bitmap.getWidth();
124-
int h = bitmap.getHeight();
125-
int[] pix = new int[w * h];
126-
bitmap.getPixels(pix, 0, w, 0, 0, w, h);
127-
128-
int wm = w - 1;
129-
int hm = h - 1;
130-
int wh = w * h;
131-
int div = radius + radius + 1;
132-
133-
int[] r = new int[wh];
134-
int[] g = new int[wh];
135-
int[] b = new int[wh];
136-
int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
137-
int[] vmin = new int[Math.max(w, h)];
138-
139-
int divsum = (div + 1) >> 1;
140-
divsum *= divsum;
141-
int[] dv = new int[256 * divsum];
142-
for (i = 0; i < 256 * divsum; i++) dv[i] = (i / divsum);
143-
144-
yw = yi = 0;
145-
int[][] stack = new int[div][3];
146-
int stackpointer;
147-
int stackstart;
148-
int[] sir;
149-
int rbs;
150-
int r1 = radius + 1;
151-
int routsum, goutsum, boutsum;
152-
int rinsum, ginsum, binsum;
153-
154-
for (y = 0; y < h; y++) {
155-
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
156-
for (i = -radius; i <= radius; i++) {
157-
p = pix[yi + Math.min(wm, Math.max(i, 0))];
158-
sir = stack[i + radius];
159-
sir[0] = (p & 0xff0000) >> 16;
160-
sir[1] = (p & 0x00ff00) >> 8;
161-
sir[2] = (p & 0x0000ff);
162-
rbs = r1 - Math.abs(i);
163-
rsum += sir[0] * rbs; gsum += sir[1] * rbs; bsum += sir[2] * rbs;
164-
if (i > 0) { rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2]; }
165-
else { routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2]; }
166-
}
167-
stackpointer = radius;
168-
for (x = 0; x < w; x++) {
169-
r[yi] = dv[rsum]; g[yi] = dv[gsum]; b[yi] = dv[bsum];
170-
rsum -= routsum; gsum -= goutsum; bsum -= boutsum;
171-
stackstart = stackpointer - radius + div;
172-
sir = stack[stackstart % div];
173-
routsum -= sir[0]; goutsum -= sir[1]; boutsum -= sir[2];
174-
if (y == 0) vmin[x] = Math.min(x + radius + 1, wm);
175-
p = pix[yw + vmin[x]];
176-
sir[0] = (p & 0xff0000) >> 16; sir[1] = (p & 0x00ff00) >> 8; sir[2] = (p & 0x0000ff);
177-
rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2];
178-
rsum += rinsum; gsum += ginsum; bsum += binsum;
179-
stackpointer = (stackpointer + 1) % div;
180-
sir = stack[stackpointer % div];
181-
routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2];
182-
rinsum -= sir[0]; ginsum -= sir[1]; binsum -= sir[2];
183-
yi++;
184-
}
185-
yw += w;
186-
}
187-
for (x = 0; x < w; x++) {
188-
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
189-
yp = -radius * w;
190-
for (i = -radius; i <= radius; i++) {
191-
yi = Math.max(0, yp) + x;
192-
sir = stack[i + radius];
193-
sir[0] = r[yi]; sir[1] = g[yi]; sir[2] = b[yi];
194-
rbs = r1 - Math.abs(i);
195-
rsum += r[yi] * rbs; gsum += g[yi] * rbs; bsum += b[yi] * rbs;
196-
if (i > 0) { rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2]; }
197-
else { routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2]; }
198-
if (i < hm) yp += w;
199-
}
200-
yi = x;
201-
stackpointer = radius;
202-
for (y = 0; y < h; y++) {
203-
pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum];
204-
rsum -= routsum; gsum -= goutsum; bsum -= boutsum;
205-
stackstart = stackpointer - radius + div;
206-
sir = stack[stackstart % div];
207-
routsum -= sir[0]; goutsum -= sir[1]; boutsum -= sir[2];
208-
if (x == 0) vmin[y] = Math.min(y + r1, hm) * w;
209-
p = x + vmin[y];
210-
sir[0] = r[p]; sir[1] = g[p]; sir[2] = b[p];
211-
rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2];
212-
rsum += rinsum; gsum += ginsum; bsum += binsum;
213-
stackpointer = (stackpointer + 1) % div;
214-
sir = stack[stackpointer];
215-
routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2];
216-
rinsum -= sir[0]; ginsum -= sir[1]; binsum -= sir[2];
217-
yi += w;
218-
}
219-
}
220-
bitmap.setPixels(pix, 0, w, 0, 0, w, h);
221-
}
222-
223102
public void destroy() {
224103
if (cachedBitmap != null && !cachedBitmap.isRecycled()) {
225104
cachedBitmap.recycle();

0 commit comments

Comments
 (0)