In addition to number and text encodings, QR codes have an 8 bit mode
and an Extended Channel Interpretation mode.
This ECI mode is like 8 bit mode but it also contains metadata
which tells the decoder how to convert the binary data to text.
For example, ECI 26 mode is decoded as UTF-8.
This problem happens because older versions of ZBar treat 8 bit mode
QR codes as unknown ECI mode QR codes. It tries to autodetect
the character set and unconditionally converts the binary data to it.
This destroys the data.
The new version of ZBar will have a ZBAR_CFG_BINARY decoder option
which will make the QR decoder return the data unmodified.
Users of the zbarimg and zbarcam tools will be able to pass
this option to the QR decoder through the -Sqr.binary option,
or simply -Sbinary.
Another source of corruption is the fact these tools output
metadata such as format descriptors and line separators.
These features were no doubt meant to make it easier to parse
the output of the tools but they can corrupt binary data.
This extra output can be suppressed with the --raw --oneshot options:
they will cause the ZBar tools to decode exactly one barcode
and output nothing but the data contained within it.
They should prove useful in scripts.
Finally, with these new features it should be possible to QR encode
secret keys in binary form and use ZBar to restore them:
$ gpg --export-secret-key $fingerprint \
| paperkey --output-type raw \
| qrencode --8bit --output secret-key.qr.png
$ zbarimg --raw --oneshot -Sbinary secret-key.qr.png \
| paperkey --pubring public-key.asc \
| gpg --import
I wrote an answer on StackOverflow about this problem:
https://stackoverflow.com/a/60518608
It has lots of references to source code and other barcode readers
in case anyone is interested.