Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions zxinglight/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,10 @@ class BarcodeType(IntEnum):
UPC_EAN_EXTENSION = 17


def read_codes(image, barcode_type=BarcodeType.NONE, try_harder=False, hybrid=False, multi=True):
def read_codes_full(image, barcode_type=BarcodeType.NONE,
try_harder=False, hybrid=False, multi=True):
"""
Reads codes from a PIL Image.
Reads codes from a PIL Image and includes metadata about what was found.

Args:
image (PIL.Image.Image): Image to read barcodes from.
Expand All @@ -80,7 +81,7 @@ def read_codes(image, barcode_type=BarcodeType.NONE, try_harder=False, hybrid=Fa
multi (bool): Search for multiple barcodes in a single image.

Returns:
A list of barcode values.
A list [(code, position, type), ...] containing each barcode found.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be great if we returned namedtuples here instead of regular tuples. Working with long/nested tuples can quickly become awkward.


.. _ZXing's documentation:
https://zxing.github.io/zxing/apidocs/com/google/zxing/Binarizer.html
Expand All @@ -98,3 +99,25 @@ def read_codes(image, barcode_type=BarcodeType.NONE, try_harder=False, hybrid=Fa
width, height = grayscale_image.size

return zxing_read_codes(raw_image, width, height, barcode_type, try_harder, hybrid, multi)


def read_codes(*args, **kwargs):
"""
Reads codes from a PIL Image.

Args:
image (PIL.Image.Image): Image to read barcodes from.
barcode_type (zxinglight.BarcodeType): Barcode type to look for.
try_harder (bool): Spend more time trying to find a barcode.
hybrid (bool): Use Hybrid Binarizer instead of Global Binarizer. For more information,
see `ZXing's documentation`_.
multi (bool): Search for multiple barcodes in a single image.

Returns:
A list of barcode contents found.

.. _ZXing's documentation:
https://zxing.github.io/zxing/apidocs/com/google/zxing/Binarizer.html
"""
codes = read_codes_full(*args, **kwargs)
return [text for text, points, format in codes]

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this library is supposed to be lightweight, I'd rather break backward compatibility than have multiple functions, which do practically the same thing.

33 changes: 18 additions & 15 deletions zxinglight/_zxinglight.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ static void log_error(const string &msg) {
PyObject_CallMethod(logger, "error", "O", PyUnicode_FromString(msg.c_str()));
}

static vector<string> *_zxing_read_codes(
static vector<Ref<Result> > *_zxing_read_codes(
char *image, int image_size, int width, int height,int barcode_type, bool try_harder,
bool hybrid, bool multi
) {
Expand Down Expand Up @@ -67,24 +67,19 @@ static vector<string> *_zxing_read_codes(

Ref<BinaryBitmap> bitmap(new BinaryBitmap(binarizer));

vector<Ref<Result> > results;
vector<Ref<Result> > *results;
Comment thread
lubo marked this conversation as resolved.
if (multi) {
MultiFormatReader delegate;
GenericMultipleBarcodeReader reader(delegate);
results = reader.decodeMultiple(bitmap, hints);
results = new vector<Ref<Result> >(reader.decodeMultiple(bitmap, hints));
} else {
// There is only one result, but wrap it in a vector anyway to give a consistent interface
// Ref<T> is an autodestructor; the `new` *does not leak*.
Ref<Reader> reader(new MultiFormatReader);
results = vector<Ref<Result> >(1, reader->decode(bitmap, hints));
results = new vector<Ref<Result> >(1, reader->decode(bitmap, hints));
}

vector<string> *codes = new vector<string>();

for (const Ref<Result> &result : results) {
codes->push_back(result->getText()->getText());
}

return codes;
return results;
} catch (const ReaderException &e) {
log_error((string) "zxing::ReaderException: " + e.what());
} catch (const zxing::IllegalArgumentException &e) {
Expand Down Expand Up @@ -113,17 +108,25 @@ static PyObject* zxing_read_codes(PyObject *self, PyObject *args) {

PyBytes_AsStringAndSize(python_image, &image, &image_size);

vector<string> *results = _zxing_read_codes(
vector<Ref<Result> > *results = _zxing_read_codes(
image, image_size, width, height, barcode_type, try_harder, hybrid, multi
);

PyObject *codes = PyList_New(0);

if (results != NULL) {
for (const string &code : *results) {
PyList_Append(codes, PyUnicode_FromString(code.c_str()));
}
for (const Ref<Result> &result : *results) {
PyObject* text = PyUnicode_FromString(result->getText()->getText().c_str());

PyObject* points = PyList_New(0);
for(auto point : result->getResultPoints()->values()) {
PyList_Append(points, Py_BuildValue("ff", point->getX(), point->getY()));
}

PyObject* format = PyLong_FromUnsignedLong(result->getBarcodeFormat());

PyList_Append(codes, PyTuple_Pack(3, text, points, format));
}
delete results;
}

Expand Down