Я работаю над приложением для чтения iOS для специального вида штрих-кода, используемого Deutsche Bahn (немецкий рельс) некоторое время. Это вариант штрих-кода Aztec, который объединяет строку подписи DSA и полезную нагрузку zlib.
Я застрял, когда узнал, что AVMetadataMachineReadableCodeObject не имеет общедоступного метода для чтения необработанных байтов, содержащихся в штрих-коде, и методы строк всегда искажают сжатые zlib-данные.
К счастью, этот ответ отправил меня в правильном направлении. Доступ к (частным) байтам можно получить с помощью KVO, и поскольку я не планирую сейчас распространять приложение в App Store, это было бы прекрасно.
Несмотря на мои почти несуществующие знания Swift и Objective-C, мне удалось заставить это работать, как вы можете видеть в примере кода. Но байты штрих-кода, хранящиеся в NSData, не соответствуют ожидаемому результату! Я подозревал, что библиотека zlib, которую я использую (DeflateSwift) не работает, поэтому я построил тестовый пример, который работал нормально.
Мой вопрос: что я делаю неправильно? Нужно ли мне обрабатывать необработанные байты, чтобы получить ожидаемый результат (см. Ниже)? Насколько сырыми являются точно байты, которые хранятся в AVMetadataMachineReadableCodeObject? Может кто-то указать мне верное направление? Любая помощь приветствуется.
Вот мой код (который является грубым mashup 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
Вот пример штрих-кода билета 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) начинается действительный поток zlib. Если вы разделите данные здесь и раздуваете данные zlib, он возвращает строку, подобную этой:
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
Тест NSDatah2 >
Если я построю массив байтов вручную, используя байты, возвращенные из bcTester, все будет работать так, как ожидалось, и данные zlib будут раздуваться правильно. Вот как я тестировал:
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)