react-native-frame-capture 1.0.1 → 1.1.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.
Files changed (50) hide show
  1. package/FrameCapture.podspec +21 -21
  2. package/LICENSE +20 -20
  3. package/README.md +159 -158
  4. package/android/build.gradle +77 -77
  5. package/android/gradle.properties +5 -5
  6. package/android/src/main/AndroidManifest.xml +20 -20
  7. package/android/src/main/java/com/framecapture/CaptureManager.kt +1013 -831
  8. package/android/src/main/java/com/framecapture/Constants.kt +205 -196
  9. package/android/src/main/java/com/framecapture/ErrorHandler.kt +165 -165
  10. package/android/src/main/java/com/framecapture/FrameCaptureModule.kt +653 -653
  11. package/android/src/main/java/com/framecapture/OverlayRenderer.kt +423 -423
  12. package/android/src/main/java/com/framecapture/PermissionHandler.kt +150 -150
  13. package/android/src/main/java/com/framecapture/ScreenCaptureService.kt +366 -366
  14. package/android/src/main/java/com/framecapture/StorageManager.kt +221 -221
  15. package/android/src/main/java/com/framecapture/capture/BitmapProcessor.kt +157 -157
  16. package/android/src/main/java/com/framecapture/capture/CaptureEventEmitter.kt +150 -120
  17. package/android/src/main/java/com/framecapture/capture/ChangeDetector.kt +191 -0
  18. package/android/src/main/java/com/framecapture/models/CaptureModels.kt +343 -302
  19. package/android/src/main/java/com/framecapture/models/EnumsAndExtensions.kt +67 -60
  20. package/android/src/main/java/com/framecapture/models/OverlayModels.kt +154 -154
  21. package/android/src/main/java/com/framecapture/service/CaptureNotificationManager.kt +286 -286
  22. package/android/src/main/java/com/framecapture/storage/StorageStrategies.kt +317 -317
  23. package/android/src/main/java/com/framecapture/utils/ValidationUtils.kt +379 -379
  24. package/ios/FrameCapture.h +5 -5
  25. package/ios/FrameCapture.mm +21 -21
  26. package/lib/module/NativeFrameCapture.js.map +1 -1
  27. package/lib/module/constants.js +45 -0
  28. package/lib/module/constants.js.map +1 -1
  29. package/lib/module/normalize.js +10 -1
  30. package/lib/module/normalize.js.map +1 -1
  31. package/lib/module/types.js +9 -0
  32. package/lib/module/types.js.map +1 -1
  33. package/lib/module/validation.js +86 -9
  34. package/lib/module/validation.js.map +1 -1
  35. package/lib/typescript/src/NativeFrameCapture.d.ts +7 -0
  36. package/lib/typescript/src/NativeFrameCapture.d.ts.map +1 -1
  37. package/lib/typescript/src/constants.d.ts +33 -0
  38. package/lib/typescript/src/constants.d.ts.map +1 -1
  39. package/lib/typescript/src/normalize.d.ts +8 -2
  40. package/lib/typescript/src/normalize.d.ts.map +1 -1
  41. package/lib/typescript/src/types.d.ts +29 -5
  42. package/lib/typescript/src/types.d.ts.map +1 -1
  43. package/lib/typescript/src/validation.d.ts.map +1 -1
  44. package/package.json +199 -196
  45. package/src/NativeFrameCapture.ts +8 -0
  46. package/src/constants.ts +45 -0
  47. package/src/normalize.ts +23 -3
  48. package/src/types.ts +30 -2
  49. package/src/validation.ts +132 -13
  50. package/plugin/build/index.js +0 -48
