Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ The following barcode types are currently supported:
* AZTEC
* PDF417

`success` and `fail` are callback functions. Success is passed an object with data, type and cancelled properties. Data is the text representation of the barcode data, type is the type of barcode detected and cancelled is whether or not the user cancelled the scan.
`success` and `fail` are callback functions. Success is passed an object with data, type and cancelled properties. Data is the text representation of the barcode data, type is the type of barcode detected and cancelled is whether or not the user cancelled the scan. In iOS you also get the successfully last-scanned image as base64 string in the success callback.

A full example could be:
```
Expand All @@ -96,6 +96,11 @@ A full example could be:
"Result: " + result.text + "\n" +
"Format: " + result.format + "\n" +
"Cancelled: " + result.cancelled);

// Use image in which the code was recognized in DOM
var scanImage = document.querySelector("#scanImage");
scanImage.setAttribute( 'src', result.scanImage );

},
function (error) {
alert("Scanning failed: " + error);
Expand Down
111 changes: 79 additions & 32 deletions src/ios/CDVBarcodeScanner.mm
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ @interface CDVBarcodeScanner : CDVPlugin {}
- (NSString*)isScanNotPossible;
- (void)scan:(CDVInvokedUrlCommand*)command;
- (void)encode:(CDVInvokedUrlCommand*)command;
- (void)returnSuccess:(NSString*)scannedText format:(NSString*)format cancelled:(BOOL)cancelled flipped:(BOOL)flipped callback:(NSString*)callback;
- (void)returnSuccess:(NSString*)scannedText format:(NSString*)format scanImage:(NSString*)imageBase64 cancelled:(BOOL)cancelled flipped:(BOOL)flipped callback:(NSString*)callback;
- (void)returnError:(NSString*)message callback:(NSString*)callback;
@end

Expand All @@ -72,7 +72,7 @@ @interface CDVbcsProcessor : NSObject <AVCaptureVideoDataOutputSampleBufferDeleg

- (id)initWithPlugin:(CDVBarcodeScanner*)plugin callback:(NSString*)callback parentViewController:(UIViewController*)parentViewController alterateOverlayXib:(NSString *)alternateXib;
- (void)scanBarcode;
- (void)barcodeScanSucceeded:(NSString*)text format:(NSString*)format;
- (void)barcodeScanSucceeded:(NSString*)text format:(NSString*)format scanImage:(NSString*)imageBase64;
- (void)barcodeScanFailed:(NSString*)message;
- (void)barcodeScanCancelled;
- (void)openDialog;
Expand Down Expand Up @@ -162,12 +162,13 @@ - (void)encode:(CDVInvokedUrlCommand*)command {
}

//--------------------------------------------------------------------------
- (void)returnSuccess:(NSString*)scannedText format:(NSString*)format cancelled:(BOOL)cancelled flipped:(BOOL)flipped callback:(NSString*)callback{
- (void)returnSuccess:(NSString*)scannedText format:(NSString*)format scanImage:(NSString*)imageBase64 cancelled:(BOOL)cancelled flipped:(BOOL)flipped callback:(NSString*)callback{
NSNumber* cancelledNumber = [NSNumber numberWithInt:(cancelled?1:0)];

NSMutableDictionary* resultDict = [[[NSMutableDictionary alloc] init] autorelease];
[resultDict setObject:scannedText forKey:@"text"];
[resultDict setObject:format forKey:@"format"];
[resultDict setObject:imageBase64 forKey:@"scanImage"];
[resultDict setObject:cancelledNumber forKey:@"cancelled"];

CDVPluginResult* result = [CDVPluginResult
Expand Down Expand Up @@ -288,9 +289,9 @@ - (void)barcodeScanDone {
}

//--------------------------------------------------------------------------
- (void)barcodeScanSucceeded:(NSString*)text format:(NSString*)format {
- (void)barcodeScanSucceeded:(NSString*)text format:(NSString*)format scanImage:(NSString*)imageBase64 {
[self barcodeScanDone];
[self.plugin returnSuccess:text format:format cancelled:FALSE flipped:FALSE callback:self.callback];
[self.plugin returnSuccess:text format:format scanImage:imageBase64 cancelled:FALSE flipped:FALSE callback:self.callback];
}

//--------------------------------------------------------------------------
Expand All @@ -302,7 +303,7 @@ - (void)barcodeScanFailed:(NSString*)message {
//--------------------------------------------------------------------------
- (void)barcodeScanCancelled {
[self barcodeScanDone];
[self.plugin returnSuccess:@"" format:@"" cancelled:TRUE flipped:self.isFlipped callback:self.callback];
[self.plugin returnSuccess:@"" format:@"" scanImage:@"" cancelled:TRUE flipped:self.isFlipped callback:self.callback];
if (self.isFlipped) {
self.isFlipped = NO;
}
Expand Down Expand Up @@ -338,8 +339,8 @@ - (NSString*)setUpCaptureSession {
if (!device) return @"unable to obtain video capture device";

}



AVCaptureDeviceInput* input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
if (!input) return @"unable to obtain video capture device input";

Expand Down Expand Up @@ -392,6 +393,11 @@ - (void)captureOutput:(AVCaptureOutput*)captureOutput didOutputSampleBuffer:(CMS

if (!self.capturing) return;

// Important: set orientation of AVCaptureCOnnection to that of the device
if ([connection isVideoOrientationSupported]) {
[connection setVideoOrientation:[[UIDevice currentDevice] orientation]];
}

#if USE_SHUTTER
if (!self.viewController.shutterPressed) return;
self.viewController.shutterPressed = NO;
Expand All @@ -410,10 +416,13 @@ - (void)captureOutput:(AVCaptureOutput*)captureOutput didOutputSampleBuffer:(CMS
}
];

// [self dumpImage: [[self getImageFromSample:sampleBuffer] autorelease]];
// [self dumpImage: [[self getImageFromSample:sampleBuffer] autorelease]];
#endif



// Canvas Part: Outputs the image stream to Javascript
//NSString *javascript = @"CanvasCamera.capture('');";
//[self.plugin.webView performSelectorOnMainThread:@selector(stringByEvaluatingJavaScriptFromString:) withObject:javascript waitUntilDone:YES];

using namespace zxing;

// LuminanceSource is pretty dumb; we have to give it a pointer to
Expand Down Expand Up @@ -450,7 +459,16 @@ - (void)captureOutput:(AVCaptureOutput*)captureOutput didOutputSampleBuffer:(CMS
const char* cString = resultText->getText().c_str();
NSString* resultString = [[[NSString alloc] initWithCString:cString encoding:NSUTF8StringEncoding] autorelease];

[self barcodeScanSucceeded:resultString format:format];
//DEBUG: Dump succeeded image to Photos
//UIImage *image= [[self getImageFromSample:sampleBuffer] autorelease];
//[self dumpImage: image];

// Write base64 to Javascript
UIImage *image= [[self getImageFromSample:sampleBuffer] autorelease];
NSString *imageBase64 = @"data:image/jpeg;base64,";
imageBase64 = [imageBase64 stringByAppendingString:[UIImagePNGRepresentation(image) base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]];

[self barcodeScanSucceeded:resultString format:format scanImage:imageBase64];

}
catch (zxing::ReaderException &rex) {
Expand Down Expand Up @@ -488,6 +506,11 @@ - (NSString*)formatStringFrom:(zxing::BarcodeFormat)format {
if (format == zxing::BarcodeFormat_CODE_128) return @"CODE_128";
if (format == zxing::BarcodeFormat_CODE_39) return @"CODE_39";
if (format == zxing::BarcodeFormat_ITF) return @"ITF";
if (format == zxing::BarcodeFormat_GS1_DATA_MATRIX) return @"GS1_DATA_MATRIX";
if (format == zxing::BarcodeFormat_GS1_QR_CODE) return @"GS1_QR_CODE";
if (format == zxing::BarcodeFormat_GS1_128) return @"GS1_128";
if (format == zxing::BarcodeFormat_GS1_DATA_BAR) return @"GS1_DATA_BAR";
if (format == zxing::BarcodeFormat_GS1_COMPOSITE) return @"GS1_COMPOSITE";
return @"???";
}

Expand Down Expand Up @@ -579,6 +602,7 @@ - (UIImage*) getImageFromLuminanceSource:(zxing::LuminanceSource*)luminanceSourc
// for debugging
//--------------------------------------------------------------------------
- (UIImage*)getImageFromSample:(CMSampleBufferRef)sampleBuffer {

CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
CVPixelBufferLockBaseAddress(imageBuffer, 0);

Expand All @@ -593,6 +617,7 @@ - (UIImage*)getImageFromSample:(CMSampleBufferRef)sampleBuffer {
baseAddress = newBaseAddress;

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

CGContextRef context = CGBitmapContextCreate(
baseAddress,
width, height, 8, bytesPerRow,
Expand Down Expand Up @@ -824,7 +849,8 @@ - (UIView*)buildOverlayView {
#define RETICLE_SIZE 500.0f
#define RETICLE_WIDTH 10.0f
#define RETICLE_OFFSET 60.0f
#define RETICLE_ALPHA 0.4f
#define RETICLE_ALPHA 1.0f
#define RADIUS 75

//-------------------------------------------------------------------------
// builds the green box and red line
Expand All @@ -833,30 +859,51 @@ - (UIImage*)buildReticleImage {
UIImage* result;
UIGraphicsBeginImageContext(CGSizeMake(RETICLE_SIZE, RETICLE_SIZE));
CGContextRef context = UIGraphicsGetCurrentContext();

if (self.processor.is1D) {
UIColor* color = [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:RETICLE_ALPHA];
CGContextSetStrokeColorWithColor(context, color.CGColor);
CGContextSetLineWidth(context, RETICLE_WIDTH);
CGContextBeginPath(context);
CGFloat lineOffset = RETICLE_OFFSET+(0.5*RETICLE_WIDTH);
CGContextMoveToPoint(context, lineOffset, RETICLE_SIZE/2);
CGContextAddLineToPoint(context, RETICLE_SIZE-lineOffset, 0.5*RETICLE_SIZE);
CGContextStrokePath(context);
}

// Cross line
// if (self.processor.is1D) {
// UIColor* color = [UIColor colorWithRed:0 green:0.55 blue:0.72 alpha:RETICLE_ALPHA];
// CGContextSetStrokeColorWithColor(context, color.CGColor);
// CGContextSetLineWidth(context, RETICLE_WIDTH);
// CGContextBeginPath(context);
// CGFloat lineOffset = RETICLE_OFFSET+(0.5*RETICLE_WIDTH);
// CGContextMoveToPoint(context, lineOffset, RETICLE_SIZE/2);
// CGContextAddLineToPoint(context, RETICLE_SIZE-lineOffset, 0.5*RETICLE_SIZE);
// CGContextStrokePath(context);
// }

if (self.processor.is2D) {
UIColor* color = [UIColor colorWithRed:0.0 green:1.0 blue:0.0 alpha:RETICLE_ALPHA];
UIColor* color = [UIColor colorWithRed:0.0 green:0.55 blue:0.72 alpha:RETICLE_ALPHA];
CGContextSetStrokeColorWithColor(context, color.CGColor);
CGContextSetLineWidth(context, RETICLE_WIDTH);
CGContextStrokeRect(context,
CGRectMake(
RETICLE_OFFSET,
RETICLE_OFFSET,
RETICLE_SIZE-2*RETICLE_OFFSET,
RETICLE_SIZE-2*RETICLE_OFFSET
)
);

// No filling
[[UIColor clearColor] setFill];

// rechts unten
CGContextMoveToPoint(context, RETICLE_SIZE - 3*RETICLE_OFFSET, RETICLE_SIZE - RETICLE_OFFSET);
//CGContextAddLineToPoint(context, RETICLE_SIZE-RETICLE_OFFSET, RETICLE_SIZE - RETICLE_OFFSET);
CGContextAddArcToPoint(context, RETICLE_SIZE-RETICLE_OFFSET, RETICLE_SIZE - RETICLE_OFFSET, RETICLE_SIZE - RETICLE_OFFSET, RETICLE_OFFSET, RADIUS);
CGContextAddLineToPoint(context, RETICLE_SIZE-RETICLE_OFFSET, RETICLE_SIZE - 3*RETICLE_OFFSET);
CGContextDrawPath(context, kCGPathFillStroke);

// rechts oben
CGContextMoveToPoint(context, RETICLE_SIZE - RETICLE_OFFSET, 3*RETICLE_OFFSET);
CGContextAddArcToPoint(context, RETICLE_SIZE - RETICLE_OFFSET, RETICLE_OFFSET, RETICLE_OFFSET, RETICLE_OFFSET, RADIUS);
CGContextAddLineToPoint(context, RETICLE_SIZE-3*RETICLE_OFFSET, RETICLE_OFFSET);
CGContextDrawPath(context, kCGPathFillStroke);

// links oben
CGContextMoveToPoint(context, 3*RETICLE_OFFSET, RETICLE_OFFSET);
CGContextAddArcToPoint(context, RETICLE_OFFSET, RETICLE_OFFSET, RETICLE_OFFSET, 2*RETICLE_OFFSET, RADIUS);
CGContextAddLineToPoint(context, RETICLE_OFFSET, 3*RETICLE_OFFSET);
CGContextDrawPath(context, kCGPathFillStroke);

// links unten
CGContextMoveToPoint(context, RETICLE_OFFSET, RETICLE_SIZE - 3*RETICLE_OFFSET);
CGContextAddArcToPoint(context, RETICLE_OFFSET, RETICLE_SIZE - RETICLE_OFFSET, 3*RETICLE_OFFSET, RETICLE_SIZE - RETICLE_OFFSET, RADIUS);
CGContextAddLineToPoint(context, 3*RETICLE_OFFSET, RETICLE_SIZE - RETICLE_OFFSET);
CGContextDrawPath(context, kCGPathFillStroke);
}

result = UIGraphicsGetImageFromCurrentImageContext();
Expand Down
33 changes: 28 additions & 5 deletions src/ios/zxing-all-in-one.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,12 @@ const char *barcodeFormatNames[] = {
"EAN_13",
"CODE_128",
"CODE_39",
"ITF"
"ITF",
"GS1_DATA_MATRIX",
"GS1_QR_CODE",
"GS1_128",
"GS1_DATA_BAR",
"GS1_COMPOSITE"
};

}
Expand Down Expand Up @@ -222,6 +227,11 @@ void DecodeHints::addFormat(BarcodeFormat toadd) {
case BarcodeFormat_CODE_128: hints |= BARCODEFORMAT_CODE_128_HINT; break;
case BarcodeFormat_CODE_39: hints |= BARCODEFORMAT_CODE_39_HINT; break;
case BarcodeFormat_ITF: hints |= BARCODEFORMAT_ITF_HINT; break;
// case BarcodeFormat_GS1_DATA_MATRIX: hints |= BarcodeFormat_GS1_DATA_MATRIX; break;
// case BarcodeFormat_GS1_QR_CODE: hints |= BarcodeFormat_GS1_QR_CODE; break;
// case BarcodeFormat_GS1_128: hints |= BarcodeFormat_GS1_128; break;
// case BarcodeFormat_GS1_DATA_BAR: hints |= BarcodeFormat_GS1_DATA_BAR; break;
// case BarcodeFormat_GS1_COMPOSITE: hints |= BarcodeFormat_GS1_COMPOSITE; break;
default: throw IllegalArgumentException("Unrecognizd barcode format");
}
}
Expand All @@ -238,6 +248,11 @@ bool DecodeHints::containsFormat(BarcodeFormat tocheck) const {
case BarcodeFormat_CODE_128: checkAgainst = BARCODEFORMAT_CODE_128_HINT; break;
case BarcodeFormat_CODE_39: checkAgainst = BARCODEFORMAT_CODE_39_HINT; break;
case BarcodeFormat_ITF: checkAgainst = BARCODEFORMAT_ITF_HINT; break;
// case BarcodeFormat_GS1_DATA_MATRIX: checkAgainst = BARCODEFORMAT_GS1_DATA_MATRIX_HINT; break;
// case BarcodeFormat_GS1_QR_CODE: checkAgainst = BARCODEFORMAT_GS1_QR_CODE_HINT; break;
// case BarcodeFormat_GS1_128: checkAgainst = BARCODEFORMAT_GS1_128_HINT; break;
// case BarcodeFormat_GS1_DATA_BAR: checkAgainst = BARCODEFORMAT_GS1_DATA_BAR_HINT; break;
// case BarcodeFormat_GS1_COMPOSITE: checkAgainst = BARCODEFORMAT_GS1_COMPOSITE_HINT; break;
default: throw IllegalArgumentException("Unrecognizd barcode format");
}
return (hints & checkAgainst);
Expand Down Expand Up @@ -3877,9 +3892,17 @@ Ref<Result> DataMatrixReader::decode(Ref<BinaryBitmap> image, DecodeHints hints)
#ifdef DEBUG
cout << "(4) decoded, have decoderResult " << decoderResult.object_ << "\n" << flush;
#endif

Ref<Result> result(
new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat_DATA_MATRIX));

Ref<Result> result;
result = new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat_DATA_MATRIX);

// Detect GS1 Codes
switch (decoderResult->getRawBytes()[0]) {
case 232:
result = new Result(decoderResult->getText(), decoderResult->getRawBytes(), points, BarcodeFormat_GS1_DATA_MATRIX);
break;
}

#ifdef DEBUG
cout << "(5) created result " << result.object_ << ", returning\n" << flush;
#endif
Expand Down Expand Up @@ -4783,7 +4806,7 @@ void DecodedBitStreamParser::decodeC40Segment(Ref<BitSource> bits, ostringstream
result << C40_SHIFT2_SET_CHARS[cValue];
}
} else if (cValue == 27) { // FNC1
result << ((char) 29); // translate as ASCII 29
result << ((char) 29); // translate as ASCII 29
} else if (cValue == 30) { // Upper Shift
upperShift = true;
} else {
Expand Down
16 changes: 13 additions & 3 deletions src/ios/zxing-all-in-one.h
Original file line number Diff line number Diff line change
Expand Up @@ -1743,9 +1743,14 @@ namespace zxing {
BarcodeFormat_EAN_13,
BarcodeFormat_CODE_128,
BarcodeFormat_CODE_39,
BarcodeFormat_ITF
BarcodeFormat_ITF,
BarcodeFormat_GS1_DATA_MATRIX,
BarcodeFormat_GS1_QR_CODE,
BarcodeFormat_GS1_128,
BarcodeFormat_GS1_DATA_BAR,
BarcodeFormat_GS1_COMPOSITE
} BarcodeFormat;

/* if you update the enum, please update the name in BarcodeFormat.cpp */
extern const char *barcodeFormatNames[];
}
Expand Down Expand Up @@ -1903,9 +1908,14 @@ class DecodeHints {
static const DecodeHintType BARCODEFORMAT_CODE_128_HINT = 1 << BarcodeFormat_CODE_128;
static const DecodeHintType BARCODEFORMAT_CODE_39_HINT = 1 << BarcodeFormat_CODE_39;
static const DecodeHintType BARCODEFORMAT_ITF_HINT = 1 << BarcodeFormat_ITF;
// static const DecodeHintType BARCODEFORMAT_GS1_DATA_MATRIX_HINT = 1 << BarcodeFormat_GS1_DATA_MATRIX;
// static const DecodeHintType BARCODEFORMAT_GS1_QR_CODE_HINT = 1 << BarcodeFormat_GS1_QR_CODE;
// static const DecodeHintType BARCODEFORMAT_GS1_128_HINT = 1 << BarcodeFormat_GS1_128;
// static const DecodeHintType BARCODEFORMAT_GS1_DATA_BAR_HINT = 1 << BarcodeFormat_GS1_DATA_BAR;
// static const DecodeHintType BARCODEFORMAT_GS1_COMPOSITE_HINT = 1 << BarcodeFormat_GS1_COMPOSITE;
static const DecodeHintType CHARACTER_SET = 1 << 30;
static const DecodeHintType TRYHARDER_HINT = 1 << 31;

static const DecodeHints PRODUCT_HINT;
static const DecodeHints ONED_HINT;
static const DecodeHints DEFAULT_HINT;
Expand Down
2 changes: 1 addition & 1 deletion www/barcodescanner.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
* }
* @param {Function} errorCallback
*/
BarcodeScanner.prototype.scan = function (successCallback, errorCallback) {
BarcodeScanner.prototype.scan = function (successCallback, errorCallback) {
if (errorCallback == null) {
errorCallback = function () {
};
Expand Down