I know that you can use AVFoundation
to scan a QR code using the device's camera. Now here comes the problem, how can I do this from an static UIImage
object?
While you can use your camera to scan QR codes that aren't on your phone, you'll need to install an app to read QR codes from existing pictures. Fortunately, the best QR code apps are free and super easy to use!
Can Static QR Code be edited or redirected to a new URL? Unfortunately, Static QR Codes can't be edited or redirected to a new URL once they are finalized. This is why we recommend choosing a Dynamic QR Code solution so that there is always the option to update the content later.
Swift 4 version of @Neimsz's answer
func detectQRCode(_ image: UIImage?) -> [CIFeature]? { if let image = image, let ciImage = CIImage.init(image: image){ var options: [String: Any] let context = CIContext() options = [CIDetectorAccuracy: CIDetectorAccuracyHigh] let qrDetector = CIDetector(ofType: CIDetectorTypeQRCode, context: context, options: options) if ciImage.properties.keys.contains((kCGImagePropertyOrientation as String)){ options = [CIDetectorImageOrientation: ciImage.properties[(kCGImagePropertyOrientation as String)] ?? 1] } else { options = [CIDetectorImageOrientation: 1] } let features = qrDetector?.features(in: ciImage, options: options) return features } return nil }
How to use
if let features = detectQRCode(#imageLiteral(resourceName: "qrcode")), !features.isEmpty{ for case let row as CIQRCodeFeature in features{ print(row.messageString ?? "nope") } }
And during the execution this doesn't produce the Finalizing CVPixelBuffer 0x170133e20 while lock count is 1
I used the following QRCode Image (QRCode = https://jingged.com)
(Tested on iPhone 6 simulator with iOS version 11.2)
Output:
2018-03-14 15:31:13.159400+0530 TestProject[25889:233062] [MC] Lazy loading NSBundle MobileCoreServices.framework 2018-03-14 15:31:13.160302+0530 TestProject[25889:233062] [MC] Loaded MobileCoreServices.framework https://jingged.com
The iOS API provides the CIDetector class from CoreImage framework. CIDetector let you find specific patterns in images, like faces, smiles, eyes, or in our case : QRCodes.
Here is the code to detect a QRCode from an UIImage in Objective-C:
-(NSArray *)detectQRCode:(UIImage *) image { @autoreleasepool { NSLog(@"%@ :: %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); NSCAssert(image != nil, @"**Assertion Error** detectQRCode : image is nil"); CIImage* ciImage = image.CIImage; // assuming underlying data is a CIImage //CIImage* ciImage = [[CIImage alloc] initWithCGImage: image.CGImage]; // to use if the underlying data is a CGImage NSDictionary* options; CIContext* context = [CIContext context]; options = @{ CIDetectorAccuracy : CIDetectorAccuracyHigh }; // Slow but thorough //options = @{ CIDetectorAccuracy : CIDetectorAccuracyLow}; // Fast but superficial CIDetector* qrDetector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:context options:options]; if ([[ciImage properties] valueForKey:(NSString*) kCGImagePropertyOrientation] == nil) { options = @{ CIDetectorImageOrientation : @1}; } else { options = @{ CIDetectorImageOrientation : [[ciImage properties] valueForKey:(NSString*) kCGImagePropertyOrientation]}; } NSArray * features = [qrDetector featuresInImage:ciImage options:options]; return features; } }
The returned NSArray*
will contain CIFeature*
if a QRCode is present and detected. If there was no QRCode, the NSArray*
will be nil
. If the QRCode decoding fails, the NSArray*
will have no element.
To obtain the encoded string :
if (features != nil && features.count > 0) { for (CIQRCodeFeature* qrFeature in features) { NSLog(@"QRFeature.messageString : %@ ", qrFeature.messageString); } }
As in the answer of @Duncan-C, you can then extract QRCode corners and draw an enclosing bounding box of the QRCode on the image.
Note : Under iOS10.0 beta 6, the call to [qrDetector featuresInImage:ciImage options:options]
when using images coming from the cameraSampleBuffer logs this internal warning (it runs smoothly but spam the console with this message, and I could not find a way to get rid of it for now):
Finalizing CVPixelBuffer 0x170133e20 while lock count is 1.
Source :
Apple Dev API Reference - CIDetector
Apple Dev API Programming guide - Face detection
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With