@@ -0,0 +1,191 @@
1
+ package com.framecapture.capture
2
+
3
+ import android.graphics.Bitmap
4
+ import android.util.Log
5
+ import com.framecapture.Constants
6
+ import com.framecapture.models.CaptureRegion
7
+ import java.nio.ByteBuffer
8
+
9
+ /**
10
+ * Detects changes between consecutive frames using pixel sampling
11
+ *
12
+ * Uses an efficient sampling algorithm that compares a subset of pixels
13
+ * to determine if the screen has changed significantly enough to warrant capture.
14
+ */
15
+ class ChangeDetector(
16
+ private val threshold: Float = Constants.DEFAULT_CHANGE_THRESHOLD,
17
+ private val sampleRate: Int = Constants.DEFAULT_CHANGE_SAMPLE_RATE,
18
+ private val detectionRegion: CaptureRegion? = null
19
+ ) {
20
+ companion object {
21
+ private const val TAG = "ChangeDetector"
22
+ }
23
+
24
+ // Store previous frame's sampled pixel data
25
+ private var previousSamples: IntArray? = null
26
+ private var previousWidth: Int = 0
27
+ private var previousHeight: Int = 0
28
+
29
+ /**
30
+ * Detects change between current bitmap and previous frame
31
+ * @return Change percentage (0-100), or 100 if no previous frame exists
32
+ */
33
+ fun detectChange(currentBitmap: Bitmap): Float {
34
+ val width = currentBitmap.width
35
+ val height = currentBitmap.height
36
+
37
+ // Calculate sampling bounds based on detection region
38
+ val (startX, startY, endX, endY) = calculateBounds(width, height)
39
+
40
+ // Sample current frame
41
+ val currentSamples = samplePixels(currentBitmap, startX, startY, endX, endY)
42
+
43
+ // If no previous frame, treat as 100% change (always capture first frame)
44
+ if (previousSamples == null || previousWidth != width || previousHeight != height) {
45
+ previousSamples = currentSamples
46
+ previousWidth = width
47
+ previousHeight = height
48
+ Log.d(TAG, "No previous frame - returning 100% change")
49
+ return 100f
50
+ }
51
+
52
+ // Compare samples
53
+ val changedPixels = countChangedPixels(previousSamples!!, currentSamples)
54
+ val totalSamples = currentSamples.size
55
+ val changePercent = if (totalSamples > 0) {
56
+ (changedPixels.toFloat() / totalSamples.toFloat()) * 100f
57
+ } else {
58
+ 0f
59
+ }
60
+
61
+ Log.d(TAG, "Change detected: $changePercent% ($changedPixels/$totalSamples samples)")
62
+ return changePercent
63
+ }
64
+
65
+ /**
66
+ * Updates the previous frame data for next comparison
67
+ */
68
+ fun updatePreviousFrame(bitmap: Bitmap) {
69
+ val width = bitmap.width
70
+ val height = bitmap.height
71
+ val (startX, startY, endX, endY) = calculateBounds(width, height)
72
+
73
+ previousSamples = samplePixels(bitmap, startX, startY, endX, endY)
74
+ previousWidth = width
75
+ previousHeight = height
76
+ }
77
+
78
+ /**
79
+ * Clears stored frame data
80
+ */
81
+ fun clear() {
82
+ previousSamples = null
83
+ previousWidth = 0
84
+ previousHeight = 0
85
+ }
86
+
87
+ /**
88
+ * Calculates bounds for sampling based on detection region
89
+ */
90
+ private fun calculateBounds(width: Int, height: Int): BoundsResult {
91
+ return if (detectionRegion != null) {
92
+ when (detectionRegion.unit) {
93
+ Constants.POSITION_UNIT_PERCENTAGE -> {
94
+ val startX = (detectionRegion.x * width).toInt().coerceIn(0, width - 1)
95
+ val startY = (detectionRegion.y * height).toInt().coerceIn(0, height - 1)
96
+ val endX = ((detectionRegion.x + detectionRegion.width) * width).toInt().coerceIn(startX + 1, width)
97
+ val endY = ((detectionRegion.y + detectionRegion.height) * height).toInt().coerceIn(startY + 1, height)
98
+ BoundsResult(startX, startY, endX, endY)
99
+ }
100
+ Constants.POSITION_UNIT_PIXELS -> {
101
+ val startX = detectionRegion.x.toInt().coerceIn(0, width - 1)
102
+ val startY = detectionRegion.y.toInt().coerceIn(0, height - 1)
103
+ val endX = (detectionRegion.x + detectionRegion.width).toInt().coerceIn(startX + 1, width)
104
+ val endY = (detectionRegion.y + detectionRegion.height).toInt().coerceIn(startY + 1, height)
105
+ BoundsResult(startX, startY, endX, endY)
106
+ }
107
+ else -> BoundsResult(0, 0, width, height)
108
+ }
109
+ } else {
110
+ BoundsResult(0, 0, width, height)
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Samples pixels at regular intervals from the bitmap
116
+ */
117
+ private fun samplePixels(bitmap: Bitmap, startX: Int, startY: Int, endX: Int, endY: Int): IntArray {
118
+ val regionWidth = endX - startX
119
+ val regionHeight = endY - startY
120
+
121
+ // Calculate sample points
122
+ val samplesX = maxOf(1, regionWidth / sampleRate)
123
+ val samplesY = maxOf(1, regionHeight / sampleRate)
124
+ val totalSamples = samplesX * samplesY
125
+
126
+ val samples = IntArray(totalSamples)
127
+ var index = 0
128
+
129
+ for (sy in 0 until samplesY) {
130
+ val y = startY + (sy * sampleRate).coerceIn(0, regionHeight - 1)
131
+ for (sx in 0 until samplesX) {
132
+ val x = startX + (sx * sampleRate).coerceIn(0, regionWidth - 1)
133
+ if (x < bitmap.width && y < bitmap.height) {
134
+ samples[index] = bitmap.getPixel(x, y)
135
+ }
136
+ index++
137
+ }
138
+ }
139
+
140
+ return samples
141
+ }
142
+
143
+ /**
144
+ * Counts pixels that have changed significantly between frames
145
+ */
146
+ private fun countChangedPixels(previous: IntArray, current: IntArray): Int {
147
+ if (previous.size != current.size) {
148
+ return current.size // All pixels considered changed if sizes don't match
149
+ }
150
+
151
+ var changedCount = 0
152
+ val tolerance = Constants.CHANGE_PIXEL_TOLERANCE
153
+
154
+ for (i in previous.indices) {
155
+ if (isPixelChanged(previous[i], current[i], tolerance)) {
156
+ changedCount++
157
+ }
158
+ }
159
+
160
+ return changedCount
161
+ }
162
+
163
+ /**
164
+ * Checks if a pixel has changed beyond the tolerance threshold
165
+ */
166
+ private fun isPixelChanged(pixel1: Int, pixel2: Int, tolerance: Int): Boolean {
167
+ // Extract RGB components (ignore alpha)
168
+ val r1 = (pixel1 shr 16) and 0xFF
169
+ val g1 = (pixel1 shr 8) and 0xFF
170
+ val b1 = pixel1 and 0xFF
171
+
172
+ val r2 = (pixel2 shr 16) and 0xFF
173
+ val g2 = (pixel2 shr 8) and 0xFF
174
+ val b2 = pixel2 and 0xFF
175
+
176
+ // Check if any channel differs beyond tolerance
177
+ return kotlin.math.abs(r1 - r2) > tolerance ||
178
+ kotlin.math.abs(g1 - g2) > tolerance ||
179
+ kotlin.math.abs(b1 - b2) > tolerance
180
+ }
181
+
182
+ /**
183
+ * Simple data class for bounds result
184
+ */
185
+ private data class BoundsResult(
186
+ val startX: Int,
187
+ val startY: Int,
188
+ val endX: Int,
189
+ val endY: Int
190
+ )
191
+ }