3

Okay, I get it, possible duplicate of Read binary QR Code with AVFoundation but I'll try to tackle this issue from a different angle.

I'm trying to scan a barcode (in this case, Aztec) in my swift app. It works for barcodes that have regular string data encoded. For my app though, I need to be able to scan a certain type of barcode (read more about this on SO) that stores the data in binary format. Sadly, stringValue of AVMetadataMachineReadableCodeObject is (per Apple's docs)

The value of this property is an NSString created by decoding the binary payload according to the format of the machine-readable code

so the output gets garbled, truncated and unusable (It's a zlib-encoded data stream).

My question is: is there a way to get to this binary payload other that stringValue? Can I override part of AVMetadataMachineReadableCodeObject and add my own binaryValue or something like it.

I'm willing to try anything, but I'd love this to work natively without resorting to ZXing or some other library, as this is a pretty compact project. If you know this to be working with a library, feel free to add a comment though.

Disclaimer: I'm coding this in Swift, but I think I could manage to abstract this from Obj-C code as well, if that is what you know.

Community
  • 1
  • 1
oelna
  • 2,210
  • 3
  • 22
  • 40
  • Hi, I'm still trying to figure out if I understood your question, but event if it's a string you can revert it to char (8bit) and encode/decode in the format that you prefer.. I've got similar issue decoding barcode for italian pharmaceutical that uses different decoding. – Andrea Dec 23 '15 at 16:09
  • 1
    I don't think this will work. The string that `stringValue` returns is way shorter than what I'd expect. There is a lot missing. I believe Xcode fails to parse much of the data and discards everything that can't be displayed. – oelna Dec 23 '15 at 16:34
  • That is exactly what I'm not getting. IF Aztec is supported, the result is just a representation of what is decoded and it must be correct, so I don't get the you say that is truncated. Maybe the raw data is just encoded in a different bit range such as UTF16 – Andrea Dec 23 '15 at 16:46
  • it's binary data. I don't believe there *is* an encoding. I think the matter is with stringValue. The data is read from the code correctly, but I can't access it other than by reading stringValue, which is – it seems – a lossy cast of this binary data to string. Is there a way to access the data that is read by the framework other than stringValue? – oelna Dec 23 '15 at 16:53
  • I've got the exact same problem, did you find a solution to this? –  Feb 26 '16 at 10:20
  • @Johannes sadly, no. I'd still be very interested to hear what you learn though, if anything! – oelna Feb 26 '16 at 22:53
  • @oelna I'll let you know. I've been trying to get the bytes out of the NSString (stringValue) which I then can inflate, to again make into NSString. But - seems like data is lost in the initial NSString created by stringValue ... It's pretty bad we can't do anything about it, rarely an Aztec comes without compressed content ... Do you know about any server-side libraries that can both decode Aztec and decompress the payload before creating a string? E.g. in Java, .NET or similar? –  Feb 26 '16 at 23:09

3 Answers3

3

With ZXing I found a solution (that is still work in progress, but I managed to inflate the deflated content with success using libz).

Go to ZXAztecDecoder.m and in the method + (NSString *)encodedData:(ZXBoolArray *)correctedBits you can use code given from + (int)readCode:(ZXBoolArray *)rawbits startIndex:(int)startIndex length:(int)length to create unsigned char.

So wherever I found a line of code trying to add characters to the NSString I also filled up a buffer of unsigned char (casted from int returned fro the readCode:rawBits:startIndex:length method).

I used the Aztec barcode from the question about parsing Deutche Ban tickets with Python that you posted. I was able to inflate the content and everything. The only problem is that inflate does not work for my Railway Company... So I'm left with figuring out what kind of algorithm that should inflate a stream that starts with 55 4E or 55 8E ...

Good luck! Your other questions I found helped a lot, so thanks.

EDIT: Some code that might help: https://gist.github.com/johanhar/a421a14bef2f06ee2340

  • I'm working on a fork of the original ZXing repo where I implement a solution to scan aztec barcodes with the UIC-918-3 standard. If it's OK with my work/customer I'll make it available when I'm done. –  Mar 07 '16 at 11:41
  • Did you manage to read/generate the UIC-918-3? It will be really helpful for me – Rizon Mar 19 '16 at 16:56
  • 1
    Yes, I managed to read UIC-918-3 barcodes. See the gist in my edited answer. –  Mar 19 '16 at 20:45
  • I'm trying to integrate your code. You used 2 extra methods - [self bytes] & [self length]. Can you share their implementation or describe what they're for? – Rizon Mar 27 '16 at 13:31
  • inflate is a category-method on NSData –  Mar 27 '16 at 14:05
1

Inspired by answers to this question 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
0

As it turns out, the raw binary data does exist in the AVMetadataMachineReadableCodeObject and can be read into an NSData object, but the method comes with a catch.

In my case I was trying to read an Aztec barcode, but it seems it works with anything iOS can detect. This SO answer has the solution: Read binary QR Code with AVFoundation

Community
  • 1
  • 1
oelna
  • 2,210
  • 3
  • 22
  • 40