Learn how easy it is to sync an existing GitHub or Google Code repo to a SourceForge project! See Demo

Close

#115 QR codes containing 8-bit bytes (binary)

latest_mercurial
open
nobody
None
3
2013-11-11
2013-10-16
LeadSuccess
No

Relating the iPhone SDK 1.2.

My problem is the same as in discussion topic
http://sourceforge.net/p/zbar/discussion/664596/thread/b7293901/#3b06
where spadix supposed to "open a support request and provide a sample image that demonstrates your problem". I didn't find any related support request.
The same issue - I think - is asked here:
http://sourceforge.net/p/zbar/discussion/664595/thread/55c42636/#1b87

And if I understand spadix right here:
http://sourceforge.net/p/zbar/discussion/664595/thread/c76bdcbd/#07e2
then this can be done somehow(?).

Using ZBar for some time now, up to recently we scanned 1-dimensional bar-codes and "normal" QR-codes containing some numeric or alphanumeric strings (mostly URLs).
A new requirement are QR-codes containing VCARDs - in three forms:
- as simple plain texts: no problem here, already implemented;
- compressed;
- encoded;
and these latter two mean that the QR doesn't contain readable alphanumerics, but binary data!
As an explicitely defined option by the QR Code Standardization:
http://www.qrcode.com/en/about/standards.html
where there are mentioned 4 types, numeric, alphanumeric, 8-bit bytes (binary), Kanji.
These binaries - of course - can also contain Nulls (which causes the resulting NSString (or the underlying char*) to not even contain all information.

Yes, the problem for me is, that ZBarSzmbol.data is of type NSString (delivering characters, not bytes) and I can't find anything of type NSData (containing the raw bytes).

Two examples of such QR codes are attached (can't get better ones at the moment, sorry, but these should be recognized by ZBar - if not, I could ask for better ones, later).

Hoping, that I explained it understandable.
And of course - sorry - it is urgent :-(

Greetings
Manfred

2 Attachments

Discussion

  • LeadSuccess
    LeadSuccess
    2013-11-11

    As time was really short, we did the following ourselves:

    download the sources of ZBar, beeing prepared to modify it for our needs :-(

    Looking into it, we realised, that in the C object zbar_symbol_t that's wrapped within Objective-C ZBarSymbol the char attribute named data (copied into ZBarSymbol.data) obviously includes all bytes of the scan, as there's also an unsigned int attribute named datalen; so it's irrelevant if data contains nulls, as long as it's read up to datalen.

    Luckily Obj-C ZBarSymbol also has a property named zbarSymbol of type const zbar_symbol_t*. So we use that directly.

    But there's another problem:
    obviously when ZBar gets binary data, it assumes, those come encoded with ISO 8859-1 - like defined in http://en.wikipedia.org/wiki/QR_code
    but that also means, many characters come coded with more than one byte - blowing up the real binary data, that was in the QR, with a lot of useless bytes between.
    Our "solution" here is to convert into a cString from NSISOLatin1 (which is ISO 8859-1).
    And as it only can be done without nulls, there has to be a loop over all chunks ending with a null, collected into a NSMutableData.
    And as the first 7 characters include some sign telling us that it's a vCard that's compressed or/and encoded, we start from the 8th character.

    The code:
    (scanResult is one - we only use the first - ZBarSymbol from reader's ZBarSymbolSet, which has to be extracted somehow (see the doku) from the second parameter of
    imagePickerController:didFinishPickingMediaWithInfo)

    //=====
    NSString * strdata = [scanResult data];
    bool convertible = [strdata canBeConvertedToEncoding:NSISOLatin1StringEncoding]; // for the safety
    NSInteger start = 7;
    NSString * header = [strdata substringToIndex:start] // we use that later to decide how to decompress/decode
    , * part;
    const zbar_symbol_t * rawobj = [scanResult zbarSymbol];
    char * rawdata = rawobj->data;
    unsigned int lenght = rawobj->datalen;
    const char * encod;
    NSMutableData * result = [NSMutableData dataWithLength:0];

    for (int i = start; i < lenght; i++) {
    if (!rawdata[i]) { // 00
    if (convertible) {
    part = [NSString stringWithUTF8String:rawdata+start]; // goes up to 00
    encod = [part cStringUsingEncoding:NSISOLatin1StringEncoding];
    [result appendBytes:encod length:strlen(encod)+1]; // +1 to include ending 00
    }
    else
    [result appendBytes:rawdata+start length:i-start];
    start = i + 1;
    }
    }
    // if there's a rest not terminated with null
    if (start < length) {
    // do nearly the same as above, just not to a 00 but to the end
    ...
    }
    //=====

    for rawobj to compile we also had to redefine <ouch!>
    . typedef struct point_s
    . typedef int refcnt_t
    . struct zbar_symbol_s
    like in the underlying sources.

    Well, can it be done more elegant?
    Is this just a workaround - or is it the intention behind ZBarSymbol's property zbarSymbol?
    Should ZBar offer another property of type NSData, besides the NSString data?
    At least it works for us!