Skip to content

Commit

Permalink
Use OpenCV for decoding test cases which do not use Kanji. Avoids pro…
Browse files Browse the repository at this point in the history
…blems with zbar and ISO 8859-1 encoding, see issue #134.
  • Loading branch information
heuer committed Feb 6, 2024
1 parent 39c93b1 commit 549a16c
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 44 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
.coverage
.[nt]ox/
.idea/
.venv/
*.egg-info
dist/
build/
Expand Down
1 change: 1 addition & 0 deletions tests/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pytest-cov
pypng~=0.0.20
pyzbar~=0.1.8
qrcode-artistic
opencv-python
Pillow
importlib-metadata>=3.6.0; python_version < '3.10'

47 changes: 34 additions & 13 deletions tests/test_encode_decode.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
Requires pyzbar and additional libs (libzbar0).
"""
import io
import cv2 as cv
import numpy as np
import pytest
import segno
try:
Expand All @@ -19,25 +21,35 @@
pytestmark = pytest.mark.skip


def qr_to_bytes(qrcode, scale):
if qrcode.is_micro:
raise Exception('zbar cannot decode Micro QR codes')
buff = io.BytesIO()
for row in qrcode.matrix_iter(scale=scale):
buff.write(bytearray(0x0 if b else 0xff for b in row))
return buff.getvalue()


def decode(qrcode):
def decode_kanji(qrcode):
scale = 3
width, height = qrcode.symbol_size(scale=scale)
qr_bytes = qr_to_bytes(qrcode, scale)
decoded = zbardecode((qr_bytes, width, height))
out = io.BytesIO()
for row in qrcode.matrix_iter(scale=scale):
out.write(bytearray(0x0 if b else 0xff for b in row))
decoded = zbardecode((out.getvalue(), width, height))
assert 1 == len(decoded)
assert 'QRCODE' == decoded[0].type
return decoded[0].data.decode('utf-8')


def decode_cv(qrcode):
out = io.BytesIO()
qrcode.save(out, scale=3, kind='png')
out.seek(0)
img = cv.imdecode(np.frombuffer(out.getvalue(), np.uint8), flags=cv.IMREAD_COLOR)
detector = cv.QRCodeDetector()
decoded, points, qrcode_bin = detector.detectAndDecode(img)
return decoded or None


def decode(qrcode):
if qrcode.is_micro:
raise Exception('Cannot decode Micro QR codes')
# OpenCV does not support Kanji
return decode_cv(qrcode) if qrcode.mode != 'kanji' else decode_kanji(qrcode)


@pytest.mark.parametrize('content, mode',
[('漢字', 'kanji'),
('続きを読む', 'kanji'),
Expand All @@ -56,7 +68,7 @@ def test_stackoverflow_issue():
content = 'Thomsôn Gonçalves Ámaral,325.432.123-21'
qr = segno.make(content, encoding='utf-8')
assert 'byte' == qr.mode
assert content == decode(qr).encode('shift-jis').decode('utf-8')
assert content == decode(qr)


def test_pyqrcode_issue76():
Expand All @@ -73,5 +85,14 @@ def test_pyqrcode_issue76():
assert content == decode(qr)


@pytest.mark.parametrize('encoding', [None, 'latin1', 'ISO-8859-1', 'utf-8'])
def test_issue134(encoding):
# See <https://github.com/heuer/segno/issues/134>
content = 'Märchen'
qr = segno.make(content, encoding=encoding, micro=False)
assert 'byte' == qr.mode
assert content == decode(qr)


if __name__ == '__main__':
pytest.main([__file__])
29 changes: 9 additions & 20 deletions tests/test_issue_105_epc_slash.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,19 @@
"""
import io
import pytest
import cv2 as cv
import numpy as np
from segno.helpers import make_epc_qr
try:
from pyzbar.pyzbar import decode as zbardecode
except (ImportError, FileNotFoundError): # The latter may occur under Windows
pytestmark = pytest.mark.skip


def qr_to_bytes(qrcode, scale):
if qrcode.is_micro:
raise Exception('zbar cannot decode Micro QR codes')
buff = io.BytesIO()
for row in qrcode.matrix_iter(scale=scale):
buff.write(bytearray(0x0 if b else 0xff for b in row))
return buff.getvalue()


def decode(qrcode):
scale = 3
width, height = qrcode.symbol_size(scale=scale)
qr_bytes = qr_to_bytes(qrcode, scale)
decoded = zbardecode((qr_bytes, width, height))
assert 1 == len(decoded)
assert 'QRCODE' == decoded[0].type
return decoded[0].data.decode('utf-8')
out = io.BytesIO()
qrcode.save(out, scale=3, kind='png')
out.seek(0)
img = cv.imdecode(np.frombuffer(out.getvalue(), np.uint8), flags=cv.IMREAD_COLOR)
detector = cv.QRCodeDetector()
decoded, points, qrcode_bin = detector.detectAndDecode(img)
return decoded or None


@pytest.mark.parametrize('text', ['/',
Expand Down
15 changes: 4 additions & 11 deletions tests/test_issue_109_bytes.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,13 @@
pytestmark = pytest.mark.skip


def qr_to_bytes(qrcode, scale):
if qrcode.is_micro:
raise Exception('zbar cannot decode Micro QR codes')
buff = io.BytesIO()
for row in qrcode.matrix_iter(scale=scale):
buff.write(bytearray(0x0 if b else 0xff for b in row))
return buff.getvalue()


def decode(qrcode):
scale = 3
width, height = qrcode.symbol_size(scale=scale)
qr_bytes = qr_to_bytes(qrcode, scale)
decoded = zbardecode((qr_bytes, width, height))
out = io.BytesIO()
for row in qrcode.matrix_iter(scale=scale):
out.write(bytearray(0x0 if b else 0xff for b in row))
decoded = zbardecode((out.getvalue(), width, height))
assert 1 == len(decoded)
assert 'QRCODE' == decoded[0].type
return decoded[0].data.decode('utf-8').encode('cp932')
Expand Down

0 comments on commit 549a16c

Please sign in to comment.