react-native-rectangle-doc-scanner 7.9.0 → 7.10.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.
@@ -24,12 +24,14 @@ import android.util.Size
24
24
  import android.view.Surface
25
25
  import android.view.TextureView
26
26
  import androidx.core.content.ContextCompat
27
+ import androidx.exifinterface.media.ExifInterface
27
28
  import com.google.mlkit.vision.common.InputImage
28
29
  import com.google.mlkit.vision.objects.ObjectDetection
29
30
  import com.google.mlkit.vision.objects.defaults.ObjectDetectorOptions
30
31
  import org.opencv.core.Point
31
32
  import java.io.File
32
33
  import java.io.FileOutputStream
34
+ import java.io.ByteArrayInputStream
33
35
  import java.util.concurrent.atomic.AtomicReference
34
36
  import java.util.concurrent.atomic.AtomicBoolean
35
37
  import kotlin.math.abs
@@ -131,6 +133,10 @@ class CameraController(
131
133
  closeSession()
132
134
  }
133
135
 
136
+ fun refreshTransform() {
137
+ configureTransform()
138
+ }
139
+
134
140
  fun capturePhoto(
135
141
  outputDirectory: File,
136
142
  onImageCaptured: (File) -> Unit,
@@ -475,10 +481,11 @@ class CameraController(
475
481
  val buffer = image.planes[0].buffer
476
482
  val bytes = ByteArray(buffer.remaining())
477
483
  buffer.get(bytes)
484
+ val exifRotation = readExifRotation(bytes)
478
485
  val bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
479
486
  ?: throw IllegalStateException("Failed to decode JPEG")
480
487
 
481
- val rotated = rotateAndMirror(bitmap, computeRotationDegrees(), useFrontCamera)
488
+ val rotated = rotateAndMirror(bitmap, exifRotation, useFrontCamera)
482
489
  val photoFile = File(pending.outputDirectory, "doc_scan_${System.currentTimeMillis()}.jpg")
483
490
  FileOutputStream(photoFile).use { out ->
484
491
  rotated.compress(Bitmap.CompressFormat.JPEG, 95, out)
@@ -649,22 +656,37 @@ class CameraController(
649
656
  private fun rotateAndMirror(bitmap: Bitmap, rotationDegrees: Int, mirror: Boolean): Bitmap {
650
657
  Log.d(TAG, "[ROTATE_MIRROR] rotationDegrees=$rotationDegrees mirror=$mirror bitmap=${bitmap.width}x${bitmap.height}")
651
658
 
652
- // JPEG_ORIENTATION is already set, so the image should already be rotated correctly.
653
- // We only need to apply mirror for front camera.
654
- if (!mirror) {
655
- // Back camera: no additional processing needed since JPEG_ORIENTATION handles rotation.
656
- Log.d(TAG, "[ROTATE_MIRROR] Back camera: returning bitmap as-is (JPEG_ORIENTATION already applied)")
659
+ if (rotationDegrees == 0 && !mirror) {
660
+ Log.d(TAG, "[ROTATE_MIRROR] No rotation/mirror needed, returning bitmap as-is")
657
661
  return bitmap
658
662
  }
659
663
 
660
- // Front camera: apply horizontal mirror
661
664
  val matrix = Matrix()
662
- matrix.postScale(-1f, 1f, bitmap.width / 2f, bitmap.height / 2f)
663
- Log.d(TAG, "[ROTATE_MIRROR] Front camera: applied horizontal mirror")
665
+ if (rotationDegrees != 0) {
666
+ matrix.postRotate(rotationDegrees.toFloat(), bitmap.width / 2f, bitmap.height / 2f)
667
+ }
668
+ if (mirror) {
669
+ matrix.postScale(-1f, 1f, bitmap.width / 2f, bitmap.height / 2f)
670
+ }
664
671
 
665
672
  return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
666
673
  }
667
674
 
675
+ private fun readExifRotation(bytes: ByteArray): Int {
676
+ return try {
677
+ val exif = ExifInterface(ByteArrayInputStream(bytes))
678
+ when (exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)) {
679
+ ExifInterface.ORIENTATION_ROTATE_90 -> 90
680
+ ExifInterface.ORIENTATION_ROTATE_180 -> 180
681
+ ExifInterface.ORIENTATION_ROTATE_270 -> 270
682
+ else -> 0
683
+ }
684
+ } catch (e: Exception) {
685
+ Log.w(TAG, "[CAMERA2] Failed to read EXIF rotation", e)
686
+ 0
687
+ }
688
+ }
689
+
668
690
  private fun refineWithOpenCv(
669
691
  nv21: ByteArray,
670
692
  imageWidth: Int,
@@ -135,6 +135,7 @@ class DocumentScannerView(context: ThemedReactContext) : FrameLayout(context), L
135
135
  super.onLayout(changed, left, top, right, bottom)
136
136
  if (changed) {
137
137
  Log.d(TAG, "[LAYOUT] View size: ${right - left}x${bottom - top}, PreviewView: ${previewView.width}x${previewView.height}")
138
+ cameraController?.refreshTransform()
138
139
  }
139
140
  }
140
141
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-rectangle-doc-scanner",
3
- "version": "7.9.0",
3
+ "version": "7.10.0",
4
4
  "description": "Native-backed document scanner for React Native with customizable overlays.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",