@scr2em/capacitor-scanner 6.0.8 → 6.0.9
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.
|
@@ -6,7 +6,10 @@ import android.content.pm.PackageManager;
|
|
|
6
6
|
import android.graphics.Bitmap;
|
|
7
7
|
import android.graphics.BitmapFactory;
|
|
8
8
|
import android.graphics.Color;
|
|
9
|
+
import android.graphics.Matrix;
|
|
10
|
+
import androidx.exifinterface.media.ExifInterface;
|
|
9
11
|
import android.net.Uri;
|
|
12
|
+
import android.os.Build;
|
|
10
13
|
import android.provider.Settings;
|
|
11
14
|
import android.util.Base64;
|
|
12
15
|
import android.util.DisplayMetrics;
|
|
@@ -51,8 +54,10 @@ import com.google.mlkit.vision.barcode.BarcodeScannerOptions;
|
|
|
51
54
|
import com.google.mlkit.vision.barcode.BarcodeScanning;
|
|
52
55
|
import com.google.mlkit.vision.common.InputImage;
|
|
53
56
|
|
|
57
|
+
import java.io.ByteArrayInputStream;
|
|
54
58
|
import java.io.ByteArrayOutputStream;
|
|
55
59
|
import java.io.IOException;
|
|
60
|
+
import java.io.InputStream;
|
|
56
61
|
import java.util.concurrent.ExecutionException;
|
|
57
62
|
import java.util.concurrent.Executor;
|
|
58
63
|
import java.util.concurrent.Executors;
|
|
@@ -392,11 +397,9 @@ public class CapacitorScannerPlugin extends Plugin {
|
|
|
392
397
|
return;
|
|
393
398
|
}
|
|
394
399
|
|
|
395
|
-
// Ratio must be between 0 and 1, where 0 or 1 means no reduction.
|
|
396
400
|
Double qualityRatioObj = call.getDouble("qualityRatio", 1.0);
|
|
397
401
|
double qualityRatio = qualityRatioObj != null ? qualityRatioObj : 1.0;
|
|
398
402
|
|
|
399
|
-
|
|
400
403
|
// Temporary stream to receive the captured image data.
|
|
401
404
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
|
402
405
|
|
|
@@ -412,32 +415,94 @@ public class CapacitorScannerPlugin extends Plugin {
|
|
|
412
415
|
byte[] originalBytes = outputStream.toByteArray();
|
|
413
416
|
int originalSize = originalBytes.length; // in bytes
|
|
414
417
|
|
|
418
|
+
BitmapFactory.Options options = new BitmapFactory.Options();
|
|
419
|
+
options.inJustDecodeBounds = true;
|
|
420
|
+
BitmapFactory.decodeByteArray(originalBytes, 0, originalSize, options);
|
|
421
|
+
|
|
415
422
|
// If qualityRatio is between 0 and 1 exclusively, perform quality reduction.
|
|
416
423
|
if (qualityRatio > 0 && qualityRatio < 1) {
|
|
417
424
|
// Calculate the target size in bytes.
|
|
418
425
|
int targetSize = (int) (originalSize * qualityRatio);
|
|
419
426
|
|
|
427
|
+
// Read EXIF orientation data from original image
|
|
428
|
+
int orientation = ExifInterface.ORIENTATION_UNDEFINED;
|
|
429
|
+
|
|
430
|
+
try {
|
|
431
|
+
InputStream inputStream = new ByteArrayInputStream(originalBytes);
|
|
432
|
+
ExifInterface exif = null;
|
|
433
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
434
|
+
exif = new ExifInterface(inputStream);
|
|
435
|
+
orientation = exif.getAttributeInt(
|
|
436
|
+
ExifInterface.TAG_ORIENTATION,
|
|
437
|
+
ExifInterface.ORIENTATION_UNDEFINED);
|
|
438
|
+
}
|
|
439
|
+
inputStream.close();
|
|
440
|
+
} catch (IOException e) {
|
|
441
|
+
echo("Warning: Could not read EXIF orientation: " + e.getMessage());
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
|
|
420
445
|
// Decode the captured image into a Bitmap.
|
|
421
|
-
|
|
446
|
+
options.inJustDecodeBounds = false;
|
|
447
|
+
options.inSampleSize = calculateInSampleSize(options, 1024, 1024); // Max size of 1024x1024
|
|
448
|
+
Bitmap originalBitmap = BitmapFactory.decodeByteArray(originalBytes, 0, originalSize, options);
|
|
422
449
|
if (originalBitmap == null) {
|
|
423
450
|
call.reject("Failed to decode captured image.");
|
|
424
451
|
return;
|
|
425
452
|
}
|
|
426
453
|
|
|
454
|
+
// Apply rotation based on EXIF orientation
|
|
455
|
+
Matrix matrix = new Matrix();
|
|
456
|
+
switch (orientation) {
|
|
457
|
+
case ExifInterface.ORIENTATION_ROTATE_90:
|
|
458
|
+
matrix.postRotate(90);
|
|
459
|
+
break;
|
|
460
|
+
case ExifInterface.ORIENTATION_ROTATE_180:
|
|
461
|
+
matrix.postRotate(180);
|
|
462
|
+
break;
|
|
463
|
+
case ExifInterface.ORIENTATION_ROTATE_270:
|
|
464
|
+
matrix.postRotate(270);
|
|
465
|
+
break;
|
|
466
|
+
case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
|
|
467
|
+
matrix.postScale(-1, 1);
|
|
468
|
+
break;
|
|
469
|
+
case ExifInterface.ORIENTATION_FLIP_VERTICAL:
|
|
470
|
+
matrix.postScale(1, -1);
|
|
471
|
+
break;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// Apply the rotation if needed
|
|
475
|
+
if (!matrix.isIdentity()) {
|
|
476
|
+
Bitmap rotatedBitmap = Bitmap.createBitmap(
|
|
477
|
+
originalBitmap, 0, 0,
|
|
478
|
+
originalBitmap.getWidth(), originalBitmap.getHeight(),
|
|
479
|
+
matrix, true);
|
|
480
|
+
originalBitmap.recycle(); // Recycle the old bitmap to free memory.
|
|
481
|
+
originalBitmap = rotatedBitmap;
|
|
482
|
+
}
|
|
483
|
+
|
|
427
484
|
// Prepare a stream to hold the compressed bitmap.
|
|
428
485
|
ByteArrayOutputStream compressedStream = new ByteArrayOutputStream();
|
|
429
|
-
int quality = 100; //
|
|
486
|
+
int quality = 100; // Start with maximum quality (100)
|
|
430
487
|
|
|
431
|
-
// Iteratively compress the bitmap until it reaches the target file size
|
|
488
|
+
// Iteratively compress the bitmap until it reaches the target file size or quality drops to 10%.
|
|
489
|
+
int maxIterations = 10; // Limit iterations to prevent excessive looping.
|
|
490
|
+
int iterations = 0;
|
|
432
491
|
do {
|
|
433
492
|
compressedStream.reset();
|
|
434
493
|
originalBitmap.compress(Bitmap.CompressFormat.JPEG, quality, compressedStream);
|
|
435
|
-
quality -= 5; //
|
|
436
|
-
|
|
494
|
+
quality -= 5; // Reduce quality step by step.
|
|
495
|
+
iterations++;
|
|
496
|
+
} while (compressedStream.toByteArray().length > targetSize && quality > 10 && iterations < maxIterations);
|
|
437
497
|
|
|
438
498
|
// Use the compressed image bytes.
|
|
439
499
|
originalBytes = compressedStream.toByteArray();
|
|
440
500
|
|
|
501
|
+
Bitmap finalBitmap = BitmapFactory.decodeByteArray(originalBytes, 0, originalBytes.length);
|
|
502
|
+
if (finalBitmap != null) {
|
|
503
|
+
finalBitmap.recycle();
|
|
504
|
+
}
|
|
505
|
+
|
|
441
506
|
// Cleanup: recycle the bitmap and close the compressed stream.
|
|
442
507
|
originalBitmap.recycle();
|
|
443
508
|
compressedStream.close();
|
|
@@ -451,6 +516,7 @@ public class CapacitorScannerPlugin extends Plugin {
|
|
|
451
516
|
} catch (Exception e) {
|
|
452
517
|
call.reject("Failed to process image: " + e.getMessage());
|
|
453
518
|
} finally {
|
|
519
|
+
// Ensure resources are cleaned up.
|
|
454
520
|
try {
|
|
455
521
|
outputStream.close();
|
|
456
522
|
} catch (IOException e) {
|
|
@@ -472,7 +538,23 @@ public class CapacitorScannerPlugin extends Plugin {
|
|
|
472
538
|
});
|
|
473
539
|
}
|
|
474
540
|
|
|
541
|
+
private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
|
|
542
|
+
// Calculate the largest inSampleSize that is a power of 2 and keeps the image smaller than the requested width/height.
|
|
543
|
+
final int height = options.outHeight;
|
|
544
|
+
final int width = options.outWidth;
|
|
545
|
+
int inSampleSize = 1;
|
|
546
|
+
|
|
547
|
+
if (height > reqHeight || width > reqWidth) {
|
|
548
|
+
final int halfHeight = height / 2;
|
|
549
|
+
final int halfWidth = width / 2;
|
|
475
550
|
|
|
551
|
+
// Calculate the largest inSampleSize value that is a power of 2 and keeps the image smaller than the requested width/height.
|
|
552
|
+
while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {
|
|
553
|
+
inSampleSize *= 2;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
return inSampleSize;
|
|
557
|
+
}
|
|
476
558
|
|
|
477
559
|
|
|
478
560
|
|