diff --git a/Changelog.rst b/Changelog.rst index 5bfcc9f..b554727 100644 --- a/Changelog.rst +++ b/Changelog.rst @@ -4,7 +4,8 @@ ChangeLog 2.0 (unreleased) ---------------- -- Drop deprecated qr_code_scanner() method. +- Drop deprecated qr_code_scanner() method +- Add helper to add background color on image 1.2 (2017-03-09) diff --git a/README.rst b/README.rst index 917726b..3866048 100644 --- a/README.rst +++ b/README.rst @@ -35,3 +35,24 @@ How To use ZbarLight codes = zbarlight.scan_codes('qrcode', image) print('QR codes: %s' % codes) + +Troubleshooting +=============== + +In some case ``zbarlight`` will not be able to detect the 1D or 2D code in an image, one of the known cause is that the +image background color is the same as the foreground color after conversion to grey scale (it's happen on images with +alpha channel). You can use the ``copy_image_on_background`` function to add a background color on your image. + +.. code-block:: python + + from PIL import Image + import zbarlight + + file_path = './tests/fixtures/two_qr_codes.png' + with open(file_path, 'rb') as image_file: + image = Image.open(image_file) + image.load() + + new_image = zbarlight.copy_image_on_background(image, color=zbarlight.WHITE) # <<<<<<<<<<<<<<<< Add this line <<<< + codes = zbarlight.scan_codes('qrcode', new_image) + print('QR codes: %s' % codes) diff --git a/docs/reference.rst b/docs/reference.rst index 829f6f6..0e361df 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -2,4 +2,4 @@ Reference ========= .. automodule:: zbarlight - :members: scan_codes + :members: scan_codes, copy_image_on_background diff --git a/src/zbarlight/__init__.py b/src/zbarlight/__init__.py index a0171f5..0f05c83 100644 --- a/src/zbarlight/__init__.py +++ b/src/zbarlight/__init__.py @@ -7,7 +7,17 @@ __version__ = pkg_resources.get_distribution('zbarlight').version -__ALL__ = ['Symbologies', 'UnknownSymbologieError', 'scan_codes'] +__ALL__ = [ + 'Symbologies', + 'UnknownSymbologieError', + 'scan_codes', + 'copy_image_on_background', + 'BLACK', + 'WHITE', +] + +WHITE = (255, 255, 255) +BLACK = (0, 0, 0) class UnknownSymbologieError(Exception): @@ -42,3 +52,18 @@ def scan_codes(code_type, image): if not symbologie: raise UnknownSymbologieError('Unknown Symbologie: %s' % code_type) return zbar_code_scanner(symbologie, raw, width, height) + + +def copy_image_on_background(image, color=WHITE): + """Create a new image by copying the image on a *color* background + + Args: + image (PIL.Image.Image): Image to copy + color (tuple): Background color usually WHITE or BLACK + + Returns: + PIL.Image.Image + """ + background = Image.new("RGB", image.size, color) + background.paste(image, mask=image.split()[3]) + return background diff --git a/tests/fixtures/sample_need_white_background.png b/tests/fixtures/sample_need_white_background.png new file mode 100644 index 0000000..1c2b5ef Binary files /dev/null and b/tests/fixtures/sample_need_white_background.png differ diff --git a/tests/test_scan_codes.py b/tests/test_scan_codes.py index 2b4ad81..f7ae31b 100644 --- a/tests/test_scan_codes.py +++ b/tests/test_scan_codes.py @@ -17,9 +17,9 @@ class ScanCodeTestCase(unittest.TestCase): def assertIsNone(self, obj, msg=None): # Python 2.6 hack return self.assertTrue(obj is None, '%s is not None' % repr(obj)) - def get_image(self, name): + def get_image(self, name, ext='png'): return pil_image( - os.path.join(os.path.dirname(__file__), 'fixtures', '{0}.png'.format(name)) + os.path.join(os.path.dirname(__file__), 'fixtures', '{0}.{1}'.format(name, ext)) ) def test_no_qr_code(self): @@ -59,3 +59,22 @@ def test_unknown_symbology(self): zbarlight.UnknownSymbologieError, zbarlight.scan_codes, 'not-a-zbar-symbologie', image, ) + + def test_need_white_background(self): + """ + User submitted sample that can only be decoded after add a white background + """ + # Not working + image = self.get_image('sample_need_white_background') + + self.assertEqual( + sorted(zbarlight.scan_codes('qrcode', image) or []), + [], + ) + + # Working when adding white background + image_with_background = zbarlight.copy_image_on_background(image) + self.assertEqual( + sorted(zbarlight.scan_codes('qrcode', image_with_background) or []), + sorted([b'http://en.m.wikipedia.org']), + )