Страница 3 из 3

Re: распознавание bar-кодов

Добавлено: 04 окт 2018, 18:55
Olej
Olej писал(а): 2-й из таких пакетов - PyQRNative, в своё время продвигаемый и популяризируемый Google.
Генератор QR кодов:

Код: Выделить всё

# -*- coding: utf-8 -*- 
import sys
import argparse
import PyQRNative
from PyQRNative import *

# QR generator using PyQRNative
ap = argparse.ArgumentParser()                        # construct the argument parse and parse the arguments
ap.add_argument( "-o", "--output", required = False,  help = "path to the output image file" )
ap.add_argument( "-v", nargs='?', const=True, required=False, help = "increased verbose level" )
ap.add_argument( "-s", nargs='?', const=True, required=False, help = "single line" )
args = vars( ap.parse_args() )
#print( args )
debug = args[ "v" ] != None                           # verbose level

#print( sys.stdin.isatty() )
s = u''
if args[ "s" ] != None:                               # single line input
    if sys.stdin.isatty():
        sys.stdout.write( 'get line (Enter for finishing): ' )
        sys.stdout.flush()
    s = sys.stdin.readline()
    if s[ len( s ) - 1 ] == '\n':
        s = s[ :-1 ]
else:                                                 # multi line input
    if sys.stdin.isatty():
       print( 'Enter text (^D for finishing)' )
    while True:
        l = sys.stdin.readline()
        if l == '': break                             # ^D - завершение ввода (EOF)
        s += l.decode( 'utf-8' )
#print( type( s ), len( s ), s )

if 2 == sys.version_info.major:
    b = bytes( s )
else:
    b = bytes( s, encoding = 'utf-8' )
#print( type( b ), b )
 
def makeQR( data, path, level = 1 ):
    quality= { 1: PyQRNative.QRErrorCorrectLevel.L,
               2: PyQRNative.QRErrorCorrectLevel.M,
               3: PyQRNative.QRErrorCorrectLevel.Q,
               4: PyQRNative.QRErrorCorrectLevel.H }
    size = 3
    while 1:
        try:
            q = PyQRNative.QRCode( size, quality[ level ] )
            q.addData( data )
            q.make()
            im = q.makeImage()
            im.save( path, format = "png" )
            break
        except TypeError:
            size += 1
            if debug: print( 'increase size: {}'.format( size ) )            
    if debug: print( 'size = {}'.format( size ) )
    return im

image = makeQR( b, 'qr1.png', level = 1 )

if args[ "output" ] != None:
    ifile = open( args[ "output" ] + '.jpg', 'wb' )
    image.save( ifile, 'JPEG' )
    ifile.close()
if debug:
    image.show()

Re: распознавание bar-кодов

Добавлено: 04 окт 2018, 19:00
Olej
Olej писал(а): Генератор QR кодов:

Код: Выделить всё

Выполнение:
[olej@dell QRgenerator]$ python2 genqr2.py -s -o xxx -v
get line (Enter for finishing): фыва
(<type 'str'>, 8, '\xd1\x84\xd1\x8b\xd0\xb2\xd0\xb0')
size = 3
А вот как зашиваются в QR бинарные данные, вообще не являются символами - просто поток байт ... с одним ограничением, что среди этих двоичных значений нет байта с значением 0: конец строки в C-соглашениях:

Код: Выделить всё

[olej@dell QRgenerator]$ cat 21.bin | python2 genqr2.py -s -o xxx -v
size = 3

[olej@dell QRgenerator]$ file xxx.jpg 
xxx.jpg: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 370x370, frames 3

[olej@dell QRgenerator]$ hexdump -b 21.bin
0000000 001 002 003 004 005 006 007 010 011 020 021 022 023 024 025 026
0000010 027 030 031 040 041                                            
0000015

Re: распознавание bar-кодов

Добавлено: 04 окт 2018, 20:05
Olej
Olej писал(а): Генератор QR кодов:
Но пакет PyQRNative, в отличие от других здесь, которые я перепробовал, не имеет симметричных методов декодирования QR изображений, только метод кодирования, который очень тонко и разнообразно настраивается.
Поэтому для контроля создаваемых QR нужно иметь какое-то независимое приложение ... например, использующее пакет pyzbar, показываемый уже раньше. Но прежде, возможно, нужно будет установить pyzbar:

Код: Выделить всё

[olej@dell QRgenerator]$ sudo python -m pip install pyzbar
[sudo] пароль для olej: 
Collecting pyzbar
  Using cached https://files.pythonhosted.org/packages/bd/e7/dc9aa3ee5ddc71df6ea1698f7e9d12dcc874346ad3051524155e121006a6/pyzbar-0.1.7-py2.py3-none-any.whl
Collecting pathlib>=1.0.1; python_version == "2.7" (from pyzbar)
  Downloading https://files.pythonhosted.org/packages/ac/aa/9b065a76b9af472437a0059f77e8f962fe350438b927cb80184c32f075eb/pathlib-1.0.1.tar.gz (49kB)
    100% |████████████████████████████████| 51kB 360kB/s 
Requirement already satisfied: enum34>=1.1.6; python_version == "2.7" in /usr/lib/python2.7/site-packages (from pyzbar) (1.1.6)
Installing collected packages: pathlib, pyzbar
  Running setup.py install for pathlib ... done
Successfully installed pathlib-1.0.1 pyzbar-0.1.7
Вот теперь можем написать приложение, выполняющее обратное декодирование сгенерированных QR:

Код: Выделить всё

# -*- coding: utf-8 -*- 
import sys
import argparse
import PyQRNative
from PyQRNative import *

# QR generator using PyQRNative
ap = argparse.ArgumentParser()                        # construct the argument parse and parse the arguments
ap.add_argument( "-o", "--output", required = False,  help = "path to the output image file" )
ap.add_argument( "-v", nargs='?', const=True, required=False, help = "increased verbose level" )
ap.add_argument( "-s", nargs='?', const=True, required=False, help = "single line" )
args = vars( ap.parse_args() )
#print( args )
debug = args[ "v" ] != None                           # verbose level

#print( sys.stdin.isatty() )
s = u''
if args[ "s" ] != None:                               # single line input
    if sys.stdin.isatty():
        sys.stdout.write( 'get line (Enter for finishing): ' )
        sys.stdout.flush()
    s = sys.stdin.readline()
    if s[ len( s ) - 1 ] == '\n':
        s = s[ :-1 ]
else:                                                 # multi line input
    if sys.stdin.isatty():
       print( 'Enter text (^D for finishing)' )
    while True:
        l = sys.stdin.readline()
        if l == '': break                             # ^D - завершение ввода (EOF)
        s += l.decode( 'utf-8' )
#print( type( s ), len( s ), s )

if 2 == sys.version_info.major:
    b = bytes( s )
else:
    b = bytes( s, encoding = 'utf-8' )
#print( type( b ), b )
 
def makeQR( data, path, level = 1 ):
    quality= { 1: PyQRNative.QRErrorCorrectLevel.L,
               2: PyQRNative.QRErrorCorrectLevel.M,
               3: PyQRNative.QRErrorCorrectLevel.Q,
               4: PyQRNative.QRErrorCorrectLevel.H }
    size = 3
    while 1:
        try:
            q = PyQRNative.QRCode( size, quality[ level ] )
            q.addData( data )
            q.make()
            im = q.makeImage()
            im.save( path, format = "png" )
            break
        except TypeError:
            size += 1
            if debug: print( 'increase size: {}'.format( size ) )            
    if debug: print( 'size = {}'.format( size ) )
    return im

image = makeQR( b, 'qr1.png', level = 1 )

if args[ "output" ] != None:
    ifile = open( args[ "output" ] + '.jpg', 'wb' )
    image.save( ifile, 'JPEG' )
    ifile.close()
if debug:
    image.show()

Re: распознавание bar-кодов

Добавлено: 04 окт 2018, 20:08
Olej
Olej писал(а): Вот теперь можем написать приложение, выполняющее обратное декодирование сгенерированных QR:
Теперь можно проверить на адекватность QR, сгенерированных предыдущим генератором (из бинарного файла 21.bin):

Код: Выделить всё

[olej@dell QRgenerator]$ python2 restoreqr.py -i xxx.jpg 
find barcodes in greenscale 1
<type 'str'>
save file: xxx.jpg.01.rest

Код: Выделить всё

[olej@dell QRgenerator]$ cmp 21.bin xxx.jpg.01.rest 

[olej@dell QRgenerator]$ echo $?
0
То, что записывали в QR - то из него и извлекли.

Re: распознавание bar-кодов

Добавлено: 05 окт 2018, 20:21
Olej
Olej писал(а): 2-й из таких пакетов - PyQRNative, в своё время продвигаемый и популяризируемый Google.
3-й из таких пакетов, наверное, самый известный, работающий как в Python 2, так и в Python 3 - это qrcode.
Но! :

Код: Выделить всё

[olej@dell 09]$ python2
Python 2.7.15 (default, Sep 21 2018, 23:31:20) 
[GCC 7.3.1 20180712 (Red Hat 7.3.1-6)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import qrcode
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named qrcode
>>> quit()
Его нет по умолчанию ни в каком дистрибутиве, и нужно устанавливать дополнительно.

Исходный Python-код проекта здесь (это бывает очень полезно разобраться в деталях): https://github.com/lincolnloop/python-qrcode

Re: распознавание bar-кодов

Добавлено: 05 окт 2018, 20:34
Olej
Olej писал(а): Его нет по умолчанию ни в каком дистрибутиве, и нужно устанавливать дополнительно.
Это можно сделать 2-мя разными способами:
1). используя Python-инсталлятор:

Код: Выделить всё

[olej@dell qrop]$ pip search qrcode | grep ^qrcode
qrcode-song (0.3)                  - A qrcode generator based on cli-qrcode and web crawler.
qrcode-converter (0.1.1.dev0)      - A qrcode generator with inner image
qrcode (6.0)                       - QR Code image generator
qrcode_terminal (0.8)              - Python QRCode Terminal
2). из репозитория дистрибутива:

Код: Выделить всё

[olej@dell 09]$ dnf list '*qrcode*'| grep python
python-qrcode.noarch                 5.1-7.fc27                          fedora
python-qrcode-core.noarch            5.1-7.fc27                          fedora
python3-qrcode.noarch                5.1-7.fc27                          fedora
python3-qrcode-core.noarch           5.1-7.fc27                          fedora
Я выберу 1-й, но только из соображений более поздней версии пакета:

Код: Выделить всё

[olej@dell qrop]$ sudo python2 -m pip install qrcode
[sudo] пароль для olej: 
Collecting qrcode
  Downloading https://files.pythonhosted.org/packages/79/be/11999004f7e6e5db0fa410c2feacd67c07f472f4500fde0026101f31d0df/qrcode-6.0-py2.py3-none-any.whl
Requirement already satisfied: six in /usr/lib/python2.7/site-packages (from qrcode) (1.11.0)
Installing collected packages: qrcode
Successfully installed qrcode-6.0

Код: Выделить всё

[olej@dell qrop]$ sudo python3 -m pip install qrcode
Collecting qrcode
  Using cached https://files.pythonhosted.org/packages/79/be/11999004f7e6e5db0fa410c2feacd67c07f472f4500fde0026101f31d0df/qrcode-6.0-py2.py3-none-any.whl
Requirement already satisfied: six in /usr/lib/python3.6/site-packages (from qrcode) (1.11.0)
Installing collected packages: qrcode
Successfully installed qrcode-6.0
Проверяем:

Код: Выделить всё

[olej@dell 09]$ python
Python 2.7.15 (default, Sep 21 2018, 23:31:20) 
[GCC 7.3.1 20180712 (Red Hat 7.3.1-6)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import qrcode
>>> help( qrcode )
...
>>> help( qrcode.QRCode )
...

Re: распознавание bar-кодов

Добавлено: 05 окт 2018, 20:58
Olej
Olej писал(а): 3-й из таких пакетов, наверное, самый известный, работающий как в Python 2, так и в Python 3 - это qrcode.
Генератор QR кодов, использующий этот вариант:

Код: Выделить всё

# -*- coding: utf-8 -*- 
import sys
import argparse
try:
    import qrcode
except ImportError:
    print( 'module qrcode not installed' )
    sys.exit( 1 )

# QR generator using qrcode: https://github.com/lincolnloop/python-qrcode
ap = argparse.ArgumentParser()                    # construct the argument parse and parse the arguments
ap.add_argument( "-o", "--output", required = False,  help = "path to the output image file" )
ap.add_argument( "-l", "--level",  required=False,    help = "errors correction level" )
ap.add_argument( "-v", nargs='?', const=True, required=False, help = "increased verbose level" )
ap.add_argument( "-s", nargs='?', const=True, required=False, help = "single line" )
args = vars( ap.parse_args() )

debug = args[ "v" ] != None                       # verbose level
if not debug and args[ "output" ] == None:
    print( 'you must use -v or|and -o options' )
    sys.exit( 1 )

#print( sys.stdin.isatty() )
s = ''
if args[ "s" ] != None:
    if sys.stdin.isatty():
        sys.stdout.write( 'get line (Enter for finishing): ' )
        sys.stdout.flush()
    s = sys.stdin.readline()
    if s[ len( s ) - 1 ] == '\n':
        s = s[ :-1 ]
else:
    if sys.stdin.isatty():
       print( 'Enter text (^D for finishing)' )
    while True:
        l = sys.stdin.readline()
        if l == '': break                         # ^D - завершение ввода (EOF)
        s += l
#print( len( s ) )

if 2 == sys.version_info.major: 
    b = bytes( s )
else: 
    b = bytes( s, encoding = 'utf-8' )

print( type( b ), len( b), b )

quality = { 
    1 : qrcode.ERROR_CORRECT_L,
    2 : qrcode.ERROR_CORRECT_M,
    3 : qrcode.ERROR_CORRECT_Q,
    4 : qrcode.ERROR_CORRECT_H
}

level = qrcode.ERROR_CORRECT_M                    # error correction level
if args[ "level" ] != None:
    try:
        ilv = int( args[ "level" ] )
        if quality[ ilv ] != None:
            level = quality[ ilv ] 
    except ValueError:
        None
    except KeyError:
        None

qr = qrcode.QRCode( version = None, error_correction = level, box_size = 10, border = 4 )
qr.add_data( b )

try: qr.make( fit = True )
except qrcode.exceptions.DataOverflowError:
    print( 'exceeding the maximum data size' )
    sys.exit( 1 )

if debug: print( 'QR version: {}'.format( qr.version ) )
image = qr.make_image()
print( type( image ) )
#print( type( image ) )
if args[ "output" ] != None:
    path = args[ "output" ] + '.jpg'
    ifile = open( path, 'wb' )
    image.save( ifile, 'JPEG' )
    ifile.close()
if debug:
    image.show()

Re: распознавание bar-кодов

Добавлено: 05 окт 2018, 21:05
Olej
Olej писал(а): Генератор QR кодов, использующий этот вариант:
Вот как этот вариант зашивает в QR код бинарные данные (любые другие, ASCII, UTF-8... он зашьёт с ещё большей лёгкостью):

Код: Выделить всё

[olej@dell QRgenerator]$ cat 21.bin | python3 genqr3.py -s -o 21 -v
<class 'bytes'> 21 b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19 !'
QR version: 2
<class 'qrcode.image.pil.PilImage'>
Восстановление:

Код: Выделить всё

[olej@dell QRgenerator]$ python2 restoreqr.py -i 21.jpg
find barcodes in greenscale 1
<type 'str'>
save file: 21.jpg.01.rest

[olej@dell QRgenerator]$ ls 21.*
21.bin  21.jpg  21.jpg.01.rest
Сравнение:

Код: Выделить всё

[olej@dell QRgenerator]$ cmp 21.bin  21.jpg.01.rest

[olej@dell QRgenerator]$ echo $?
0
И вот что в QR зашито:

Код: Выделить всё

[olej@dell QRgenerator]$ hexdump -b 21.jpg.01.rest
0000000 001 002 003 004 005 006 007 010 011 020 021 022 023 024 025 026
0000010 027 030 031 040 041
0000015

Re: распознавание bar-кодов

Добавлено: 05 окт 2018, 21:15
Olej
Интересно сравнить как по-разному представляют одну и ту же информацию разные генераторы...
Повторю рядом 2 изображения QR кодов, сгенерированные из тестового бинарного файла 21.bin с помощью PyQRNative (слева) и qrcode (справа):
Изображение Изображение
Это наглядная иллюстрация того, что стандарт QR избыточен, имеет слишком много степеней свободы (параметров создания), и разные генераторы создают разные изображения.
P.S. Я предполагаю (!?) что даже если тщательно подобрать эквивалентные параметры 2-х разных генераторов (а они имеют разные наборы параметров и названы по-разному), то изображения будут разные.