mirror of
https://github.com/Myzel394/Alibi.git
synced 2025-06-18 23:05:26 +02:00
current stand
This commit is contained in:
parent
f035c40c21
commit
0dcf106a22
@ -126,4 +126,5 @@ dependencies {
|
||||
implementation 'com.maxkeppeler.sheets-compose-dialogs:input:1.2.0'
|
||||
|
||||
implementation 'io.github.ujizin:camposer:0.1.0'
|
||||
implementation "com.github.skydoves:cloudy:0.1.2"
|
||||
}
|
@ -2,26 +2,35 @@ package app.myzel394.alibi
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.ImageFormat
|
||||
import android.hardware.camera2.CameraCaptureSession
|
||||
import android.hardware.camera2.CameraCharacteristics
|
||||
import android.hardware.camera2.CameraDevice
|
||||
import android.hardware.camera2.CameraManager
|
||||
import android.media.ImageReader
|
||||
import android.net.wifi.aware.Characteristics
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import android.renderscript.Allocation
|
||||
import android.renderscript.Element
|
||||
import android.renderscript.RenderScript
|
||||
import android.renderscript.ScriptIntrinsicYuvToRGB
|
||||
import android.util.Log
|
||||
import android.util.Size
|
||||
import android.view.Surface
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.ContextCompat.getSystemService
|
||||
import app.myzel394.alibi.ui.utils.fastblur
|
||||
import app.myzel394.alibi.ui.utils.getScreenSize
|
||||
import app.myzel394.alibi.ui.utils.imageToByteBuffer
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import java.io.File
|
||||
import java.nio.ByteBuffer
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
|
||||
|
||||
class CameraHandler(
|
||||
private val manager: CameraManager,
|
||||
private val device: CameraDevice,
|
||||
@ -65,7 +74,87 @@ class CameraHandler(
|
||||
val captureRequest = device.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
|
||||
captureRequest.addTarget(surface)
|
||||
|
||||
session.setRepeatingRequest(captureRequest.build(), null, handler)
|
||||
session.setRepeatingRequest(
|
||||
captureRequest.build(),
|
||||
null,
|
||||
handler,
|
||||
)
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.P)
|
||||
suspend fun startBlurredPreview(
|
||||
surface: Surface,
|
||||
context: Context,
|
||||
size: Size? = null,
|
||||
) {
|
||||
val readerSize = size ?: getScreenSize(context).let {
|
||||
Size(
|
||||
it.width / 10,
|
||||
it.height / 10,
|
||||
)
|
||||
}
|
||||
val imageReader = ImageReader.newInstance(
|
||||
readerSize.width,
|
||||
readerSize.height,
|
||||
ImageFormat.YUV_420_888,
|
||||
IMAGE_BUFFER_SIZE,
|
||||
)
|
||||
imageReader.setOnImageAvailableListener({ reader ->
|
||||
val image = reader.acquireLatestImage() ?: return@setOnImageAvailableListener
|
||||
|
||||
val yuvBytes: ByteBuffer = imageToByteBuffer(image)
|
||||
|
||||
// Convert YUV to RGB
|
||||
val rs = RenderScript.create(context)
|
||||
|
||||
val bitmap = Bitmap.createBitmap(image.width, image.height, Bitmap.Config.ARGB_8888)
|
||||
val allocationRgb = Allocation.createFromBitmap(rs, bitmap)
|
||||
|
||||
val allocationYuv = Allocation.createSized(rs, Element.U8(rs), yuvBytes.array().size)
|
||||
allocationYuv.copyFrom(yuvBytes.array())
|
||||
|
||||
val scriptYuvToRgb = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs))
|
||||
scriptYuvToRgb.setInput(allocationYuv)
|
||||
scriptYuvToRgb.forEach(allocationRgb)
|
||||
|
||||
allocationRgb.copyTo(bitmap)
|
||||
|
||||
// Rotate bitmap
|
||||
val matrix = android.graphics.Matrix()
|
||||
matrix.postRotate(90f)
|
||||
val rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
|
||||
|
||||
val blurredBitmap = fastblur(rotatedBitmap, 1f, 2)
|
||||
|
||||
// Send blurredBitmap to `surface`
|
||||
val canvas = surface.lockCanvas(null)
|
||||
canvas.drawBitmap(blurredBitmap, 0f, 0f, null)
|
||||
surface.unlockCanvasAndPost(canvas)
|
||||
|
||||
// Destroy
|
||||
allocationRgb.destroy()
|
||||
allocationYuv.destroy()
|
||||
scriptYuvToRgb.destroy()
|
||||
rs.destroy()
|
||||
bitmap.recycle()
|
||||
rotatedBitmap.recycle()
|
||||
blurredBitmap.recycle()
|
||||
|
||||
// Release
|
||||
image.close()
|
||||
}, handler)
|
||||
|
||||
val outputs = listOf(imageReader.surface)
|
||||
val session = createCaptureSession(outputs)
|
||||
|
||||
val captureRequest = device.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
|
||||
captureRequest.addTarget(imageReader.surface)
|
||||
|
||||
session.setRepeatingRequest(
|
||||
captureRequest.build(),
|
||||
null,
|
||||
handler,
|
||||
)
|
||||
}
|
||||
|
||||
fun stopPreview() {
|
||||
@ -160,7 +249,7 @@ class CameraHandler(
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val IMAGE_BUFFER_SIZE = 3
|
||||
const val IMAGE_BUFFER_SIZE = 2
|
||||
|
||||
fun getCameraManager(
|
||||
context: Context,
|
||||
|
@ -1,29 +1,23 @@
|
||||
package app.myzel394.alibi.ui.screens
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.graphics.Point
|
||||
import android.hardware.camera2.CameraCharacteristics
|
||||
import android.hardware.display.DisplayManager
|
||||
import android.os.Build
|
||||
import android.util.Size
|
||||
import android.view.Display
|
||||
import android.view.SurfaceHolder
|
||||
import android.view.SurfaceView
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.scale
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.navigation.NavController
|
||||
import app.myzel394.alibi.CameraHandler
|
||||
@ -31,6 +25,7 @@ import app.myzel394.alibi.ui.models.AudioRecorderModel
|
||||
import app.myzel394.alibi.ui.models.VideoRecorderModel
|
||||
import app.myzel394.alibi.ui.utils.ChangeNavColors
|
||||
import app.myzel394.alibi.ui.utils.getOptimalPreviewSize
|
||||
import app.myzel394.alibi.ui.utils.rememberScreenSize
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
import java.lang.Float.max
|
||||
@ -58,64 +53,26 @@ fun RecorderScreen(
|
||||
} else {
|
||||
var scaleValue by remember { mutableFloatStateOf(1f) }
|
||||
|
||||
val screenSize = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
|
||||
val bounds = windowManager.currentWindowMetrics.bounds
|
||||
println("scaleValue: $scaleValue")
|
||||
|
||||
Size(bounds.width(), bounds.height())
|
||||
} else {
|
||||
val displayManager = context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
|
||||
val display = displayManager.getDisplay(Display.DEFAULT_DISPLAY)
|
||||
|
||||
val size = Point()
|
||||
display.getRealSize(size)
|
||||
|
||||
Size(size.x, size.y)
|
||||
}
|
||||
val screenSize = rememberScreenSize()
|
||||
val previewSize = Size(
|
||||
screenSize.width / 10,
|
||||
screenSize.height / 10,
|
||||
)
|
||||
|
||||
ChangeNavColors(color = Color.Transparent)
|
||||
|
||||
AndroidView(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.scale(scaleValue),
|
||||
.fillMaxSize(),
|
||||
factory = { context ->
|
||||
val surface = object : SurfaceView(context) {
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
val width = resolveSize(suggestedMinimumWidth, widthMeasureSpec);
|
||||
val height = resolveSize(suggestedMinimumHeight, heightMeasureSpec);
|
||||
|
||||
val supportedPreviewSizes = camera!!
|
||||
.characteristics
|
||||
.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)!!
|
||||
.getOutputSizes(SurfaceHolder::class.java)
|
||||
|
||||
// Make sure preview is in `cover` mode and not `contain` mode
|
||||
|
||||
if (supportedPreviewSizes != null) {
|
||||
val previewSize = getOptimalPreviewSize(supportedPreviewSizes, width, height);
|
||||
|
||||
val ratio = if (previewSize.height >= previewSize.width)
|
||||
(previewSize.height / previewSize.width).toFloat()
|
||||
else (previewSize.width / previewSize.height).toFloat()
|
||||
|
||||
val optimalWidth = width
|
||||
val optimalHeight = (width * ratio).toInt()
|
||||
|
||||
// Make sure the camera preview uses the whole screen
|
||||
val widthScaleRatio = optimalWidth.toFloat() / previewSize.width
|
||||
val heightScaleUpRatio = optimalHeight.toFloat() / previewSize.height
|
||||
|
||||
setMeasuredDimension(
|
||||
(previewSize.width * widthScaleRatio).toInt(),
|
||||
(previewSize.height * heightScaleUpRatio).toInt()
|
||||
)
|
||||
|
||||
scaleValue = max(
|
||||
screenSize.width / optimalWidth.toFloat(),
|
||||
screenSize.height / optimalHeight.toFloat(),
|
||||
)
|
||||
}
|
||||
setMeasuredDimension(
|
||||
screenSize.width,
|
||||
screenSize.height,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,27 +83,36 @@ fun RecorderScreen(
|
||||
)
|
||||
}
|
||||
|
||||
surfaceView.holder.addCallback(object : SurfaceHolder.Callback {
|
||||
override fun surfaceCreated(holder: SurfaceHolder) {
|
||||
scope.launch {
|
||||
camera!!.startPreview(holder.surface)
|
||||
surfaceView.holder.apply {
|
||||
addCallback(object : SurfaceHolder.Callback {
|
||||
override fun surfaceCreated(holder: SurfaceHolder) {
|
||||
scope.launch {
|
||||
camera!!.startBlurredPreview(
|
||||
holder.surface,
|
||||
context,
|
||||
previewSize,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun surfaceChanged(
|
||||
holder: SurfaceHolder,
|
||||
format: Int,
|
||||
width: Int,
|
||||
height: Int
|
||||
) {
|
||||
}
|
||||
|
||||
override fun surfaceDestroyed(holder: SurfaceHolder) {
|
||||
scope.launch {
|
||||
camera!!.stopPreview()
|
||||
override fun surfaceChanged(
|
||||
holder: SurfaceHolder,
|
||||
format: Int,
|
||||
width: Int,
|
||||
height: Int
|
||||
) {
|
||||
println("surfaceChanged")
|
||||
println("width: $width, height: $height")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
override fun surfaceDestroyed(holder: SurfaceHolder) {
|
||||
scope.launch {
|
||||
camera!!.stopPreview()
|
||||
}
|
||||
}
|
||||
})
|
||||
setFixedSize(previewSize.width, previewSize.height)
|
||||
}
|
||||
|
||||
surfaceView
|
||||
}
|
||||
@ -165,6 +131,13 @@ fun RecorderScreen(
|
||||
}) {
|
||||
Text("Take photo")
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(
|
||||
MaterialTheme.colorScheme.surface.copy(alpha = 0.5f)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1,9 +1,15 @@
|
||||
package app.myzel394.alibi.ui.utils
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.ImageFormat
|
||||
import android.graphics.Rect
|
||||
import android.hardware.camera2.CameraCharacteristics
|
||||
import android.media.Image
|
||||
import android.util.Size
|
||||
import java.nio.ByteBuffer
|
||||
import kotlin.math.abs
|
||||
|
||||
|
||||
/**
|
||||
* Computes rotation required to transform the camera sensor output orientation to the
|
||||
* device's current orientation in degrees.
|
||||
@ -55,3 +61,292 @@ fun getOptimalPreviewSize(sizes: Array<Size>, w: Int, h: Int): Size {
|
||||
}
|
||||
return optimalSize!!
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/55544614/9878135
|
||||
fun imageToByteBuffer(image: Image): ByteBuffer {
|
||||
val crop: Rect = image.cropRect
|
||||
val width: Int = crop.width()
|
||||
val height: Int = crop.height()
|
||||
val planes = image.planes
|
||||
val rowData = ByteArray(planes[0].rowStride)
|
||||
val bufferSize = width * height * ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888) / 8
|
||||
val output = ByteBuffer.allocateDirect(bufferSize)
|
||||
var channelOffset = 0
|
||||
var outputStride = 0
|
||||
for (planeIndex in 0..2) {
|
||||
if (planeIndex == 0) {
|
||||
channelOffset = 0
|
||||
outputStride = 1
|
||||
} else if (planeIndex == 1) {
|
||||
channelOffset = width * height + 1
|
||||
outputStride = 2
|
||||
} else if (planeIndex == 2) {
|
||||
channelOffset = width * height
|
||||
outputStride = 2
|
||||
}
|
||||
val buffer = planes[planeIndex].buffer
|
||||
val rowStride = planes[planeIndex].rowStride
|
||||
val pixelStride = planes[planeIndex].pixelStride
|
||||
val shift = if (planeIndex == 0) 0 else 1
|
||||
val widthShifted = width shr shift
|
||||
val heightShifted = height shr shift
|
||||
buffer.position(rowStride * (crop.top shr shift) + pixelStride * (crop.left shr shift))
|
||||
for (row in 0 until heightShifted) {
|
||||
val length: Int
|
||||
if (pixelStride == 1 && outputStride == 1) {
|
||||
length = widthShifted
|
||||
buffer[output.array(), channelOffset, length]
|
||||
channelOffset += length
|
||||
} else {
|
||||
length = (widthShifted - 1) * pixelStride + 1
|
||||
buffer[rowData, 0, length]
|
||||
for (col in 0 until widthShifted) {
|
||||
output.array()[channelOffset] = rowData[col * pixelStride]
|
||||
channelOffset += outputStride
|
||||
}
|
||||
}
|
||||
if (row < heightShifted - 1) {
|
||||
buffer.position(buffer.position() + rowStride - length)
|
||||
}
|
||||
}
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
|
||||
// The following code is from https://stackoverflow.com/a/10028267/9878135
|
||||
/**
|
||||
* Stack Blur v1.0 from
|
||||
* http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
|
||||
* Java Author: Mario Klingemann <mario at quasimondo.com>
|
||||
* http://incubator.quasimondo.com
|
||||
*
|
||||
* created Feburary 29, 2004
|
||||
* Android port : Yahel Bouaziz <yahel at kayenko.com>
|
||||
* http://www.kayenko.com
|
||||
* ported april 5th, 2012
|
||||
*
|
||||
* This is a compromise between Gaussian Blur and Box blur
|
||||
* It creates much better looking blurs than Box Blur, but is
|
||||
* 7x faster than my Gaussian Blur implementation.
|
||||
*
|
||||
* I called it Stack Blur because this describes best how this
|
||||
* filter works internally: it creates a kind of moving stack
|
||||
* of colors whilst scanning through the image. Thereby it
|
||||
* just has to add one new block of color to the right side
|
||||
* of the stack and remove the leftmost color. The remaining
|
||||
* colors on the topmost layer of the stack are either added on
|
||||
* or reduced by one, depending on if they are on the right or
|
||||
* on the left side of the stack.
|
||||
*
|
||||
* If you are using this algorithm in your code please add
|
||||
* the following line:
|
||||
* Stack Blur Algorithm by Mario Klingemann <mario></mario>@quasimondo.com>
|
||||
</yahel></mario> */
|
||||
fun fastblur(sentBitmap: Bitmap, scale: Float, radius: Int): Bitmap {
|
||||
assert(radius >= 1) { "radius must be >= 1" }
|
||||
|
||||
var sentBitmap = sentBitmap
|
||||
val width = Math.round(sentBitmap.width * scale)
|
||||
val height = Math.round(sentBitmap.height * scale)
|
||||
sentBitmap = Bitmap.createScaledBitmap(sentBitmap, width, height, false)
|
||||
val bitmap = sentBitmap.copy(sentBitmap.config, true)
|
||||
val w = bitmap.width
|
||||
val h = bitmap.height
|
||||
val pix = IntArray(w * h)
|
||||
bitmap.getPixels(pix, 0, w, 0, 0, w, h)
|
||||
val wm = w - 1
|
||||
val hm = h - 1
|
||||
val wh = w * h
|
||||
val div = radius + radius + 1
|
||||
val r = IntArray(wh)
|
||||
val g = IntArray(wh)
|
||||
val b = IntArray(wh)
|
||||
var rsum: Int
|
||||
var gsum: Int
|
||||
var bsum: Int
|
||||
var x: Int
|
||||
var y: Int
|
||||
var i: Int
|
||||
var p: Int
|
||||
var yp: Int
|
||||
var yi: Int
|
||||
var yw: Int
|
||||
val vmin = IntArray(Math.max(w, h))
|
||||
var divsum = div + 1 shr 1
|
||||
divsum *= divsum
|
||||
val dv = IntArray(256 * divsum)
|
||||
i = 0
|
||||
while (i < 256 * divsum) {
|
||||
dv[i] = i / divsum
|
||||
i++
|
||||
}
|
||||
yi = 0
|
||||
yw = yi
|
||||
val stack = Array(div) { IntArray(3) }
|
||||
var stackpointer: Int
|
||||
var stackstart: Int
|
||||
var sir: IntArray
|
||||
var rbs: Int
|
||||
val r1 = radius + 1
|
||||
var routsum: Int
|
||||
var goutsum: Int
|
||||
var boutsum: Int
|
||||
var rinsum: Int
|
||||
var ginsum: Int
|
||||
var binsum: Int
|
||||
y = 0
|
||||
while (y < h) {
|
||||
bsum = 0
|
||||
gsum = bsum
|
||||
rsum = gsum
|
||||
boutsum = rsum
|
||||
goutsum = boutsum
|
||||
routsum = goutsum
|
||||
binsum = routsum
|
||||
ginsum = binsum
|
||||
rinsum = ginsum
|
||||
i = -radius
|
||||
while (i <= radius) {
|
||||
p = pix[yi + Math.min(wm, Math.max(i, 0))]
|
||||
sir = stack[i + radius]
|
||||
sir[0] = p and 0xff0000 shr 16
|
||||
sir[1] = p and 0x00ff00 shr 8
|
||||
sir[2] = p and 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]
|
||||
}
|
||||
i++
|
||||
}
|
||||
stackpointer = radius
|
||||
x = 0
|
||||
while (x < w) {
|
||||
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 and 0xff0000 shr 16
|
||||
sir[1] = p and 0x00ff00 shr 8
|
||||
sir[2] = p and 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++
|
||||
x++
|
||||
}
|
||||
yw += w
|
||||
y++
|
||||
}
|
||||
x = 0
|
||||
while (x < w) {
|
||||
bsum = 0
|
||||
gsum = bsum
|
||||
rsum = gsum
|
||||
boutsum = rsum
|
||||
goutsum = boutsum
|
||||
routsum = goutsum
|
||||
binsum = routsum
|
||||
ginsum = binsum
|
||||
rinsum = ginsum
|
||||
yp = -radius * w
|
||||
i = -radius
|
||||
while (i <= radius) {
|
||||
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
|
||||
}
|
||||
i++
|
||||
}
|
||||
yi = x
|
||||
stackpointer = radius
|
||||
y = 0
|
||||
while (y < h) {
|
||||
|
||||
// Preserve alpha channel: ( 0xff000000 & pix[yi] )
|
||||
pix[yi] = -0x1000000 and pix[yi] or (dv[rsum] shl 16) or (dv[gsum] shl 8) or 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
|
||||
y++
|
||||
}
|
||||
x++
|
||||
}
|
||||
bitmap.setPixels(pix, 0, w, 0, 0, w, h)
|
||||
return bitmap
|
||||
}
|
||||
|
@ -1,5 +1,12 @@
|
||||
package app.myzel394.alibi.ui.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Point
|
||||
import android.hardware.display.DisplayManager
|
||||
import android.os.Build
|
||||
import android.util.Size
|
||||
import android.view.Display
|
||||
import android.view.WindowManager
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
@ -14,3 +21,28 @@ fun KeepScreenOn() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getScreenSize(context: Context): Size {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
|
||||
val bounds = windowManager.currentWindowMetrics.bounds
|
||||
|
||||
Size(bounds.width(), bounds.height())
|
||||
} else {
|
||||
val displayManager = context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
|
||||
val display = displayManager.getDisplay(Display.DEFAULT_DISPLAY)
|
||||
|
||||
val size = Point()
|
||||
display.getRealSize(size)
|
||||
|
||||
Size(size.x, size.y)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun rememberScreenSize(): Size {
|
||||
val context = LocalView.current.context
|
||||
|
||||
return getScreenSize(context)
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
plugins {
|
||||
id 'com.android.application' version '8.1.0' apply false
|
||||
id 'com.android.library' version '8.1.0' apply false
|
||||
id 'com.android.application' version '8.1.1' apply false
|
||||
id 'com.android.library' version '8.1.1' apply false
|
||||
id 'org.jetbrains.kotlin.android' version '1.9.0' apply false
|
||||
|
||||
id 'org.jetbrains.kotlin.plugin.serialization' version '1.8.21'
|
||||
|
Loading…
x
Reference in New Issue
Block a user