react-native-pdf417-scanner 1.4.0 → 1.7.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.
- package/android/src/main/java/com/pdf417scanner/PDF417CameraView.java +483 -28
- package/android/src/main/java/com/pdf417scanner/PDF417CameraViewManager.java +38 -1
- package/android/src/main/java/com/pdf417scanner/PDF417ScannerModule.java +4 -50
- package/android/src/main/java/com/pdf417scanner/PDF417ScannerPackage.java +7 -1
- package/lib/index.d.ts +2 -24
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +0 -55
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
- package/android/src/main/java/com/pdf417scanner/PDF417CameraManager.java +0 -283
- package/android/src/main/java/com/pdf417scanner/PDF417ScannerConfig.java +0 -49
|
@@ -3,6 +3,7 @@ package com.pdf417scanner;
|
|
|
3
3
|
import android.Manifest;
|
|
4
4
|
import android.content.Context;
|
|
5
5
|
import android.content.pm.PackageManager;
|
|
6
|
+
import android.graphics.ImageFormat;
|
|
6
7
|
import android.graphics.SurfaceTexture;
|
|
7
8
|
import android.hardware.camera2.CameraAccessException;
|
|
8
9
|
import android.hardware.camera2.CameraCaptureSession;
|
|
@@ -11,6 +12,8 @@ import android.hardware.camera2.CameraDevice;
|
|
|
11
12
|
import android.hardware.camera2.CameraManager;
|
|
12
13
|
import android.hardware.camera2.CaptureRequest;
|
|
13
14
|
import android.hardware.camera2.params.StreamConfigurationMap;
|
|
15
|
+
import android.media.Image;
|
|
16
|
+
import android.media.ImageReader;
|
|
14
17
|
import android.os.Handler;
|
|
15
18
|
import android.os.HandlerThread;
|
|
16
19
|
import android.util.AttributeSet;
|
|
@@ -22,7 +25,19 @@ import android.view.TextureView;
|
|
|
22
25
|
import androidx.annotation.NonNull;
|
|
23
26
|
import androidx.core.app.ActivityCompat;
|
|
24
27
|
|
|
28
|
+
import com.google.zxing.BarcodeFormat;
|
|
29
|
+
import com.google.zxing.BinaryBitmap;
|
|
30
|
+
import com.google.zxing.DecodeHintType;
|
|
31
|
+
import com.google.zxing.MultiFormatReader;
|
|
32
|
+
import com.google.zxing.PlanarYUVLuminanceSource;
|
|
33
|
+
import com.google.zxing.Result;
|
|
34
|
+
import com.google.zxing.common.HybridBinarizer;
|
|
35
|
+
|
|
36
|
+
import java.nio.ByteBuffer;
|
|
25
37
|
import java.util.Arrays;
|
|
38
|
+
import java.util.EnumMap;
|
|
39
|
+
import java.util.EnumSet;
|
|
40
|
+
import java.util.Map;
|
|
26
41
|
import java.util.concurrent.Semaphore;
|
|
27
42
|
import java.util.concurrent.TimeUnit;
|
|
28
43
|
|
|
@@ -32,19 +47,30 @@ public class PDF417CameraView extends TextureView implements TextureView.Surface
|
|
|
32
47
|
private CameraManager cameraManager;
|
|
33
48
|
private CameraDevice cameraDevice;
|
|
34
49
|
private CameraCaptureSession captureSession;
|
|
50
|
+
private ImageReader imageReader;
|
|
35
51
|
private HandlerThread backgroundThread;
|
|
36
52
|
private Handler backgroundHandler;
|
|
37
53
|
private Semaphore cameraOpenCloseLock = new Semaphore(1);
|
|
38
54
|
private String cameraId;
|
|
39
55
|
private Size previewSize;
|
|
40
56
|
private boolean torchEnabled = false;
|
|
57
|
+
private boolean isScanning = false;
|
|
58
|
+
private MultiFormatReader multiFormatReader;
|
|
41
59
|
private CameraReadyListener cameraReadyListener;
|
|
60
|
+
private ScanResultListener scanResultListener;
|
|
61
|
+
private long lastProcessTime = 0;
|
|
62
|
+
private static final long PROCESS_INTERVAL_MS = 50; // Process every 50ms for better responsiveness
|
|
42
63
|
|
|
43
64
|
public interface CameraReadyListener {
|
|
44
65
|
void onCameraReady();
|
|
45
66
|
void onCameraError(String error);
|
|
46
67
|
}
|
|
47
68
|
|
|
69
|
+
public interface ScanResultListener {
|
|
70
|
+
void onScanResult(String data, String format);
|
|
71
|
+
void onScanError(String code, String message);
|
|
72
|
+
}
|
|
73
|
+
|
|
48
74
|
public PDF417CameraView(Context context) {
|
|
49
75
|
super(context);
|
|
50
76
|
init();
|
|
@@ -63,39 +89,132 @@ public class PDF417CameraView extends TextureView implements TextureView.Surface
|
|
|
63
89
|
private void init() {
|
|
64
90
|
cameraManager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
|
|
65
91
|
setSurfaceTextureListener(this);
|
|
92
|
+
setupBarcodeReader();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private void setupBarcodeReader() {
|
|
96
|
+
multiFormatReader = new MultiFormatReader();
|
|
97
|
+
Map<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class);
|
|
98
|
+
|
|
99
|
+
// Enable all barcode formats for maximum compatibility
|
|
100
|
+
hints.put(DecodeHintType.POSSIBLE_FORMATS, EnumSet.of(
|
|
101
|
+
BarcodeFormat.PDF_417,
|
|
102
|
+
BarcodeFormat.DATA_MATRIX,
|
|
103
|
+
BarcodeFormat.QR_CODE,
|
|
104
|
+
BarcodeFormat.AZTEC,
|
|
105
|
+
BarcodeFormat.CODE_128,
|
|
106
|
+
BarcodeFormat.CODE_39,
|
|
107
|
+
BarcodeFormat.CODABAR
|
|
108
|
+
));
|
|
109
|
+
|
|
110
|
+
// Enhanced scanning hints for lengthy and dense barcodes
|
|
111
|
+
hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
|
|
112
|
+
hints.put(DecodeHintType.PURE_BARCODE, Boolean.FALSE);
|
|
113
|
+
hints.put(DecodeHintType.ALSO_INVERTED, Boolean.TRUE);
|
|
114
|
+
|
|
115
|
+
// Character set for international cards
|
|
116
|
+
hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
|
|
117
|
+
|
|
118
|
+
// Allow partial decoding for lengthy barcodes
|
|
119
|
+
hints.put(DecodeHintType.ASSUME_GS1, Boolean.FALSE);
|
|
120
|
+
|
|
121
|
+
multiFormatReader.setHints(hints);
|
|
66
122
|
}
|
|
67
123
|
|
|
68
124
|
public void setCameraReadyListener(CameraReadyListener listener) {
|
|
69
125
|
this.cameraReadyListener = listener;
|
|
70
126
|
}
|
|
71
127
|
|
|
128
|
+
public void setScanResultListener(ScanResultListener listener) {
|
|
129
|
+
this.scanResultListener = listener;
|
|
130
|
+
}
|
|
131
|
+
|
|
72
132
|
public void startCamera() {
|
|
73
133
|
Log.d(TAG, "Starting camera...");
|
|
74
134
|
startBackgroundThread();
|
|
75
135
|
|
|
76
|
-
// Add a small delay to ensure background thread is ready
|
|
77
136
|
if (backgroundHandler != null) {
|
|
78
137
|
backgroundHandler.post(() -> {
|
|
79
138
|
if (isAvailable()) {
|
|
80
139
|
openCamera(getWidth(), getHeight());
|
|
81
140
|
} else {
|
|
82
141
|
Log.d(TAG, "Surface texture not available yet, waiting...");
|
|
83
|
-
// Will be called from onSurfaceTextureAvailable
|
|
84
142
|
}
|
|
85
143
|
});
|
|
86
|
-
} else {
|
|
87
|
-
Log.e(TAG, "Background handler not ready");
|
|
88
|
-
if (cameraReadyListener != null) {
|
|
89
|
-
cameraReadyListener.onCameraError("Camera initialization failed");
|
|
90
|
-
}
|
|
91
144
|
}
|
|
92
145
|
}
|
|
93
146
|
|
|
94
147
|
public void stopCamera() {
|
|
148
|
+
isScanning = false;
|
|
95
149
|
closeCamera();
|
|
96
150
|
stopBackgroundThread();
|
|
97
151
|
}
|
|
98
152
|
|
|
153
|
+
public void startScanning() {
|
|
154
|
+
isScanning = true;
|
|
155
|
+
Log.d(TAG, "Started scanning for PDF417 barcodes");
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
public void stopScanning() {
|
|
159
|
+
isScanning = false;
|
|
160
|
+
Log.d(TAG, "Stopped scanning");
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
public void triggerAutoFocus() {
|
|
164
|
+
if (captureSession != null && cameraDevice != null) {
|
|
165
|
+
try {
|
|
166
|
+
// Enhanced autofocus for barcode scanning
|
|
167
|
+
CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
|
|
168
|
+
builder.addTarget(new Surface(getSurfaceTexture()));
|
|
169
|
+
builder.addTarget(imageReader.getSurface());
|
|
170
|
+
|
|
171
|
+
// Trigger AF with enhanced settings
|
|
172
|
+
builder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START);
|
|
173
|
+
builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
|
|
174
|
+
|
|
175
|
+
// Enhanced focus settings for barcode scanning
|
|
176
|
+
builder.set(CaptureRequest.LENS_FOCUS_DISTANCE, 0.0f); // Start with infinity
|
|
177
|
+
builder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
|
|
178
|
+
|
|
179
|
+
// Apply enhanced image quality settings during focus
|
|
180
|
+
builder.set(CaptureRequest.EDGE_MODE, CaptureRequest.EDGE_MODE_HIGH_QUALITY);
|
|
181
|
+
builder.set(CaptureRequest.NOISE_REDUCTION_MODE, CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY);
|
|
182
|
+
builder.set(CaptureRequest.SHADING_MODE, CaptureRequest.SHADING_MODE_HIGH_QUALITY);
|
|
183
|
+
|
|
184
|
+
captureSession.capture(builder.build(), null, backgroundHandler);
|
|
185
|
+
|
|
186
|
+
// Reset AF trigger after a short delay
|
|
187
|
+
backgroundHandler.postDelayed(() -> {
|
|
188
|
+
try {
|
|
189
|
+
if (captureSession != null && cameraDevice != null) {
|
|
190
|
+
CaptureRequest.Builder resetBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
|
|
191
|
+
resetBuilder.addTarget(new Surface(getSurfaceTexture()));
|
|
192
|
+
resetBuilder.addTarget(imageReader.getSurface());
|
|
193
|
+
|
|
194
|
+
resetBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
|
|
195
|
+
resetBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
|
|
196
|
+
resetBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
|
|
197
|
+
|
|
198
|
+
// Maintain enhanced quality settings
|
|
199
|
+
resetBuilder.set(CaptureRequest.EDGE_MODE, CaptureRequest.EDGE_MODE_HIGH_QUALITY);
|
|
200
|
+
resetBuilder.set(CaptureRequest.NOISE_REDUCTION_MODE, CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY);
|
|
201
|
+
resetBuilder.set(CaptureRequest.SHADING_MODE, CaptureRequest.SHADING_MODE_HIGH_QUALITY);
|
|
202
|
+
resetBuilder.set(CaptureRequest.FLASH_MODE, torchEnabled ?
|
|
203
|
+
CaptureRequest.FLASH_MODE_TORCH : CaptureRequest.FLASH_MODE_OFF);
|
|
204
|
+
|
|
205
|
+
captureSession.setRepeatingRequest(resetBuilder.build(), null, backgroundHandler);
|
|
206
|
+
}
|
|
207
|
+
} catch (CameraAccessException e) {
|
|
208
|
+
Log.e(TAG, "Error resetting autofocus", e);
|
|
209
|
+
}
|
|
210
|
+
}, 500); // 500ms delay for focus to complete
|
|
211
|
+
|
|
212
|
+
} catch (CameraAccessException e) {
|
|
213
|
+
Log.e(TAG, "Error triggering autofocus", e);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
99
218
|
public void setTorchEnabled(boolean enabled) {
|
|
100
219
|
this.torchEnabled = enabled;
|
|
101
220
|
updateTorch();
|
|
@@ -239,7 +358,6 @@ public class PDF417CameraView extends TextureView implements TextureView.Surface
|
|
|
239
358
|
SurfaceTexture texture = getSurfaceTexture();
|
|
240
359
|
if (texture == null) {
|
|
241
360
|
Log.e(TAG, "Surface texture not available, retrying...");
|
|
242
|
-
// Retry after a short delay
|
|
243
361
|
backgroundHandler.postDelayed(() -> {
|
|
244
362
|
if (cameraDevice != null) {
|
|
245
363
|
createCameraPreviewSession();
|
|
@@ -248,7 +366,6 @@ public class PDF417CameraView extends TextureView implements TextureView.Surface
|
|
|
248
366
|
return;
|
|
249
367
|
}
|
|
250
368
|
|
|
251
|
-
// Ensure surface texture is properly configured
|
|
252
369
|
if (previewSize == null) {
|
|
253
370
|
Log.e(TAG, "Preview size not set");
|
|
254
371
|
if (cameraReadyListener != null) {
|
|
@@ -258,21 +375,43 @@ public class PDF417CameraView extends TextureView implements TextureView.Surface
|
|
|
258
375
|
}
|
|
259
376
|
|
|
260
377
|
texture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
|
|
261
|
-
Surface
|
|
378
|
+
Surface previewSurface = new Surface(texture);
|
|
379
|
+
|
|
380
|
+
// Setup ImageReader for barcode scanning with optimal resolution
|
|
381
|
+
setupImageReader();
|
|
262
382
|
|
|
263
383
|
CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
|
|
264
|
-
builder.addTarget(
|
|
384
|
+
builder.addTarget(previewSurface);
|
|
385
|
+
builder.addTarget(imageReader.getSurface());
|
|
265
386
|
|
|
266
|
-
// Enhanced camera settings for
|
|
387
|
+
// Enhanced camera settings for barcode scanning
|
|
267
388
|
builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
|
|
268
389
|
builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
|
|
269
390
|
builder.set(CaptureRequest.CONTROL_AWB_MODE, CaptureRequest.CONTROL_AWB_MODE_AUTO);
|
|
270
391
|
|
|
271
|
-
//
|
|
392
|
+
// Optimize for document/barcode scanning
|
|
393
|
+
builder.set(CaptureRequest.CONTROL_SCENE_MODE, CaptureRequest.CONTROL_SCENE_MODE_BARCODE);
|
|
394
|
+
builder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_ON);
|
|
395
|
+
|
|
396
|
+
// Enhanced image quality for better barcode detection
|
|
397
|
+
builder.set(CaptureRequest.EDGE_MODE, CaptureRequest.EDGE_MODE_HIGH_QUALITY);
|
|
398
|
+
builder.set(CaptureRequest.NOISE_REDUCTION_MODE, CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY);
|
|
399
|
+
builder.set(CaptureRequest.SHADING_MODE, CaptureRequest.SHADING_MODE_HIGH_QUALITY);
|
|
400
|
+
builder.set(CaptureRequest.COLOR_CORRECTION_MODE, CaptureRequest.COLOR_CORRECTION_MODE_HIGH_QUALITY);
|
|
401
|
+
|
|
402
|
+
// Focus settings for sharp barcode capture
|
|
403
|
+
builder.set(CaptureRequest.LENS_FOCUS_DISTANCE, 0.0f); // Infinity focus for documents
|
|
404
|
+
builder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
|
|
405
|
+
|
|
406
|
+
// Exposure and ISO settings for consistent lighting
|
|
407
|
+
builder.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, 0);
|
|
408
|
+
builder.set(CaptureRequest.CONTROL_AE_LOCK, false);
|
|
409
|
+
|
|
410
|
+
// Set flash mode
|
|
272
411
|
builder.set(CaptureRequest.FLASH_MODE, torchEnabled ?
|
|
273
412
|
CaptureRequest.FLASH_MODE_TORCH : CaptureRequest.FLASH_MODE_OFF);
|
|
274
413
|
|
|
275
|
-
cameraDevice.createCaptureSession(Arrays.asList(
|
|
414
|
+
cameraDevice.createCaptureSession(Arrays.asList(previewSurface, imageReader.getSurface()),
|
|
276
415
|
new CameraCaptureSession.StateCallback() {
|
|
277
416
|
@Override
|
|
278
417
|
public void onConfigured(@NonNull CameraCaptureSession session) {
|
|
@@ -285,7 +424,7 @@ public class PDF417CameraView extends TextureView implements TextureView.Surface
|
|
|
285
424
|
try {
|
|
286
425
|
CaptureRequest request = builder.build();
|
|
287
426
|
session.setRepeatingRequest(request, null, backgroundHandler);
|
|
288
|
-
Log.d(TAG, "Camera preview started successfully");
|
|
427
|
+
Log.d(TAG, "Camera preview started successfully with enhanced settings");
|
|
289
428
|
if (cameraReadyListener != null) {
|
|
290
429
|
cameraReadyListener.onCameraReady();
|
|
291
430
|
}
|
|
@@ -294,11 +433,6 @@ public class PDF417CameraView extends TextureView implements TextureView.Surface
|
|
|
294
433
|
if (cameraReadyListener != null) {
|
|
295
434
|
cameraReadyListener.onCameraError("Failed to start preview: " + e.getMessage());
|
|
296
435
|
}
|
|
297
|
-
} catch (IllegalStateException e) {
|
|
298
|
-
Log.e(TAG, "Camera in illegal state", e);
|
|
299
|
-
if (cameraReadyListener != null) {
|
|
300
|
-
cameraReadyListener.onCameraError("Camera state error: " + e.getMessage());
|
|
301
|
-
}
|
|
302
436
|
}
|
|
303
437
|
}
|
|
304
438
|
|
|
@@ -309,22 +443,339 @@ public class PDF417CameraView extends TextureView implements TextureView.Surface
|
|
|
309
443
|
cameraReadyListener.onCameraError("Failed to configure camera session");
|
|
310
444
|
}
|
|
311
445
|
}
|
|
312
|
-
|
|
313
|
-
@Override
|
|
314
|
-
public void onClosed(@NonNull CameraCaptureSession session) {
|
|
315
|
-
Log.d(TAG, "Camera session closed");
|
|
316
|
-
}
|
|
317
446
|
}, backgroundHandler);
|
|
318
447
|
} catch (CameraAccessException e) {
|
|
319
448
|
Log.e(TAG, "Error creating camera preview session", e);
|
|
320
449
|
if (cameraReadyListener != null) {
|
|
321
450
|
cameraReadyListener.onCameraError("Failed to create preview session: " + e.getMessage());
|
|
322
451
|
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
private void setupImageReader() {
|
|
456
|
+
// Use optimal resolution for barcode scanning
|
|
457
|
+
Size scanSize = chooseBestScanSize();
|
|
458
|
+
imageReader = ImageReader.newInstance(scanSize.getWidth(), scanSize.getHeight(),
|
|
459
|
+
ImageFormat.YUV_420_888, 5); // Increased buffer for better processing
|
|
460
|
+
imageReader.setOnImageAvailableListener(onImageAvailableListener, backgroundHandler);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
private Size chooseBestScanSize() {
|
|
464
|
+
// For lengthy barcodes, we need higher resolution
|
|
465
|
+
if (previewSize.getWidth() > 2560 || previewSize.getHeight() > 1440) {
|
|
466
|
+
return new Size(2560, 1440); // 4K support for very detailed barcodes
|
|
467
|
+
} else if (previewSize.getWidth() > 1920 || previewSize.getHeight() > 1080) {
|
|
468
|
+
return new Size(1920, 1080); // Full HD for detailed barcodes
|
|
469
|
+
} else if (previewSize.getWidth() < 1280 || previewSize.getHeight() < 720) {
|
|
470
|
+
return new Size(1280, 720); // Minimum HD for basic scanning
|
|
471
|
+
}
|
|
472
|
+
return previewSize;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
private final ImageReader.OnImageAvailableListener onImageAvailableListener =
|
|
476
|
+
new ImageReader.OnImageAvailableListener() {
|
|
477
|
+
@Override
|
|
478
|
+
public void onImageAvailable(ImageReader reader) {
|
|
479
|
+
if (!isScanning) return;
|
|
480
|
+
|
|
481
|
+
// Throttle processing to avoid overwhelming the CPU
|
|
482
|
+
long currentTime = System.currentTimeMillis();
|
|
483
|
+
if (currentTime - lastProcessTime < PROCESS_INTERVAL_MS) {
|
|
484
|
+
// Skip this frame
|
|
485
|
+
Image image = reader.acquireLatestImage();
|
|
486
|
+
if (image != null) {
|
|
487
|
+
image.close();
|
|
488
|
+
}
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
lastProcessTime = currentTime;
|
|
492
|
+
|
|
493
|
+
Image image = reader.acquireLatestImage();
|
|
494
|
+
if (image != null) {
|
|
495
|
+
try {
|
|
496
|
+
processImage(image);
|
|
497
|
+
} finally {
|
|
498
|
+
image.close();
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
|
|
504
|
+
private void processImage(Image image) {
|
|
505
|
+
try {
|
|
506
|
+
// Get image dimensions
|
|
507
|
+
int width = image.getWidth();
|
|
508
|
+
int height = image.getHeight();
|
|
509
|
+
|
|
510
|
+
// Extract Y plane (luminance) from YUV_420_888
|
|
511
|
+
Image.Plane yPlane = image.getPlanes()[0];
|
|
512
|
+
ByteBuffer yBuffer = yPlane.getBuffer();
|
|
513
|
+
int ySize = yBuffer.remaining();
|
|
514
|
+
byte[] yData = new byte[ySize];
|
|
515
|
+
yBuffer.get(yData);
|
|
516
|
+
|
|
517
|
+
// Enhanced processing for lengthy and dense barcodes
|
|
518
|
+
Result result = null;
|
|
519
|
+
|
|
520
|
+
// Approach 1: Full image with enhanced preprocessing
|
|
521
|
+
result = tryDecodeWithEnhancedProcessing(yData, width, height, 0, 0, width, height);
|
|
522
|
+
|
|
523
|
+
// Approach 2: Horizontal strips for lengthy barcodes (like Canadian health cards)
|
|
524
|
+
if (result == null) {
|
|
525
|
+
result = tryHorizontalStrips(yData, width, height);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// Approach 3: Vertical strips for rotated lengthy barcodes
|
|
529
|
+
if (result == null) {
|
|
530
|
+
result = tryVerticalStrips(yData, width, height);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// Approach 4: Center crop with different sizes
|
|
534
|
+
if (result == null) {
|
|
535
|
+
result = tryMultipleCrops(yData, width, height);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// Approach 5: Enhanced rotation detection
|
|
539
|
+
if (result == null) {
|
|
540
|
+
result = tryEnhancedRotation(yData, width, height);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// Approach 6: Scale variations for different densities
|
|
544
|
+
if (result == null) {
|
|
545
|
+
result = tryScaleVariations(yData, width, height);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
if (result != null && scanResultListener != null) {
|
|
549
|
+
Log.d(TAG, "Barcode detected: " + result.getBarcodeFormat() + " - Length: " + result.getText().length());
|
|
550
|
+
scanResultListener.onScanResult(result.getText(), result.getBarcodeFormat().toString());
|
|
551
|
+
}
|
|
323
552
|
} catch (Exception e) {
|
|
324
|
-
Log.
|
|
325
|
-
|
|
326
|
-
|
|
553
|
+
Log.d(TAG, "No barcode found in frame: " + e.getMessage());
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
private Result tryDecodeWithEnhancedProcessing(byte[] yData, int dataWidth, int dataHeight,
|
|
558
|
+
int left, int top, int width, int height) {
|
|
559
|
+
try {
|
|
560
|
+
// Create luminance source
|
|
561
|
+
PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(
|
|
562
|
+
yData, dataWidth, dataHeight, left, top, width, height, false);
|
|
563
|
+
|
|
564
|
+
// Try multiple binarization approaches
|
|
565
|
+
Result result = null;
|
|
566
|
+
|
|
567
|
+
// 1. HybridBinarizer (best for mixed content)
|
|
568
|
+
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
|
|
569
|
+
try {
|
|
570
|
+
result = multiFormatReader.decode(bitmap);
|
|
571
|
+
if (result != null) return result;
|
|
572
|
+
} catch (Exception e) { /* Continue to next approach */ }
|
|
573
|
+
|
|
574
|
+
// 2. GlobalHistogramBinarizer (best for uniform lighting)
|
|
575
|
+
bitmap = new BinaryBitmap(new com.google.zxing.common.GlobalHistogramBinarizer(source));
|
|
576
|
+
try {
|
|
577
|
+
result = multiFormatReader.decode(bitmap);
|
|
578
|
+
if (result != null) return result;
|
|
579
|
+
} catch (Exception e) { /* Continue to next approach */ }
|
|
580
|
+
|
|
581
|
+
// 3. Try with inverted source for negative barcodes
|
|
582
|
+
PlanarYUVLuminanceSource invertedSource = new PlanarYUVLuminanceSource(
|
|
583
|
+
invertYUVData(yData, width * height), dataWidth, dataHeight, left, top, width, height, false);
|
|
584
|
+
|
|
585
|
+
bitmap = new BinaryBitmap(new HybridBinarizer(invertedSource));
|
|
586
|
+
try {
|
|
587
|
+
result = multiFormatReader.decode(bitmap);
|
|
588
|
+
if (result != null) return result;
|
|
589
|
+
} catch (Exception e) { /* Continue */ }
|
|
590
|
+
|
|
591
|
+
return null;
|
|
592
|
+
} catch (Exception e) {
|
|
593
|
+
return null;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
private Result tryHorizontalStrips(byte[] yData, int width, int height) {
|
|
598
|
+
// Scan in horizontal strips for lengthy horizontal barcodes
|
|
599
|
+
int stripHeight = height / 5; // 5 horizontal strips
|
|
600
|
+
|
|
601
|
+
for (int i = 0; i < 5; i++) {
|
|
602
|
+
int stripTop = i * stripHeight;
|
|
603
|
+
if (stripTop + stripHeight > height) stripHeight = height - stripTop;
|
|
604
|
+
|
|
605
|
+
Result result = tryDecodeWithEnhancedProcessing(yData, width, height,
|
|
606
|
+
0, stripTop, width, stripHeight);
|
|
607
|
+
if (result != null) return result;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// Try overlapping strips
|
|
611
|
+
stripHeight = height / 3;
|
|
612
|
+
for (int i = 0; i < 4; i++) {
|
|
613
|
+
int stripTop = i * stripHeight / 2;
|
|
614
|
+
if (stripTop + stripHeight > height) stripHeight = height - stripTop;
|
|
615
|
+
|
|
616
|
+
Result result = tryDecodeWithEnhancedProcessing(yData, width, height,
|
|
617
|
+
0, stripTop, width, stripHeight);
|
|
618
|
+
if (result != null) return result;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
return null;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
private Result tryVerticalStrips(byte[] yData, int width, int height) {
|
|
625
|
+
// Scan in vertical strips for lengthy vertical barcodes
|
|
626
|
+
int stripWidth = width / 5; // 5 vertical strips
|
|
627
|
+
|
|
628
|
+
for (int i = 0; i < 5; i++) {
|
|
629
|
+
int stripLeft = i * stripWidth;
|
|
630
|
+
if (stripLeft + stripWidth > width) stripWidth = width - stripLeft;
|
|
631
|
+
|
|
632
|
+
Result result = tryDecodeWithEnhancedProcessing(yData, width, height,
|
|
633
|
+
stripLeft, 0, stripWidth, height);
|
|
634
|
+
if (result != null) return result;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
return null;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
private Result tryMultipleCrops(byte[] yData, int width, int height) {
|
|
641
|
+
// Try different crop sizes for various barcode densities
|
|
642
|
+
float[] cropFactors = {0.9f, 0.8f, 0.7f, 0.6f, 0.5f};
|
|
643
|
+
|
|
644
|
+
for (float factor : cropFactors) {
|
|
645
|
+
int cropWidth = (int)(width * factor);
|
|
646
|
+
int cropHeight = (int)(height * factor);
|
|
647
|
+
int cropLeft = (width - cropWidth) / 2;
|
|
648
|
+
int cropTop = (height - cropHeight) / 2;
|
|
649
|
+
|
|
650
|
+
Result result = tryDecodeWithEnhancedProcessing(yData, width, height,
|
|
651
|
+
cropLeft, cropTop, cropWidth, cropHeight);
|
|
652
|
+
if (result != null) return result;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
return null;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
private Result tryEnhancedRotation(byte[] yData, int width, int height) {
|
|
659
|
+
try {
|
|
660
|
+
// Try 90-degree rotations with enhanced processing
|
|
661
|
+
int[] rotations = {90, 180, 270};
|
|
662
|
+
|
|
663
|
+
for (int rotation : rotations) {
|
|
664
|
+
byte[] rotatedData = rotateYUVEnhanced(yData, width, height, rotation);
|
|
665
|
+
int newWidth = (rotation == 90 || rotation == 270) ? height : width;
|
|
666
|
+
int newHeight = (rotation == 90 || rotation == 270) ? width : height;
|
|
667
|
+
|
|
668
|
+
Result result = tryDecodeWithEnhancedProcessing(rotatedData, newWidth, newHeight,
|
|
669
|
+
0, 0, newWidth, newHeight);
|
|
670
|
+
if (result != null) return result;
|
|
327
671
|
}
|
|
672
|
+
|
|
673
|
+
return null;
|
|
674
|
+
} catch (Exception e) {
|
|
675
|
+
return null;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
private Result tryScaleVariations(byte[] yData, int width, int height) {
|
|
680
|
+
try {
|
|
681
|
+
// Try different scaling for high/low density barcodes
|
|
682
|
+
float[] scales = {1.5f, 0.75f, 0.5f};
|
|
683
|
+
|
|
684
|
+
for (float scale : scales) {
|
|
685
|
+
byte[] scaledData = scaleYUVData(yData, width, height, scale);
|
|
686
|
+
int newWidth = (int)(width * scale);
|
|
687
|
+
int newHeight = (int)(height * scale);
|
|
688
|
+
|
|
689
|
+
if (newWidth > 0 && newHeight > 0 && scaledData != null) {
|
|
690
|
+
Result result = tryDecodeWithEnhancedProcessing(scaledData, newWidth, newHeight,
|
|
691
|
+
0, 0, newWidth, newHeight);
|
|
692
|
+
if (result != null) return result;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
return null;
|
|
697
|
+
} catch (Exception e) {
|
|
698
|
+
return null;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
private byte[] invertYUVData(byte[] data, int length) {
|
|
703
|
+
byte[] inverted = new byte[data.length];
|
|
704
|
+
System.arraycopy(data, 0, inverted, 0, data.length);
|
|
705
|
+
|
|
706
|
+
// Invert only the Y (luminance) component
|
|
707
|
+
for (int i = 0; i < length; i++) {
|
|
708
|
+
inverted[i] = (byte)(255 - (inverted[i] & 0xFF));
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
return inverted;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
private byte[] rotateYUVEnhanced(byte[] data, int width, int height, int rotation) {
|
|
715
|
+
if (rotation == 0) return data;
|
|
716
|
+
|
|
717
|
+
byte[] rotated = new byte[data.length];
|
|
718
|
+
int index = 0;
|
|
719
|
+
|
|
720
|
+
// Only rotate the Y component for barcode detection
|
|
721
|
+
int ySize = width * height;
|
|
722
|
+
|
|
723
|
+
switch (rotation) {
|
|
724
|
+
case 90:
|
|
725
|
+
for (int x = 0; x < width; x++) {
|
|
726
|
+
for (int y = height - 1; y >= 0; y--) {
|
|
727
|
+
rotated[index++] = data[y * width + x];
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
break;
|
|
731
|
+
case 180:
|
|
732
|
+
for (int y = height - 1; y >= 0; y--) {
|
|
733
|
+
for (int x = width - 1; x >= 0; x--) {
|
|
734
|
+
rotated[index++] = data[y * width + x];
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
break;
|
|
738
|
+
case 270:
|
|
739
|
+
for (int x = width - 1; x >= 0; x--) {
|
|
740
|
+
for (int y = 0; y < height; y++) {
|
|
741
|
+
rotated[index++] = data[y * width + x];
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
break;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
// Copy remaining UV data as-is (not used for barcode detection)
|
|
748
|
+
if (data.length > ySize) {
|
|
749
|
+
System.arraycopy(data, ySize, rotated, ySize, data.length - ySize);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
return rotated;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
private byte[] scaleYUVData(byte[] data, int width, int height, float scale) {
|
|
756
|
+
try {
|
|
757
|
+
int newWidth = (int)(width * scale);
|
|
758
|
+
int newHeight = (int)(height * scale);
|
|
759
|
+
|
|
760
|
+
if (newWidth <= 0 || newHeight <= 0) return null;
|
|
761
|
+
|
|
762
|
+
byte[] scaled = new byte[newWidth * newHeight];
|
|
763
|
+
|
|
764
|
+
// Simple nearest neighbor scaling for Y component
|
|
765
|
+
for (int y = 0; y < newHeight; y++) {
|
|
766
|
+
for (int x = 0; x < newWidth; x++) {
|
|
767
|
+
int srcX = (int)(x / scale);
|
|
768
|
+
int srcY = (int)(y / scale);
|
|
769
|
+
|
|
770
|
+
if (srcX < width && srcY < height) {
|
|
771
|
+
scaled[y * newWidth + x] = data[srcY * width + srcX];
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
return scaled;
|
|
777
|
+
} catch (Exception e) {
|
|
778
|
+
return null;
|
|
328
779
|
}
|
|
329
780
|
}
|
|
330
781
|
|
|
@@ -339,6 +790,10 @@ public class PDF417CameraView extends TextureView implements TextureView.Surface
|
|
|
339
790
|
cameraDevice.close();
|
|
340
791
|
cameraDevice = null;
|
|
341
792
|
}
|
|
793
|
+
if (imageReader != null) {
|
|
794
|
+
imageReader.close();
|
|
795
|
+
imageReader = null;
|
|
796
|
+
}
|
|
342
797
|
} catch (InterruptedException e) {
|
|
343
798
|
throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
|
|
344
799
|
} finally {
|
|
@@ -17,11 +17,16 @@ import com.facebook.react.uimanager.events.RCTEventEmitter;
|
|
|
17
17
|
import java.util.Map;
|
|
18
18
|
|
|
19
19
|
public class PDF417CameraViewManager extends SimpleViewManager<PDF417CameraView>
|
|
20
|
-
implements PDF417CameraView.CameraReadyListener {
|
|
20
|
+
implements PDF417CameraView.CameraReadyListener, PDF417CameraView.ScanResultListener {
|
|
21
21
|
|
|
22
22
|
public static final String REACT_CLASS = "PDF417CameraView";
|
|
23
23
|
|
|
24
24
|
private PDF417CameraView currentCameraView;
|
|
25
|
+
private PDF417ScannerModule scannerModule;
|
|
26
|
+
|
|
27
|
+
public void setScannerModule(PDF417ScannerModule module) {
|
|
28
|
+
this.scannerModule = module;
|
|
29
|
+
}
|
|
25
30
|
|
|
26
31
|
@NonNull
|
|
27
32
|
@Override
|
|
@@ -34,6 +39,7 @@ public class PDF417CameraViewManager extends SimpleViewManager<PDF417CameraView>
|
|
|
34
39
|
protected PDF417CameraView createViewInstance(@NonNull ThemedReactContext reactContext) {
|
|
35
40
|
PDF417CameraView cameraView = new PDF417CameraView(reactContext);
|
|
36
41
|
cameraView.setCameraReadyListener(this);
|
|
42
|
+
cameraView.setScanResultListener(this);
|
|
37
43
|
currentCameraView = cameraView;
|
|
38
44
|
return cameraView;
|
|
39
45
|
}
|
|
@@ -47,11 +53,27 @@ public class PDF417CameraViewManager extends SimpleViewManager<PDF417CameraView>
|
|
|
47
53
|
}
|
|
48
54
|
}
|
|
49
55
|
|
|
56
|
+
@ReactProp(name = "isScanning")
|
|
57
|
+
public void setIsScanning(PDF417CameraView view, boolean isScanning) {
|
|
58
|
+
if (isScanning) {
|
|
59
|
+
view.startScanning();
|
|
60
|
+
} else {
|
|
61
|
+
view.stopScanning();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
50
65
|
@ReactProp(name = "torchEnabled")
|
|
51
66
|
public void setTorchEnabled(PDF417CameraView view, boolean torchEnabled) {
|
|
52
67
|
view.setTorchEnabled(torchEnabled);
|
|
53
68
|
}
|
|
54
69
|
|
|
70
|
+
@ReactProp(name = "triggerFocus")
|
|
71
|
+
public void setTriggerFocus(PDF417CameraView view, boolean trigger) {
|
|
72
|
+
if (trigger) {
|
|
73
|
+
view.triggerAutoFocus();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
55
77
|
@Override
|
|
56
78
|
public void onDropViewInstance(@NonNull PDF417CameraView view) {
|
|
57
79
|
view.stopCamera();
|
|
@@ -92,4 +114,19 @@ public class PDF417CameraViewManager extends SimpleViewManager<PDF417CameraView>
|
|
|
92
114
|
event);
|
|
93
115
|
}
|
|
94
116
|
}
|
|
117
|
+
|
|
118
|
+
// ScanResultListener implementation
|
|
119
|
+
@Override
|
|
120
|
+
public void onScanResult(String data, String format) {
|
|
121
|
+
if (scannerModule != null) {
|
|
122
|
+
scannerModule.onScanResult(data, format);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
@Override
|
|
127
|
+
public void onScanError(String code, String message) {
|
|
128
|
+
if (scannerModule != null) {
|
|
129
|
+
scannerModule.onScanError(code, message);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
95
132
|
}
|
|
@@ -25,7 +25,6 @@ public class PDF417ScannerModule extends ReactContextBaseJavaModule {
|
|
|
25
25
|
private static final String TAG = "PDF417ScannerModule";
|
|
26
26
|
private static final String MODULE_NAME = "PDF417Scanner";
|
|
27
27
|
|
|
28
|
-
private PDF417CameraManager cameraManager;
|
|
29
28
|
private ReactApplicationContext reactContext;
|
|
30
29
|
private Handler mainHandler;
|
|
31
30
|
|
|
@@ -33,7 +32,6 @@ public class PDF417ScannerModule extends ReactContextBaseJavaModule {
|
|
|
33
32
|
super(reactContext);
|
|
34
33
|
this.reactContext = reactContext;
|
|
35
34
|
this.mainHandler = new Handler(Looper.getMainLooper());
|
|
36
|
-
this.cameraManager = new PDF417CameraManager(reactContext, this);
|
|
37
35
|
}
|
|
38
36
|
|
|
39
37
|
@NonNull
|
|
@@ -51,64 +49,20 @@ public class PDF417ScannerModule extends ReactContextBaseJavaModule {
|
|
|
51
49
|
return constants;
|
|
52
50
|
}
|
|
53
51
|
|
|
52
|
+
// Simplified methods - actual functionality is handled by CameraView
|
|
54
53
|
@ReactMethod
|
|
55
54
|
public void startScanning(ReadableMap config, Promise promise) {
|
|
56
|
-
|
|
57
|
-
if (!hasRequiredPermissions()) {
|
|
58
|
-
promise.reject("PERMISSION_DENIED", "Camera permission is required");
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
PDF417ScannerConfig scannerConfig = new PDF417ScannerConfig();
|
|
63
|
-
if (config.hasKey("enableAutoFocus")) {
|
|
64
|
-
scannerConfig.setEnableAutoFocus(config.getBoolean("enableAutoFocus"));
|
|
65
|
-
}
|
|
66
|
-
if (config.hasKey("enableTorch")) {
|
|
67
|
-
scannerConfig.setEnableTorch(config.getBoolean("enableTorch"));
|
|
68
|
-
}
|
|
69
|
-
if (config.hasKey("scanTimeout")) {
|
|
70
|
-
scannerConfig.setScanTimeout(config.getInt("scanTimeout"));
|
|
71
|
-
}
|
|
72
|
-
if (config.hasKey("enableBeep")) {
|
|
73
|
-
scannerConfig.setEnableBeep(config.getBoolean("enableBeep"));
|
|
74
|
-
}
|
|
75
|
-
if (config.hasKey("enableVibration")) {
|
|
76
|
-
scannerConfig.setEnableVibration(config.getBoolean("enableVibration"));
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
cameraManager.startScanning(scannerConfig);
|
|
80
|
-
promise.resolve(null);
|
|
81
|
-
} catch (Exception e) {
|
|
82
|
-
Log.e(TAG, "Error starting scanner", e);
|
|
83
|
-
promise.reject("START_SCANNING_ERROR", e.getMessage());
|
|
84
|
-
}
|
|
55
|
+
promise.resolve(null);
|
|
85
56
|
}
|
|
86
57
|
|
|
87
58
|
@ReactMethod
|
|
88
59
|
public void stopScanning(Promise promise) {
|
|
89
|
-
|
|
90
|
-
cameraManager.stopScanning();
|
|
91
|
-
promise.resolve(null);
|
|
92
|
-
} catch (Exception e) {
|
|
93
|
-
Log.e(TAG, "Error stopping scanner", e);
|
|
94
|
-
promise.reject("STOP_SCANNING_ERROR", e.getMessage());
|
|
95
|
-
}
|
|
60
|
+
promise.resolve(null);
|
|
96
61
|
}
|
|
97
62
|
|
|
98
63
|
@ReactMethod
|
|
99
64
|
public void setTorchEnabled(boolean enabled, Promise promise) {
|
|
100
|
-
|
|
101
|
-
cameraManager.setTorchEnabled(enabled);
|
|
102
|
-
promise.resolve(null);
|
|
103
|
-
} catch (Exception e) {
|
|
104
|
-
Log.e(TAG, "Error setting torch", e);
|
|
105
|
-
promise.reject("TORCH_ERROR", e.getMessage());
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
private boolean hasRequiredPermissions() {
|
|
110
|
-
return ActivityCompat.checkSelfPermission(reactContext, Manifest.permission.CAMERA)
|
|
111
|
-
== PackageManager.PERMISSION_GRANTED;
|
|
65
|
+
promise.resolve(null);
|
|
112
66
|
}
|
|
113
67
|
|
|
114
68
|
public void sendEvent(String eventName, WritableMap params) {
|
|
@@ -24,7 +24,13 @@ public class PDF417ScannerPackage implements ReactPackage {
|
|
|
24
24
|
@Override
|
|
25
25
|
public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
|
|
26
26
|
List<ViewManager> viewManagers = new ArrayList<>();
|
|
27
|
-
|
|
27
|
+
|
|
28
|
+
// Create the module and view manager with proper connection
|
|
29
|
+
PDF417ScannerModule scannerModule = new PDF417ScannerModule(reactContext);
|
|
30
|
+
PDF417CameraViewManager cameraViewManager = new PDF417CameraViewManager();
|
|
31
|
+
cameraViewManager.setScannerModule(scannerModule);
|
|
32
|
+
|
|
33
|
+
viewManagers.add(cameraViewManager);
|
|
28
34
|
return viewManagers;
|
|
29
35
|
}
|
|
30
36
|
}
|
package/lib/index.d.ts
CHANGED
|
@@ -8,17 +8,12 @@ export interface PDF417ScanError {
|
|
|
8
8
|
code: string;
|
|
9
9
|
message: string;
|
|
10
10
|
}
|
|
11
|
-
export interface PDF417ScannerConfig {
|
|
12
|
-
enableAutoFocus?: boolean;
|
|
13
|
-
enableTorch?: boolean;
|
|
14
|
-
scanTimeout?: number;
|
|
15
|
-
enableBeep?: boolean;
|
|
16
|
-
enableVibration?: boolean;
|
|
17
|
-
}
|
|
18
11
|
export interface PDF417CameraViewProps {
|
|
19
12
|
style?: ViewStyle;
|
|
20
13
|
isActive?: boolean;
|
|
14
|
+
isScanning?: boolean;
|
|
21
15
|
torchEnabled?: boolean;
|
|
16
|
+
triggerFocus?: boolean;
|
|
22
17
|
onCameraReady?: () => void;
|
|
23
18
|
onCameraError?: (event: {
|
|
24
19
|
nativeEvent: {
|
|
@@ -29,7 +24,6 @@ export interface PDF417CameraViewProps {
|
|
|
29
24
|
export declare const PDF417CameraView: import("react-native").HostComponent<PDF417CameraViewProps>;
|
|
30
25
|
declare class PDF417ScannerModule {
|
|
31
26
|
private eventEmitter;
|
|
32
|
-
private isScanning;
|
|
33
27
|
constructor();
|
|
34
28
|
/**
|
|
35
29
|
* Request camera permission
|
|
@@ -39,22 +33,6 @@ declare class PDF417ScannerModule {
|
|
|
39
33
|
* Check if camera permission is granted
|
|
40
34
|
*/
|
|
41
35
|
hasCameraPermission(): Promise<boolean>;
|
|
42
|
-
/**
|
|
43
|
-
* Start PDF417 scanning
|
|
44
|
-
*/
|
|
45
|
-
startScanning(config?: PDF417ScannerConfig): Promise<void>;
|
|
46
|
-
/**
|
|
47
|
-
* Stop PDF417 scanning
|
|
48
|
-
*/
|
|
49
|
-
stopScanning(): Promise<void>;
|
|
50
|
-
/**
|
|
51
|
-
* Check if scanner is currently running
|
|
52
|
-
*/
|
|
53
|
-
isCurrentlyScanning(): boolean;
|
|
54
|
-
/**
|
|
55
|
-
* Enable/disable torch (flashlight)
|
|
56
|
-
*/
|
|
57
|
-
setTorchEnabled(enabled: boolean): Promise<void>;
|
|
58
36
|
/**
|
|
59
37
|
* Listen for scan results
|
|
60
38
|
*/
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2F,SAAS,EAAE,MAAM,cAAc,CAAC;AAIlI,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2F,SAAS,EAAE,MAAM,cAAc,CAAC;AAIlI,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,WAAW,EAAE;YAAE,KAAK,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,KAAK,IAAI,CAAC;CACrE;AAGD,eAAO,MAAM,gBAAgB,6DAAoE,CAAC;AAElG,cAAM,mBAAmB;IACvB,OAAO,CAAC,YAAY,CAAqB;;IAMzC;;OAEG;IACG,uBAAuB,IAAI,OAAO,CAAC,OAAO,CAAC;IAuBjD;;OAEG;IACG,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC;IAgB7C;;OAEG;IACH,YAAY,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,GAAG,MAAM,IAAI;IAKtE;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,GAAG,MAAM,IAAI;IAKnE;;OAEG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;CAIhD;;AAED,wBAAyC"}
|
package/lib/index.js
CHANGED
|
@@ -7,7 +7,6 @@ const { PDF417Scanner } = react_native_1.NativeModules;
|
|
|
7
7
|
exports.PDF417CameraView = (0, react_native_1.requireNativeComponent)('PDF417CameraView');
|
|
8
8
|
class PDF417ScannerModule {
|
|
9
9
|
constructor() {
|
|
10
|
-
this.isScanning = false;
|
|
11
10
|
this.eventEmitter = new react_native_1.NativeEventEmitter(PDF417Scanner);
|
|
12
11
|
}
|
|
13
12
|
/**
|
|
@@ -48,60 +47,6 @@ class PDF417ScannerModule {
|
|
|
48
47
|
return false;
|
|
49
48
|
}
|
|
50
49
|
}
|
|
51
|
-
/**
|
|
52
|
-
* Start PDF417 scanning
|
|
53
|
-
*/
|
|
54
|
-
async startScanning(config = {}) {
|
|
55
|
-
if (this.isScanning) {
|
|
56
|
-
throw new Error('Scanner is already running');
|
|
57
|
-
}
|
|
58
|
-
const hasPermission = await this.hasCameraPermission();
|
|
59
|
-
if (!hasPermission) {
|
|
60
|
-
const granted = await this.requestCameraPermission();
|
|
61
|
-
if (!granted) {
|
|
62
|
-
throw new Error('Camera permission denied');
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
try {
|
|
66
|
-
await PDF417Scanner.startScanning(config);
|
|
67
|
-
this.isScanning = true;
|
|
68
|
-
}
|
|
69
|
-
catch (error) {
|
|
70
|
-
throw new Error(`Failed to start scanning: ${error}`);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Stop PDF417 scanning
|
|
75
|
-
*/
|
|
76
|
-
async stopScanning() {
|
|
77
|
-
if (!this.isScanning) {
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
try {
|
|
81
|
-
await PDF417Scanner.stopScanning();
|
|
82
|
-
this.isScanning = false;
|
|
83
|
-
}
|
|
84
|
-
catch (error) {
|
|
85
|
-
throw new Error(`Failed to stop scanning: ${error}`);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* Check if scanner is currently running
|
|
90
|
-
*/
|
|
91
|
-
isCurrentlyScanning() {
|
|
92
|
-
return this.isScanning;
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Enable/disable torch (flashlight)
|
|
96
|
-
*/
|
|
97
|
-
async setTorchEnabled(enabled) {
|
|
98
|
-
try {
|
|
99
|
-
await PDF417Scanner.setTorchEnabled(enabled);
|
|
100
|
-
}
|
|
101
|
-
catch (error) {
|
|
102
|
-
throw new Error(`Failed to set torch: ${error}`);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
50
|
/**
|
|
106
51
|
* Listen for scan results
|
|
107
52
|
*/
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,+CAAkI;AAElI,MAAM,EAAE,aAAa,EAAE,GAAG,4BAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,+CAAkI;AAElI,MAAM,EAAE,aAAa,EAAE,GAAG,4BAAa,CAAC;AAuBxC,+BAA+B;AAClB,QAAA,gBAAgB,GAAG,IAAA,qCAAsB,EAAwB,kBAAkB,CAAC,CAAC;AAElG,MAAM,mBAAmB;IAGvB;QACE,IAAI,CAAC,YAAY,GAAG,IAAI,iCAAkB,CAAC,aAAa,CAAC,CAAC;IAC5D,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,uBAAuB;QAC3B,IAAI,uBAAQ,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;YAC9B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,iCAAkB,CAAC,OAAO,CAC9C,iCAAkB,CAAC,WAAW,CAAC,MAAM,EACrC;gBACE,KAAK,EAAE,mBAAmB;gBAC1B,OAAO,EAAE,sDAAsD;gBAC/D,aAAa,EAAE,cAAc;gBAC7B,cAAc,EAAE,QAAQ;gBACxB,cAAc,EAAE,IAAI;aACrB,CACF,CAAC;YACF,OAAO,OAAO,KAAK,iCAAkB,CAAC,OAAO,CAAC,OAAO,CAAC;QACxD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,0BAA0B,EAAE,GAAG,CAAC,CAAC;YAC9C,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,mBAAmB;QACvB,IAAI,uBAAQ,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;YAC9B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC;YACH,MAAM,aAAa,GAAG,MAAM,iCAAkB,CAAC,KAAK,CAClD,iCAAkB,CAAC,WAAW,CAAC,MAAM,CACtC,CAAC;YACF,OAAO,aAAa,CAAC;QACvB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAC;YAC7C,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,QAA4C;QACvD,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,kBAAkB,EAAE,QAAQ,CAAC,CAAC;QACjF,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;IACrC,CAAC;IAED;;OAEG;IACH,WAAW,CAAC,QAA0C;QACpD,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAAC;QAChF,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;IACrC,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,QAAoB;QAChC,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,mBAAmB,EAAE,QAAQ,CAAC,CAAC;QAClF,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;IACrC,CAAC;CACF;AAED,kBAAe,IAAI,mBAAmB,EAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,283 +0,0 @@
|
|
|
1
|
-
package com.pdf417scanner;
|
|
2
|
-
|
|
3
|
-
import android.app.Activity;
|
|
4
|
-
import android.content.Context;
|
|
5
|
-
import android.graphics.ImageFormat;
|
|
6
|
-
import android.hardware.camera2.CameraAccessException;
|
|
7
|
-
import android.hardware.camera2.CameraCaptureSession;
|
|
8
|
-
import android.hardware.camera2.CameraCharacteristics;
|
|
9
|
-
import android.hardware.camera2.CameraDevice;
|
|
10
|
-
import android.hardware.camera2.CameraManager;
|
|
11
|
-
import android.hardware.camera2.CaptureRequest;
|
|
12
|
-
import android.hardware.camera2.params.StreamConfigurationMap;
|
|
13
|
-
import android.media.Image;
|
|
14
|
-
import android.media.ImageReader;
|
|
15
|
-
import android.os.Handler;
|
|
16
|
-
import android.os.HandlerThread;
|
|
17
|
-
import android.util.Log;
|
|
18
|
-
import android.util.Size;
|
|
19
|
-
import android.view.Surface;
|
|
20
|
-
|
|
21
|
-
import androidx.annotation.NonNull;
|
|
22
|
-
|
|
23
|
-
import com.facebook.react.bridge.ReactApplicationContext;
|
|
24
|
-
import com.google.zxing.BarcodeFormat;
|
|
25
|
-
import com.google.zxing.BinaryBitmap;
|
|
26
|
-
import com.google.zxing.DecodeHintType;
|
|
27
|
-
import com.google.zxing.MultiFormatReader;
|
|
28
|
-
import com.google.zxing.PlanarYUVLuminanceSource;
|
|
29
|
-
import com.google.zxing.Result;
|
|
30
|
-
import com.google.zxing.common.HybridBinarizer;
|
|
31
|
-
|
|
32
|
-
import java.nio.ByteBuffer;
|
|
33
|
-
import java.util.Arrays;
|
|
34
|
-
import java.util.EnumMap;
|
|
35
|
-
import java.util.EnumSet;
|
|
36
|
-
import java.util.Map;
|
|
37
|
-
import java.util.concurrent.Semaphore;
|
|
38
|
-
import java.util.concurrent.TimeUnit;
|
|
39
|
-
|
|
40
|
-
public class PDF417CameraManager {
|
|
41
|
-
private static final String TAG = "PDF417CameraManager";
|
|
42
|
-
|
|
43
|
-
private ReactApplicationContext reactContext;
|
|
44
|
-
private PDF417ScannerModule scannerModule;
|
|
45
|
-
private CameraManager cameraManager;
|
|
46
|
-
private CameraDevice cameraDevice;
|
|
47
|
-
private CameraCaptureSession captureSession;
|
|
48
|
-
private ImageReader imageReader;
|
|
49
|
-
private HandlerThread backgroundThread;
|
|
50
|
-
private Handler backgroundHandler;
|
|
51
|
-
private MultiFormatReader multiFormatReader;
|
|
52
|
-
private Semaphore cameraOpenCloseLock = new Semaphore(1);
|
|
53
|
-
private String cameraId;
|
|
54
|
-
private Size previewSize;
|
|
55
|
-
private boolean isScanning = false;
|
|
56
|
-
private PDF417ScannerConfig config;
|
|
57
|
-
|
|
58
|
-
public PDF417CameraManager(ReactApplicationContext reactContext, PDF417ScannerModule scannerModule) {
|
|
59
|
-
this.reactContext = reactContext;
|
|
60
|
-
this.scannerModule = scannerModule;
|
|
61
|
-
this.cameraManager = (CameraManager) reactContext.getSystemService(Context.CAMERA_SERVICE);
|
|
62
|
-
setupBarcodeReader();
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
private void setupBarcodeReader() {
|
|
66
|
-
multiFormatReader = new MultiFormatReader();
|
|
67
|
-
Map<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class);
|
|
68
|
-
hints.put(DecodeHintType.POSSIBLE_FORMATS, EnumSet.of(BarcodeFormat.PDF_417));
|
|
69
|
-
hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
|
|
70
|
-
multiFormatReader.setHints(hints);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
public void startScanning(PDF417ScannerConfig config) throws Exception {
|
|
74
|
-
this.config = config;
|
|
75
|
-
startBackgroundThread();
|
|
76
|
-
openCamera();
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
public void stopScanning() {
|
|
80
|
-
isScanning = false;
|
|
81
|
-
closeCamera();
|
|
82
|
-
stopBackgroundThread();
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
public void setTorchEnabled(boolean enabled) throws CameraAccessException {
|
|
86
|
-
if (captureSession != null && cameraDevice != null) {
|
|
87
|
-
CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
|
|
88
|
-
builder.addTarget(imageReader.getSurface());
|
|
89
|
-
builder.set(CaptureRequest.FLASH_MODE, enabled ?
|
|
90
|
-
CaptureRequest.FLASH_MODE_TORCH : CaptureRequest.FLASH_MODE_OFF);
|
|
91
|
-
captureSession.setRepeatingRequest(builder.build(), null, backgroundHandler);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
private void startBackgroundThread() {
|
|
96
|
-
backgroundThread = new HandlerThread("CameraBackground");
|
|
97
|
-
backgroundThread.start();
|
|
98
|
-
backgroundHandler = new Handler(backgroundThread.getLooper());
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
private void stopBackgroundThread() {
|
|
102
|
-
if (backgroundThread != null) {
|
|
103
|
-
backgroundThread.quitSafely();
|
|
104
|
-
try {
|
|
105
|
-
backgroundThread.join();
|
|
106
|
-
backgroundThread = null;
|
|
107
|
-
backgroundHandler = null;
|
|
108
|
-
} catch (InterruptedException e) {
|
|
109
|
-
Log.e(TAG, "Error stopping background thread", e);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
private void openCamera() throws Exception {
|
|
115
|
-
if (!cameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
|
|
116
|
-
throw new RuntimeException("Time out waiting to lock camera opening.");
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
try {
|
|
120
|
-
cameraId = selectCamera();
|
|
121
|
-
if (cameraId == null) {
|
|
122
|
-
throw new RuntimeException("No suitable camera found");
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
setupImageReader();
|
|
126
|
-
cameraManager.openCamera(cameraId, stateCallback, backgroundHandler);
|
|
127
|
-
} catch (CameraAccessException e) {
|
|
128
|
-
throw new RuntimeException("Failed to open camera", e);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
private String selectCamera() throws CameraAccessException {
|
|
133
|
-
for (String cameraId : cameraManager.getCameraIdList()) {
|
|
134
|
-
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
|
|
135
|
-
Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
|
|
136
|
-
if (facing != null && facing == CameraCharacteristics.LENS_FACING_BACK) {
|
|
137
|
-
StreamConfigurationMap map = characteristics.get(
|
|
138
|
-
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
|
|
139
|
-
if (map != null) {
|
|
140
|
-
previewSize = chooseOptimalSize(map.getOutputSizes(ImageFormat.YUV_420_888));
|
|
141
|
-
return cameraId;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
return null;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
private Size chooseOptimalSize(Size[] choices) {
|
|
149
|
-
for (Size size : choices) {
|
|
150
|
-
if (size.getWidth() <= 1920 && size.getHeight() <= 1080) {
|
|
151
|
-
return size;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
return choices[0];
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
private void setupImageReader() {
|
|
158
|
-
imageReader = ImageReader.newInstance(previewSize.getWidth(), previewSize.getHeight(),
|
|
159
|
-
ImageFormat.YUV_420_888, 2);
|
|
160
|
-
imageReader.setOnImageAvailableListener(onImageAvailableListener, backgroundHandler);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
|
|
164
|
-
@Override
|
|
165
|
-
public void onOpened(@NonNull CameraDevice camera) {
|
|
166
|
-
cameraOpenCloseLock.release();
|
|
167
|
-
cameraDevice = camera;
|
|
168
|
-
createCameraPreviewSession();
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
@Override
|
|
172
|
-
public void onDisconnected(@NonNull CameraDevice camera) {
|
|
173
|
-
cameraOpenCloseLock.release();
|
|
174
|
-
camera.close();
|
|
175
|
-
cameraDevice = null;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
@Override
|
|
179
|
-
public void onError(@NonNull CameraDevice camera, int error) {
|
|
180
|
-
cameraOpenCloseLock.release();
|
|
181
|
-
camera.close();
|
|
182
|
-
cameraDevice = null;
|
|
183
|
-
scannerModule.onScanError("CAMERA_ERROR", "Camera error: " + error);
|
|
184
|
-
}
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
private void createCameraPreviewSession() {
|
|
188
|
-
try {
|
|
189
|
-
CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
|
|
190
|
-
builder.addTarget(imageReader.getSurface());
|
|
191
|
-
|
|
192
|
-
if (config.isEnableAutoFocus()) {
|
|
193
|
-
builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
cameraDevice.createCaptureSession(Arrays.asList(imageReader.getSurface()),
|
|
197
|
-
new CameraCaptureSession.StateCallback() {
|
|
198
|
-
@Override
|
|
199
|
-
public void onConfigured(@NonNull CameraCaptureSession session) {
|
|
200
|
-
if (cameraDevice == null) return;
|
|
201
|
-
|
|
202
|
-
captureSession = session;
|
|
203
|
-
try {
|
|
204
|
-
session.setRepeatingRequest(builder.build(), null, backgroundHandler);
|
|
205
|
-
isScanning = true;
|
|
206
|
-
scannerModule.onCameraReady();
|
|
207
|
-
} catch (CameraAccessException e) {
|
|
208
|
-
Log.e(TAG, "Error starting camera preview", e);
|
|
209
|
-
scannerModule.onScanError("CAMERA_ERROR", "Failed to start preview");
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
@Override
|
|
214
|
-
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
|
|
215
|
-
scannerModule.onScanError("CAMERA_ERROR", "Failed to configure camera");
|
|
216
|
-
}
|
|
217
|
-
}, null);
|
|
218
|
-
} catch (CameraAccessException e) {
|
|
219
|
-
Log.e(TAG, "Error creating camera preview session", e);
|
|
220
|
-
scannerModule.onScanError("CAMERA_ERROR", "Failed to create preview session");
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
private final ImageReader.OnImageAvailableListener onImageAvailableListener =
|
|
225
|
-
new ImageReader.OnImageAvailableListener() {
|
|
226
|
-
@Override
|
|
227
|
-
public void onImageAvailable(ImageReader reader) {
|
|
228
|
-
if (!isScanning) return;
|
|
229
|
-
|
|
230
|
-
Image image = reader.acquireLatestImage();
|
|
231
|
-
if (image != null) {
|
|
232
|
-
try {
|
|
233
|
-
processImage(image);
|
|
234
|
-
} finally {
|
|
235
|
-
image.close();
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
};
|
|
240
|
-
|
|
241
|
-
private void processImage(Image image) {
|
|
242
|
-
try {
|
|
243
|
-
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
|
|
244
|
-
byte[] data = new byte[buffer.remaining()];
|
|
245
|
-
buffer.get(data);
|
|
246
|
-
|
|
247
|
-
PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(
|
|
248
|
-
data, image.getWidth(), image.getHeight(), 0, 0,
|
|
249
|
-
image.getWidth(), image.getHeight(), false);
|
|
250
|
-
|
|
251
|
-
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
|
|
252
|
-
Result result = multiFormatReader.decode(bitmap);
|
|
253
|
-
|
|
254
|
-
if (result != null) {
|
|
255
|
-
scannerModule.onScanResult(result.getText(), result.getBarcodeFormat().toString());
|
|
256
|
-
}
|
|
257
|
-
} catch (Exception e) {
|
|
258
|
-
// No barcode found, continue scanning
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
private void closeCamera() {
|
|
263
|
-
try {
|
|
264
|
-
cameraOpenCloseLock.acquire();
|
|
265
|
-
if (captureSession != null) {
|
|
266
|
-
captureSession.close();
|
|
267
|
-
captureSession = null;
|
|
268
|
-
}
|
|
269
|
-
if (cameraDevice != null) {
|
|
270
|
-
cameraDevice.close();
|
|
271
|
-
cameraDevice = null;
|
|
272
|
-
}
|
|
273
|
-
if (imageReader != null) {
|
|
274
|
-
imageReader.close();
|
|
275
|
-
imageReader = null;
|
|
276
|
-
}
|
|
277
|
-
} catch (InterruptedException e) {
|
|
278
|
-
throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
|
|
279
|
-
} finally {
|
|
280
|
-
cameraOpenCloseLock.release();
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
package com.pdf417scanner;
|
|
2
|
-
|
|
3
|
-
public class PDF417ScannerConfig {
|
|
4
|
-
private boolean enableAutoFocus = true;
|
|
5
|
-
private boolean enableTorch = false;
|
|
6
|
-
private int scanTimeout = 30000; // 30 seconds
|
|
7
|
-
private boolean enableBeep = true;
|
|
8
|
-
private boolean enableVibration = true;
|
|
9
|
-
|
|
10
|
-
public boolean isEnableAutoFocus() {
|
|
11
|
-
return enableAutoFocus;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
public void setEnableAutoFocus(boolean enableAutoFocus) {
|
|
15
|
-
this.enableAutoFocus = enableAutoFocus;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
public boolean isEnableTorch() {
|
|
19
|
-
return enableTorch;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
public void setEnableTorch(boolean enableTorch) {
|
|
23
|
-
this.enableTorch = enableTorch;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
public int getScanTimeout() {
|
|
27
|
-
return scanTimeout;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
public void setScanTimeout(int scanTimeout) {
|
|
31
|
-
this.scanTimeout = scanTimeout;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
public boolean isEnableBeep() {
|
|
35
|
-
return enableBeep;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
public void setEnableBeep(boolean enableBeep) {
|
|
39
|
-
this.enableBeep = enableBeep;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
public boolean isEnableVibration() {
|
|
43
|
-
return enableVibration;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
public void setEnableVibration(boolean enableVibration) {
|
|
47
|
-
this.enableVibration = enableVibration;
|
|
48
|
-
}
|
|
49
|
-
}
|