Move SSD bitmap extraction to typed Kotlin

ober

996853762dee3c84547948c35649467443049d49

diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index c57896b..58b0457 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -6060,6 +6060,65 @@
        "    }"
        "}"
        ))
+    (typed-kotlin-file "com/sfb/ssdreview/AndroidBitmap.kt"
+      (kotlin-imports (android graphics Bitmap))
+      (typed-library (com sfb ssdreview)
+        (export bitmapPixelWidth bitmapPixelHeight bitmapHasPixels
+                bitmapPixels bitmapWindowPixels bitmapToRgba)
+        (type Bitmap)
+        (type Int32)
+        (type IntArray)
+        (type Bytes)
+        (extern (bitmapWidth (bitmap : Bitmap)) : Int32
+          (kotlin-member-get width))
+        (extern (bitmapHeight (bitmap : Bitmap)) : Int32
+          (kotlin-member-get height))
+        (extern (bitmapGetPixels (bitmap : Bitmap)
+                                 (pixels : IntArray)
+                                 (offset : Int32)
+                                 (stride : Int32)
+                                 (x : Int32)
+                                 (y : Int32)
+                                 (width : Int32)
+                                 (height : Int32)) : Unit
+          (kotlin-member-call getPixels))
+        (def (bitmapPixelWidth (bitmap : Bitmap)) : Int32
+          (bitmapWidth bitmap))
+        (def (bitmapPixelHeight (bitmap : Bitmap)) : Int32
+          (bitmapHeight bitmap))
+        (def (bitmapHasPixels (bitmap : Bitmap)) : Bool
+          (and (> (bitmapPixelWidth bitmap) (int32 0))
+               (> (bitmapPixelHeight bitmap) (int32 0))))
+        (def (bitmapWindowPixels (bitmap : Bitmap)
+                                 (x : Int32)
+                                 (y : Int32)
+                                 (width : Int32)
+                                 (height : Int32)) : IntArray
+          (let ((pixels
+                  (int-array-build
+                    (* width height)
+                    (index (int32 0)))))
+            (begin
+              (bitmapGetPixels
+                bitmap
+                pixels
+                (int32 0)
+                width
+                x
+                y
+                width
+                height)
+              pixels)))
+        (def (bitmapPixels (bitmap : Bitmap)) : IntArray
+          (bitmapWindowPixels
+            bitmap
+            (int32 0)
+            (int32 0)
+            (bitmapPixelWidth bitmap)
+            (bitmapPixelHeight bitmap)))
+        (def (bitmapToRgba (bitmap : Bitmap)) : Bytes
+          (pixelsToRgba (bitmapPixels bitmap)))))
+
     (typed-kotlin-file "com/sfb/ssdreview/SsdDetector.kt"
       (kotlin-imports (android graphics Bitmap))
       (typed-library (com sfb ssdreview)
@@ -6207,10 +6266,10 @@
        "    fun loadErrorMessage(): String = loadError?.message ?: \"\""
        ""
        "    fun detect(bitmap: Bitmap): NativeDetection? {"
-       "        if (!loaded || bitmap.width <= 0 || bitmap.height <= 0) return null"
+       "        if (!loaded || !bitmapHasPixels(bitmap)) return null"
        "        val rgba = bitmapToRgba(bitmap)"
        "        val jsonText = try {"
-       "            nativeDetectRgbaJson(bitmap.width, bitmap.height, rgba)"
+       "            nativeDetectRgbaJson(bitmapPixelWidth(bitmap), bitmapPixelHeight(bitmap), rgba)"
        "        } catch (error: Throwable) {"
        "            loadError = error"
        "            return null"
@@ -6223,14 +6282,6 @@
        "        return nativeDetectionFromJsonRoot(root)"
        "    }"
        ""
-       "    private fun bitmapToRgba(bitmap: Bitmap): ByteArray {"
-       "        val width = bitmap.width"
-       "        val height = bitmap.height"
-       "        val pixels = IntArray(width * height)"
-       "        bitmap.getPixels(pixels, 0, width, 0, 0, width, height)"
-       "        return pixelsToRgba(pixels)"
-       "    }"
-       ""
        "    private external fun nativeDetectRgbaJson(width: Int, height: Int, rgba: ByteArray): String"
        "}"
        ))