react-native-rectangle-doc-scanner 10.23.0 → 10.24.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.
@@ -25,6 +25,7 @@ import kotlinx.coroutines.delay
25
25
  import java.io.File
26
26
  import kotlin.math.min
27
27
  import kotlin.math.max
28
+ import kotlin.math.hypot
28
29
 
29
30
  class DocumentScannerView(context: ThemedReactContext) : FrameLayout(context), LifecycleOwner {
30
31
  private val themedContext = context
@@ -58,6 +59,7 @@ class DocumentScannerView(context: ThemedReactContext) : FrameLayout(context), L
58
59
  private var lastDetectedImageWidth = 0
59
60
  private var lastDetectedImageHeight = 0
60
61
  private var lastRectangleOnScreen: Rectangle? = null
62
+ private var lastSmoothedRectangleOnScreen: Rectangle? = null
61
63
 
62
64
  // Coroutine scope for async operations
63
65
  private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
@@ -215,19 +217,82 @@ class DocumentScannerView(context: ThemedReactContext) : FrameLayout(context), L
215
217
  } else {
216
218
  null
217
219
  }
218
- lastRectangleOnScreen = rectangleOnScreen
220
+ val smoothedRectangleOnScreen = smoothRectangle(rectangleOnScreen, width, height)
221
+ lastRectangleOnScreen = smoothedRectangleOnScreen
219
222
  val quality = when {
220
- rectangleOnScreen != null && width > 0 && height > 0 ->
221
- DocumentDetector.evaluateRectangleQualityInView(rectangleOnScreen, width, height)
223
+ smoothedRectangleOnScreen != null && width > 0 && height > 0 ->
224
+ DocumentDetector.evaluateRectangleQualityInView(smoothedRectangleOnScreen, width, height)
222
225
  rectangle != null -> DocumentDetector.evaluateRectangleQuality(rectangle, imageWidth, imageHeight)
223
226
  else -> RectangleQuality.TOO_FAR
224
227
  }
225
228
 
226
229
  post {
227
- onRectangleDetected(rectangleOnScreen, rectangle, quality, imageWidth, imageHeight)
230
+ onRectangleDetected(smoothedRectangleOnScreen, rectangle, quality, imageWidth, imageHeight)
228
231
  }
229
232
  }
230
233
 
234
+ private fun smoothRectangle(rectangle: Rectangle?, viewWidth: Int, viewHeight: Int): Rectangle? {
235
+ if (rectangle == null || viewWidth <= 0 || viewHeight <= 0) {
236
+ lastSmoothedRectangleOnScreen = null
237
+ return null
238
+ }
239
+
240
+ val prev = lastSmoothedRectangleOnScreen
241
+ if (prev == null) {
242
+ lastSmoothedRectangleOnScreen = rectangle
243
+ return rectangle
244
+ }
245
+
246
+ val minDim = min(viewWidth, viewHeight).toDouble()
247
+ val snapThreshold = max(12.0, minDim * 0.015)
248
+ val smoothThreshold = max(24.0, minDim * 0.06)
249
+ val maxCornerDistance = max(
250
+ maxCornerDistance(prev, rectangle),
251
+ maxCornerDistance(rectangle, prev)
252
+ )
253
+
254
+ val result = when {
255
+ maxCornerDistance <= snapThreshold -> prev
256
+ maxCornerDistance <= smoothThreshold -> blendRectangle(prev, rectangle, 0.35)
257
+ else -> rectangle
258
+ }
259
+
260
+ lastSmoothedRectangleOnScreen = result
261
+ return result
262
+ }
263
+
264
+ private fun maxCornerDistance(a: Rectangle, b: Rectangle): Double {
265
+ return max(
266
+ max(
267
+ distance(a.topLeft, b.topLeft),
268
+ distance(a.topRight, b.topRight)
269
+ ),
270
+ max(
271
+ distance(a.bottomLeft, b.bottomLeft),
272
+ distance(a.bottomRight, b.bottomRight)
273
+ )
274
+ )
275
+ }
276
+
277
+ private fun distance(p1: Point, p2: Point): Double {
278
+ return hypot(p1.x - p2.x, p1.y - p2.y)
279
+ }
280
+
281
+ private fun blendRectangle(a: Rectangle, b: Rectangle, t: Double): Rectangle {
282
+ fun lerp(p1: Point, p2: Point): Point {
283
+ val x = p1.x + (p2.x - p1.x) * t
284
+ val y = p1.y + (p2.y - p1.y) * t
285
+ return Point(x, y)
286
+ }
287
+
288
+ return Rectangle(
289
+ lerp(a.topLeft, b.topLeft),
290
+ lerp(a.topRight, b.topRight),
291
+ lerp(a.bottomLeft, b.bottomLeft),
292
+ lerp(a.bottomRight, b.bottomRight)
293
+ )
294
+ }
295
+
231
296
  private fun onRectangleDetected(
232
297
  rectangleOnScreen: Rectangle?,
233
298
  rectangleCoordinates: Rectangle?,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-rectangle-doc-scanner",
3
- "version": "10.23.0",
3
+ "version": "10.24.0",
4
4
  "description": "Native-backed document scanner for React Native with customizable overlays.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",