Skip to content
This repository was archived by the owner on Jun 16, 2023. It is now read-only.

Commit d69d28b

Browse files
cozmon1ru4l
authored andcommitted
feat(qr-code): return raw barcode data if available (#1904)
1 parent f6f9f29 commit d69d28b

File tree

4 files changed

+66
-19
lines changed

4 files changed

+66
-19
lines changed

android/src/main/java/org/reactnative/camera/events/BarCodeReadEvent.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import com.google.zxing.ResultPoint;
1313

1414
import java.util.Date;
15+
import java.util.Formatter;
1516

1617
public class BarCodeReadEvent extends Event<BarCodeReadEvent> {
1718
private static final Pools.SynchronizedPool<BarCodeReadEvent> EVENTS_POOL =
@@ -68,6 +69,14 @@ private WritableMap serializeEventData() {
6869

6970
event.putInt("target", getViewTag());
7071
event.putString("data", mBarCode.getText());
72+
73+
Formatter formatter = new Formatter();
74+
for (byte b : mBarCode.getRawBytes()) {
75+
formatter.format("%02x", b);
76+
}
77+
event.putString("rawData", formatter.toString());
78+
formatter.close();
79+
7180
event.putString("type", mBarCode.getBarcodeFormat().toString());
7281
WritableArray resultPoints = Arguments.createArray();
7382
ResultPoint[] points = mBarCode.getResultPoints();

docs/RNCamera.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,10 @@ Function to be called when native code emit onPictureTaken event, when camera ha
319319

320320
Will call the specified method when a barcode is detected in the camera's view.
321321

322-
Event contains `data` (the data in the barcode) and `type` (the type of the barcode detected).
322+
Event contains the following fields
323+
- `data` - a textual representation of the barcode, if available
324+
- `rawData` - The raw data encoded in the barcode, if available
325+
- `type` - the type of the barcode detected
323326

324327
The following barcode types can be recognised:
325328

@@ -337,8 +340,6 @@ The following barcode types can be recognised:
337340
- `itf14` (when available)
338341
- `datamatrix` (when available)
339342

340-
The barcode type is provided in the `data` object.
341-
342343

343344
#### `barCodeTypes`
344345

ios/RN/RNCamera.m

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -869,22 +869,58 @@ - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:
869869
for (id barcodeType in self.barCodeTypes) {
870870
if ([metadata.type isEqualToString:barcodeType]) {
871871
AVMetadataMachineReadableCodeObject *transformed = (AVMetadataMachineReadableCodeObject *)[_previewLayer transformedMetadataObjectForMetadataObject:metadata];
872-
NSDictionary *event = @{
873-
@"type" : codeMetadata.type,
874-
@"data" : codeMetadata.stringValue,
875-
@"bounds": @{
876-
@"origin": @{
877-
@"x": [NSString stringWithFormat:@"%f", transformed.bounds.origin.x],
878-
@"y": [NSString stringWithFormat:@"%f", transformed.bounds.origin.y]
879-
},
880-
@"size": @{
881-
@"height": [NSString stringWithFormat:@"%f", transformed.bounds.size.height],
882-
@"width": [NSString stringWithFormat:@"%f", transformed.bounds.size.width]
883-
}
884-
}
885-
};
886-
887-
[self onCodeRead:event];
872+
NSMutableDictionary *event = [NSMutableDictionary dictionaryWithDictionary:@{
873+
@"type" : codeMetadata.type,
874+
@"data" : [NSNull null],
875+
@"rawData" : [NSNull null],
876+
@"bounds": @{
877+
@"origin": @{
878+
@"x": [NSString stringWithFormat:@"%f", transformed.bounds.origin.x],
879+
@"y": [NSString stringWithFormat:@"%f", transformed.bounds.origin.y]
880+
},
881+
@"size": @{
882+
@"height": [NSString stringWithFormat:@"%f", transformed.bounds.size.height],
883+
@"width": [NSString stringWithFormat:@"%f", transformed.bounds.size.width]
884+
}
885+
}
886+
}
887+
];
888+
889+
NSData *rawData;
890+
// If we're on ios11 then we can use `descriptor` to access the raw data of the barcode.
891+
// If we're on an older version of iOS we're stuck using valueForKeyPath to peak at the
892+
// data.
893+
if (@available(iOS 11, *)) {
894+
// descriptor is a CIBarcodeDescriptor which is an abstract base class with no useful fields.
895+
// in practice it's a subclass, many of which contain errorCorrectedPayload which is the data we
896+
// want. Instead of individually checking the class types, just duck type errorCorrectedPayload
897+
if ([codeMetadata.descriptor respondsToSelector:@selector(errorCorrectedPayload)]) {
898+
rawData = [codeMetadata.descriptor performSelector:@selector(errorCorrectedPayload)];
899+
}
900+
} else {
901+
rawData = [codeMetadata valueForKeyPath:@"_internal.basicDescriptor.BarcodeRawData"];
902+
}
903+
904+
// Now that we have the raw data of the barcode translate it into a hex string to pass to the JS
905+
const unsigned char *dataBuffer = (const unsigned char *)[rawData bytes];
906+
if (dataBuffer) {
907+
NSMutableString *rawDataHexString = [NSMutableString stringWithCapacity:([rawData length] * 2)];
908+
for (int i = 0; i < [rawData length]; ++i) {
909+
[rawDataHexString appendString:[NSString stringWithFormat:@"%02lx", (unsigned long)dataBuffer[i]]];
910+
}
911+
[event setObject:[NSString stringWithString:rawDataHexString] forKey:@"rawData"];
912+
}
913+
914+
// If we were able to extract a string representation of the barcode, attach it to the event as well
915+
// else just send null along.
916+
if (codeMetadata.stringValue) {
917+
[event setObject:codeMetadata.stringValue forKey:@"data"];
918+
}
919+
920+
// Only send the event if we were able to pull out a binary or string representation
921+
if ([event objectForKey:@"data"] != [NSNull null] || [event objectForKey:@"rawData"] != [NSNull null]) {
922+
[self onCodeRead:event];
923+
}
888924
}
889925
}
890926
}

types/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ export interface RNCameraProps {
8989
googleVisionBarcodeType?: keyof GoogleVisionBarcodeType;
9090
onBarCodeRead?(event: {
9191
data: string,
92+
rawData?: string,
9293
type: keyof BarCodeType,
9394
/**
9495
* @description For Android use `[Point<string>, Point<string>]`

0 commit comments

Comments
 (0)