diff --git a/.travis.yml b/.travis.yml index d24fbcb..d6626fd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,11 +12,11 @@ virtualenv: install: - sudo apt-get -qq update - - sudo apt-get install -y --fix-missing libdmtx0a python-opencv - - pip install -r requirements.txt + - sudo apt-get install -y --fix-missing libdmtx0a libzbar0 python-opencv + - pip install -r requirements.pip script: -- nosetests + - python -m nose --verbose --with-coverage --cover-inclusive --cover-tests --cover-package=gouda gouda after_success: - coveralls diff --git a/CHANGELOG.md b/CHANGELOG.md index d0ca3fe..c77b90d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +# v0.1.9 +- #27 Support pyzbar + # v0.1.8 - #24 Support pylibdmtx diff --git a/MANIFEST.in b/MANIFEST.in index cd664b0..9bc3e07 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,3 @@ include *.py -include requirements.txt +include requirements.pip +include gouda/tests/test_data/*png diff --git a/README.md b/README.md index 593fee5..0acd7f9 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ The easiest way is to install the current Python 2.7 release of conda update --all pip install --upgrade pip python \Scripts\pywin32_postinstall.py -install - pip install -r requirements.txt + pip install -r requirements.pip ## Install [OpenCV](http://www.opencv.org/) ### Linux @@ -98,7 +98,7 @@ Windows only. Download and install their [SDK](http://www.inliteresearch.com/). ### libdmtx The [pylibdmtx](https://pypi.python.org/pypi/pylibdmtx/) Python package is -a dependency of `gouda` and is listed in `requirements.txt`. +a dependency of `gouda` and is listed in `requirements.pip`. The `libdmtx` `DLL`s are included with the Windows Python wheel builds of `pylibdmtx`. diff --git a/build.sh b/build.sh index 8a91d66..caf219e 100755 --- a/build.sh +++ b/build.sh @@ -15,5 +15,5 @@ echo Tests nosetests --with-coverage --cover-html --cover-inclusive --cover-erase --cover-tests --cover-package=gouda echo Build -./setup.py sdist +./setup.py bdist_wheel pyinstaller --onefile --clean decode_barcodes.spec diff --git a/decode_barcodes.spec b/decode_barcodes.spec index fe0762e..e73dc9a 100644 --- a/decode_barcodes.spec +++ b/decode_barcodes.spec @@ -1,9 +1,13 @@ -# For PyInstaller build on Mac +# For PyInstaller build import sys from pathlib import Path +from pylibdmtx import pylibdmtx +from pyzbar import pyzbar + + block_cipher = None a = Analysis(['gouda/scripts/decode_barcodes.py'], @@ -18,13 +22,14 @@ a = Analysis(['gouda/scripts/decode_barcodes.py'], win_private_assemblies=False, cipher=block_cipher) -if 'darwin' == sys.platform: - # libdmtx dylib is not detected because it is loaded by a ctypes call in - # pylibdmtx - a.binaries += TOC([ - ('libdmtx.dylib', '/usr/local/Cellar/libdmtx/0.7.4/lib/libdmtx.dylib', 'BINARY'), - ]) +# dylibs not detected because they are loaded by ctypes +a.binaries += TOC([ + (Path(dep._name).name, dep._name, 'BINARY') + for dep in pylibdmtx.EXTERNAL_DEPENDENCIES + pyzbar.EXTERNAL_DEPENDENCIES +]) + +if 'darwin' == sys.platform: # PyInstaller does not detect some dylibs, in some cases (I think) because they # are symlinked. # See Stack Overflow post http://stackoverflow.com/a/17595149 for example @@ -56,13 +61,6 @@ if 'darwin' == sys.platform: a.binaries += TOC([ (lib, str(LIB.joinpath(lib).resolve()), 'BINARY') for lib in MISSING_DYLIBS ]) -elif 'win32' == sys.platform: - # libdmtx dylib is not detected because it is loaded by a ctypes call in - # pylibdmtx - fname = 'libdmtx-{0}.dll'.format('64' if sys.maxsize > 2**32 else '32') - a.binaries += TOC([ - (fname, str(Path(sys.argv[0]).parent.parent.joinpath(fname)), 'BINARY'), - ]) pyz = PYZ(a.pure, a.zipped_data, diff --git a/gouda/__init__.py b/gouda/__init__.py index c3bb296..1c98a23 100644 --- a/gouda/__init__.py +++ b/gouda/__init__.py @@ -1 +1 @@ -__version__ = '0.1.8' +__version__ = '0.1.9' diff --git a/gouda/engines/zbar_engine.py b/gouda/engines/zbar_engine.py index f28e0b2..a3f05f0 100644 --- a/gouda/engines/zbar_engine.py +++ b/gouda/engines/zbar_engine.py @@ -1,22 +1,22 @@ # This file is not called zbar.py to avoid collision with the zbar package -import cv2 - from gouda.barcode import Barcode from gouda.gouda_error import GoudaError from gouda.util import debug_print +from PIL import Image + try: - import zbar + from pyzbar import pyzbar except ImportError: - zbar = None + pyzbar = None class ZbarEngine(object): """Decode using the zbar library http://sourceforge.net/projects/zbar/ - https://pypi.python.org/pypi/zbar + https://pypi.python.org/pypi/pyzbar """ def __init__(self): if not self.available(): @@ -24,20 +24,11 @@ def __init__(self): @classmethod def available(cls): - return zbar is not None + return pyzbar is not None def decode_file(self, path): - return self(cv2.imread(str(path), cv2.IMREAD_GRAYSCALE)) + return self(Image.open(str(path))) def __call__(self, img): - # Decode barcodes in img using zbar - # https://github.com/ZBar/ZBar/blob/master/python/README - # https://github.com/herbyme/zbar/blob/master/python/examples/scan_image.py - scanner = zbar.ImageScanner() - height, width = img.shape[:2] - if 'uint8' != img.dtype or 2 != len(img.shape): - debug_print('Convert to greyscale for zbar') - img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) - image = zbar.Image(width, height, 'Y800', img.tostring()) - scanner.scan(image) - return [Barcode(str(s.type), unicode(s.data, 'utf8')) for s in image] + # Decode barcodes in img using pyzbar + return [Barcode(r.type, r.data) for r in pyzbar.decode(img)] diff --git a/gouda/scripts/decode_barcodes.py b/gouda/scripts/decode_barcodes.py index 706b8b5..a79751c 100755 --- a/gouda/scripts/decode_barcodes.py +++ b/gouda/scripts/decode_barcodes.py @@ -26,7 +26,7 @@ def decode(paths, strategies, engine, visitors, read_greyscale): """Finds and decodes barcodes in images given in pathss """ - for p in paths: + for p in sorted(paths): if p.is_dir(): # Descend into directory decode(p.iterdir(), strategies, engine, visitors, read_greyscale) diff --git a/gouda/util.py b/gouda/util.py index 534b485..458fb8a 100644 --- a/gouda/util.py +++ b/gouda/util.py @@ -22,8 +22,10 @@ def debug_print(*args, **kwargs): def read_image(path, greyscale): - flags = cv2.IMREAD_GRAYSCALE if greyscale else cv2.IMREAD_UNCHANGED - return cv2.imread(str(path), flags) + if greyscale: + return cv2.imread(str(path), cv2.IMREAD_GRAYSCALE) + else: + return cv2.imread(str(path)) def expand_wildcard(args): diff --git a/requirements.pip b/requirements.pip new file mode 100644 index 0000000..47d1e46 --- /dev/null +++ b/requirements.pip @@ -0,0 +1,13 @@ +# TODO How to specify OpenCV? 'cv2>=2.4.8', +pathlib>=1.0.1 +Pillow>=3.2.0 +pylibdmtx==0.1.4 +pyzbar==0.1.2 +numpy>=1.8.2 + +# Packages required for testing +coveralls>=1.1 +nose>=1.3.4 + +# Packages required for distribution +PyInstaller==3.1.1 diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index a737c7e..0000000 --- a/requirements.txt +++ /dev/null @@ -1,7 +0,0 @@ -pathlib>=1.0 -pylibdmtx>=0.1.1 -numpy>=1.8.2 - -# Packages required for testing -coveralls>=1.1 -nose>=1.3.4 diff --git a/setup.py b/setup.py index f969ef3..79138a2 100755 --- a/setup.py +++ b/setup.py @@ -32,6 +32,7 @@ # TODO How to specify OpenCV? 'cv2>=2.4.8,<3', 'pathlib>=1.0.1', 'pylibdmtx>=0.1.1', + 'pyzbar>=0.1.1', 'numpy>=1.8.2', ], 'tests_require': [