Extract StackBlur and split CameraScreen into smaller files
Move the ~220-line stack blur algorithm from ImageCaptureHandler into its own util/StackBlur.kt object, making it independently testable and reducing ImageCaptureHandler from 759 to 531 lines. Split CameraScreen.kt (873 lines) by extracting: - ControlPanel.kt: ModeToggle, ControlPanel, SliderControl - CaptureControls.kt: CaptureButton, LastPhotoThumbnail CameraScreen.kt is now 609 lines focused on layout and state wiring. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5b9aedd109
commit
88d04515e2
5 changed files with 579 additions and 501 deletions
|
|
@ -18,6 +18,7 @@ import no.naiv.tiltshift.effect.BlurMode
|
|||
import no.naiv.tiltshift.effect.BlurParameters
|
||||
import no.naiv.tiltshift.storage.PhotoSaver
|
||||
import no.naiv.tiltshift.storage.SaveResult
|
||||
import no.naiv.tiltshift.util.StackBlur
|
||||
import java.util.concurrent.Executor
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.math.cos
|
||||
|
|
@ -386,7 +387,7 @@ class ImageCaptureHandler(
|
|||
|
||||
scaled = Bitmap.createScaledBitmap(source, blurredWidth, blurredHeight, true)
|
||||
|
||||
blurred = stackBlur(scaled, (params.blurAmount * 25).toInt().coerceIn(1, 25))
|
||||
blurred = StackBlur.blur(scaled, (params.blurAmount * 25).toInt().coerceIn(1, 25))
|
||||
scaled.recycle()
|
||||
scaled = null
|
||||
|
||||
|
|
@ -530,230 +531,4 @@ class ImageCaptureHandler(
|
|||
return fullPixels
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast stack blur algorithm.
|
||||
*/
|
||||
private fun stackBlur(bitmap: Bitmap, radius: Int): Bitmap {
|
||||
if (radius < 1) return bitmap.copy(Bitmap.Config.ARGB_8888, 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(maxOf(w, h))
|
||||
|
||||
var divsum = (div + 1) shr 1
|
||||
divsum *= divsum
|
||||
val dv = IntArray(256 * divsum)
|
||||
for (i2 in 0 until 256 * divsum) {
|
||||
dv[i2] = (i2 / divsum)
|
||||
}
|
||||
|
||||
yi = 0
|
||||
yw = 0
|
||||
|
||||
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
|
||||
|
||||
for (y2 in 0 until h) {
|
||||
rinsum = 0
|
||||
ginsum = 0
|
||||
binsum = 0
|
||||
routsum = 0
|
||||
goutsum = 0
|
||||
boutsum = 0
|
||||
rsum = 0
|
||||
gsum = 0
|
||||
bsum = 0
|
||||
for (i2 in -radius..radius) {
|
||||
p = pix[yi + minOf(wm, maxOf(i2, 0))]
|
||||
sir = stack[i2 + radius]
|
||||
sir[0] = (p and 0xff0000) shr 16
|
||||
sir[1] = (p and 0x00ff00) shr 8
|
||||
sir[2] = (p and 0x0000ff)
|
||||
rbs = r1 - kotlin.math.abs(i2)
|
||||
rsum += sir[0] * rbs
|
||||
gsum += sir[1] * rbs
|
||||
bsum += sir[2] * rbs
|
||||
if (i2 > 0) {
|
||||
rinsum += sir[0]
|
||||
ginsum += sir[1]
|
||||
binsum += sir[2]
|
||||
} else {
|
||||
routsum += sir[0]
|
||||
goutsum += sir[1]
|
||||
boutsum += sir[2]
|
||||
}
|
||||
}
|
||||
stackpointer = radius
|
||||
|
||||
for (x2 in 0 until 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 (y2 == 0) {
|
||||
vmin[x2] = minOf(x2 + radius + 1, wm)
|
||||
}
|
||||
p = pix[yw + vmin[x2]]
|
||||
|
||||
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++
|
||||
}
|
||||
yw += w
|
||||
}
|
||||
for (x2 in 0 until w) {
|
||||
rinsum = 0
|
||||
ginsum = 0
|
||||
binsum = 0
|
||||
routsum = 0
|
||||
goutsum = 0
|
||||
boutsum = 0
|
||||
rsum = 0
|
||||
gsum = 0
|
||||
bsum = 0
|
||||
yp = -radius * w
|
||||
for (i2 in -radius..radius) {
|
||||
yi = maxOf(0, yp) + x2
|
||||
|
||||
sir = stack[i2 + radius]
|
||||
|
||||
sir[0] = r[yi]
|
||||
sir[1] = g[yi]
|
||||
sir[2] = b[yi]
|
||||
|
||||
rbs = r1 - kotlin.math.abs(i2)
|
||||
|
||||
rsum += r[yi] * rbs
|
||||
gsum += g[yi] * rbs
|
||||
bsum += b[yi] * rbs
|
||||
|
||||
if (i2 > 0) {
|
||||
rinsum += sir[0]
|
||||
ginsum += sir[1]
|
||||
binsum += sir[2]
|
||||
} else {
|
||||
routsum += sir[0]
|
||||
goutsum += sir[1]
|
||||
boutsum += sir[2]
|
||||
}
|
||||
|
||||
if (i2 < hm) {
|
||||
yp += w
|
||||
}
|
||||
}
|
||||
yi = x2
|
||||
stackpointer = radius
|
||||
for (y2 in 0 until h) {
|
||||
pix[yi] = (0xff000000.toInt() 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 (x2 == 0) {
|
||||
vmin[y2] = minOf(y2 + r1, hm) * w
|
||||
}
|
||||
p = x2 + vmin[y2]
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
val result = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
|
||||
result.setPixels(pix, 0, w, 0, 0, w, h)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue