react-native-rectangle-doc-scanner 10.7.0 → 10.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,13 @@
1
1
  package com.reactnativerectangledocscanner
2
2
 
3
3
  import android.content.Context
4
+ import android.graphics.SurfaceTexture
4
5
  import android.util.Log
6
+ import android.util.Size
7
+ import android.view.Surface
8
+ import android.view.TextureView
5
9
  import androidx.camera.core.*
6
10
  import androidx.camera.lifecycle.ProcessCameraProvider
7
- import androidx.camera.view.PreviewView
8
11
  import androidx.core.content.ContextCompat
9
12
  import androidx.lifecycle.LifecycleOwner
10
13
  import com.google.mlkit.vision.common.InputImage
@@ -16,12 +19,12 @@ import java.util.concurrent.Executors
16
19
 
17
20
  /**
18
21
  * CameraX-based camera controller for document scanning
19
- * Handles Preview, ImageAnalysis (ML Kit + OpenCV), and ImageCapture
22
+ * Handles Preview (via TextureView), ImageAnalysis (ML Kit + OpenCV), and ImageCapture
20
23
  */
21
24
  class CameraController(
22
25
  private val context: Context,
23
26
  private val lifecycleOwner: LifecycleOwner,
24
- private val previewView: PreviewView
27
+ private val textureView: TextureView
25
28
  ) {
26
29
  private var camera: Camera? = null
27
30
  private var cameraProvider: ProcessCameraProvider? = null
@@ -93,19 +96,57 @@ class CameraController(
93
96
  CameraSelector.DEFAULT_BACK_CAMERA
94
97
  }
95
98
 
96
- // Preview UseCase
97
- Log.d(TAG, "[CAMERAX] PreviewView size: ${previewView.width}x${previewView.height}")
98
- Log.d(TAG, "[CAMERAX] PreviewView visibility: ${previewView.visibility}")
99
- Log.d(TAG, "[CAMERAX] PreviewView scaleType: ${previewView.scaleType}")
100
- Log.d(TAG, "[CAMERAX] PreviewView implementationMode: ${previewView.implementationMode}")
99
+ // Preview UseCase with TextureView
100
+ Log.d(TAG, "[CAMERAX] TextureView size: ${textureView.width}x${textureView.height}")
101
+ Log.d(TAG, "[CAMERAX] TextureView visibility: ${textureView.visibility}")
102
+ Log.d(TAG, "[CAMERAX] TextureView isAvailable: ${textureView.isAvailable}")
103
+
104
+ // Force portrait orientation (app is portrait-only)
105
+ val targetRotation = android.view.Surface.ROTATION_0
106
+ Log.d(TAG, "[CAMERAX] Setting target rotation to ROTATION_0 (portrait-only app)")
107
+
101
108
  preview = Preview.Builder()
102
- .setTargetResolution(android.util.Size(1920, 1080)) // 16:9 resolution
109
+ .setTargetRotation(targetRotation) // Force portrait
103
110
  .build()
104
111
  .also { previewUseCase ->
105
- Log.d(TAG, "[CAMERAX] Setting SurfaceProvider...")
106
-
107
- // Use PreviewView's default SurfaceProvider
108
- previewUseCase.setSurfaceProvider(ContextCompat.getMainExecutor(context), previewView.surfaceProvider)
112
+ Log.d(TAG, "[CAMERAX] Setting SurfaceProvider for TextureView...")
113
+
114
+ // Set custom SurfaceProvider for TextureView
115
+ previewUseCase.setSurfaceProvider(ContextCompat.getMainExecutor(context)) { request ->
116
+ Log.d(TAG, "[CAMERAX] Surface requested - resolution: ${request.resolution}")
117
+
118
+ val surfaceTexture = textureView.surfaceTexture
119
+ if (surfaceTexture != null) {
120
+ Log.d(TAG, "[CAMERAX] SurfaceTexture available, providing surface")
121
+ surfaceTexture.setDefaultBufferSize(
122
+ request.resolution.width,
123
+ request.resolution.height
124
+ )
125
+ val surface = Surface(surfaceTexture)
126
+ request.provideSurface(surface, ContextCompat.getMainExecutor(context)) { result ->
127
+ Log.d(TAG, "[CAMERAX] Surface provided - result: ${result.resultCode}")
128
+ surface.release()
129
+ }
130
+ } else {
131
+ Log.e(TAG, "[CAMERAX] SurfaceTexture is null! Waiting for TextureView to be ready...")
132
+ // Set listener for when SurfaceTexture becomes available
133
+ textureView.surfaceTextureListener = object : TextureView.SurfaceTextureListener {
134
+ override fun onSurfaceTextureAvailable(st: SurfaceTexture, width: Int, height: Int) {
135
+ Log.d(TAG, "[CAMERAX] SurfaceTexture now available ($width x $height)")
136
+ st.setDefaultBufferSize(request.resolution.width, request.resolution.height)
137
+ val surface = Surface(st)
138
+ request.provideSurface(surface, ContextCompat.getMainExecutor(context)) { result ->
139
+ Log.d(TAG, "[CAMERAX] Surface provided (delayed) - result: ${result.resultCode}")
140
+ surface.release()
141
+ }
142
+ }
143
+
144
+ override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) {}
145
+ override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean = true
146
+ override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {}
147
+ }
148
+ }
149
+ }
109
150
 
110
151
  Log.d(TAG, "[CAMERAX] SurfaceProvider set successfully")
111
152
  }
@@ -114,6 +155,7 @@ class CameraController(
114
155
  imageAnalyzer = ImageAnalysis.Builder()
115
156
  .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
116
157
  .setTargetResolution(android.util.Size(1280, 960)) // Limit resolution for analysis
158
+ .setTargetRotation(targetRotation) // Match preview rotation
117
159
  .build()
118
160
  .also {
119
161
  it.setAnalyzer(cameraExecutor) { imageProxy ->
@@ -128,6 +170,7 @@ class CameraController(
128
170
  // ImageCapture UseCase
129
171
  imageCapture = ImageCapture.Builder()
130
172
  .setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY)
173
+ .setTargetRotation(targetRotation) // Match preview rotation
131
174
  .build()
132
175
 
133
176
  try {
@@ -147,7 +190,7 @@ class CameraController(
147
190
 
148
191
  // Add ImageAnalysis after a short delay to avoid timeout
149
192
  if (detectionEnabled) {
150
- previewView.post {
193
+ textureView.post {
151
194
  try {
152
195
  Log.d(TAG, "[CAMERAX] Adding ImageAnalysis...")
153
196
  camera = cameraProvider.bindToLifecycle(
@@ -166,19 +209,6 @@ class CameraController(
166
209
 
167
210
  Log.d(TAG, "[CAMERAX] Camera bound successfully")
168
211
 
169
- // Monitor preview stream state
170
- previewView.previewStreamState.observe(lifecycleOwner) { state ->
171
- Log.d(TAG, "[CAMERAX] PreviewStreamState changed: $state")
172
- when (state) {
173
- androidx.camera.view.PreviewView.StreamState.IDLE ->
174
- Log.w(TAG, "[CAMERAX] Preview stream is IDLE")
175
- androidx.camera.view.PreviewView.StreamState.STREAMING ->
176
- Log.d(TAG, "[CAMERAX] Preview stream is STREAMING ✓")
177
- else ->
178
- Log.d(TAG, "[CAMERAX] Preview stream state: $state")
179
- }
180
- }
181
-
182
212
  } catch (e: Exception) {
183
213
  Log.e(TAG, "[CAMERAX] Use case binding failed", e)
184
214
  }
@@ -353,19 +383,17 @@ class CameraController(
353
383
  }
354
384
 
355
385
  fun refreshTransform() {
356
- // CameraX handles transform automatically via PreviewView
357
- // No manual matrix calculation needed!
358
- Log.d(TAG, "[CAMERAX] Transform refresh requested - handled automatically by PreviewView")
386
+ // CameraX with TextureView - no manual transform needed
387
+ Log.d(TAG, "[CAMERAX] Transform refresh requested - handled automatically")
359
388
  }
360
389
 
361
- // Simplified coordinate mapping - PreviewView handles most of the work
390
+ // Simplified coordinate mapping for TextureView
362
391
  fun mapRectangleToView(rectangle: Rectangle?, imageWidth: Int, imageHeight: Int): Rectangle? {
363
392
  if (rectangle == null || imageWidth <= 0 || imageHeight <= 0) return null
364
393
 
365
- // CameraX PreviewView with FILL_CENTER handles scaling and centering
366
- // We just need to scale the coordinates proportionally
367
- val viewWidth = previewView.width.toFloat()
368
- val viewHeight = previewView.height.toFloat()
394
+ // Simple proportional scaling for TextureView
395
+ val viewWidth = textureView.width.toFloat()
396
+ val viewHeight = textureView.height.toFloat()
369
397
 
370
398
  if (viewWidth <= 0 || viewHeight <= 0) return null
371
399
 
@@ -389,9 +417,9 @@ class CameraController(
389
417
  }
390
418
 
391
419
  fun getPreviewViewport(): android.graphics.RectF? {
392
- // With CameraX PreviewView, the viewport is simply the view bounds
393
- val width = previewView.width.toFloat()
394
- val height = previewView.height.toFloat()
420
+ // With TextureView, the viewport is simply the view bounds
421
+ val width = textureView.width.toFloat()
422
+ val height = textureView.height.toFloat()
395
423
 
396
424
  if (width <= 0 || height <= 0) return null
397
425
 
@@ -10,8 +10,8 @@ import android.graphics.PorterDuffXfermode
10
10
  import org.opencv.core.Point
11
11
  import android.util.Log
12
12
  import android.view.View
13
+ import android.view.TextureView
13
14
  import android.widget.FrameLayout
14
- import androidx.camera.view.PreviewView
15
15
  import androidx.lifecycle.Lifecycle
16
16
  import androidx.lifecycle.LifecycleOwner
17
17
  import androidx.lifecycle.LifecycleRegistry
@@ -28,7 +28,7 @@ import kotlin.math.max
28
28
 
29
29
  class DocumentScannerView(context: ThemedReactContext) : FrameLayout(context), LifecycleOwner {
30
30
  private val themedContext = context
31
- private val previewView: PreviewView
31
+ private val previewView: TextureView
32
32
  private val overlayView: OverlayView
33
33
  private val useNativeOverlay = false
34
34
  private var cameraController: CameraController? = null
@@ -81,21 +81,19 @@ class DocumentScannerView(context: ThemedReactContext) : FrameLayout(context), L
81
81
  lifecycleRegistry.currentState = Lifecycle.State.INITIALIZED
82
82
  Log.d(TAG, "[INIT] Lifecycle state: ${lifecycleRegistry.currentState}")
83
83
 
84
- // Create preview view (CameraX PreviewView)
85
- Log.d(TAG, "[INIT] Creating PreviewView...")
86
- previewView = PreviewView(context).apply {
84
+ // Create TextureView for camera preview (CameraX compatible)
85
+ Log.d(TAG, "[INIT] Creating TextureView...")
86
+ previewView = TextureView(context).apply {
87
87
  layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
88
88
  visibility = View.VISIBLE
89
89
  keepScreenOn = true
90
- implementationMode = PreviewView.ImplementationMode.COMPATIBLE // Use TextureView - more compatible with React Native
91
- scaleType = PreviewView.ScaleType.FILL_CENTER // Fill and center the preview
92
90
  }
93
- Log.d(TAG, "[INIT] PreviewView created: $previewView")
94
- Log.d(TAG, "[INIT] PreviewView visibility: ${previewView.visibility}")
91
+ Log.d(TAG, "[INIT] TextureView created: $previewView")
92
+ Log.d(TAG, "[INIT] TextureView visibility: ${previewView.visibility}")
95
93
 
96
- Log.d(TAG, "[INIT] Adding PreviewView to parent...")
94
+ Log.d(TAG, "[INIT] Adding TextureView to parent...")
97
95
  addView(previewView, 0) // Add at index 0 (back)
98
- Log.d(TAG, "[INIT] PreviewView added, childCount: $childCount")
96
+ Log.d(TAG, "[INIT] TextureView added, childCount: $childCount")
99
97
 
100
98
  // Create overlay view for drawing rectangle
101
99
  Log.d(TAG, "[INIT] Creating OverlayView...")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-rectangle-doc-scanner",
3
- "version": "10.7.0",
3
+ "version": "10.9.0",
4
4
  "description": "Native-backed document scanner for React Native with customizable overlays.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",