Skip to content

Latest commit

 

History

History
164 lines (146 loc) · 5.65 KB

File metadata and controls

164 lines (146 loc) · 5.65 KB

Blur-It

Blur-It is an Android project demonstrating an efficient method for background blurring, particularly challenging on Android 11 or earlier devices.
The project includes a movable blur view that traverses the constraint layout , along with a seek bar to dynamically adjust the blur radius. Additionally, it addresses and seeks to ignore any UI glitches for a smoother user experience. 🙏🏻

Here is the sample Images


BlurIt Demo BlurIt Demo

Gif is pixellated

Download BlurIt APK


Special credits to https://github.com/Dimezis/

Thank You 🙏🏻

Update:


Here is the code for Composable equalent

package com.example.facedetection.ui.componants

import android.content.Context import android.graphics.Bitmap import android.graphics.Rect import android.renderscript.Allocation import android.renderscript.Element import android.renderscript.RenderScript import android.renderscript.ScriptIntrinsicBlur import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.gestures.detectDragGestures import androidx.compose.foundation.layout.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp import androidx.core.view.drawToBitmap import com.example.facedetection.R import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import kotlin.math.roundToInt

@Composable fun DraggableBlurOverlay(blurRadius: Float = 16f) { val context = LocalContext.current val view = LocalView.current // your ComposeView

// 1️⃣ Hold the “clean” full‐screen bitmap, but *only* after layout
var originalBmp by remember { mutableStateOf<Bitmap?>(null) }
DisposableEffect(view) {
    // post runs after measure+layout
    view.post {
        if (originalBmp == null && view.width > 0 && view.height > 0) {
            originalBmp = view.drawToBitmap()
        }
    }
    onDispose { /* nothing to clean up */ }
}

// 2️⃣ Drag + blur state
var dragOffset by remember { mutableStateOf(Offset.Zero) }
var targetRect by remember { mutableStateOf<Rect?>(null) }
var blurBmp    by remember { mutableStateOf<ImageBitmap?>(null) }

Box(Modifier.fillMaxSize()) {
    // background
    Box(
        Modifier
            .size(900.dp)
            .background(Color(0xFF3366FF))
    ) {
        Image(painterResource(R.drawable.abc), contentDescription = null)
    }

    // draggable window
    Box(
        Modifier
            .offset { IntOffset(dragOffset.x.roundToInt(), dragOffset.y.roundToInt()) }
            .size(300.dp)
            .pointerInput(Unit) {
                detectDragGestures { change, dragAmount ->
                    change.consume()
                    dragOffset += dragAmount
                }
            }
            .onGloballyPositioned { coords ->
                coords.localToWindow(Offset.Zero).let { pos ->
                    targetRect = Rect(
                        pos.x.toInt(),
                        pos.y.toInt(),
                        (pos.x + coords.size.width).toInt(),
                        (pos.y + coords.size.height).toInt()
                    )
                }
            }
    ) {
        blurBmp?.let { bmp ->
            Image(bmp, contentDescription = null, Modifier.fillMaxSize())
        } ?: Box(Modifier.matchParentSize().background(Color.Gray.copy(alpha = .3f)))
    }
}

// 3️⃣ When we have both the original & a new drag rect, re‐crop & blur
targetRect?.let { rect ->
    LaunchedEffect(rect, originalBmp) {
        val full = originalBmp ?: return@LaunchedEffect
        blurBmp = null
        val cropped = withContext(Dispatchers.Default) {
            // clamp in-bounds
            val left = rect.left.coerceIn(0, full.width)
            val top  = rect.top.coerceIn(0, full.height)
            val w    = rect.width().coerceAtMost(full.width - left)
            val h    = rect.height().coerceAtMost(full.height - top)
            Bitmap.createBitmap(full, left, top, w, h)
                .let { blurBitmap(context, it, blurRadius) }
        }
        blurBmp = cropped.asImageBitmap()
    }
}

}

// same as before fun blurBitmap( context: Context, input: Bitmap, radius: Float ): Bitmap { val r = radius.coerceIn(0f, 25f) val output = Bitmap.createBitmap(input.width, input.height, Bitmap.Config.ARGB_8888) val rs = RenderScript.create(context) val inAlloc = Allocation.createFromBitmap(rs, input) val outAlloc = Allocation.createTyped(rs, inAlloc.type) val script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)) script.setRadius(r) script.setInput(inAlloc) script.forEach(outAlloc) outAlloc.copyTo(output) rs.destroy() return output }

THANKS AGAIN