通过AVMetadataMachineReadableCodeObject从Aztec条形码读取原始字节会产生意外的结果
我一直在研究一种适用于德国铁路公司(德国铁路公司)使用的特殊条形码的iOS阅读器应用程序。 它是一个连接DSA签名string和zlib瘪负载的Aztec条形码的变体。
当我得知AVMetadataMachineReadableCodeObject
没有读取条码中包含的原始字节的公开方法时,我被卡住了,string方法总是乱码zlib压缩数据。
幸运的是, 这个答案给了我正确的方向。 (私人)字节可以通过KVO访问,因为我目前不期望在App Store上分发应用程序,所以这是完美的。
尽pipe我几乎不存在Swift
和Objective-C
知识,但是我设法使这个工作起来,就像你在示例代码中看到的那样。 但是,存储在NSData
的条形码字节与预期的结果不符! 我怀疑我使用的zlib库( DeflateSwift )没有工作,所以我构build了一个testing用例,它工作正常。
我的问题是:我做错了什么? 我是否需要进一步处理原始字节以获得预期结果(请参阅下文)? AVMetadataMachineReadableCodeObject
中存储的字节的原始数据是AVMetadataMachineReadableCodeObject
? 任何人都可以指向正确的方向吗? 任何帮助表示赞赏。
这是我的代码(这是一个Swift
和Objective-C
混搭)
if let metadataObject = metadataObjects.first { let readableObject = metadataObject as! AVMetadataMachineReadableCodeObject; let rawReadableObject = readableObject.valueForKeyPath("_internal.basicDescriptor")!["BarcodeRawData"] as? NSData; if let rawBytes = rawReadableObject { let barcodeData = rawBytes; // or use testData instead let barcodeSplit:Int = 68; let barcodeLength:Int = barcodeData.length; let barcodeHeader:NSData = barcodeData.subdataWithRange(NSRange(location: 0, length: barcodeSplit)) let barcodeZlibContent:NSData = barcodeData.subdataWithRange(NSRange(location: barcodeSplit, length: (barcodeLength-barcodeSplit))) let count = barcodeZlibContent.length / sizeof(UInt8) var array = [UInt8](count: count, repeatedValue: 0) barcodeZlibContent.getBytes(&array, length:count * sizeof(UInt8)) print("\(barcodeLength)kb") print(barcodeHeader) print(barcodeZlibContent) var inflater = InflateStream() var (inflated, err) = inflater.write(array, flush: true) if err != nil{ fatalError("\(err!)") } if let ticketString = String(bytes: inflated, encoding: NSUTF8StringEncoding) { print(ticketString) } else { print("not a valid UTF-8 sequence") } } }
这是我得到的
从AVMetadataMachineReadableCodeObject
返回的字节是
40 B4 FA 88 89 8A 88 88 98 E6 3E 20 09 10 0A 0E EF 25 ED AC DE C8 80 5A 6F 9D 21 9F 4A 6D 61 33 19 F3 12 10 8A 80 2B F0 C2 7C CE E0 AB 83 46 AF A6 42 79 FD E8 35 D4 8B 0B 00 00 00 00 03 13 3B A3 47 8E A9 C2 B4 DC 30 03 C2 89 32 8D A3 B0 D4 E6 2B 35 5B 7B 08 88 12 A0 AA A2 00 8E 22 20 31 95 10 1C 21 2A FF 78 2C BE 31 1B A2 12 B5 CF A3 87 9B 9B 59 EF 7B BC AC AE CA 88 C8 1C 02 E8 D2 B5 87 76 0D 93 77 8B FB 04 A2 B5 D1 F8 9A 67 D5 55 15 DA 61 13 91 EC 08 60 2D 9B 86 E1 94 35 C3 D8 A9 49 41 5B 3A 7C 59 A5 FD 9A E3 FE F8 3C 9F 3F 7B B2 59 DC 98 E3 5E 92 CC C0 21 11 EC AF BA D7 F4 5D DB FC BD A5 CA AF 99 08 28 E3 02 30 06 20 A8 00 88 43 8E A2 58 2D 87 24 33 40 18 C1 AE 50 04 08 91 7E 59 E1 F6 9B 87 E7 8A 67 AA 1B 3E FF FE EF 79 46 18 5A 23 03 B4 E9 1A 4F 2F 15 EA DC 46 F5 A9 67 AE B8 F7 16 0B F2 38 8B B3 96 35 34 AB D3 A6 0E 6C 77 9D 72 D5 85 7E 58 0B E0 25 69 2C AC 42 9C 13 0F 27 4F 13 72 4A 90 CB 1C ED 78 B3 60 F4 AD 4C FE 2B F4 51 A8 0D 60 CC DF 78 C7 65 78 CC E6 63 02 45 B1 F3 1F A8 ED 9E FE 63 00 00 00 00
这是我用来testing的Deutsche Bahn票据的样本条形码。
这是我需要的
当用适当的条形码阅读器(我使用bcTester 5)进行扫描时,会产生以下字节:
23 55 54 30 31 30 30 38 30 30 30 30 30 31 30 2C 02 14 1C 3D E9 2D CD 5E C4 C0 56 BD AE 61 3E 54 AD A1 B3 26 33 D2 02 14 40 75 03 D0 CF 9C C1 F5 70 58 BD 59 50 A7 AF C5 EB 0A F4 74 00 00 00 00 30 32 37 31 78 9C 65 50 CB 4E C3 30 10 E4 53 2C 71 43 4A D9 F5 2B 36 B7 84 04 52 01 55 51 40 1C 51 01 23 2A 42 0E 21 15 3F C7 8D 1F 63 36 11 52 2B 7C F1 78 76 76 66 BD F7 8F 4D 5D 54 C4 44 CE 10 05 D2 EB 78 5B AC 32 7B B4 77 C8 11 6B 62 C7 D6 79 AA EA AA 16 E1 B2 22 4D C4 01 AD 36 58 61 CA 6B 30 C6 E5 64 A0 B6 97 0F A6 A9 6F D6 71 DF C7 CF 3E 7F 37 93 66 8E C6 71 DE 92 4C C0 E1 22 0D FD 57 7A CB EE B6 CF EF 69 54 FD 66 44 05 31 D0 03 18 01 05 40 04 70 9C 51 46 AD 38 49 33 00 86 20 DD 42 88 04 22 5F A6 A1 DB F6 78 79 D4 79 95 76 1F 3F DF FD E7 98 86 16 B1 30 0B 65 D6 3C BD 2A 15 CE D8 AB E5 79 9D 47 7B DA 34 13 C7 34 73 5A 6B 0B 35 72 D9 5C 0D BB AE 53 AA E8 5F 86 B4 01 E9 25 8D 0D 50 8E 72 3C 39 3C B2 13 94 82 74 CE 2D C7 B3 41 8B ED 4C 9F F5 0B E2 85 6C 01 8C FE C7 B8 E9 87 8C D9 F1 90 28 A3 73 FE 05 6D DE 5F F1
正如你所看到的,在偏移量68( 78 9C
)开始一个有效的zlibstream。 如果你在这里分割数据并膨胀zlib数据,它会返回一个如下的string:
U_HEAD01005300802P9QAN-40501201514560DEDE0080ID0200180104840080BL020357031204GW3HEMP906012015060120151021193517S0010018Fernweh-Ticket natS00200012S0030001AS00900051-0-0S01200010S0140002S2S0150006BerlinS0160011NeumünsterS0210038B-Hbf 8:16 ICE794/HH-Hbf 10:16 IC2224S0230013Krull AndreaS026000213S0270019***************0484S0280013Andrea#Krull S031001006.01.2015S032001006.01.2015S035000511160S0360003271
testingNSData
如果我使用从bcTester返回的字节手动构build字节数组,则一切按预期工作,并且zlib数据膨胀正确。 这是我如何testing:
let testArray = [UInt8](arrayLiteral: 0x23, 0x55, 0x54, 0x30, 0x31, 0x30, 0x30, 0x38, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x2C, 0x02, 0x14, 0x1C, 0x3D, 0xE9, 0x2D, 0xCD, 0x5E, 0xC4, 0xC0, 0x56, 0xBD, 0xAE, 0x61, 0x3E, 0x54, 0xAD, 0xA1, 0xB3, 0x26, 0x33, 0xD2, 0x02, 0x14, 0x40, 0x75, 0x03, 0xD0, 0xCF, 0x9C, 0xC1, 0xF5, 0x70, 0x58, 0xBD, 0x59, 0x50, 0xA7, 0xAF, 0xC5, 0xEB, 0x0A, 0xF4, 0x74, 0x00, 0x00, 0x00, 0x00, 0x30, 0x32, 0x37, 0x31, 0x78, 0x9C, 0x65, 0x50, 0xCB, 0x4E, 0xC3, 0x30, 0x10, 0xE4, 0x53, 0x2C, 0x71, 0x43, 0x4A, 0xD9, 0xF5, 0x2B, 0x36, 0xB7, 0x84, 0x04, 0x52, 0x01, 0x55, 0x51, 0x40, 0x1C, 0x51, 0x01, 0x23, 0x2A, 0x42, 0x0E, 0x21, 0x15, 0x3F, 0xC7, 0x8D, 0x1F, 0x63, 0x36, 0x11, 0x52, 0x2B, 0x7C, 0xF1, 0x78, 0x76, 0x76, 0x66, 0xBD, 0xF7, 0x8F, 0x4D, 0x5D, 0x54, 0xC4, 0x44, 0xCE, 0x10, 0x05, 0xD2, 0xEB, 0x78, 0x5B, 0xAC, 0x32, 0x7B, 0xB4, 0x77, 0xC8, 0x11, 0x6B, 0x62, 0xC7, 0xD6, 0x79, 0xAA, 0xEA, 0xAA, 0x16, 0xE1, 0xB2, 0x22, 0x4D, 0xC4, 0x01, 0xAD, 0x36, 0x58, 0x61, 0xCA, 0x6B, 0x30, 0xC6, 0xE5, 0x64, 0xA0, 0xB6, 0x97, 0x0F, 0xA6, 0xA9, 0x6F, 0xD6, 0x71, 0xDF, 0xC7, 0xCF, 0x3E, 0x7F, 0x37, 0x93, 0x66, 0x8E, 0xC6, 0x71, 0xDE, 0x92, 0x4C, 0xC0, 0xE1, 0x22, 0x0D, 0xFD, 0x57, 0x7A, 0xCB, 0xEE, 0xB6, 0xCF, 0xEF, 0x69, 0x54, 0xFD, 0x66, 0x44, 0x05, 0x31, 0xD0, 0x03, 0x18, 0x01, 0x05, 0x40, 0x04, 0x70, 0x9C, 0x51, 0x46, 0xAD, 0x38, 0x49, 0x33, 0x00, 0x86, 0x20, 0xDD, 0x42, 0x88, 0x04, 0x22, 0x5F, 0xA6, 0xA1, 0xDB, 0xF6, 0x78, 0x79, 0xD4, 0x79, 0x95, 0x76, 0x1F, 0x3F, 0xDF, 0xFD, 0xE7, 0x98, 0x86, 0x16, 0xB1, 0x30, 0x0B, 0x65, 0xD6, 0x3C, 0xBD, 0x2A, 0x15, 0xCE, 0xD8, 0xAB, 0xE5, 0x79, 0x9D, 0x47, 0x7B, 0xDA, 0x34, 0x13, 0xC7, 0x34, 0x73, 0x5A, 0x6B, 0x0B, 0x35, 0x72, 0xD9, 0x5C, 0x0D, 0xBB, 0xAE, 0x53, 0xAA, 0xE8, 0x5F, 0x86, 0xB4, 0x01, 0xE9, 0x25, 0x8D, 0x0D, 0x50, 0x8E, 0x72, 0x3C, 0x39, 0x3C, 0xB2, 0x13, 0x94, 0x82, 0x74, 0xCE, 0x2D, 0xC7, 0xB3, 0x41, 0x8B, 0xED, 0x4C, 0x9F, 0xF5, 0x0B, 0xE2, 0x85, 0x6C, 0x01, 0x8C, 0xFE, 0xC7, 0xB8, 0xE9, 0x87, 0x8C, 0xD9, 0xF1, 0x90, 0x28, 0xA3, 0x73, 0xFE, 0x05, 0x6D, 0xDE, 0x5F, 0xF1) let testData = NSData(bytes: testArray, length: testArray.count)
我前段时间在Xamarin / C#中解决了这个问题,但Swift的想法也是一样的。 encodedData
和ReadCode
方法取自ZXing lib。 希望能帮助到你。
它适用于阅读和解码“小”和“大”的门票代码,但iOS SDK默认的Aztec阅读器不够好,所以最后我们和Manateeworks的读者进行了交stream。 现在我可以看到,iOS 10 SDK没有更好的performance。
public override void DidOutputMetadataObjects (AVCaptureMetadataOutput captureOutput, AVMetadataObject[] metadataObjects, AVCaptureConnection connection) { foreach (AVMetadataMachineReadableCodeObject metadata in metadataObjects) { var d1 = (metadata.ValueForKey ((NSString)"_internal")); var d2 = (d1.ValueForKey ((NSString)"basicDescriptor")); var data = (d2.ValueForKey ((NSString)"BarcodeRawData")); var str = data.ToString ().Trim ().Trim (new [] { '<', '>' }).Replace (" ", ""); var bitarray = new bool[str.Length * 4]; for (var i = 0; i < str.Length / 2; i++) { int value = Convert.ToInt32 (str.Substring (i * 2, 2), 16); bitarray [i * 8 + 0] = (value & 1) > 0; bitarray [i * 8 + 1] = (value & 2) > 0; bitarray [i * 8 + 2] = (value & 4) > 0; bitarray [i * 8 + 3] = (value & 8) > 0; bitarray [i * 8 + 4] = (value & 16) > 0; bitarray [i * 8 + 5] = (value & 32) > 0; bitarray [i * 8 + 6] = (value & 64) > 0; bitarray [i * 8 + 7] = (value & 128) > 0; } var pabData = encodedData (bitarray); parent.scanFinished (true, pabData); } } enum ZXAztecTable { ZXAztecTableUpper, ZXAztecTableBinary, ZXAztecTableDigit }; public byte[] encodedData (bool[] bitArray) { var result = new List<byte> (); int endIndex = bitArray.Length; ZXAztecTable latchTable = ZXAztecTable.ZXAztecTableUpper; // table most recently latched to ZXAztecTable shiftTable = ZXAztecTable.ZXAztecTableUpper; // table to use for the next read int index = 0; while (index < endIndex) { if (shiftTable == ZXAztecTable.ZXAztecTableBinary) { if (endIndex - index < 5) { break; } int length = ReadCode (bitArray, index, 5); index += 5; if (length == 0) { if (endIndex - index < 11) { break; } length = ReadCode (bitArray, index, 11) + 31; index += 11; } for (int charCount = 0; charCount < length; charCount++) { if (endIndex - index < 8) { index = endIndex; // Force outer loop to exit break; } byte code = (byte)ReadCode (bitArray, index, 8); result.Add (code); index += 8; } // Go back to whatever mode we had been in shiftTable = latchTable; } else { int size = shiftTable == ZXAztecTable.ZXAztecTableDigit ? 4 : 5; if (endIndex - index < size) { break; } ReadCode (bitArray, index, size); index += size; latchTable = shiftTable; shiftTable = ZXAztecTable.ZXAztecTableBinary; } } return result.ToArray (); } public int ReadCode (bool[] bitArray, int startIndex, int length) { int res = 0; for (int i = startIndex; i < startIndex + length; i++) { res <<= 1; if (bitArray [i]) { res |= 0x01; } } return res; }