Skip to content

Commit 69497a7

Browse files
committed
Accept data: URIs on the command-line
1 parent b89e734 commit 69497a7

File tree

3 files changed

+40
-3
lines changed

3 files changed

+40
-3
lines changed

test/test_all.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,16 @@ def test_bad_file_format_error():
187187
global test_reader
188188
with helper.assertRaises(zxing.BarCodeReaderException):
189189
test_reader.decode(os.path.join(test_barcode_dir, 'bad_format.png'))
190+
191+
192+
def test_data_uris():
193+
def _check_data_uri(uri, contents, suffix):
194+
fobj = zxing.data_uri_to_fobj(uri)
195+
assert fobj.getvalue() == contents
196+
assert fobj.name.endswith(suffix)
197+
198+
yield from ((_check_data_uri, uri, contents, suffix) for (uri, contents, suffix) in (
199+
('data:image/png,ABCD', b'ABCD', '.png'),
200+
('data:image/jpeg;base64,3q2+7w==', bytes.fromhex('deadbeef'), '.jpeg'),
201+
('data:application/binary,%f1%f2%f3', bytes.fromhex('f1f2f3'), '.binary'),
202+
))

zxing/__init__.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@
1414
import sys
1515
import urllib.parse
1616
import zipfile
17+
from base64 import b64decode
1718
from enum import Enum
18-
from io import IOBase
19+
from io import BytesIO, IOBase
1920
from itertools import chain
2021

2122
try:
@@ -34,6 +35,23 @@ def file_uri_to_path(s):
3435
raise ValueError(uri)
3536
return urllib.parse.unquote_plus(uri.path)
3637

38+
39+
def data_uri_to_fobj(s):
40+
r = urllib.parse.urlparse(s)
41+
if r.scheme == 'data' and not r.netloc:
42+
mime, *rest = r.path.split(',', 1)
43+
if rest:
44+
if mime.endswith(';base64') and rest:
45+
mime = mime[:-7]
46+
data = b64decode(rest[0])
47+
else:
48+
data = urllib.parse.unquote_to_bytes(rest[0])
49+
ff = BytesIO(data)
50+
ff.name = f'data_uri_{len(data)}_bytes.{mime.split("/")[-1]}'
51+
return ff
52+
raise ValueError("Cannot handle URIs other than data:MIMETYPE[;base64],DATA")
53+
54+
3755
class BarCodeReaderException(Exception):
3856
def __init__(self, message, filename=None):
3957
self.message, self.filename = message, filename

zxing/__main__.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import csv
33
from sys import stdout, stdin
44

5-
from . import BarCodeReader, BarCodeReaderException
5+
from . import BarCodeReader, BarCodeReaderException, data_uri_to_fobj
66
from .version import __version__
77

88

@@ -24,7 +24,7 @@ def main():
2424
p.add_argument('-c', '--csv', action='store_true')
2525
p.add_argument('--try-harder', action='store_true')
2626
p.add_argument('--pure-barcode', action='store_true')
27-
p.add_argument('image', nargs='+')
27+
p.add_argument('image', nargs='+', help='File path or data: URI of an image containing a barcode')
2828
p.add_argument('-P', '--classpath', help=argparse.SUPPRESS)
2929
p.add_argument('-J', '--java', help=argparse.SUPPRESS)
3030
p.add_argument('-V', '--version', action='store_true')
@@ -46,6 +46,12 @@ def main():
4646
if fn == '-':
4747
ff = stdin.buffer
4848
fn = ff.name
49+
elif ':' in fn:
50+
try:
51+
ff = data_uri_to_fobj(fn)
52+
fn = ff.name
53+
except ValueError as exc:
54+
p.error(exc.args[0])
4955
else:
5056
ff = fn
5157

0 commit comments

Comments
 (0)