15

Is it possible to read a binary encoded QR Code with AVFoundation?

I can get a AVMetadataMachineReadableCodeObject object of .type AVMetadataObjectTypeQRCode, however this only has a stringValue property, which won't work, because the data contained in the QR Code can't be converted to a string friendly representation.

Should I use ZXing instead?

Thanks.

Halil Ozel
  • 2,482
  • 3
  • 17
  • 32
Michael Bates
  • 1,884
  • 2
  • 29
  • 40

4 Answers4

8

The raw data does exist in your AVMetadataMachineReadableCodeObject, but it's not available through a public getter.

However, you can use KVO to extract it, but Apple might reject your app. Also, future iOS versions might change their private APIs and your code could become invalid (because of the hardcoded private keys).

Swift:

readableCodeObject.valueForKeyPath("_internal.basicDescriptor")!["BarcodeRawData"]

Objective-C

[readableCodeObject valueForKeyPath:@"_internal.basicDescriptor"][@"BarcodeRawData"];

I tested this for iOS 8 and 9.

Alexandru Motoc
  • 582
  • 7
  • 14
  • This worked for me, but the result is of type `AnyObject`. Can I cast this to a type that is more usable? What is the type of the data contained in the Object? – oelna May 10 '16 at 21:14
  • 2
    In Swift you can use `readableCodeObject.valueForKeyPath("_internal.basicDescriptor")!["BarcodeRawData"] as? NSData` to get the NSData stored in your `AVMetadataMachineReadableCodeObject`. – Alexandru Motoc May 12 '16 at 04:46
  • Very helpful. However, the bytes I get from the raw data don't match my reference material in a test. The application *bctester* for example returns the correct bytes, and they are totally different from the ones returned by `AVMetadataMachineReadableCodeObject`. Can you point me in the right direction? I think I'll post this as a separate question too, as it is not strictly on topic for this one. – oelna May 12 '16 at 18:05
  • 1
    You might want to check whether the data you're reading is encrypted or not. There's a chance you would have to decrypt it before using it. I think the data is usually compressed and serialized by some algorithm, so you would have to perform the reverse process: decompress and deserialize. – Alexandru Motoc May 14 '16 at 08:24
  • 1
    The format is actually deflated (zlib) and I have managed to build a test case that inflates the data correctly, but the `BarcodeRawData` is still a lot different from what other readers return. I have put this up as a new question with actual data and code: http://stackoverflow.com/questions/37225276/reading-raw-bytes-from-an-aztec-barcode-via-avmetadatamachinereadablecodeobject – oelna May 19 '16 at 09:33
3

I was able to solve this issue by Base64 encoding the data in the QR code. This obviously won't work if you're not also generating the QR codes but could be option for people that are.

We were running into the upper limit of data that can be stored in a QR code but by compressing the data (we used zlib) and then Base64 encoding the compressed data, so long as your data compresses to less than 75% of its original size you get some additional capacity and can use the stringValue property to get your data back out, you just have to Base64 decode and then decompress to get the original data back.

Even if you're starting with binary data that isn't very compressible, so long as you can handle the overhead of Base64 and still be within the limitations of QR codes this may be a viable option that avoids working around the fact that AVMetadataMachineReadableCodeObject seems to want to work with string values.

thesquaregroot
  • 1,414
  • 1
  • 21
  • 35
  • Thanks, this is a great solution for me. My data compresses down to roughly 25%, so I don't mind the additional overhead of Base64. It is still at least 50-60% smaller than the original data! – inexcitus Oct 31 '19 at 07:18
2

You can use a CIDetector to get to a CIQRCodeFeature which has a symbolDescriptor which has a errorCorrectedPayload which contains the data.

Only problem is that this data still includes QR code headers, like ECI etc... so you still need to interpret the bits.

I summed it up in a post here.

Kristof Van Landschoot
  • 1,427
  • 1
  • 12
  • 30
0

Inspired by previous answers and other sites, I have created a gist that allows to extract binary from QR code or Aztec code, without using private APIs nor other library. It is a AVMetadataMachineReadableCodeObject extension presenting a binaryValue.

However, it only runs on iOS 11 and later, because of the CIQRCodeDescriptor use.

It is available here : https://gist.github.com/PetrusM/267e2ee8c1d8b5dca17eac085afa7d7c

For QR codes, it works only with 100% binary ones. But if they contain further parts, you can easily adapt it.

Pierre
  • 422
  • 2
  • 12