diff app/src/main/java/com/bartsent/simpleresizer/lib/Resizer.kt @ 9:884092efe31a concur

Gets gratuitously killed. WTF?
author David Barts <n5jrn@me.com>
date Wed, 17 Feb 2021 13:20:25 -0800
parents 9374d044a132
children
line wrap: on
line diff
--- a/app/src/main/java/com/bartsent/simpleresizer/lib/Resizer.kt	Wed Feb 17 07:24:26 2021 -0800
+++ b/app/src/main/java/com/bartsent/simpleresizer/lib/Resizer.kt	Wed Feb 17 13:20:25 2021 -0800
@@ -2,6 +2,7 @@
 
 import android.graphics.Bitmap
 import android.graphics.Color
+import android.util.Log
 import java.io.Closeable
 import kotlin.math.ceil
 import kotlin.math.floor
@@ -10,21 +11,28 @@
     private val NWORKERS = maxOf(1, Runtime.getRuntime().availableProcessors() - 2)
     private val workers = Channel<Worker>(NWORKERS)
     init {
+        Log.d("Resizer", "workers channel is ${workers.hashCode()}")
+        Log.d("Resizer", "writing workers…")
         for (i in 0 until NWORKERS)
-            workers.write(Worker(workers))
+            workers.write(Worker(workers).apply { start() })
+        Log.d("Resizer", "writing done")
     }
 
     override fun close() {
+        Log.d("Resizer", "closing, stack trace follows…", Exception("dummy exception"))
         for (i in 0 until NWORKERS)
             workers.read().run {
                 interrupt()
                 join()
             }
+        Log.d("Resizer", "closing done")
     }
 
     private fun drain(): Unit {
+        Log.d("Resizer", "draining workers…")
         val saved = Array<Worker>(NWORKERS) { workers.read() }
         saved.forEach { workers.write(it) }
+        Log.d("Resizer", "draining done")
     }
 
     private data class IndexWeight(var index: Int, var weight: Double)
@@ -61,80 +69,88 @@
         return out
     }
 
-    private data class WorkUnit(val target: Bitmap, val x: Int, val y: Int,
-                                val weights: Array<IndexWeight>, val scanLine: IntArray)
-
     private class Worker(private val workers: Channel<Worker>): Thread() {
-        private val _input = Channel<WorkUnit>(1)
+        private val _input = Channel<() -> Unit>(1)
 
         override fun run() {
             while (true) {
-                val data = _input.read()
-                if (isInterrupted)
+                val (block: () -> Unit, interrupted: Boolean) = try {
+                    Pair(_input.read(), isInterrupted)
+                } catch (e: InterruptedException) {
+                    Pair({}, true)
+                }
+                if (interrupted)
                     return
-                resample(data.target, data.x, data.y, data.weights, data.scanLine)
+                block()
                 workers.write(this)
             }
         }
 
-        fun send(data: WorkUnit) {
-            _input.write(data)
-        }
-
-        private fun clamp(v: Double): Int = minOf(255, maxOf(0, (v + 0.5).toInt()))
-
-        private fun resample(target: Bitmap, x: Int, y: Int, weights: Array<IndexWeight>, scanLine: IntArray): Unit {
-            var r = 0.0; var g = 0.0; var b = 0.0; var a = 0.0
-            weights.forEach {
-                val c = scanLine[it.index]
-                val aw = Color.alpha(c).toDouble() * it.weight
-                r += Color.red(c).toDouble() * aw
-                g += Color.green(c).toDouble() * aw
-                b += Color.blue(c).toDouble() * aw
-                a += aw
-            }
-            if (a == 0.0)
-                return
-            val argb = Color.argb(clamp(a), clamp(r/a), clamp(g/a), clamp(b/a))
-            synchronized(target) {
-                target.setPixel(x, y, argb)
-            }
+        fun send(block: () -> Unit) {
+            _input.write(block)
         }
     }
 
+    private fun clamp(v: Double): Int = minOf(255, maxOf(0, (v + 0.5).toInt()))
+
+    fun parallel(block: () -> Unit) = workers.read().send(block)
+
     private fun resample(target: Bitmap, x: Int, y: Int, weights: Array<IndexWeight>, scanLine: IntArray): Unit {
-        workers.read().send(WorkUnit(target, x, y, weights, scanLine))
+        // Log.d("Resizer", "resample: x=$x, y=$y")
+        var r = 0.0; var g = 0.0; var b = 0.0; var a = 0.0
+        weights.forEach {
+            val c = scanLine[it.index]
+            val aw = Color.alpha(c).toDouble() * it.weight
+            r += Color.red(c).toDouble() * aw
+            g += Color.green(c).toDouble() * aw
+            b += Color.blue(c).toDouble() * aw
+            a += aw
+        }
+        if (a == 0.0) {
+            Log.d("Resizer", "resample: a=0.0, done")
+            return
+        }
+        val argb = Color.argb(clamp(a), clamp(r/a), clamp(g/a), clamp(b/a))
+        // Log.d("Resizer", "setting pixel…")
+        synchronized(target) {
+            target.setPixel(x, y, argb)
+        }
+        // Log.d("Resizer", "resample: a=$a, done")
     }
 
     fun horizontal(image: Bitmap, newWidth: Int, kernel: ScalingKernel): Bitmap {
+        Log.d("Resizer", "horizontal…")
         val dst = Bitmap.createBitmap(newWidth, image.height, Bitmap.Config.ARGB_8888)
         val weights = precomputeWeights(newWidth, image.width, kernel)
-        val scanLine = IntArray(image.width)
         for (y in 0 until image.height) {
-            for (x in 0 until image.width) {
-                scanLine[x] = image.getPixel(x, y)
-            }
-            for (x in weights.indices) {
-                resample(dst, x, y, weights[x], scanLine)
+            val scanLine = IntArray(image.width) { image.getPixel(it, y) }
+            parallel {
+                Log.d("Resizer", "horizontal: y=$y")
+                for (x in weights.indices) {
+                    resample(dst, x, y, weights[x], scanLine)
+                }
             }
         }
         drain()
+        Log.d("Resizer", "horizontal done")
         return dst
     }
 
     fun vertical(image: Bitmap, newHeight: Int, kernel: ScalingKernel): Bitmap {
+        Log.d("Resizer", "vertical…")
         val dst = Bitmap.createBitmap(image.width, newHeight, Bitmap.Config.ARGB_8888)
         val weights = precomputeWeights(newHeight, image.height, kernel)
-        val scanLine = IntArray(image.height)
         for (x in 0 until image.width) {
-            for (y in 0 until image.height) {
-                scanLine[y] = image.getPixel(x, y)
-            }
-            for (y in weights.indices) {
-                resample(dst, x, y, weights[y], scanLine)
+            val scanLine = IntArray(image.height) { image.getPixel(x, it) }
+            parallel {
+                Log.d("Resizer", "vertical: x=$x")
+                for (y in weights.indices) {
+                    resample(dst, x, y, weights[y], scanLine)
+                }
             }
         }
         drain()
+        Log.d("Resizer", "vertical done")
         return dst
     }
 }
\ No newline at end of file